SystemVerilog probes · 101bVivado: supported
the same always_latch next to a foreach loop (43_foreach_loop), so the design is read with yosys-slang
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 Latches (p.84): the LDCE Vivado builds for a latch (the 01_latch_comb source); Ch.10 Table 27 (p.287): 'Loop statements: Supported'
What does the open-source chain do with it?
built by yosys-slang ('note [read-with-slang]' in bit.log), and the same warning at the always_latch line: 'design.sv:4: warning [latch-hazard]: always_latch builds a latch for q (an LDCE cell, as Vivado builds it, UG901 Ch.5 Latches), and a latch has no clock: when its gate (sw[1]) closes in the same instant its data changes' then 'if (sw[1]) q <= ...; keep always_latch only when the gate is held steady while the data changes.'; bit: 'pnr ok: 27 LUT, 1 FF, no clocked paths, timing not applicable'
Which error pages explain the messages?
- latch-hazard: An always_latch whose gate and data come from the same inputs: when both change at once the board races, where the simulation keeps the old value; the build goes on with the warning.
- read-with-slang: Not an error: yosys' own reader refused the code, yosys-slang read it, and synthesis went on as usual.
What is the probe's code?
From test/sv/101b_always_latch_slang.
design.sv
module top(input logic [15:0] sw, output logic [15:0] led);
logic q;
logic [3:0] n [0:3];
always_latch if (sw[1]) q = sw[0]; // a latch on purpose: sw[1] is its gate
always_comb foreach (n[i]) n[i] = sw[4*i +: 4] + 4'(i); // foreach: yosys' own reader refuses it, yosys-slang reads it
assign led = {n[3], n[2], n[1], n[0][3:1], q};
endmodule
tb.sv
module tb;
reg clk = 1'b0;
reg btnC = 1'b0, btnU = 1'b0, btnD = 1'b0, btnL = 1'b0, btnR = 1'b0;
reg [15:0] sw = 16'h0000;
wire [15:0] led; wire [6:0] seg; wire dp; wire [3:0] an;
task tick; begin #5 clk = 1'b1; #5 clk = 1'b0; end endtask
initial begin #200000 $display("FAIL: timeout"); $finish; end
top dut(.sw(sw), .led(led));
initial begin
sw = 16'h0003; #1
if (!(led[0] === 1'b1)) begin $display("FAIL: open latch must pass sw[0]=1 (led=%h)", led); $finish; end
sw = 16'h0001; #1 sw = 16'h0000; #1
if (!(led[0] === 1'b1)) begin $display("FAIL: closed latch must hold 1 (led=%h)", led); $finish; end
sw = 16'h0002; #1
if (!(led[0] === 1'b0)) begin $display("FAIL: open latch must pass sw[0]=0 (led=%h)", led); $finish; end
sw = 16'h0000; #1 sw = 16'h0001; #1
if (!(led[0] === 1'b0)) begin $display("FAIL: closed latch must hold 0 (led=%h)", led); $finish; end
sw = 16'h3210; #1 // n = {0+0, 1+1, 2+2, 3+3} = 0, 2, 4, 6
if (!(led[15:1] === 15'b0110_0100_0010_000)) begin $display("FAIL: foreach rows (led=%h)", led); $finish; end
$display("PASS"); $finish;
end
endmodule
previous: always_latch if (sw[1]) q = sw[0]; (a latch on purpose, sw[1] its gate), read by yosys' own reader
next: an always_latch whose gate (s < sw) and data (sw < 16'd1791) come from the same inputs, so both change at once (seed 7 of test/fuzz, shrunk)