up_clock_mon: Remove extra hold register
Currently the clock monitor features a hold register in the monitored clock domain. This old register is used to store a instantaneous copy of the counter register. The value in the old register is then transferred to the monitoring domain. Since the counter is continuously counting it is not possible to directly transfer it since that might result in inconsistent data. Instead stop the counter and hold the registers stable for a duration that is long enough for the monitoring domain to correctly capture the value. Once the value has been transferred the counter is reset and restarted for the next iteration. This allows to eliminate the hold register, which slightly reduces utilization. The externally visible behaviour is identical before and after the patch. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>main
parent
696305360c
commit
139876d28a
|
@ -38,76 +38,89 @@ module up_clock_mon (
|
|||
|
||||
// internal registers
|
||||
|
||||
reg [15:0] up_count = 'd0;
|
||||
reg up_count_toggle = 'd0;
|
||||
reg up_count_toggle_m1 = 'd0;
|
||||
reg up_count_toggle_m2 = 'd0;
|
||||
reg up_count_toggle_m3 = 'd0;
|
||||
reg d_count_toggle_m1 = 'd0;
|
||||
reg d_count_toggle_m2 = 'd0;
|
||||
reg d_count_toggle_m3 = 'd0;
|
||||
reg d_count_toggle = 'd0;
|
||||
reg [31:0] d_count_hold = 'd0;
|
||||
reg [15:0] up_count = 'd1;
|
||||
reg up_count_run = 'd0;
|
||||
reg up_count_running_m1 = 'd0;
|
||||
reg up_count_running_m2 = 'd0;
|
||||
reg up_count_running_m3 = 'd0;
|
||||
reg d_count_run_m1 = 'd0;
|
||||
reg d_count_run_m2 = 'd0;
|
||||
reg d_count_run_m3 = 'd0;
|
||||
reg [32:0] d_count = 'd0;
|
||||
|
||||
// internal signals
|
||||
|
||||
wire up_count_toggle_s;
|
||||
wire d_count_toggle_s;
|
||||
wire up_count_capture_s;
|
||||
wire d_count_reset_s;
|
||||
|
||||
// processor reference
|
||||
|
||||
assign up_count_toggle_s = up_count_toggle_m3 ^ up_count_toggle_m2;
|
||||
// Capture on the falling edge of running
|
||||
assign up_count_capture_s = up_count_running_m3 == 1'b1 && up_count_running_m2 == 1'b0;
|
||||
|
||||
always @(negedge up_rstn or posedge up_clk) begin
|
||||
if (up_rstn == 0) begin
|
||||
up_count_running_m1 <= 1'b0;
|
||||
up_count_running_m2 <= 1'b0;
|
||||
up_count_running_m3 <= 1'b0;
|
||||
end else begin
|
||||
up_count_running_m1 <= d_count_run_m3;
|
||||
up_count_running_m2 <= up_count_running_m1;
|
||||
up_count_running_m3 <= up_count_running_m2;
|
||||
end
|
||||
end
|
||||
|
||||
always @(negedge up_rstn or posedge up_clk) begin
|
||||
if (up_rstn == 0) begin
|
||||
up_count <= 'd0;
|
||||
up_count_toggle <= 'd0;
|
||||
up_count_toggle_m1 <= 'd0;
|
||||
up_count_toggle_m2 <= 'd0;
|
||||
up_count_toggle_m3 <= 'd0;
|
||||
up_d_count <= 'd0;
|
||||
up_count_run <= 1'b0;
|
||||
end else begin
|
||||
if (up_count_running_m3 == 1'b0) begin
|
||||
up_count_run <= 1'b1;
|
||||
end else if (up_count == 'h00) begin
|
||||
up_count_run <= 1'b0;
|
||||
end
|
||||
|
||||
if (up_count_capture_s == 1'b1) begin
|
||||
up_d_count <= d_count;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge up_clk) begin
|
||||
if (up_count_run == 1'b0) begin
|
||||
up_count <= 'h01;
|
||||
end else begin
|
||||
up_count <= up_count + 1'b1;
|
||||
if (up_count == 16'd0) begin
|
||||
up_count_toggle <= ~up_count_toggle;
|
||||
end
|
||||
up_count_toggle_m1 <= d_count_toggle;
|
||||
up_count_toggle_m2 <= up_count_toggle_m1;
|
||||
up_count_toggle_m3 <= up_count_toggle_m2;
|
||||
if (up_count_toggle_s == 1'b1) begin
|
||||
up_d_count <= d_count_hold;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// device free running
|
||||
|
||||
assign d_count_toggle_s = d_count_toggle_m3 ^ d_count_toggle_m2;
|
||||
// Reset on the rising edge of run
|
||||
assign d_count_reset_s = d_count_run_m3 == 1'b0 && d_count_run_m2 == 1'b1;
|
||||
|
||||
always @(posedge d_clk or posedge d_rst) begin
|
||||
if (d_rst == 1'b1) begin
|
||||
d_count_toggle_m1 <= 'd0;
|
||||
d_count_toggle_m2 <= 'd0;
|
||||
d_count_toggle_m3 <= 'd0;
|
||||
d_count_run_m1 <= 1'b0;
|
||||
d_count_run_m2 <= 1'b0;
|
||||
d_count_run_m3 <= 1'b0;
|
||||
end else begin
|
||||
d_count_toggle_m1 <= up_count_toggle;
|
||||
d_count_toggle_m2 <= d_count_toggle_m1;
|
||||
d_count_toggle_m3 <= d_count_toggle_m2;
|
||||
d_count_run_m1 <= up_count_run;
|
||||
d_count_run_m2 <= d_count_run_m1;
|
||||
d_count_run_m3 <= d_count_run_m2;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge d_clk) begin
|
||||
if (d_count_toggle_s == 1'b1) begin
|
||||
d_count_toggle <= ~d_count_toggle;
|
||||
d_count_hold <= d_count[31:0];
|
||||
end
|
||||
if (d_count_toggle_s == 1'b1) begin
|
||||
d_count <= 33'd1;
|
||||
end else if (d_count[32] == 1'b0) begin
|
||||
d_count <= d_count + 1'b1;
|
||||
end else begin
|
||||
d_count <= {33{1'b1}};
|
||||
if (d_count_reset_s == 1'b1) begin
|
||||
d_count <= 'h00;
|
||||
end else if (d_count_run_m3 == 1'b1) begin
|
||||
if (d_count[32] == 1'b0) begin
|
||||
d_count <= d_count + 1'b1;
|
||||
end else begin
|
||||
d_count <= {33{1'b1}};
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
set_property ASYNC_REG TRUE [get_cells -hier -filter {name =~ *up_count_toggle_m*}]
|
||||
set_property ASYNC_REG TRUE [get_cells -hier -filter {name =~ *d_count_toggle_m*}]
|
||||
set_property ASYNC_REG true [get_cells -hier -filter {name =~ *up_count_running_m*}]
|
||||
set_property ASYNC_REG true [get_cells -hier -filter {name =~ *d_count_run_m*}]
|
||||
|
||||
set_false_path -from [get_cells -hier -filter {name =~ *d_count_toggle_reg && IS_SEQUENTIAL}] -to [get_cells -hier -filter {name =~ *up_count_toggle_m1_reg && IS_SEQUENTIAL}]
|
||||
set_false_path -from [get_cells -hier -filter {name =~ *up_count_toggle_reg && IS_SEQUENTIAL}] -to [get_cells -hier -filter {name =~ *d_count_toggle_m1_reg && IS_SEQUENTIAL}]
|
||||
set_false_path -from [get_cells -hier -filter {name =~ *d_count_hold* && IS_SEQUENTIAL}] -to [get_cells -hier -filter {name =~ *up_d_count* && IS_SEQUENTIAL}]
|
||||
set_false_path -from [get_cells -hier -filter {name =~ *d_count_run_m3_reg && IS_SEQUENTIAL}] -to [get_cells -hier -filter {name =~ *up_count_running_m1_reg && IS_SEQUENTIAL}]
|
||||
set_false_path -from [get_cells -hier -filter {name =~ *up_count_run_reg && IS_SEQUENTIAL}] -to [get_cells -hier -filter {name =~ *d_count_run_m1_reg && IS_SEQUENTIAL}]
|
||||
set_false_path -from [get_cells -hier -filter {name =~ *d_count* && IS_SEQUENTIAL}] -to [get_cells -hier -filter {name =~ *up_d_count* && IS_SEQUENTIAL}]
|
||||
|
|
Loading…
Reference in New Issue