Which SystemVerilog builds without Vivado?
148 constructs, one probe each: the design and a tb.sv that prints PASS. Vivado supports 122 of them; 104 of those pass every stage here.
Every probe in test/sv goes through four stages in a folder that holds only its sources. test/sv/expect.tsv records what each stage does today, whether Vivado accepts the construct and the source for that; test/sv/run.sh fails on any difference, in both directions. Sources for Vivado: UG901 v2023.2 (chapter, table, page), UG953 v2022.2 (the 7-series primitive guide) and Vivado logs from public CS223 lab repos, where the student's module and signal names are replaced by a description. A forum is marked as a weak source.
What does each stage check?
| rtl simulation | The design and its tb.sv simulated with Icarus Verilog (dewfpga sim). Pass: exit 0 and the testbench printed PASS. |
| synth synthesis | Yosys synthesis (dewfpga bit), with the whole Basys3_Master.xdc uncommented as in a lab folder. Pass: the netlist was written. |
| netlist the netlist | That netlist written back as Verilog: the same tb.sv, simulated on it with Yosys' xilinx/cells_sim.v, prints PASS, and every output bit matches the RTL on the same inputs (test/sv/eqv.py). This stage checks what synthesis made, not place and route or the bitstream. |
| bit the bitstream | The same dewfpga bit exits 0 and writes top.bit: place and route with nextpnr-xilinx, the timing check, the frames and the bitstream. |
Which probes pass every stage?
114 of 148.
- always_comb with an if and no else (a latch is inferred) (01, Vivado: supported)
- module instance with no instance name: inv(sw[0], led[0]); (02, Vivado: supported)
- packed array of enums: statetype [1:0] state, nextstate; (07, Vivado: supported)
- ANSI port inheriting its direction: output [6:0] seg, logic dp, (the course's seven-segment file) (08, Vivado: supported)
- the course's port line (output [6:0] seg, logic dp) with comments in the port list: one after seg, one with a ';' in it (08b, Vivado: supported)
- the course's port line shape with a range only, written in an always block: output logic [6:0] seg, [3:0] an; with an set in an always_comb (08c, Vivado: supported)
- always_ff / always_comb / always_latch (09, Vivado: supported)
- typedef enum FSM with an explicit base type and with the default (int), plus a light_t'(l+1) cast (10, Vivado: supported)
- typedef struct packed, nested, member read and write (12, Vivado: supported)
- named assignment pattern '{hi: x, lo: y} and '{default: 0} (12b, Vivado: supported)
- a packed array of structs indexed by a signal, then a member select: cars[sw[15]].x (12c, Vivado: supported)
- packed 2-D, unpacked, unpacked 2-D arrays, for (int i..) in always_comb (13, Vivado: supported)
- an unpacked array as a module port: input logic [3:0] v [0:3] (13b, Vivado: supported)
- an unpacked array concatenation: assign arr = {sw[3:0], sw[7:4]}; to logic [3:0] arr [0:1] (13c, Vivado: supported)
- a packed 2-D array indexed by a variable, then a bit or part select: grid[i][j] <= ... in a loop, grid[sw[13:12]][3:1] (13d, Vivado: supported)
- typed parameters, one depending on another, localparam, #(.W(8),.K(3)) and positional #(4) (14, Vivado: supported)
- generate for with genvar (named block), for (genvar j..) with if-generate, case-generate (15, Vivado: supported)
- function automatic with a loop, plain function, task automatic called in always_comb (16, Vivado: supported)
- 'return expr;' inside a function (16b, Vivado: supported)
- while loop in an always block (UG901 example) (16c, Vivado: supported)
- $clog2 in a localparam and a range, $bits, size cast 4'(expr) (17, Vivado: supported)
- unique case / priority casez (18, Vivado: supported)
- unique if / priority if (18b, Vivado: supported)
- unique0 if: an if/else if chain where no branch may match (18c, Vivado: supported)
- casez with ? wildcards, casex (19, Vivado: supported)
- set membership: x inside {1,3,[8:10]} and case (x) inside (20, Vivado: not supported)
- x++ and x += in always_comb, k++ inside always_ff, for (int i..;i++) with c++ (21, Vivado: supported)
- an assignment within an expression: a = (b = sw[3:0]) + 4'd1; in always_comb (21b, Vivado: supported)
- interface with two modports, modport-typed module ports (sum_if.prod bus) (22, Vivado: supported)
- an interface declared in its own file (sum_if.sv), generic interface ports (22b, Vivado: supported)
- an interface with ports, interface cnt_if(input logic clk, input logic en), holding a counter; top reads c.q (22c, Vivado: supported)
- an array of interfaces: pair_if p [0:1] (); p[0].d and p[1].d driven and read in top (22d, Vivado: supported)
- a modport expression: modport lo (input .nib(data[3:0])); a submodule reads b.nib (22e, Vivado: supported)
- an interface without ports whose members the module that instantiates it drives and reads: add_if bus (); assign bus.a = sw[7:0]; ... led = bus.s (22f, Vivado: supported)
- package (enum, parameter, localparam, function) + import pkg::*; inside the module + pkg::NAME (23, Vivado: supported)
- the same package with import pkg::*; at file level, using an imported typedef (23b, Vivado: supported)
- a package in its own file (pkg.sv), referenced as cfg_pkg::NAME (23c, Vivado: supported)
- import in the module header: module top import pkg::*; (...) (23d, Vivado: supported)
- a package that exports a name it imported: package p2; import p1::K; export p1::K; endpackage, and import p2::* in the module (23e, Vivado: supported)
- `include of a .svh, `define with arguments, `ifdef/`ifndef/`else, +: part select (24, Vivado: supported)
- .* and .name implicit port connections (25, Vivado: supported)
- array of instances: inv u_inv [3:0] (.a(sw[3:0]), .y(led[3:0])); (26, Vivado: supported)
- ROM from initial $readmemh("rom.mem") with async and sync read (27, Vivado: supported)
- RAM: sync write, async read (distributed RAM, -nobram) (28, Vivado: supported)
- 32-deep shift register (SRL) + dynamic tap sr[sw[8:4]] (29, Vivado: supported)
- signed 8x8 multiply, >>> arithmetic shift, signed compare, $signed (30, Vivado: supported)
- sync active-high reset, async active-low reset (negedge rst_n), async set to a nonzero constant (31, Vivado: supported)
- registers on the falling edge with no start value: a counter with a synchronous set (FDSE_1) and a bit with an asynchronous preset (FDPE_1), both reset from two switches (31b, Vivado: supported)
- clock divider making a derived clock (always_ff @(posedge slow)) + 4-digit 7-seg multiplexing + hex ROM via case (32, Vivado: supported)
- inout JA: JA[0] = oe ? d : 1'bz and read back; JA[7:1] = 'z, JA[1] read as input (33, Vivado: supported)
- inout pin only read (never assigned 'z) + one bidirectional pin (33b, Vivado: supported)
- UNISIM primitive instantiation: BUFG (34, Vivado: supported)
- (* keep = "true" *) and (* dont_touch = "true" *) on internal nets (36, Vivado: supported)
- register power-up value: logic [3:0] cnt = 5; and initial c2 = 9; (37, Vivado: unverified)
- gate primitives (not, and, or, xor) driving logic variables and an output logic port (38, Vivado: supported)
- a module named display next to a $display call in a design module (40, Vivado: supported)
- a module name and ( inside a $display string in a design module: $display("counter (u_cnt) wrapped") next to module counter (40b, Vivado: supported)
- wildcard equality: sw[7:0] ==? 8'b1??0_??01 and !=? (41, Vivado: supported)
- streaming concatenation: {<<{sw[7:0]}} (bit reverse) and {<<4{sw[15:8]}} (42, Vivado: not supported)
- foreach over an unpacked array in always_comb (43, Vivado: supported)
- break out of a for loop in always_comb (lowest set bit) (45, Vivado: supported)
- continue in a for loop in always_comb (count of set bits) (46, Vivado: unverified)
- type parameter: module inv_t #(parameter type T = logic [3:0]), overridden with #(.T(logic [7:0])) (47, Vivado: supported)
- iff event qualifier: always_ff @(posedge clk iff sw[15]) (48, Vivado: unverified)
- function argument with a default value, called without it (49, Vivado: supported)
- function arguments bound by name, in another order: diff(.b(x), .a(y)) (50, Vivado: supported)
- an unpacked array localparam set with an assignment pattern: localparam logic [6:0] SEGS [0:3] = '{...} (51, Vivado: supported)
- a packed 2-D localparam as a lookup table: localparam logic [3:0][6:0] SEG = {...}; seg = SEG[sw[1:0]]; (51b, Vivado: supported)
- a name used before its declaration: assign led[0] = stop; logic stop; (54, Vivado: supported)
- a conditional between two values of one enum: next = sw[0] ? RUN : IDLE; (55, Vivado: unverified)
- typedef enum {S0, S1, S2} outside the module (compilation-unit scope), with the textbook's state names (56, Vivado: supported)
- a typedef at file scope in a file of its own (types.sv holds only typedef enum ... state_t;), used by the design's module (56b, Vivado: supported)
- a course 'ready module' in netlist form in its own file ((* keep_hierarchy *), \<const0>, GND, LUT2), instantiated by the design (57, Vivado: supported)
- a hierarchical name that reads a submodule's signal: assign led[1:0] = u_fsm.state; (58, Vivado: supported)
- enum ranges: typedef enum {S[3]} (S0, S1, S2) and {T[5:7]} (T5, T6, T7) (61, Vivado: supported)
- the type operator: var type(a) b; (62, Vivado: supported)
- a real localparam cast to int: localparam int INC = int'(STEP); (2.6 rounds to 3) (63, Vivado: unverified)
- an unpacked struct: typedef struct { logic [3:0] a; logic [3:0] b; } (no packed) (64, Vivado: supported)
- an unpacked union: typedef union { logic [7:0] byte_v; logic [3:0] nib; } (no packed), one member written and read (64b, Vivado: supported)
- streaming concatenation as the target of an assignment: {>>{a, b}} = sw[7:0]; (65, Vivado: supported)
- equality of two whole unpacked arrays: a == b, a != b (67, Vivado: supported)
- a slice of an unpacked array: b = a[2:3]; (68, Vivado: supported)
- one whole unpacked array assigned to another in always_ff: b <= a; (71, Vivado: supported)
- a void function that returns through output arguments (72, Vivado: supported)
- an unpacked array as a function argument (73, Vivado: supported)
- a .v design file with bit and final as names (keywords in SystemVerilog, names in Verilog 2005) (74, Vivado: supported)
- names the standard declares implicitly: a net from a port connection (.y(w)) and one from the left of an assign (assign eq = ...) (76, Vivado: supported)
- (* keep_hierarchy = "yes" *) on a module, spaced as in UG901 (78, Vivado: supported)
- the same attribute written without spaces: (*keep_hierarchy="yes"*) (yosys keeps the submodule) (79, Vivado: supported)
- $realtobits and $bitstoreal in localparams (a real turned into its IEEE 754 bits and back) (83, Vivado: supported)
- a repeat loop with a constant count in always_comb (count the switches that are up) (84, Vivado: supported)
- a bitstream cast to an unpacked array: q = quad_t'(sw[7:0]); with typedef logic [3:0] quad_t [0:1] (85, Vivado: supported)
- an extern module declaration ahead of the module: extern module inv4(input logic [3:0] a, output logic [3:0] y); (86, Vivado: supported)
- a config declaration next to the design: config cfg; design work.top; default liblist work; endconfig (87, Vivado: supported)
- a class used for its static function, called as util::rev(sw[3:0]) (no object is made) (88, Vivado: supported)
- a parameter check in an initial block: initial if (N < 8) $warning(...) (90, Vivado: supported)
- a design split over two files: top in design.sv, its submodule counter in counter.sv (the usual lab layout) (91, Vivado: supported)
- a $display debug print left in a clocked design module: if (q == 4'd15) $display("wrapped"); (92, Vivado: supported)
- a port declared [N-1:0] with N = 1: a vector of one bit, numbered 0 (96, Vivado: supported)
- ports numbered from 1: input logic [4:1] sw, output logic [4:1] led, with the lab's own XDC, whose lines for sw[1] to sw[4] and led[1] to led[4] are uncommented (96b, Vivado: supported)
- a student's module named like a Xilinx primitive: module INV (GND, VCC and MUXF7 too) (98, Vivado: unverified)
- a parameter of type string: parameter string INIT_FILE = "digits.mem" (a ROM that takes its $readmemh file as a parameter) (99, Vivado: unverified)
- always_latch if (sw[1]) q = sw[0]; (a latch on purpose, sw[1] its gate), read by yosys' own reader (101, Vivado: supported)
- the same always_latch next to a foreach loop (43_foreach_loop), so the design is read with yosys-slang (101b, Vivado: supported)
- the same .* connection with the signals declared the port's width (logic [7:0] sub_in, sub_out) (102b, Vivado: supported)
- the same instance connected by name, sub #(.N(8)) u (.sub_in(sub_in), .sub_out(sub_out)), with 4-bit signals (102c, Vivado: supported)
- a package in its own file (pkg.sv: localparam, typedef, function), imported inside two modules in two files (design.sv, sub.sv), no `include anywhere (103, Vivado: supported)
- two package files where a_pkg.sv imports z_pkg (declared in z_pkg.sv) and the design imports a_pkg::*; alphabetical order reads a_pkg.sv first (103b, Vivado: supported)
- a package in its own file (pkg.sv) that design.sv `includes on line 1, 23c's documented fix (103c, Vivado: supported)
- a 3-state enum FSM with no start value, read by a case and an if before its first reset (led before the first clock edge) (104, Vivado: supported)
- a 1-bit register set by the reset button (FDSE, no start value) read by an if before its first reset, beside a 16-bit counter (FDRE) (104b, Vivado: supported)
- four 4-bit registers read before the first clock edge: a synchronous reset to 5, an asynchronous reset to 4'b1010, no reset, a declared start value (logic [3:0] d = 4'd9) (105, Vivado: supported)
- a 3-state enum FSM with a synchronous reset and no start value, read at the first clock edge before any reset (the board starts in IDLE and moves to RUN) (105b, Vivado: supported)
- a 4-word LUT RAM read before any write (mem[0] on the first edge) (105c, Vivado: unverified)
Which probes build a bitstream whose netlist check fails?
3 of 148.
- UNISIM MMCME2_BASE (100 to 50 MHz) + BUFG (35, Vivado: supported)
- UG901's RAM_STYLE attribute: (* ram_style = "block" *) on a 256-byte memory, written with btnC and read one clock later (97, Vivado: supported)
- 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) (101c, Vivado: unverified)
Which probes stop before a bitstream?
30 of 148.
- always_ff @(posedge clk or posedge btnC) if (btnC) q <= sw[3:0]; (async load from a signal) (03, Vivado: unverified)
- a button used as an async 'reset' that loads cnt+1 (the button-as-clock counter) (03b, Vivado: unverified)
- always @(posedge clk or negedge clk) cnt <= cnt + 1; (04, Vivado: unverified)
- one reg written from two always blocks on different edges (posedge btnU / posedge btnC) (05, Vivado: unverified)
- a case item's begin (S2: begin) never closed before default: (invalid code; a typo seen in a CS223 lab) (06, Vivado: not supported)
- enum methods s.first() / s.next() / s.last() (11, Vivado: 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 (33c, Vivado: supported)
- a variable declared with an initializer that reads inputs: logic [3:0] sum = sw[3:0] + sw[7:4]; (meant as an adder) (37b, Vivado: unverified)
- a typo: an undeclared name on the right of an assign (summ for sum) (39, Vivado: unverified)
- do ... while in always_comb, twice: a popcount, and a loop whose condition is false on entry (its body still runs once, which tells do-while from while) (44, Vivado: supported)
- an internal tri bus with two tristate drivers taking turns (the textbook's mux from tristate buffers) (52, Vivado: supported)
- async reset ORed with a synchronous clear: always_ff @(posedge clk, posedge btnC) if (btnC || btnU) q <= 0; (53, Vivado: supported)
- $isunknown(sw) in a design (a real signal is never x, so it is 0) (59, Vivado: supported)
- a function with a ref argument: function automatic void inc(ref logic [3:0] x) (60, Vivado: supported)
- a real literal in a localparam used in an expression: localparam MAX = 1e1; ... count == MAX - 1 (a lab writes 50e6) (63b, Vivado: unverified)
- alias a = b; (two nets made one) (66, Vivado: unverified)
- disable of a named block to leave a loop (the lowest switch that is up) (69, Vivado: supported)
- a wor and a wand net, two drivers each (70, Vivado: supported)
- a design that misses 100 MHz: a 14-bit value turned into four registered decimal digits (a long divide chain) (75, Vivado: supported)
- an initial block that reads a signal: initial num = sw; (seen in a CS223 lab) (77, Vivado: unverified)
- an always_ff with an async reset and a statement after its if/else (d <= q; runs on the reset edge too) (80, Vivado: unverified)
- a design module that calls $finish in a simulation check (always @(posedge clk) if (...) $finish;), its submodule's ports named as the XDC's (counter.sv) (81, Vivado: supported)
- file tasks left in a design module: $fopen, $fdisplay and $fwrite (a debug trace) (82, Vivado: supported)
- a clock divider's output clocks more logic than 100 MHz allows (four decimal digits of a 14-bit value on the slow clock); the XDC has no create_clock, as the course's master XDC arrives (89, Vivado: supported)
- two modules nothing instantiates, in one file named after one of them (counter.sv: the plain counter, and the board version the project names as its top) (93, Vivado: supported)
- a variable raised to a constant power: assign led = sw[7:0] ** 2; (94, Vivado: supported)
- a submodule declared with its ports and no body (a lab part not written yet), its output used by top (95, Vivado: unverified)
- the same module defined in two files of the folder (design.sv and a backup design_old.sv), an older body in the backup (95b, Vivado: unverified)
- a unique casez whose items overlap: 4'b10?? and 4'b??11 both match 4'b1011 (the simulation takes the first item, the hardware ORs both) (100, Vivado: unverified)
- a .* connection whose port (N bits, N = 8) and signal (4 bits) widths differ (102, Vivado: unverified)
Which probes build, and fail only in simulation?
1 of 148.
- the same lookup table with its type named first: typedef logic [3:0][6:0] tab_t; localparam tab_t SEG = {...}; (51c, Vivado: supported)
An error code from one of these runs? Every code, with what you saw, why and the fix. What the chain cannot do yet, in the guide: section 8.