From 945f22fd339eae4f60ef7813161a78b4813bfad7 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 27 Mar 2022 23:46:49 -0700 Subject: [PATCH 1/2] Add output pipeline to PTP clock module --- rtl/ptp_clock.v | 82 ++++++++++++++++++++++++++++++---- tb/ptp_clock/Makefile | 3 ++ tb/ptp_clock/test_ptp_clock.py | 1 + 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/rtl/ptp_clock.v b/rtl/ptp_clock.v index b1bebbff3..ca646c14d 100644 --- a/rtl/ptp_clock.v +++ b/rtl/ptp_clock.v @@ -42,7 +42,8 @@ module ptp_clock # parameter DRIFT_ENABLE = 1, parameter DRIFT_NS = 4'h0, parameter DRIFT_FNS = 16'h0002, - parameter DRIFT_RATE = 16'h0005 + parameter DRIFT_RATE = 16'h0005, + parameter PIPELINE_OUTPUT = 0 ) ( input wire clk, @@ -131,15 +132,78 @@ reg pps_reg = 0; assign input_adj_active = adj_active_reg; -assign output_ts_96[95:48] = ts_96_s_reg; -assign output_ts_96[47:46] = 2'b00; -assign output_ts_96[45:16] = ts_96_ns_reg; -assign output_ts_96[15:0] = FNS_WIDTH > 16 ? ts_96_fns_reg >> (FNS_WIDTH-16) : ts_96_fns_reg << (16-FNS_WIDTH); -assign output_ts_64[63:16] = ts_64_ns_reg; -assign output_ts_64[15:0] = FNS_WIDTH > 16 ? ts_64_fns_reg >> (FNS_WIDTH-16) : ts_64_fns_reg << (16-FNS_WIDTH); -assign output_ts_step = ts_step_reg; +generate -assign output_pps = pps_reg; +if (PIPELINE_OUTPUT > 0) begin + + // pipeline + (* shreg_extract = "no" *) + reg [95:0] output_ts_96_reg[0:PIPELINE_OUTPUT-1]; + (* shreg_extract = "no" *) + reg [63:0] output_ts_64_reg[0:PIPELINE_OUTPUT-1]; + (* shreg_extract = "no" *) + reg output_ts_step_reg[0:PIPELINE_OUTPUT-1]; + (* shreg_extract = "no" *) + reg output_pps_reg[0:PIPELINE_OUTPUT-1]; + + assign output_ts_96 = output_ts_96_reg[PIPELINE_OUTPUT-1]; + assign output_ts_64 = output_ts_64_reg[PIPELINE_OUTPUT-1]; + assign output_ts_step = output_ts_step_reg[PIPELINE_OUTPUT-1]; + assign output_pps = output_pps_reg[PIPELINE_OUTPUT-1]; + + integer i; + + initial begin + for (i = 0; i < PIPELINE_OUTPUT; i = i + 1) begin + output_ts_96_reg[i] = 96'd0; + output_ts_64_reg[i] = 64'd0; + output_ts_step_reg[i] = 1'b0; + output_pps_reg[i] = 1'b0; + end + end + + always @(posedge clk) begin + output_ts_96_reg[0][95:48] <= ts_96_s_reg; + output_ts_96_reg[0][47:46] <= 2'b00; + output_ts_96_reg[0][45:16] <= ts_96_ns_reg; + output_ts_96_reg[0][15:0] <= {ts_96_fns_reg, 16'd0} >> FNS_WIDTH; + output_ts_64_reg[0][63:16] <= ts_64_ns_reg; + output_ts_64_reg[0][15:0] <= {ts_64_fns_reg, 16'd0} >> FNS_WIDTH; + output_ts_step_reg[0] <= ts_step_reg; + output_pps_reg[0] <= pps_reg; + + for (i = 0; i < PIPELINE_OUTPUT-1; i = i + 1) begin + output_ts_96_reg[i+1] <= output_ts_96_reg[i]; + output_ts_64_reg[i+1] <= output_ts_64_reg[i]; + output_ts_step_reg[i+1] <= output_ts_step_reg[i]; + output_pps_reg[i+1] <= output_pps_reg[i]; + end + + if (rst) begin + for (i = 0; i < PIPELINE_OUTPUT; i = i + 1) begin + output_ts_96_reg[i] = 96'd0; + output_ts_64_reg[i] = 64'd0; + output_ts_step_reg[i] = 1'b0; + output_pps_reg[i] = 1'b0; + end + end + end + +end else begin + + assign output_ts_96[95:48] = ts_96_s_reg; + assign output_ts_96[47:46] = 2'b00; + assign output_ts_96[45:16] = ts_96_ns_reg; + assign output_ts_96[15:0] = {ts_96_fns_reg, 16'd0} >> FNS_WIDTH; + assign output_ts_64[63:16] = ts_64_ns_reg; + assign output_ts_64[15:0] = {ts_64_fns_reg, 16'd0} >> FNS_WIDTH; + assign output_ts_step = ts_step_reg; + + assign output_pps = pps_reg; + +end + +endgenerate always @(posedge clk) begin ts_step_reg <= 0; diff --git a/tb/ptp_clock/Makefile b/tb/ptp_clock/Makefile index be710f6de..96bd292aa 100644 --- a/tb/ptp_clock/Makefile +++ b/tb/ptp_clock/Makefile @@ -42,6 +42,7 @@ export PARAM_DRIFT_ENABLE ?= 1 export PARAM_DRIFT_NS ?= 0 export PARAM_DRIFT_FNS ?= 2 export PARAM_DRIFT_RATE ?= 5 +export PARAM_PIPELINE_OUTPUT ?= 0 ifeq ($(SIM), icarus) PLUSARGS += -fst @@ -56,6 +57,7 @@ ifeq ($(SIM), icarus) COMPILE_ARGS += -P $(TOPLEVEL).DRIFT_NS=$(PARAM_DRIFT_NS) COMPILE_ARGS += -P $(TOPLEVEL).DRIFT_FNS=$(PARAM_DRIFT_FNS) COMPILE_ARGS += -P $(TOPLEVEL).DRIFT_RATE=$(PARAM_DRIFT_RATE) + COMPILE_ARGS += -P $(TOPLEVEL).PIPELINE_OUTPUT=$(PARAM_PIPELINE_OUTPUT) ifeq ($(WAVES), 1) VERILOG_SOURCES += iverilog_dump.v @@ -74,6 +76,7 @@ else ifeq ($(SIM), verilator) COMPILE_ARGS += -GDRIFT_NS=$(PARAM_DRIFT_NS) COMPILE_ARGS += -GDRIFT_FNS=$(PARAM_DRIFT_FNS) COMPILE_ARGS += -GDRIFT_RATE=$(PARAM_DRIFT_RATE) + COMPILE_ARGS += -GPIPELINE_OUTPUT=$(PARAM_PIPELINE_OUTPUT) ifeq ($(WAVES), 1) COMPILE_ARGS += --trace-fst diff --git a/tb/ptp_clock/test_ptp_clock.py b/tb/ptp_clock/test_ptp_clock.py index 1166d182b..fb60fdc87 100644 --- a/tb/ptp_clock/test_ptp_clock.py +++ b/tb/ptp_clock/test_ptp_clock.py @@ -367,6 +367,7 @@ def test_ptp_clock(request): parameters['DRIFT_NS'] = 0x0 parameters['DRIFT_FNS'] = 0x0002 parameters['DRIFT_RATE'] = 0x0005 + parameters['PIPELINE_OUTPUT'] = 0 extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} From 6f2d581d62fa66c7c19ec8cbaf32c0432dbca049 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 27 Mar 2022 23:47:14 -0700 Subject: [PATCH 2/2] Add output pipeline to PTP clock CDC module --- rtl/ptp_clock_cdc.v | 137 ++++++++++++++++++++++--- tb/ptp_clock_cdc/Makefile | 3 + tb/ptp_clock_cdc/test_ptp_clock_cdc.py | 1 + 3 files changed, 126 insertions(+), 15 deletions(-) diff --git a/rtl/ptp_clock_cdc.v b/rtl/ptp_clock_cdc.v index d0b86c980..a284c43ac 100644 --- a/rtl/ptp_clock_cdc.v +++ b/rtl/ptp_clock_cdc.v @@ -37,7 +37,8 @@ module ptp_clock_cdc # parameter NS_WIDTH = 4, parameter FNS_WIDTH = 16, parameter USE_SAMPLE_CLOCK = 1, - parameter LOG_RATE = 3 + parameter LOG_RATE = 3, + parameter PIPELINE_OUTPUT = 0 ) ( input wire input_clk, @@ -115,7 +116,13 @@ reg [FNS_WIDTH-1:0] ts_fns_ovf_reg = {FNS_WIDTH{1'b1}}, ts_fns_ovf_next; reg ts_step_reg = 1'b0, ts_step_next; -reg pps_reg = 0; +reg pps_reg = 1'b0; + +reg [47:0] ts_s_pipe_reg[0:PIPELINE_OUTPUT-1]; +reg [TS_NS_WIDTH-1:0] ts_ns_pipe_reg[0:PIPELINE_OUTPUT-1]; +reg [FNS_WIDTH-1:0] ts_fns_pipe_reg[0:PIPELINE_OUTPUT-1]; +reg ts_step_pipe_reg[0:PIPELINE_OUTPUT-1]; +reg pps_pipe_reg[0:PIPELINE_OUTPUT-1]; reg [PHASE_CNT_WIDTH-1:0] src_phase_reg = {PHASE_CNT_WIDTH{1'b0}}; reg [PHASE_ACC_WIDTH-1:0] dest_phase_reg = {PHASE_ACC_WIDTH{1'b0}}, dest_phase_next; @@ -150,21 +157,90 @@ reg sample_update_sync3_reg = 1'b0; generate -if (TS_WIDTH == 96) begin - assign output_ts[95:48] = ts_s_reg; - assign output_ts[47:46] = 2'b00; - assign output_ts[45:16] = ts_ns_reg; - assign output_ts[15:0] = FNS_WIDTH > 16 ? ts_fns_reg >> (FNS_WIDTH-16) : ts_fns_reg << (16-FNS_WIDTH); -end else if (TS_WIDTH == 64) begin - assign output_ts[63:16] = ts_ns_reg; - assign output_ts[15:0] = FNS_WIDTH > 16 ? ts_fns_reg >> (FNS_WIDTH-16) : ts_fns_reg << (16-FNS_WIDTH); +if (PIPELINE_OUTPUT > 0) begin + + // pipeline + (* shreg_extract = "no" *) + reg [TS_WIDTH-1:0] output_ts_reg[0:PIPELINE_OUTPUT-1]; + (* shreg_extract = "no" *) + reg output_ts_step_reg[0:PIPELINE_OUTPUT-1]; + (* shreg_extract = "no" *) + reg output_pps_reg[0:PIPELINE_OUTPUT-1]; + + assign output_ts = output_ts_reg[PIPELINE_OUTPUT-1]; + assign output_ts_step = output_ts_step_reg[PIPELINE_OUTPUT-1]; + assign output_pps = output_pps_reg[PIPELINE_OUTPUT-1]; + + integer i; + + initial 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; + end + end + + always @(posedge output_clk) begin + if (TS_WIDTH == 96) begin + output_ts_reg[0][95:48] <= ts_s_reg; + output_ts_reg[0][47:46] <= 2'b00; + output_ts_reg[0][45:16] <= ts_ns_reg; + output_ts_reg[0][15:0] <= {ts_fns_reg, 16'd0} >> FNS_WIDTH; + end else if (TS_WIDTH == 64) begin + output_ts_reg[0][63:16] <= ts_ns_reg; + output_ts_reg[0][15:0] <= {ts_fns_reg, 16'd0} >> FNS_WIDTH; + end + + output_ts_step_reg[0] <= ts_step_reg; + output_pps_reg[0] <= pps_reg; + + for (i = 0; i < PIPELINE_OUTPUT-1; i = i + 1) begin + output_ts_reg[i+1] <= output_ts_reg[i]; + output_ts_step_reg[i+1] <= output_ts_step_reg[i]; + output_pps_reg[i+1] <= output_pps_reg[i]; + end + + 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; + end + end + end + +end else begin + + if (TS_WIDTH == 96) begin + assign output_ts[95:48] = ts_s_reg; + assign output_ts[47:46] = 2'b00; + assign output_ts[45:16] = ts_ns_reg; + assign output_ts[15:0] = {ts_fns_reg, 16'd0} >> FNS_WIDTH; + end else if (TS_WIDTH == 64) begin + assign output_ts[63:16] = ts_ns_reg; + assign output_ts[15:0] = {ts_fns_reg, 16'd0} >> FNS_WIDTH; + end + + assign output_ts_step = ts_step_reg; + + assign output_pps = pps_reg; + end endgenerate -assign output_ts_step = ts_step_reg; +integer i; -assign output_pps = pps_reg; +initial begin + 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; + end +end // source PTP clock capture and sync logic reg input_ts_step_reg = 1'b0; @@ -381,9 +457,15 @@ always @(posedge output_clk) begin if (dest_update_reg) begin // capture local TS - dest_ts_s_capt_reg <= ts_s_reg; - dest_ts_ns_capt_reg <= ts_ns_reg; - dest_ts_fns_capt_reg <= ts_fns_reg; + if (PIPELINE_OUTPUT > 0) begin + dest_ts_s_capt_reg <= ts_s_pipe_reg[PIPELINE_OUTPUT-1]; + dest_ts_ns_capt_reg <= ts_ns_pipe_reg[PIPELINE_OUTPUT-1]; + dest_ts_fns_capt_reg <= ts_fns_pipe_reg[PIPELINE_OUTPUT-1]; + end else begin + dest_ts_s_capt_reg <= ts_s_reg; + dest_ts_ns_capt_reg <= ts_ns_reg; + dest_ts_fns_capt_reg <= ts_fns_reg; + end dest_sync_reg <= !dest_sync_reg; ts_capt_valid_reg <= 1'b1; @@ -668,6 +750,23 @@ always @(posedge output_clk) begin pps_reg <= 1'b0; // not currently implemented for 64 bit timestamp format end + // pipeline + if (PIPELINE_OUTPUT > 0) begin + ts_s_pipe_reg[0] <= ts_s_reg; + ts_ns_pipe_reg[0] <= ts_ns_reg; + ts_fns_pipe_reg[0] <= ts_fns_reg; + ts_step_pipe_reg[0] <= ts_step_reg; + pps_pipe_reg[0] <= pps_reg; + + for (i = 0; i < PIPELINE_OUTPUT-1; i = i + 1) begin + ts_s_pipe_reg[i+1] <= ts_s_pipe_reg[i]; + ts_ns_pipe_reg[i+1] <= ts_ns_pipe_reg[i]; + ts_fns_pipe_reg[i+1] <= ts_fns_pipe_reg[i]; + ts_step_pipe_reg[i+1] <= ts_step_pipe_reg[i]; + pps_pipe_reg[i+1] <= pps_pipe_reg[i]; + end + end + if (output_rst) begin period_ns_reg <= 0; period_fns_reg <= 0; @@ -689,6 +788,14 @@ always @(posedge output_clk) begin ptp_lock_count_reg <= 0; 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; + end end end diff --git a/tb/ptp_clock_cdc/Makefile b/tb/ptp_clock_cdc/Makefile index ff4c9f9c4..eac841e16 100644 --- a/tb/ptp_clock_cdc/Makefile +++ b/tb/ptp_clock_cdc/Makefile @@ -37,6 +37,7 @@ export PARAM_NS_WIDTH ?= 4 export PARAM_FNS_WIDTH ?= 16 export PARAM_USE_SAMPLE_CLOCK ?= 1 export PARAM_LOG_RATE ?= 3 +export PARAM_PIPELINE_OUTPUT ?= 0 ifeq ($(SIM), icarus) PLUSARGS += -fst @@ -46,6 +47,7 @@ ifeq ($(SIM), icarus) COMPILE_ARGS += -P $(TOPLEVEL).FNS_WIDTH=$(PARAM_FNS_WIDTH) COMPILE_ARGS += -P $(TOPLEVEL).USE_SAMPLE_CLOCK=$(PARAM_USE_SAMPLE_CLOCK) COMPILE_ARGS += -P $(TOPLEVEL).LOG_RATE=$(PARAM_LOG_RATE) + COMPILE_ARGS += -P $(TOPLEVEL).PIPELINE_OUTPUT=$(PARAM_PIPELINE_OUTPUT) ifeq ($(WAVES), 1) VERILOG_SOURCES += iverilog_dump.v @@ -59,6 +61,7 @@ else ifeq ($(SIM), verilator) COMPILE_ARGS += -GFNS_WIDTH=$(PARAM_FNS_WIDTH) COMPILE_ARGS += -GUSE_SAMPLE_CLOCK=$(PARAM_USE_SAMPLE_CLOCK) COMPILE_ARGS += -GLOG_RATE=$(PARAM_LOG_RATE) + COMPILE_ARGS += -GPIPELINE_OUTPUT=$(PARAM_PIPELINE_OUTPUT) ifeq ($(WAVES), 1) COMPILE_ARGS += --trace-fst diff --git a/tb/ptp_clock_cdc/test_ptp_clock_cdc.py b/tb/ptp_clock_cdc/test_ptp_clock_cdc.py index f3a26f95f..66cfd37a6 100644 --- a/tb/ptp_clock_cdc/test_ptp_clock_cdc.py +++ b/tb/ptp_clock_cdc/test_ptp_clock_cdc.py @@ -247,6 +247,7 @@ def test_ptp_clock_cdc(request, ts_width, sample_clock): parameters['FNS_WIDTH'] = 16 parameters['USE_SAMPLE_CLOCK'] = sample_clock parameters['LOG_RATE'] = 3 + parameters['PIPELINE_OUTPUT'] = 0 extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()}