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
92 changes: 92 additions & 0 deletions rtl/int2_quant/int2_packer.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// =============================================================================
// Wave 43 -- Lane MM -- S-180 + S-181
// File : rtl/int2_quant/int2_packer.sv
// Anchor : phi^2+phi^-2=3 (three-path witness)
// DOI : 10.5281/zenodo.19227877
//
// INT2 Codebook
// State Code INT4 approx
// -1 2'b00 4'sb1111 (-1)
// 0 2'b01 4'sb0000 ( 0)
// +phi^-1 2'b10 4'b0011 (~+0.618 quantized to +3 in 4-bit scale)
// +1 2'b11 4'sb0001 (+1)
//
// phi^-1 = (sqrt(5)-1)/2 ~ 0.618
// +phi^-1 quantized to nearest INT4 value: 3 in range [-8..+7] -> 4'b0011
//
// R-SI-1 compliance: zero star, zero slash, zero unsigned-right-shift sign-loss.
// Only assign, case, comparison, addition, bitwise operators used.
// =============================================================================

// -----------------------------------------------------------------------------
// Module: int2_unpacker
// Combinational lookup: INT2 code -> sign-extended INT4 activation
// -----------------------------------------------------------------------------
module int2_unpacker (
input logic [1:0] code,
output logic [3:0] int4_act
);
// Decode INT2 code to INT4 representation.
// Code 2'b00 => -1 => 4'sb1111
// Code 2'b01 => 0 => 4'sb0000
// Code 2'b10 => +phi^-1 (~0.618) quantized => 4'b0011 (+3 in INT4)
// Code 2'b11 => +1 => 4'sb0001
always_comb begin
case (code)
2'b00: int4_act = 4'sb1111; // -1
2'b01: int4_act = 4'sb0000; // 0
2'b10: int4_act = 4'b0011; // +phi^-1, quantized to +3
2'b11: int4_act = 4'sb0001; // +1
default: int4_act = 4'sb0000;
endcase
end
endmodule

// -----------------------------------------------------------------------------
// Module: int2_pack_sram_iface
// Packs four INT2 codes into one 8-bit SRAM word (little-endian bit order).
// act0 occupies bits [1:0], act1 bits [3:2], act2 bits [5:4], act3 bits [7:6].
// -----------------------------------------------------------------------------
module int2_pack_sram_iface (
input logic [1:0] act0,
input logic [1:0] act1,
input logic [1:0] act2,
input logic [1:0] act3,
output logic [7:0] sram_word
);
assign sram_word = {act3, act2, act1, act0};
endmodule

