SystemVerilog probes · 31bVivado: supported
registers on the falling edge with no start value: a counter with a synchronous set (FDSE_1) and a bit with an asynchronous preset (FDPE_1), both reset from two switches
Vivado: supported. The open-source chain: all four stages pass.
| stage | today |
|---|---|
| rtl, simulation | pass |
| synth, synthesis | pass |
| netlist, the netlist | pass |
| bit, the bitstream | pass |
What does Vivado do with it?
Supported. UG901 v2023.2 Ch.5 'Flip-Flops, Registers, and Latches' (p.81): Vivado synthesis recognizes registers with 'Rising or falling-edge clocks', 'Asynchronous Set/Reset' and 'Synchronous Set/Reset'
What does the open-source chain do with it?
every stage passes: yosys maps the counter to FDSE_1 and the preset bit to FDPE_1; since #34 the Makefile sets their INIT to 1 before write_json (setundef -one -params; before, INIT x), the value nextpnr programs, so the netlist starts both at 1 and equals the RTL started at 1 (the resets are built from two switches, so the bench does not press them first). Since #5 the pnr line names the clock by its port, 'pnr ok: 11 LUT, 5 FF, clk' '(PASS at 100.00 MHz)' (before #5 a cut internal name ending in slice$...C, the net after abc9)
What is the probe's code?
From test/sv/31b_negedge_set.
design.sv
// registers clocked on the falling edge, with no start value: a counter with a synchronous set and a bit with
// an asynchronous preset. Both resets are built from two switches, so the power-up state shows until they are used
module top(input logic clk, input logic [15:0] sw, output logic [15:0] led);
logic [3:0] q;
logic p;
wire pre = sw[13] & sw[12];
always_ff @(negedge clk)
if (sw[15] & sw[14]) q <= 4'hf;
else q <= q + 4'd1;
always_ff @(negedge clk, posedge pre)
if (pre) p <= 1'b1;
else p <= sw[0];
assign led = {11'd0, p, q};
endmodule
tb.sv
module tb;
logic clk = 1; logic [15:0] sw = 0; logic [15:0] led;
top dut(.clk(clk), .sw(sw), .led(led));
always #5 clk = ~clk; // falling edges at 5, 15, 25, ...
integer i, bad = 0;
initial begin
sw = 16'hc000; @(posedge clk); #1; // no edge yet: nothing set
@(negedge clk); #1 if (led[3:0] !== 4'hf) begin bad++; $display("FAIL: the set on the falling edge: led=%h", led); end
sw = 16'h0000;
for (i = 1; i <= 20; i++) begin
@(posedge clk); #1 if (led[3:0] !== 4'(15 + i - 1)) begin bad++; if (bad < 4) $display("FAIL: the rising edge moved q: led=%h", led); end
@(negedge clk); #1 if (led[3:0] !== 4'(15 + i)) begin bad++; if (bad < 4) $display("FAIL: after %0d falling edges led=%h", i, led); end
end
sw = 16'h3000; #1 if (led[4] !== 1'b1) begin bad++; $display("FAIL: the preset, before any edge: led=%h", led); end
sw = 16'h0000; @(negedge clk); #1 if (led[4] !== 1'b0) begin bad++; $display("FAIL: p follows sw[0] on the falling edge: led=%h", led); end
sw = 16'h0001; @(posedge clk); #1 if (led[4] !== 1'b0) begin bad++; $display("FAIL: p moved on a rising edge: led=%h", led); end
@(negedge clk); #1 if (led[4] !== 1'b1) begin bad++; $display("FAIL: p follows sw[0] on the falling edge: led=%h", led); end
if (bad == 0) $display("PASS"); else $display("FAIL: %0d checks", bad);
$finish;
end
endmodule
previous: sync active-high reset, async active-low reset (negedge rst_n), async set to a nonzero constant
next: clock divider making a derived clock (always_ff @(posedge slow)) + 4-digit 7-seg multiplexing + hex ROM via case