mirror of
https://github.com/corundum/corundum.git
synced 2025-01-16 08:12:53 +08:00
merged changes in eth
This commit is contained in:
commit
c9fc3473c1
@ -662,6 +662,8 @@ always @(posedge clk) begin
|
|||||||
|
|
||||||
swap_lanes_reg <= swap_lanes_next;
|
swap_lanes_reg <= swap_lanes_next;
|
||||||
|
|
||||||
|
frame_min_count_reg <= frame_min_count_next;
|
||||||
|
|
||||||
ifg_count_reg <= ifg_count_next;
|
ifg_count_reg <= ifg_count_next;
|
||||||
deficit_idle_count_reg <= deficit_idle_count_next;
|
deficit_idle_count_reg <= deficit_idle_count_next;
|
||||||
|
|
||||||
|
@ -55,7 +55,6 @@ module eth_mac_10g_fifo #
|
|||||||
parameter RX_DROP_WHEN_FULL = RX_DROP_OVERSIZE_FRAME,
|
parameter RX_DROP_WHEN_FULL = RX_DROP_OVERSIZE_FRAME,
|
||||||
parameter PTP_PERIOD_NS = 4'h6,
|
parameter PTP_PERIOD_NS = 4'h6,
|
||||||
parameter PTP_PERIOD_FNS = 16'h6666,
|
parameter PTP_PERIOD_FNS = 16'h6666,
|
||||||
parameter PTP_USE_SAMPLE_CLOCK = 0,
|
|
||||||
parameter TX_PTP_TS_ENABLE = 0,
|
parameter TX_PTP_TS_ENABLE = 0,
|
||||||
parameter RX_PTP_TS_ENABLE = TX_PTP_TS_ENABLE,
|
parameter RX_PTP_TS_ENABLE = TX_PTP_TS_ENABLE,
|
||||||
parameter TX_PTP_TS_CTRL_IN_TUSER = 0,
|
parameter TX_PTP_TS_CTRL_IN_TUSER = 0,
|
||||||
@ -228,9 +227,7 @@ if (TX_PTP_TS_ENABLE) begin : tx_ptp
|
|||||||
|
|
||||||
ptp_clock_cdc #(
|
ptp_clock_cdc #(
|
||||||
.TS_WIDTH(PTP_TS_WIDTH),
|
.TS_WIDTH(PTP_TS_WIDTH),
|
||||||
.NS_WIDTH(6),
|
.NS_WIDTH(6)
|
||||||
.FNS_WIDTH(16),
|
|
||||||
.USE_SAMPLE_CLOCK(PTP_USE_SAMPLE_CLOCK)
|
|
||||||
)
|
)
|
||||||
tx_ptp_cdc (
|
tx_ptp_cdc (
|
||||||
.input_clk(logic_clk),
|
.input_clk(logic_clk),
|
||||||
@ -305,9 +302,7 @@ if (RX_PTP_TS_ENABLE) begin : rx_ptp
|
|||||||
|
|
||||||
ptp_clock_cdc #(
|
ptp_clock_cdc #(
|
||||||
.TS_WIDTH(PTP_TS_WIDTH),
|
.TS_WIDTH(PTP_TS_WIDTH),
|
||||||
.NS_WIDTH(6),
|
.NS_WIDTH(6)
|
||||||
.FNS_WIDTH(16),
|
|
||||||
.USE_SAMPLE_CLOCK(PTP_USE_SAMPLE_CLOCK)
|
|
||||||
)
|
)
|
||||||
rx_ptp_cdc (
|
rx_ptp_cdc (
|
||||||
.input_clk(logic_clk),
|
.input_clk(logic_clk),
|
||||||
|
@ -63,7 +63,6 @@ module eth_mac_phy_10g_fifo #
|
|||||||
parameter RX_DROP_WHEN_FULL = RX_DROP_OVERSIZE_FRAME,
|
parameter RX_DROP_WHEN_FULL = RX_DROP_OVERSIZE_FRAME,
|
||||||
parameter PTP_PERIOD_NS = 4'h6,
|
parameter PTP_PERIOD_NS = 4'h6,
|
||||||
parameter PTP_PERIOD_FNS = 16'h6666,
|
parameter PTP_PERIOD_FNS = 16'h6666,
|
||||||
parameter PTP_USE_SAMPLE_CLOCK = 0,
|
|
||||||
parameter TX_PTP_TS_ENABLE = 0,
|
parameter TX_PTP_TS_ENABLE = 0,
|
||||||
parameter RX_PTP_TS_ENABLE = TX_PTP_TS_ENABLE,
|
parameter RX_PTP_TS_ENABLE = TX_PTP_TS_ENABLE,
|
||||||
parameter TX_PTP_TS_CTRL_IN_TUSER = 0,
|
parameter TX_PTP_TS_CTRL_IN_TUSER = 0,
|
||||||
@ -257,9 +256,7 @@ if (TX_PTP_TS_ENABLE) begin : tx_ptp
|
|||||||
|
|
||||||
ptp_clock_cdc #(
|
ptp_clock_cdc #(
|
||||||
.TS_WIDTH(PTP_TS_WIDTH),
|
.TS_WIDTH(PTP_TS_WIDTH),
|
||||||
.NS_WIDTH(6),
|
.NS_WIDTH(6)
|
||||||
.FNS_WIDTH(16),
|
|
||||||
.USE_SAMPLE_CLOCK(PTP_USE_SAMPLE_CLOCK)
|
|
||||||
)
|
)
|
||||||
tx_ptp_cdc (
|
tx_ptp_cdc (
|
||||||
.input_clk(logic_clk),
|
.input_clk(logic_clk),
|
||||||
@ -334,9 +331,7 @@ if (RX_PTP_TS_ENABLE) begin : rx_ptp
|
|||||||
|
|
||||||
ptp_clock_cdc #(
|
ptp_clock_cdc #(
|
||||||
.TS_WIDTH(PTP_TS_WIDTH),
|
.TS_WIDTH(PTP_TS_WIDTH),
|
||||||
.NS_WIDTH(6),
|
.NS_WIDTH(6)
|
||||||
.FNS_WIDTH(16),
|
|
||||||
.USE_SAMPLE_CLOCK(PTP_USE_SAMPLE_CLOCK)
|
|
||||||
)
|
)
|
||||||
rx_ptp_cdc (
|
rx_ptp_cdc (
|
||||||
.input_clk(logic_clk),
|
.input_clk(logic_clk),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright (c) 2019-2021 Alex Forencich
|
Copyright (c) 2019-2023 Alex Forencich
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -25,7 +25,7 @@ THE SOFTWARE.
|
|||||||
// Language: Verilog 2001
|
// Language: Verilog 2001
|
||||||
|
|
||||||
`resetall
|
`resetall
|
||||||
`timescale 1ns / 1ps
|
`timescale 1ns / 1fs
|
||||||
`default_nettype none
|
`default_nettype none
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -35,8 +35,6 @@ module ptp_clock_cdc #
|
|||||||
(
|
(
|
||||||
parameter TS_WIDTH = 96,
|
parameter TS_WIDTH = 96,
|
||||||
parameter NS_WIDTH = 4,
|
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
|
parameter PIPELINE_OUTPUT = 0
|
||||||
)
|
)
|
||||||
@ -78,55 +76,56 @@ initial begin
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
parameter TS_NS_WIDTH = TS_WIDTH == 96 ? 30 : 48;
|
localparam FNS_WIDTH = 16;
|
||||||
|
|
||||||
parameter PHASE_CNT_WIDTH = LOG_RATE;
|
localparam TS_NS_WIDTH = TS_WIDTH == 96 ? 30 : 48;
|
||||||
parameter PHASE_ACC_WIDTH = PHASE_CNT_WIDTH+16;
|
localparam TS_FNS_WIDTH = FNS_WIDTH > 16 ? 16 : FNS_WIDTH;
|
||||||
|
|
||||||
parameter LOG_SAMPLE_SYNC_RATE = LOG_RATE;
|
localparam CMP_FNS_WIDTH = 4;
|
||||||
parameter SAMPLE_ACC_WIDTH = LOG_SAMPLE_SYNC_RATE+2;
|
|
||||||
|
|
||||||
parameter DEST_SYNC_LOCK_WIDTH = 7;
|
localparam PHASE_CNT_WIDTH = LOG_RATE;
|
||||||
parameter PTP_LOCK_WIDTH = 8;
|
localparam PHASE_ACC_WIDTH = PHASE_CNT_WIDTH+16;
|
||||||
|
|
||||||
|
localparam LOG_SAMPLE_SYNC_RATE = LOG_RATE;
|
||||||
|
localparam SAMPLE_ACC_WIDTH = LOG_SAMPLE_SYNC_RATE+2;
|
||||||
|
|
||||||
|
localparam LOG_PHASE_ERR_RATE = 4;
|
||||||
|
localparam PHASE_ERR_ACC_WIDTH = LOG_PHASE_ERR_RATE+2;
|
||||||
|
|
||||||
|
localparam DEST_SYNC_LOCK_WIDTH = 7;
|
||||||
|
localparam FREQ_LOCK_WIDTH = 8;
|
||||||
|
localparam PTP_LOCK_WIDTH = 8;
|
||||||
|
|
||||||
|
localparam TIME_ERR_INT_WIDTH = NS_WIDTH+FNS_WIDTH;
|
||||||
|
|
||||||
localparam [30:0] NS_PER_S = 31'd1_000_000_000;
|
localparam [30:0] NS_PER_S = 31'd1_000_000_000;
|
||||||
|
|
||||||
reg [NS_WIDTH-1:0] period_ns_reg = 0, period_ns_next;
|
reg [NS_WIDTH+FNS_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+FNS_WIDTH-1:0] period_ns_delay_reg = 0, period_ns_delay_next;
|
||||||
reg [NS_WIDTH-1:0] period_ns_delay_reg = 0, period_ns_delay_next;
|
reg [31+FNS_WIDTH-1:0] period_ns_ovf_reg = 0, period_ns_ovf_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 [47:0] src_ts_s_capt_reg = 0;
|
||||||
reg [TS_NS_WIDTH-1:0] src_ts_ns_capt_reg = 0;
|
reg [TS_NS_WIDTH+CMP_FNS_WIDTH-1:0] src_ts_ns_capt_reg = 0;
|
||||||
reg [FNS_WIDTH-1:0] src_ts_fns_capt_reg = 0;
|
|
||||||
reg src_ts_step_capt_reg = 0;
|
reg src_ts_step_capt_reg = 0;
|
||||||
|
|
||||||
reg [47:0] dest_ts_s_capt_reg = 0;
|
reg [47:0] dest_ts_s_capt_reg = 0;
|
||||||
reg [TS_NS_WIDTH-1:0] dest_ts_ns_capt_reg = 0;
|
reg [TS_NS_WIDTH+CMP_FNS_WIDTH-1:0] dest_ts_ns_capt_reg = 0;
|
||||||
reg [FNS_WIDTH-1:0] dest_ts_fns_capt_reg = 0;
|
|
||||||
|
|
||||||
reg [47:0] ts_s_sync_reg = 0;
|
reg [47:0] src_ts_s_sync_reg = 0;
|
||||||
reg [TS_NS_WIDTH-1:0] ts_ns_sync_reg = 0;
|
reg [TS_NS_WIDTH+CMP_FNS_WIDTH-1:0] src_ts_ns_sync_reg = 0;
|
||||||
reg [FNS_WIDTH-1:0] ts_fns_sync_reg = 0;
|
reg src_ts_step_sync_reg = 0;
|
||||||
reg ts_step_sync_reg = 0;
|
|
||||||
|
|
||||||
reg [47:0] ts_s_reg = 0, ts_s_next;
|
reg [47:0] ts_s_reg = 0, ts_s_next;
|
||||||
reg [TS_NS_WIDTH-1:0] ts_ns_reg = 0, ts_ns_next;
|
reg [TS_NS_WIDTH+FNS_WIDTH-1:0] ts_ns_reg = 0, ts_ns_next;
|
||||||
reg [FNS_WIDTH-1:0] ts_fns_reg = 0, ts_fns_next;
|
reg [TS_NS_WIDTH+FNS_WIDTH-1:0] ts_ns_inc_reg = 0, ts_ns_inc_next;
|
||||||
reg [TS_NS_WIDTH-1:0] ts_ns_inc_reg = 0, ts_ns_inc_next;
|
reg [TS_NS_WIDTH+FNS_WIDTH+1-1:0] ts_ns_ovf_reg = {TS_NS_WIDTH+FNS_WIDTH+1{1'b1}}, ts_ns_ovf_next;
|
||||||
reg [FNS_WIDTH-1:0] ts_fns_inc_reg = 0, ts_fns_inc_next;
|
|
||||||
reg [TS_NS_WIDTH+1-1:0] ts_ns_ovf_reg = {TS_NS_WIDTH+1{1'b1}}, ts_ns_ovf_next;
|
|
||||||
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 ts_step_reg = 1'b0, ts_step_next;
|
||||||
|
|
||||||
reg pps_reg = 1'b0;
|
reg pps_reg = 1'b0;
|
||||||
|
|
||||||
reg [47:0] ts_s_pipe_reg[0:PIPELINE_OUTPUT-1];
|
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 [TS_NS_WIDTH+CMP_FNS_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 ts_step_pipe_reg[0:PIPELINE_OUTPUT-1];
|
||||||
reg pps_pipe_reg[0:PIPELINE_OUTPUT-1];
|
reg pps_pipe_reg[0:PIPELINE_OUTPUT-1];
|
||||||
|
|
||||||
@ -136,15 +135,20 @@ reg [PHASE_ACC_WIDTH-1:0] dest_phase_inc_reg = {PHASE_ACC_WIDTH{1'b0}}, dest_pha
|
|||||||
|
|
||||||
reg src_sync_reg = 1'b0;
|
reg src_sync_reg = 1'b0;
|
||||||
reg src_update_reg = 1'b0;
|
reg src_update_reg = 1'b0;
|
||||||
reg dest_sync_reg = 1'b0, dest_sync_next = 1'b0;
|
reg src_phase_sync_reg = 1'b0;
|
||||||
|
reg dest_sync_reg = 1'b0;
|
||||||
reg dest_update_reg = 1'b0, dest_update_next = 1'b0;
|
reg dest_update_reg = 1'b0, dest_update_next = 1'b0;
|
||||||
|
reg dest_phase_sync_reg = 1'b0;
|
||||||
|
|
||||||
reg src_sync_sync1_reg = 1'b0;
|
reg src_sync_sync1_reg = 1'b0;
|
||||||
reg src_sync_sync2_reg = 1'b0;
|
reg src_sync_sync2_reg = 1'b0;
|
||||||
reg src_sync_sync3_reg = 1'b0;
|
reg src_sync_sync3_reg = 1'b0;
|
||||||
reg dest_sync_sync1_reg = 1'b0;
|
reg src_phase_sync_sync1_reg = 1'b0;
|
||||||
reg dest_sync_sync2_reg = 1'b0;
|
reg src_phase_sync_sync2_reg = 1'b0;
|
||||||
reg dest_sync_sync3_reg = 1'b0;
|
reg src_phase_sync_sync3_reg = 1'b0;
|
||||||
|
reg dest_phase_sync_sync1_reg = 1'b0;
|
||||||
|
reg dest_phase_sync_sync2_reg = 1'b0;
|
||||||
|
reg dest_phase_sync_sync3_reg = 1'b0;
|
||||||
|
|
||||||
reg src_sync_sample_sync1_reg = 1'b0;
|
reg src_sync_sample_sync1_reg = 1'b0;
|
||||||
reg src_sync_sample_sync2_reg = 1'b0;
|
reg src_sync_sample_sync2_reg = 1'b0;
|
||||||
@ -153,7 +157,7 @@ reg dest_sync_sample_sync1_reg = 1'b0;
|
|||||||
reg dest_sync_sample_sync2_reg = 1'b0;
|
reg dest_sync_sample_sync2_reg = 1'b0;
|
||||||
reg dest_sync_sample_sync3_reg = 1'b0;
|
reg dest_sync_sample_sync3_reg = 1'b0;
|
||||||
|
|
||||||
reg [SAMPLE_ACC_WIDTH-1:0] sample_acc_reg = 0, sample_acc_next = 0;
|
reg [SAMPLE_ACC_WIDTH-1:0] sample_acc_reg = 0;
|
||||||
reg [SAMPLE_ACC_WIDTH-1:0] sample_acc_out_reg = 0;
|
reg [SAMPLE_ACC_WIDTH-1:0] sample_acc_out_reg = 0;
|
||||||
reg [LOG_SAMPLE_SYNC_RATE-1:0] sample_cnt_reg = 0;
|
reg [LOG_SAMPLE_SYNC_RATE-1:0] sample_cnt_reg = 0;
|
||||||
reg sample_update_reg = 1'b0;
|
reg sample_update_reg = 1'b0;
|
||||||
@ -191,11 +195,9 @@ if (PIPELINE_OUTPUT > 0) begin
|
|||||||
if (TS_WIDTH == 96) begin
|
if (TS_WIDTH == 96) begin
|
||||||
output_ts_reg[0][95:48] <= ts_s_reg;
|
output_ts_reg[0][95:48] <= ts_s_reg;
|
||||||
output_ts_reg[0][47:46] <= 2'b00;
|
output_ts_reg[0][47:46] <= 2'b00;
|
||||||
output_ts_reg[0][45:16] <= ts_ns_reg;
|
output_ts_reg[0][45:0] <= {ts_ns_reg, 16'd0} >> FNS_WIDTH;
|
||||||
output_ts_reg[0][15:0] <= {ts_fns_reg, 16'd0} >> FNS_WIDTH;
|
|
||||||
end else if (TS_WIDTH == 64) begin
|
end else if (TS_WIDTH == 64) begin
|
||||||
output_ts_reg[0][63:16] <= ts_ns_reg;
|
output_ts_reg[0] <= {ts_ns_reg, 16'd0} >> FNS_WIDTH;
|
||||||
output_ts_reg[0][15:0] <= {ts_fns_reg, 16'd0} >> FNS_WIDTH;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
output_ts_step_reg[0] <= ts_step_reg;
|
output_ts_step_reg[0] <= ts_step_reg;
|
||||||
@ -221,11 +223,9 @@ end else begin
|
|||||||
if (TS_WIDTH == 96) begin
|
if (TS_WIDTH == 96) begin
|
||||||
assign output_ts[95:48] = ts_s_reg;
|
assign output_ts[95:48] = ts_s_reg;
|
||||||
assign output_ts[47:46] = 2'b00;
|
assign output_ts[47:46] = 2'b00;
|
||||||
assign output_ts[45:16] = ts_ns_reg;
|
assign output_ts[45:0] = {ts_ns_reg, 16'd0} >> FNS_WIDTH;
|
||||||
assign output_ts[15:0] = {ts_fns_reg, 16'd0} >> FNS_WIDTH;
|
|
||||||
end else if (TS_WIDTH == 64) begin
|
end else if (TS_WIDTH == 64) begin
|
||||||
assign output_ts[63:16] = ts_ns_reg;
|
assign output_ts = {ts_ns_reg, 16'd0} >> FNS_WIDTH;
|
||||||
assign output_ts[15:0] = {ts_fns_reg, 16'd0} >> FNS_WIDTH;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
assign output_ts_step = ts_step_reg;
|
assign output_ts_step = ts_step_reg;
|
||||||
@ -242,7 +242,6 @@ initial begin
|
|||||||
for (i = 0; i < PIPELINE_OUTPUT; i = i + 1) begin
|
for (i = 0; i < PIPELINE_OUTPUT; i = i + 1) begin
|
||||||
ts_s_pipe_reg[i] = 0;
|
ts_s_pipe_reg[i] = 0;
|
||||||
ts_ns_pipe_reg[i] = 0;
|
ts_ns_pipe_reg[i] = 0;
|
||||||
ts_fns_pipe_reg[i] = 0;
|
|
||||||
ts_step_pipe_reg[i] = 1'b0;
|
ts_step_pipe_reg[i] = 1'b0;
|
||||||
pps_pipe_reg[i] = 1'b0;
|
pps_pipe_reg[i] = 1'b0;
|
||||||
end
|
end
|
||||||
@ -254,17 +253,18 @@ reg input_ts_step_reg = 1'b0;
|
|||||||
always @(posedge input_clk) begin
|
always @(posedge input_clk) begin
|
||||||
input_ts_step_reg <= input_ts_step || input_ts_step_reg;
|
input_ts_step_reg <= input_ts_step || input_ts_step_reg;
|
||||||
|
|
||||||
|
src_phase_sync_reg <= input_ts[16+8];
|
||||||
|
|
||||||
{src_update_reg, src_phase_reg} <= src_phase_reg+1;
|
{src_update_reg, src_phase_reg} <= src_phase_reg+1;
|
||||||
|
|
||||||
if (src_update_reg) begin
|
if (src_update_reg) begin
|
||||||
// capture source TS
|
// capture source TS
|
||||||
if (TS_WIDTH == 96) begin
|
if (TS_WIDTH == 96) begin
|
||||||
src_ts_s_capt_reg <= input_ts[95:48];
|
src_ts_s_capt_reg <= input_ts[95:48];
|
||||||
src_ts_ns_capt_reg <= input_ts[45:16];
|
src_ts_ns_capt_reg <= input_ts[45:0] >> (16-CMP_FNS_WIDTH);
|
||||||
end else begin
|
end else begin
|
||||||
src_ts_ns_capt_reg <= input_ts[63:16];
|
src_ts_ns_capt_reg <= input_ts >> (16-CMP_FNS_WIDTH);
|
||||||
end
|
end
|
||||||
src_ts_fns_capt_reg <= FNS_WIDTH > 16 ? input_ts[15:0] << (FNS_WIDTH-16) : input_ts[15:0] >> (16-FNS_WIDTH);
|
|
||||||
src_ts_step_capt_reg <= input_ts_step || input_ts_step_reg;
|
src_ts_step_capt_reg <= input_ts_step || input_ts_step_reg;
|
||||||
input_ts_step_reg <= 1'b0;
|
input_ts_step_reg <= 1'b0;
|
||||||
src_sync_reg <= !src_sync_reg;
|
src_sync_reg <= !src_sync_reg;
|
||||||
@ -284,9 +284,12 @@ always @(posedge output_clk) begin
|
|||||||
src_sync_sync1_reg <= src_sync_reg;
|
src_sync_sync1_reg <= src_sync_reg;
|
||||||
src_sync_sync2_reg <= src_sync_sync1_reg;
|
src_sync_sync2_reg <= src_sync_sync1_reg;
|
||||||
src_sync_sync3_reg <= src_sync_sync2_reg;
|
src_sync_sync3_reg <= src_sync_sync2_reg;
|
||||||
dest_sync_sync1_reg <= dest_sync_reg;
|
src_phase_sync_sync1_reg <= src_phase_sync_reg;
|
||||||
dest_sync_sync2_reg <= dest_sync_sync1_reg;
|
src_phase_sync_sync2_reg <= src_phase_sync_sync1_reg;
|
||||||
dest_sync_sync3_reg <= dest_sync_sync2_reg;
|
src_phase_sync_sync3_reg <= src_phase_sync_sync2_reg;
|
||||||
|
dest_phase_sync_sync1_reg <= dest_phase_sync_reg;
|
||||||
|
dest_phase_sync_sync2_reg <= dest_phase_sync_sync1_reg;
|
||||||
|
dest_phase_sync_sync3_reg <= dest_phase_sync_sync2_reg;
|
||||||
end
|
end
|
||||||
|
|
||||||
always @(posedge sample_clk) begin
|
always @(posedge sample_clk) begin
|
||||||
@ -304,37 +307,35 @@ reg edge_2_reg = 1'b0;
|
|||||||
reg [3:0] active_reg = 0;
|
reg [3:0] active_reg = 0;
|
||||||
|
|
||||||
always @(posedge sample_clk) begin
|
always @(posedge sample_clk) begin
|
||||||
if (USE_SAMPLE_CLOCK) begin
|
// phase and frequency detector
|
||||||
// phase and frequency detector
|
if (dest_sync_sample_sync2_reg && !dest_sync_sample_sync3_reg) begin
|
||||||
if (dest_sync_sample_sync2_reg && !dest_sync_sample_sync3_reg) begin
|
|
||||||
if (src_sync_sample_sync2_reg && !src_sync_sample_sync3_reg) begin
|
|
||||||
edge_1_reg <= 1'b0;
|
|
||||||
edge_2_reg <= 1'b0;
|
|
||||||
end else begin
|
|
||||||
edge_1_reg <= !edge_2_reg;
|
|
||||||
edge_2_reg <= 1'b0;
|
|
||||||
end
|
|
||||||
end else if (src_sync_sample_sync2_reg && !src_sync_sample_sync3_reg) begin
|
|
||||||
edge_1_reg <= 1'b0;
|
|
||||||
edge_2_reg <= !edge_1_reg;
|
|
||||||
end
|
|
||||||
|
|
||||||
// accumulator
|
|
||||||
sample_acc_reg <= $signed(sample_acc_reg) + $signed({1'b0, edge_2_reg}) - $signed({1'b0, edge_1_reg});
|
|
||||||
|
|
||||||
sample_cnt_reg <= sample_cnt_reg + 1;
|
|
||||||
|
|
||||||
if (src_sync_sample_sync2_reg && !src_sync_sample_sync3_reg) begin
|
if (src_sync_sample_sync2_reg && !src_sync_sample_sync3_reg) begin
|
||||||
active_reg[0] <= 1'b1;
|
edge_1_reg <= 1'b0;
|
||||||
|
edge_2_reg <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
edge_1_reg <= !edge_2_reg;
|
||||||
|
edge_2_reg <= 1'b0;
|
||||||
end
|
end
|
||||||
|
end else if (src_sync_sample_sync2_reg && !src_sync_sample_sync3_reg) begin
|
||||||
|
edge_1_reg <= 1'b0;
|
||||||
|
edge_2_reg <= !edge_1_reg;
|
||||||
|
end
|
||||||
|
|
||||||
if (sample_cnt_reg == 0) begin
|
// accumulator
|
||||||
active_reg <= {active_reg, src_sync_sample_sync2_reg && !src_sync_sample_sync3_reg};
|
sample_acc_reg <= $signed(sample_acc_reg) + $signed({1'b0, edge_2_reg}) - $signed({1'b0, edge_1_reg});
|
||||||
sample_acc_reg <= $signed({1'b0, edge_2_reg}) - $signed({1'b0, edge_1_reg});
|
|
||||||
sample_acc_out_reg <= sample_acc_reg;
|
sample_cnt_reg <= sample_cnt_reg + 1;
|
||||||
if (active_reg != 0) begin
|
|
||||||
sample_update_reg <= !sample_update_reg;
|
if (src_sync_sample_sync2_reg && !src_sync_sample_sync3_reg) begin
|
||||||
end
|
active_reg[0] <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (sample_cnt_reg == 0) begin
|
||||||
|
active_reg <= {active_reg, src_sync_sample_sync2_reg && !src_sync_sample_sync3_reg};
|
||||||
|
sample_acc_reg <= $signed({1'b0, edge_2_reg}) - $signed({1'b0, edge_1_reg});
|
||||||
|
sample_acc_out_reg <= sample_acc_reg;
|
||||||
|
if (active_reg != 0) begin
|
||||||
|
sample_update_reg <= !sample_update_reg;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -348,50 +349,6 @@ end
|
|||||||
reg [SAMPLE_ACC_WIDTH-1:0] sample_acc_sync_reg = 0;
|
reg [SAMPLE_ACC_WIDTH-1:0] sample_acc_sync_reg = 0;
|
||||||
reg sample_acc_sync_valid_reg = 0;
|
reg sample_acc_sync_valid_reg = 0;
|
||||||
|
|
||||||
always @(posedge output_clk) begin
|
|
||||||
if (USE_SAMPLE_CLOCK) begin
|
|
||||||
// latch in synchronized counts from phase detector
|
|
||||||
sample_acc_sync_valid_reg <= 1'b0;
|
|
||||||
if (sample_update_sync2_reg ^ sample_update_sync3_reg) begin
|
|
||||||
sample_acc_sync_reg <= sample_acc_out_reg;
|
|
||||||
sample_acc_sync_valid_reg <= 1'b1;
|
|
||||||
end
|
|
||||||
end else begin
|
|
||||||
// phase and frequency detector
|
|
||||||
if (dest_sync_sync2_reg && !dest_sync_sync3_reg) begin
|
|
||||||
if (src_sync_sync2_reg && !src_sync_sync3_reg) begin
|
|
||||||
edge_1_reg <= 1'b0;
|
|
||||||
edge_2_reg <= 1'b0;
|
|
||||||
end else begin
|
|
||||||
edge_1_reg <= !edge_2_reg;
|
|
||||||
edge_2_reg <= 1'b0;
|
|
||||||
end
|
|
||||||
end else if (src_sync_sync2_reg && !src_sync_sync3_reg) begin
|
|
||||||
edge_1_reg <= 1'b0;
|
|
||||||
edge_2_reg <= !edge_1_reg;
|
|
||||||
end
|
|
||||||
|
|
||||||
// accumulator
|
|
||||||
sample_acc_reg <= $signed(sample_acc_reg) + $signed({1'b0, edge_2_reg}) - $signed({1'b0, edge_1_reg});
|
|
||||||
|
|
||||||
sample_cnt_reg <= sample_cnt_reg + 1;
|
|
||||||
|
|
||||||
if (src_sync_sync2_reg && !src_sync_sync3_reg) begin
|
|
||||||
active_reg[0] <= 1'b1;
|
|
||||||
end
|
|
||||||
|
|
||||||
sample_acc_sync_valid_reg <= 1'b0;
|
|
||||||
if (sample_cnt_reg == 0) begin
|
|
||||||
active_reg <= {active_reg, src_sync_sync2_reg && !src_sync_sync3_reg};
|
|
||||||
sample_acc_reg <= $signed({1'b0, edge_2_reg}) - $signed({1'b0, edge_1_reg});
|
|
||||||
sample_acc_sync_reg <= sample_acc_reg;
|
|
||||||
if (active_reg != 0) begin
|
|
||||||
sample_acc_sync_valid_reg <= 1'b1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
reg [PHASE_ACC_WIDTH-1:0] dest_err_int_reg = 0, dest_err_int_next = 0;
|
reg [PHASE_ACC_WIDTH-1:0] dest_err_int_reg = 0, dest_err_int_next = 0;
|
||||||
reg [1:0] dest_ovf;
|
reg [1:0] dest_ovf;
|
||||||
|
|
||||||
@ -456,6 +413,16 @@ always @* begin
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
reg [PHASE_ERR_ACC_WIDTH-1:0] phase_err_acc_reg = 0;
|
||||||
|
reg [PHASE_ERR_ACC_WIDTH-1:0] phase_err_out_reg = 0;
|
||||||
|
reg [LOG_PHASE_ERR_RATE-1:0] phase_err_cnt_reg = 0;
|
||||||
|
reg phase_err_out_valid_reg = 0;
|
||||||
|
|
||||||
|
reg phase_edge_1_reg = 1'b0;
|
||||||
|
reg phase_edge_2_reg = 1'b0;
|
||||||
|
|
||||||
|
reg [5:0] phase_active_reg = 0;
|
||||||
|
|
||||||
reg ts_sync_valid_reg = 1'b0;
|
reg ts_sync_valid_reg = 1'b0;
|
||||||
reg ts_capt_valid_reg = 1'b0;
|
reg ts_capt_valid_reg = 1'b0;
|
||||||
|
|
||||||
@ -464,16 +431,60 @@ always @(posedge output_clk) begin
|
|||||||
dest_phase_inc_reg <= dest_phase_inc_next;
|
dest_phase_inc_reg <= dest_phase_inc_next;
|
||||||
dest_update_reg <= dest_update_next;
|
dest_update_reg <= dest_update_next;
|
||||||
|
|
||||||
|
sample_acc_sync_valid_reg <= 1'b0;
|
||||||
|
if (sample_update_sync2_reg ^ sample_update_sync3_reg) begin
|
||||||
|
// latch in synchronized counts from phase detector
|
||||||
|
sample_acc_sync_reg <= sample_acc_out_reg;
|
||||||
|
sample_acc_sync_valid_reg <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (PIPELINE_OUTPUT > 0) begin
|
||||||
|
dest_phase_sync_reg <= ts_ns_pipe_reg[PIPELINE_OUTPUT-1][8+FNS_WIDTH];
|
||||||
|
end else begin
|
||||||
|
dest_phase_sync_reg <= ts_ns_reg[8+FNS_WIDTH];
|
||||||
|
end
|
||||||
|
|
||||||
|
// phase and frequency detector
|
||||||
|
if (dest_phase_sync_sync2_reg && !dest_phase_sync_sync3_reg) begin
|
||||||
|
if (src_phase_sync_sync2_reg && !src_phase_sync_sync3_reg) begin
|
||||||
|
phase_edge_1_reg <= 1'b0;
|
||||||
|
phase_edge_2_reg <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
phase_edge_1_reg <= !phase_edge_2_reg;
|
||||||
|
phase_edge_2_reg <= 1'b0;
|
||||||
|
end
|
||||||
|
end else if (src_phase_sync_sync2_reg && !src_phase_sync_sync3_reg) begin
|
||||||
|
phase_edge_1_reg <= 1'b0;
|
||||||
|
phase_edge_2_reg <= !phase_edge_1_reg;
|
||||||
|
end
|
||||||
|
|
||||||
|
// accumulator
|
||||||
|
phase_err_acc_reg <= $signed(phase_err_acc_reg) + $signed({1'b0, phase_edge_2_reg}) - $signed({1'b0, phase_edge_1_reg});
|
||||||
|
|
||||||
|
phase_err_cnt_reg <= phase_err_cnt_reg + 1;
|
||||||
|
|
||||||
|
if (src_phase_sync_sync2_reg && !src_phase_sync_sync3_reg) begin
|
||||||
|
phase_active_reg[0] <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
phase_err_out_valid_reg <= 1'b0;
|
||||||
|
if (phase_err_cnt_reg == 0) begin
|
||||||
|
phase_active_reg <= {phase_active_reg, src_phase_sync_sync2_reg && !src_phase_sync_sync3_reg};
|
||||||
|
phase_err_acc_reg <= $signed({1'b0, phase_edge_2_reg}) - $signed({1'b0, phase_edge_1_reg});
|
||||||
|
phase_err_out_reg <= phase_err_acc_reg;
|
||||||
|
if (phase_active_reg != 0) begin
|
||||||
|
phase_err_out_valid_reg <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if (dest_update_reg) begin
|
if (dest_update_reg) begin
|
||||||
// capture local TS
|
// capture local TS
|
||||||
if (PIPELINE_OUTPUT > 0) begin
|
if (PIPELINE_OUTPUT > 0) begin
|
||||||
dest_ts_s_capt_reg <= ts_s_pipe_reg[PIPELINE_OUTPUT-1];
|
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_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
|
end else begin
|
||||||
dest_ts_s_capt_reg <= ts_s_reg;
|
dest_ts_s_capt_reg <= ts_s_reg;
|
||||||
dest_ts_ns_capt_reg <= ts_ns_reg;
|
dest_ts_ns_capt_reg <= ts_ns_reg >> FNS_WIDTH-CMP_FNS_WIDTH;
|
||||||
dest_ts_fns_capt_reg <= ts_fns_reg;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
dest_sync_reg <= !dest_sync_reg;
|
dest_sync_reg <= !dest_sync_reg;
|
||||||
@ -485,11 +496,10 @@ always @(posedge output_clk) begin
|
|||||||
if (src_sync_sync2_reg ^ src_sync_sync3_reg) begin
|
if (src_sync_sync2_reg ^ src_sync_sync3_reg) begin
|
||||||
// store captured source TS
|
// store captured source TS
|
||||||
if (TS_WIDTH == 96) begin
|
if (TS_WIDTH == 96) begin
|
||||||
ts_s_sync_reg <= src_ts_s_capt_reg;
|
src_ts_s_sync_reg <= src_ts_s_capt_reg;
|
||||||
end
|
end
|
||||||
ts_ns_sync_reg <= src_ts_ns_capt_reg;
|
src_ts_ns_sync_reg <= src_ts_ns_capt_reg;
|
||||||
ts_fns_sync_reg <= src_ts_fns_capt_reg;
|
src_ts_step_sync_reg <= src_ts_step_capt_reg;
|
||||||
ts_step_sync_reg <= src_ts_step_capt_reg;
|
|
||||||
|
|
||||||
ts_sync_valid_reg <= ts_capt_valid_reg;
|
ts_sync_valid_reg <= ts_capt_valid_reg;
|
||||||
ts_capt_valid_reg <= 1'b0;
|
ts_capt_valid_reg <= 1'b0;
|
||||||
@ -516,172 +526,172 @@ always @(posedge output_clk) begin
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
parameter TIME_ERR_INT_WIDTH = NS_WIDTH+FNS_WIDTH+16;
|
reg ts_diff_reg = 1'b0, ts_diff_next;
|
||||||
|
reg ts_diff_valid_reg = 1'b0, ts_diff_valid_next;
|
||||||
|
reg [3:0] mismatch_cnt_reg = 0, mismatch_cnt_next;
|
||||||
|
reg load_ts_reg = 1'b0, load_ts_next;
|
||||||
|
|
||||||
reg sec_mismatch_reg = 1'b0, sec_mismatch_next;
|
reg [9+CMP_FNS_WIDTH-1:0] ts_ns_diff_reg = 0, ts_ns_diff_next;
|
||||||
reg diff_valid_reg = 1'b0, diff_valid_next;
|
|
||||||
reg diff_corr_valid_reg = 1'b0, diff_corr_valid_next;
|
|
||||||
|
|
||||||
reg ts_s_msb_diff_reg = 1'b0, ts_s_msb_diff_next;
|
|
||||||
reg [7:0] ts_s_diff_reg = 0, ts_s_diff_next;
|
|
||||||
reg [TS_NS_WIDTH+1-1:0] ts_ns_diff_reg = 0, ts_ns_diff_next;
|
|
||||||
reg [FNS_WIDTH-1:0] ts_fns_diff_reg = 0, ts_fns_diff_next;
|
|
||||||
|
|
||||||
reg [16:0] ts_ns_diff_corr_reg = 0, ts_ns_diff_corr_next;
|
|
||||||
reg [FNS_WIDTH-1:0] ts_fns_diff_corr_reg = 0, ts_fns_diff_corr_next;
|
|
||||||
|
|
||||||
reg [TIME_ERR_INT_WIDTH-1:0] time_err_int_reg = 0, time_err_int_next;
|
reg [TIME_ERR_INT_WIDTH-1:0] time_err_int_reg = 0, time_err_int_next;
|
||||||
|
|
||||||
reg [1:0] ptp_ovf;
|
reg [1:0] ptp_ovf;
|
||||||
|
|
||||||
|
reg [FREQ_LOCK_WIDTH-1:0] freq_lock_count_reg = 0, freq_lock_count_next;
|
||||||
|
reg freq_locked_reg = 1'b0, freq_locked_next;
|
||||||
reg [PTP_LOCK_WIDTH-1:0] ptp_lock_count_reg = 0, ptp_lock_count_next;
|
reg [PTP_LOCK_WIDTH-1:0] ptp_lock_count_reg = 0, ptp_lock_count_next;
|
||||||
reg ptp_locked_reg = 1'b0, ptp_locked_next;
|
reg ptp_locked_reg = 1'b0, ptp_locked_next;
|
||||||
|
|
||||||
assign locked = ptp_locked_reg && dest_sync_locked_reg;
|
reg gain_sel_reg = 0, gain_sel_next;
|
||||||
|
|
||||||
|
assign locked = ptp_locked_reg && freq_locked_reg && dest_sync_locked_reg;
|
||||||
|
|
||||||
always @* begin
|
always @* begin
|
||||||
period_ns_next = period_ns_reg;
|
period_ns_next = period_ns_reg;
|
||||||
period_fns_next = period_fns_reg;
|
|
||||||
|
|
||||||
ts_s_next = ts_s_reg;
|
ts_s_next = ts_s_reg;
|
||||||
ts_ns_next = ts_ns_reg;
|
ts_ns_next = ts_ns_reg;
|
||||||
ts_fns_next = ts_fns_reg;
|
|
||||||
ts_ns_inc_next = ts_ns_inc_reg;
|
ts_ns_inc_next = ts_ns_inc_reg;
|
||||||
ts_fns_inc_next = ts_fns_inc_reg;
|
|
||||||
ts_ns_ovf_next = ts_ns_ovf_reg;
|
ts_ns_ovf_next = ts_ns_ovf_reg;
|
||||||
ts_fns_ovf_next = ts_fns_ovf_reg;
|
|
||||||
|
|
||||||
ts_step_next = 0;
|
ts_step_next = 0;
|
||||||
|
|
||||||
diff_valid_next = 1'b0;
|
ts_diff_next = 1'b0;
|
||||||
diff_corr_valid_next = 1'b0;
|
ts_diff_valid_next = 1'b0;
|
||||||
|
mismatch_cnt_next = mismatch_cnt_reg;
|
||||||
|
load_ts_next = load_ts_reg;
|
||||||
|
|
||||||
sec_mismatch_next = sec_mismatch_reg;
|
|
||||||
diff_valid_next = 1'b0;
|
|
||||||
diff_corr_valid_next = 1'b0;
|
|
||||||
|
|
||||||
ts_s_msb_diff_next = ts_s_msb_diff_reg;
|
|
||||||
ts_s_diff_next = ts_s_diff_reg;
|
|
||||||
ts_ns_diff_next = ts_ns_diff_reg;
|
ts_ns_diff_next = ts_ns_diff_reg;
|
||||||
ts_fns_diff_next = ts_fns_diff_reg;
|
|
||||||
|
|
||||||
ts_ns_diff_corr_next = ts_ns_diff_corr_reg;
|
|
||||||
ts_fns_diff_corr_next = ts_fns_diff_corr_reg;
|
|
||||||
|
|
||||||
time_err_int_next = time_err_int_reg;
|
time_err_int_next = time_err_int_reg;
|
||||||
|
|
||||||
|
freq_lock_count_next = freq_lock_count_reg;
|
||||||
|
freq_locked_next = freq_locked_reg;
|
||||||
ptp_lock_count_next = ptp_lock_count_reg;
|
ptp_lock_count_next = ptp_lock_count_reg;
|
||||||
ptp_locked_next = ptp_locked_reg;
|
ptp_locked_next = ptp_locked_reg;
|
||||||
|
|
||||||
|
gain_sel_next = gain_sel_reg;
|
||||||
|
|
||||||
// PTP clock
|
// PTP clock
|
||||||
{period_ns_delay_next, period_fns_delay_next} = {period_ns_reg, period_fns_reg};
|
period_ns_delay_next = period_ns_reg;
|
||||||
{period_ns_ovf_next, period_fns_ovf_next} = {NS_PER_S, {FNS_WIDTH{1'b0}}} - {period_ns_reg, period_fns_reg};
|
period_ns_ovf_next = {NS_PER_S, {FNS_WIDTH{1'b0}}} - period_ns_reg;
|
||||||
|
|
||||||
if (TS_WIDTH == 96) begin
|
if (TS_WIDTH == 96) begin
|
||||||
// 96 bit timestamp
|
// 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_inc_next = ts_ns_inc_reg + period_ns_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_ovf_next = ts_ns_inc_reg - period_ns_ovf_reg;
|
||||||
{ts_ns_next, ts_fns_next} = {ts_ns_inc_reg, ts_fns_inc_reg};
|
ts_ns_next = ts_ns_inc_reg;
|
||||||
|
|
||||||
if (!ts_ns_ovf_reg[30]) begin
|
if (!ts_ns_ovf_reg[30+FNS_WIDTH]) begin
|
||||||
// if the overflow lookahead did not borrow, one second has elapsed
|
// if the overflow lookahead did not borrow, one second has elapsed
|
||||||
// increment seconds field, pre-compute normal increment, force overflow lookahead borrow bit set
|
// 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_inc_next = ts_ns_ovf_reg + period_ns_delay_reg;
|
||||||
ts_ns_ovf_next[30] = 1'b1;
|
ts_ns_ovf_next[30+FNS_WIDTH] = 1'b1;
|
||||||
{ts_ns_next, ts_fns_next} = {ts_ns_ovf_reg, ts_fns_ovf_reg};
|
ts_ns_next = ts_ns_ovf_reg;
|
||||||
ts_s_next = ts_s_reg + 1;
|
ts_s_next = ts_s_reg + 1;
|
||||||
end
|
end
|
||||||
end else if (TS_WIDTH == 64) begin
|
end else if (TS_WIDTH == 64) begin
|
||||||
// 64 bit timestamp
|
// 64 bit timestamp
|
||||||
{ts_ns_next, ts_fns_next} = {ts_ns_reg, ts_fns_reg} + {period_ns_reg, period_fns_reg};
|
ts_ns_next = ts_ns_reg + period_ns_reg;
|
||||||
end
|
end
|
||||||
|
|
||||||
if (ts_sync_valid_reg) begin
|
if (ts_sync_valid_reg) begin
|
||||||
// Read new value
|
// Read new value
|
||||||
if (TS_WIDTH == 96) begin
|
if (TS_WIDTH == 96) begin
|
||||||
if (ts_step_sync_reg || sec_mismatch_reg) begin
|
if (src_ts_step_sync_reg || load_ts_reg) begin
|
||||||
// input stepped
|
// input stepped
|
||||||
sec_mismatch_next = 1'b0;
|
load_ts_next = 1'b0;
|
||||||
|
|
||||||
ts_s_next = ts_s_sync_reg;
|
ts_s_next = src_ts_s_sync_reg;
|
||||||
ts_ns_next = ts_ns_sync_reg;
|
ts_ns_next[TS_NS_WIDTH+FNS_WIDTH-1:9+FNS_WIDTH] = src_ts_ns_sync_reg[TS_NS_WIDTH+CMP_FNS_WIDTH-1:9+CMP_FNS_WIDTH];
|
||||||
ts_ns_inc_next = ts_ns_sync_reg;
|
ts_ns_inc_next[TS_NS_WIDTH+FNS_WIDTH-1:9+FNS_WIDTH] = src_ts_ns_sync_reg[TS_NS_WIDTH+CMP_FNS_WIDTH-1:9+CMP_FNS_WIDTH];
|
||||||
ts_ns_ovf_next[30] = 1'b1;
|
ts_ns_ovf_next[30+FNS_WIDTH] = 1'b1;
|
||||||
ts_fns_next = ts_fns_sync_reg;
|
|
||||||
ts_fns_inc_next = ts_fns_sync_reg;
|
|
||||||
ts_step_next = 1;
|
ts_step_next = 1;
|
||||||
end else begin
|
end else begin
|
||||||
// input did not step
|
// input did not step
|
||||||
sec_mismatch_next = 1'b0;
|
load_ts_next = 1'b0;
|
||||||
diff_valid_next = 1'b1;
|
ts_diff_valid_next = freq_locked_reg;
|
||||||
end
|
end
|
||||||
// compute difference
|
// compute difference
|
||||||
ts_s_msb_diff_next = ts_s_sync_reg[47:8] != dest_ts_s_capt_reg[47:8];
|
ts_ns_diff_next = src_ts_ns_sync_reg - dest_ts_ns_capt_reg;
|
||||||
ts_s_diff_next = ts_s_sync_reg[7:0] - dest_ts_s_capt_reg[7:0];
|
ts_diff_next = src_ts_s_sync_reg != dest_ts_s_capt_reg || src_ts_ns_sync_reg[TS_NS_WIDTH+CMP_FNS_WIDTH-1:9+CMP_FNS_WIDTH] != dest_ts_ns_capt_reg[TS_NS_WIDTH+CMP_FNS_WIDTH-1:9+CMP_FNS_WIDTH];
|
||||||
{ts_ns_diff_next, ts_fns_diff_next} = {ts_ns_sync_reg, ts_fns_sync_reg} - {dest_ts_ns_capt_reg, dest_ts_fns_capt_reg};
|
|
||||||
end else if (TS_WIDTH == 64) begin
|
end else if (TS_WIDTH == 64) begin
|
||||||
if (ts_step_sync_reg || sec_mismatch_reg) begin
|
if (src_ts_step_sync_reg || load_ts_reg) begin
|
||||||
// input stepped
|
// input stepped
|
||||||
sec_mismatch_next = 1'b0;
|
load_ts_next = 1'b0;
|
||||||
|
|
||||||
ts_ns_next = ts_ns_sync_reg;
|
ts_ns_next[TS_NS_WIDTH+FNS_WIDTH-1:9+FNS_WIDTH] = src_ts_ns_sync_reg[TS_NS_WIDTH+CMP_FNS_WIDTH-1:9+CMP_FNS_WIDTH];
|
||||||
ts_fns_next = ts_fns_sync_reg;
|
|
||||||
ts_step_next = 1;
|
ts_step_next = 1;
|
||||||
end else begin
|
end else begin
|
||||||
// input did not step
|
// input did not step
|
||||||
sec_mismatch_next = 1'b0;
|
load_ts_next = 1'b0;
|
||||||
diff_valid_next = 1'b1;
|
ts_diff_valid_next = freq_locked_reg;
|
||||||
end
|
end
|
||||||
// compute difference
|
// compute difference
|
||||||
{ts_ns_diff_next, ts_fns_diff_next} = {ts_ns_sync_reg, ts_fns_sync_reg} - {dest_ts_ns_capt_reg, dest_ts_fns_capt_reg};
|
ts_ns_diff_next = src_ts_ns_sync_reg - dest_ts_ns_capt_reg;
|
||||||
|
ts_diff_next = src_ts_ns_sync_reg[TS_NS_WIDTH+CMP_FNS_WIDTH-1:9+CMP_FNS_WIDTH] != dest_ts_ns_capt_reg[TS_NS_WIDTH+CMP_FNS_WIDTH-1:9+CMP_FNS_WIDTH];
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (diff_valid_reg) begin
|
if (ts_diff_valid_reg) begin
|
||||||
// seconds field correction
|
if (ts_diff_reg) begin
|
||||||
if (TS_WIDTH == 96) begin
|
if (&mismatch_cnt_reg) begin
|
||||||
if ($signed(ts_s_diff_reg) == 0 && ts_s_msb_diff_reg == 0 && ($signed(ts_ns_diff_reg[30:16]) == 0 || $signed(ts_ns_diff_reg[30:16]) == -1)) begin
|
load_ts_next = 1'b1;
|
||||||
// difference is small and no seconds difference; slew
|
mismatch_cnt_next = 0;
|
||||||
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] == ~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] + 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] == 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] - NS_PER_S[16:0];
|
|
||||||
ts_fns_diff_corr_next = ts_fns_diff_reg;
|
|
||||||
diff_corr_valid_next = 1'b1;
|
|
||||||
end else begin
|
end else begin
|
||||||
// difference is too large; step the clock
|
mismatch_cnt_next = mismatch_cnt_reg + 1;
|
||||||
sec_mismatch_next = 1'b1;
|
|
||||||
end
|
|
||||||
end else if (TS_WIDTH == 64) begin
|
|
||||||
if ($signed(ts_ns_diff_reg[47:16]) == 0 || $signed(ts_ns_diff_reg[47:16]) == -1) begin
|
|
||||||
// difference is small enough to slew
|
|
||||||
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 begin
|
|
||||||
// difference is too large; step the clock
|
|
||||||
sec_mismatch_next = 1'b1;
|
|
||||||
end
|
end
|
||||||
|
end else begin
|
||||||
|
mismatch_cnt_next = 0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (diff_corr_valid_reg) begin
|
if (phase_err_out_valid_reg) begin
|
||||||
|
// coarse phase/frequency lock of PTP clock
|
||||||
|
if ($signed(phase_err_out_reg) > 4 || $signed(phase_err_out_reg) < -4) begin
|
||||||
|
if (freq_lock_count_reg) begin
|
||||||
|
freq_lock_count_next = freq_lock_count_reg - 1;
|
||||||
|
end else begin
|
||||||
|
freq_locked_next = 1'b0;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
if (&freq_lock_count_reg) begin
|
||||||
|
freq_locked_next = 1'b1;
|
||||||
|
end else begin
|
||||||
|
freq_lock_count_next = freq_lock_count_reg + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (!freq_locked_reg) begin
|
||||||
|
ts_ns_diff_next = $signed(phase_err_out_reg) * 8 * 2**CMP_FNS_WIDTH;
|
||||||
|
ts_diff_valid_next = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (ts_diff_valid_reg) begin
|
||||||
// PI control
|
// PI control
|
||||||
|
|
||||||
// time integral of error
|
// gain scheduling
|
||||||
if (ptp_locked_reg) begin
|
if (!ts_ns_diff_reg[8+CMP_FNS_WIDTH]) begin
|
||||||
{ptp_ovf, time_err_int_next} = $signed({1'b0, time_err_int_reg}) + $signed({ts_ns_diff_corr_reg, ts_fns_diff_corr_reg});
|
if (ts_ns_diff_reg[4+CMP_FNS_WIDTH +: 4]) begin
|
||||||
|
gain_sel_next = 1'b1;
|
||||||
|
end else begin
|
||||||
|
gain_sel_next = 1'b0;
|
||||||
|
end
|
||||||
end else begin
|
end else begin
|
||||||
{ptp_ovf, time_err_int_next} = $signed({1'b0, time_err_int_reg}) + ($signed({ts_ns_diff_corr_reg, ts_fns_diff_corr_reg}) * 2**3);
|
if (~ts_ns_diff_reg[4+CMP_FNS_WIDTH +: 4]) begin
|
||||||
|
gain_sel_next = 1'b1;
|
||||||
|
end else begin
|
||||||
|
gain_sel_next = 1'b0;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// time integral of error
|
||||||
|
case (gain_sel_reg)
|
||||||
|
1'b0: {ptp_ovf, time_err_int_next} = $signed({1'b0, time_err_int_reg}) + ($signed(ts_ns_diff_reg) / 2**4);
|
||||||
|
1'b1: {ptp_ovf, time_err_int_next} = $signed({1'b0, time_err_int_reg}) + ($signed(ts_ns_diff_reg) * 2**2);
|
||||||
|
endcase
|
||||||
|
|
||||||
// saturate
|
// saturate
|
||||||
if (ptp_ovf[1]) begin
|
if (ptp_ovf[1]) begin
|
||||||
// sign bit set indicating underflow across zero; saturate to zero
|
// sign bit set indicating underflow across zero; saturate to zero
|
||||||
@ -692,80 +702,78 @@ always @* begin
|
|||||||
end
|
end
|
||||||
|
|
||||||
// compute output
|
// compute output
|
||||||
if (ptp_locked_reg) begin
|
case (gain_sel_reg)
|
||||||
{ptp_ovf, period_ns_next, period_fns_next} = ($signed({1'b0, time_err_int_reg}) / 2**16) + ($signed({ts_ns_diff_corr_reg, ts_fns_diff_corr_reg}) / 2**10);
|
1'b0: {ptp_ovf, period_ns_next} = $signed({1'b0, time_err_int_reg}) + ($signed(ts_ns_diff_reg) * 2**2);
|
||||||
end else begin
|
1'b1: {ptp_ovf, period_ns_next} = $signed({1'b0, time_err_int_reg}) + ($signed(ts_ns_diff_reg) * 2**6);
|
||||||
{ptp_ovf, period_ns_next, period_fns_next} = ($signed({1'b0, time_err_int_reg}) / 2**16) + ($signed({ts_ns_diff_corr_reg, ts_fns_diff_corr_reg}) / 2**7);
|
endcase
|
||||||
end
|
|
||||||
|
|
||||||
// saturate
|
// saturate
|
||||||
if (ptp_ovf[1]) begin
|
if (ptp_ovf[1]) begin
|
||||||
// sign bit set indicating underflow across zero; saturate to zero
|
// sign bit set indicating underflow across zero; saturate to zero
|
||||||
{period_ns_next, period_fns_next} = {NS_WIDTH+FNS_WIDTH{1'b0}};
|
period_ns_next = {NS_WIDTH+FNS_WIDTH{1'b0}};
|
||||||
end else if (ptp_ovf[0]) begin
|
end else if (ptp_ovf[0]) begin
|
||||||
// sign bit clear but carry bit set indicating overflow; saturate to all 1
|
// sign bit clear but carry bit set indicating overflow; saturate to all 1
|
||||||
{period_ns_next, period_fns_next} = {NS_WIDTH+FNS_WIDTH{1'b1}};
|
period_ns_next = {NS_WIDTH+FNS_WIDTH{1'b1}};
|
||||||
end
|
end
|
||||||
|
|
||||||
// adjust period if integrator is saturated
|
// adjust period if integrator is saturated
|
||||||
if (time_err_int_reg == 0) begin
|
if (time_err_int_reg == 0) begin
|
||||||
{period_ns_next, period_fns_next} = {NS_WIDTH+FNS_WIDTH{1'b0}};
|
period_ns_next = {NS_WIDTH+FNS_WIDTH{1'b0}};
|
||||||
end else if (~time_err_int_reg == 0) begin
|
end else if (~time_err_int_reg == 0) begin
|
||||||
{period_ns_next, period_fns_next} = {NS_WIDTH+FNS_WIDTH{1'b1}};
|
period_ns_next = {NS_WIDTH+FNS_WIDTH{1'b1}};
|
||||||
end
|
end
|
||||||
|
|
||||||
// locked status
|
// locked status
|
||||||
if ($signed(ts_ns_diff_corr_reg[17-1:4]) == 0 || $signed(ts_ns_diff_corr_reg[17-1:4]) == -1) begin
|
if (!freq_locked_reg) begin
|
||||||
if (ptp_lock_count_reg == {PTP_LOCK_WIDTH{1'b1}}) begin
|
ptp_lock_count_next = 0;
|
||||||
|
ptp_locked_next = 1'b0;
|
||||||
|
end else if (gain_sel_reg == 1'b0) begin
|
||||||
|
if (&ptp_lock_count_reg) begin
|
||||||
ptp_locked_next = 1'b1;
|
ptp_locked_next = 1'b1;
|
||||||
end else begin
|
end else begin
|
||||||
ptp_lock_count_next = ptp_lock_count_reg + 1;
|
ptp_lock_count_next = ptp_lock_count_reg + 1;
|
||||||
end
|
end
|
||||||
end else begin
|
end else begin
|
||||||
ptp_lock_count_next = 0;
|
if (ptp_lock_count_reg) begin
|
||||||
ptp_locked_next = 1'b0;
|
ptp_lock_count_next = ptp_lock_count_reg - 1;
|
||||||
|
end else begin
|
||||||
|
ptp_locked_next = 1'b0;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
always @(posedge output_clk) begin
|
always @(posedge output_clk) begin
|
||||||
period_ns_reg <= period_ns_next;
|
period_ns_reg <= period_ns_next;
|
||||||
period_fns_reg <= period_fns_next;
|
|
||||||
period_ns_delay_reg <= period_ns_delay_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_ns_ovf_reg <= period_ns_ovf_next;
|
||||||
period_fns_ovf_reg <= period_fns_ovf_next;
|
|
||||||
|
|
||||||
ts_s_reg <= ts_s_next;
|
ts_s_reg <= ts_s_next;
|
||||||
ts_ns_reg <= ts_ns_next;
|
ts_ns_reg <= ts_ns_next;
|
||||||
ts_fns_reg <= ts_fns_next;
|
|
||||||
ts_ns_inc_reg <= ts_ns_inc_next;
|
ts_ns_inc_reg <= ts_ns_inc_next;
|
||||||
ts_fns_inc_reg <= ts_fns_inc_next;
|
|
||||||
ts_ns_ovf_reg <= ts_ns_ovf_next;
|
ts_ns_ovf_reg <= ts_ns_ovf_next;
|
||||||
ts_fns_ovf_reg <= ts_fns_ovf_next;
|
|
||||||
|
|
||||||
ts_step_reg <= ts_step_next;
|
ts_step_reg <= ts_step_next;
|
||||||
|
|
||||||
sec_mismatch_reg <= sec_mismatch_next;
|
ts_diff_reg <= ts_diff_next;
|
||||||
diff_valid_reg <= diff_valid_next;
|
ts_diff_valid_reg <= ts_diff_valid_next;
|
||||||
diff_corr_valid_reg <= diff_corr_valid_next;
|
mismatch_cnt_reg <= mismatch_cnt_next;
|
||||||
|
load_ts_reg <= load_ts_next;
|
||||||
|
|
||||||
ts_s_msb_diff_reg <= ts_s_msb_diff_next;
|
|
||||||
ts_s_diff_reg <= ts_s_diff_next;
|
|
||||||
ts_ns_diff_reg <= ts_ns_diff_next;
|
ts_ns_diff_reg <= ts_ns_diff_next;
|
||||||
ts_fns_diff_reg <= ts_fns_diff_next;
|
|
||||||
|
|
||||||
ts_ns_diff_corr_reg <= ts_ns_diff_corr_next;
|
|
||||||
ts_fns_diff_corr_reg <= ts_fns_diff_corr_next;
|
|
||||||
|
|
||||||
time_err_int_reg <= time_err_int_next;
|
time_err_int_reg <= time_err_int_next;
|
||||||
|
|
||||||
|
freq_lock_count_reg <= freq_lock_count_next;
|
||||||
|
freq_locked_reg <= freq_locked_next;
|
||||||
ptp_lock_count_reg <= ptp_lock_count_next;
|
ptp_lock_count_reg <= ptp_lock_count_next;
|
||||||
ptp_locked_reg <= ptp_locked_next;
|
ptp_locked_reg <= ptp_locked_next;
|
||||||
|
|
||||||
|
gain_sel_reg <= gain_sel_next;
|
||||||
|
|
||||||
// PPS output
|
// PPS output
|
||||||
if (TS_WIDTH == 96) begin
|
if (TS_WIDTH == 96) begin
|
||||||
pps_reg <= !ts_ns_ovf_reg[30];
|
pps_reg <= !ts_ns_ovf_reg[30+FNS_WIDTH];
|
||||||
end else if (TS_WIDTH == 64) begin
|
end else if (TS_WIDTH == 64) begin
|
||||||
pps_reg <= 1'b0; // not currently implemented for 64 bit timestamp format
|
pps_reg <= 1'b0; // not currently implemented for 64 bit timestamp format
|
||||||
end
|
end
|
||||||
@ -773,15 +781,13 @@ always @(posedge output_clk) begin
|
|||||||
// pipeline
|
// pipeline
|
||||||
if (PIPELINE_OUTPUT > 0) begin
|
if (PIPELINE_OUTPUT > 0) begin
|
||||||
ts_s_pipe_reg[0] <= ts_s_reg;
|
ts_s_pipe_reg[0] <= ts_s_reg;
|
||||||
ts_ns_pipe_reg[0] <= ts_ns_reg;
|
ts_ns_pipe_reg[0] <= ts_ns_reg >> FNS_WIDTH-TS_FNS_WIDTH;
|
||||||
ts_fns_pipe_reg[0] <= ts_fns_reg;
|
|
||||||
ts_step_pipe_reg[0] <= ts_step_reg;
|
ts_step_pipe_reg[0] <= ts_step_reg;
|
||||||
pps_pipe_reg[0] <= pps_reg;
|
pps_pipe_reg[0] <= pps_reg;
|
||||||
|
|
||||||
for (i = 0; i < PIPELINE_OUTPUT-1; i = i + 1) begin
|
for (i = 0; i < PIPELINE_OUTPUT-1; i = i + 1) begin
|
||||||
ts_s_pipe_reg[i+1] <= ts_s_pipe_reg[i];
|
ts_s_pipe_reg[i+1] <= ts_s_pipe_reg[i];
|
||||||
ts_ns_pipe_reg[i+1] <= ts_ns_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];
|
ts_step_pipe_reg[i+1] <= ts_step_pipe_reg[i];
|
||||||
pps_pipe_reg[i+1] <= pps_pipe_reg[i];
|
pps_pipe_reg[i+1] <= pps_pipe_reg[i];
|
||||||
end
|
end
|
||||||
@ -789,33 +795,30 @@ always @(posedge output_clk) begin
|
|||||||
|
|
||||||
if (output_rst) begin
|
if (output_rst) begin
|
||||||
period_ns_reg <= 0;
|
period_ns_reg <= 0;
|
||||||
period_fns_reg <= 0;
|
|
||||||
period_ns_delay_reg <= 0;
|
period_ns_delay_reg <= 0;
|
||||||
period_fns_delay_reg <= 0;
|
|
||||||
period_ns_ovf_reg <= 0;
|
period_ns_ovf_reg <= 0;
|
||||||
period_fns_ovf_reg <= 0;
|
|
||||||
ts_s_reg <= 0;
|
ts_s_reg <= 0;
|
||||||
ts_ns_reg <= 0;
|
ts_ns_reg <= 0;
|
||||||
ts_fns_reg <= 0;
|
|
||||||
ts_ns_inc_reg <= 0;
|
ts_ns_inc_reg <= 0;
|
||||||
ts_fns_inc_reg <= 0;
|
ts_ns_ovf_reg[30+FNS_WIDTH] <= 1'b1;
|
||||||
ts_ns_ovf_reg[30] <= 1'b1;
|
|
||||||
ts_step_reg <= 0;
|
ts_step_reg <= 0;
|
||||||
pps_reg <= 0;
|
pps_reg <= 0;
|
||||||
|
|
||||||
sec_mismatch_reg <= 1'b0;
|
ts_diff_reg <= 1'b0;
|
||||||
diff_valid_reg <= 1'b0;
|
ts_diff_valid_reg <= 1'b0;
|
||||||
diff_corr_valid_reg <= 1'b0;
|
mismatch_cnt_reg <= 0;
|
||||||
|
load_ts_reg <= 0;
|
||||||
|
|
||||||
time_err_int_reg <= 0;
|
time_err_int_reg <= 0;
|
||||||
|
|
||||||
|
freq_lock_count_reg <= 0;
|
||||||
|
freq_locked_reg <= 1'b0;
|
||||||
ptp_lock_count_reg <= 0;
|
ptp_lock_count_reg <= 0;
|
||||||
ptp_locked_reg <= 1'b0;
|
ptp_locked_reg <= 1'b0;
|
||||||
|
|
||||||
for (i = 0; i < PIPELINE_OUTPUT; i = i + 1) begin
|
for (i = 0; i < PIPELINE_OUTPUT; i = i + 1) begin
|
||||||
ts_s_pipe_reg[i] <= 0;
|
ts_s_pipe_reg[i] <= 0;
|
||||||
ts_ns_pipe_reg[i] <= 0;
|
ts_ns_pipe_reg[i] <= 0;
|
||||||
ts_fns_pipe_reg[i] <= 0;
|
|
||||||
ts_step_pipe_reg[i] <= 1'b0;
|
ts_step_pipe_reg[i] <= 1'b0;
|
||||||
pps_pipe_reg[i] <= 1'b0;
|
pps_pipe_reg[i] <= 1'b0;
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2019-2021 Alex Forencich
|
# Copyright (c) 2019-2023 Alex Forencich
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -31,22 +31,19 @@ foreach inst [get_cells -hier -filter {(ORIG_REF_NAME == ptp_clock_cdc || REF_NA
|
|||||||
set output_clk_period [if {[llength $output_clk]} {get_property -min PERIOD $output_clk} {expr 1.0}]
|
set output_clk_period [if {[llength $output_clk]} {get_property -min PERIOD $output_clk} {expr 1.0}]
|
||||||
|
|
||||||
# timestamp synchronization
|
# timestamp synchronization
|
||||||
set_property ASYNC_REG TRUE [get_cells -hier -regexp ".*/ts_(s|ns|fns|step)_sync_reg_reg(\\\[\\d+\\\])?" -filter "PARENT == $inst"]
|
set_property ASYNC_REG TRUE [get_cells -hier -regexp ".*/src_ts_(s|ns|step)_sync_reg_reg(\\\[\\d+\\\])?" -filter "PARENT == $inst"]
|
||||||
|
|
||||||
if {[llength [get_cells "$inst/src_ts_s_capt_reg_reg[*]"]]} {
|
if {[llength [get_cells "$inst/src_ts_s_capt_reg_reg[*]"]]} {
|
||||||
set_max_delay -from [get_cells "$inst/src_ts_s_capt_reg_reg[*]"] -to [get_cells "$inst/ts_s_sync_reg_reg[*]"] -datapath_only $output_clk_period
|
set_max_delay -from [get_cells "$inst/src_ts_s_capt_reg_reg[*]"] -to [get_cells "$inst/src_ts_s_sync_reg_reg[*]"] -datapath_only $output_clk_period
|
||||||
set_bus_skew -from [get_cells "$inst/src_ts_s_capt_reg_reg[*]"] -to [get_cells "$inst/ts_s_sync_reg_reg[*]"] $input_clk_period
|
set_bus_skew -from [get_cells "$inst/src_ts_s_capt_reg_reg[*]"] -to [get_cells "$inst/src_ts_s_sync_reg_reg[*]"] $input_clk_period
|
||||||
}
|
}
|
||||||
|
|
||||||
set_max_delay -from [get_cells "$inst/src_ts_ns_capt_reg_reg[*]"] -to [get_cells "$inst/ts_ns_sync_reg_reg[*]"] -datapath_only $output_clk_period
|
set_max_delay -from [get_cells "$inst/src_ts_ns_capt_reg_reg[*]"] -to [get_cells "$inst/src_ts_ns_sync_reg_reg[*]"] -datapath_only $output_clk_period
|
||||||
set_bus_skew -from [get_cells "$inst/src_ts_ns_capt_reg_reg[*]"] -to [get_cells "$inst/ts_ns_sync_reg_reg[*]"] $input_clk_period
|
set_bus_skew -from [get_cells "$inst/src_ts_ns_capt_reg_reg[*]"] -to [get_cells "$inst/src_ts_ns_sync_reg_reg[*]"] $input_clk_period
|
||||||
|
|
||||||
set_max_delay -from [get_cells "$inst/src_ts_fns_capt_reg_reg[*]"] -to [get_cells "$inst/ts_fns_sync_reg_reg[*]"] -datapath_only $output_clk_period
|
|
||||||
set_bus_skew -from [get_cells "$inst/src_ts_fns_capt_reg_reg[*]"] -to [get_cells "$inst/ts_fns_sync_reg_reg[*]"] $input_clk_period
|
|
||||||
|
|
||||||
if {[llength [get_cells "$inst/src_ts_step_capt_reg_reg"]]} {
|
if {[llength [get_cells "$inst/src_ts_step_capt_reg_reg"]]} {
|
||||||
set_max_delay -from [get_cells "$inst/src_ts_step_capt_reg_reg"] -to [get_cells "$inst/ts_step_sync_reg_reg"] -datapath_only $output_clk_period
|
set_max_delay -from [get_cells "$inst/src_ts_step_capt_reg_reg"] -to [get_cells "$inst/src_ts_step_sync_reg_reg"] -datapath_only $output_clk_period
|
||||||
set_bus_skew -from [get_cells "$inst/src_ts_step_capt_reg_reg"] -to [get_cells "$inst/ts_step_sync_reg_reg"] $input_clk_period
|
set_bus_skew -from [get_cells "$inst/src_ts_step_capt_reg_reg"] -to [get_cells "$inst/src_ts_step_sync_reg_reg"] $input_clk_period
|
||||||
}
|
}
|
||||||
|
|
||||||
# sample clock
|
# sample clock
|
||||||
@ -82,7 +79,7 @@ foreach inst [get_cells -hier -filter {(ORIG_REF_NAME == ptp_clock_cdc || REF_NA
|
|||||||
set_bus_skew -from [get_cells "$inst/sample_acc_out_reg_reg[*]"] -to [get_cells $inst/sample_acc_sync_reg_reg[*]] $output_clk_period
|
set_bus_skew -from [get_cells "$inst/sample_acc_out_reg_reg[*]"] -to [get_cells $inst/sample_acc_sync_reg_reg[*]] $output_clk_period
|
||||||
}
|
}
|
||||||
|
|
||||||
# no sample clock
|
# timestamp transfer sync
|
||||||
set sync_ffs [get_cells -quiet -hier -regexp ".*/src_sync_sync\[12\]_reg_reg" -filter "PARENT == $inst"]
|
set sync_ffs [get_cells -quiet -hier -regexp ".*/src_sync_sync\[12\]_reg_reg" -filter "PARENT == $inst"]
|
||||||
|
|
||||||
if {[llength $sync_ffs]} {
|
if {[llength $sync_ffs]} {
|
||||||
@ -90,4 +87,21 @@ foreach inst [get_cells -hier -filter {(ORIG_REF_NAME == ptp_clock_cdc || REF_NA
|
|||||||
|
|
||||||
set_max_delay -from [get_cells "$inst/src_sync_reg_reg"] -to [get_cells "$inst/src_sync_sync1_reg_reg"] -datapath_only $input_clk_period
|
set_max_delay -from [get_cells "$inst/src_sync_reg_reg"] -to [get_cells "$inst/src_sync_sync1_reg_reg"] -datapath_only $input_clk_period
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# phase sync
|
||||||
|
set sync_ffs [get_cells -quiet -hier -regexp ".*/src_phase_sync_sync\[12\]_reg_reg" -filter "PARENT == $inst"]
|
||||||
|
|
||||||
|
if {[llength $sync_ffs]} {
|
||||||
|
set_property ASYNC_REG TRUE $sync_ffs
|
||||||
|
|
||||||
|
# hunt down source
|
||||||
|
set dest_pins [get_pins -of_objects [get_cells "$inst/src_phase_sync_sync1_reg_reg"] -filter {REF_PIN_NAME == "D"}]
|
||||||
|
set nets [get_nets -segments -of_objects $dest_pins]
|
||||||
|
set source_pins [get_pins -of_objects $nets -filter {IS_LEAF && DIRECTION == "OUT"}]
|
||||||
|
set source [get_cells -of_objects $source_pins]
|
||||||
|
|
||||||
|
if {[llength $source]} {
|
||||||
|
set_max_delay -from $source -to [get_cells "$inst/src_phase_sync_sync1_reg_reg"] -datapath_only $input_clk_period
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,6 @@ export PARAM_RX_DROP_BAD_FRAME := $(PARAM_RX_DROP_OVERSIZE_FRAME)
|
|||||||
export PARAM_RX_DROP_WHEN_FULL := $(PARAM_RX_DROP_OVERSIZE_FRAME)
|
export PARAM_RX_DROP_WHEN_FULL := $(PARAM_RX_DROP_OVERSIZE_FRAME)
|
||||||
export PARAM_PTP_PERIOD_NS := 6
|
export PARAM_PTP_PERIOD_NS := 6
|
||||||
export PARAM_PTP_PERIOD_FNS := 26214
|
export PARAM_PTP_PERIOD_FNS := 26214
|
||||||
export PARAM_PTP_USE_SAMPLE_CLOCK := 0
|
|
||||||
export PARAM_TX_PTP_TS_ENABLE := 1
|
export PARAM_TX_PTP_TS_ENABLE := 1
|
||||||
export PARAM_RX_PTP_TS_ENABLE := $(PARAM_TX_PTP_TS_ENABLE)
|
export PARAM_RX_PTP_TS_ENABLE := $(PARAM_TX_PTP_TS_ENABLE)
|
||||||
export PARAM_TX_PTP_TS_CTRL_IN_TUSER := $(PARAM_TX_PTP_TS_ENABLE)
|
export PARAM_TX_PTP_TS_CTRL_IN_TUSER := $(PARAM_TX_PTP_TS_ENABLE)
|
||||||
|
@ -62,6 +62,7 @@ class TB:
|
|||||||
cocotb.start_soon(Clock(dut.logic_clk, self.clk_period, units="ns").start())
|
cocotb.start_soon(Clock(dut.logic_clk, self.clk_period, units="ns").start())
|
||||||
cocotb.start_soon(Clock(dut.rx_clk, self.clk_period, units="ns").start())
|
cocotb.start_soon(Clock(dut.rx_clk, self.clk_period, units="ns").start())
|
||||||
cocotb.start_soon(Clock(dut.tx_clk, self.clk_period, units="ns").start())
|
cocotb.start_soon(Clock(dut.tx_clk, self.clk_period, units="ns").start())
|
||||||
|
cocotb.start_soon(Clock(dut.ptp_sample_clk, 9.9, units="ns").start())
|
||||||
|
|
||||||
self.xgmii_source = XgmiiSource(dut.xgmii_rxd, dut.xgmii_rxc, dut.rx_clk, dut.rx_rst)
|
self.xgmii_source = XgmiiSource(dut.xgmii_rxd, dut.xgmii_rxc, dut.rx_clk, dut.rx_rst)
|
||||||
self.xgmii_sink = XgmiiSink(dut.xgmii_txd, dut.xgmii_txc, dut.tx_clk, dut.tx_rst)
|
self.xgmii_sink = XgmiiSink(dut.xgmii_txd, dut.xgmii_txc, dut.tx_clk, dut.tx_rst)
|
||||||
@ -72,7 +73,6 @@ class TB:
|
|||||||
self.ptp_clock = PtpClockSimTime(ts_64=dut.ptp_ts_96, clock=dut.logic_clk)
|
self.ptp_clock = PtpClockSimTime(ts_64=dut.ptp_ts_96, clock=dut.logic_clk)
|
||||||
self.tx_ptp_ts_sink = PtpTsSink(PtpTsBus.from_prefix(dut, "tx_axis_ptp"), dut.tx_clk, dut.tx_rst)
|
self.tx_ptp_ts_sink = PtpTsSink(PtpTsBus.from_prefix(dut, "tx_axis_ptp"), dut.tx_clk, dut.tx_rst)
|
||||||
|
|
||||||
dut.ptp_sample_clk.setimmediatevalue(0)
|
|
||||||
dut.ptp_ts_step.setimmediatevalue(0)
|
dut.ptp_ts_step.setimmediatevalue(0)
|
||||||
|
|
||||||
dut.cfg_ifg.setimmediatevalue(0)
|
dut.cfg_ifg.setimmediatevalue(0)
|
||||||
@ -108,8 +108,10 @@ async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12):
|
|||||||
await tb.reset()
|
await tb.reset()
|
||||||
|
|
||||||
tb.log.info("Wait for PTP CDC lock")
|
tb.log.info("Wait for PTP CDC lock")
|
||||||
while not dut.tx_ptp.tx_ptp_cdc.locked.value.integer:
|
while not dut.rx_ptp.rx_ptp_cdc.locked.value.integer:
|
||||||
await RisingEdge(dut.tx_clk)
|
await RisingEdge(dut.rx_clk)
|
||||||
|
for k in range(1000):
|
||||||
|
await RisingEdge(dut.rx_clk)
|
||||||
|
|
||||||
test_frames = [payload_data(x) for x in payload_lengths()]
|
test_frames = [payload_data(x) for x in payload_lengths()]
|
||||||
tx_frames = []
|
tx_frames = []
|
||||||
@ -138,7 +140,7 @@ async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12):
|
|||||||
|
|
||||||
assert rx_frame.tdata == test_data
|
assert rx_frame.tdata == test_data
|
||||||
assert frame_error == 0
|
assert frame_error == 0
|
||||||
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period) < tb.clk_period
|
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period) < tb.clk_period*2
|
||||||
|
|
||||||
assert tb.axis_sink.empty()
|
assert tb.axis_sink.empty()
|
||||||
|
|
||||||
@ -159,6 +161,8 @@ async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12):
|
|||||||
tb.log.info("Wait for PTP CDC lock")
|
tb.log.info("Wait for PTP CDC lock")
|
||||||
while not dut.tx_ptp.tx_ptp_cdc.locked.value.integer:
|
while not dut.tx_ptp.tx_ptp_cdc.locked.value.integer:
|
||||||
await RisingEdge(dut.tx_clk)
|
await RisingEdge(dut.tx_clk)
|
||||||
|
for k in range(1000):
|
||||||
|
await RisingEdge(dut.tx_clk)
|
||||||
|
|
||||||
test_frames = [payload_data(x) for x in payload_lengths()]
|
test_frames = [payload_data(x) for x in payload_lengths()]
|
||||||
|
|
||||||
@ -184,7 +188,7 @@ async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12):
|
|||||||
assert rx_frame.get_payload() == test_data
|
assert rx_frame.get_payload() == test_data
|
||||||
assert rx_frame.check_fcs()
|
assert rx_frame.check_fcs()
|
||||||
assert rx_frame.ctrl is None
|
assert rx_frame.ctrl is None
|
||||||
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < tb.clk_period
|
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < tb.clk_period*2
|
||||||
|
|
||||||
assert tb.xgmii_sink.empty()
|
assert tb.xgmii_sink.empty()
|
||||||
|
|
||||||
@ -209,6 +213,8 @@ async def run_test_tx_alignment(dut, payload_data=None, ifg=12):
|
|||||||
tb.log.info("Wait for PTP CDC lock")
|
tb.log.info("Wait for PTP CDC lock")
|
||||||
while not dut.tx_ptp.tx_ptp_cdc.locked.value.integer:
|
while not dut.tx_ptp.tx_ptp_cdc.locked.value.integer:
|
||||||
await RisingEdge(dut.tx_clk)
|
await RisingEdge(dut.tx_clk)
|
||||||
|
for k in range(1000):
|
||||||
|
await RisingEdge(dut.tx_clk)
|
||||||
|
|
||||||
for length in range(60, 92):
|
for length in range(60, 92):
|
||||||
|
|
||||||
@ -240,7 +246,7 @@ async def run_test_tx_alignment(dut, payload_data=None, ifg=12):
|
|||||||
assert rx_frame.get_payload() == test_data
|
assert rx_frame.get_payload() == test_data
|
||||||
assert rx_frame.check_fcs()
|
assert rx_frame.check_fcs()
|
||||||
assert rx_frame.ctrl is None
|
assert rx_frame.ctrl is None
|
||||||
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < tb.clk_period
|
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period) < tb.clk_period*2
|
||||||
|
|
||||||
start_lane.append(rx_frame.start_lane)
|
start_lane.append(rx_frame.start_lane)
|
||||||
|
|
||||||
@ -365,7 +371,6 @@ def test_eth_mac_10g_fifo(request, data_width, enable_dic):
|
|||||||
parameters['RX_DROP_WHEN_FULL'] = parameters['RX_DROP_OVERSIZE_FRAME']
|
parameters['RX_DROP_WHEN_FULL'] = parameters['RX_DROP_OVERSIZE_FRAME']
|
||||||
parameters['PTP_PERIOD_NS'] = 0x6 if parameters['DATA_WIDTH'] == 64 else 0x3
|
parameters['PTP_PERIOD_NS'] = 0x6 if parameters['DATA_WIDTH'] == 64 else 0x3
|
||||||
parameters['PTP_PERIOD_FNS'] = 0x6666 if parameters['DATA_WIDTH'] == 64 else 0x3333
|
parameters['PTP_PERIOD_FNS'] = 0x6666 if parameters['DATA_WIDTH'] == 64 else 0x3333
|
||||||
parameters['PTP_USE_SAMPLE_CLOCK'] = 0
|
|
||||||
parameters['TX_PTP_TS_ENABLE'] = 1
|
parameters['TX_PTP_TS_ENABLE'] = 1
|
||||||
parameters['RX_PTP_TS_ENABLE'] = parameters['TX_PTP_TS_ENABLE']
|
parameters['RX_PTP_TS_ENABLE'] = parameters['TX_PTP_TS_ENABLE']
|
||||||
parameters['TX_PTP_TS_CTRL_IN_TUSER'] = parameters['TX_PTP_TS_ENABLE']
|
parameters['TX_PTP_TS_CTRL_IN_TUSER'] = parameters['TX_PTP_TS_ENABLE']
|
||||||
|
@ -69,7 +69,6 @@ export PARAM_RX_DROP_BAD_FRAME := $(PARAM_RX_DROP_OVERSIZE_FRAME)
|
|||||||
export PARAM_RX_DROP_WHEN_FULL := $(PARAM_RX_DROP_OVERSIZE_FRAME)
|
export PARAM_RX_DROP_WHEN_FULL := $(PARAM_RX_DROP_OVERSIZE_FRAME)
|
||||||
export PARAM_PTP_PERIOD_NS := 6
|
export PARAM_PTP_PERIOD_NS := 6
|
||||||
export PARAM_PTP_PERIOD_FNS := 26214
|
export PARAM_PTP_PERIOD_FNS := 26214
|
||||||
export PARAM_PTP_USE_SAMPLE_CLOCK := 0
|
|
||||||
export PARAM_TX_PTP_TS_ENABLE := 1
|
export PARAM_TX_PTP_TS_ENABLE := 1
|
||||||
export PARAM_RX_PTP_TS_ENABLE := $(PARAM_TX_PTP_TS_ENABLE)
|
export PARAM_RX_PTP_TS_ENABLE := $(PARAM_TX_PTP_TS_ENABLE)
|
||||||
export PARAM_TX_PTP_TS_CTRL_IN_TUSER := $(PARAM_TX_PTP_TS_ENABLE)
|
export PARAM_TX_PTP_TS_CTRL_IN_TUSER := $(PARAM_TX_PTP_TS_ENABLE)
|
||||||
|
@ -73,6 +73,7 @@ class TB:
|
|||||||
cocotb.start_soon(Clock(dut.logic_clk, self.clk_period, units="ns").start())
|
cocotb.start_soon(Clock(dut.logic_clk, self.clk_period, units="ns").start())
|
||||||
cocotb.start_soon(Clock(dut.rx_clk, self.clk_period, units="ns").start())
|
cocotb.start_soon(Clock(dut.rx_clk, self.clk_period, units="ns").start())
|
||||||
cocotb.start_soon(Clock(dut.tx_clk, self.clk_period, units="ns").start())
|
cocotb.start_soon(Clock(dut.tx_clk, self.clk_period, units="ns").start())
|
||||||
|
cocotb.start_soon(Clock(dut.ptp_sample_clk, 9.9, units="ns").start())
|
||||||
|
|
||||||
self.serdes_source = BaseRSerdesSource(dut.serdes_rx_data, dut.serdes_rx_hdr, dut.rx_clk, slip=dut.serdes_rx_bitslip)
|
self.serdes_source = BaseRSerdesSource(dut.serdes_rx_data, dut.serdes_rx_hdr, dut.rx_clk, slip=dut.serdes_rx_bitslip)
|
||||||
self.serdes_sink = BaseRSerdesSink(dut.serdes_tx_data, dut.serdes_tx_hdr, dut.tx_clk)
|
self.serdes_sink = BaseRSerdesSink(dut.serdes_tx_data, dut.serdes_tx_hdr, dut.tx_clk)
|
||||||
@ -83,7 +84,6 @@ class TB:
|
|||||||
self.ptp_clock = PtpClockSimTime(ts_64=dut.ptp_ts_96, clock=dut.logic_clk)
|
self.ptp_clock = PtpClockSimTime(ts_64=dut.ptp_ts_96, clock=dut.logic_clk)
|
||||||
self.tx_ptp_ts_sink = PtpTsSink(PtpTsBus.from_prefix(dut, "tx_axis_ptp"), dut.tx_clk, dut.tx_rst)
|
self.tx_ptp_ts_sink = PtpTsSink(PtpTsBus.from_prefix(dut, "tx_axis_ptp"), dut.tx_clk, dut.tx_rst)
|
||||||
|
|
||||||
dut.ptp_sample_clk.setimmediatevalue(0)
|
|
||||||
dut.ptp_ts_step.setimmediatevalue(0)
|
dut.ptp_ts_step.setimmediatevalue(0)
|
||||||
|
|
||||||
dut.cfg_ifg.setimmediatevalue(0)
|
dut.cfg_ifg.setimmediatevalue(0)
|
||||||
@ -125,8 +125,10 @@ async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12):
|
|||||||
await RisingEdge(dut.rx_clk)
|
await RisingEdge(dut.rx_clk)
|
||||||
|
|
||||||
tb.log.info("Wait for PTP CDC lock")
|
tb.log.info("Wait for PTP CDC lock")
|
||||||
while not dut.tx_ptp.tx_ptp_cdc.locked.value.integer:
|
while not dut.rx_ptp.rx_ptp_cdc.locked.value.integer:
|
||||||
await RisingEdge(dut.tx_clk)
|
await RisingEdge(dut.rx_clk)
|
||||||
|
for k in range(1000):
|
||||||
|
await RisingEdge(dut.rx_clk)
|
||||||
|
|
||||||
# clear out sink buffer
|
# clear out sink buffer
|
||||||
tb.axis_sink.clear()
|
tb.axis_sink.clear()
|
||||||
@ -158,7 +160,7 @@ async def run_test_rx(dut, payload_lengths=None, payload_data=None, ifg=12):
|
|||||||
|
|
||||||
assert rx_frame.tdata == test_data
|
assert rx_frame.tdata == test_data
|
||||||
assert frame_error == 0
|
assert frame_error == 0
|
||||||
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*4) < tb.clk_period
|
assert abs(ptp_ts_ns - tx_frame_sfd_ns - tb.clk_period*4) < tb.clk_period*2
|
||||||
|
|
||||||
assert tb.axis_sink.empty()
|
assert tb.axis_sink.empty()
|
||||||
|
|
||||||
@ -179,6 +181,8 @@ async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12):
|
|||||||
tb.log.info("Wait for PTP CDC lock")
|
tb.log.info("Wait for PTP CDC lock")
|
||||||
while not dut.tx_ptp.tx_ptp_cdc.locked.value.integer:
|
while not dut.tx_ptp.tx_ptp_cdc.locked.value.integer:
|
||||||
await RisingEdge(dut.tx_clk)
|
await RisingEdge(dut.tx_clk)
|
||||||
|
for k in range(1000):
|
||||||
|
await RisingEdge(dut.tx_clk)
|
||||||
|
|
||||||
test_frames = [payload_data(x) for x in payload_lengths()]
|
test_frames = [payload_data(x) for x in payload_lengths()]
|
||||||
|
|
||||||
@ -204,7 +208,7 @@ async def run_test_tx(dut, payload_lengths=None, payload_data=None, ifg=12):
|
|||||||
assert rx_frame.get_payload() == test_data
|
assert rx_frame.get_payload() == test_data
|
||||||
assert rx_frame.check_fcs()
|
assert rx_frame.check_fcs()
|
||||||
assert rx_frame.ctrl is None
|
assert rx_frame.ctrl is None
|
||||||
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < tb.clk_period
|
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < tb.clk_period*2
|
||||||
|
|
||||||
assert tb.serdes_sink.empty()
|
assert tb.serdes_sink.empty()
|
||||||
|
|
||||||
@ -229,6 +233,8 @@ async def run_test_tx_alignment(dut, payload_data=None, ifg=12):
|
|||||||
tb.log.info("Wait for PTP CDC lock")
|
tb.log.info("Wait for PTP CDC lock")
|
||||||
while not dut.tx_ptp.tx_ptp_cdc.locked.value.integer:
|
while not dut.tx_ptp.tx_ptp_cdc.locked.value.integer:
|
||||||
await RisingEdge(dut.tx_clk)
|
await RisingEdge(dut.tx_clk)
|
||||||
|
for k in range(1000):
|
||||||
|
await RisingEdge(dut.tx_clk)
|
||||||
|
|
||||||
for length in range(60, 92):
|
for length in range(60, 92):
|
||||||
|
|
||||||
@ -260,7 +266,7 @@ async def run_test_tx_alignment(dut, payload_data=None, ifg=12):
|
|||||||
assert rx_frame.get_payload() == test_data
|
assert rx_frame.get_payload() == test_data
|
||||||
assert rx_frame.check_fcs()
|
assert rx_frame.check_fcs()
|
||||||
assert rx_frame.ctrl is None
|
assert rx_frame.ctrl is None
|
||||||
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < tb.clk_period
|
assert abs(rx_frame_sfd_ns - ptp_ts_ns - tb.clk_period*5) < tb.clk_period*2
|
||||||
|
|
||||||
start_lane.append(rx_frame.start_lane)
|
start_lane.append(rx_frame.start_lane)
|
||||||
|
|
||||||
@ -431,7 +437,6 @@ def test_eth_mac_phy_10g_fifo(request, data_width, enable_dic):
|
|||||||
parameters['RX_DROP_WHEN_FULL'] = parameters['RX_DROP_OVERSIZE_FRAME']
|
parameters['RX_DROP_WHEN_FULL'] = parameters['RX_DROP_OVERSIZE_FRAME']
|
||||||
parameters['PTP_PERIOD_NS'] = 0x6 if parameters['DATA_WIDTH'] == 64 else 0x3
|
parameters['PTP_PERIOD_NS'] = 0x6 if parameters['DATA_WIDTH'] == 64 else 0x3
|
||||||
parameters['PTP_PERIOD_FNS'] = 0x6666 if parameters['DATA_WIDTH'] == 64 else 0x3333
|
parameters['PTP_PERIOD_FNS'] = 0x6666 if parameters['DATA_WIDTH'] == 64 else 0x3333
|
||||||
parameters['PTP_USE_SAMPLE_CLOCK'] = 0
|
|
||||||
parameters['TX_PTP_TS_ENABLE'] = 1
|
parameters['TX_PTP_TS_ENABLE'] = 1
|
||||||
parameters['RX_PTP_TS_ENABLE'] = parameters['TX_PTP_TS_ENABLE']
|
parameters['RX_PTP_TS_ENABLE'] = parameters['TX_PTP_TS_ENABLE']
|
||||||
parameters['TX_PTP_TS_CTRL_IN_TUSER'] = parameters['TX_PTP_TS_ENABLE']
|
parameters['TX_PTP_TS_CTRL_IN_TUSER'] = parameters['TX_PTP_TS_ENABLE']
|
||||||
|
@ -24,7 +24,7 @@ SIM ?= icarus
|
|||||||
WAVES ?= 0
|
WAVES ?= 0
|
||||||
|
|
||||||
COCOTB_HDL_TIMEUNIT = 1ns
|
COCOTB_HDL_TIMEUNIT = 1ns
|
||||||
COCOTB_HDL_TIMEPRECISION = 1ps
|
COCOTB_HDL_TIMEPRECISION = 1fs
|
||||||
|
|
||||||
DUT = ptp_clock_cdc
|
DUT = ptp_clock_cdc
|
||||||
TOPLEVEL = $(DUT)
|
TOPLEVEL = $(DUT)
|
||||||
@ -34,8 +34,6 @@ VERILOG_SOURCES += ../../rtl/$(DUT).v
|
|||||||
# module parameters
|
# module parameters
|
||||||
export PARAM_TS_WIDTH := 96
|
export PARAM_TS_WIDTH := 96
|
||||||
export PARAM_NS_WIDTH := 4
|
export PARAM_NS_WIDTH := 4
|
||||||
export PARAM_FNS_WIDTH := 16
|
|
||||||
export PARAM_USE_SAMPLE_CLOCK := 1
|
|
||||||
export PARAM_LOG_RATE := 3
|
export PARAM_LOG_RATE := 3
|
||||||
export PARAM_PIPELINE_OUTPUT := 0
|
export PARAM_PIPELINE_OUTPUT := 0
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Copyright (c) 2020 Alex Forencich
|
Copyright (c) 2020-2023 Alex Forencich
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -25,6 +25,7 @@ THE SOFTWARE.
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
from statistics import mean, stdev
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import cocotb_test.simulator
|
import cocotb_test.simulator
|
||||||
@ -32,7 +33,7 @@ import cocotb_test.simulator
|
|||||||
import cocotb
|
import cocotb
|
||||||
from cocotb.clock import Clock
|
from cocotb.clock import Clock
|
||||||
from cocotb.triggers import RisingEdge, Timer
|
from cocotb.triggers import RisingEdge, Timer
|
||||||
from cocotb.utils import get_sim_steps
|
from cocotb.utils import get_sim_steps, get_sim_time
|
||||||
|
|
||||||
from cocotbext.eth import PtpClock
|
from cocotbext.eth import PtpClock
|
||||||
|
|
||||||
@ -44,9 +45,7 @@ class TB:
|
|||||||
self.log = logging.getLogger("cocotb.tb")
|
self.log = logging.getLogger("cocotb.tb")
|
||||||
self.log.setLevel(logging.DEBUG)
|
self.log.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
cocotb.start_soon(Clock(dut.input_clk, 6.4, units="ns").start())
|
cocotb.start_soon(Clock(dut.sample_clk, 9.9, units="ns").start())
|
||||||
|
|
||||||
cocotb.start_soon(Clock(dut.sample_clk, 10, units="ns").start())
|
|
||||||
|
|
||||||
if len(dut.input_ts) == 64:
|
if len(dut.input_ts) == 64:
|
||||||
self.ptp_clock = PtpClock(
|
self.ptp_clock = PtpClock(
|
||||||
@ -65,8 +64,13 @@ class TB:
|
|||||||
period_ns=6.4
|
period_ns=6.4
|
||||||
)
|
)
|
||||||
|
|
||||||
self._clock_cr = None
|
self.input_clock_period = 6.4
|
||||||
self.set_output_clock_period(6.4)
|
dut.input_clk.setimmediatevalue(0)
|
||||||
|
cocotb.start_soon(self._run_input_clock())
|
||||||
|
|
||||||
|
self.output_clock_period = 6.4
|
||||||
|
dut.output_clk.setimmediatevalue(0)
|
||||||
|
cocotb.start_soon(self._run_output_clock())
|
||||||
|
|
||||||
async def reset(self):
|
async def reset(self):
|
||||||
self.dut.input_rst.setimmediatevalue(0)
|
self.dut.input_rst.setimmediatevalue(0)
|
||||||
@ -82,17 +86,33 @@ class TB:
|
|||||||
for k in range(10):
|
for k in range(10):
|
||||||
await RisingEdge(self.dut.input_clk)
|
await RisingEdge(self.dut.input_clk)
|
||||||
|
|
||||||
def set_output_clock_period(self, period):
|
def set_input_clock_period(self, period):
|
||||||
if self._clock_cr is not None:
|
self.input_clock_period = period
|
||||||
self._clock_cr.kill()
|
|
||||||
|
|
||||||
self._clock_cr = cocotb.start_soon(self._run_clock(period))
|
async def _run_input_clock(self):
|
||||||
|
period = None
|
||||||
async def _run_clock(self, period):
|
steps_per_ns = get_sim_steps(1.0, 'ns')
|
||||||
half_period = get_sim_steps(period / 2.0, 'ns')
|
|
||||||
t = Timer(half_period)
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
if period != self.input_clock_period:
|
||||||
|
period = self.input_clock_period
|
||||||
|
t = Timer(int(steps_per_ns * period / 2.0))
|
||||||
|
await t
|
||||||
|
self.dut.input_clk.value = 1
|
||||||
|
await t
|
||||||
|
self.dut.input_clk.value = 0
|
||||||
|
|
||||||
|
def set_output_clock_period(self, period):
|
||||||
|
self.output_clock_period = period
|
||||||
|
|
||||||
|
async def _run_output_clock(self):
|
||||||
|
period = None
|
||||||
|
steps_per_ns = get_sim_steps(1.0, 'ns')
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if period != self.output_clock_period:
|
||||||
|
period = self.output_clock_period
|
||||||
|
t = Timer(int(steps_per_ns * period / 2.0))
|
||||||
await t
|
await t
|
||||||
self.dut.output_clk.value = 1
|
self.dut.output_clk.value = 1
|
||||||
await t
|
await t
|
||||||
@ -112,14 +132,45 @@ class TB:
|
|||||||
else:
|
else:
|
||||||
return (ts >> 48) + ((ts & 0xffffffffffff)/2**16*1e-9)
|
return (ts >> 48) + ((ts & 0xffffffffffff)/2**16*1e-9)
|
||||||
|
|
||||||
async def measure_ts_diff(self, N=1000):
|
async def measure_ts_diff(self, N=100):
|
||||||
total = 0
|
input_ts_lst = []
|
||||||
|
output_ts_lst = []
|
||||||
|
|
||||||
|
async def collect_timestamps(clk, get_ts, lst):
|
||||||
|
while True:
|
||||||
|
await RisingEdge(clk)
|
||||||
|
lst.append((get_sim_time('sec'), get_ts()))
|
||||||
|
|
||||||
|
input_cr = cocotb.start_soon(collect_timestamps(self.dut.input_clk, self.get_input_ts_ns, input_ts_lst))
|
||||||
|
output_cr = cocotb.start_soon(collect_timestamps(self.dut.output_clk, self.get_output_ts_ns, output_ts_lst))
|
||||||
|
|
||||||
for k in range(N):
|
for k in range(N):
|
||||||
input_ts_ns = self.get_input_ts_ns()
|
await RisingEdge(self.dut.output_clk)
|
||||||
output_ts_ns = self.get_output_ts_ns()
|
|
||||||
total += input_ts_ns-output_ts_ns
|
input_cr.kill()
|
||||||
await Timer(100, 'ps')
|
output_cr.kill()
|
||||||
return total/N
|
|
||||||
|
diffs = []
|
||||||
|
|
||||||
|
its1 = input_ts_lst.pop(0)
|
||||||
|
its2 = input_ts_lst.pop(0)
|
||||||
|
|
||||||
|
for ots in output_ts_lst:
|
||||||
|
while its2[0] < ots[0] and input_ts_lst:
|
||||||
|
its1 = its2
|
||||||
|
its2 = input_ts_lst.pop(0)
|
||||||
|
|
||||||
|
if its2[0] < ots[0]:
|
||||||
|
break
|
||||||
|
|
||||||
|
dt = its2[0] - its1[0]
|
||||||
|
dts = its2[1] - its1[1]
|
||||||
|
|
||||||
|
its = its1[1]+dts/dt*(ots[0]-its1[0])
|
||||||
|
|
||||||
|
diffs.append(ots[1] - its)
|
||||||
|
|
||||||
|
return diffs
|
||||||
|
|
||||||
|
|
||||||
@cocotb.test()
|
@cocotb.test()
|
||||||
@ -132,90 +183,236 @@ async def run_test(dut):
|
|||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
tb.log.info("Same clock speed")
|
tb.log.info("Same clock speed")
|
||||||
|
|
||||||
|
tb.set_input_clock_period(6.4)
|
||||||
|
tb.set_output_clock_period(6.4)
|
||||||
|
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
for i in range(40000):
|
for i in range(100000):
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
assert tb.dut.locked.value.integer
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
diff = await tb.measure_ts_diff()*1e9
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
tb.log.info(f"Difference: {diff} ns")
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
assert abs(diff) < 10
|
|
||||||
|
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
tb.log.info("Slightly faster")
|
tb.log.info("10 ppm slower")
|
||||||
|
|
||||||
tb.set_output_clock_period(6.2)
|
tb.set_input_clock_period(6.4)
|
||||||
|
tb.set_output_clock_period(6.4*(1+.00001))
|
||||||
|
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
for i in range(40000):
|
for i in range(100000):
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
assert tb.dut.locked.value.integer
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
diff = await tb.measure_ts_diff()*1e9
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
tb.log.info(f"Difference: {diff} ns")
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
assert abs(diff) < 10
|
|
||||||
|
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
tb.log.info("Slightly slower")
|
tb.log.info("10 ppm faster")
|
||||||
|
|
||||||
tb.set_output_clock_period(6.6)
|
tb.set_input_clock_period(6.4)
|
||||||
|
tb.set_output_clock_period(6.4*(1-.00001))
|
||||||
|
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
for i in range(40000):
|
for i in range(100000):
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
assert tb.dut.locked.value.integer
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
diff = await tb.measure_ts_diff()*1e9
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
tb.log.info(f"Difference: {diff} ns")
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
assert abs(diff) < 10
|
|
||||||
|
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
tb.log.info("Significantly faster")
|
tb.log.info("200 ppm slower")
|
||||||
|
|
||||||
|
tb.set_input_clock_period(6.4)
|
||||||
|
tb.set_output_clock_period(6.4*(1+.0002))
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
for i in range(100000):
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
tb.log.info("200 ppm faster")
|
||||||
|
|
||||||
|
tb.set_input_clock_period(6.4)
|
||||||
|
tb.set_output_clock_period(6.4*(1-.0002))
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
for i in range(100000):
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
tb.log.info("Coherent tracking (+/- 10 ppm)")
|
||||||
|
|
||||||
|
tb.set_input_clock_period(6.4)
|
||||||
|
tb.set_output_clock_period(6.4)
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
period = 6.400
|
||||||
|
step = 0.000002
|
||||||
|
period_min = 6.4*(1-.00001)
|
||||||
|
period_max = 6.4*(1+.00001)
|
||||||
|
|
||||||
|
for i in range(500):
|
||||||
|
period += step
|
||||||
|
|
||||||
|
if period <= period_min:
|
||||||
|
step = abs(step)
|
||||||
|
if period >= period_max:
|
||||||
|
step = -abs(step)
|
||||||
|
|
||||||
|
tb.set_output_clock_period(period)
|
||||||
|
|
||||||
|
for i in range(200):
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
tb.log.info("Coherent tracking (+/- 200 ppm)")
|
||||||
|
|
||||||
|
tb.set_input_clock_period(6.4)
|
||||||
|
tb.set_output_clock_period(6.4)
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
period = 6.400
|
||||||
|
step = 0.000002
|
||||||
|
period_min = 6.4*(1-.0002)
|
||||||
|
period_max = 6.4*(1+.0002)
|
||||||
|
|
||||||
|
for i in range(5000):
|
||||||
|
period += step
|
||||||
|
|
||||||
|
if period <= period_min:
|
||||||
|
step = abs(step)
|
||||||
|
if period >= period_max:
|
||||||
|
step = -abs(step)
|
||||||
|
|
||||||
|
tb.set_output_clock_period(period)
|
||||||
|
|
||||||
|
for i in range(20):
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
tb.log.info("Slightly faster (6.3 ns)")
|
||||||
|
|
||||||
|
tb.set_input_clock_period(6.4)
|
||||||
|
tb.set_output_clock_period(6.3)
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
for i in range(100000):
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
tb.log.info("Slightly slower (6.5 ns)")
|
||||||
|
|
||||||
|
tb.set_input_clock_period(6.4)
|
||||||
|
tb.set_output_clock_period(6.5)
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
for i in range(100000):
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
tb.log.info("Significantly faster (250 MHz)")
|
||||||
|
|
||||||
|
tb.set_input_clock_period(6.4)
|
||||||
tb.set_output_clock_period(4.0)
|
tb.set_output_clock_period(4.0)
|
||||||
|
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
for i in range(40000):
|
for i in range(100000):
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
assert tb.dut.locked.value.integer
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
diff = await tb.measure_ts_diff()*1e9
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
tb.log.info(f"Difference: {diff} ns")
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
assert abs(diff) < 10
|
|
||||||
|
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
tb.log.info("Significantly slower")
|
tb.log.info("Significantly slower (100 MHz)")
|
||||||
|
|
||||||
|
tb.set_input_clock_period(6.4)
|
||||||
tb.set_output_clock_period(10.0)
|
tb.set_output_clock_period(10.0)
|
||||||
|
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
for i in range(30000):
|
for i in range(100000):
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
assert tb.dut.locked.value.integer
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
diff = await tb.measure_ts_diff()*1e9
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
tb.log.info(f"Difference: {diff} ns")
|
await RisingEdge(dut.input_clk)
|
||||||
|
tb.log.info("Significantly faster (390.625 MHz)")
|
||||||
|
|
||||||
assert abs(diff) < 10
|
tb.set_input_clock_period(6.4)
|
||||||
|
tb.set_output_clock_period(2.56)
|
||||||
|
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
for i in range(100000):
|
||||||
|
await RisingEdge(dut.input_clk)
|
||||||
|
|
||||||
|
assert tb.dut.locked.value.integer
|
||||||
|
|
||||||
|
diffs = await tb.measure_ts_diff()
|
||||||
|
tb.log.info(f"Difference: {mean(diffs)*1e9} ns (stdev: {stdev(diffs)*1e9})")
|
||||||
|
assert abs(mean(diffs)*1e9) < 5
|
||||||
|
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
await RisingEdge(dut.input_clk)
|
await RisingEdge(dut.input_clk)
|
||||||
@ -229,9 +426,8 @@ lib_dir = os.path.abspath(os.path.join(rtl_dir, '..', 'lib'))
|
|||||||
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
axis_rtl_dir = os.path.abspath(os.path.join(lib_dir, 'axis', 'rtl'))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("sample_clock", [1, 0])
|
|
||||||
@pytest.mark.parametrize("ts_width", [96, 64])
|
@pytest.mark.parametrize("ts_width", [96, 64])
|
||||||
def test_ptp_clock_cdc(request, ts_width, sample_clock):
|
def test_ptp_clock_cdc(request, ts_width):
|
||||||
dut = "ptp_clock_cdc"
|
dut = "ptp_clock_cdc"
|
||||||
module = os.path.splitext(os.path.basename(__file__))[0]
|
module = os.path.splitext(os.path.basename(__file__))[0]
|
||||||
toplevel = dut
|
toplevel = dut
|
||||||
@ -244,8 +440,6 @@ def test_ptp_clock_cdc(request, ts_width, sample_clock):
|
|||||||
|
|
||||||
parameters['TS_WIDTH'] = ts_width
|
parameters['TS_WIDTH'] = ts_width
|
||||||
parameters['NS_WIDTH'] = 4
|
parameters['NS_WIDTH'] = 4
|
||||||
parameters['FNS_WIDTH'] = 16
|
|
||||||
parameters['USE_SAMPLE_CLOCK'] = sample_clock
|
|
||||||
parameters['LOG_RATE'] = 3
|
parameters['LOG_RATE'] = 3
|
||||||
parameters['PIPELINE_OUTPUT'] = 0
|
parameters['PIPELINE_OUTPUT'] = 0
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user