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.

stagetoday
rtl, simulationpass
synth, synthesispass
netlist, the netlistfail
bit, the bitstreamfail

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?

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