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.

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): '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?

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;