From 4a16c9070bf215832c3dbccca0f33e432ab4a3ad Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Fri, 22 Jul 2022 01:24:22 -0700 Subject: [PATCH 1/3] Fix mixed assignments Signed-off-by: Alex Forencich --- rtl/ptp_clock_cdc.v | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rtl/ptp_clock_cdc.v b/rtl/ptp_clock_cdc.v index 45e69e635..16141542c 100644 --- a/rtl/ptp_clock_cdc.v +++ b/rtl/ptp_clock_cdc.v @@ -203,9 +203,9 @@ if (PIPELINE_OUTPUT > 0) begin if (output_rst) begin for (i = 0; i < PIPELINE_OUTPUT; i = i + 1) begin - output_ts_reg[i] = 0; - output_ts_step_reg[i] = 1'b0; - output_pps_reg[i] = 1'b0; + output_ts_reg[i] <= 0; + output_ts_step_reg[i] <= 1'b0; + output_pps_reg[i] <= 1'b0; end end end @@ -800,11 +800,11 @@ always @(posedge output_clk) begin ptp_locked_reg <= 1'b0; for (i = 0; i < PIPELINE_OUTPUT; i = i + 1) begin - ts_s_pipe_reg[i] = 0; - ts_ns_pipe_reg[i] = 0; - ts_fns_pipe_reg[i] = 0; - ts_step_pipe_reg[i] = 1'b0; - pps_pipe_reg[i] = 1'b0; + ts_s_pipe_reg[i] <= 0; + ts_ns_pipe_reg[i] <= 0; + ts_fns_pipe_reg[i] <= 0; + ts_step_pipe_reg[i] <= 1'b0; + pps_pipe_reg[i] <= 1'b0; end end end From db881ed5511810b174e1e591af73531fb4c3c511 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Fri, 22 Jul 2022 18:39:21 -0700 Subject: [PATCH 2/3] Remove magic numbers Signed-off-by: Alex Forencich --- rtl/ptp_clock.v | 6 ++++-- rtl/ptp_clock_cdc.v | 14 ++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/rtl/ptp_clock.v b/rtl/ptp_clock.v index ca646c14d..ce3bf6927 100644 --- a/rtl/ptp_clock.v +++ b/rtl/ptp_clock.v @@ -96,6 +96,8 @@ module ptp_clock # parameter INC_NS_WIDTH = $clog2(2**PERIOD_NS_WIDTH + 2**OFFSET_NS_WIDTH + 2**DRIFT_NS_WIDTH); +localparam [30:0] NS_PER_S = 31'd1_000_000_000; + reg [PERIOD_NS_WIDTH-1:0] period_ns_reg = PERIOD_NS; reg [FNS_WIDTH-1:0] period_fns_reg = PERIOD_FNS; @@ -252,13 +254,13 @@ always @(posedge clk) begin // if the overflow lookahead did not borrow, one second has elapsed // increment seconds field, pre-compute both normal increment and overflow values {ts_96_ns_inc_reg, ts_96_fns_inc_reg} <= {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} + {ts_inc_ns_reg, ts_inc_fns_reg}; - {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} <= {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} + {ts_inc_ns_reg, ts_inc_fns_reg} - {31'd1_000_000_000, {FNS_WIDTH{1'b0}}}; + {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} <= {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} + {ts_inc_ns_reg, ts_inc_fns_reg} - {NS_PER_S, {FNS_WIDTH{1'b0}}}; {ts_96_ns_reg, ts_96_fns_reg} <= {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg}; ts_96_s_reg <= ts_96_s_reg + 1; end else begin // no increment seconds field, pre-compute both normal increment and overflow values {ts_96_ns_inc_reg, ts_96_fns_inc_reg} <= {ts_96_ns_inc_reg, ts_96_fns_inc_reg} + {ts_inc_ns_reg, ts_inc_fns_reg}; - {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} <= {ts_96_ns_inc_reg, ts_96_fns_inc_reg} + {ts_inc_ns_reg, ts_inc_fns_reg} - {31'd1_000_000_000, {FNS_WIDTH{1'b0}}}; + {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} <= {ts_96_ns_inc_reg, ts_96_fns_inc_reg} + {ts_inc_ns_reg, ts_inc_fns_reg} - {NS_PER_S, {FNS_WIDTH{1'b0}}}; {ts_96_ns_reg, ts_96_fns_reg} <= {ts_96_ns_inc_reg, ts_96_fns_inc_reg}; ts_96_s_reg <= ts_96_s_reg; end diff --git a/rtl/ptp_clock_cdc.v b/rtl/ptp_clock_cdc.v index 16141542c..cd7c5174b 100644 --- a/rtl/ptp_clock_cdc.v +++ b/rtl/ptp_clock_cdc.v @@ -89,6 +89,8 @@ parameter SAMPLE_ACC_WIDTH = LOG_SAMPLE_SYNC_RATE+2; parameter DEST_SYNC_LOCK_WIDTH = 7; parameter PTP_LOCK_WIDTH = 8; +localparam [30:0] NS_PER_S = 31'd1_000_000_000; + reg [NS_WIDTH-1:0] period_ns_reg = 0, period_ns_next; reg [FNS_WIDTH-1:0] period_fns_reg = 0, period_fns_next; @@ -574,13 +576,13 @@ always @* begin // if the overflow lookahead did not borrow, one second has elapsed // increment seconds field, pre-compute both normal increment and overflow values {ts_ns_inc_next, ts_fns_inc_next} = {ts_ns_ovf_reg, ts_fns_ovf_reg} + {period_ns_reg, period_fns_reg}; - {ts_ns_ovf_next, ts_fns_ovf_next} = {ts_ns_ovf_reg, ts_fns_ovf_reg} + {period_ns_reg, period_fns_reg} - {31'd1_000_000_000, {FNS_WIDTH{1'b0}}}; + {ts_ns_ovf_next, ts_fns_ovf_next} = {ts_ns_ovf_reg, ts_fns_ovf_reg} + {period_ns_reg, period_fns_reg} - {NS_PER_S, {FNS_WIDTH{1'b0}}}; {ts_ns_next, ts_fns_next} = {ts_ns_ovf_reg, ts_fns_ovf_reg}; ts_s_next = ts_s_next + 1; end else begin // no increment seconds field, pre-compute both normal increment and overflow values {ts_ns_inc_next, ts_fns_inc_next} = {ts_ns_inc_reg, ts_fns_inc_reg} + {period_ns_reg, period_fns_reg}; - {ts_ns_ovf_next, ts_fns_ovf_next} = {ts_ns_inc_reg, ts_fns_inc_reg} + {period_ns_reg, period_fns_reg} - {31'd1_000_000_000, {FNS_WIDTH{1'b0}}}; + {ts_ns_ovf_next, ts_fns_ovf_next} = {ts_ns_inc_reg, ts_fns_inc_reg} + {period_ns_reg, period_fns_reg} - {NS_PER_S, {FNS_WIDTH{1'b0}}}; {ts_ns_next, ts_fns_next} = {ts_ns_inc_reg, ts_fns_inc_reg}; ts_s_next = ts_s_next; end @@ -639,14 +641,14 @@ always @* begin ts_ns_diff_corr_next = ts_ns_diff_reg[16:0]; ts_fns_diff_corr_next = ts_fns_diff_reg; diff_corr_valid_next = 1'b1; - end else if ($signed(ts_s_diff_reg) == 1 && ts_ns_diff_reg[30:16] == 15'h4465) begin + end else if ($signed(ts_s_diff_reg) == 1 && ts_ns_diff_reg[30:16] == ~NS_PER_S[30:16]) begin // difference is small with 1 second difference; adjust and slew - ts_ns_diff_corr_next = ts_ns_diff_reg[16:0] + 17'h0ca00; + ts_ns_diff_corr_next = ts_ns_diff_reg[16:0] + NS_PER_S[16:0]; ts_fns_diff_corr_next = ts_fns_diff_reg; diff_corr_valid_next = 1'b1; - end else if ($signed(ts_s_diff_reg) == -1 && ts_ns_diff_reg[30:16] == 15'h3b9a) begin + end else if ($signed(ts_s_diff_reg) == -1 && ts_ns_diff_reg[30:16] == NS_PER_S[30:16]) begin // difference is small with 1 second difference; adjust and slew - ts_ns_diff_corr_next = ts_ns_diff_reg[16:0] - 17'h0ca00; + ts_ns_diff_corr_next = ts_ns_diff_reg[16:0] - NS_PER_S[16:0]; ts_fns_diff_corr_next = ts_fns_diff_reg; diff_corr_valid_next = 1'b1; end else begin From c1e947dc3dec93a12636194bdbd8176fd11d9229 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Fri, 22 Jul 2022 22:57:44 -0700 Subject: [PATCH 3/3] Timing optimization of PTP modules Signed-off-by: Alex Forencich --- rtl/ptp_clock.v | 33 ++++++++++++++++------------ rtl/ptp_clock_cdc.v | 39 ++++++++++++++++++++++------------ tb/ptp_clock/test_ptp_clock.py | 1 + 3 files changed, 46 insertions(+), 27 deletions(-) diff --git a/rtl/ptp_clock.v b/rtl/ptp_clock.v index ce3bf6927..da0acec1e 100644 --- a/rtl/ptp_clock.v +++ b/rtl/ptp_clock.v @@ -112,6 +112,10 @@ reg [15:0] drift_rate_reg = DRIFT_RATE; reg [INC_NS_WIDTH-1:0] ts_inc_ns_reg = 0; reg [FNS_WIDTH-1:0] ts_inc_fns_reg = 0; +reg [INC_NS_WIDTH-1:0] ts_inc_ns_delay_reg = 0; +reg [FNS_WIDTH-1:0] ts_inc_fns_delay_reg = 0; +reg [30:0] ts_inc_ns_ovf_reg = 0; +reg [FNS_WIDTH-1:0] ts_inc_fns_ovf_reg = 0; reg [47:0] ts_96_s_reg = 0; reg [29:0] ts_96_ns_reg = 0; @@ -250,19 +254,20 @@ always @(posedge clk) begin end // 96 bit timestamp + {ts_inc_ns_delay_reg, ts_inc_fns_delay_reg} <= {ts_inc_ns_reg, ts_inc_fns_reg}; + {ts_inc_ns_ovf_reg, ts_inc_fns_ovf_reg} <= {NS_PER_S, {FNS_WIDTH{1'b0}}} - {ts_inc_ns_reg, ts_inc_fns_reg}; + + {ts_96_ns_inc_reg, ts_96_fns_inc_reg} <= {ts_96_ns_inc_reg, ts_96_fns_inc_reg} + {ts_inc_ns_delay_reg, ts_inc_fns_delay_reg}; + {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} <= {ts_96_ns_inc_reg, ts_96_fns_inc_reg} - {ts_inc_ns_ovf_reg, ts_inc_fns_ovf_reg}; + {ts_96_ns_reg, ts_96_fns_reg} <= {ts_96_ns_inc_reg, ts_96_fns_inc_reg}; + if (!ts_96_ns_ovf_reg[30]) begin // if the overflow lookahead did not borrow, one second has elapsed - // increment seconds field, pre-compute both normal increment and overflow values - {ts_96_ns_inc_reg, ts_96_fns_inc_reg} <= {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} + {ts_inc_ns_reg, ts_inc_fns_reg}; - {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} <= {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} + {ts_inc_ns_reg, ts_inc_fns_reg} - {NS_PER_S, {FNS_WIDTH{1'b0}}}; + // increment seconds field, pre-compute normal increment, force overflow lookahead borrow bit set + {ts_96_ns_inc_reg, ts_96_fns_inc_reg} <= {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} + {ts_inc_ns_delay_reg, ts_inc_fns_delay_reg}; + ts_96_ns_ovf_reg[30] <= 1'b1; {ts_96_ns_reg, ts_96_fns_reg} <= {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg}; ts_96_s_reg <= ts_96_s_reg + 1; - end else begin - // no increment seconds field, pre-compute both normal increment and overflow values - {ts_96_ns_inc_reg, ts_96_fns_inc_reg} <= {ts_96_ns_inc_reg, ts_96_fns_inc_reg} + {ts_inc_ns_reg, ts_inc_fns_reg}; - {ts_96_ns_ovf_reg, ts_96_fns_ovf_reg} <= {ts_96_ns_inc_reg, ts_96_fns_inc_reg} + {ts_inc_ns_reg, ts_inc_fns_reg} - {NS_PER_S, {FNS_WIDTH{1'b0}}}; - {ts_96_ns_reg, ts_96_fns_reg} <= {ts_96_ns_inc_reg, ts_96_fns_inc_reg}; - ts_96_s_reg <= ts_96_s_reg; end if (input_ts_96_valid) begin @@ -270,10 +275,9 @@ always @(posedge clk) begin ts_96_s_reg <= input_ts_96[95:48]; ts_96_ns_reg <= input_ts_96[45:16]; ts_96_ns_inc_reg <= input_ts_96[45:16]; - ts_96_ns_ovf_reg <= 31'h7fffffff; + ts_96_ns_ovf_reg[30] <= 1'b1; ts_96_fns_reg <= FNS_WIDTH > 16 ? input_ts_96[15:0] << (FNS_WIDTH-16) : input_ts_96[15:0] >> (16-FNS_WIDTH); ts_96_fns_inc_reg <= FNS_WIDTH > 16 ? input_ts_96[15:0] << (FNS_WIDTH-16) : input_ts_96[15:0] >> (16-FNS_WIDTH); - ts_96_fns_ovf_reg <= {FNS_WIDTH{1'b1}}; ts_step_reg <= 1; end @@ -300,13 +304,16 @@ always @(posedge clk) begin drift_rate_reg <= DRIFT_RATE; ts_inc_ns_reg <= 0; ts_inc_fns_reg <= 0; + ts_inc_ns_delay_reg <= 0; + ts_inc_fns_delay_reg <= 0; + ts_inc_ns_ovf_reg <= 0; + ts_inc_fns_ovf_reg <= 0; ts_96_s_reg <= 0; ts_96_ns_reg <= 0; ts_96_fns_reg <= 0; ts_96_ns_inc_reg <= 0; ts_96_fns_inc_reg <= 0; - ts_96_ns_ovf_reg <= 31'h7fffffff; - ts_96_fns_ovf_reg <= {FNS_WIDTH{1'b1}}; + ts_96_ns_ovf_reg[30] <= 1'b1; ts_64_ns_reg <= 0; ts_64_fns_reg <= 0; ts_step_reg <= 0; diff --git a/rtl/ptp_clock_cdc.v b/rtl/ptp_clock_cdc.v index cd7c5174b..5dd32167a 100644 --- a/rtl/ptp_clock_cdc.v +++ b/rtl/ptp_clock_cdc.v @@ -93,6 +93,10 @@ localparam [30:0] NS_PER_S = 31'd1_000_000_000; reg [NS_WIDTH-1:0] period_ns_reg = 0, period_ns_next; reg [FNS_WIDTH-1:0] period_fns_reg = 0, period_fns_next; +reg [NS_WIDTH-1:0] period_ns_delay_reg = 0, period_ns_delay_next; +reg [FNS_WIDTH-1:0] period_fns_delay_reg = 0, period_fns_delay_next; +reg [30:0] period_ns_ovf_reg = 0, period_ns_ovf_next; +reg [FNS_WIDTH-1:0] period_fns_ovf_reg = 0, period_fns_ovf_next; reg [47:0] src_ts_s_capt_reg = 0; reg [TS_NS_WIDTH-1:0] src_ts_ns_capt_reg = 0; @@ -570,21 +574,22 @@ always @* begin ptp_locked_next = ptp_locked_reg; // PTP clock + {period_ns_delay_next, period_fns_delay_next} = {period_ns_reg, period_fns_reg}; + {period_ns_ovf_next, period_fns_ovf_next} = {NS_PER_S, {FNS_WIDTH{1'b0}}} - {period_ns_reg, period_fns_reg}; + if (TS_WIDTH == 96) begin // 96 bit timestamp + {ts_ns_inc_next, ts_fns_inc_next} = {ts_ns_inc_reg, ts_fns_inc_reg} + {period_ns_delay_reg, period_fns_delay_reg}; + {ts_ns_ovf_next, ts_fns_ovf_next} = {ts_ns_inc_reg, ts_fns_inc_reg} - {period_ns_ovf_reg, period_fns_ovf_reg}; + {ts_ns_next, ts_fns_next} = {ts_ns_inc_reg, ts_fns_inc_reg}; + if (!ts_ns_ovf_reg[30]) begin // if the overflow lookahead did not borrow, one second has elapsed - // increment seconds field, pre-compute both normal increment and overflow values - {ts_ns_inc_next, ts_fns_inc_next} = {ts_ns_ovf_reg, ts_fns_ovf_reg} + {period_ns_reg, period_fns_reg}; - {ts_ns_ovf_next, ts_fns_ovf_next} = {ts_ns_ovf_reg, ts_fns_ovf_reg} + {period_ns_reg, period_fns_reg} - {NS_PER_S, {FNS_WIDTH{1'b0}}}; + // increment seconds field, pre-compute normal increment, force overflow lookahead borrow bit set + {ts_ns_inc_next, ts_fns_inc_next} = {ts_ns_ovf_reg, ts_fns_ovf_reg} + {period_ns_delay_reg, period_fns_delay_reg}; + ts_ns_ovf_next[30] = 1'b1; {ts_ns_next, ts_fns_next} = {ts_ns_ovf_reg, ts_fns_ovf_reg}; - ts_s_next = ts_s_next + 1; - end else begin - // no increment seconds field, pre-compute both normal increment and overflow values - {ts_ns_inc_next, ts_fns_inc_next} = {ts_ns_inc_reg, ts_fns_inc_reg} + {period_ns_reg, period_fns_reg}; - {ts_ns_ovf_next, ts_fns_ovf_next} = {ts_ns_inc_reg, ts_fns_inc_reg} + {period_ns_reg, period_fns_reg} - {NS_PER_S, {FNS_WIDTH{1'b0}}}; - {ts_ns_next, ts_fns_next} = {ts_ns_inc_reg, ts_fns_inc_reg}; - ts_s_next = ts_s_next; + ts_s_next = ts_s_reg + 1; end end else if (TS_WIDTH == 64) begin // 64 bit timestamp @@ -601,10 +606,9 @@ always @* begin ts_s_next = ts_s_sync_reg; ts_ns_next = ts_ns_sync_reg; ts_ns_inc_next = ts_ns_sync_reg; - ts_ns_ovf_next = {TS_NS_WIDTH+1{1'b1}}; + ts_ns_ovf_next[30] = 1'b1; ts_fns_next = ts_fns_sync_reg; ts_fns_inc_next = ts_fns_sync_reg; - ts_fns_ovf_next = {FNS_WIDTH{1'b1}}; ts_step_next = 1; end else begin // input did not step @@ -727,6 +731,10 @@ end always @(posedge output_clk) begin period_ns_reg <= period_ns_next; period_fns_reg <= period_fns_next; + period_ns_delay_reg <= period_ns_delay_next; + period_fns_delay_reg <= period_fns_delay_next; + period_ns_ovf_reg <= period_ns_ovf_next; + period_fns_ovf_reg <= period_fns_ovf_next; ts_s_reg <= ts_s_next; ts_ns_reg <= ts_ns_next; @@ -782,13 +790,16 @@ always @(posedge output_clk) begin if (output_rst) begin period_ns_reg <= 0; period_fns_reg <= 0; + period_ns_delay_reg <= 0; + period_fns_delay_reg <= 0; + period_ns_ovf_reg <= 0; + period_fns_ovf_reg <= 0; ts_s_reg <= 0; ts_ns_reg <= 0; ts_fns_reg <= 0; ts_ns_inc_reg <= 0; ts_fns_inc_reg <= 0; - ts_ns_ovf_reg <= {TS_NS_WIDTH+1{1'b1}}; - ts_fns_ovf_reg <= {FNS_WIDTH{1'b1}}; + ts_ns_ovf_reg[30] <= 1'b1; ts_step_reg <= 0; pps_reg <= 0; diff --git a/tb/ptp_clock/test_ptp_clock.py b/tb/ptp_clock/test_ptp_clock.py index fb60fdc87..6b2413d79 100644 --- a/tb/ptp_clock/test_ptp_clock.py +++ b/tb/ptp_clock/test_ptp_clock.py @@ -81,6 +81,7 @@ async def run_default_rate(dut): await tb.reset() + await RisingEdge(dut.clk) await RisingEdge(dut.clk) start_time = get_sim_time('sec') start_ts_96 = (dut.output_ts_96.value.integer >> 48) + ((dut.output_ts_96.value.integer & 0xffffffffffff)/2**16*1e-9)