tests/test.sh exit code (0 → resolved); the classification below is post-hoc and cannot change it.module TopModule(
input logic clk,
input logic rst,
input logic [3:0] req,
input logic lock,
output logic [3:0] grant,
output logic grant_valid
);
// Fairness / hold state
logic [1:0] last; // last requester served; search starts just past it
logic held; // a locked hold is active
logic [1:0] held_who; // which requester is held
// Combinational round-robin arbitration starting just past `last`
logic [1:0] astart;
logic arb_valid;
logic [1:0] arb_idx;
always_comb begin
arb_valid = 1'b0;
arb_idx = 2'd0;
astart = last + 2'd1;
for (int k = 0; k < 4; k++) begin
if (!arb_valid && req[astart + k[1:0]]) begin
arb_valid = 1'b1;
arb_idx = astart + k[1:0];
end
end
end
// Mealy outputs
always_comb begin
grant = 4'b0000;
grant_valid = 1'b0;
if (!rst) begin
if (held) begin
// Hold lives only while the held requester keeps asking.
if (req[held_who]) begin
grant = 4'b0001 << held_who;
grant_valid = 1'b1;
end
// else: dead air (grant 0, grant_valid 0)
end else begin
if (arb_valid) begin
grant = 4'b0001 << arb_idx;
grant_valid = 1'b1;
end
end
end
end
// State update
always_ff @(posedge clk) begin
if (rst) begin
last <= 2'd3; // first search starts at requester 0
held <= 1'b0;
held_who <= 2'd0;
end else if (held) begin
if (req[held_who]) begin
// Held winner owns this cycle; keep holding only while lock stays high.
last <= held_who;
held <= lock;
// held_who unchanged
end else begin
// Dead air: hold over, but counts as served.
last <= held_who;
held <= 1'b0;
end
end else begin
if (arb_valid) begin
last <= arb_idx;
// Lock high on a granted cycle latches this winner.
held <= lock;
held_who <= arb_idx;
end else begin
// Idle keeps your place.
held <= 1'b0;
end
end
end
endmodule
Compile check with iverilog
iverilog -g2012 -o /tmp/dut_test dut.sv -e 2>&1 | head; echo "---syntax check (no top TB yet)---"; iverilog -g2012 -o /tmp/x dut.sv 2>&1 | head; echo "exit=$?"
iverilog: invalid option -- 'e' ---syntax check (no top TB yet)--- dut.sv:20: sorry: constant selects in always_* processes are not currently supported (all bits will be included). exit=0 [stdout] iverilog: invalid option -- 'e' ---syntax check (no top TB yet)--- dut.sv:20: sorry: constant selects in always_* processes are not currently supported (all bits will be included). exit=0
Run testbench simulation
cat > /tmp/tb.sv <<'EOF'
module tb;
logic clk=0, rst, lock;
logic [3:0] req;
logic [3:0] grant;
logic gv;
TopModule d(.clk,.rst,.req,.lock,.grant(grant),.grant_valid(gv));
always #5 clk=~clk;
task step; @(posedge clk); #1; $display("t=%0t rst=%b req=%b lock=%b -> grant=%b gv=%b", $time, rst, req, lock, grant, gv); endtask
initial begin
rst=1; req=0; lock=0; @(posedge clk);#1; rst=0;
$display("== all four forever ==");
req=4'b1111; lock=0;
step; step; step; step; step; step;
$display("== lone requester (only 2) ==");
req=4'b0100; step; step; step;
$display("== lock latch then hold then drop ==");
req=4'b1111; lock=1; step; // grant someone, latch
step; // held, lock high, continue
lock=0; step; // lock drops, holder still owns
step; // resume next
$display("== dead air: hold but req low, lock high ==");
req=4'b1111; lock=1; step; // latch a winner
// drop that winner's req: find who was granted
$display("(now force granted one's req low)");
req=4'b1110; step; // if holder was 0, dead air
lock=0; req=4'b1111; step; step;
$finish;
end
endmodule
EOF
iverilog -g2012 -o /tmp/sim dut.sv /tmp/tb.sv 2>&1 | grep -v "constant selects" ; vvp /tmp/sim 2>&1== all four forever == t=16 rst=0 req=1111 lock=0 -> grant=0010 gv=1 t=26 rst=0 req=1111 lock=0 -> grant=0100 gv=1 t=36 rst=0 req=1111 lock=0 -> grant=1000 gv=1 t=46 rst=0 req=1111 lock=0 -> grant=0001 gv=1 t=56 rst=0 req=1111 lock=0 -> grant=0010 gv=1 t=66 rst=0 req=1111 lock=0 -> grant=0100 gv=1 == lone requester (only 2) == t=76 rst=0 req=0100 lock=0 -> grant=0100 gv=1 t=86 rst=0 req=0100 lock=0 -> grant=0100 gv=1 t=96 rst=0 req=0100 lock=0 -> grant=0100 gv=1 == lock latch then hold then drop == t=106 rst=0 req=1111 lock=1 -> grant=1000 gv=1 t=116 rst=0 req=1111 lock=1 -> grant=1000 gv=1 t=126 rst=0 req=1111 lock=0 -> grant=0001 gv=1 t=136 rst=0 req=1111 lock=0 -> grant=0010 gv=1 == dead air: hold but req low, lock high == t=146 rst=0 req=1111 lock=1 -> grant=0010 gv=1 (now force granted one's req low) t=156 rst=0 req=1110 lock=1 -> grant=0010 gv=1 t=166 rst=0 req=1111 lock=0 -> grant=0100 gv=1 t=176 rst=0 req=1111 lock=0 -> grant=1000 gv=1 /tmp/tb.sv:27: $finish called at 176 (1s) [stdout] == all four forever == t=16 rst=0 req=1111 lock=0 -> grant=0010 gv=1 t=26 rst=0 req=1111 lock=0 -> grant=0100 gv=1 t=36 rst=0 req=1111 lock=0 -> grant=1000 gv=1 t=46 rst=0 req=1111 lock=0 -> grant=0001 gv=1 t=56 rst=0 req=1111 lock=0 -> grant=0010 gv=1 t=66 rst=0 req=1111 lock=0 -> grant=0100 gv=1 == lone requester (only 2) == t=76 rst=0 req=0100 lock=0 -> grant=0100 gv=1 t=86 rst=0 req=0100 lock=0 -> grant=0100 gv=1 t=96 rst=0 req=0100 lock=0 -> grant=0100 gv=1 == lock latch then hold then drop == t=106 rst=0 req=1111 lock=1 -> grant=1000 gv=1 t=116 rst=0 req=1111 lock=1 -> grant=1000 gv=1 t=126 rst=0 req=1111 lock=0 -> grant=0001 gv=1 t=136 rst=0 req=1111 lock=0 -> grant=0010 gv=1 == dead air: hold but req low, lock high == t=146 rst=0 req=1111 lock=1 -> grant=0010 gv=1 (now force granted one's req low) t=156 rst=0 req=1110 lock=1 -> grant=0010 gv=1 t=166 rst=0 req=1111 lock=0 -> grant=0100 gv=1 t=176 rst=0 req=1111 lock=0 -> grant=1000 gv=1 /tmp/tb.sv:27: $finish called at 176 (1s)
/app/dut.sv
// Combinational round-robin arbitration starting just past `last`
logic [1:0] astart;
logic arb_valid;
logic [1:0] arb_idx;
always_comb begin
arb_valid = 1'b0;
arb_idx = 2'd0;
astart = last + 2'd1;
for (int k = 0; k < 4; k++) begin
if (!arb_valid && req[astart + k[1:0]]) begin
arb_valid = 1'b1;
arb_idx = astart + k[1:0];
end
end
end // Combinational round-robin arbitration starting just past `last`.
// Each asking requester's rank = distance from the start position; the
// smallest rank wins. Uses only constant indices into `req`.
logic [1:0] astart;
logic arb_valid;
logic [1:0] arb_idx;
logic [2:0] best_rank;
logic [1:0] rank;
always_comb begin
arb_valid = 1'b0;
arb_idx = 2'd0;
best_rank = 3'd4; // larger than any real rank (0..3)
astart = last + 2'd1;
for (int i = 0; i < 4; i++) begin
if (req[i]) begin
rank = i[1:0] - astart; // 2-bit modulo-4 distance
if ({1'b0, rank} < best_rank) begin
best_rank = {1'b0, rank};
arb_valid = 1'b1;
arb_idx = i[1:0];
end
end
end
endRecompile and rerun testbench
iverilog -g2012 -o /tmp/sim dut.sv /tmp/tb.sv 2>&1; echo "compile-exit=$?"; vvp /tmp/sim 2>&1
dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). compile-exit=0 == all four forever == t=16 rst=0 req=1111 lock=0 -> grant=0010 gv=1 t=26 rst=0 req=1111 lock=0 -> grant=0100 gv=1 t=36 rst=0 req=1111 lock=0 -> grant=1000 gv=1 t=46 rst=0 req=1111 lock=0 -> grant=0001 gv=1 t=56 rst=0 req=1111 lock=0 -> grant=0010 gv=1 t=66 rst=0 req=1111 lock=0 -> grant=0100 gv=1 == lone requester (only 2) == t=76 rst=0 req=0100 lock=0 -> grant=0100 gv=1 t=86 rst=0 req=0100 lock=0 -> grant=0100 gv=1 t=96 rst=0 req=0100 lock=0 -> grant=0100 gv=1 == lock latch then hold then drop == t=106 rst=0 req=1111 lock=1 -> grant=1000 gv=1 t=116 rst=0 req=1111 lock=1 -> grant=1000 gv=1 t=126 rst=0 req=1111 lock=0 -> grant=0001 gv=1 t=136 rst=0 req=1111 lock=0 -> grant=0010 gv=1 == dead air: hold but req low, lock high == t=146 rst=0 req=1111 lock=1 -> grant=0010 gv=1 (now force granted one's req low) t=156 rst=0 req=1110 lock=1 -> grant=0010 gv=1 t=166 rst=0 req=1111 lock=0 -> grant=0100 gv=1 t=176 rst=0 req=1111 lock=0 -> grant=1000 gv=1 /tmp/tb.sv:27: $finish called at 176 (1s) [stdout] dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). compile-exit=0 == all four forever == t=16 rst=0 req=1111 lock=0 -> grant=0010 gv=1 t=26 rst=0 req=1111 lock=0 -> grant=0100 gv=1 t=36 rst=0 req=1111 lock=0 -> grant=1000 gv=1 t=46 rst=0 req=1111 lock=0 -> grant=0001 gv=1 t=56 rst=0 req=1111 lock=0 -> grant=0010 gv=1 t=66 rst=0 req=1111 lock=0 -> grant=0100 gv=1 == lone requester (only 2) == t=76 rst=0 req=0100 lock=0 -> grant=0100 gv=1 t=86 rst=0 req=0100 lock=0 -> grant=0100 gv=1 t=96 rst=0 req=0100 lock=0 -> grant=0100 gv=1 == lock latch then hold then drop == t=106 rst=0 req=1111 lock=1 -> grant=1000 gv=1 t=116 rst=0 req=1111 lock=1 -> grant=1000 gv=1 t=126 rst=0 req=1111 lock=0 -> grant=0001 gv=1 t=136 rst=0 req=1111 lock=0 -> grant=0010 gv=1 == dead air: hold but req low, lock high == t=146 rst=0 req=1111 lock=1 -> grant=0010 gv=1 (now force granted one's req low) t=156 rst=0 req=1110 lock=1 -> grant=0010 gv=1 t=166 rst=0 req=1111 lock=0 -> grant=0100 gv=1 t=176 rst=0 req=1111 lock=0 -> grant=1000 gv=1 /tmp/tb.sv:27: $finish called at 176 (1s)
Probe internal arbiter state
cat > /tmp/tb2.sv <<'EOF'
module tb;
logic clk=0, rst, lock;
logic [3:0] req;
logic [3:0] grant; logic gv;
TopModule d(.clk,.rst,.req,.lock,.grant(grant),.grant_valid(gv));
always #5 clk=~clk;
initial begin
rst=1; req=0; lock=0;
@(posedge clk);#1;
$display("after rst edge: last=%0d held=%b astart=%0d", d.last, d.held, d.astart);
rst=0;
req=4'b1111; lock=0;
#1 $display("comb before edge: astart=%0d arb_valid=%b arb_idx=%0d", d.astart, d.arb_valid, d.arb_idx);
@(posedge clk);#1;
$display("cyc1: grant=%b last=%0d astart=%0d arb_idx=%0d", grant, d.last, d.astart, d.arb_idx);
$finish;
end
endmodule
EOF
iverilog -g2012 -o /tmp/sim2 dut.sv /tmp/tb2.sv 2>&1 | grep -v constant; vvp /tmp/sim2 2>&1after rst edge: last=3 held=0 astart=0 comb before edge: astart=0 arb_valid=1 arb_idx=0 cyc1: grant=0010 last=0 astart=1 arb_idx=1 /tmp/tb2.sv:16: $finish called at 16 (1s) [stdout] after rst edge: last=3 held=0 astart=0 comb before edge: astart=0 arb_valid=1 arb_idx=0 cyc1: grant=0010 last=0 astart=1 arb_idx=1 /tmp/tb2.sv:16: $finish called at 16 (1s)
Cycle-accurate testbench sampling before edges
cat > /tmp/tb3.sv <<'EOF'
module tb;
logic clk=0, rst, lock; logic [3:0] req;
logic [3:0] grant; logic gv;
TopModule d(.clk,.rst,.req,.lock,.grant(grant),.grant_valid(gv));
always #5 clk=~clk;
integer n=0;
// drive inputs just after posedge; sample just before next posedge
task automatic cyc(input [3:0] r, input logic l, input string tag);
req=r; lock=l; #1; // settle in this cycle
$display("cyc%0d %-10s rst=%b req=%b lock=%b -> grant=%b gv=%b", n, tag, rst, req, lock, grant, gv);
@(posedge clk); n++;
endtask
initial begin
// reset cycle
rst=1; req=0; lock=0; #1; @(posedge clk); n++; rst=0;
$display("== all four forever (expect 0,1,2,3,0,1) ==");
cyc(4'b1111,0,"all"); cyc(4'b1111,0,"all"); cyc(4'b1111,0,"all");
cyc(4'b1111,0,"all"); cyc(4'b1111,0,"all"); cyc(4'b1111,0,"all");
$display("== lone req2 keeps winning ==");
cyc(4'b0100,0,"lone"); cyc(4'b0100,0,"lone"); cyc(4'b0100,0,"lone");
$display("== idle keeps place (last served=2) then req 0&1 -> expect 0 ==");
cyc(4'b0000,0,"idle"); cyc(4'b0000,0,"idle"); cyc(4'b0011,0,"resume");
$display("== lock latch/hold/drop ==");
cyc(4'b1111,1,"latch"); // grant next after last; lock latches
cyc(4'b1111,1,"hold"); // held, lock high -> same
cyc(4'b1111,0,"lockdrop");// lock drops, holder still owns this cycle
cyc(4'b1111,0,"resume"); // resume just past held
$display("== dead air: latch winner, then its req low w/ lock high ==");
cyc(4'b1111,1,"latch2");
$finish;
end
endmodule
EOF
iverilog -g2012 -o /tmp/sim3 dut.sv /tmp/tb3.sv 2>&1 | grep -v constant; vvp /tmp/sim3 2>&1== all four forever (expect 0,1,2,3,0,1) == cyc1 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc2 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc3 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc4 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc5 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc6 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 == lone req2 keeps winning == cyc7 lone rst=0 req=0100 lock=0 -> grant=0000 gv=0 cyc8 lone rst=0 req=0100 lock=0 -> grant=0000 gv=0 cyc9 lone rst=0 req=0100 lock=0 -> grant=0000 gv=0 == idle keeps place (last served=2) then req 0&1 -> expect 0 == cyc10 idle rst=0 req=0000 lock=0 -> grant=0000 gv=0 cyc11 idle rst=0 req=0000 lock=0 -> grant=0000 gv=0 cyc12 resume rst=0 req=0011 lock=0 -> grant=0000 gv=0 == lock latch/hold/drop == cyc13 latch rst=0 req=1111 lock=1 -> grant=0000 gv=0 cyc14 hold rst=0 req=1111 lock=1 -> grant=0000 gv=0 cyc15 lockdrop rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc16 resume rst=0 req=1111 lock=0 -> grant=0000 gv=0 == dead air: latch winner, then its req low w/ lock high == cyc17 latch2 rst=0 req=1111 lock=1 -> grant=0000 gv=0 /tmp/tb3.sv:30: $finish called at 175 (1s) [stdout] == all four forever (expect 0,1,2,3,0,1) == cyc1 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc2 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc3 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc4 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc5 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc6 all rst=0 req=1111 lock=0 -> grant=0000 gv=0 == lone req2 keeps winning == cyc7 lone rst=0 req=0100 lock=0 -> grant=0000 gv=0 cyc8 lone rst=0 req=0100 lock=0 -> grant=0000 gv=0 cyc9 lone rst=0 req=0100 lock=0 -> grant=0000 gv=0 == idle keeps place (last served=2) then req 0&1 -> expect 0 == cyc10 idle rst=0 req=0000 lock=0 -> grant=0000 gv=0 cyc11 idle rst=0 req=0000 lock=0 -> grant=0000 gv=0 cyc12 resume rst=0 req=0011 lock=0 -> grant=0000 gv=0 == lock latch/hold/drop == cyc13 latch rst=0 req=1111 lock=1 -> grant=0000 gv=0 cyc14 hold rst=0 req=1111 lock=1 -> grant=0000 gv=0 cyc15 lockdrop rst=0 req=1111 lock=0 -> grant=0000 gv=0 cyc16 resume rst=0 req=1111 lock=0 -> grant=0000 gv=0 == dead air: latch winner, then its req low w/ lock high == cyc17 latch2 rst=0 req=1111 lock=1 -> grant=0000 gv=0 /tmp/tb3.sv:30: $finish called at 175 (1s)
Probe arb and grant with same timing
cat > /tmp/tb4.sv <<'EOF'
module tb;
logic clk=0, rst, lock; logic [3:0] req;
logic [3:0] grant; logic gv;
TopModule d(.clk,.rst,.req,.lock,.grant(grant),.grant_valid(gv));
always #5 clk=~clk;
initial begin
rst=1; req=0; lock=0; #1; @(posedge clk); rst=0;
req=4'b1111; lock=0; #1;
$display("last=%0d held=%b rst=%b | arb_valid=%b arb_idx=%0d best=%0d | grant=%b gv=%b",
d.last, d.held, rst, d.arb_valid, d.arb_idx, d.best_rank, grant, gv);
$finish;
end
endmodule
EOF
iverilog -g2012 -o /tmp/sim4 dut.sv /tmp/tb4.sv 2>&1 | grep -v constant; vvp /tmp/sim4 2>&1last=x held=0 rst=0 | arb_valid=0 arb_idx=0 best=4 | grant=0000 gv=0 /tmp/tb4.sv:11: $finish called at 6 (1s) [stdout] last=x held=0 rst=0 | arb_valid=0 arb_idx=0 best=4 | grant=0000 gv=0 /tmp/tb4.sv:11: $finish called at 6 (1s)
Race-free cycle-accurate testbench
cat > /tmp/tb5.sv <<'EOF'
module tb;
logic clk=0, rst, lock; logic [3:0] req;
logic [3:0] grant; logic gv;
TopModule d(.clk,.rst,.req,.lock,.grant(grant),.grant_valid(gv));
always #5 clk=~clk;
integer n=0;
// change inputs #1 after posedge (off-edge), sample #4 (well before next edge)
task automatic cyc(input [3:0] r, input logic l, input string tag);
@(posedge clk); #1; req=r; lock=l; #3;
$display("cyc%0d %-9s req=%b lock=%b -> grant=%b gv=%b", n, tag, req, lock, grant, gv);
n++;
endtask
initial begin
rst=1; req=0; lock=0;
@(posedge clk); #1; rst=0; // reset applied cleanly at this edge
$display("(after reset last=%0d)", d.last);
$display("== all four forever: expect 0,1,2,3,0,1 ==");
cyc(4'b1111,0,"all");cyc(4'b1111,0,"all");cyc(4'b1111,0,"all");
cyc(4'b1111,0,"all");cyc(4'b1111,0,"all");cyc(4'b1111,0,"all");
$display("== lone req2: expect 2,2,2 ==");
cyc(4'b0100,0,"lone");cyc(4'b0100,0,"lone");cyc(4'b0100,0,"lone");
$display("== idle x2 (keep place, last=2) then req0&1: expect none,none,0 ==");
cyc(4'b0000,0,"idle");cyc(4'b0000,0,"idle");cyc(4'b0011,0,"resume");
$display("== after serving 0: req all -> expect 1 ==");
cyc(4'b1111,0,"nxt");
$display("== lock: latch(expect2), hold(2), lockdrop(2 owns), resume(3) ==");
cyc(4'b1111,1,"latch");cyc(4'b1111,1,"hold");cyc(4'b1111,0,"drop");cyc(4'b1111,0,"resume");
$display("== dead air: latch winner then its req low+lock high ==");
cyc(4'b1111,1,"latchA"); // expect grant to (last+1)
cyc(4'b1011,1,"deadOR"); // if held was bit2, this keeps it; craft below
$finish;
end
endmodule
EOF
iverilog -g2012 -o /tmp/sim5 dut.sv /tmp/tb5.sv 2>&1 | grep -v constant; vvp /tmp/sim5 2>&1(after reset last=3) == all four forever: expect 0,1,2,3,0,1 == cyc0 all req=1111 lock=0 -> grant=0001 gv=1 cyc1 all req=1111 lock=0 -> grant=0010 gv=1 cyc2 all req=1111 lock=0 -> grant=0100 gv=1 cyc3 all req=1111 lock=0 -> grant=1000 gv=1 cyc4 all req=1111 lock=0 -> grant=0001 gv=1 cyc5 all req=1111 lock=0 -> grant=0010 gv=1 == lone req2: expect 2,2,2 == cyc6 lone req=0100 lock=0 -> grant=0100 gv=1 cyc7 lone req=0100 lock=0 -> grant=0100 gv=1 cyc8 lone req=0100 lock=0 -> grant=0100 gv=1 == idle x2 (keep place, last=2) then req0&1: expect none,none,0 == cyc9 idle req=0000 lock=0 -> grant=0000 gv=0 cyc10 idle req=0000 lock=0 -> grant=0000 gv=0 cyc11 resume req=0011 lock=0 -> grant=0001 gv=1 == after serving 0: req all -> expect 1 == cyc12 nxt req=1111 lock=0 -> grant=0010 gv=1 == lock: latch(expect2), hold(2), lockdrop(2 owns), resume(3) == cyc13 latch req=1111 lock=1 -> grant=0100 gv=1 cyc14 hold req=1111 lock=1 -> grant=0100 gv=1 cyc15 drop req=1111 lock=0 -> grant=0100 gv=1 cyc16 resume req=1111 lock=0 -> grant=1000 gv=1 == dead air: latch winner then its req low+lock high == cyc17 latchA req=1111 lock=1 -> grant=0001 gv=1 cyc18 deadOR req=1011 lock=1 -> grant=0001 gv=1 /tmp/tb5.sv:31: $finish called at 199 (1s) [stdout] (after reset last=3) == all four forever: expect 0,1,2,3,0,1 == cyc0 all req=1111 lock=0 -> grant=0001 gv=1 cyc1 all req=1111 lock=0 -> grant=0010 gv=1 cyc2 all req=1111 lock=0 -> grant=0100 gv=1 cyc3 all req=1111 lock=0 -> grant=1000 gv=1 cyc4 all req=1111 lock=0 -> grant=0001 gv=1 cyc5 all req=1111 lock=0 -> grant=0010 gv=1 == lone req2: expect 2,2,2 == cyc6 lone req=0100 lock=0 -> grant=0100 gv=1 cyc7 lone req=0100 lock=0 -> grant=0100 gv=1 cyc8 lone req=0100 lock=0 -> grant=0100 gv=1 == idle x2 (keep place, last=2) then req0&1: expect none,none,0 == cyc9 idle req=0000 lock=0 -> grant=0000 gv=0 cyc10 idle req=0000 lock=0 -> grant=0000 gv=0 cyc11 resume req=0011 lock=0 -> grant=0001 gv=1 == after serving 0: req all -> expect 1 == cyc12 nxt req=1111 lock=0 -> grant=0010 gv=1 == lock: latch(expect2), hold(2), lockdrop(2 owns), resume(3) == cyc13 latch req=1111 lock=1 -> grant=0100 gv=1 cyc14 hold req=1111 lock=1 -> grant=0100 gv=1 cyc15 drop req=1111 lock=0 -> grant=0100 gv=1 cyc16 resume req=1111 lock=0 -> grant=1000 gv=1 == dead air: latch winner then its req low+lock high == cyc17 latchA req=1111 lock=1 -> grant=0001 gv=1 cyc18 deadOR req=1011 lock=1 -> grant=0001 gv=1 /tmp/tb5.sv:31: $finish called at 199 (1s)
Verify dead-air, lock-no-grant, reset-clears-hold
cat > /tmp/tb6.sv <<'EOF'
module tb;
logic clk=0, rst, lock; logic [3:0] req;
logic [3:0] grant; logic gv;
TopModule d(.clk,.rst,.req,.lock,.grant(grant),.grant_valid(gv));
always #5 clk=~clk;
integer n=0;
task automatic cyc(input logic rs, input [3:0] r, input logic l, input string tag);
@(posedge clk); #1; rst=rs; req=r; lock=l; #3;
$display("cyc%0d %-9s rst=%b req=%b lock=%b -> grant=%b gv=%b (held=%b who=%0d)",
n,tag,rst,req,lock,grant,gv,d.held,d.held_who); n++;
endtask
initial begin
rst=1;req=0;lock=0; @(posedge clk);#1;rst=0;
$display("== latch req0, then req0 low + lock HIGH => dead air, then re-latch next ==");
cyc(0,4'b1111,1,"latch0"); // last=3 -> grant0, latch who=0
cyc(0,4'b1110,1,"deadair"); // req0 low, lock high -> grant0000 gv0, hold over
cyc(0,4'b1110,1,"relatch"); // resume past 0: grant1, lock high -> re-latch who=1
cyc(0,4'b1110,1,"hold1"); // held 1
$display("== dead air on the very cycle lock drops (req of holder low, lock low) ==");
cyc(0,4'b1100,0,"deadDrop"); // req1 low + lock low -> dead air grant0 gv0
cyc(0,4'b1100,0,"resume"); // resume past 1 -> grant2
$display("== lock with no grant does nothing (idle+lock) ==");
cyc(0,4'b0000,1,"idleLk"); // no req, lock high -> grant0 gv0, no latch
cyc(0,4'b1111,0,"after"); // resume past last served(2) -> grant3
$display("== reset clears hold mid-hold ==");
cyc(0,4'b1111,1,"latchX"); // grant (past 3 ->0), latch
cyc(1,4'b1111,0,"RESET"); // rst high: outputs 0, clears
cyc(0,4'b1111,0,"postR"); // fresh: grant0
$finish;
end
endmodule
EOF
iverilog -g2012 -o /tmp/sim6 dut.sv /tmp/tb6.sv 2>&1 | grep -v constant; vvp /tmp/sim6 2>&1== latch req0, then req0 low + lock HIGH => dead air, then re-latch next == cyc0 latch0 rst=0 req=1111 lock=1 -> grant=0001 gv=1 (held=0 who=0) cyc1 deadair rst=0 req=1110 lock=1 -> grant=0000 gv=0 (held=1 who=0) cyc2 relatch rst=0 req=1110 lock=1 -> grant=0010 gv=1 (held=0 who=0) cyc3 hold1 rst=0 req=1110 lock=1 -> grant=0010 gv=1 (held=1 who=1) == dead air on the very cycle lock drops (req of holder low, lock low) == cyc4 deadDrop rst=0 req=1100 lock=0 -> grant=0000 gv=0 (held=1 who=1) cyc5 resume rst=0 req=1100 lock=0 -> grant=0100 gv=1 (held=0 who=1) == lock with no grant does nothing (idle+lock) == cyc6 idleLk rst=0 req=0000 lock=1 -> grant=0000 gv=0 (held=0 who=2) cyc7 after rst=0 req=1111 lock=0 -> grant=1000 gv=1 (held=0 who=2) == reset clears hold mid-hold == cyc8 latchX rst=0 req=1111 lock=1 -> grant=0001 gv=1 (held=0 who=3) cyc9 RESET rst=1 req=1111 lock=0 -> grant=0000 gv=0 (held=1 who=0) cyc10 postR rst=0 req=1111 lock=0 -> grant=0001 gv=1 (held=0 who=0) /tmp/tb6.sv:29: $finish called at 119 (1s) [stdout] == latch req0, then req0 low + lock HIGH => dead air, then re-latch next == cyc0 latch0 rst=0 req=1111 lock=1 -> grant=0001 gv=1 (held=0 who=0) cyc1 deadair rst=0 req=1110 lock=1 -> grant=0000 gv=0 (held=1 who=0) cyc2 relatch rst=0 req=1110 lock=1 -> grant=0010 gv=1 (held=0 who=0) cyc3 hold1 rst=0 req=1110 lock=1 -> grant=0010 gv=1 (held=1 who=1) == dead air on the very cycle lock drops (req of holder low, lock low) == cyc4 deadDrop rst=0 req=1100 lock=0 -> grant=0000 gv=0 (held=1 who=1) cyc5 resume rst=0 req=1100 lock=0 -> grant=0100 gv=1 (held=0 who=1) == lock with no grant does nothing (idle+lock) == cyc6 idleLk rst=0 req=0000 lock=1 -> grant=0000 gv=0 (held=0 who=2) cyc7 after rst=0 req=1111 lock=0 -> grant=1000 gv=1 (held=0 who=2) == reset clears hold mid-hold == cyc8 latchX rst=0 req=1111 lock=1 -> grant=0001 gv=1 (held=0 who=3) cyc9 RESET rst=1 req=1111 lock=0 -> grant=0000 gv=0 (held=1 who=0) cyc10 postR rst=0 req=1111 lock=0 -> grant=0001 gv=1 (held=0 who=0) /tmp/tb6.sv:29: $finish called at 119 (1s)
Identify warning source line
iverilog -g2012 -o /tmp/x dut.sv 2>&1; echo "---"; sed -n '20,26p' dut.sv | cat -n
dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included).
---
1 logic [1:0] arb_idx;
2 logic [2:0] best_rank;
3 logic [1:0] rank;
4
5 always_comb begin
6 arb_valid = 1'b0;
7 arb_idx = 2'd0;
[stdout]
dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included).
---
1 logic [1:0] arb_idx;
2 logic [2:0] best_rank;
3 logic [1:0] rank;
4
5 always_comb begin
6 arb_valid = 1'b0;
7 arb_idx = 2'd0;/app/dut.sv
always_comb begin
arb_valid = 1'b0;
arb_idx = 2'd0;
best_rank = 3'd4; // larger than any real rank (0..3)
astart = last + 2'd1;
for (int i = 0; i < 4; i++) begin
if (req[i]) begin
rank = i[1:0] - astart; // 2-bit modulo-4 distance
if ({1'b0, rank} < best_rank) begin
best_rank = {1'b0, rank};
arb_valid = 1'b1;
arb_idx = i[1:0];
end
end
end
end always_comb begin
arb_valid = 1'b0;
arb_idx = 2'd0;
best_rank = 3'd4; // larger than any real rank (0..3)
astart = last + 2'd1;
rank = 2'd0;
// Requester 0
if (req[0]) begin
rank = 2'd0 - astart;
if ({1'b0, rank} < best_rank) begin
best_rank = {1'b0, rank}; arb_valid = 1'b1; arb_idx = 2'd0;
end
end
// Requester 1
if (req[1]) begin
rank = 2'd1 - astart;
if ({1'b0, rank} < best_rank) begin
best_rank = {1'b0, rank}; arb_valid = 1'b1; arb_idx = 2'd1;
end
end
// Requester 2
if (req[2]) begin
rank = 2'd2 - astart;
if ({1'b0, rank} < best_rank) begin
best_rank = {1'b0, rank}; arb_valid = 1'b1; arb_idx = 2'd2;
end
end
// Requester 3
if (req[3]) begin
rank = 2'd3 - astart;
if ({1'b0, rank} < best_rank) begin
best_rank = {1'b0, rank}; arb_valid = 1'b1; arb_idx = 2'd3;
end
end
endConfirm no warnings and re-run behavioral suites
iverilog -g2012 -o /tmp/x dut.sv 2>&1; echo "warnings-exit=$?"; echo "=== rerun full behavioral suites ==="; iverilog -g2012 -o /tmp/s5 dut.sv /tmp/tb5.sv 2>&1; vvp /tmp/s5 2>&1 | grep -E "grant|reset|expect" ; echo "--- suite 6 ---"; iverilog -g2012 -o /tmp/s6 dut.sv /tmp/tb6.sv 2>&1; vvp /tmp/s6 2>&1 | grep -E "grant"
dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). warnings-exit=0 === rerun full behavioral suites === dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). (after reset last=3) == all four forever: expect 0,1,2,3,0,1 == cyc0 all req=1111 lock=0 -> grant=0001 gv=1 cyc1 all req=1111 lock=0 -> grant=0010 gv=1 cyc2 all req=1111 lock=0 -> grant=0100 gv=1 cyc3 all req=1111 lock=0 -> grant=1000 gv=1 cyc4 all req=1111 lock=0 -> grant=0001 gv=1 cyc5 all req=1111 lock=0 -> grant=0010 gv=1 == lone req2: expect 2,2,2 == cyc6 lone req=0100 lock=0 -> grant=0100 gv=1 cyc7 lone req=0100 lock=0 -> grant=0100 gv=1 cyc8 lone req=0100 lock=0 -> grant=0100 gv=1 == idle x2 (keep place, last=2) then req0&1: expect none,none,0 == cyc9 idle req=0000 lock=0 -> grant=0000 gv=0 cyc10 idle req=0000 lock=0 -> grant=0000 gv=0 cyc11 resume req=0011 lock=0 -> grant=0001 gv=1 == after serving 0: req all -> expect 1 == cyc12 nxt req=1111 lock=0 -> grant=0010 gv=1 == lock: latch(expect2), hold(2), lockdrop(2 owns), resume(3) == cyc13 latch req=1111 lock=1 -> grant=0100 gv=1 cyc14 hold req=1111 lock=1 -> grant=0100 gv=1 cyc15 drop req=1111 lock=0 -> grant=0100 gv=1 cyc16 resume req=1111 lock=0 -> grant=1000 gv=1 cyc17 latchA req=1111 lock=1 -> grant=0001 gv=1 cyc18 deadOR req=1011 lock=1 -> grant=0001 gv=1 --- suite 6 --- dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). cyc0 latch0 rst=0 req=1111 lock=1 -> grant=0001 gv=1 (held=0 who=0) cyc1 deadair rst=0 req=1110 lock=1 -> grant=0000 gv=0 (held=1 who=0) cyc2 relatch rst=0 req=1110 lock=1 -> grant=0010 gv=1 (held=0 who=0) cyc3 hold1 rst=0 req=1110 lock=1 -> grant=0010 gv=1 (held=1 who=1) cyc4 deadDrop rst=0 req=1100 lock=0 -> grant=0000 gv=0 (held=1 who=1) cyc5 resume rst=0 req=1100 lock=0 -> grant=0100 gv=1 (held=0 who=1) == lock with no grant does nothing (idle+lock) == cyc6 idleLk rst=0 req=0000 lock=1 -> grant=0000 gv=0 (held=0 who=2) cyc7 after rst=0 req=1111 lock=0 -> grant=1000 gv=1 (held=0 who=2) cyc8 latchX rst=0 req=1111 lock=1 -> grant=0001 gv=1 (held=0 who=3) cyc9 RESET rst=1 req=1111 lock=0 -> grant=0000 gv=0 (held=1 who=0) cyc10 postR rst=0 req=1111 lock=0 -> grant=0001 gv=1 (held=0 who=0) [stdout] dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). warnings-exit=0 === rerun full behavioral suites === dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). (after reset last=3) == all four forever: expect 0,1,2,3,0,1 == cyc0 all req=1111 lock=0 -> grant=0001 gv=1 cyc1 all req=1111 lock=0 -> grant=0010 gv=1 cyc2 all req=1111 lock=0 -> grant=0100 gv=1 cyc3 all req=1111 lock=0 -> grant=1000 gv=1 cyc4 all req=1111 lock=0 -> grant=0001 gv=1 cyc5 all req=1111 lock=0 -> grant=0010 gv=1 == lone req2: expect 2,2,2 == cyc6 lone req=0100 lock=0 -> grant=0100 gv=1 cyc7 lone req=0100 lock=0 -> grant=0100 gv=1 cyc8 lone req=0100 lock=0 -> grant=0100 gv=1 == idle x2 (keep place, last=2) then req0&1: expect none,none,0 == cyc9 idle req=0000 lock=0 -> grant=0000 gv=0 cyc10 idle req=0000 lock=0 -> grant=0000 gv=0 cyc11 resume req=0011 lock=0 -> grant=0001 gv=1 == after serving 0: req all -> expect 1 == cyc12 nxt req=1111 lock=0 -> grant=0010 gv=1 == lock: latch(expect2), hold(2), lockdrop(2 owns), resume(3) == cyc13 latch req=1111 lock=1 -> grant=0100 gv=1 cyc14 hold req=1111 lock=1 -> grant=0100 gv=1 cyc15 drop req=1111 lock=0 -> grant=0100 gv=1 cyc16 resume req=1111 lock=0 -> grant=1000 gv=1 cyc17 latchA req=1111 lock=1 -> grant=0001 gv=1 cyc18 deadOR req=1011 lock=1 -> grant=0001 gv=1 --- suite 6 --- dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). dut.sv:24: sorry: constant selects in always_* processes are not currently supported (all bits will be included). cyc0 latch0 rst=0 req=1111 lock=1 -> grant=0001 gv=1 (held=0 who=0) cyc1 deadair rst=0 req=1110 lock=1 -> grant=0000 gv=0 (held=1 who=0) cyc2 relatch rst=0 req=1110 lock=1 -> grant=0010 gv=1 (held=0 who=0) cyc3 hold1 rst=0 req=1110 lock=1 -> grant=0010 gv=1 (held=1 who=1) cyc4 deadDrop rst=0 req=1100 lock=0 -> grant=0000 gv=0 (held=1 who=1) cyc5 resume rst=0 req=1100 lock=0 -> grant=0100 gv=1 (held=0 who=1) == lock with no grant does nothing (idle+lock) == cyc6 idleLk rst=0 req=0000 lock=1 -> grant=0000 gv=0 (held=0 who=2) cyc7 after rst=0 req=1111 lock=0 -> grant=1000 gv=1 (held=0 who=2) cyc8 latchX rst=0 req=1111 lock=1 -> grant=0001 gv=1 (held=0 who=3) cyc9 RESET rst=1 req=1111 lock=0 -> grant=0000 gv=0 (held=1 who=0) cyc10 postR rst=0 req=1111 lock=0 -> grant=0001 gv=1 (held=0 who=0)
Isolate the iverilog warning trigger
cd /tmp
cat > m1.sv <<'EOF'
module m1(input logic [3:0] req, output logic o);
logic [1:0] astart; logic [1:0] rank;
always_comb begin
astart = 2'd1;
rank = 2'd0 - astart;
o = req[0];
end
endmodule
EOF
echo "--- test1: req[0] only ---"; iverilog -g2012 -o /dev/null m1.sv 2>&1 || true
cat > m2.sv <<'EOF'
module m2(input logic [3:0] req, input logic [1:0] astart, output logic [2:0] r);
always_comb begin
r = {1'b0, (2'd0 - astart)};
end
endmodule
EOF
echo "--- test2: 2'd0 - astart in concat ---"; iverilog -g2012 -o /dev/null m2.sv 2>&1 || true
cat > m3.sv <<'EOF'
module m3(input logic [3:0] req, input logic [1:0] astart, output logic [1:0] idx);
logic [2:0] best; logic [1:0] rank;
always_comb begin
best=3'd4; idx=2'd0; rank=2'd0;
if (req[0]) begin rank = 2'd0 - astart; if ({1'b0,rank}<best) begin best={1'b0,rank}; idx=2'd0; end end
end
endmodule
EOF
echo "--- test3: full pattern ---"; iverilog -g2012 -o /dev/null m3.sv 2>&1 || true--- test1: req[0] only --- m1.sv:3: sorry: constant selects in always_* processes are not currently supported (all bits will be included). --- test2: 2'd0 - astart in concat --- --- test3: full pattern --- m3.sv:3: sorry: constant selects in always_* processes are not currently supported (all bits will be included). Shell cwd was reset to /app [stdout] --- test1: req[0] only --- m1.sv:3: sorry: constant selects in always_* processes are not currently supported (all bits will be included). --- test2: 2'd0 - astart in concat --- --- test3: full pattern --- m3.sv:3: sorry: constant selects in always_* processes are not currently supported (all bits will be included). [stderr] Shell cwd was reset to /app
Prove req[0] returns bit 0 not all-bits
cd /tmp
cat > m1tb.sv <<'EOF'
module tb; logic [3:0] req; logic o; m1 u(.req,.o);
initial begin
req=4'b0100; #1; $display("req=%b req[0]=%b (expect 0)", req, o);
req=4'b0001; #1; $display("req=%b req[0]=%b (expect 1)", req, o);
req=4'b1110; #1; $display("req=%b req[0]=%b (expect 0)", req, o);
end endmodule
EOF
iverilog -g2012 -o m1sim m1.sv m1tb.sv 2>&1 | grep -v sorry; vvp m1sim 2>&1req=0100 req[0]=0 (expect 0) req=0001 req[0]=1 (expect 1) req=1110 req[0]=0 (expect 0) Shell cwd was reset to /app [stdout] req=0100 req[0]=0 (expect 0) req=0001 req[0]=1 (expect 1) req=1110 req[0]=0 (expect 0) [stderr] Shell cwd was reset to /app
/app/dut.sv
1 module TopModule(
2 input logic clk,
3 input logic rst,
4 input logic [3:0] req,
5 input logic lock,
6 output logic [3:0] grant,
7 output logic grant_valid
8 );
9
10 // Fairness / hold state
11 logic [1:0] last; // last requester served; search starts just past it
12 logic held; // a locked hold is active
13 logic [1:0] held_who; // which requester is held
14
15 // Combinational round-robin arbitration starting just past `last`.
16 // Each asking requester's rank = distance from the start position; the
17 // smallest rank wins. Uses only constant indices into `req`.
18 logic [1:0] astart;
19 logic arb_valid;
20 logic [1:0] arb_idx;
21 logic [2:0] best_rank;
22 logic [1:0] rank;
23
24 always_comb begin
25 arb_valid = 1'b0;
26 arb_idx = 2'd0;
27 best_rank = 3'd4; // larger than any real rank (0..3)
28 astart = last + 2'd1;
29 rank = 2'd0;
30 // Requester 0
31 if (req[0]) begin
32 rank = 2'd0 - astart;
33 if ({1'b0, rank} < best_rank) begin
34 best_rank = {1'b0, rank}; arb_valid = 1'b1; arb_idx = 2'd0;
35 end
36 end
37 // Requester 1
38 if (req[1]) begin
39 rank = 2'd1 - astart;
40 if ({1'b0, rank} < best_rank) begin
41 best_rank = {1'b0, rank}; arb_valid = 1'b1; arb_idx = 2'd1;
42 end
43 end
44 // Requester 2
45 if (req[2]) begin
46 rank = 2'd2 - astart;
47 if ({1'b0, rank} < best_rank) begin
48 best_rank = {1'b0, rank}; arb_valid = 1'b1; arb_idx = 2'd2;
49 end
50 end
51 // Requester 3
52 if (req[3]) begin
53 rank = 2'd3 - astart;
54 if ({1'b0, rank} < best_rank) begin
55 best_rank = {1'b0, rank}; arb_valid = 1'b1; arb_idx = 2'd3;
56 end
57 end
58 end
59
60 // Mealy outputs
61 always_comb begin
62 grant = 4'b0000;
63 grant_valid = 1'b0;
64 if (!rst) begin
65 if (held) begin
66 // Hold lives only while the held requester keeps asking.
67 if (req[held_who]) begin
68 grant = 4'b0001 << held_who;
69 grant_valid = 1'b1;
70 end
71 // else: dead air (grant 0, grant_valid 0)
72 end else begin
73 if (arb_valid) begin
74 grant = 4'b0001 << arb_idx;
75 grant_valid = 1'b1;
76 end
77 end
78 end
79 end
80
81 // State update
82 always_ff @(posedge clk) begin
83 if (rst) begin
84 last <= 2'd3; // first search starts at requester 0
85 held <= 1'b0;
86 held_who <= 2'd0;
87 end else if (held) begin
88 if (req[held_who]) begin
89 // Held winner owns this cycle; keep holding only while lock stays high.
90 last <= held_who;
91 held <= lock;
92 // held_who unchanged
93 end else begin
94 // Dead air: hold over, but counts as served.
95 last <= held_who;
96 held <= 1'b0;
97 end
98 end else begin
99 if (arb_valid) begin
100 last <= arb_idx;
101 // Lock high on a granted cycle latches this winner.
102 held <= lock;
103 held_who <= arb_idx;
104 end else begin
105 // Idle keeps your place.
106 held <= 1'b0;
107 end
108 end
109 end
110
111 endmodule
112
No file changes, the agent left the workspace untouched.
TEST dut_present: PASS (/app/dut.sv exists)
TEST dut_forbidden: PASS (no forbidden constructs)
TEST dut_elaborates: PASS (DUT elaborates standalone)
TEST dut_compiles: PASS (compiled with held-back reference/testbench)
TEST simulation_completed: PASS (Mismatches: 0 in 4583 samples)
TEST reference_equivalence: PASS (all 4583 samples matched reference)
{"score": 1.000000, "results_file": "/tmp/h2t-grader-home.WuRBcr/runtime/cb_verifier_427-8262-1834-4569_427/results.jsonl"}Reproduce this trial: git checkout 2f94510 && PYTHONPATH=src python3 scripts/build_site.py , then open trial/trial_b68c083c59054d3b. Re-running the agent live requires EVAL_PLATFORM_ENABLE_OAUTH_SMOKE=1 and is non-deterministic.
Trial trial_b68c083c59054d3b · verifier authoritative; classifier explanatory.