SystemVerilog probes · 33cVivado: supported
the textbook's tristate buffer module (assign y = en ? a : 4'bz) instantiated four times, each driving one nibble of an output tri [15:0] port
Vivado: supported. The open-source chain: it stops before a bitstream.
| stage | today |
|---|---|
| rtl, simulation | pass |
| synth, synthesis | pass |
| netlist, the netlist | fail |
| bit, the bitstream | fail |
What does Vivado do with it?
Supported. UG901 v2023.2 Ch.5 'Tristates' (p.86): 'Inferred Tristate buffers are implemented with ... An external pin of the circuit (OBUFT)', and 'When an internal bus inferring a BUFT is driving an output of the top module, the Vivado synthesis infers an OBUF.'
What does the open-source chain do with it?
yosys keeps the buffers as $_TBUF_ cells: the netlist has no model for them (netlist fails), and nextpnr stops with 'no Bels remaining of type '$_TBUF_'', which since #5 the CLI reads as 'design.sv:4: ERROR [internal-tristate]: a tri-state driver (a z, at design.sv:4) on a signal that is not an inout pin of the top module: the chip has tri-state buffers on its pins only. Vivado converts such a driver to logic (UG901 Ch.5 Tristates); yosys keeps it as a $_TBUF_ cell, and nextpnr has nothing to place it on. Not a size problem. Fix: select with a mux instead: assign bus = sel ? b : a; and keep z for an inout pin only.' (before #5: the design does not fit the XC7A35T, for four buffers). One instance driving the whole port, or the same buffers written in top, builds (measured apart)
Which error pages explain the messages?
- internal-tristate: A z driven onto an internal signal or a submodule port; the chip's tri-state buffers sit on pins only, and yosys keeps the buffer as a cell nextpnr cannot place.
What is the probe's code?
From test/sv/33c_tristate_submodule_port.
design.sv
module tristate(input logic [3:0] a, // the textbook's tristate buffer
input logic en,
output tri [3:0] y);
assign y = en ? a : 4'bz;
endmodule
module top(input logic [15:0] sw, output tri [15:0] led); // each nibble of led driven from its own instance
tristate t0 (.a(sw[3:0]), .en(sw[15]), .y(led[3:0]));
tristate t1 (.a(sw[7:4]), .en(sw[14]), .y(led[7:4]));
tristate t2 (.a(sw[11:8]), .en(sw[13]), .y(led[11:8]));
tristate t3 (.a(sw[15:12]), .en(sw[12]), .y(led[15:12]));
endmodule
tb.sv
module tb;
logic [15:0] sw; wire [15:0] led;
top dut(.sw(sw), .led(led));
integer i, k, bad = 0; logic [3:0] want;
initial begin
for (i = 0; i < 65536; i++) begin
sw = i; #1;
for (k = 0; k < 4; k++) begin
want = sw[15 - k] ? sw[4*k +: 4] : 4'bzzzz; // a nibble that is not enabled floats
if (led[4*k +: 4] !== want) begin bad++; if (bad < 4) $display("FAIL: sw=%h led=%h", sw, led); end
end
end
if (bad == 0) $display("PASS"); else $display("FAIL: %0d", bad);
$finish;
end
endmodule
previous: inout pin only read (never assigned 'z) + one bidirectional pin
next: UNISIM primitive instantiation: BUFG