diff --git a/rtl/ptp_perout.v b/rtl/ptp_perout.v index 34d928be9..9071b5d2e 100644 --- a/rtl/ptp_perout.v +++ b/rtl/ptp_perout.v @@ -1,6 +1,6 @@ /* -Copyright (c) 2019 Alex Forencich +Copyright (c) 2019-2024 Alex Forencich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -77,15 +77,12 @@ module ptp_perout # output wire output_pulse ); -localparam [2:0] +localparam [1:0] STATE_IDLE = 3'd0, - STATE_UPDATE_RISE_1 = 3'd1, - STATE_UPDATE_RISE_2 = 3'd2, - STATE_UPDATE_FALL_1 = 3'd3, - STATE_UPDATE_FALL_2 = 3'd4, - STATE_WAIT_EDGE = 3'd5; + STATE_UPDATE_RISE = 3'd1, + STATE_UPDATE_FALL = 3'd2; -reg [2:0] state_reg = STATE_IDLE, state_next; +reg [1:0] state_reg = STATE_IDLE, state_next; reg [47:0] time_s_reg = 0; reg [30:0] time_ns_reg = 0; @@ -95,9 +92,9 @@ reg [47:0] next_rise_s_reg = 0, next_rise_s_next; reg [30:0] next_rise_ns_reg = 0, next_rise_ns_next; reg [15:0] next_rise_fns_reg = 0, next_rise_fns_next; -reg [47:0] next_fall_s_reg = 0, next_fall_s_next; -reg [30:0] next_fall_ns_reg = 0, next_fall_ns_next; -reg [15:0] next_fall_fns_reg = 0, next_fall_fns_next; +reg [47:0] next_edge_s_reg = 0, next_edge_s_next; +reg [30:0] next_edge_ns_reg = 0, next_edge_ns_next; +reg [15:0] next_edge_fns_reg = 0, next_edge_fns_next; reg [47:0] start_s_reg = OUT_START_S; reg [30:0] start_ns_reg = OUT_START_NS; @@ -116,6 +113,7 @@ reg [15:0] ts_96_fns_inc_reg = 0, ts_96_fns_inc_next; reg [30:0] ts_96_ns_ovf_reg = 0, ts_96_ns_ovf_next; reg [15:0] ts_96_fns_ovf_reg = 0, ts_96_fns_ovf_next; +reg restart_reg = 1'b1; reg locked_reg = 1'b0, locked_next; reg error_reg = 1'b0, error_next; reg ffwd_reg = 1'b0, ffwd_next; @@ -133,9 +131,9 @@ always @* begin next_rise_ns_next = next_rise_ns_reg; next_rise_fns_next = next_rise_fns_reg; - next_fall_s_next = next_fall_s_reg; - next_fall_ns_next = next_fall_ns_reg; - next_fall_fns_next = next_fall_fns_reg; + next_edge_s_next = next_edge_s_reg; + next_edge_ns_next = next_edge_ns_reg; + next_edge_fns_next = next_edge_fns_reg; ts_96_ns_inc_next = ts_96_ns_inc_reg; ts_96_fns_inc_next = ts_96_fns_inc_reg; @@ -149,97 +147,97 @@ always @* begin level_next = level_reg; output_next = output_reg; - if (input_start_valid || input_period_valid || input_ts_step) begin - locked_next = 1'b0; - level_next = 1'b0; - output_next = 1'b0; - error_next = input_ts_step; - state_next = STATE_IDLE; - end else begin - case (state_reg) - STATE_IDLE: begin - // set next rise to start time - next_rise_s_next = start_s_reg; - next_rise_ns_next = start_ns_reg; - if (FNS_ENABLE) begin - next_rise_fns_next = start_fns_reg; - end - locked_next = 1'b0; - ffwd_next = 1'b1; - output_next = 1'b0; - level_next = 1'b0; - state_next = STATE_WAIT_EDGE; - end - STATE_UPDATE_RISE_1: begin - // set next rise time to next rise time plus period + case (state_reg) + STATE_IDLE: begin + if (ffwd_reg || level_reg) begin + // fast forward or falling edge, set up for next rising edge + // set next rise time to previous rise time plus period {ts_96_ns_inc_next, ts_96_fns_inc_next} = {next_rise_ns_reg, next_rise_fns_reg} + {period_ns_reg, period_fns_reg}; {ts_96_ns_ovf_next, ts_96_fns_ovf_next} = {next_rise_ns_reg, next_rise_fns_reg} + {period_ns_reg, period_fns_reg} - {31'd1_000_000_000, 16'd0}; - state_next = STATE_UPDATE_RISE_2; - end - STATE_UPDATE_RISE_2: begin - if (!ts_96_ns_ovf_reg[30]) begin - // if the overflow lookahead did not borrow, one second has elapsed - next_rise_s_next = next_rise_s_reg + period_s_reg + 1; - next_rise_ns_next = ts_96_ns_ovf_reg; - next_rise_fns_next = ts_96_fns_ovf_reg; - end else begin - // no increment seconds field - next_rise_s_next = next_rise_s_reg + period_s_reg; - next_rise_ns_next = ts_96_ns_inc_reg; - next_rise_fns_next = ts_96_fns_inc_reg; - end - state_next = STATE_WAIT_EDGE; - end - STATE_UPDATE_FALL_1: begin - // set next fall time to next rise time plus width + end else begin + // rising edge; set up for next falling edge + // set next fall time to previous rise time plus width {ts_96_ns_inc_next, ts_96_fns_inc_next} = {next_rise_ns_reg, next_rise_fns_reg} + {width_ns_reg, width_fns_reg}; {ts_96_ns_ovf_next, ts_96_fns_ovf_next} = {next_rise_ns_reg, next_rise_fns_reg} + {width_ns_reg, width_fns_reg} - {31'd1_000_000_000, 16'd0}; - state_next = STATE_UPDATE_FALL_2; end - STATE_UPDATE_FALL_2: begin - if (!ts_96_ns_ovf_reg[30]) begin - // if the overflow lookahead did not borrow, one second has elapsed - next_fall_s_next = next_rise_s_reg + width_s_reg + 1; - next_fall_ns_next = ts_96_ns_ovf_reg; - next_fall_fns_next = ts_96_fns_ovf_reg; - end else begin - // no increment seconds field - next_fall_s_next = next_rise_s_reg + width_s_reg; - next_fall_ns_next = ts_96_ns_inc_reg; - next_fall_fns_next = ts_96_fns_inc_reg; - end - state_next = STATE_WAIT_EDGE; - end - STATE_WAIT_EDGE: begin - if ((!level_reg || ffwd_reg) && ((time_s_reg > next_rise_s_reg) || (time_s_reg == next_rise_s_reg && {time_ns_reg, time_fns_reg} > {next_rise_ns_reg, next_rise_fns_reg}))) begin - // rising edge - if (ffwd_reg) begin - output_next = 1'b0; - level_next = 1'b0; - state_next = STATE_UPDATE_RISE_1; - end else begin - locked_next = 1'b1; - error_next = 1'b0; - output_next = enable; - level_next = 1'b1; - state_next = STATE_UPDATE_FALL_1; - end - end else if (level_reg && ((time_s_reg > next_fall_s_reg) || (time_s_reg == next_fall_s_reg && {time_ns_reg, time_fns_reg} > {next_fall_ns_reg, next_fall_fns_reg}))) begin - // falling edge + + // wait for edge + if ((time_s_reg > next_edge_s_reg) || (time_s_reg == next_edge_s_reg && {time_ns_reg, time_fns_reg} > {next_edge_ns_reg, next_edge_fns_reg})) begin + if (ffwd_reg || level_reg) begin + // fast forward or falling edge, set up for next rising edge output_next = 1'b0; level_next = 1'b0; - state_next = STATE_UPDATE_RISE_1; + state_next = STATE_UPDATE_RISE; end else begin - ffwd_next = 1'b0; - state_next = STATE_WAIT_EDGE; + // rising edge; set up for next falling edge + locked_next = 1'b1; + error_next = 1'b0; + output_next = enable; + level_next = 1'b1; + state_next = STATE_UPDATE_FALL; end + end else begin + ffwd_next = 1'b0; + state_next = STATE_IDLE; end - endcase + end + STATE_UPDATE_RISE: begin + if (!ts_96_ns_ovf_reg[30]) begin + // if the overflow lookahead did not borrow, one second has elapsed + next_edge_s_next = next_rise_s_reg + period_s_reg + 1; + next_edge_ns_next = ts_96_ns_ovf_reg; + next_edge_fns_next = ts_96_fns_ovf_reg; + end else begin + // no increment seconds field + next_edge_s_next = next_rise_s_reg + period_s_reg; + next_edge_ns_next = ts_96_ns_inc_reg; + next_edge_fns_next = ts_96_fns_inc_reg; + end + next_rise_s_next = next_edge_s_next; + next_rise_ns_next = next_edge_ns_next; + next_rise_fns_next = next_edge_fns_next; + state_next = STATE_IDLE; + end + STATE_UPDATE_FALL: begin + if (!ts_96_ns_ovf_reg[30]) begin + // if the overflow lookahead did not borrow, one second has elapsed + next_edge_s_next = next_rise_s_reg + width_s_reg + 1; + next_edge_ns_next = ts_96_ns_ovf_reg; + next_edge_fns_next = ts_96_fns_ovf_reg; + end else begin + // no increment seconds field + next_edge_s_next = next_rise_s_reg + width_s_reg; + next_edge_ns_next = ts_96_ns_inc_reg; + next_edge_fns_next = ts_96_fns_inc_reg; + end + state_next = STATE_IDLE; + end + endcase + + if (restart_reg || input_ts_step) begin + // set next rise and next edge to start time + next_rise_s_next = start_s_reg; + next_rise_ns_next = start_ns_reg; + if (FNS_ENABLE) begin + next_rise_fns_next = start_fns_reg; + end + next_edge_s_next = start_s_reg; + next_edge_ns_next = start_ns_reg; + if (FNS_ENABLE) begin + next_edge_fns_next = start_fns_reg; + end + locked_next = 1'b0; + ffwd_next = 1'b1; + output_next = 1'b0; + level_next = 1'b0; + error_next = input_ts_step; + state_next = STATE_IDLE; end end always @(posedge clk) begin state_reg <= state_next; + restart_reg <= 1'b0; time_s_reg <= input_ts_96[95:48]; time_ns_reg <= input_ts_96[45:16]; @@ -253,6 +251,7 @@ always @(posedge clk) begin if (FNS_ENABLE) begin start_fns_reg <= input_start[15:0]; end + restart_reg <= 1'b1; end if (input_period_valid) begin @@ -261,6 +260,7 @@ always @(posedge clk) begin if (FNS_ENABLE) begin period_fns_reg <= input_period[15:0]; end + restart_reg <= 1'b1; end if (input_width_valid) begin @@ -277,10 +277,10 @@ always @(posedge clk) begin next_rise_fns_reg <= next_rise_fns_next; end - next_fall_s_reg <= next_fall_s_next; - next_fall_ns_reg <= next_fall_ns_next; + next_edge_s_reg <= next_edge_s_next; + next_edge_ns_reg <= next_edge_ns_next; if (FNS_ENABLE) begin - next_fall_fns_reg <= next_fall_fns_next; + next_edge_fns_reg <= next_edge_fns_next; end ts_96_ns_inc_reg <= ts_96_ns_inc_next; @@ -314,6 +314,7 @@ always @(posedge clk) begin width_ns_reg <= OUT_WIDTH_NS; width_fns_reg <= OUT_WIDTH_FNS; + restart_reg <= 1'b1; locked_reg <= 1'b0; error_reg <= 1'b0; output_reg <= 1'b0;