mirror of
https://github.com/alexforencich/verilog-ethernet.git
synced 2025-02-04 07:13:13 +08:00
More extensive overhaul of the PTP period output module to improve resource consumption and parallelize computation
Signed-off-by: Alex Forencich <alex@alexforencich.com>
This commit is contained in:
parent
f313fafc70
commit
b4d09cbbdf
185
rtl/ptp_perout.v
185
rtl/ptp_perout.v
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
Copyright (c) 2019 Alex Forencich
|
Copyright (c) 2019-2024 Alex Forencich
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
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
|
||||||
@ -77,15 +77,12 @@ module ptp_perout #
|
|||||||
output wire output_pulse
|
output wire output_pulse
|
||||||
);
|
);
|
||||||
|
|
||||||
localparam [2:0]
|
localparam [1:0]
|
||||||
STATE_IDLE = 3'd0,
|
STATE_IDLE = 3'd0,
|
||||||
STATE_UPDATE_RISE_1 = 3'd1,
|
STATE_UPDATE_RISE = 3'd1,
|
||||||
STATE_UPDATE_RISE_2 = 3'd2,
|
STATE_UPDATE_FALL = 3'd2;
|
||||||
STATE_UPDATE_FALL_1 = 3'd3,
|
|
||||||
STATE_UPDATE_FALL_2 = 3'd4,
|
|
||||||
STATE_WAIT_EDGE = 3'd5;
|
|
||||||
|
|
||||||
reg [2:0] state_reg = STATE_IDLE, state_next;
|
reg [1:0] state_reg = STATE_IDLE, state_next;
|
||||||
|
|
||||||
reg [47:0] time_s_reg = 0;
|
reg [47:0] time_s_reg = 0;
|
||||||
reg [30:0] time_ns_reg = 0;
|
reg [30:0] time_ns_reg = 0;
|
||||||
@ -95,9 +92,9 @@ reg [47:0] next_rise_s_reg = 0, next_rise_s_next;
|
|||||||
reg [30:0] next_rise_ns_reg = 0, next_rise_ns_next;
|
reg [30:0] next_rise_ns_reg = 0, next_rise_ns_next;
|
||||||
reg [15:0] next_rise_fns_reg = 0, next_rise_fns_next;
|
reg [15:0] next_rise_fns_reg = 0, next_rise_fns_next;
|
||||||
|
|
||||||
reg [47:0] next_fall_s_reg = 0, next_fall_s_next;
|
reg [47:0] next_edge_s_reg = 0, next_edge_s_next;
|
||||||
reg [30:0] next_fall_ns_reg = 0, next_fall_ns_next;
|
reg [30:0] next_edge_ns_reg = 0, next_edge_ns_next;
|
||||||
reg [15:0] next_fall_fns_reg = 0, next_fall_fns_next;
|
reg [15:0] next_edge_fns_reg = 0, next_edge_fns_next;
|
||||||
|
|
||||||
reg [47:0] start_s_reg = OUT_START_S;
|
reg [47:0] start_s_reg = OUT_START_S;
|
||||||
reg [30:0] start_ns_reg = OUT_START_NS;
|
reg [30:0] start_ns_reg = OUT_START_NS;
|
||||||
@ -116,6 +113,7 @@ reg [15:0] ts_96_fns_inc_reg = 0, ts_96_fns_inc_next;
|
|||||||
reg [30:0] ts_96_ns_ovf_reg = 0, ts_96_ns_ovf_next;
|
reg [30:0] ts_96_ns_ovf_reg = 0, ts_96_ns_ovf_next;
|
||||||
reg [15:0] ts_96_fns_ovf_reg = 0, ts_96_fns_ovf_next;
|
reg [15:0] ts_96_fns_ovf_reg = 0, ts_96_fns_ovf_next;
|
||||||
|
|
||||||
|
reg restart_reg = 1'b1;
|
||||||
reg locked_reg = 1'b0, locked_next;
|
reg locked_reg = 1'b0, locked_next;
|
||||||
reg error_reg = 1'b0, error_next;
|
reg error_reg = 1'b0, error_next;
|
||||||
reg ffwd_reg = 1'b0, ffwd_next;
|
reg ffwd_reg = 1'b0, ffwd_next;
|
||||||
@ -133,9 +131,9 @@ always @* begin
|
|||||||
next_rise_ns_next = next_rise_ns_reg;
|
next_rise_ns_next = next_rise_ns_reg;
|
||||||
next_rise_fns_next = next_rise_fns_reg;
|
next_rise_fns_next = next_rise_fns_reg;
|
||||||
|
|
||||||
next_fall_s_next = next_fall_s_reg;
|
next_edge_s_next = next_edge_s_reg;
|
||||||
next_fall_ns_next = next_fall_ns_reg;
|
next_edge_ns_next = next_edge_ns_reg;
|
||||||
next_fall_fns_next = next_fall_fns_reg;
|
next_edge_fns_next = next_edge_fns_reg;
|
||||||
|
|
||||||
ts_96_ns_inc_next = ts_96_ns_inc_reg;
|
ts_96_ns_inc_next = ts_96_ns_inc_reg;
|
||||||
ts_96_fns_inc_next = ts_96_fns_inc_reg;
|
ts_96_fns_inc_next = ts_96_fns_inc_reg;
|
||||||
@ -149,97 +147,97 @@ always @* begin
|
|||||||
level_next = level_reg;
|
level_next = level_reg;
|
||||||
output_next = output_reg;
|
output_next = output_reg;
|
||||||
|
|
||||||
if (input_start_valid || input_period_valid || input_ts_step) begin
|
|
||||||
locked_next = 1'b0;
|
|
||||||
level_next = 1'b0;
|
|
||||||
output_next = 1'b0;
|
|
||||||
error_next = input_ts_step;
|
|
||||||
state_next = STATE_IDLE;
|
|
||||||
end else begin
|
|
||||||
case (state_reg)
|
case (state_reg)
|
||||||
STATE_IDLE: begin
|
STATE_IDLE: begin
|
||||||
// set next rise to start time
|
if (ffwd_reg || level_reg) begin
|
||||||
|
// fast forward or falling edge, set up for next rising edge
|
||||||
|
// set next rise time to previous rise time plus period
|
||||||
|
{ts_96_ns_inc_next, ts_96_fns_inc_next} = {next_rise_ns_reg, next_rise_fns_reg} + {period_ns_reg, period_fns_reg};
|
||||||
|
{ts_96_ns_ovf_next, ts_96_fns_ovf_next} = {next_rise_ns_reg, next_rise_fns_reg} + {period_ns_reg, period_fns_reg} - {31'd1_000_000_000, 16'd0};
|
||||||
|
end else begin
|
||||||
|
// rising edge; set up for next falling edge
|
||||||
|
// set next fall time to previous rise time plus width
|
||||||
|
{ts_96_ns_inc_next, ts_96_fns_inc_next} = {next_rise_ns_reg, next_rise_fns_reg} + {width_ns_reg, width_fns_reg};
|
||||||
|
{ts_96_ns_ovf_next, ts_96_fns_ovf_next} = {next_rise_ns_reg, next_rise_fns_reg} + {width_ns_reg, width_fns_reg} - {31'd1_000_000_000, 16'd0};
|
||||||
|
end
|
||||||
|
|
||||||
|
// wait for edge
|
||||||
|
if ((time_s_reg > next_edge_s_reg) || (time_s_reg == next_edge_s_reg && {time_ns_reg, time_fns_reg} > {next_edge_ns_reg, next_edge_fns_reg})) begin
|
||||||
|
if (ffwd_reg || level_reg) begin
|
||||||
|
// fast forward or falling edge, set up for next rising edge
|
||||||
|
output_next = 1'b0;
|
||||||
|
level_next = 1'b0;
|
||||||
|
state_next = STATE_UPDATE_RISE;
|
||||||
|
end else begin
|
||||||
|
// rising edge; set up for next falling edge
|
||||||
|
locked_next = 1'b1;
|
||||||
|
error_next = 1'b0;
|
||||||
|
output_next = enable;
|
||||||
|
level_next = 1'b1;
|
||||||
|
state_next = STATE_UPDATE_FALL;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
ffwd_next = 1'b0;
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
STATE_UPDATE_RISE: begin
|
||||||
|
if (!ts_96_ns_ovf_reg[30]) begin
|
||||||
|
// if the overflow lookahead did not borrow, one second has elapsed
|
||||||
|
next_edge_s_next = next_rise_s_reg + period_s_reg + 1;
|
||||||
|
next_edge_ns_next = ts_96_ns_ovf_reg;
|
||||||
|
next_edge_fns_next = ts_96_fns_ovf_reg;
|
||||||
|
end else begin
|
||||||
|
// no increment seconds field
|
||||||
|
next_edge_s_next = next_rise_s_reg + period_s_reg;
|
||||||
|
next_edge_ns_next = ts_96_ns_inc_reg;
|
||||||
|
next_edge_fns_next = ts_96_fns_inc_reg;
|
||||||
|
end
|
||||||
|
next_rise_s_next = next_edge_s_next;
|
||||||
|
next_rise_ns_next = next_edge_ns_next;
|
||||||
|
next_rise_fns_next = next_edge_fns_next;
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
end
|
||||||
|
STATE_UPDATE_FALL: begin
|
||||||
|
if (!ts_96_ns_ovf_reg[30]) begin
|
||||||
|
// if the overflow lookahead did not borrow, one second has elapsed
|
||||||
|
next_edge_s_next = next_rise_s_reg + width_s_reg + 1;
|
||||||
|
next_edge_ns_next = ts_96_ns_ovf_reg;
|
||||||
|
next_edge_fns_next = ts_96_fns_ovf_reg;
|
||||||
|
end else begin
|
||||||
|
// no increment seconds field
|
||||||
|
next_edge_s_next = next_rise_s_reg + width_s_reg;
|
||||||
|
next_edge_ns_next = ts_96_ns_inc_reg;
|
||||||
|
next_edge_fns_next = ts_96_fns_inc_reg;
|
||||||
|
end
|
||||||
|
state_next = STATE_IDLE;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
|
||||||
|
if (restart_reg || input_ts_step) begin
|
||||||
|
// set next rise and next edge to start time
|
||||||
next_rise_s_next = start_s_reg;
|
next_rise_s_next = start_s_reg;
|
||||||
next_rise_ns_next = start_ns_reg;
|
next_rise_ns_next = start_ns_reg;
|
||||||
if (FNS_ENABLE) begin
|
if (FNS_ENABLE) begin
|
||||||
next_rise_fns_next = start_fns_reg;
|
next_rise_fns_next = start_fns_reg;
|
||||||
end
|
end
|
||||||
|
next_edge_s_next = start_s_reg;
|
||||||
|
next_edge_ns_next = start_ns_reg;
|
||||||
|
if (FNS_ENABLE) begin
|
||||||
|
next_edge_fns_next = start_fns_reg;
|
||||||
|
end
|
||||||
locked_next = 1'b0;
|
locked_next = 1'b0;
|
||||||
ffwd_next = 1'b1;
|
ffwd_next = 1'b1;
|
||||||
output_next = 1'b0;
|
output_next = 1'b0;
|
||||||
level_next = 1'b0;
|
level_next = 1'b0;
|
||||||
state_next = STATE_WAIT_EDGE;
|
error_next = input_ts_step;
|
||||||
end
|
state_next = STATE_IDLE;
|
||||||
STATE_UPDATE_RISE_1: begin
|
|
||||||
// set next rise time to next rise time plus period
|
|
||||||
{ts_96_ns_inc_next, ts_96_fns_inc_next} = {next_rise_ns_reg, next_rise_fns_reg} + {period_ns_reg, period_fns_reg};
|
|
||||||
{ts_96_ns_ovf_next, ts_96_fns_ovf_next} = {next_rise_ns_reg, next_rise_fns_reg} + {period_ns_reg, period_fns_reg} - {31'd1_000_000_000, 16'd0};
|
|
||||||
state_next = STATE_UPDATE_RISE_2;
|
|
||||||
end
|
|
||||||
STATE_UPDATE_RISE_2: begin
|
|
||||||
if (!ts_96_ns_ovf_reg[30]) begin
|
|
||||||
// if the overflow lookahead did not borrow, one second has elapsed
|
|
||||||
next_rise_s_next = next_rise_s_reg + period_s_reg + 1;
|
|
||||||
next_rise_ns_next = ts_96_ns_ovf_reg;
|
|
||||||
next_rise_fns_next = ts_96_fns_ovf_reg;
|
|
||||||
end else begin
|
|
||||||
// no increment seconds field
|
|
||||||
next_rise_s_next = next_rise_s_reg + period_s_reg;
|
|
||||||
next_rise_ns_next = ts_96_ns_inc_reg;
|
|
||||||
next_rise_fns_next = ts_96_fns_inc_reg;
|
|
||||||
end
|
|
||||||
state_next = STATE_WAIT_EDGE;
|
|
||||||
end
|
|
||||||
STATE_UPDATE_FALL_1: begin
|
|
||||||
// set next fall time to next rise time plus width
|
|
||||||
{ts_96_ns_inc_next, ts_96_fns_inc_next} = {next_rise_ns_reg, next_rise_fns_reg} + {width_ns_reg, width_fns_reg};
|
|
||||||
{ts_96_ns_ovf_next, ts_96_fns_ovf_next} = {next_rise_ns_reg, next_rise_fns_reg} + {width_ns_reg, width_fns_reg} - {31'd1_000_000_000, 16'd0};
|
|
||||||
state_next = STATE_UPDATE_FALL_2;
|
|
||||||
end
|
|
||||||
STATE_UPDATE_FALL_2: begin
|
|
||||||
if (!ts_96_ns_ovf_reg[30]) begin
|
|
||||||
// if the overflow lookahead did not borrow, one second has elapsed
|
|
||||||
next_fall_s_next = next_rise_s_reg + width_s_reg + 1;
|
|
||||||
next_fall_ns_next = ts_96_ns_ovf_reg;
|
|
||||||
next_fall_fns_next = ts_96_fns_ovf_reg;
|
|
||||||
end else begin
|
|
||||||
// no increment seconds field
|
|
||||||
next_fall_s_next = next_rise_s_reg + width_s_reg;
|
|
||||||
next_fall_ns_next = ts_96_ns_inc_reg;
|
|
||||||
next_fall_fns_next = ts_96_fns_inc_reg;
|
|
||||||
end
|
|
||||||
state_next = STATE_WAIT_EDGE;
|
|
||||||
end
|
|
||||||
STATE_WAIT_EDGE: begin
|
|
||||||
if ((!level_reg || ffwd_reg) && ((time_s_reg > next_rise_s_reg) || (time_s_reg == next_rise_s_reg && {time_ns_reg, time_fns_reg} > {next_rise_ns_reg, next_rise_fns_reg}))) begin
|
|
||||||
// rising edge
|
|
||||||
if (ffwd_reg) begin
|
|
||||||
output_next = 1'b0;
|
|
||||||
level_next = 1'b0;
|
|
||||||
state_next = STATE_UPDATE_RISE_1;
|
|
||||||
end else begin
|
|
||||||
locked_next = 1'b1;
|
|
||||||
error_next = 1'b0;
|
|
||||||
output_next = enable;
|
|
||||||
level_next = 1'b1;
|
|
||||||
state_next = STATE_UPDATE_FALL_1;
|
|
||||||
end
|
|
||||||
end else if (level_reg && ((time_s_reg > next_fall_s_reg) || (time_s_reg == next_fall_s_reg && {time_ns_reg, time_fns_reg} > {next_fall_ns_reg, next_fall_fns_reg}))) begin
|
|
||||||
// falling edge
|
|
||||||
output_next = 1'b0;
|
|
||||||
level_next = 1'b0;
|
|
||||||
state_next = STATE_UPDATE_RISE_1;
|
|
||||||
end else begin
|
|
||||||
ffwd_next = 1'b0;
|
|
||||||
state_next = STATE_WAIT_EDGE;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
endcase
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
state_reg <= state_next;
|
state_reg <= state_next;
|
||||||
|
restart_reg <= 1'b0;
|
||||||
|
|
||||||
time_s_reg <= input_ts_96[95:48];
|
time_s_reg <= input_ts_96[95:48];
|
||||||
time_ns_reg <= input_ts_96[45:16];
|
time_ns_reg <= input_ts_96[45:16];
|
||||||
@ -253,6 +251,7 @@ always @(posedge clk) begin
|
|||||||
if (FNS_ENABLE) begin
|
if (FNS_ENABLE) begin
|
||||||
start_fns_reg <= input_start[15:0];
|
start_fns_reg <= input_start[15:0];
|
||||||
end
|
end
|
||||||
|
restart_reg <= 1'b1;
|
||||||
end
|
end
|
||||||
|
|
||||||
if (input_period_valid) begin
|
if (input_period_valid) begin
|
||||||
@ -261,6 +260,7 @@ always @(posedge clk) begin
|
|||||||
if (FNS_ENABLE) begin
|
if (FNS_ENABLE) begin
|
||||||
period_fns_reg <= input_period[15:0];
|
period_fns_reg <= input_period[15:0];
|
||||||
end
|
end
|
||||||
|
restart_reg <= 1'b1;
|
||||||
end
|
end
|
||||||
|
|
||||||
if (input_width_valid) begin
|
if (input_width_valid) begin
|
||||||
@ -277,10 +277,10 @@ always @(posedge clk) begin
|
|||||||
next_rise_fns_reg <= next_rise_fns_next;
|
next_rise_fns_reg <= next_rise_fns_next;
|
||||||
end
|
end
|
||||||
|
|
||||||
next_fall_s_reg <= next_fall_s_next;
|
next_edge_s_reg <= next_edge_s_next;
|
||||||
next_fall_ns_reg <= next_fall_ns_next;
|
next_edge_ns_reg <= next_edge_ns_next;
|
||||||
if (FNS_ENABLE) begin
|
if (FNS_ENABLE) begin
|
||||||
next_fall_fns_reg <= next_fall_fns_next;
|
next_edge_fns_reg <= next_edge_fns_next;
|
||||||
end
|
end
|
||||||
|
|
||||||
ts_96_ns_inc_reg <= ts_96_ns_inc_next;
|
ts_96_ns_inc_reg <= ts_96_ns_inc_next;
|
||||||
@ -314,6 +314,7 @@ always @(posedge clk) begin
|
|||||||
width_ns_reg <= OUT_WIDTH_NS;
|
width_ns_reg <= OUT_WIDTH_NS;
|
||||||
width_fns_reg <= OUT_WIDTH_FNS;
|
width_fns_reg <= OUT_WIDTH_FNS;
|
||||||
|
|
||||||
|
restart_reg <= 1'b1;
|
||||||
locked_reg <= 1'b0;
|
locked_reg <= 1'b0;
|
||||||
error_reg <= 1'b0;
|
error_reg <= 1'b0;
|
||||||
output_reg <= 1'b0;
|
output_reg <= 1'b0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user