SystemVerilog probes · 32Vivado: supported

clock divider making a derived clock (always_ff @(posedge slow)) + 4-digit 7-seg multiplexing + hex ROM via case

Vivado: supported. The open-source chain: all four stages pass.

stagetoday
rtl, simulationpass
synth, synthesispass
netlist, the netlistpass
bit, the bitstreampass

What does Vivado do with it?

Supported. Vivado 2020.1 synthesis log of a public CS223 lab repo: a register toggled by a counter is the clock of another module's always_ff @(posedge clk), 'Synthesis finished with 0 errors, 0 critical warnings and 0 warnings.', implementation 'write_bitstream completed successfully'. UG901 v2023.2 Ch.5 (p.81): 'Rising or falling-edge clocks'

What does the open-source chain do with it?

since #5 the pnr line names both clocks, the port and the divided one: 'pnr ok: 19 LUT, 4 FF, slow' 'MHz), clk' (before #5 the same two names; the derived clock keeps the name the student gave its net)

What is the probe's code?

From test/sv/32_clkdiv_7seg.

design.sv

module hex7(input logic [3:0] x, output logic [6:0] seg);
  always_comb
    case (x)                              // ROM via case
      4'h0: seg = 7'b1000000; 4'h1: seg = 7'b1111001; 4'h2: seg = 7'b0100100; 4'h3: seg = 7'b0110000;
      4'h4: seg = 7'b0011001; 4'h5: seg = 7'b0010010; 4'h6: seg = 7'b0000010; 4'h7: seg = 7'b1111000;
      4'h8: seg = 7'b0000000; 4'h9: seg = 7'b0010000; 4'hA: seg = 7'b0001000; 4'hB: seg = 7'b0000011;
      4'hC: seg = 7'b1000110; 4'hD: seg = 7'b0100001; 4'hE: seg = 7'b0000110; default: seg = 7'b0001110;
    endcase
endmodule
module top(input logic clk, input logic btnC, input logic [15:0] sw,
           output logic [6:0] seg, output logic dp, output logic [3:0] an);
  logic divcnt, slow;                     // clock divider: a derived clock, CS223 style
  always_ff @(posedge clk)
    if (btnC) begin divcnt <= 1'b0; slow <= 1'b0; end
    else begin divcnt <= divcnt + 1'b1; if (divcnt) slow <= ~slow; end
  logic [1:0] digit;
  always_ff @(posedge slow or posedge btnC)
    if (btnC) digit <= 2'd0; else digit <= digit + 2'd1;
  logic [3:0] nib;
  always_comb
    case (digit)
      2'd0:    begin an = 4'b1110; nib = sw[3:0];   end
      2'd1:    begin an = 4'b1101; nib = sw[7:4];   end
      2'd2:    begin an = 4'b1011; nib = sw[11:8];  end
      default: begin an = 4'b0111; nib = sw[15:12]; end
    endcase
  hex7 u_hex (.x(nib), .seg(seg));
  assign dp = 1'b1;
endmodule

tb.sv

module tb;
  reg clk = 1'b0;
  reg btnC = 1'b0;
  reg [15:0] sw = 16'h0000;
  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
  top dut(.clk(clk), .btnC(btnC), .sw(sw), .seg(seg), .dp(dp), .an(an));
  // the reference: the 16 hex patterns (active low, gfedcba) and the digit order an = 1110, 1101, 1011, 0111
  reg [6:0] hex [0:15];
  reg [3:0] prev; integer n, p, k;
  initial begin
    hex[0] = 7'b1000000; hex[1] = 7'b1111001; hex[2] = 7'b0100100; hex[3] = 7'b0110000;
    hex[4] = 7'b0011001; hex[5] = 7'b0010010; hex[6] = 7'b0000010; hex[7] = 7'b1111000;
    hex[8] = 7'b0000000; hex[9] = 7'b0010000; hex[10] = 7'b0001000; hex[11] = 7'b0000011;
    hex[12] = 7'b1000110; hex[13] = 7'b0100001; hex[14] = 7'b0000110; hex[15] = 7'b0001110;
  end
  task check(input integer d); begin
    if (an !== ~(4'b0001 << d) || seg !== hex[sw[4*d +: 4]] || dp !== 1'b1) begin
      $display("FAIL: digit %0d of sw=%h: an=%b seg=%b, want an=%b seg=%b", d, sw, an, seg, ~(4'b0001 << d), hex[sw[4*d +: 4]]); $finish; end
  end endtask
  initial begin
    for (p = 0; p < 4; p = p + 1) begin
      sw = {4'(4*p + 3), 4'(4*p + 2), 4'(4*p + 1), 4'(4*p)};    // every hex digit shows once
      btnC = 1; tick; btnC = 0; #1
      check(0);
      for (k = 1; k <= 4; k = k + 1) begin               // the derived clock steps the digit; 4 wraps to 0
        prev = an; n = 0;
        while (an === prev && n < 12) begin tick; n = n + 1; end
        check(k % 4);
      end
    end
    $display("PASS"); $finish;
  end
endmodule

previous: 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
next: inout JA: JA[0] = oe ? d : 1'bz and read back; JA[7:1] = 'z, JA[1] read as input