SystemVerilog probes · 52Vivado: supported
an internal tri bus with two tristate drivers taking turns (the textbook's mux from tristate buffers)
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): 'An Internal bus (BUFT): An inferred BUFT is converted automatically to logic realized in LUTs by Vivado synthesis.'
What does the open-source chain do with it?
yosys keeps the two drivers 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:2: ERROR [internal-tristate]: a tri-state driver (a z, at design.sv:2) 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 a design of four muxes)
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/52_internal_tristate.
design.sv
module tristate(input logic [3:0] a, input logic en, output tri [3:0] y);
assign y = en ? a : 4'bz;
endmodule
module top(input logic [15:0] sw, output logic [15:0] led);
tri [3:0] bus; // one internal bus, two drivers taking turns
tristate t0(.a(sw[3:0]), .en(~sw[8]), .y(bus));
tristate t1(.a(sw[7:4]), .en(sw[8]), .y(bus));
assign led = {12'b0, bus};
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
integer i;
top dut(.sw(sw), .led(led));
initial begin
for (i = 0; i < 65536; i = i + 1) begin
sw = i; #1
if (!(led === {12'd0, sw[8] ? sw[7:4] : sw[3:0]})) begin $display("FAIL: mux from two tristate drivers (sw=%h led=%h)", sw, led); $finish; end
end
$display("PASS"); $finish;
end
endmodule
previous: the same lookup table with its type named first: typedef logic [3:0][6:0] tab_t; localparam tab_t SEG = {...};
next: async reset ORed with a synchronous clear: always_ff @(posedge clk, posedge btnC) if (btnC || btnU) q <= 0;