Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions rtl/stoch_skip/stoch_skip_gate.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Wave 44, lane OO, S-188 + S-189
// anchor phi^2+phi^-2=3, DOI 10.5281/zenodo.19227877
// theta_freq=7 Hz, theta_period_ps=142857143

module theta_phase_counter (
input logic clk,
input logic rst_n,
output logic theta_off_phase // 1 when in OFF half of theta cycle
);
// 32-bit counter modulo HALF_PERIOD_CYCLES; toggles theta_off_phase
parameter int HALF_PERIOD_CYCLES = 32'd71428571; // half of theta_period_ps/2 at 1 ns clock
logic [31:0] cnt;
logic phase;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 32'd0;
phase <= 1'b0;
end else if (cnt == (HALF_PERIOD_CYCLES - 1)) begin
cnt <= 32'd0;
phase <= ~phase;
end else begin
cnt <= cnt + 32'd1;
end
end
assign theta_off_phase = phase;
endmodule

module stoch_skip_decision (
input logic cos_sim_pass, // 1 when cos_sim(act_t, act_{t-1}) >= 0.94
input logic theta_off_phase, // 1 when theta phase is OFF
output logic skip_compute // 1 when row skips current cycle
);
assign skip_compute = cos_sim_pass & theta_off_phase;
endmodule

module theta_skip_gate_top (
input logic clk,
input logic rst_n,
input logic cos_sim_pass,
output logic skip_compute
);
logic theta_off_phase;

theta_phase_counter u_phase_ctr (
.clk (clk),
.rst_n (rst_n),
.theta_off_phase(theta_off_phase)
);

stoch_skip_decision u_skip_dec (
.cos_sim_pass (cos_sim_pass),
.theta_off_phase(theta_off_phase),
.skip_compute (skip_compute)
);
endmodule
152 changes: 152 additions & 0 deletions rtl/stoch_skip/stoch_skip_gate_tb.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Testbench for stoch_skip_gate.sv
// Wave 44, lane OO, S-188 + S-189
// 7 test cases

`timescale 1ns/1ps

module stoch_skip_gate_tb;

logic clk;
logic rst_n;
logic cos_sim_pass;
logic skip_compute;

// Instantiate DUT
theta_skip_gate_top dut (
.clk (clk),
.rst_n (rst_n),
.cos_sim_pass (cos_sim_pass),
.skip_compute (skip_compute)
);

// Clock generation: 1 ns period
initial clk = 1'b0;
always #0.5 clk = ~clk;

// Task: apply one clock edge
task tick;
@(posedge clk);
#0.1;
endtask

integer fail_count;

initial begin
fail_count = 0;

// TB1: rst_n=0 => skip_compute must be 0
rst_n = 1'b0;
cos_sim_pass = 1'b1;
@(posedge clk); #0.1;
if (skip_compute !== 1'b0) begin
$display("FAIL TB1: expected skip=0 during reset, got %b", skip_compute);
fail_count = fail_count + 1;
end else begin
$display("PASS TB1: reset holds skip=0");
end

// Deassert reset
rst_n = 1'b1;
tick;

// TB2: cos_pass=0, theta_off=0 => skip=0
cos_sim_pass = 1'b0;
// theta_off_phase starts at 0 after reset
tick;
if (skip_compute !== 1'b0) begin
$display("FAIL TB2: expected skip=0 (cos=0, theta_off=0), got %b", skip_compute);
fail_count = fail_count + 1;
end else begin
$display("PASS TB2: cos=0 theta_off=0 => skip=0");
end

// TB3: cos_pass=1, theta_off=0 => skip=0
cos_sim_pass = 1'b1;
tick;
if (skip_compute !== 1'b0) begin
$display("FAIL TB3: expected skip=0 (cos=1, theta_off=0), got %b", skip_compute);
fail_count = fail_count + 1;
end else begin
$display("PASS TB3: cos=1 theta_off=0 => skip=0");
end

// TB4 and TB5: need to force theta_off_phase=1 via direct force
// Force internal phase signal to 1 to test OFF-phase behavior
force dut.u_phase_ctr.phase = 1'b1;
tick;

// TB4: cos_pass=0, theta_off=1 => skip=0
cos_sim_pass = 1'b0;
tick;
if (skip_compute !== 1'b0) begin
$display("FAIL TB4: expected skip=0 (cos=0, theta_off=1), got %b", skip_compute);
fail_count = fail_count + 1;
end else begin
$display("PASS TB4: cos=0 theta_off=1 => skip=0");
end

// TB5: cos_pass=1, theta_off=1 => skip=1
cos_sim_pass = 1'b1;
tick;
if (skip_compute !== 1'b1) begin
$display("FAIL TB5: expected skip=1 (cos=1, theta_off=1), got %b", skip_compute);
fail_count = fail_count + 1;
end else begin
$display("PASS TB5: cos=1 theta_off=1 => skip=1");
end

// Release force
release dut.u_phase_ctr.phase;

// TB6: clock several cycles to observe theta_off toggling
// Reset and run until first toggle
rst_n = 1'b0;
repeat(2) tick;
rst_n = 1'b1;
cos_sim_pass = 1'b1;
begin
logic prev_theta;
integer toggle_count;
integer i;
prev_theta = 1'b0;
toggle_count = 0;
// Run enough cycles to see multiple toggles using a shortened HALF_PERIOD
// Force cnt near rollover to observe toggle quickly
force dut.u_phase_ctr.cnt = 32'd71428569;
repeat(4) tick;
release dut.u_phase_ctr.cnt;
// Check that theta_off_phase toggled at least once
for (i = 0; i < 5; i++) begin
if (dut.u_phase_ctr.theta_off_phase !== prev_theta) begin
toggle_count = toggle_count + 1;
prev_theta = dut.u_phase_ctr.theta_off_phase;
end
tick;
end
if (toggle_count >= 1) begin
$display("PASS TB6: theta_off_phase toggled %0d time(s)", toggle_count);
end else begin
$display("FAIL TB6: theta_off_phase did not toggle");
fail_count = fail_count + 1;
end
end

// TB7: assert HALF_PERIOD_CYCLES parameter value
if (dut.u_phase_ctr.HALF_PERIOD_CYCLES !== 32'd71428571) begin
$display("FAIL TB7: HALF_PERIOD_CYCLES mismatch, got %0d", dut.u_phase_ctr.HALF_PERIOD_CYCLES);
fail_count = fail_count + 1;
end else begin
$display("PASS TB7: HALF_PERIOD_CYCLES == 71428571");
end

// Summary
if (fail_count == 0) begin
$display("ALL TESTS PASSED (7/7)");
end else begin
$display("FAILED: %0d test(s) failed", fail_count);
end

$finish;
end

endmodule
Loading