// -----------------------------------------------------------------------------
// Module: int2_col13_gate
// Quantizes a signed INT4 activation back to INT2 code.
// Thresholds (approximate, integer arithmetic only -- R-SI-1 compliant):
// act < -1 => code 2'b00 (-1 bucket)
// act == 0 => code 2'b01 ( 0 bucket)
// 0 < act < 2 => code 2'b10 (phi^-1 bucket, mid-positive)
// act >= 2 => code 2'b11 (+1 bucket)
// act < 0 and act != -1 ... rounded to -1 bucket
//
// Decision boundaries chosen to partition [-8..+7] into four regions:
// Region 2'b00: act_int4 <= -1 (any negative)
// Region 2'b01: act_int4 == 0
// Region 2'b10: act_int4 == 1 or act_int4 == 2 (small positive)
// Region 2'b11: act_int4 >= 3 (large positive)
//
// No star, no slash operators used.
// -----------------------------------------------------------------------------
module int2_col13_gate (
input logic signed [3:0] act_int4,
output logic [1:0] code
);
always_comb begin
if (act_int4 <= 4'sb1111) // act_int4 <= -1 (negative)
code = 2'b00;
else if (act_int4 == 4'sb0000) // act_int4 == 0
code = 2'b01;
else if (act_int4 <= 4'sb0010) // 1 <= act_int4 <= 2 (phi^-1 region)
code = 2'b10;
else // act_int4 >= 3 (+1 region)
code = 2'b11;
end
endmodule
130 changes: 130 additions & 0 deletions rtl/int2_quant/int2_packer_tb.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// =============================================================================
// Testbench: int2_packer_tb
// Wave 43, Lane MM -- S-180 + S-181
// Tests: int2_unpacker, int2_pack_sram_iface, int2_col13_gate
// =============================================================================
module int2_packer_tb;

// -------------------------------------------------------------------------
// DUT signals
// -------------------------------------------------------------------------
logic [1:0] code_in;
logic [3:0] int4_out;

logic [1:0] act0, act1, act2, act3;
logic [7:0] sram_word;

logic signed [3:0] act_int4_in;
logic [1:0] code_out;

integer errors;

// -------------------------------------------------------------------------
// Instantiations
// -------------------------------------------------------------------------
int2_unpacker u_unpacker (
.code (code_in),
.int4_act(int4_out)
);

int2_pack_sram_iface u_packer (
.act0 (act0),
.act1 (act1),
.act2 (act2),
.act3 (act3),
.sram_word(sram_word)
);

int2_col13_gate u_gate (
.act_int4(act_int4_in),
.code (code_out)
);

// -------------------------------------------------------------------------
// Test tasks
// -------------------------------------------------------------------------
task check_unpack;
input [1:0] c;
input signed [3:0] expected;
input [63:0] test_id;
begin
code_in = c;
#1;
if (int4_out !== expected) begin
$display("FAIL Test %0d: int2_unpacker(2'b%02b) = 4'b%04b, expected 4'b%04b",
test_id, c, int4_out, expected);
errors = errors + 1;
end else begin
$display("PASS Test %0d: int2_unpacker(2'b%02b) = 4'b%04b", test_id, c, int4_out);
end
end
endtask

task check_gate;
input signed [3:0] act;
input [1:0] expected_code;
input [63:0] test_id;
begin
act_int4_in = act;
#1;
if (code_out !== expected_code) begin
$display("FAIL Test %0d: int2_col13_gate(4'sb%04b) = 2'b%02b, expected 2'b%02b",
test_id, act, code_out, expected_code);
errors = errors + 1;
end else begin
$display("PASS Test %0d: int2_col13_gate(4'sb%04b) = 2'b%02b", test_id, act, code_out);
end
end
endtask

// -------------------------------------------------------------------------
// Main test sequence
// -------------------------------------------------------------------------
initial begin
errors = 0;

// Test 1: int2_unpacker code=2'b00 -> -1 => 4'sb1111
check_unpack(2'b00, 4'sb1111, 1);

// Test 2: int2_unpacker code=2'b01 -> 0 => 4'sb0000
check_unpack(2'b01, 4'sb0000, 2);

// Test 3: int2_unpacker code=2'b10 -> phi^-1 approx => 4'b0011 (+3)
check_unpack(2'b10, 4'b0011, 3);

// Test 4: int2_unpacker code=2'b11 -> +1 => 4'sb0001
check_unpack(2'b11, 4'sb0001, 4);

// Test 5: int2_pack_sram_iface -- verify bit packing
// act0=2'b01, act1=2'b10, act2=2'b11, act3=2'b00 -> sram_word = 8'b00_11_10_01
act0 = 2'b01;
act1 = 2'b10;
act2 = 2'b11;
act3 = 2'b00;
#1;
if (sram_word !== 8'b00111001) begin
$display("FAIL Test 5: pack({00,11,10,01}) = 8'b%08b, expected 8'b00111001", sram_word);
errors = errors + 1;
end else begin
$display("PASS Test 5: pack({00,11,10,01}) = 8'b%08b", sram_word);
end

// Test 6: int2_col13_gate(4'sb0000 = 0) -> code 2'b01
check_gate(4'sb0000, 2'b01, 6);

// Test 7: int2_col13_gate(4'sb0111 = +7, max positive) -> code 2'b11 (+1 region)
check_gate(4'sb0111, 2'b11, 7);

// Test 8: int2_col13_gate(4'sb1001 = -7, negative) -> code 2'b00 (-1 region)
check_gate(4'sb1001, 2'b00, 8);

// Summary
if (errors == 0)
$display("ALL TESTS PASSED (8/8)");
else
$display("FAILURES: %0d / 8 tests failed", errors);

$finish;
end

endmodule
Loading