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.
| stage | today |
|---|---|
| rtl, simulation | pass |
| synth, synthesis | pass |
| netlist, the netlist | pass |
| bit, the bitstream | pass |
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