From 8ed0c66233426e45c0a25414a83f55ea3948e065 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Fri, 18 Sep 2026 18:27:41 +0200 Subject: [PATCH 01/36] Modify multiplier testbench to disable Q_BITWIDTH Commented out Q_BITWIDTH and fraction_bit_i in the testbench. --- test/multiplier/multiplier_tb.v | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/multiplier/multiplier_tb.v b/test/multiplier/multiplier_tb.v index 270e47f8..d9f27d39 100644 --- a/test/multiplier/multiplier_tb.v +++ b/test/multiplier/multiplier_tb.v @@ -10,7 +10,7 @@ module multiplier_tb(); localparam integer DATA_WIDTH_FAC1 = 8; localparam integer DATA_WIDTH_FAC2 = 8; localparam integer DATA_WIDTH_PROD = 20; - localparam integer Q_BITWIDTH = $clog2(DATA_WIDTH_PROD); + //localparam integer Q_BITWIDTH = $clog2(DATA_WIDTH_PROD); localparam integer TEST_STEP = 20; //only for testbench verification @@ -21,7 +21,7 @@ module multiplier_tb(); reg signed [DATA_WIDTH_FAC1-1:0] factor1_tb; reg signed [DATA_WIDTH_FAC2-1:0] factor2_tb; wire signed [DATA_WIDTH_PROD-1:0] product_tb; - reg [Q_BITWIDTH-1:0] fraction_bit_i; + //reg [Q_BITWIDTH-1:0] fraction_bit_i; reg result_in_step[0:TEST_STEP-1]; //Result vector //only for testbench verification reg computation_was_right = 1; //Result flag //only for testbench verification @@ -33,8 +33,8 @@ module multiplier_tb(); .DATA_WIDTH_FAC1(DATA_WIDTH_FAC1), .DATA_WIDTH_FAC2(DATA_WIDTH_FAC2), - .DATA_WIDTH_PROD(DATA_WIDTH_PROD), - .Q_BITWIDTH(Q_BITWIDTH) + .DATA_WIDTH_PROD(DATA_WIDTH_PROD) + //.Q_BITWIDTH(Q_BITWIDTH) ) multiplier( @@ -43,8 +43,9 @@ module multiplier_tb(); .multiplier_en_i(multiplier_en_i_tb), .factor_1(factor1_tb), .factor_2(factor2_tb), - .product(product_tb), - .fraction_bit_i(fraction_bit_i)); + .product(product_tb) + //.fraction_bit_i(fraction_bit_i) + ); // main test block From cefbb44cac2af300e9898de14bc4be9cf2c727f2 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Wed, 23 Sep 2026 15:58:03 +0200 Subject: [PATCH 02/36] Add PE matrix multiplication testbench --- test/cocotb_PE/PE_matrix_tb.py | 308 +++++++++++++++++++++++++++++++ test/cocotb_PE/test_PE_matrix.py | 42 +++++ 2 files changed, 350 insertions(+) create mode 100644 test/cocotb_PE/PE_matrix_tb.py create mode 100644 test/cocotb_PE/test_PE_matrix.py diff --git a/test/cocotb_PE/PE_matrix_tb.py b/test/cocotb_PE/PE_matrix_tb.py new file mode 100644 index 00000000..56f36362 --- /dev/null +++ b/test/cocotb_PE/PE_matrix_tb.py @@ -0,0 +1,308 @@ +import cocotb + +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, FallingEdge, Timer +from cocotb.utils import get_sim_time + +@cocotb.test() +async def test_pe_matrix(dut): + + # --------------------------------- + # 1. Define our matrices + # --------------------------------- + + A = [ + [1, 2], + [3, 4] + ] + + W = [ + [5, 6], + [7, 8] + ] + + # Expected output matrix + Y = [ + [0, 0], + [0, 0] + ] + + # Calculate the expected result + for row in range(2): + for col in range(2): + for k in range(2): + + Y[row][col] += A[row][k] * W[k][col] + + assert Y == [[19, 22], [43, 50]] + + dut._log.info(f"Expected matrix: {Y}") + + # --------------------------------- + # 2. Initialize all inputs + # --------------------------------- + + dut.clk_i.value = 0 + dut.rst_ni.value = 0 + + inputs = [ + "iact_select_i", + "iact_data_i", + "iact_enable_i", + "wght_data_i", + "wght_enable_i", + "psum_data_i", + "psum_enable_i", + "psum_ready_i", + "compute_i", + "enable_stream_i", + "data_stream_i", + "iact_pass_data_i", + "iact_pass_enable_i", + "iact_pass_ready_i", + ] + + for name in inputs: + getattr(dut, name).value = 0 + + # --------------------------------- + # 3. Start clock + # --------------------------------- + + cocotb.start_soon( + Clock(dut.clk_i, 10, unit="ns").start() + ) + + # --------------------------------- + # 4. Reset PE + # --------------------------------- + + for _ in range(3): + await RisingEdge(dut.clk_i) + + await FallingEdge(dut.clk_i) + dut.rst_ni.value = 1 + + # --------------------------------- + # 5. Send configuration + # --------------------------------- + + # One row has two activations. + # C0 = 1, B = 2, M0 = 2 + + for value in [2, 1, 2]: + + await FallingEdge(dut.clk_i) + + dut.enable_stream_i.value = 1 + dut.data_stream_i.value = value + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + await FallingEdge(dut.clk_i) + + dut.enable_stream_i.value = 0 + dut.data_stream_i.value = 0 + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + # --------------------------------- + # 6. Check configuration + # --------------------------------- + + assert int(dut.iact_addr_max_reg.value) == 2 + assert int(dut.channel_reg_C0.value) == 1 + assert int(dut.filters_reg_M0.value) == 2 + + dut._log.info("PASS: Matrix definition, reset and configuration") + + # --------------------------------- + # 7. Send first row of Input activations + # --------------------------------- + + # Select activation input lane 0 + dut.iact_select_i.value = 0 + + dut.iact_data_i.value = (2 << 8) | 1 + + # Enable activation lane 0 + dut.iact_enable_i.value = 0b001 + + # PE extracts activation 1 + # ------------------------------------------------- + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + # PE writes 1 into SPad + # ------------------------------------------------- + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + # --------------------------------- + # 8. Stop sending activation data + # --------------------------------- + + await FallingEdge(dut.clk_i) + + dut.iact_enable_i.value = 0 + dut.iact_data_i.value = 0 + + # --------------------------------- + # 9. Check First activation is loaded into SPad + # --------------------------------- + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + dut._log.info("Activation row [1, 2] loaded") + + # --------------------------------- + # 10. send the weight + # --------------------------------- + + weights = [5, 6, 7, 8] + + for weight in weights: + + await FallingEdge(dut.clk_i) + + dut.wght_data_i.value = weight + dut.wght_enable_i.value = 1 + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + await FallingEdge(dut.clk_i) + + dut.wght_enable_i.value = 0 + dut.wght_data_i.value = 0 + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + dut._log.info("Weight loading sequence completed") + + #--------------------------------- + ## Send the first weight row: [5, 7] + #weight_word = (W[0][1] << 8) | W[0][0] + + #await FallingEdge(dut.clk_i) + + #dut.wght_data_i.value = weight_word + #dut.wght_enable_i.value = 1 + + #await RisingEdge(dut.clk_i) + #await Timer(1, unit="ns") + + ## Send the second weight row: [6, 8] + #await FallingEdge(dut.clk_i) + + #weight_word = (W[1][1] << 8) | W[1][0] + + #dut.wght_data_i.value = weight_word + + #await RisingEdge(dut.clk_i) + #await Timer(1, unit="ns") + #--------------------------------- + + # --------------------------------- + # 11. Allow the registered SPad writes to complete. + # --------------------------------- + + await FallingEdge(dut.clk_i) + + dut.wght_enable_i.value = 0 + dut.wght_data_i.value = 0 + + await RisingEdge(dut.clk_i) + await RisingEdge(dut.clk_i) + + await Timer(1, unit="ns") + + dut._log.info("Weight loading sequence completed") + + # --------------------------------- + # 12. Computation. + # --------------------------------- + + # Check that the PE is ready + assert int(dut.iact_set.value) == 1 + assert int(dut.wght_set.value) == 1 + + await FallingEdge(dut.clk_i) + + dut.compute_i.value = 1 + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + assert int(dut.current_state_computing.value) == 1 + + await FallingEdge(dut.clk_i) + + dut.compute_i.value = 0 + + # --------------------------------- + # 13. Psum ready and data + # --------------------------------- + + # Wait until the PE finishes computing + for _ in range(30): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + if int(dut.current_state_computing.value) == 7: + break + + assert int(dut.current_state_computing.value) == 7 + + dut._log.info("PE computation completed") + + # --------------------------------- + # 14. PSUM handshake + # --------------------------------- + + dut.psum_ready_i.value = 1 + + await RisingEdge(dut.psum_ready_o) + await Timer(10, unit="ns") + + # M0 = 2 -> send two zero biases + for _ in range(2): + + await FallingEdge(dut.clk_i) + + dut.psum_data_i.value = 0 + dut.psum_enable_i.value = 1 + + await RisingEdge(dut.clk_i) + + await FallingEdge(dut.clk_i) + + dut.psum_enable_i.value = 0 + dut.psum_data_i.value = 0 + + # --------------------------------- + # 15. Read outputs + # --------------------------------- + + await RisingEdge(dut.psum_enable_o) + await Timer(10, unit="ns") + + outputs = [] + + while int(dut.psum_enable_o.value) == 1: + + data = dut.psum_data_o.value.to_signed() + + outputs.append(data) + + dut._log.info(f"PE output: {data}") + await Timer(10, unit="ns") + + dut._log.info(f"Final outputs: {outputs}") + + assert outputs == [19, 22], \ + f"Expected [19, 22], got {outputs}" \ No newline at end of file diff --git a/test/cocotb_PE/test_PE_matrix.py b/test/cocotb_PE/test_PE_matrix.py new file mode 100644 index 00000000..220c0424 --- /dev/null +++ b/test/cocotb_PE/test_PE_matrix.py @@ -0,0 +1,42 @@ +from pathlib import Path + +import cocotb_test.simulator + +from open_eye import hdl_dir +import pe_test_utils as ptu + + +def test_matrix(): + + test_dir = Path(__file__).parent + + cocotb_test.simulator.run( + + verilog_sources=ptu.get_verilog_sources(str(hdl_dir)), + + toplevel="PE", + module="PE_matrix_tb", + + python_search=[str(test_dir)], + + parameters={ + "SPARSITY_EN": 0, + "USE_DSP": 0, + "PARALLEL_MACS": 1, + }, + + defines={ + "USE_INTERNAL_PARAMS_PE": "1", + }, + + simulator="icarus", + + sim_build=str(test_dir / ".temp" / "pe_matrix"), + + extra_env={ + "IVERILOG_DUMPER": "fst", + }, + + waves=True, + force_compile=True, + ) \ No newline at end of file From d36e955c3e36e46b73776ca43893c5e15113c30c Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Thu, 24 Sep 2026 14:13:38 +0200 Subject: [PATCH 03/36] Verify parallel PE computation for first input row For now, only the first input row is calculated. The PE performs the MAC operations in parallel with PARALLEL_MACS=2. --- test/cocotb_PE/PE_matrix_tb.py | 112 +++++++++++++++---------------- test/cocotb_PE/test_PE_matrix.py | 2 +- 2 files changed, 56 insertions(+), 58 deletions(-) diff --git a/test/cocotb_PE/PE_matrix_tb.py b/test/cocotb_PE/PE_matrix_tb.py index 56f36362..71b6d286 100644 --- a/test/cocotb_PE/PE_matrix_tb.py +++ b/test/cocotb_PE/PE_matrix_tb.py @@ -17,24 +17,24 @@ async def test_pe_matrix(dut): ] W = [ - [5, 6], - [7, 8] + [5, 6, 7,8], + [9,10,11,12] ] # Expected output matrix Y = [ - [0, 0], - [0, 0] + [0, 0 ,0, 0], + [0, 0, 0, 0] ] # Calculate the expected result for row in range(2): - for col in range(2): + for col in range(len(W[row])): for k in range(2): Y[row][col] += A[row][k] * W[k][col] - assert Y == [[19, 22], [43, 50]] + assert Y == [[23, 26, 29, 32], [51, 58, 65, 72]] dut._log.info(f"Expected matrix: {Y}") @@ -88,9 +88,9 @@ async def test_pe_matrix(dut): # --------------------------------- # One row has two activations. - # C0 = 1, B = 2, M0 = 2 + # C0 = 1, B = 2, M0 = 4 - for value in [2, 1, 2]: + for value in [2, 1, 4]: await FallingEdge(dut.clk_i) @@ -114,7 +114,7 @@ async def test_pe_matrix(dut): assert int(dut.iact_addr_max_reg.value) == 2 assert int(dut.channel_reg_C0.value) == 1 - assert int(dut.filters_reg_M0.value) == 2 + assert int(dut.filters_reg_M0.value) == 4 dut._log.info("PASS: Matrix definition, reset and configuration") @@ -159,54 +159,49 @@ async def test_pe_matrix(dut): dut._log.info("Activation row [1, 2] loaded") # --------------------------------- - # 10. send the weight + # 10. Send weights - PARALLEL_MACS = 2 # --------------------------------- - weights = [5, 6, 7, 8] - - for weight in weights: - - await FallingEdge(dut.clk_i) - - dut.wght_data_i.value = weight - dut.wght_enable_i.value = 1 - - await RisingEdge(dut.clk_i) - await Timer(1, unit="ns") + #activation 1: + #filter group 0 → [5, 6] + weight_word = (6 << 8) | 5 await FallingEdge(dut.clk_i) - - dut.wght_enable_i.value = 0 - dut.wght_data_i.value = 0 + dut.wght_data_i.value = weight_word + dut.wght_enable_i.value = 1 await RisingEdge(dut.clk_i) await Timer(1, unit="ns") - dut._log.info("Weight loading sequence completed") - - #--------------------------------- - ## Send the first weight row: [5, 7] - #weight_word = (W[0][1] << 8) | W[0][0] - - #await FallingEdge(dut.clk_i) - - #dut.wght_data_i.value = weight_word - #dut.wght_enable_i.value = 1 - - #await RisingEdge(dut.clk_i) - #await Timer(1, unit="ns") + #filter group 1 → [7, 8] + weight_word = (8 << 8) | 7 - ## Send the second weight row: [6, 8] - #await FallingEdge(dut.clk_i) + await FallingEdge(dut.clk_i) + dut.wght_data_i.value = weight_word - #weight_word = (W[1][1] << 8) | W[1][0] + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") - #dut.wght_data_i.value = weight_word + #activation 2: + #filter group 0 → [9, 10] + weight_word = (10 << 8) | 9 + + await FallingEdge(dut.clk_i) + dut.wght_data_i.value = weight_word + dut.wght_enable_i.value = 1 + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") - #await RisingEdge(dut.clk_i) - #await Timer(1, unit="ns") - #--------------------------------- + #filter group 1 → [11, 12] + weight_word = (12 << 8) | 11 + + await FallingEdge(dut.clk_i) + dut.wght_data_i.value = weight_word + dut.wght_enable_i.value = 1 + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") # --------------------------------- # 11. Allow the registered SPad writes to complete. # --------------------------------- @@ -269,28 +264,31 @@ async def test_pe_matrix(dut): await RisingEdge(dut.psum_ready_o) await Timer(10, unit="ns") - # M0 = 2 -> send two zero biases - for _ in range(2): + async def send_zero_biases (): # M0 = 4 -> send four zero biases + for _ in range(4): + + await FallingEdge(dut.clk_i) + + dut.psum_data_i.value = 0 + dut.psum_enable_i.value = 1 + + await RisingEdge(dut.clk_i) await FallingEdge(dut.clk_i) + dut.psum_enable_i.value = 0 dut.psum_data_i.value = 0 - dut.psum_enable_i.value = 1 - await RisingEdge(dut.clk_i) + # Start sending biases in parallel + bias_task = cocotb.start_soon(send_zero_biases()) - await FallingEdge(dut.clk_i) - - dut.psum_enable_i.value = 0 - dut.psum_data_i.value = 0 + await RisingEdge(dut.psum_enable_o) + await Timer(1, unit="ns") # --------------------------------- # 15. Read outputs # --------------------------------- - await RisingEdge(dut.psum_enable_o) - await Timer(10, unit="ns") - outputs = [] while int(dut.psum_enable_o.value) == 1: @@ -304,5 +302,5 @@ async def test_pe_matrix(dut): dut._log.info(f"Final outputs: {outputs}") - assert outputs == [19, 22], \ - f"Expected [19, 22], got {outputs}" \ No newline at end of file + assert outputs == [23, 26, 29, 32], \ + f"Expected [23, 26, 29, 32], got {outputs}" \ No newline at end of file diff --git a/test/cocotb_PE/test_PE_matrix.py b/test/cocotb_PE/test_PE_matrix.py index 220c0424..0731c367 100644 --- a/test/cocotb_PE/test_PE_matrix.py +++ b/test/cocotb_PE/test_PE_matrix.py @@ -22,7 +22,7 @@ def test_matrix(): parameters={ "SPARSITY_EN": 0, "USE_DSP": 0, - "PARALLEL_MACS": 1, + "PARALLEL_MACS": 2, }, defines={ From 6f49a57f77b3f5ab9732f0b2d414e834d3f8c57c Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Thu, 24 Sep 2026 18:50:31 +0200 Subject: [PATCH 04/36] Add Description --- test/cocotb_PE/PE_matrix_tb.py | 73 +++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/test/cocotb_PE/PE_matrix_tb.py b/test/cocotb_PE/PE_matrix_tb.py index 71b6d286..aa44ca0d 100644 --- a/test/cocotb_PE/PE_matrix_tb.py +++ b/test/cocotb_PE/PE_matrix_tb.py @@ -1,3 +1,51 @@ +""" +PE Matrix Multiplication Testbench + +Purpose: +This testbench verifies the standalone Processing Element (PE) in dense mode +with PARALLEL_MACS = 2. + +The goal is to confirm that one PE can correctly process one input row of a +matrix and calculate multiple output values using two MAC lanes in parallel. + +Test setup: + Input row: + A_row = [1, 2] + + Weight matrix: + W = [ + [5, 6, 7, 8], + [9, 10, 11, 12] + ] + + Expected output: + A_row x W = [23, 26, 29, 32] + +The activation values are loaded into the PE input activation SPad and the +weights are packed in pairs because PARALLEL_MACS = 2. Therefore, two weights +are processed simultaneously by the two MAC lanes. + +The PE performs the following dot products: + + 1*5 + 2*9 = 23 + 1*6 + 2*10 = 26 + 1*7 + 2*11 = 29 + 1*8 + 2*12 = 32 + +The testbench performs the following steps: + 1. Reset and configure the PE. + 2. Load the first input row [1, 2] into the activation SPad. + 3. Load the corresponding weight matrix into the weight SPad. + 4. Start the PE computation. + 5. Supply zero initial partial sums (biases). + 6. Read the resulting partial sums from the PE output. + 7. Compare the hardware outputs against the expected result. + +This test currently verifies only one input row on a standalone PE. +Calculation of multiple matrix rows in parallel is not covered by this test +and is intended to be handled later using multiple PEs / the PE cluster. +""" + import cocotb from cocotb.clock import Clock @@ -303,4 +351,27 @@ async def send_zero_biases (): # M0 = 4 -> send four zero biases dut._log.info(f"Final outputs: {outputs}") assert outputs == [23, 26, 29, 32], \ - f"Expected [23, 26, 29, 32], got {outputs}" \ No newline at end of file + f"Expected [23, 26, 29, 32], got {outputs}" + + + # --------------------------------- + # 16. Send second row of Input activations + # --------------------------------- + + await Timer(10, unit="ns") + await RisingEdge(dut.clk_i) + + dut.iact_data_i.value = (4 << 8) | 3 + + # Enable activation lane 0 + dut.iact_enable_i.value = 1 + + # ... load activation + # ... compute again + # ... read psum again + # ... load and read Outputs + #. + #. + #. + + \ No newline at end of file From be51295fcec142f0f490f91a534fa953f8f02a54 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sun, 27 Sep 2026 18:17:46 +0200 Subject: [PATCH 05/36] Fix PE cluster waveform generation --- test/cocotb_PE_cluster/cluster_simulator.py | 5 ++++- test/cocotb_PE_cluster/test_PE_CLUSTER_GEMM.py | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/test/cocotb_PE_cluster/cluster_simulator.py b/test/cocotb_PE_cluster/cluster_simulator.py index a3902310..cba3c9ef 100644 --- a/test/cocotb_PE_cluster/cluster_simulator.py +++ b/test/cocotb_PE_cluster/cluster_simulator.py @@ -23,7 +23,10 @@ def run_cluster_simulation(**kwargs): kwargs["parameters"] = {**parameters, **config} env.update({name: str(value) for name, value in config.items()}) kwargs["extra_env"] = env - waves = os.environ.get("OPENEYE_CLUSTER_WAVES") == "1" + waves = ( + bool(kwargs.get("waves", False)) + or os.environ.get("OPENEYE_CLUSTER_WAVES", "").strip() == "1" + ) kwargs["waves"] = waves kwargs["force_compile"] = False diff --git a/test/cocotb_PE_cluster/test_PE_CLUSTER_GEMM.py b/test/cocotb_PE_cluster/test_PE_CLUSTER_GEMM.py index bb414a83..2ab13576 100644 --- a/test/cocotb_PE_cluster/test_PE_CLUSTER_GEMM.py +++ b/test/cocotb_PE_cluster/test_PE_CLUSTER_GEMM.py @@ -104,6 +104,7 @@ def test_pe_cluster_gemm_approach1(IACTSIZE_X, IACTSIZE_Y, WGHTSIZE_X, SEED, PE_ sim_build=target_dir, testcase="start_test_gemm_approach1", defines=_pe_defines(PE_MODULE), + waves=True, simulator="icarus", extra_env={ **_common_env, @@ -140,6 +141,7 @@ def test_pe_cluster_gemm_approach2(IACTSIZE_X, IACTSIZE_Y, WGHTSIZE_X, SEED, PE_ sim_build=target_dir, testcase="start_test_gemm_approach2", defines=_pe_defines(PE_MODULE), + waves=True, simulator="icarus", extra_env={ **_common_env, @@ -182,6 +184,7 @@ def test_pe_cluster_gemm_approach3(IACTSIZE_X, IACTSIZE_Y, WGHTSIZE_X, SEED, PE_ testcase="start_test_gemm_approach3", parameters={"SYSTOLIC_GEMM_EN": 1, "PARALLEL_MACS": 1}, defines=_pe_defines(PE_MODULE), + waves=True, simulator="icarus", extra_env={ **_common_env, From 3026e3a3a309a359ef526bee676e36981a174035 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sat, 17 Oct 2026 15:07:45 +0200 Subject: [PATCH 06/36] feat(attention): implement and verify GEMV controller FSM --- hdl/attention_qkt_ctrl.v | 127 ++++++++++++++++++ .../attention_qkt_ctrl_tb.py | 73 ++++++++++ .../test_attention_qkt_ctrl.py | 20 +++ 3 files changed, 220 insertions(+) create mode 100644 hdl/attention_qkt_ctrl.v create mode 100644 test/cocotb_attention_qkt/attention_qkt_ctrl_tb.py create mode 100644 test/cocotb_attention_qkt/test_attention_qkt_ctrl.py diff --git a/hdl/attention_qkt_ctrl.v b/hdl/attention_qkt_ctrl.v new file mode 100644 index 00000000..9ac1719c --- /dev/null +++ b/hdl/attention_qkt_ctrl.v @@ -0,0 +1,127 @@ +//============================================================================== +// Module: attention_qkt_ctrl +// Project: OpenEye - Single-Head Attention Accelerator +//============================================================================== +// Description: +// Main finite state machine (FSM) for controlling the execution of +// single-head self-attention operations using the existing OpenEye +// hardware accelerator. +// +// The controller is responsible for sequencing the following operations: +// 1. Query projection: Q = X * W_Q +// 2. Key projection: K = X * W_K +// 3. Value projection: V = X * W_V +// 4. Attention scores: S = Q * K^T +// +// Matrix operations are executed by the existing OpenEye processing +// elements (PEs). This module does not implement arithmetic units. +// +// A separate DMA adapter handles the configuration and data transfer +// between this controller and the OpenEye_FPGA module. +// +// Intermediate tensor storage and requantization are coordinated by +// this controller through dedicated hardware modules. +// +// Scope: +// - Single-head attention only. +// - Fully synthesizable RTL implementation. +// - No runtime Python or processor-based orchestration. +// - Softmax and subsequent attention operations are excluded. +// - Architecture intended to allow future multi-head extensions. +// +// Development Status: +// Initial version: Single GEMV execution controller. +// Future versions: Complete Q, K, V and QK^T operation sequencing. +// +//============================================================================== + +`timescale 1ns / 1ps + +module attention_qkt_ctrl ( + input wire clk_i, + input wire rst_ni, + + input wire start_i, + input wire gemv_done_i, + + output reg gemv_start_o, + output reg busy_o, + output reg done_o +); + + + +//========================================================================== +// FSM State Definitions +//========================================================================== + + localparam [1:0] IDLE = 2'd0; + localparam [1:0] START_GEMV = 2'd1; + localparam [1:0] WAIT_GEMV = 2'd2; + localparam [1:0] DONE = 2'd3; + + reg [1:0] state_reg; + +//========================================================================== +// Main FSM +//========================================================================== + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state_reg <= IDLE; + gemv_start_o <= 1'b0; + busy_o <= 1'b0; + done_o <= 1'b0; + end + else begin + + // Default pulse outputs + gemv_start_o <= 1'b0; + done_o <= 1'b0; + + case (state_reg) + + IDLE: begin + busy_o <= 1'b0; + + if (start_i) begin + busy_o <= 1'b1; + state_reg <= START_GEMV; + end + end + + START_GEMV: begin + gemv_start_o <= 1'b1; // Trigger GEMV operation + busy_o <= 1'b1; + state_reg <= WAIT_GEMV; + end + + WAIT_GEMV: begin + busy_o <= 1'b1; + + if (gemv_done_i) begin + state_reg <= DONE; + end + end + + DONE: begin + + done_o <= 1'b1; + busy_o <= 1'b0; + state_reg <= IDLE; + + end + + default: begin + state_reg <= IDLE; // Default case to handle unexpected states + gemv_start_o <= 1'b0; + busy_o <= 1'b0; + done_o <= 1'b0; + end + + + endcase + end + end + +endmodule \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_qkt_ctrl_tb.py b/test/cocotb_attention_qkt/attention_qkt_ctrl_tb.py new file mode 100644 index 00000000..6db215f4 --- /dev/null +++ b/test/cocotb_attention_qkt/attention_qkt_ctrl_tb.py @@ -0,0 +1,73 @@ +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, Timer + + +async def tick(dut): + """Wait for one rising clock edge and updated RTL outputs.""" + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + +@cocotb.test() +async def test_controller(dut): + + dut.clk_i.value = 0 + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.gemv_done_i.value = 0 + + cocotb.start_soon(Clock(dut.clk_i, 10, unit="ns").start()) + + # Test 1: Reset + await tick(dut) + assert int(dut.busy_o.value) == 0 + assert int(dut.done_o.value) == 0 + assert int(dut.gemv_start_o.value) == 0 + + dut.rst_ni.value = 1 + + # Test 2: Start a GEMV operation + dut.start_i.value = 1 + await tick(dut) + + assert int(dut.busy_o.value) == 1 + + dut.start_i.value = 0 + await tick(dut) + + assert int(dut.gemv_start_o.value) == 1 + + # Test 3: Wait for GEMV completion + await tick(dut) + assert int(dut.gemv_start_o.value) == 0 + assert int(dut.busy_o.value) == 1 + + for _ in range(3): + await tick(dut) + assert int(dut.done_o.value) == 0 + + # Test 4: Simulate GEMV completion + dut.gemv_done_i.value = 1 + await tick(dut) + dut.gemv_done_i.value = 0 + + await tick(dut) + + assert int(dut.done_o.value) == 1 + assert int(dut.busy_o.value) == 0 + + # Test 5: Completion pulse must end + await tick(dut) + assert int(dut.done_o.value) == 0 + + # Test 6: Controller accepts another operation + dut.start_i.value = 1 + await tick(dut) + + dut.start_i.value = 0 + await tick(dut) + + assert int(dut.gemv_start_o.value) == 1 + + dut._log.info("Attention QKT controller FSM test PASSED") \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_qkt_ctrl.py b/test/cocotb_attention_qkt/test_attention_qkt_ctrl.py new file mode 100644 index 00000000..f68f944a --- /dev/null +++ b/test/cocotb_attention_qkt/test_attention_qkt_ctrl.py @@ -0,0 +1,20 @@ +from pathlib import Path +import cocotb_test.simulator + + +def test_attention_qkt_ctrl(): + + root = Path(__file__).resolve().parents[2] + test_dir = Path(__file__).resolve().parent + + cocotb_test.simulator.run( + verilog_sources=[ + str(root / "hdl" / "attention_qkt_ctrl.v") + ], + toplevel="attention_qkt_ctrl", + module="attention_qkt_ctrl_tb", + python_search=[str(test_dir)], + sim_build=str(test_dir / ".sim_build"), + simulator="icarus", + force_compile=True, + ) \ No newline at end of file From 747c4ed0b36722853e83a6c3d70ba6c04e074aca Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sat, 17 Oct 2026 18:09:59 +0200 Subject: [PATCH 07/36] feat(attention): add and unit-test basic DMA stream adapter --- hdl/attention_dma_adapter.v | 171 ++++++++++++++++++ .../attention_dma_adapter_tb.py | 116 ++++++++++++ .../test_attention_dma_adapter.py | 21 +++ 3 files changed, 308 insertions(+) create mode 100644 hdl/attention_dma_adapter.v create mode 100644 test/cocotb_attention_qkt/attention_dma_adapter_tb.py create mode 100644 test/cocotb_attention_qkt/test_attention_dma_adapter.py diff --git a/hdl/attention_dma_adapter.v b/hdl/attention_dma_adapter.v new file mode 100644 index 00000000..863b77dd --- /dev/null +++ b/hdl/attention_dma_adapter.v @@ -0,0 +1,171 @@ +`timescale 1ns / 1ps + +//============================================================================== +// Module: attention_dma_adapter +// Project: OpenEye - Single-Head Attention Accelerator +//============================================================================== +// Description: +// Handles one GEMV transaction through the OpenEye_FPGA DMA interface. +// +// This initial version: +// - Reads preformatted 64-bit words from an external word source. +// - Streams the words to OpenEye. +// - Captures result words and their addresses. +// - Reports completion after the final output word. +// +// DMA packet generation and tensor storage are implemented separately. +// Input streaming initially follows OpenEye's existing continuous-stream +// testbench protocol. Per-word backpressure requires integration testing. +//============================================================================== + +// DMA Adapter <--> OpenEye_FPGA Connections: +// +// Adapter Output OpenEye Input +// --------------------------------------------------------------- +// dma_data_o -----------> data_dma_i +// dma_valid_o -----------> enable_dma_i +// dma_result_ready_o -----------> ready_dma_i +// +// Adapter Input OpenEye Output +// --------------------------------------------------------------- +// dma_ready_i <----------- ready_dma_o +// dma_result_data_i <----------- data_dma_o +// dma_result_valid_i <----------- enable_dma_o +// dma_result_last_i <----------- last_data_o +// +// Data Flow: +// 1. Adapter -> OpenEye: +// Sends configuration, input activations, weights, and other +// required data through the DMA input interface. +// +// 2. OpenEye -> Adapter: +// Returns computed partial sums (PSUMs) through the DMA +// output interface. + +module attention_dma_adapter #( + parameter integer DMA_WIDTH = 64, + parameter integer ADDR_WIDTH = 16 +)( + input wire clk_i, + input wire rst_ni, + + // Main Attention controller + input wire gemv_start_i, + output reg gemv_done_o, + output wire busy_o, + + // Input word source (future packet generator / buffer) + input wire [ADDR_WIDTH-1:0] stream_word_count_i, + output wire [ADDR_WIDTH-1:0] stream_addr_o, + input wire [DMA_WIDTH-1:0] stream_data_i, + + // DMA input interface of OpenEye_FPGA + input wire dma_ready_i, + output wire [DMA_WIDTH-1:0] dma_data_o, + output wire dma_valid_o, + + // DMA output interface of OpenEye_FPGA + input wire [DMA_WIDTH-1:0] dma_result_data_i, + input wire dma_result_valid_i, + input wire dma_result_last_i, + output wire dma_result_ready_o, + + // Interface to future result buffer + output wire result_write_o, + output wire [DMA_WIDTH-1:0] result_data_o, + output wire [ADDR_WIDTH-1:0] result_addr_o +); + + //========================================================================== + // FSM States + //========================================================================== + + localparam [1:0] IDLE = 2'd0; + localparam [1:0] WAIT_READY = 2'd1; + localparam [1:0] SEND_STREAM = 2'd2; + localparam [1:0] WAIT_RESULT = 2'd3; + + reg [1:0] state_reg; + + reg [ADDR_WIDTH-1:0] stream_addr_reg; + reg [ADDR_WIDTH-1:0] stream_count_reg; + reg [ADDR_WIDTH-1:0] result_addr_reg; + + //========================================================================== + // Combinational Output Logic + //========================================================================== + + assign busy_o = (state_reg != IDLE); + + assign stream_addr_o = stream_addr_reg; + + assign dma_data_o = stream_data_i; + assign dma_valid_o = (state_reg == SEND_STREAM); + + assign dma_result_ready_o = (state_reg == WAIT_RESULT); + + assign result_write_o = dma_result_valid_i && dma_result_ready_o; + assign result_data_o = dma_result_data_i; + assign result_addr_o = result_addr_reg; + + //========================================================================== + // Main FSM + //========================================================================== + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state_reg <= IDLE; + stream_addr_reg <= 0; + stream_count_reg <= 0; + result_addr_reg <= 0; + gemv_done_o <= 1'b0; + end + else begin + gemv_done_o <= 1'b0; + + case (state_reg) + + IDLE: begin + if (gemv_start_i && stream_word_count_i != 0) begin + stream_count_reg <= stream_word_count_i; + stream_addr_reg <= 0; + result_addr_reg <= 0; + state_reg <= WAIT_READY; + end + end + + WAIT_READY: begin + if (dma_ready_i) begin + state_reg <= SEND_STREAM; + end + end + + SEND_STREAM: begin + if (stream_addr_reg == stream_count_reg - 1'b1) begin + state_reg <= WAIT_RESULT; + end + else begin + stream_addr_reg <= stream_addr_reg + 1'b1; + end + end + + WAIT_RESULT: begin + if (result_write_o) begin + result_addr_reg <= result_addr_reg + 1'b1; + + if (dma_result_last_i) begin + gemv_done_o <= 1'b1; + state_reg <= IDLE; + end + end + end + + default: begin + state_reg <= IDLE; + end + + endcase + end + end + +endmodule \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_dma_adapter_tb.py b/test/cocotb_attention_qkt/attention_dma_adapter_tb.py new file mode 100644 index 00000000..0f343575 --- /dev/null +++ b/test/cocotb_attention_qkt/attention_dma_adapter_tb.py @@ -0,0 +1,116 @@ +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, Timer + + +async def tick(dut): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + +@cocotb.test() +async def test_dma_adapter(dut): + + # -------------------------------------------------- + # 1. Initialize inputs and reset + # -------------------------------------------------- + + dut.clk_i.value = 0 + dut.rst_ni.value = 0 + + dut.gemv_start_i.value = 0 + dut.stream_word_count_i.value = 3 + dut.stream_data_i.value = 0 + + dut.dma_ready_i.value = 0 + + dut.dma_result_data_i.value = 0 + dut.dma_result_valid_i.value = 0 + dut.dma_result_last_i.value = 0 + + cocotb.start_soon(Clock(dut.clk_i, 10, unit="ns").start()) + + await tick(dut) + dut.rst_ni.value = 1 + + # -------------------------------------------------- + # 2. Request one GEMV transaction + # -------------------------------------------------- + + dut.gemv_start_i.value = 1 + await tick(dut) + dut.gemv_start_i.value = 0 + + assert int(dut.busy_o.value) == 1 + + # Adapter must wait while OpenEye is not ready + for _ in range(2): + await tick(dut) + assert int(dut.dma_valid_o.value) == 0 + + # Simulate OpenEye becoming ready + dut.dma_ready_i.value = 1 + await tick(dut) + + # -------------------------------------------------- + # 3. Send three DMA words + # -------------------------------------------------- + + input_words = [0x11, 0x22, 0x33] + + for address, word in enumerate(input_words): + + # Simulate a memory returning the requested word + dut.stream_data_i.value = word + await Timer(1, unit="ns") + + assert int(dut.stream_addr_o.value) == address + assert int(dut.dma_valid_o.value) == 1 + assert int(dut.dma_data_o.value) == word + + await tick(dut) + + # All input words have now been sent + assert int(dut.dma_valid_o.value) == 0 + assert int(dut.dma_result_ready_o.value) == 1 + + # -------------------------------------------------- + # 4. Simulate two output words from OpenEye + # -------------------------------------------------- + + results = {} + + for address, word in enumerate([0xAA, 0xBB]): + + dut.dma_result_data_i.value = word + dut.dma_result_valid_i.value = 1 + dut.dma_result_last_i.value = int(address == 1) + + await Timer(1, unit="ns") + + assert int(dut.result_write_o.value) == 1 + assert int(dut.result_addr_o.value) == address + assert int(dut.result_data_o.value) == word + + # Simulate a result memory accepting the word + results[address] = int(dut.result_data_o.value) + + await tick(dut) + + dut.dma_result_valid_i.value = 0 + dut.dma_result_last_i.value = 0 + + # -------------------------------------------------- + # 5. Verify stored values and completion + # -------------------------------------------------- + + assert results == {0: 0xAA, 1: 0xBB} + + assert int(dut.gemv_done_o.value) == 1 + assert int(dut.busy_o.value) == 0 + + await tick(dut) + + assert int(dut.gemv_done_o.value) == 0 + + dut._log.info("DMA adapter unit test PASSED") \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_dma_adapter.py b/test/cocotb_attention_qkt/test_attention_dma_adapter.py new file mode 100644 index 00000000..3f552e1b --- /dev/null +++ b/test/cocotb_attention_qkt/test_attention_dma_adapter.py @@ -0,0 +1,21 @@ +from pathlib import Path +import cocotb_test.simulator + + +def test_attention_dma_adapter(): + + root = Path(__file__).resolve().parents[2] + test_dir = Path(__file__).resolve().parent + + cocotb_test.simulator.run( + verilog_sources=[ + str(root / "hdl" / "attention_dma_adapter.v") + ], + toplevel="attention_dma_adapter", + module="attention_dma_adapter_tb", + python_search=[str(test_dir)], + sim_build=str(test_dir / ".sim_build_dma"), + simulator="icarus", + force_compile=True, + waves=True, + ) \ No newline at end of file From 445463a2c82cd9b4bb6535691c5f2cbf5592b6dd Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sat, 17 Oct 2026 18:10:47 +0200 Subject: [PATCH 08/36] Update gitignore for simulation files --- test/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/test/.gitignore b/test/.gitignore index 0866e7e3..c98e7b2f 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -5,3 +5,4 @@ */simulation/* *.fst *.fst.hier +.sim_build_dma/ \ No newline at end of file From 0d4f23779bb960cb62d02929e9660663855796b2 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sun, 18 Oct 2026 11:35:34 +0200 Subject: [PATCH 09/36] test(attention): verify controller and DMA adapter integration --- hdl/attention_gemv_control_top.v | 103 ++++++++++++ .../attention_gemv_control_top_tb.py | 156 ++++++++++++++++++ .../test_attention_gemv_control_top.py | 26 +++ 3 files changed, 285 insertions(+) create mode 100644 hdl/attention_gemv_control_top.v create mode 100644 test/cocotb_attention_qkt/attention_gemv_control_top_tb.py create mode 100644 test/cocotb_attention_qkt/test_attention_gemv_control_top.py diff --git a/hdl/attention_gemv_control_top.v b/hdl/attention_gemv_control_top.v new file mode 100644 index 00000000..c8ad483d --- /dev/null +++ b/hdl/attention_gemv_control_top.v @@ -0,0 +1,103 @@ +`timescale 1ns / 1ps + +//============================================================================== +// Module: attention_gemv_control_top +// Project: OpenEye - Single-Head Attention Accelerator +//============================================================================== +// Description: +// Integrates the Attention GEMV controller and DMA adapter. +// +// The controller manages execution requests, while the DMA adapter +// handles the transfer of input and output data. +// +// This module is intended for integration testing before connecting +// the actual OpenEye_FPGA accelerator. +//============================================================================== + +module attention_gemv_control_top #( + parameter integer DMA_WIDTH = 64, + parameter integer ADDR_WIDTH = 16 +)( + input wire clk_i, + input wire rst_ni, + + // External operation control + input wire start_i, + output wire busy_o, + output wire done_o, + output wire adapter_busy_o, + + // Input stream source + input wire [ADDR_WIDTH-1:0] stream_word_count_i, + output wire [ADDR_WIDTH-1:0] stream_addr_o, + input wire [DMA_WIDTH-1:0] stream_data_i, + + // DMA input connection + input wire dma_ready_i, + output wire [DMA_WIDTH-1:0] dma_data_o, + output wire dma_valid_o, + + // DMA result connection + input wire [DMA_WIDTH-1:0] dma_result_data_i, + input wire dma_result_valid_i, + input wire dma_result_last_i, + output wire dma_result_ready_o, + + // Result storage interface + output wire result_write_o, + output wire [DMA_WIDTH-1:0] result_data_o, + output wire [ADDR_WIDTH-1:0] result_addr_o +); + + // Internal connections between the two modules + wire gemv_start_wire; + wire gemv_done_wire; + + //========================================================================== + // Attention Controller Instance + //========================================================================== + + attention_qkt_ctrl u_attention_ctrl ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .start_i (start_i), + .gemv_done_i (gemv_done_wire), + .gemv_start_o (gemv_start_wire), + .busy_o (busy_o), + .done_o (done_o) + ); + + //========================================================================== + // DMA Adapter Instance + //========================================================================== + + attention_dma_adapter #( + .DMA_WIDTH (DMA_WIDTH), + .ADDR_WIDTH (ADDR_WIDTH) + ) u_dma_adapter ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + .gemv_start_i (gemv_start_wire), + .gemv_done_o (gemv_done_wire), + .busy_o (adapter_busy_o), + + .stream_word_count_i (stream_word_count_i), + .stream_addr_o (stream_addr_o), + .stream_data_i (stream_data_i), + + .dma_ready_i (dma_ready_i), + .dma_data_o (dma_data_o), + .dma_valid_o (dma_valid_o), + + .dma_result_data_i (dma_result_data_i), + .dma_result_valid_i (dma_result_valid_i), + .dma_result_last_i (dma_result_last_i), + .dma_result_ready_o (dma_result_ready_o), + + .result_write_o (result_write_o), + .result_data_o (result_data_o), + .result_addr_o (result_addr_o) + ); + +endmodule \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_gemv_control_top_tb.py b/test/cocotb_attention_qkt/attention_gemv_control_top_tb.py new file mode 100644 index 00000000..9b33a8c2 --- /dev/null +++ b/test/cocotb_attention_qkt/attention_gemv_control_top_tb.py @@ -0,0 +1,156 @@ +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, Timer + + +async def tick(dut): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + +@cocotb.test() +async def test_gemv_integration(dut): + + # ================================================== + # 1. Initialize signals + # ================================================== + + dut.clk_i.value = 0 + dut.rst_ni.value = 0 + + dut.start_i.value = 0 + + dut.stream_word_count_i.value = 3 + dut.stream_data_i.value = 0 + + dut.dma_ready_i.value = 0 + + dut.dma_result_data_i.value = 0 + dut.dma_result_valid_i.value = 0 + dut.dma_result_last_i.value = 0 + + cocotb.start_soon( + Clock(dut.clk_i, 10, unit="ns").start() + ) + + await tick(dut) + + # Release reset + dut.rst_ni.value = 1 + await tick(dut) + + assert int(dut.busy_o.value) == 0 + assert int(dut.adapter_busy_o.value) == 0 + + # ================================================== + # 2. Start the main controller + # ================================================== + + dut.start_i.value = 1 + await tick(dut) + dut.start_i.value = 0 + + assert int(dut.busy_o.value) == 1 + + # Controller generates GEMV start pulse + await tick(dut) + + # Adapter receives the pulse on the next edge + await tick(dut) + + assert int(dut.adapter_busy_o.value) == 1 + + # ================================================== + # 3. Test WAIT_READY + # ================================================== + + # OpenEye is not ready yet + for _ in range(3): + await tick(dut) + + assert int(dut.dma_valid_o.value) == 0 + assert int(dut.adapter_busy_o.value) == 1 + + # Simulate OpenEye becoming ready + dut.dma_ready_i.value = 1 + await tick(dut) + + # ================================================== + # 4. Test DMA input transmission + # ================================================== + + input_words = [0x11, 0x22, 0x33] + + for address, word in enumerate(input_words): + + # Simulated combinational word source + dut.stream_data_i.value = word + await Timer(1, unit="ns") + + assert int(dut.stream_addr_o.value) == address + assert int(dut.dma_valid_o.value) == 1 + assert int(dut.dma_data_o.value) == word + + await tick(dut) + + assert int(dut.dma_valid_o.value) == 0 + assert int(dut.dma_result_ready_o.value) == 1 + + # Main controller must still be waiting + assert int(dut.busy_o.value) == 1 + + # ================================================== + # 5. Simulate results from OpenEye + # ================================================== + + received = {} + + for address, word in enumerate([0xAA, 0xBB]): + + dut.dma_result_data_i.value = word + dut.dma_result_valid_i.value = 1 + dut.dma_result_last_i.value = int(address == 1) + + await Timer(1, unit="ns") + + assert int(dut.result_write_o.value) == 1 + assert int(dut.result_addr_o.value) == address + assert int(dut.result_data_o.value) == word + + received[address] = int(dut.result_data_o.value) + + await tick(dut) + + dut.dma_result_valid_i.value = 0 + dut.dma_result_last_i.value = 0 + + assert received == {0: 0xAA, 1: 0xBB} + + # Adapter has completed, but the main controller + # has not yet processed the completion signal. + assert int(dut.adapter_busy_o.value) == 0 + assert int(dut.busy_o.value) == 1 + assert int(dut.done_o.value) == 0 + + # ================================================== + # 6. Verify main controller completion + # ================================================== + + # Main controller detects the adapter's done pulse + await tick(dut) + + assert int(dut.done_o.value) == 0 + + # Main controller executes its DONE state + await tick(dut) + + assert int(dut.done_o.value) == 1 + assert int(dut.busy_o.value) == 0 + assert int(dut.adapter_busy_o.value) == 0 + + # Completion must last exactly one clock + await tick(dut) + + assert int(dut.done_o.value) == 0 + + dut._log.info("GEMV controller + DMA adapter integration PASSED") \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_gemv_control_top.py b/test/cocotb_attention_qkt/test_attention_gemv_control_top.py new file mode 100644 index 00000000..85bb8cb7 --- /dev/null +++ b/test/cocotb_attention_qkt/test_attention_gemv_control_top.py @@ -0,0 +1,26 @@ +from pathlib import Path +import cocotb_test.simulator + + +def test_attention_gemv_control_top(): + + root = Path(__file__).resolve().parents[2] + test_dir = Path(__file__).resolve().parent + + cocotb_test.simulator.run( + verilog_sources=[ + str(root / "hdl" / "attention_qkt_ctrl.v"), + str(root / "hdl" / "attention_dma_adapter.v"), + str(root / "hdl" / "attention_gemv_control_top.v"), + ], + + toplevel="attention_gemv_control_top", + module="attention_gemv_control_top_tb", + + python_search=[str(test_dir)], + sim_build=str(test_dir / ".sim_build"), + + simulator="icarus", + force_compile=True, + waves=True, + ) From 781dafce2d809c89b2763724b014c3c3cc90a85a Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sun, 18 Oct 2026 15:35:23 +0200 Subject: [PATCH 10/36] Fix the extra comma problem in generator.py --- src/open_eye/generator.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/open_eye/generator.py b/src/open_eye/generator.py index f0eb888e..57d5f73a 100644 --- a/src/open_eye/generator.py +++ b/src/open_eye/generator.py @@ -264,10 +264,16 @@ def create_regmap_params_vh_file(regmap_yaml_path, output_vh_path=None, output_v dv.write(f" input wire [DMA_BITWIDTH-1:0] dma_data_i, // Packed 64-bit data\n") # Output ports changed to WIRE! + # Generate output ports without a trailing comma + output_ports = [] + for regs in transmissions: for reg in regs: - dv.write(f" output wire [{reg['width']-1}:0] {reg['name']},\n") - dv.seek(dv.tell()-2) # Last comma removal + output_ports.append( + f" output wire [{reg['width']-1}:0] {reg['name']}" + ) + + dv.write(",\n".join(output_ports)) dv.write("\n);\n\n") # Internal Pipeline Register Chain From 33e527717c9f6804d942cefb83f7720cbf6912ff Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sun, 18 Oct 2026 15:46:57 +0200 Subject: [PATCH 11/36] test(attention): add and verify GEMV reference ROM --- hdl/attention_gemv_rom.v | 26 + .../attention_gemv_rom_tb.py | 43 + .../data/gemv_reference.mem | 939 ++++++++++++++++++ .../test_attention_gemv_rom.py | 34 + 4 files changed, 1042 insertions(+) create mode 100644 hdl/attention_gemv_rom.v create mode 100644 test/cocotb_attention_qkt/attention_gemv_rom_tb.py create mode 100644 test/cocotb_attention_qkt/data/gemv_reference.mem create mode 100644 test/cocotb_attention_qkt/test_attention_gemv_rom.py diff --git a/hdl/attention_gemv_rom.v b/hdl/attention_gemv_rom.v new file mode 100644 index 00000000..f01241e5 --- /dev/null +++ b/hdl/attention_gemv_rom.v @@ -0,0 +1,26 @@ +`timescale 1ns / 1ps + +module attention_gemv_rom #( + parameter integer DMA_WIDTH = 64, + parameter integer ADDR_WIDTH = 16, + parameter integer ROM_DEPTH = 939, + parameter MEM_FILE = "gemv_reference.mem" +)( + input wire [ADDR_WIDTH-1:0] addr_i, + output wire [DMA_WIDTH-1:0] data_o +); + + // Memory containing the reference GEMV DMA stream + reg [DMA_WIDTH-1:0] rom [0:ROM_DEPTH-1]; + + // Initialize ROM from the hexadecimal memory file + initial begin + $readmemh(MEM_FILE, rom); + end + + // Return the requested word + assign data_o = (addr_i < ROM_DEPTH) + ? rom[addr_i] + : {DMA_WIDTH{1'b0}}; + +endmodule \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_gemv_rom_tb.py b/test/cocotb_attention_qkt/attention_gemv_rom_tb.py new file mode 100644 index 00000000..a30988ae --- /dev/null +++ b/test/cocotb_attention_qkt/attention_gemv_rom_tb.py @@ -0,0 +1,43 @@ +from pathlib import Path + +import cocotb +from cocotb.triggers import Timer + + +@cocotb.test() +async def test_gemv_rom(dut): + + # Read the original reference file + test_dir = Path(__file__).resolve().parent + mem_file = test_dir / "data" / "gemv_reference.mem" + + words = [ + int(line.strip(), 16) + for line in mem_file.read_text().splitlines() + if line.strip() + ] + + assert len(words) == 939 + + # Verify every ROM address + for address, expected_word in enumerate(words): + + dut.addr_i.value = address + + await Timer(1, unit="ns") + + actual_word = int(dut.data_o.value) + + assert actual_word == expected_word, ( + f"ROM mismatch at address {address}: " + f"expected {expected_word:016X}, " + f"got {actual_word:016X}" + ) + + # Verify an out-of-range address returns zero + dut.addr_i.value = len(words) + await Timer(1, unit="ns") + + assert int(dut.data_o.value) == 0 + + dut._log.info("ROM verification PASSED: 939 words checked") \ No newline at end of file diff --git a/test/cocotb_attention_qkt/data/gemv_reference.mem b/test/cocotb_attention_qkt/data/gemv_reference.mem new file mode 100644 index 00000000..4e93e8af --- /dev/null +++ b/test/cocotb_attention_qkt/data/gemv_reference.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +c2c9c5e7e201112c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +103000e0e002e0cb +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +c00a0f10210050c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +302c03f0fa0e60ca +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +70f003d0270f60fd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +e0f60170f00c30f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +101c0130390cf0c0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +70c901802b0150c1 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +d0040f101a012003 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000009016 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e90e0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000c01c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000eb000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f2021 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000310ea +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000dd0e1 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f01b +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/test_attention_gemv_rom.py b/test/cocotb_attention_qkt/test_attention_gemv_rom.py new file mode 100644 index 00000000..d13a9758 --- /dev/null +++ b/test/cocotb_attention_qkt/test_attention_gemv_rom.py @@ -0,0 +1,34 @@ +from pathlib import Path +import shutil + +import cocotb_test.simulator + + +def test_attention_gemv_rom(): + + root = Path(__file__).resolve().parents[2] + test_dir = Path(__file__).resolve().parent + + build_dir = test_dir / ".sim_build" + build_dir.mkdir(parents=True, exist_ok=True) + + # Copy memory initialization file into simulation directory + shutil.copyfile( + test_dir / "data" / "gemv_reference.mem", + build_dir / "gemv_reference.mem" + ) + + cocotb_test.simulator.run( + verilog_sources=[ + str(root / "hdl" / "attention_gemv_rom.v") + ], + + toplevel="attention_gemv_rom", + module="attention_gemv_rom_tb", + + python_search=[str(test_dir)], + sim_build=str(build_dir), + + simulator="icarus", + force_compile=True + ) \ No newline at end of file From 21a09c072cacdcfde8f99f268969b7c5f7e34132 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Mon, 19 Oct 2026 16:42:41 +0200 Subject: [PATCH 12/36] feat(attention): integrate and verify ROM-based GEMV execution on OpenEye --- hdl/attention_gemv_openeye_top.v | 105 ++++++++++++ hdl/attention_gemv_rom_top.v | 82 ++++++++++ .../attention_gemv_openeye_top_tb.py | 149 ++++++++++++++++++ .../attention_gemv_rom_top_tb.py | 95 +++++++++++ .../test_attention_gemv_openeye_top.py | 80 ++++++++++ .../test_attention_gemv_rom_top.py | 37 +++++ 6 files changed, 548 insertions(+) create mode 100644 hdl/attention_gemv_openeye_top.v create mode 100644 hdl/attention_gemv_rom_top.v create mode 100644 test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py create mode 100644 test/cocotb_attention_qkt/attention_gemv_rom_top_tb.py create mode 100644 test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py create mode 100644 test/cocotb_attention_qkt/test_attention_gemv_rom_top.py diff --git a/hdl/attention_gemv_openeye_top.v b/hdl/attention_gemv_openeye_top.v new file mode 100644 index 00000000..3b31543f --- /dev/null +++ b/hdl/attention_gemv_openeye_top.v @@ -0,0 +1,105 @@ +`timescale 1ns / 1ps + +//============================================================== +// Module: attention_gemv_openeye_top +// +// Purpose: +// Connect the verified GEMV ROM/control path to OpenEye_FPGA. +// +// This is an integration prototype for one fixed GEMV. +//============================================================== + +module attention_gemv_openeye_top #( + parameter integer DMA_WIDTH = 64, + parameter integer ADDR_WIDTH = 16, + parameter integer ROM_DEPTH = 939 +)( + input wire clk_i, + input wire rst_ni, + input wire start_i, + + output wire busy_o, + output wire adapter_busy_o, + output wire done_o, + + // Result interface for verification + output wire result_write_o, + output wire [DMA_WIDTH-1:0] result_data_o, + output wire [ADDR_WIDTH-1:0] result_addr_o, + + // Debug address + output wire [ADDR_WIDTH-1:0] stream_addr_o +); + + //========================================================== + // DMA connections between the adapter and OpenEye + //========================================================== + + wire [DMA_WIDTH-1:0] dma_input_data; + wire dma_input_valid; + wire dma_input_ready; + + wire [DMA_WIDTH-1:0] dma_output_data; + wire dma_output_valid; + wire dma_output_last; + wire dma_output_ready; + + //========================================================== + // Controller + DMA Adapter + ROM + //========================================================== + + attention_gemv_rom_top #( + .DMA_WIDTH (DMA_WIDTH), + .ADDR_WIDTH (ADDR_WIDTH), + .ROM_DEPTH (ROM_DEPTH) + ) u_attention_stream ( + + .clk_i (clk_i), + .rst_ni (rst_ni), + .start_i (start_i), + + .busy_o (busy_o), + .adapter_busy_o (adapter_busy_o), + .done_o (done_o), + + // Input DMA + .dma_ready_i (dma_input_ready), + .dma_data_o (dma_input_data), + .dma_valid_o (dma_input_valid), + + // Output DMA + .dma_result_data_i (dma_output_data), + .dma_result_valid_i (dma_output_valid), + .dma_result_last_i (dma_output_last), + .dma_result_ready_o (dma_output_ready), + + // Results + .result_write_o (result_write_o), + .result_data_o (result_data_o), + .result_addr_o (result_addr_o), + + .stream_addr_o (stream_addr_o) + ); + + //========================================================== + // Real OpenEye accelerator + //========================================================== + + OpenEye_FPGA u_openeye ( + + .clk_i (clk_i), + .rst_ni (rst_ni), + + // DMA input + .data_dma_i (dma_input_data), + .enable_dma_i (dma_input_valid), + .ready_dma_o (dma_input_ready), + + // DMA output + .data_dma_o (dma_output_data), + .enable_dma_o (dma_output_valid), + .last_data_o (dma_output_last), + .ready_dma_i (dma_output_ready) + ); + +endmodule \ No newline at end of file diff --git a/hdl/attention_gemv_rom_top.v b/hdl/attention_gemv_rom_top.v new file mode 100644 index 00000000..3d23d6b2 --- /dev/null +++ b/hdl/attention_gemv_rom_top.v @@ -0,0 +1,82 @@ +`timescale 1ns / 1ps + +module attention_gemv_rom_top #( + parameter integer DMA_WIDTH = 64, + parameter integer ADDR_WIDTH = 16, + parameter integer ROM_DEPTH = 939 +)( + input wire clk_i, + input wire rst_ni, + input wire start_i, + + output wire busy_o, + output wire adapter_busy_o, + output wire done_o, + + // DMA transmit interface + input wire dma_ready_i, + output wire [DMA_WIDTH-1:0] dma_data_o, + output wire dma_valid_o, + + // DMA receive interface + input wire [DMA_WIDTH-1:0] dma_result_data_i, + input wire dma_result_valid_i, + input wire dma_result_last_i, + output wire dma_result_ready_o, + + // Result storage interface + output wire result_write_o, + output wire [DMA_WIDTH-1:0] result_data_o, + output wire [ADDR_WIDTH-1:0] result_addr_o, + + // Debug: current ROM address + output wire [ADDR_WIDTH-1:0] stream_addr_o +); + + localparam [ADDR_WIDTH-1:0] ROM_WORD_COUNT = ROM_DEPTH; + + wire [DMA_WIDTH-1:0] stream_data_wire; + + + // ROM: returns a DMA word for each requested address + attention_gemv_rom #( + .DMA_WIDTH (DMA_WIDTH), + .ADDR_WIDTH (ADDR_WIDTH), + .ROM_DEPTH (ROM_DEPTH) + ) u_rom ( + .addr_i (stream_addr_o), + .data_o (stream_data_wire) + ); + + // Existing controller + DMA adapter + attention_gemv_control_top #( + .DMA_WIDTH (DMA_WIDTH), + .ADDR_WIDTH (ADDR_WIDTH) + ) u_control_top ( + .clk_i (clk_i), + .rst_ni (rst_ni), + + .start_i (start_i), + .busy_o (busy_o), + .done_o (done_o), + .adapter_busy_o (adapter_busy_o), + + .stream_word_count_i (ROM_WORD_COUNT), + .stream_addr_o (stream_addr_o), + .stream_data_i (stream_data_wire), + + .dma_ready_i (dma_ready_i), + .dma_data_o (dma_data_o), + .dma_valid_o (dma_valid_o), + + .dma_result_data_i (dma_result_data_i), + .dma_result_valid_i (dma_result_valid_i), + .dma_result_last_i (dma_result_last_i), + .dma_result_ready_o (dma_result_ready_o), + + .result_write_o (result_write_o), + .result_data_o (result_data_o), + .result_addr_o (result_addr_o) + ); + +endmodule \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py b/test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py new file mode 100644 index 00000000..281cdeb0 --- /dev/null +++ b/test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py @@ -0,0 +1,149 @@ +from pathlib import Path + +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, FallingEdge, Timer + + +@cocotb.test() +async def test_one_real_gemv(dut): + + data_dir = Path(__file__).resolve().parent / "data" + + # Golden input stream + input_words = [ + int(line, 16) + for line in + (data_dir / "gemv_reference.mem").read_text().splitlines() + if line.strip() + ] + + # Golden mathematical output + expected = [ + int(line) + for line in + (data_dir / "gemv_expected_output.txt").read_text().splitlines() + if line.strip() + ] + + assert len(input_words) == 939 + assert len(expected) == 8 + + # Initialize hardware + dut.clk_i.value = 0 + dut.rst_ni.value = 0 + dut.start_i.value = 0 + + cocotb.start_soon( + Clock(dut.clk_i, 20, unit="ns").start() + ) + + # Reset + for _ in range(6): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + dut.rst_ni.value = 1 + + # Allow OpenEye reset synchronizer to settle + for _ in range(4): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + # Start one GEMV + dut.start_i.value = 1 + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + dut.start_i.value = 0 + + sent_count = 0 + raw_results = [] + + # Wait for the GEMV to finish + for cycle in range(2500): + + await FallingEdge(dut.clk_i) + await Timer(1, unit="ns") + + # Monitor input words entering OpenEye + if int(dut.u_openeye.enable_dma_i.value): + + assert sent_count < len(input_words), ( + "More than 939 input words transmitted" + ) + + actual_word = int(dut.u_openeye.data_dma_i.value) + expected_word = input_words[sent_count] + + assert actual_word == expected_word, ( + f"Input mismatch at word {sent_count}: " + f"expected {expected_word:016X}, " + f"got {actual_word:016X}" + ) + + sent_count += 1 + + # Capture results accepted by our DMA adapter + if int(dut.result_write_o.value): + + address = int(dut.result_addr_o.value) + word = int(dut.result_data_o.value) + + assert address == len(raw_results), ( + f"Unexpected result address: {address}" + ) + + raw_results.append(word) + + if int(dut.done_o.value): + break + + else: + raise AssertionError( + f"GEMV timeout: sent={sent_count}/939, " + f"results={len(raw_results)}" + ) + + assert sent_count == 939, ( + f"Only {sent_count} input words transmitted" + ) + + # The 32 padded output values use one DMA word each + assert len(raw_results) == 32, ( + f"Expected 32 result words, got {len(raw_results)}" + ) + + # Decode signed 20-bit PSUM values + decoded = [] + + for word in raw_results: + raw = word & ((1 << 20) - 1) + + if raw & (1 << 19): + raw -= 1 << 20 + + decoded.append(raw) + + # OpenEye interleaves its two cluster columns + actual = [0] * 32 + + for beat, value in enumerate(decoded): + filter_index = (beat % 2) * 16 + (beat // 2) + actual[filter_index] = value + + assert actual[:8] == expected, ( + f"GEMV mismatch:\n" + f"Expected: {expected}\n" + f"Actual: {actual[:8]}" + ) + + assert actual[8:] == [0] * 24, ( + "Nonzero values found in padded outputs" + ) + + dut._log.info("Input words transmitted: %d", sent_count) + dut._log.info("DMA result words received: %d", len(raw_results)) + dut._log.info("GEMV result: %s", actual[:8]) + dut._log.info("Real OpenEye GEMV integration PASSED") \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_gemv_rom_top_tb.py b/test/cocotb_attention_qkt/attention_gemv_rom_top_tb.py new file mode 100644 index 00000000..2b47ca2f --- /dev/null +++ b/test/cocotb_attention_qkt/attention_gemv_rom_top_tb.py @@ -0,0 +1,95 @@ +from pathlib import Path + +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, Timer + + +async def tick(dut): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + +@cocotb.test() +async def test_rom_adapter_stream(dut): + + # Load expected DMA words + test_dir = Path(__file__).resolve().parent + mem_file = test_dir / "data" / "gemv_reference.mem" + + expected_words = [ + int(line.strip(), 16) + for line in mem_file.read_text().splitlines() + if line.strip() + ] + + assert len(expected_words) == 939 + + # Initialize signals + dut.clk_i.value = 0 + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.dma_ready_i.value = 0 + + dut.dma_result_data_i.value = 0 + dut.dma_result_valid_i.value = 0 + dut.dma_result_last_i.value = 0 + + cocotb.start_soon( + Clock(dut.clk_i, 10, unit="ns").start() + ) + + # Reset + await tick(dut) + await tick(dut) + + dut.rst_ni.value = 1 + await tick(dut) + + # Start one GEMV + dut.start_i.value = 1 + await tick(dut) + dut.start_i.value = 0 + + # DMA is not ready yet + for _ in range(4): + await tick(dut) + assert int(dut.dma_valid_o.value) == 0 + + # Allow transmission + dut.dma_ready_i.value = 1 + await tick(dut) + + # Verify all 939 transmitted words + for address, expected_word in enumerate(expected_words): + + actual_address = int(dut.stream_addr_o.value) + actual_word = int(dut.dma_data_o.value) + valid = int(dut.dma_valid_o.value) + + assert valid == 1, f"DMA not valid at word {address}" + + assert actual_address == address, ( + f"Address mismatch: expected {address}, " + f"got {actual_address}" + ) + + assert actual_word == expected_word, ( + f"Data mismatch at address {address}: " + f"expected {expected_word:016X}, " + f"got {actual_word:016X}" + ) + + await tick(dut) + + # Input transfer must be finished + assert int(dut.dma_valid_o.value) == 0 + + # Adapter should now be waiting for OpenEye results + assert int(dut.dma_result_ready_o.value) == 1 + assert int(dut.done_o.value) == 0 + + dut._log.info( + "ROM + DMA Adapter PASSED: %d words transmitted", + len(expected_words) + ) \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py b/test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py new file mode 100644 index 00000000..991f9597 --- /dev/null +++ b/test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py @@ -0,0 +1,80 @@ +import os +import shutil +from pathlib import Path + +import cocotb_test.simulator + +import open_eye.test_utils_main as ptu +import open_eye.vh_file_creator as vh_creator +import open_eye.generator as generator + +from open_eye import hdl_dir + + +def test_attention_gemv_openeye_top(): + + root = Path(__file__).resolve().parents[2] + test_dir = Path(__file__).resolve().parent + + build_dir = test_dir / ".sim_build_openeye" + build_dir.mkdir(parents=True, exist_ok=True) + + # Match the configuration of the original Attention test + config = { + "CLUSTER_ROWS": "2", + "CLUSTER_COLUMNS": "2", + "NUM_GLB_IACT": "3", + "NUM_GLB_PSUM": "4", + "NUM_GLB_WGHT": "3", + "DATAFLOW": "output_stationary", + "BRANCHES": "1", + "BUFFER_WIDTH": "12", + "QUANT_AMOUNT": "1024", + "RAM_CELLS": "32", + } + + os.environ.update(config) + + # Generate the exact OpenEye parameter headers + vh_creator.create_vh_file_from_envvars( + str(build_dir), + str(hdl_dir) + os.sep, + toplevel="OpenEye_FPGA" + ) + + # Generate the register-map decoder + generator.create_regmap_params_vh_file( + str(root / "test" / "cocotb_fpga"), + str(build_dir), + str(build_dir) + ) + + # Copy the reference DMA stream for $readmemh + shutil.copyfile( + test_dir / "data" / "gemv_reference.mem", + build_dir / "gemv_reference.mem" + ) + + # Compile the actual OpenEye hardware sources + sources = [ + src for src in ptu.get_verilog_sources(str(hdl_dir)) + if os.path.basename(src) != "dma_storage.v" + ] + + # Use the decoder generated for this exact configuration + sources.append(str(build_dir / "dma_storage.v")) + + cocotb_test.simulator.run( + verilog_sources=sources, + toplevel="attention_gemv_openeye_top", + module="attention_gemv_openeye_top_tb", + python_search=[str(test_dir)], + sim_build=str(build_dir), + simulator="icarus", + defines={ + "NO_TRACE": "TRUE", + "USE_INTERNAL_PARAMS_PE": "TRUE", + }, + force_compile=True, + waves=True, + ) \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_gemv_rom_top.py b/test/cocotb_attention_qkt/test_attention_gemv_rom_top.py new file mode 100644 index 00000000..db22ae8f --- /dev/null +++ b/test/cocotb_attention_qkt/test_attention_gemv_rom_top.py @@ -0,0 +1,37 @@ +from pathlib import Path +import shutil + +import cocotb_test.simulator + + +def test_attention_gemv_rom_top(): + + root = Path(__file__).resolve().parents[2] + test_dir = Path(__file__).resolve().parent + + build_dir = test_dir / ".sim_build" + build_dir.mkdir(parents=True, exist_ok=True) + + shutil.copyfile( + test_dir / "data" / "gemv_reference.mem", + build_dir / "gemv_reference.mem" + ) + + cocotb_test.simulator.run( + verilog_sources=[ + str(root / "hdl" / "attention_qkt_ctrl.v"), + str(root / "hdl" / "attention_dma_adapter.v"), + str(root / "hdl" / "attention_gemv_control_top.v"), + str(root / "hdl" / "attention_gemv_rom.v"), + str(root / "hdl" / "attention_gemv_rom_top.v"), + ], + + toplevel="attention_gemv_rom_top", + module="attention_gemv_rom_top_tb", + python_search=[str(test_dir)], + sim_build=str(build_dir), + + simulator="icarus", + force_compile=True, + waves=True, + ) \ No newline at end of file From 556d05939f5a510ae12bc3bb6909de747b1ed43a Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Tue, 20 Oct 2026 15:40:01 +0200 Subject: [PATCH 13/36] feat(attention): add selectable ROM banks for GEMV execution --- hdl/attention_gemv_openeye_top.v | 6 +- hdl/attention_gemv_rom_top.v | 42 +- .../attention_gemv_openeye_top_tb.py | 3 + .../data/gemv_q1_reference.mem | 939 ++++++++++++++++++ 4 files changed, 984 insertions(+), 6 deletions(-) create mode 100644 test/cocotb_attention_qkt/data/gemv_q1_reference.mem diff --git a/hdl/attention_gemv_openeye_top.v b/hdl/attention_gemv_openeye_top.v index 3b31543f..ead37643 100644 --- a/hdl/attention_gemv_openeye_top.v +++ b/hdl/attention_gemv_openeye_top.v @@ -6,7 +6,9 @@ // Purpose: // Connect the verified GEMV ROM/control path to OpenEye_FPGA. // -// This is an integration prototype for one fixed GEMV. +// Top-level integration of the GEMV controller, DMA adapter, ROM banks, +// and the real OpenEye FPGA accelerator. +// Supports hardware-controlled GEMV execution with selectable input streams. //============================================================== module attention_gemv_openeye_top #( @@ -17,6 +19,7 @@ module attention_gemv_openeye_top #( input wire clk_i, input wire rst_ni, input wire start_i, + input wire bank_select_i, output wire busy_o, output wire adapter_busy_o, @@ -57,6 +60,7 @@ module attention_gemv_openeye_top #( .clk_i (clk_i), .rst_ni (rst_ni), .start_i (start_i), + .bank_select_i (bank_select_i), .busy_o (busy_o), .adapter_busy_o (adapter_busy_o), diff --git a/hdl/attention_gemv_rom_top.v b/hdl/attention_gemv_rom_top.v index 3d23d6b2..f4512e0b 100644 --- a/hdl/attention_gemv_rom_top.v +++ b/hdl/attention_gemv_rom_top.v @@ -1,3 +1,4 @@ + `timescale 1ns / 1ps module attention_gemv_rom_top #( @@ -9,6 +10,9 @@ module attention_gemv_rom_top #( input wire rst_ni, input wire start_i, + // Select input stream: 0 = Q[0], 1 = Q[1] + input wire bank_select_i, + output wire busy_o, output wire adapter_busy_o, output wire done_o, @@ -34,20 +38,48 @@ module attention_gemv_rom_top #( ); localparam [ADDR_WIDTH-1:0] ROM_WORD_COUNT = ROM_DEPTH; - + + wire [DMA_WIDTH-1:0] rom_q0_data; + wire [DMA_WIDTH-1:0] rom_q1_data; wire [DMA_WIDTH-1:0] stream_data_wire; + reg active_bank_reg; - // ROM: returns a DMA word for each requested address + // Latch ROM selection when a new GEMV starts + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) + active_bank_reg <= 1'b0; + else if (start_i && !busy_o) + active_bank_reg <= bank_select_i; + end + + // ROM bank 0: Q[0] attention_gemv_rom #( .DMA_WIDTH (DMA_WIDTH), .ADDR_WIDTH (ADDR_WIDTH), - .ROM_DEPTH (ROM_DEPTH) - ) u_rom ( + .ROM_DEPTH (ROM_DEPTH), + .MEM_FILE ("gemv_reference.mem") + ) u_rom_q0 ( .addr_i (stream_addr_o), - .data_o (stream_data_wire) + .data_o (rom_q0_data) ); + // ROM bank 1: Q[1] + attention_gemv_rom #( + .DMA_WIDTH (DMA_WIDTH), + .ADDR_WIDTH (ADDR_WIDTH), + .ROM_DEPTH (ROM_DEPTH), + .MEM_FILE ("gemv_q1_reference.mem") + ) u_rom_q1 ( + .addr_i (stream_addr_o), + .data_o (rom_q1_data) + ); + + // Select one ROM using the latched bank + assign stream_data_wire = active_bank_reg + ? rom_q1_data + : rom_q0_data; + // Existing controller + DMA adapter attention_gemv_control_top #( .DMA_WIDTH (DMA_WIDTH), diff --git a/test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py b/test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py index 281cdeb0..04c3e092 100644 --- a/test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py +++ b/test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py @@ -1,3 +1,6 @@ +# Single-GEMV integration test for the real OpenEye accelerator. +# Verifies DMA input streaming and Q[0] results against golden references. + from pathlib import Path import cocotb diff --git a/test/cocotb_attention_qkt/data/gemv_q1_reference.mem b/test/cocotb_attention_qkt/data/gemv_q1_reference.mem new file mode 100644 index 00000000..db0d2010 --- /dev/null +++ b/test/cocotb_attention_qkt/data/gemv_q1_reference.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +1d3c0d00341328d6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +103000e0e002e0cb +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +c00a0f10210050c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +302c03f0fa0e60ca +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +70f003d0270f60fd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +e0f60170f00c30f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +101c0130390cf0c0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +70c901802b0150c1 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +d0040f101a012003 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000009016 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e90e0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000c01c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000eb000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f2021 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000310ea +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000dd0e1 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f01b +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 From b0cebc0b1519ca494da08b751a86bca3f4b639b9 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Tue, 20 Oct 2026 15:40:56 +0200 Subject: [PATCH 14/36] Update gitignore --- test/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/.gitignore b/test/.gitignore index c98e7b2f..95ddfa67 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -5,4 +5,4 @@ */simulation/* *.fst *.fst.hier -.sim_build_dma/ \ No newline at end of file +test/cocotb_attention_qkt/.sim_build*/ \ No newline at end of file From 15a0c4838183201989d97c4f25d3911a2b6b30e5 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Tue, 20 Oct 2026 15:42:27 +0200 Subject: [PATCH 15/36] test(attention): verify consecutive Q0 and Q1 GEMVs without reset --- .../attention_gemv_openeye_repeat_tb.py | 187 ++++++++++++++++++ .../data/gemv_q1_expected_output.txt | 8 + .../test_attention_gemv_openeye_repeat.py | 85 ++++++++ 3 files changed, 280 insertions(+) create mode 100644 test/cocotb_attention_qkt/attention_gemv_openeye_repeat_tb.py create mode 100644 test/cocotb_attention_qkt/data/gemv_q1_expected_output.txt create mode 100644 test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py diff --git a/test/cocotb_attention_qkt/attention_gemv_openeye_repeat_tb.py b/test/cocotb_attention_qkt/attention_gemv_openeye_repeat_tb.py new file mode 100644 index 00000000..74e09d08 --- /dev/null +++ b/test/cocotb_attention_qkt/attention_gemv_openeye_repeat_tb.py @@ -0,0 +1,187 @@ +# Multi-GEMV integration test without resetting the hardware. +# Executes Q[0] and Q[1] using selectable ROM banks. +# Verifies input streams, output results, and bank selection stability. + +from pathlib import Path + +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, FallingEdge, Timer + + +@cocotb.test() +async def test_two_distinct_gemvs(dut): + + data_dir = Path(__file__).resolve().parent / "data" + +# Reference data for both GEMV operations + gemv_cases = [ + ( + 0, + "gemv_reference.mem", + "gemv_expected_output.txt", + ), + ( + 1, + "gemv_q1_reference.mem", + "gemv_q1_expected_output.txt", + ), + ] + + # Initialize hardware only once + dut.clk_i.value = 0 + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.bank_select_i.value = 0 + + cocotb.start_soon(Clock(dut.clk_i, 20, unit="ns").start()) + + for _ in range(8): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + dut.rst_ni.value = 1 + + for _ in range(8): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + # Execute three independent GEMVs without another reset + for run_id, (bank, input_file, output_file) in enumerate(gemv_cases): + + input_words = [ + int(line, 16) + for line in (data_dir / input_file).read_text().splitlines() + if line.strip() + ] + + expected = [ + int(line) + for line in (data_dir / output_file).read_text().splitlines() + if line.strip() + ] + + assert len(input_words) == 939 + assert len(expected) == 8 + + # Continue with the existing ready-wait loop... + + # Allow controller to return to IDLE + for _ in range(3): + await FallingEdge(dut.clk_i) + await Timer(1, unit="ns") + + # Wait until OpenEye can accept a new stream + for _ in range(200): + await FallingEdge(dut.clk_i) + await Timer(1, unit="ns") + + if (int(dut.u_openeye.ready_dma_o.value) == 1 + and int(dut.busy_o.value) == 0): + break + else: + raise AssertionError( + f"GEMV {run_id + 1}: OpenEye not ready" + ) + + dut._log.info("Starting GEMV %d", run_id + 1) + + # Select the ROM bank before starting the GEMV + dut.bank_select_i.value = bank + + # Send one start pulse + dut.start_i.value = 1 + + await FallingEdge(dut.clk_i) + await Timer(1, unit="ns") + + dut.start_i.value = 0 + + sent_count = 0 + raw_results = [] + + # Monitor this GEMV + for cycle in range(2500): + + await FallingEdge(dut.clk_i) + await Timer(1, unit="ns") + + if int(dut.u_openeye.enable_dma_i.value): + + assert sent_count < 939, ( + f"GEMV {run_id + 1}: Extra input word" + ) + + actual_word = int(dut.u_openeye.data_dma_i.value) + + assert actual_word == input_words[sent_count], ( + f"GEMV {run_id + 1}: " + f"Input mismatch at word {sent_count}" + ) + + sent_count += 1 + + # Try changing the external bank during transmission + if sent_count == 100: + dut.bank_select_i.value = 1 - bank + + if sent_count == 200: + dut.bank_select_i.value = bank + + if int(dut.result_write_o.value): + + address = int(dut.result_addr_o.value) + word = int(dut.result_data_o.value) + + assert address == len(raw_results), ( + f"GEMV {run_id + 1}: Result address mismatch" + ) + + raw_results.append(word) + + if int(dut.done_o.value): + break + + else: + raise AssertionError( + f"GEMV {run_id + 1} timeout: " + f"sent={sent_count}/939, " + f"results={len(raw_results)}" + ) + + assert sent_count == 939 + assert len(raw_results) == 32 + + # Decode signed 20-bit PSUM values + decoded = [] + + for word in raw_results: + value = word & ((1 << 20) - 1) + + if value & (1 << 19): + value -= 1 << 20 + + decoded.append(value) + + # Restore logical output ordering + actual = [0] * 32 + + for beat, value in enumerate(decoded): + filter_index = (beat % 2) * 16 + (beat // 2) + actual[filter_index] = value + + assert actual[:8] == expected, ( + f"GEMV {run_id + 1}: " + f"Expected {expected}, got {actual[:8]}" + ) + + assert actual[8:] == [0] * 24, ( + f"GEMV {run_id + 1}: Padding mismatch" + ) + + dut._log.info( + "GEMV %d PASSED: cycles=%d, inputs=%d, outputs=%d", + run_id + 1, cycle + 1, sent_count, len(raw_results) + ) + + dut._log.info("Both Q[0] and Q[1] GEMVs PASSED") diff --git a/test/cocotb_attention_qkt/data/gemv_q1_expected_output.txt b/test/cocotb_attention_qkt/data/gemv_q1_expected_output.txt new file mode 100644 index 00000000..64e4988c --- /dev/null +++ b/test/cocotb_attention_qkt/data/gemv_q1_expected_output.txt @@ -0,0 +1,8 @@ +2413 +-2802 +1441 +-789 +1936 +4797 +3174 +447 diff --git a/test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py b/test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py new file mode 100644 index 00000000..ff74e82c --- /dev/null +++ b/test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py @@ -0,0 +1,85 @@ +import os +import shutil +from pathlib import Path + +import cocotb_test.simulator + +import open_eye.test_utils_main as ptu +import open_eye.vh_file_creator as vh_creator +import open_eye.generator as generator + +from open_eye import hdl_dir + + +def test_attention_gemv_openeye_top(): + + root = Path(__file__).resolve().parents[2] + test_dir = Path(__file__).resolve().parent + + build_dir = test_dir / ".sim_build_openeye_repeat" + build_dir.mkdir(parents=True, exist_ok=True) + + # Match the configuration of the original Attention test + config = { + "CLUSTER_ROWS": "2", + "CLUSTER_COLUMNS": "2", + "NUM_GLB_IACT": "3", + "NUM_GLB_PSUM": "4", + "NUM_GLB_WGHT": "3", + "DATAFLOW": "output_stationary", + "BRANCHES": "1", + "BUFFER_WIDTH": "12", + "QUANT_AMOUNT": "1024", + "RAM_CELLS": "32", + } + + os.environ.update(config) + + # Generate the exact OpenEye parameter headers + vh_creator.create_vh_file_from_envvars( + str(build_dir), + str(hdl_dir) + os.sep, + toplevel="OpenEye_FPGA" + ) + + # Generate the register-map decoder + generator.create_regmap_params_vh_file( + str(root / "test" / "cocotb_fpga"), + str(build_dir), + str(build_dir) + ) + + # Copy the reference DMA stream for $readmemh + shutil.copyfile( + test_dir / "data" / "gemv_reference.mem", + build_dir / "gemv_reference.mem" + ) + + shutil.copyfile( + test_dir / "data" / "gemv_q1_reference.mem", + build_dir / "gemv_q1_reference.mem" + ) + + # Compile the actual OpenEye hardware sources + sources = [ + src for src in ptu.get_verilog_sources(str(hdl_dir)) + if os.path.basename(src) != "dma_storage.v" + ] + + # Use the decoder generated for this exact configuration + sources.append(str(build_dir / "dma_storage.v")) + + cocotb_test.simulator.run( + verilog_sources=sources, + toplevel="attention_gemv_openeye_top", + module="attention_gemv_openeye_repeat_tb", + python_search=[str(test_dir)], + sim_build=str(build_dir), + simulator="icarus", + defines={ + "NO_TRACE": "TRUE", + "USE_INTERNAL_PARAMS_PE": "TRUE", + }, + force_compile=True, + waves=True, + ) \ No newline at end of file From a134068c8c7855904363f94b3357e41d5fa41057 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Tue, 20 Oct 2026 15:45:45 +0200 Subject: [PATCH 16/36] chore: ignore generated Cocotb simulation directories --- test/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/.gitignore b/test/.gitignore index 95ddfa67..c2b88b71 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -5,4 +5,4 @@ */simulation/* *.fst *.fst.hier -test/cocotb_attention_qkt/.sim_build*/ \ No newline at end of file +/cocotb_attention_qkt/.sim_build*/ \ No newline at end of file From 9c867b9c379d930e1a9fa51daef352e7ddda05da Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Thu, 22 Oct 2026 16:52:28 +0200 Subject: [PATCH 17/36] Attention: generate QKV projection streams and compact ROM/RAM images --- attention_rom_override_split.py | 117 +++ src/open_eye/attention_projection_mapper.py | 294 ++++++ .../attention_mapper_v1/activation_ram.mem | 32 + .../data/attention_mapper_v1/common_rom.mem | 691 +++++++++++++ .../verification_streams/k_t0.mem | 939 ++++++++++++++++++ .../verification_streams/k_t1.mem | 939 ++++++++++++++++++ .../verification_streams/k_t2.mem | 939 ++++++++++++++++++ .../verification_streams/k_t3.mem | 939 ++++++++++++++++++ .../verification_streams/q_t0.mem | 939 ++++++++++++++++++ .../verification_streams/q_t1.mem | 939 ++++++++++++++++++ .../verification_streams/q_t2.mem | 939 ++++++++++++++++++ .../verification_streams/q_t3.mem | 939 ++++++++++++++++++ .../verification_streams/v_t0.mem | 939 ++++++++++++++++++ .../verification_streams/v_t1.mem | 939 ++++++++++++++++++ .../verification_streams/v_t2.mem | 939 ++++++++++++++++++ .../verification_streams/v_t3.mem | 939 ++++++++++++++++++ .../data/attention_mapper_v1/weight_ram.mem | 720 ++++++++++++++ 17 files changed, 13122 insertions(+) create mode 100644 attention_rom_override_split.py create mode 100644 src/open_eye/attention_projection_mapper.py create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/activation_ram.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/common_rom.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t0.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t1.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t2.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t3.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t0.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t1.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t2.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t3.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t0.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t1.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t2.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t3.mem create mode 100644 test/cocotb_attention_qkt/data/attention_mapper_v1/weight_ram.mem diff --git a/attention_rom_override_split.py b/attention_rom_override_split.py new file mode 100644 index 00000000..856ae40e --- /dev/null +++ b/attention_rom_override_split.py @@ -0,0 +1,117 @@ +"""Split two verified OpenEye GEMV streams into ROM/RAM images. + +Phase-1 fixed-geometry baseline for the Attention ROM-override architecture. +The script changes neither OpenEye RTL nor the original reference files. + +Run at the OpenEye repository root: + python attention_rom_override_split.py + +Defaults expect: + test/cocotb_attention_qkt/data/gemv_reference.mem + test/cocotb_attention_qkt/data/gemv_q1_reference.mem +""" + +from __future__ import annotations + +import argparse +import json +from pathlib import Path + +WORD_BITS = 64 +EXPECTED_WORDS = 939 +IACT_START, IACT_END = 19, 27 # [19, 26]: 8 DMA words +WGHT_START, WGHT_END = 27, 267 # [27, 266]: 240 DMA words + + +def read_mem(path: Path) -> list[int]: + if not path.is_file(): + raise FileNotFoundError(f"Missing reference stream: {path}") + words = [] + for line_num, raw in enumerate(path.read_text(encoding="utf-8-sig").splitlines(), start=1): + line = raw.split("//", 1)[0].split("#", 1)[0].strip() + if not line: + continue + if line.startswith("0x"): + line = line[2:] + try: + value = int(line.replace("_", ""), 16) + except ValueError as exc: + raise ValueError(f"Invalid hex at {path}:{line_num}: {line!r}") from exc + if not 0 <= value < (1 << WORD_BITS): + raise ValueError(f"Word outside {WORD_BITS}-bit range at {path}:{line_num}") + words.append(value) + if len(words) != EXPECTED_WORDS: + raise ValueError(f"Expected {EXPECTED_WORDS} words in {path}; got {len(words)}") + return words + + +def write_mem(path: Path, words: list[int]) -> None: + path.write_text("".join(f"{value:016x}\n" for value in words), encoding="ascii") + + +def assemble(template: list[int], activations: list[int], weights: list[int]) -> list[int]: + if len(activations) != IACT_END - IACT_START: + raise ValueError("Unexpected activation RAM size") + if len(weights) != WGHT_END - WGHT_START: + raise ValueError("Unexpected weight RAM size") + result = template.copy() + result[IACT_START:IACT_END] = activations + result[WGHT_START:WGHT_END] = weights + return result + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--data-dir", type=Path, default=Path("test/cocotb_attention_qkt/data")) + parser.add_argument("--out-dir", type=Path, default=None) + args = parser.parse_args() + source_dir = args.data_dir + output_dir = args.out_dir or source_dir / "rom_override_baseline" + + q0 = read_mem(source_dir / "gemv_reference.mem") + q1 = read_mem(source_dir / "gemv_q1_reference.mem") + + differences = [i for i, (left, right) in enumerate(zip(q0, q1)) if left != right] + outside_iact = [i for i in differences if not (IACT_START <= i < IACT_END)] + if outside_iact: + raise ValueError( + f"Q0/Q1 differ outside the activation region at {outside_iact}. " + "Cannot share a single common template/weight image yet." + ) + + common_rom = q0.copy() + common_rom[IACT_START:WGHT_END] = [0] * (WGHT_END - IACT_START) + activation_q0 = q0[IACT_START:IACT_END] + activation_q1 = q1[IACT_START:IACT_END] + weight_wq = q0[WGHT_START:WGHT_END] + + assert assemble(common_rom, activation_q0, weight_wq) == q0 + assert assemble(common_rom, activation_q1, weight_wq) == q1 + + output_dir.mkdir(parents=True, exist_ok=True) + write_mem(output_dir / "common_rom.mem", common_rom) + write_mem(output_dir / "activation_q0_ram.mem", activation_q0) + write_mem(output_dir / "activation_q1_ram.mem", activation_q1) + write_mem(output_dir / "weight_wq_ram.mem", weight_wq) + + manifest = { + "dma_word_bits": WORD_BITS, + "complete_stream_words": EXPECTED_WORDS, + "common_rom_words": len(common_rom), + "activation_override": {"start": IACT_START, "word_count": len(activation_q0)}, + "weight_override": {"start": WGHT_START, "word_count": len(weight_wq)}, + "q0_q1_differing_word_addresses": differences, + "quantization": "Unchanged in the common ROM; supervisor reviewing optimization.", + "skip_flags": "Baseline assumes all skip flags disabled.", + "scope": "Verified Q0/Q1 only; dynamic Q/K/V mapping follows later.", + } + (output_dir / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8") + + print("PASS: Both Q0 and Q1 streams reconstructed exactly (939 / 939 words each).") + print(f"Differences between source streams: {differences}") + print(f"Saved 4 .mem files and manifest.json to: {output_dir.resolve()}") + print("Next: compare the generated images against the Attention Python mapper output.") + + +if __name__ == "__main__": + main() diff --git a/src/open_eye/attention_projection_mapper.py b/src/open_eye/attention_projection_mapper.py new file mode 100644 index 00000000..bf289a79 --- /dev/null +++ b/src/open_eye/attention_projection_mapper.py @@ -0,0 +1,294 @@ +"""OpenEye Attention Q/K/V projection stream and ROM-override image generator. + +First-stage, INT8, fixed-geometry implementation. Uses OpenEye's existing +DRAMContents, LayerParameters, and GemmMapper; no changes to OpenEye RTL. + +By default, 4x8 input X and three 8x8 projection matrices are generated +with a reproducible random seed. Alternatively, use --input-npz containing +X, WQ, WK, WV (with W matrices in mathematical [input, output] layout). + +The output is an *offline initialization image*, NOT a runtime Python scheduler. +All skip flags remain 0 until hardware reuse is independently verified. +""" + +from __future__ import annotations + +import argparse +import json +import os +from pathlib import Path +from types import SimpleNamespace + +import numpy as np + +# Keep these imports from the same OpenEye checkout used for RTL simulation. +from open_eye import DRAM +from open_eye import layer_parameters as lp +from open_eye import open_eye_parameters as oep +from open_eye import stream_dicts as strdic +from open_eye.gemm_mapper import GemmMapper + + +SECTION_NAMES = ("status", "iact", "wght", "psum", "quantize") +WORD_MASK = (1 << 64) - 1 +MIN_PAD_K = MIN_PAD_N = 32 # Existing attention cocotb test's proven envelope. + +# Matches the public cocotb GEMM test platform; only used when unset in shell. +BASELINE_ENV = { + "CLUSTER_COLUMNS": "2", "CLUSTER_ROWS": "2", + "NUM_GLB_IACT": "3", "NUM_GLB_WGHT": "3", "NUM_GLB_PSUM": "4", + "PARALLEL_MACS": "2", "BRANCHES": "1", "BUFFER_WIDTH": "12", + "RAM_CELLS": "32", "QUANT_AMOUNT": "1024", "DATAFLOW": "output_stationary", +} + + +def _layer_shim(k: int, n: int) -> SimpleNamespace: + """Supply just the Dense layer interface expected by LayerParameters.""" + return SimpleNamespace( + name="dense_attention_projection", + input=SimpleNamespace(shape=(1, k)), + output=SimpleNamespace(shape=(1, n)), + kernel=SimpleNamespace(shape=(k, n)), + ) + + +def _as_int8_matrix(name: str, data: np.ndarray, shape: tuple[int, int]) -> np.ndarray: + values = np.asarray(data) + if values.shape != shape: + raise ValueError(f"{name} must have shape {shape}, got {values.shape}") + if not np.issubdtype(values.dtype, np.integer): + raise ValueError(f"{name} must contain integer operands, got {values.dtype}") + if np.any(values < -128) or np.any(values > 127): + raise ValueError(f"{name} contains values outside signed INT8 range") + return values.astype(np.int64) + + +def input_tensors(args: argparse.Namespace) -> tuple[np.ndarray, dict[str, np.ndarray]]: + if args.input_npz: + with np.load(args.input_npz, allow_pickle=False) as data: + required = ("X", "WQ", "WK", "WV") + missing = [key for key in required if key not in data] + if missing: + raise ValueError(f"Input NPZ is missing {missing}; expected {required}") + x = _as_int8_matrix("X", data["X"], (args.seq_len, args.d_model)) + matrices = { + kind: _as_int8_matrix(key, data[key], (args.d_model, args.d_model)) + for kind, key in (("q", "WQ"), ("k", "WK"), ("v", "WV")) + } + else: + rng = np.random.default_rng(args.seed) + x = rng.integers(-64, 64, size=(args.seq_len, args.d_model), dtype=np.int64) + matrices = { + kind: rng.integers(-64, 64, size=(args.d_model, args.d_model), dtype=np.int64) + for kind in ("q", "k", "v") + } + return x, matrices + + +class AttentionProjectionMapper: + """Adapt OpenEye's GEMM stream mapper to autonomous Q/K/V projection setup. + + One GEMV pass at a time is generated for the *existing* GEMM datapath. + This is not an implementation of true batched/multi-token GEMM. + """ + + def __init__(self, params: object, k_pad: int = 32, n_pad: int = 32): + if not params.SERIAL or int(params.DMA_BITWIDTH) != 64: + raise ValueError("This ROM-override baseline requires SERIAL=1, DMA_BITWIDTH=64") + self.params = params + self.k_pad = k_pad + self.n_pad = n_pad + + def make_pass(self, iact: np.ndarray, weights_out_in: np.ndarray) -> dict[str, list[int]]: + """Build one complete, zero-skip GEMV DMA stream, preserving segment boundaries. + + iact has shape [K], and weights_out_in has shape [N, K]. + """ + k = int(len(iact)) + n = int(weights_out_in.shape[0]) + if weights_out_in.shape != (n, k): + raise ValueError(f"Expected weights [N,K], got {weights_out_in.shape}") + if k > self.k_pad or n > self.n_pad: + raise ValueError("First baseline supports K,N <= 32; larger tiles need separate mapping verification") + + act_pad = np.zeros(self.k_pad, dtype=np.int64) + act_pad[:k] = iact + w_pad = np.zeros((self.n_pad, self.k_pad), dtype=np.int64) + w_pad[:n, :k] = weights_out_in + + layer = _layer_shim(self.k_pad, self.n_pad) + layer_params = lp.LayerParameters([0], layer, self.params, 0, 1) + if layer_params.needed_total_transmissions != 1: + raise ValueError("Only a one-repetition GEMV mapping is supported by this baseline") + # No unverified OpenEye weight/activation reuse at this stage. + layer_params.skipIact = 0 + layer_params.skipWght = 0 + layer_params.skipPsum = 0 + layer_params.send_values_out = 1 # Raw PSUM output via DMA. + + dram = DRAM.DRAMContents([layer], [layer_params]) + dram.fmap[0] = act_pad.tolist() + dram.weights[0] = w_pad.tolist() + dram.bias[0] = [0] * self.n_pad + content = [dram.fmap[0], dram.weights[0], dram.bias[0]] + + mapper = GemmMapper(self.params, layer_params, 0, content, 0, 0) + mapper.make_stream() + raw = mapper.get_stream() + if any(getattr(layer_params, key) != 0 for key in ("skipIact", "skipWght", "skipPsum")): + raise ValueError("Baseline mapper unexpectedly enabled a skip flag") + + sections: dict[str, list[int]] = {} + for name in SECTION_NAMES: + section = raw[strdic.stream_parallel_dict[name]] + words = [int(v) for v in section] + if any(v < 0 or v > WORD_MASK for v in words): + raise ValueError(f"Section {name} contains a value outside unsigned 64 bits") + sections[name] = words + if not sections["status"] or not sections["iact"] or not sections["wght"]: + raise ValueError("Required DMA section is empty") + return sections + + +def _write_mem(path: Path, words: list[int]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text("".join(f"{w:016x}\n" for w in words), encoding="ascii") + + +def _flatten(sections: dict[str, list[int]]) -> list[int]: + return [word for name in SECTION_NAMES for word in sections[name]] + + +def _assemble(template, iact, wght, offsets): + status_end = offsets["iact"]["start"] + + return ( + template[:status_end] + + iact + + wght + + template[status_end:] + ) + + +def export_projection_images( + x: np.ndarray, matrices: dict[str, np.ndarray], mapper: AttentionProjectionMapper, out: Path +) -> dict: + """Build one shared ROM plus banked activation and projection-weight RAM images.""" + seq_len, d_model = x.shape + sections_by_pass: dict[str, dict[str, list[int]]] = {} + weight_for_kind: dict[str, list[int]] = {} + iact_for_token: dict[int, list[int]] = {} + + for kind in ("q", "k", "v"): + for token in range(seq_len): + name = f"{kind}_t{token}" + # DRAM Dense weights are indexed [out][in]; mathematical W is [in][out]. + sections = mapper.make_pass(x[token], matrices[kind].T) + sections_by_pass[name] = sections + if kind not in weight_for_kind: + weight_for_kind[kind] = sections["wght"] + elif weight_for_kind[kind] != sections["wght"]: + raise ValueError(f"Weight DMA image changed between tokens for {kind}") + if token not in iact_for_token: + iact_for_token[token] = sections["iact"] + elif iact_for_token[token] != sections["iact"]: + raise ValueError(f"Activation DMA image changed between Q/K/V for token {token}") + + first = sections_by_pass["q_t0"] + counts = {name: len(first[name]) for name in SECTION_NAMES} + offsets = {} + at = 0 + for name in SECTION_NAMES: + offsets[name] = {"start": at, "words": counts[name]} + at += counts[name] + + # Full common template requires equal static sections across ALL 12 passes. + # Fail rather than silently supply a wrong configuration for a later pass. + for pass_name, sections in sections_by_pass.items(): + for name in SECTION_NAMES: + if len(sections[name]) != counts[name]: + raise ValueError(f"DMA section length for {pass_name}/{name} differs from q_t0") + if name not in ("iact", "wght") and sections[name] != first[name]: + raise ValueError( + f"Static section {name} differs for {pass_name}; " + "one common-ROM image is not valid for these inputs/configurations" + ) + + template = first["status"] + first["psum"] + first["quantize"] + + iact_words = counts["iact"] + wght_words = counts["wght"] + iact_ram = [word for token in range(seq_len) for word in iact_for_token[token]] + weight_ram = [word for kind in ("q", "k", "v") for word in weight_for_kind[kind]] + + operations = [] + for bank, kind in enumerate(("q", "k", "v")): + for token in range(seq_len): + name = f"{kind}_t{token}" + act_base = token * iact_words + w_base = bank * wght_words + expected = _flatten(sections_by_pass[name]) + reconstructed = _assemble( + template, + iact_ram[act_base:act_base + iact_words], + weight_ram[w_base:w_base + wght_words], + offsets, + ) + if expected != reconstructed: + raise AssertionError(f"ROM/RAM reconstruction mismatch for {name}") + operations.append({ + "name": name, "activation_base_word": act_base, + "weight_base_word": w_base, "dma_words": len(expected), + }) + _write_mem(out / "verification_streams" / f"{name}.mem", expected) + + _write_mem(out / "common_rom.mem", template) + _write_mem(out / "activation_ram.mem", iact_ram) + _write_mem(out / "weight_ram.mem", weight_ram) + np.savez(out / "inputs_used.npz", X=x, WQ=matrices["q"], WK=matrices["k"], WV=matrices["v"]) + + manifest = { + "scope": "Q/K/V projection only; 12 sequential GEMV passes via existing gemm_mode=1", + "skip_flags": {"skipIact": 0, "skipWght": 0, "skipPsum": 0}, + "precision": "signed INT8 operands / raw PSUM output", + "shape": {"sequence_length": seq_len, "embedding_width": d_model, + "padded_k": mapper.k_pad, "padded_n": mapper.n_pad}, + "dma_word_bits": 64, "complete_stream_words": sum(counts.values()), + "sections": offsets, + "memories": {"common_rom_words": len(template), "activation_ram_words": len(iact_ram), + "weight_ram_words": len(weight_ram)}, + "operations": operations, + "caveat": "Bit-exact Python stream reconstruction checked, NOT yet RTL/DUT-verified. " + "RAM contents are initialization images; writable hardware is a separate RTL step.", + } + (out / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n", encoding="utf-8") + return manifest + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--seq-len", type=int, default=4) + parser.add_argument("--d-model", type=int, default=8) + parser.add_argument("--seed", type=int, default=0) + parser.add_argument("--input-npz", type=Path, default=None) + parser.add_argument("--out-dir", type=Path, default=Path("test/cocotb_attention_qkt/data/attention_mapper_v1")) + args = parser.parse_args() + if args.seq_len < 1 or not (1 <= args.d_model <= 32): + parser.error("This baseline requires seq_len >= 1 and 1 <= d_model <= 32") + for key, value in BASELINE_ENV.items(): + os.environ.setdefault(key, value) + x, matrices = input_tensors(args) + params = oep.get_oep(1) + mapper = AttentionProjectionMapper(params) + args.out_dir.mkdir(parents=True, exist_ok=True) + manifest = export_projection_images(x, matrices, mapper, args.out_dir) + + print("PASS: Reconstructed all", len(manifest["operations"]), "Q/K/V DMA streams bit-exactly.") + print("Section word counts:", {k: v["words"] for k, v in manifest["sections"].items()}) + print("Memory images:", manifest["memories"]) + print("Output:", args.out_dir.resolve()) + print("NOTE: This checks the Python Mapper/ROM overlay, not execution on OpenEye RTL.") + + +if __name__ == "__main__": + main() diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/activation_ram.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/activation_ram.mem new file mode 100644 index 00000000..cb462c23 --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/activation_ram.mem @@ -0,0 +1,32 @@ +0000000000000000 +0000000000000000 +0000000000000000 +c2c9c5e7e201112c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +1d3c0d00341328d6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +c01528e337070510 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +d62c1d21c4062df2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/common_rom.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/common_rom.mem new file mode 100644 index 00000000..b5f144fd --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/common_rom.mem @@ -0,0 +1,691 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t0.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t0.mem new file mode 100644 index 00000000..89c2ba5d --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t0.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +c2c9c5e7e201112c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +60330f902e0ca0c6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +603302503202a0f0 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +90310dd01a0240f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +80210c60220de0e8 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +e0c60f3008030025 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000c +d0110d903f0c70ca +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +00010cb0390eb015 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +602100a00f0d3009 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f80f4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003a0fc +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000ff0d9 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f60c6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f039 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003f0ec +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003900d +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000fa0c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t1.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t1.mem new file mode 100644 index 00000000..5008c26b --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t1.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +1d3c0d00341328d6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +60330f902e0ca0c6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +603302503202a0f0 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +90310dd01a0240f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +80210c60220de0e8 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +e0c60f3008030025 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000c +d0110d903f0c70ca +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +00010cb0390eb015 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +602100a00f0d3009 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f80f4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003a0fc +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000ff0d9 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f60c6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f039 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003f0ec +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003900d +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000fa0c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t2.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t2.mem new file mode 100644 index 00000000..db97172e --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t2.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +c01528e337070510 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +60330f902e0ca0c6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +603302503202a0f0 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +90310dd01a0240f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +80210c60220de0e8 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +e0c60f3008030025 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000c +d0110d903f0c70ca +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +00010cb0390eb015 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +602100a00f0d3009 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f80f4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003a0fc +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000ff0d9 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f60c6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f039 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003f0ec +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003900d +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000fa0c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t3.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t3.mem new file mode 100644 index 00000000..42acf0e1 --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t3.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +d62c1d21c4062df2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +60330f902e0ca0c6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +603302503202a0f0 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +90310dd01a0240f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +80210c60220de0e8 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +e0c60f3008030025 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000c +d0110d903f0c70ca +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +00010cb0390eb015 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +602100a00f0d3009 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f80f4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003a0fc +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000ff0d9 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f60c6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f039 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003f0ec +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003900d +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000fa0c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t0.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t0.mem new file mode 100644 index 00000000..4e93e8af --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t0.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +c2c9c5e7e201112c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +103000e0e002e0cb +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +c00a0f10210050c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +302c03f0fa0e60ca +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +70f003d0270f60fd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +e0f60170f00c30f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +101c0130390cf0c0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +70c901802b0150c1 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +d0040f101a012003 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000009016 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e90e0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000c01c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000eb000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f2021 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000310ea +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000dd0e1 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f01b +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t1.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t1.mem new file mode 100644 index 00000000..db0d2010 --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t1.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +1d3c0d00341328d6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +103000e0e002e0cb +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +c00a0f10210050c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +302c03f0fa0e60ca +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +70f003d0270f60fd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +e0f60170f00c30f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +101c0130390cf0c0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +70c901802b0150c1 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +d0040f101a012003 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000009016 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e90e0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000c01c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000eb000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f2021 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000310ea +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000dd0e1 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f01b +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t2.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t2.mem new file mode 100644 index 00000000..f235ef3c --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t2.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +c01528e337070510 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +103000e0e002e0cb +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +c00a0f10210050c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +302c03f0fa0e60ca +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +70f003d0270f60fd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +e0f60170f00c30f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +101c0130390cf0c0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +70c901802b0150c1 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +d0040f101a012003 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000009016 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e90e0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000c01c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000eb000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f2021 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000310ea +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000dd0e1 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f01b +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t3.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t3.mem new file mode 100644 index 00000000..f9491410 --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t3.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +d62c1d21c4062df2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +103000e0e002e0cb +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +c00a0f10210050c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +302c03f0fa0e60ca +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +70f003d0270f60fd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +e0f60170f00c30f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +101c0130390cf0c0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +70c901802b0150c1 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +d0040f101a012003 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000009016 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e90e0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000c01c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000eb000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f2021 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000310ea +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000dd0e1 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f01b +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t0.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t0.mem new file mode 100644 index 00000000..405e7663 --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t0.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +c2c9c5e7e201112c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +30ee0ce0d702002a +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +c00201d0d00ff0f4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +10ef03603c0030f5 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000002 +90f103b0150240dd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +d0dd0c102f0f50c9 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +d0e902e0cf01e0e4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000002 +603203d0ca01b01f +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +60d103a029037036 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e203c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000040f6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f8014 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000370d3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000c5018 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000001d028 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000e0d7 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000c3000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t1.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t1.mem new file mode 100644 index 00000000..53bec370 --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t1.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +1d3c0d00341328d6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +30ee0ce0d702002a +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +c00201d0d00ff0f4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +10ef03603c0030f5 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000002 +90f103b0150240dd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +d0dd0c102f0f50c9 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +d0e902e0cf01e0e4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000002 +603203d0ca01b01f +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +60d103a029037036 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e203c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000040f6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f8014 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000370d3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000c5018 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000001d028 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000e0d7 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000c3000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t2.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t2.mem new file mode 100644 index 00000000..923709ab --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t2.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +c01528e337070510 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +30ee0ce0d702002a +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +c00201d0d00ff0f4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +10ef03603c0030f5 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000002 +90f103b0150240dd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +d0dd0c102f0f50c9 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +d0e902e0cf01e0e4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000002 +603203d0ca01b01f +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +60d103a029037036 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e203c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000040f6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f8014 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000370d3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000c5018 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000001d028 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000e0d7 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000c3000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t3.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t3.mem new file mode 100644 index 00000000..75b6c3a4 --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t3.mem @@ -0,0 +1,939 @@ +0000081882200901 +000003c000200001 +0000200200130020 +0000020002401010 +0024108010102000 +00015640aa060101 +000b00bff0210201 +2070090120180013 +0000000360020030 +0000000300000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +d62c1d21c4062df2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +30ee0ce0d702002a +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +c00201d0d00ff0f4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +10ef03603c0030f5 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000002 +90f103b0150240dd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +d0dd0c102f0f50c9 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +d0e902e0cf01e0e4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000002 +603203d0ca01b01f +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +60d103a029037036 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e203c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000040f6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f8014 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000370d3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000c5018 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000001d028 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000e0d7 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000c3000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 +0000008900000000 +8900000000890000 +0000890000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/weight_ram.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/weight_ram.mem new file mode 100644 index 00000000..03967f11 --- /dev/null +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/weight_ram.mem @@ -0,0 +1,720 @@ +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +103000e0e002e0cb +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +c00a0f10210050c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +302c03f0fa0e60ca +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +70f003d0270f60fd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +e0f60170f00c30f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +101c0130390cf0c0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +70c901802b0150c1 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +d0040f101a012003 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000009016 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e90e0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000c01c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000eb000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f2021 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000310ea +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000dd0e1 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f01b +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +60330f902e0ca0c6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +603302503202a0f0 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +90310dd01a0240f3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +80210c60220de0e8 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000e +e0c60f3008030025 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000c +d0110d903f0c70ca +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000001 +00010cb0390eb015 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +602100a00f0d3009 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f80f4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003a0fc +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000ff0d9 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f60c6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000f039 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003f0ec +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000003900d +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000fa0c2 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +30ee0ce0d702002a +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +c00201d0d00ff0f4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +10ef03603c0030f5 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000002 +90f103b0150240dd +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000f +d0dd0c102f0f50c9 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000000d +d0e902e0cf01e0e4 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000002 +603203d0ca01b01f +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000003 +60d103a029037036 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000e203c +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000040f6 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000f8014 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000370d3 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000c5018 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000001d028 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +000000000000e0d7 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +00000000000c3000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 From 9b24609dd5adfbdece0969a396ea4f71a19d964c Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Thu, 22 Oct 2026 16:56:28 +0200 Subject: [PATCH 18/36] Attention: implement ROM RAM override with cocotb verification --- hdl/attention_projection_memory.v | 122 ++++++++++++++++++ .../attention_projection_memory_tb.py | 112 ++++++++++++++++ .../test_attention_projection_memory.py | 39 ++++++ 3 files changed, 273 insertions(+) create mode 100644 hdl/attention_projection_memory.v create mode 100644 test/cocotb_attention_qkt/attention_projection_memory_tb.py create mode 100644 test/cocotb_attention_qkt/test_attention_projection_memory.py diff --git a/hdl/attention_projection_memory.v b/hdl/attention_projection_memory.v new file mode 100644 index 00000000..e475a9bf --- /dev/null +++ b/hdl/attention_projection_memory.v @@ -0,0 +1,122 @@ +// OpenEye Q/K/V Projection: ROM Template + RAM Override (baseline v1) +// SPDX-License-Identifier: SHL-2.1 +// +// Offline Python prepares the three memory images using GemmMapper. +// This module chooses the appropriate 64-bit DMA word at runtime. +// +// Projection IDs: 0=Q, 1=K, 2=V. +// Token IDs: 0..TOKEN_COUNT-1. +// Stream layout: status | iact | wght | psum | quantize. +// +// Compatibility with the existing combinational attention_gemv_rom.v: +// The read path is combinational. A future BRAM-optimized synchronous-read +// implementation needs a one-cycle look-ahead / valid-ready pipeline. +// +// The RAM write ports are provided for future memory updates. Keep both +// write enables low during the first projection ROM-override test. + +`timescale 1ns / 1ps + + +module attention_projection_memory #( + parameter integer DMA_WIDTH = 64, + parameter integer ADDR_WIDTH = 16, + parameter integer STATUS_WORDS = 19, + parameter integer IACT_WORDS = 8, + parameter integer WGHT_WORDS = 240, + parameter integer PSUM_WORDS = 32, + parameter integer QUANT_WORDS = 640, + parameter integer TOKEN_COUNT = 4, + parameter integer PROJECTION_COUNT = 3, + parameter COMMON_MEM_FILE = "common_rom.mem", + parameter ACTIVATION_MEM_FILE = "activation_ram.mem", + parameter WEIGHT_MEM_FILE = "weight_ram.mem" +)( + input wire clk_i, + input wire rst_ni, + input wire start_i, + input wire busy_i, + input wire [1:0] token_select_i, + input wire [1:0] projection_select_i, + input wire [ADDR_WIDTH-1:0] addr_i, + output reg [DMA_WIDTH-1:0] data_o, + + // Optional write ports: unused for the first preinitialized-memory test. + input wire iact_we_i, + input wire [ADDR_WIDTH-1:0] iact_wr_addr_i, + input wire [DMA_WIDTH-1:0] iact_wr_data_i, + input wire wght_we_i, + input wire [ADDR_WIDTH-1:0] wght_wr_addr_i, + input wire [DMA_WIDTH-1:0] wght_wr_data_i +); + + localparam integer IACT_START = STATUS_WORDS; + localparam integer WGHT_START = IACT_START + IACT_WORDS; + localparam integer PSUM_START = WGHT_START + WGHT_WORDS; + localparam integer QUANT_START = PSUM_START + PSUM_WORDS; + localparam integer STREAM_WORDS = QUANT_START + QUANT_WORDS; + localparam integer IACT_RAM_DEPTH = TOKEN_COUNT * IACT_WORDS; + localparam integer COMMON_ROM_DEPTH = STATUS_WORDS + PSUM_WORDS + QUANT_WORDS; + localparam integer WGHT_RAM_DEPTH = PROJECTION_COUNT * WGHT_WORDS; + + reg [DMA_WIDTH-1:0] common_rom [0:COMMON_ROM_DEPTH-1]; + reg [DMA_WIDTH-1:0] activation_ram [0:IACT_RAM_DEPTH-1]; + reg [DMA_WIDTH-1:0] weight_ram [0:WGHT_RAM_DEPTH-1]; + + reg [1:0] active_token_reg; + reg [1:0] active_projection_reg; + + // Read all offline-generated images. Simulation working directory must + // contain these files (the provided test runner copies them there). + initial begin + $readmemh(COMMON_MEM_FILE, common_rom); + $readmemh(ACTIVATION_MEM_FILE, activation_ram); + $readmemh(WEIGHT_MEM_FILE, weight_ram); + end + + // Latch the next operation's selectors when idle. This prevents a + // mid-stream change of external selection inputs from corrupting a GEMV. + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + active_token_reg <= 2'd0; + active_projection_reg <= 2'd0; + end else if (start_i && !busy_i) begin + active_token_reg <= token_select_i; + active_projection_reg <= projection_select_i; + end + end + + // Preinitialized, but writable RAMs. Do not write to them while a + // projection is reading the same addresses in the baseline experiment. + always @(posedge clk_i) begin + if (iact_we_i && (iact_wr_addr_i < IACT_RAM_DEPTH)) + activation_ram[iact_wr_addr_i] <= iact_wr_data_i; + if (wght_we_i && (wght_wr_addr_i < WGHT_RAM_DEPTH)) + weight_ram[wght_wr_addr_i] <= wght_wr_data_i; + end + + wire [ADDR_WIDTH-1:0] iact_index = + (active_token_reg * IACT_WORDS) + (addr_i - IACT_START); + wire [ADDR_WIDTH-1:0] wght_index = + (active_projection_reg * WGHT_WORDS) + (addr_i - WGHT_START); + + always @(*) begin + data_o = {DMA_WIDTH{1'b0}}; + if (addr_i < STREAM_WORDS) begin + if ((addr_i >= IACT_START) && (addr_i < WGHT_START)) begin + if ((active_token_reg < TOKEN_COUNT) && + (iact_index < IACT_RAM_DEPTH)) + data_o = activation_ram[iact_index]; + end else if ((addr_i >= WGHT_START) && (addr_i < PSUM_START)) begin + if ((active_projection_reg < PROJECTION_COUNT) && + (wght_index < WGHT_RAM_DEPTH)) + data_o = weight_ram[wght_index]; + end else if (addr_i < IACT_START) begin + data_o = common_rom[addr_i]; + + end else begin + data_o = common_rom[addr_i - IACT_WORDS - WGHT_WORDS]; + end + end + end +endmodule diff --git a/test/cocotb_attention_qkt/attention_projection_memory_tb.py b/test/cocotb_attention_qkt/attention_projection_memory_tb.py new file mode 100644 index 00000000..ad021868 --- /dev/null +++ b/test/cocotb_attention_qkt/attention_projection_memory_tb.py @@ -0,0 +1,112 @@ +"""Cocotb verification of ROM Template + RAM Override for all 12 GEMVs. + +Checks every 64-bit word, selector latching, and the two RAM write ports. +Requires files generated by open_eye.attention_projection_mapper. +""" + +import os +from pathlib import Path +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import Timer, RisingEdge + +DATA_DIR = Path(os.environ.get("ATTENTION_MEMORY_DATA_DIR", "test/cocotb_attention_qkt/data/attention_mapper_v1")) + + +def read_mem(filename): + return [ + int(line.strip(), 16) + for line in (DATA_DIR / filename).read_text().splitlines() + if line.strip()] + + +async def wait_for_comb(): + await Timer(1, unit="ns") + + +@cocotb.test() +async def verify_all_projection_streams(dut): + clock = Clock(dut.clk_i, 10, unit="ns") + cocotb.start_soon(clock.start()) + + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.busy_i.value = 0 + dut.token_select_i.value = 0 + dut.projection_select_i.value = 0 + dut.addr_i.value = 0 + dut.iact_we_i.value = 0 + dut.iact_wr_addr_i.value = 0 + dut.iact_wr_data_i.value = 0 + dut.wght_we_i.value = 0 + dut.wght_wr_addr_i.value = 0 + dut.wght_wr_data_i.value = 0 + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + dut.rst_ni.value = 1 + + total_checked = 0 + for proj_id, kind in enumerate(("q", "k", "v")): + for token in range(4): + expected = read_mem(f"verification_streams/{kind}_t{token}.mem") + assert len(expected) == 939 + + # Submit operation while idle, then keep busy high during reading. + await Timer(1, unit="ns") + dut.projection_select_i.value = proj_id + dut.token_select_i.value = token + dut.busy_i.value = 0 + dut.start_i.value = 1 + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + dut.start_i.value = 0 + dut.busy_i.value = 1 + + # Deliberately perturb requests while busy: latched values must win. + dut.projection_select_i.value = (proj_id + 1) % 3 + dut.token_select_i.value = (token + 1) % 4 + + for addr, word in enumerate(expected): + dut.addr_i.value = addr + await wait_for_comb() + got = int(dut.data_o.value) + assert got == word, ( + f"{kind}_t{token} addr={addr}: " + f"got 0x{got:016x}, expected 0x{word:016x}" + ) + total_checked += 1 + + dut.busy_i.value = 0 + dut.addr_i.value = 939 + await wait_for_comb() + assert int(dut.data_o.value) == 0, "Invalid stream address must read as zero" + + # RAM writable ports: update one activation and one weight word, + # reselect q_t0, and ensure only the relevant addresses read back changed data. + dut.iact_we_i.value = 1 + dut.iact_wr_addr_i.value = 0 + dut.iact_wr_data_i.value = 0x0123456789ABCDEF + dut.wght_we_i.value = 1 + dut.wght_wr_addr_i.value = 0 + dut.wght_wr_data_i.value = 0xFEDCBA9876543210 + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + dut.iact_we_i.value = 0 + dut.wght_we_i.value = 0 + + dut.token_select_i.value = 0 + dut.projection_select_i.value = 0 + dut.start_i.value = 1 + dut.busy_i.value = 0 + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + dut.start_i.value = 0 + + dut.addr_i.value = 19 + await wait_for_comb() + assert int(dut.data_o.value) == 0x0123456789ABCDEF + dut.addr_i.value = 27 + await wait_for_comb() + assert int(dut.data_o.value) == 0xFEDCBA9876543210 + + dut._log.info("PASS: %d DMA words across 12 Q/K/V streams; selectors latched; RAM writes verified", total_checked) diff --git a/test/cocotb_attention_qkt/test_attention_projection_memory.py b/test/cocotb_attention_qkt/test_attention_projection_memory.py new file mode 100644 index 00000000..63eeccba --- /dev/null +++ b/test/cocotb_attention_qkt/test_attention_projection_memory.py @@ -0,0 +1,39 @@ +"""Run: python -m pytest -s test/cocotb_attention_qkt/test_attention_projection_memory.py + +Place attention_projection_memory.v in hdl/ and +attention_projection_memory_tb.py in test/cocotb_attention_qkt/. +The Python Mapper output must exist at data/attention_mapper_v1/. +""" + +import os +import shutil +from pathlib import Path + +import pytest +from cocotb_test.simulator import run + +ROOT = Path(__file__).resolve().parents[2] +TEST_DIR = Path(__file__).resolve().parent +DATA_DIR = TEST_DIR / "data" / "attention_mapper_v1" + + +@pytest.mark.parametrize("simulator", ["icarus"]) +def test_attention_projection_memory(simulator): + build_dir = TEST_DIR / ".sim_build_projection_memory" + build_dir.mkdir(parents=True, exist_ok=True) + + for filename in ("common_rom.mem", "activation_ram.mem", "weight_ram.mem"): + source = DATA_DIR / filename + assert source.exists(), f"Missing {source}; run the Python Mapper first" + shutil.copyfile(source, build_dir / filename) + + run( + simulator=simulator, + verilog_sources=[str(ROOT / "hdl" / "attention_projection_memory.v")], + toplevel="attention_projection_memory", + module="attention_projection_memory_tb", + python_search=[str(TEST_DIR)], + sim_build=str(build_dir), + extra_env={"ATTENTION_MEMORY_DATA_DIR": str(DATA_DIR)}, + force_compile=True, + ) From 2bea9abb54bb028ababa892c09c98f4b812b4479 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Fri, 23 Oct 2026 16:16:23 +0200 Subject: [PATCH 19/36] Attention : Add GEMV projection integration with ROM/RAM-based DMA streaming and verify 12 seq GEMV operations for Q,k,V projections --- hdl/attention_gemv_projection_openeye_top.v | 131 +++++++++++ hdl/attention_gemv_projection_stream_top.v | 112 +++++++++ .../attention_gemv_projection_openeye_tb.py | 212 ++++++++++++++++++ .../test_attention_gemv_projection_openeye.py | 87 +++++++ 4 files changed, 542 insertions(+) create mode 100644 hdl/attention_gemv_projection_openeye_top.v create mode 100644 hdl/attention_gemv_projection_stream_top.v create mode 100644 test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py create mode 100644 test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py diff --git a/hdl/attention_gemv_projection_openeye_top.v b/hdl/attention_gemv_projection_openeye_top.v new file mode 100644 index 00000000..f84ee3cf --- /dev/null +++ b/hdl/attention_gemv_projection_openeye_top.v @@ -0,0 +1,131 @@ +`timescale 1ns / 1ps + +//============================================================== +// Module: attention_gemv_openeye_top +// +// Purpose: +// Connect the verified GEMV ROM/control path to OpenEye_FPGA. +// +// Top-level integration of the GEMV controller, DMA adapter, ROM banks, +// and the real OpenEye FPGA accelerator. +// Supports hardware-controlled GEMV execution with selectable input streams. +//============================================================== + +module attention_projection_openeye_top #( + parameter integer DMA_WIDTH = 64, + parameter integer ADDR_WIDTH = 16, + parameter integer ROM_DEPTH = 939 +)( + input wire clk_i, + input wire rst_ni, + input wire start_i, + input wire [1:0] token_select_i, + input wire [1:0] projection_select_i, + + // Activation RAM write interface + input wire iact_we_i, + input wire [ADDR_WIDTH-1:0] iact_wr_addr_i, + input wire [DMA_WIDTH-1:0] iact_wr_data_i, + + // Weight RAM write interface + input wire wght_we_i, + input wire [ADDR_WIDTH-1:0] wght_wr_addr_i, + input wire [DMA_WIDTH-1:0] wght_wr_data_i, + + output wire busy_o, + output wire adapter_busy_o, + output wire done_o, + + // Result interface for verification + output wire result_write_o, + output wire [DMA_WIDTH-1:0] result_data_o, + output wire [ADDR_WIDTH-1:0] result_addr_o, + + // Debug address + output wire [ADDR_WIDTH-1:0] stream_addr_o +); + + //========================================================== + // DMA connections between the adapter and OpenEye + //========================================================== + + wire [DMA_WIDTH-1:0] dma_input_data; + wire dma_input_valid; + wire dma_input_ready; + + wire [DMA_WIDTH-1:0] dma_output_data; + wire dma_output_valid; + wire dma_output_last; + wire dma_output_ready; + + //========================================================== + // Controller + DMA Adapter + ROM + //========================================================== + + attention_projection_stream_top #( + .DMA_WIDTH (DMA_WIDTH), + .ADDR_WIDTH (ADDR_WIDTH), + .STREAM_WORDS (ROM_DEPTH) + ) u_attention_stream ( + + .clk_i (clk_i), + .rst_ni (rst_ni), + .start_i (start_i), + .token_select_i (token_select_i), + .projection_select_i (projection_select_i), + + .busy_o (busy_o), + .adapter_busy_o (adapter_busy_o), + .done_o (done_o), + + // Input DMA + .dma_ready_i (dma_input_ready), + .dma_data_o (dma_input_data), + .dma_valid_o (dma_input_valid), + + // Output DMA + .dma_result_data_i (dma_output_data), + .dma_result_valid_i (dma_output_valid), + .dma_result_last_i (dma_output_last), + .dma_result_ready_o (dma_output_ready), + + // Results + .result_write_o (result_write_o), + .result_data_o (result_data_o), + .result_addr_o (result_addr_o), + + // Activation RAM write interface + .iact_we_i (iact_we_i), + .iact_wr_addr_i (iact_wr_addr_i), + .iact_wr_data_i (iact_wr_data_i), + + // Weight RAM write interface + .wght_we_i (wght_we_i), + .wght_wr_addr_i (wght_wr_addr_i), + .wght_wr_data_i (wght_wr_data_i), + + .stream_addr_o (stream_addr_o) + ); + + //========================================================== + // Real OpenEye accelerator + //========================================================== + + OpenEye_FPGA u_openeye ( + + .clk_i (clk_i), + .rst_ni (rst_ni), + + // DMA input + .data_dma_i (dma_input_data), + .enable_dma_i (dma_input_valid), + .ready_dma_o (dma_input_ready), + + // DMA output + .data_dma_o (dma_output_data), + .enable_dma_o (dma_output_valid), + .last_data_o (dma_output_last), + .ready_dma_i (dma_output_ready) + ); + +endmodule \ No newline at end of file diff --git a/hdl/attention_gemv_projection_stream_top.v b/hdl/attention_gemv_projection_stream_top.v new file mode 100644 index 00000000..c6f50971 --- /dev/null +++ b/hdl/attention_gemv_projection_stream_top.v @@ -0,0 +1,112 @@ +`timescale 1ns / 1ps + +module attention_projection_stream_top #( + parameter integer DMA_WIDTH = 64, + parameter integer ADDR_WIDTH = 16, + parameter integer STREAM_WORDS = 939 +)( + // Clock and control + input wire clk_i, + input wire rst_ni, + input wire start_i, + + // Projection selection + input wire [1:0] token_select_i, + input wire [1:0] projection_select_i, + + // Execution status + output wire busy_o, + output wire adapter_busy_o, + output wire done_o, + + // DMA transmit interface + input wire dma_ready_i, + output wire [DMA_WIDTH-1:0] dma_data_o, + output wire dma_valid_o, + + // DMA receive interface + input wire [DMA_WIDTH-1:0] dma_result_data_i, + input wire dma_result_valid_i, + input wire dma_result_last_i, + output wire dma_result_ready_o, + + // Result storage interface + output wire result_write_o, + output wire [DMA_WIDTH-1:0] result_data_o, + output wire [ADDR_WIDTH-1:0] result_addr_o, + + // Activation RAM write interface + input wire iact_we_i, + input wire [ADDR_WIDTH-1:0] iact_wr_addr_i, + input wire [DMA_WIDTH-1:0] iact_wr_data_i, + + // Weight RAM write interface + input wire wght_we_i, + input wire [ADDR_WIDTH-1:0] wght_wr_addr_i, + input wire [DMA_WIDTH-1:0] wght_wr_data_i, + + // Debug + output wire [ADDR_WIDTH-1:0] stream_addr_o +); + + wire [DMA_WIDTH-1:0] stream_data_wire; + + localparam [ADDR_WIDTH-1:0] STREAM_WORD_COUNT = STREAM_WORDS; + + attention_projection_memory #( + .DMA_WIDTH (DMA_WIDTH), + .ADDR_WIDTH (ADDR_WIDTH) + ) u_projection_memory ( + + .clk_i (clk_i), + .rst_ni (rst_ni), + .start_i (start_i), + .busy_i (busy_o), + + .token_select_i (token_select_i), + .projection_select_i (projection_select_i), + + .addr_i (stream_addr_o), + .data_o (stream_data_wire), + + .iact_we_i (iact_we_i), + .iact_wr_addr_i (iact_wr_addr_i), + .iact_wr_data_i (iact_wr_data_i), + + .wght_we_i (wght_we_i), + .wght_wr_addr_i (wght_wr_addr_i), + .wght_wr_data_i (wght_wr_data_i) + ); + + attention_gemv_control_top #( + .DMA_WIDTH (DMA_WIDTH), + .ADDR_WIDTH (ADDR_WIDTH) + ) u_control_top ( + + .clk_i (clk_i), + .rst_ni (rst_ni), + + .start_i (start_i), + .busy_o (busy_o), + .done_o (done_o), + .adapter_busy_o (adapter_busy_o), + + .stream_word_count_i (STREAM_WORD_COUNT), + .stream_addr_o (stream_addr_o), + .stream_data_i (stream_data_wire), + + .dma_ready_i (dma_ready_i), + .dma_data_o (dma_data_o), + .dma_valid_o (dma_valid_o), + + .dma_result_data_i (dma_result_data_i), + .dma_result_valid_i (dma_result_valid_i), + .dma_result_last_i (dma_result_last_i), + .dma_result_ready_o (dma_result_ready_o), + + .result_write_o (result_write_o), + .result_data_o (result_data_o), + .result_addr_o (result_addr_o) + ); + +endmodule \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py b/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py new file mode 100644 index 00000000..cec4e408 --- /dev/null +++ b/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py @@ -0,0 +1,212 @@ +# Multi-GEMV integration test without resetting the hardware. +# Executes all 12 Q/K/V projections using token and projection selectors. +# Verifies DMA streams, GEMV results, and selector stability. + +from pathlib import Path + +import cocotb +import numpy as np +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, FallingEdge, Timer + + +@cocotb.test() +async def test_twelve_projection_gemvs(dut): + + data_dir = ( + Path(__file__).resolve().parent + / "data" + / "attention_mapper_v1" + ) + + # Reference data for both GEMV operations + gemv_cases = [ + (proj_id, token, f"verification_streams/{kind}_t{token}.mem") + for proj_id, kind in enumerate(("q", "k", "v")) + for token in range(4) + ] + + with np.load(data_dir / "inputs_used.npz") as tensors: + x = tensors["X"].astype(np.int64) + weights = { + "q": tensors["WQ"].astype(np.int64), + "k": tensors["WK"].astype(np.int64), + "v": tensors["WV"].astype(np.int64), + } + + # Initialize hardware only once + dut.clk_i.value = 0 + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.token_select_i.value = 0 + dut.projection_select_i.value = 0 + + # Activation RAM write interface + dut.iact_we_i.value = 0 + dut.iact_wr_addr_i.value = 0 + dut.iact_wr_data_i.value = 0 + + # Weight RAM write interface + dut.wght_we_i.value = 0 + dut.wght_wr_addr_i.value = 0 + dut.wght_wr_data_i.value = 0 + + cocotb.start_soon(Clock(dut.clk_i, 20, unit="ns").start()) + + for _ in range(8): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + dut.rst_ni.value = 1 + + for _ in range(8): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + # Execute three independent GEMVs without another reset + for run_id, (proj_id, token, input_file) in enumerate(gemv_cases): + + input_words = [ + int(line, 16) + for line in (data_dir / input_file).read_text().splitlines() + if line.strip() + ] + + kind = ("q", "k", "v")[proj_id] + + expected = ( + x[token] @ weights[kind] + ).tolist() + + assert len(input_words) == 939 + assert len(expected) == 8 + + # Continue with the existing ready-wait loop... + + # Allow controller to return to IDLE + for _ in range(3): + await FallingEdge(dut.clk_i) + await Timer(1, unit="ns") + + # Wait until OpenEye can accept a new stream + for _ in range(200): + await FallingEdge(dut.clk_i) + await Timer(1, unit="ns") + + if (int(dut.u_openeye.ready_dma_o.value) == 1 + and int(dut.busy_o.value) == 0): + break + else: + raise AssertionError( + f"GEMV {run_id + 1}: OpenEye not ready" + ) + + dut._log.info( + "Starting %s[%d] - GEMV %d/12", + kind.upper(), token, run_id + 1 + ) + + dut.token_select_i.value = token + dut.projection_select_i.value = proj_id + + dut.start_i.value = 1 + + await FallingEdge(dut.clk_i) + await Timer(1, unit="ns") + + dut.start_i.value = 0 + + sent_count = 0 + raw_results = [] + + # Monitor this GEMV + for cycle in range(2500): + + await FallingEdge(dut.clk_i) + await Timer(1, unit="ns") + + if int(dut.u_openeye.enable_dma_i.value): + + assert sent_count < 939, ( + f"{kind.upper()}[{token}]: Extra input word" + ) + + actual_word = int(dut.u_openeye.data_dma_i.value) + + assert actual_word == input_words[sent_count], ( + f"{kind.upper()}[{token}]: " + f"Input mismatch at word {sent_count}" + ) + + sent_count += 1 + + # Change external selections during transmission + if sent_count == 100: + dut.token_select_i.value = (token + 1) % 4 + dut.projection_select_i.value = (proj_id + 1) % 3 + + # Restore original selections + if sent_count == 200: + dut.token_select_i.value = token + dut.projection_select_i.value = proj_id + + if int(dut.result_write_o.value): + + address = int(dut.result_addr_o.value) + word = int(dut.result_data_o.value) + + assert address == len(raw_results), ( + f"GEMV {run_id + 1}: Result address mismatch" + ) + + raw_results.append(word) + + if int(dut.done_o.value): + break + + else: + raise AssertionError( + f"GEMV {run_id + 1} timeout: " + f"sent={sent_count}/939, " + f"results={len(raw_results)}" + ) + + assert sent_count == 939 + assert len(raw_results) == 32 + + # Decode signed 20-bit PSUM values + decoded = [] + + for word in raw_results: + value = word & ((1 << 20) - 1) + + if value & (1 << 19): + value -= 1 << 20 + + decoded.append(value) + + # Restore logical output ordering + actual = [0] * 32 + + for beat, value in enumerate(decoded): + filter_index = (beat % 2) * 16 + (beat // 2) + actual[filter_index] = value + + assert actual[:8] == expected, ( + f"{kind.upper()}[{token}]: " + f"Expected {expected}, got {actual[:8]}" + ) + + assert actual[8:] == [0] * 24, ( + f"{kind.upper()}[{token}]: Padding mismatch" + ) + + dut._log.info( + "%s[%d] PASSED: cycles=%d, inputs=%d, outputs=%d", + kind.upper(), token, cycle + 1, + sent_count, len(raw_results) + ) + + dut._log.info( + "All 12 Q/K/V projection GEMVs PASSED without reset" + ) \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py b/test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py new file mode 100644 index 00000000..2083ac4a --- /dev/null +++ b/test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py @@ -0,0 +1,87 @@ +import os +import shutil +from pathlib import Path + +import cocotb_test.simulator + +import open_eye.test_utils_main as ptu +import open_eye.vh_file_creator as vh_creator +import open_eye.generator as generator + +from open_eye import hdl_dir + + +def test_attention_projection_openeye_top(): + + root = Path(__file__).resolve().parents[2] + test_dir = Path(__file__).resolve().parent + + build_dir = test_dir / ".sim_build_projection_openeye" + build_dir.mkdir(parents=True, exist_ok=True) + + # Match the configuration of the original Attention test + config = { + "CLUSTER_ROWS": "2", + "CLUSTER_COLUMNS": "2", + "NUM_GLB_IACT": "3", + "NUM_GLB_PSUM": "4", + "NUM_GLB_WGHT": "3", + "DATAFLOW": "output_stationary", + "BRANCHES": "1", + "BUFFER_WIDTH": "12", + "QUANT_AMOUNT": "1024", + "RAM_CELLS": "32", + } + + os.environ.update(config) + + # Generate the exact OpenEye parameter headers + vh_creator.create_vh_file_from_envvars( + str(build_dir), + str(hdl_dir) + os.sep, + toplevel="OpenEye_FPGA" + ) + + # Generate the register-map decoder + generator.create_regmap_params_vh_file( + str(root / "test" / "cocotb_fpga"), + str(build_dir), + str(build_dir) + ) + + # Memory images generated by Attention Projection Mapper + memory_dir = test_dir / "data" / "attention_mapper_v1" + + for filename in ( + "common_rom.mem", + "activation_ram.mem", + "weight_ram.mem", + ): + shutil.copyfile( + memory_dir / filename, + build_dir / filename + ) + + # Compile the actual OpenEye hardware sources + sources = [ + src for src in ptu.get_verilog_sources(str(hdl_dir)) + if os.path.basename(src) != "dma_storage.v" + ] + + # Use the decoder generated for this exact configuration + sources.append(str(build_dir / "dma_storage.v")) + + cocotb_test.simulator.run( + verilog_sources=sources, + toplevel="attention_projection_openeye_top", + module="attention_gemv_projection_openeye_tb", + python_search=[str(test_dir)], + sim_build=str(build_dir), + simulator="icarus", + defines={ + "NO_TRACE": "TRUE", + "USE_INTERNAL_PARAMS_PE": "TRUE", + }, + force_compile=True, + waves=True, + ) \ No newline at end of file From 658e837320c75bd28c29567a4fabd24c5f316e0f Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Fri, 23 Oct 2026 20:20:53 +0200 Subject: [PATCH 20/36] Switch attention GEMV projection to Dense mode Replace GemmMapper with DenseMapper and enable row-stationary dataflow. Regenerate ROM configuration and DMA verification streams. Verify all 12 Q/K/V GEMV passes and assert gemm_mode=0 during computation. --- src/open_eye/attention_projection_mapper.py | 10 ++++----- .../attention_gemv_projection_openeye_tb.py | 22 ++++++++++++++++++- .../data/attention_mapper_v1/common_rom.mem | 2 +- .../verification_streams/k_t0.mem | 2 +- .../verification_streams/k_t1.mem | 2 +- .../verification_streams/k_t2.mem | 2 +- .../verification_streams/k_t3.mem | 2 +- .../verification_streams/q_t0.mem | 2 +- .../verification_streams/q_t1.mem | 2 +- .../verification_streams/q_t2.mem | 2 +- .../verification_streams/q_t3.mem | 2 +- .../verification_streams/v_t0.mem | 2 +- .../verification_streams/v_t1.mem | 2 +- .../verification_streams/v_t2.mem | 2 +- .../verification_streams/v_t3.mem | 2 +- .../test_attention_gemv_openeye_repeat.py | 2 +- .../test_attention_gemv_openeye_top.py | 2 +- .../test_attention_gemv_projection_openeye.py | 2 +- 18 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/open_eye/attention_projection_mapper.py b/src/open_eye/attention_projection_mapper.py index bf289a79..8e4196a4 100644 --- a/src/open_eye/attention_projection_mapper.py +++ b/src/open_eye/attention_projection_mapper.py @@ -1,7 +1,7 @@ """OpenEye Attention Q/K/V projection stream and ROM-override image generator. First-stage, INT8, fixed-geometry implementation. Uses OpenEye's existing -DRAMContents, LayerParameters, and GemmMapper; no changes to OpenEye RTL. +DRAMContents, LayerParameters, and DenseMapper; no changes to OpenEye RTL. By default, 4x8 input X and three 8x8 projection matrices are generated with a reproducible random seed. Alternatively, use --input-npz containing @@ -26,7 +26,7 @@ from open_eye import layer_parameters as lp from open_eye import open_eye_parameters as oep from open_eye import stream_dicts as strdic -from open_eye.gemm_mapper import GemmMapper +from open_eye.dense_mapper import DenseMapper SECTION_NAMES = ("status", "iact", "wght", "psum", "quantize") @@ -38,7 +38,7 @@ "CLUSTER_COLUMNS": "2", "CLUSTER_ROWS": "2", "NUM_GLB_IACT": "3", "NUM_GLB_WGHT": "3", "NUM_GLB_PSUM": "4", "PARALLEL_MACS": "2", "BRANCHES": "1", "BUFFER_WIDTH": "12", - "RAM_CELLS": "32", "QUANT_AMOUNT": "1024", "DATAFLOW": "output_stationary", + "RAM_CELLS": "32", "QUANT_AMOUNT": "1024", "DATAFLOW": "row stationary", } @@ -132,7 +132,7 @@ def make_pass(self, iact: np.ndarray, weights_out_in: np.ndarray) -> dict[str, l dram.bias[0] = [0] * self.n_pad content = [dram.fmap[0], dram.weights[0], dram.bias[0]] - mapper = GemmMapper(self.params, layer_params, 0, content, 0, 0) + mapper = DenseMapper(self.params, layer_params, 0, content, 0, 0) mapper.make_stream() raw = mapper.get_stream() if any(getattr(layer_params, key) != 0 for key in ("skipIact", "skipWght", "skipPsum")): @@ -248,7 +248,7 @@ def export_projection_images( np.savez(out / "inputs_used.npz", X=x, WQ=matrices["q"], WK=matrices["k"], WV=matrices["v"]) manifest = { - "scope": "Q/K/V projection only; 12 sequential GEMV passes via existing gemm_mode=1", + "scope": "Q/K/V projection only; 12 sequential GEMV passes via existing gemm_mode=0", "skip_flags": {"skipIact": 0, "skipWght": 0, "skipPsum": 0}, "precision": "signed INT8 operands / raw PSUM output", "shape": {"sequence_length": seq_len, "embedding_width": d_model, diff --git a/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py b/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py index cec4e408..c6642eb2 100644 --- a/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py +++ b/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py @@ -7,8 +7,27 @@ import cocotb import numpy as np from cocotb.clock import Clock -from cocotb.triggers import RisingEdge, FallingEdge, Timer +from cocotb.triggers import RisingEdge, FallingEdge, ReadOnly, Timer +async def check_dense_mode(dut): + fpga = dut.u_openeye + + # OpenEye calculation-related FSM states + COMPUTE_STATES = (7, 8, 9, 10) + + while True: + await RisingEdge(dut.clk_i) + await ReadOnly() + + state = int(fpga.fsm_current_state.value) + + if state in COMPUTE_STATES: + mode = int(fpga.gemm_mode.value) + + assert mode == 0, ( + f"Dense Mode violation: " + f"gemm_mode={mode}, FSM state={state}" + ) @cocotb.test() async def test_twelve_projection_gemvs(dut): @@ -51,6 +70,7 @@ async def test_twelve_projection_gemvs(dut): dut.wght_wr_addr_i.value = 0 dut.wght_wr_data_i.value = 0 + cocotb.start_soon(check_dense_mode(dut)) cocotb.start_soon(Clock(dut.clk_i, 20, unit="ns").start()) for _ in range(8): diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/common_rom.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/common_rom.mem index b5f144fd..659f7bcf 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/common_rom.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/common_rom.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t0.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t0.mem index 89c2ba5d..7fbcdd61 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t0.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t0.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t1.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t1.mem index 5008c26b..37db5fd9 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t1.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t1.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t2.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t2.mem index db97172e..89c14212 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t2.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t2.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t3.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t3.mem index 42acf0e1..bc641e33 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t3.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/k_t3.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t0.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t0.mem index 4e93e8af..5cedaac5 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t0.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t0.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t1.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t1.mem index db0d2010..09cf5c49 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t1.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t1.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t2.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t2.mem index f235ef3c..f6fd522b 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t2.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t2.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t3.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t3.mem index f9491410..ba4d425b 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t3.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/q_t3.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t0.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t0.mem index 405e7663..59dd7129 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t0.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t0.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t1.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t1.mem index 53bec370..4c5810c7 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t1.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t1.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t2.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t2.mem index 923709ab..2e710057 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t2.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t2.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t3.mem b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t3.mem index 75b6c3a4..3e0e5a0f 100644 --- a/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t3.mem +++ b/test/cocotb_attention_qkt/data/attention_mapper_v1/verification_streams/v_t3.mem @@ -5,7 +5,7 @@ 0024108010102000 00015640aa060101 000b00bff0210201 -2070090120180013 +0070090120180013 0000000360020030 0000000300000100 10000100ff0ff000 diff --git a/test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py b/test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py index ff74e82c..1a71a4da 100644 --- a/test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py +++ b/test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py @@ -26,7 +26,7 @@ def test_attention_gemv_openeye_top(): "NUM_GLB_IACT": "3", "NUM_GLB_PSUM": "4", "NUM_GLB_WGHT": "3", - "DATAFLOW": "output_stationary", + "DATAFLOW": "row stationary", "BRANCHES": "1", "BUFFER_WIDTH": "12", "QUANT_AMOUNT": "1024", diff --git a/test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py b/test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py index 991f9597..a5ae284f 100644 --- a/test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py +++ b/test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py @@ -26,7 +26,7 @@ def test_attention_gemv_openeye_top(): "NUM_GLB_IACT": "3", "NUM_GLB_PSUM": "4", "NUM_GLB_WGHT": "3", - "DATAFLOW": "output_stationary", + "DATAFLOW": "row stationary", "BRANCHES": "1", "BUFFER_WIDTH": "12", "QUANT_AMOUNT": "1024", diff --git a/test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py b/test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py index 2083ac4a..5c5a9c31 100644 --- a/test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py +++ b/test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py @@ -26,7 +26,7 @@ def test_attention_projection_openeye_top(): "NUM_GLB_IACT": "3", "NUM_GLB_PSUM": "4", "NUM_GLB_WGHT": "3", - "DATAFLOW": "output_stationary", + "DATAFLOW": "row stationary", "BRANCHES": "1", "BUFFER_WIDTH": "12", "QUANT_AMOUNT": "1024", From 9cdeda38232af62c305d0c33dd0162db982a0020 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sat, 24 Oct 2026 13:17:30 +0200 Subject: [PATCH 21/36] Attention : Add and verify Q/K/V Buffer Integration --- hdl/attention_gemv_projection_openeye_top.v | 45 ++++++++ hdl/attention_projection_result_buffer.v | 105 ++++++++++++++++++ .../attention_gemv_projection_openeye_tb.py | 86 +++++++++++++- 3 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 hdl/attention_projection_result_buffer.v diff --git a/hdl/attention_gemv_projection_openeye_top.v b/hdl/attention_gemv_projection_openeye_top.v index f84ee3cf..9d9ff664 100644 --- a/hdl/attention_gemv_projection_openeye_top.v +++ b/hdl/attention_gemv_projection_openeye_top.v @@ -41,6 +41,19 @@ module attention_projection_openeye_top #( output wire [DMA_WIDTH-1:0] result_data_o, output wire [ADDR_WIDTH-1:0] result_addr_o, + input wire [1:0] q_rd_token_i, + input wire [2:0] q_rd_feature_i, + + input wire [1:0] k_rd_token_i, + input wire [2:0] k_rd_feature_i, + + input wire [1:0] v_rd_token_i, + input wire [2:0] v_rd_feature_i, + + output wire [19:0] q_data_o, + output wire [19:0] k_data_o, + output wire [19:0] v_data_o, + // Debug address output wire [ADDR_WIDTH-1:0] stream_addr_o ); @@ -106,7 +119,39 @@ module attention_projection_openeye_top #( .stream_addr_o (stream_addr_o) ); + //========================================================== + // Q/K/V Projection Result Buffer + //========================================================== + + attention_projection_result_buffer u_qkv_buffer ( + + .clk_i (clk_i), + .rst_ni (rst_ni), + // Capture the selected operation + .start_i (start_i), + .token_select_i (token_select_i), + .projection_select_i(projection_select_i), + + // Receive calculated PSUM values + .result_write_i (result_write_o), + .result_addr_i (result_addr_o), + .result_data_i (result_data_o), + + .q_rd_token_i (q_rd_token_i), + .q_rd_feature_i (q_rd_feature_i), + + .k_rd_token_i (k_rd_token_i), + .k_rd_feature_i (k_rd_feature_i), + + .v_rd_token_i (v_rd_token_i), + .v_rd_feature_i (v_rd_feature_i), + + .q_data_o (q_data_o), + .k_data_o (k_data_o), + .v_data_o (v_data_o) + + ); //========================================================== // Real OpenEye accelerator //========================================================== diff --git a/hdl/attention_projection_result_buffer.v b/hdl/attention_projection_result_buffer.v new file mode 100644 index 00000000..74d5851f --- /dev/null +++ b/hdl/attention_projection_result_buffer.v @@ -0,0 +1,105 @@ +`timescale 1ns / 1ps + +module attention_projection_result_buffer ( + input wire clk_i, + input wire rst_ni, + + // Capture operation metadata at start + input wire start_i, + input wire [1:0] token_select_i, + input wire [1:0] projection_select_i, + + // DMA result interface + input wire result_write_i, + input wire [15:0] result_addr_i, + input wire [63:0] result_data_i, + + // Independent Q read address + input wire [1:0] q_rd_token_i, + input wire [2:0] q_rd_feature_i, + + // Independent K read address + input wire [1:0] k_rd_token_i, + input wire [2:0] k_rd_feature_i, + + // Independent V read address + input wire [1:0] v_rd_token_i, + input wire [2:0] v_rd_feature_i, + + output wire [19:0] q_data_o, + output wire [19:0] k_data_o, + output wire [19:0] v_data_o +); + + reg [1:0] active_token; + reg [1:0] active_projection; + + reg [19:0] q_mem [0:31]; + reg [19:0] k_mem [0:31]; + reg [19:0] v_mem [0:31]; + + wire [4:0] write_addr; + wire [4:0] read_addr; + + // Only even beats 0,2,...,14 contain + // the eight logical projection outputs. + wire valid_feature = + result_write_i && + (result_addr_i < 16) && + (result_addr_i[0] == 1'b0); + + assign write_addr = { + active_token, + result_addr_i[3:1] + }; + + wire [4:0] q_read_addr; + wire [4:0] k_read_addr; + wire [4:0] v_read_addr; + + assign q_read_addr = {q_rd_token_i, q_rd_feature_i}; + assign k_read_addr = {k_rd_token_i, k_rd_feature_i}; + assign v_read_addr = {v_rd_token_i, v_rd_feature_i}; + + assign q_data_o = q_mem[q_read_addr]; + assign k_data_o = k_mem[k_read_addr]; + assign v_data_o = v_mem[v_read_addr]; + + integer i; + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + active_token <= 0; + active_projection <= 0; + + for (i = 0; i < 32; i = i + 1) begin + q_mem[i] <= 0; + k_mem[i] <= 0; + v_mem[i] <= 0; + end + end else begin + + // Keep metadata stable throughout GEMV + if (start_i) begin + active_token <= token_select_i; + active_projection <= projection_select_i; + end + + if (valid_feature) begin + case (active_projection) + 2'd0: + q_mem[write_addr] <= result_data_i[19:0]; + + 2'd1: + k_mem[write_addr] <= result_data_i[19:0]; + + 2'd2: + v_mem[write_addr] <= result_data_i[19:0]; + + default: ; + endcase + end + end + end + +endmodule \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py b/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py index c6642eb2..c37d2565 100644 --- a/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py +++ b/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py @@ -70,6 +70,16 @@ async def test_twelve_projection_gemvs(dut): dut.wght_wr_addr_i.value = 0 dut.wght_wr_data_i.value = 0 + # Q/K/V Buffer read interface + dut.q_rd_token_i.value = 0 + dut.q_rd_feature_i.value = 0 + + dut.k_rd_token_i.value = 0 + dut.k_rd_feature_i.value = 0 + + dut.v_rd_token_i.value = 0 + dut.v_rd_feature_i.value = 0 + cocotb.start_soon(check_dense_mode(dut)) cocotb.start_soon(Clock(dut.clk_i, 20, unit="ns").start()) @@ -229,4 +239,78 @@ async def test_twelve_projection_gemvs(dut): dut._log.info( "All 12 Q/K/V projection GEMVs PASSED without reset" - ) \ No newline at end of file + ) + # ===================================================== + # Verify complete Q/K/V matrices stored in FPGA buffers + # ===================================================== + + buffer_ports = { + "q": dut.q_data_o, + "k": dut.k_data_o, + "v": dut.v_data_o, + } + + for kind in ("q", "k", "v"): + + expected_matrix = x @ weights[kind] + + for token in range(4): + for feature in range(8): + + getattr(dut, f"{kind}_rd_token_i").value = token + getattr(dut, f"{kind}_rd_feature_i").value = feature + + await Timer(1, unit="ns") + + raw = int(buffer_ports[kind].value) + + # Signed 20-bit conversion + actual = raw + if actual & (1 << 19): + actual -= 1 << 20 + + expected = int(expected_matrix[token, feature]) + + assert actual == expected, ( + f"{kind.upper()} Buffer mismatch: " + f"token={token}, feature={feature}, " + f"expected={expected}, actual={actual}" + ) + + dut._log.info( + "%s Buffer PASSED: all 32 matrix elements verified", + kind.upper() + ) + + dut._log.info( + "All Q/K/V buffers verified: 96 matrix elements PASSED" + ) + # Verify independent simultaneous Q/K/V reads + dut.q_rd_token_i.value = 1 + dut.q_rd_feature_i.value = 3 + + dut.k_rd_token_i.value = 2 + dut.k_rd_feature_i.value = 5 + + dut.v_rd_token_i.value = 3 + dut.v_rd_feature_i.value = 1 + + await Timer(1, unit="ns") + + cases = [ + ("Q", dut.q_data_o, weights["q"], 1, 3), + ("K", dut.k_data_o, weights["k"], 2, 5), + ("V", dut.v_data_o, weights["v"], 3, 1), + ] + + for name, signal, weight, token, feature in cases: + raw = int(signal.value) + actual = raw - (1 << 20) if raw & (1 << 19) else raw + expected = int((x @ weight)[token, feature]) + + assert actual == expected, ( + f"{name} independent read failed: " + f"expected={expected}, actual={actual}" + ) + + dut._log.info("Independent Q/K/V address test PASSED") \ No newline at end of file From 6398beb111a0d0939b53514051e986894d19af8f Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sun, 25 Oct 2026 17:21:13 +0100 Subject: [PATCH 22/36] Add Q/K quantization controller and verification tests --- hdl/attention_qk_quantization_controller.v | 214 ++++++++++++++++++ .../analyze_qk_quantization_v2.py | 196 ++++++++++++++++ .../attention_gemv_projection_openeye_tb.py | 15 +- ...attention_qk_quantization_controller_tb.py | 126 +++++++++++ ...tion_qk_quantization_controller_test_top.v | 48 ++++ .../quantization_unit_tb.py | 89 ++++++++ ...st_attention_qk_quantization_controller.py | 21 ++ .../test_quantization_unit.py | 27 +++ 8 files changed, 734 insertions(+), 2 deletions(-) create mode 100644 hdl/attention_qk_quantization_controller.v create mode 100644 test/cocotb_attention_qkt/analyze_qk_quantization_v2.py create mode 100644 test/cocotb_attention_qkt/attention_qk_quantization_controller_tb.py create mode 100644 test/cocotb_attention_qkt/attention_qk_quantization_controller_test_top.v create mode 100644 test/cocotb_attention_qkt/quantization_unit_tb.py create mode 100644 test/cocotb_attention_qkt/test_attention_qk_quantization_controller.py create mode 100644 test/cocotb_attention_qkt/test_quantization_unit.py diff --git a/hdl/attention_qk_quantization_controller.v b/hdl/attention_qk_quantization_controller.v new file mode 100644 index 00000000..15dac777 --- /dev/null +++ b/hdl/attention_qk_quantization_controller.v @@ -0,0 +1,214 @@ +// Attention Q/K INT8 quantization controller. +// Reuses the UNMODIFIED OpenEye quantization_unit.v (two instances). +// Raw Q and K ports assume combinational/asynchronous reads, as implemented +// by attention_projection_result_buffer.v. +// Power-of-two per-tensor scale is chosen in RTL from max(abs(raw)). +// For bit-exact round-half-away-from-zero: mantissa=1, sign-dependent offset. +// Designed for Q,K [NUM_TOKENS x NUM_FEATURES]; defaults to 4 x 8. +`timescale 1ns/1ps + +module attention_qk_quantization_controller #( + parameter integer NUM_TOKENS = 4, + parameter integer NUM_FEATURES = 8, + parameter integer DATA_WIDTH = 20, + parameter integer SHIFT_WIDTH = 7, + parameter integer TOKEN_BITS = (NUM_TOKENS <= 1) ? 1 : $clog2(NUM_TOKENS), + parameter integer FEATURE_BITS = (NUM_FEATURES <= 1) ? 1 : $clog2(NUM_FEATURES), + parameter integer TOTAL = NUM_TOKENS * NUM_FEATURES, + parameter integer INDEX_BITS = (TOTAL <= 1) ? 1 : $clog2(TOTAL) +) ( + input wire clk_i, + input wire rst_ni, + input wire start_i, + output reg busy_o, + output reg done_o, // one-clock completion pulse + + // Read addresses into the existing RAW Q/K result buffer. + output wire [TOKEN_BITS-1:0] q_raw_rd_token_o, + output wire [FEATURE_BITS-1:0] q_raw_rd_feature_o, + output wire [TOKEN_BITS-1:0] k_raw_rd_token_o, + output wire [FEATURE_BITS-1:0] k_raw_rd_feature_o, + input wire signed [DATA_WIDTH-1:0] q_raw_data_i, + input wire signed [DATA_WIDTH-1:0] k_raw_data_i, + + // Independent read ports for quantized Q and K. + input wire [TOKEN_BITS-1:0] q8_rd_token_i, + input wire [FEATURE_BITS-1:0] q8_rd_feature_i, + input wire [TOKEN_BITS-1:0] k8_rd_token_i, + input wire [FEATURE_BITS-1:0] k8_rd_feature_i, + output wire signed [7:0] q8_data_o, + output wire signed [7:0] k8_data_o, + output reg [SHIFT_WIDTH-1:0] q_shift_o, + output reg [SHIFT_WIDTH-1:0] k_shift_o +); + localparam [2:0] IDLE=3'd0, SCAN=3'd1, PICK_SHIFT=3'd2, + FEED=3'd3, DRAIN=3'd4; + reg [2:0] state; + reg [INDEX_BITS-1:0] scan_index; + reg [INDEX_BITS-1:0] feed_index; + reg [DATA_WIDTH:0] q_max_abs; + reg [DATA_WIDTH:0] k_max_abs; + + // Delayed valid/address align with quantization_unit's 3-edge pipeline. + reg [2:0] valid_pipe; + reg [INDEX_BITS-1:0] addr_pipe0, addr_pipe1, addr_pipe2; + + reg signed [7:0] q8_mem [0:TOTAL-1]; + reg signed [7:0] k8_mem [0:TOTAL-1]; + + wire [INDEX_BITS-1:0] raw_read_index = + (state == SCAN) ? scan_index : feed_index; + + assign q_raw_rd_token_o = raw_read_index / NUM_FEATURES; + assign q_raw_rd_feature_o = raw_read_index % NUM_FEATURES; + assign k_raw_rd_token_o = raw_read_index / NUM_FEATURES; + assign k_raw_rd_feature_o = raw_read_index % NUM_FEATURES; + + wire [INDEX_BITS-1:0] q8_read_index = + q8_rd_token_i * NUM_FEATURES + q8_rd_feature_i; + wire [INDEX_BITS-1:0] k8_read_index = + k8_rd_token_i * NUM_FEATURES + k8_rd_feature_i; + assign q8_data_o = q8_mem[q8_read_index]; + assign k8_data_o = k8_mem[k8_read_index]; + + // Widen BEFORE abs(), so abs(minimum signed 20-bit value) is valid. + function [DATA_WIDTH:0] magnitude; + input signed [DATA_WIDTH-1:0] value; + reg signed [DATA_WIDTH:0] extended; + begin + extended = {value[DATA_WIDTH-1], value}; + magnitude = (extended < 0) ? -extended : extended; + end + endfunction + + // Smallest shift s with max(abs(value)) <= 127 * 2^s. + // For signed 20-bit raw data, s<=13. A signed W-bit value + // requires at most W-7 bits of downshift to fit signed INT8. + // The loop deliberately stops there to avoid shift-threshold overflow. + function [SHIFT_WIDTH-1:0] choose_shift; + input [DATA_WIDTH:0] maximum; + integer s; + reg [DATA_WIDTH:0] threshold; + begin + choose_shift = 0; + for (s=0; s<=DATA_WIDTH-7; s=s+1) begin + threshold = {{(DATA_WIDTH-6){1'b0}},7'd127} << s; + if (maximum > threshold) + choose_shift = s + 1; + end + end + endfunction + + wire [DATA_WIDTH:0] q_abs_now = magnitude(q_raw_data_i); + wire [DATA_WIDTH:0] k_abs_now = magnitude(k_raw_data_i); + + // A +half offset for nonnegative data, +(half-1) for negative. + // This converts arithmetic >>> (floor) into round-half-away-from-zero. + wire signed [DATA_WIDTH-1:0] q_offset = + (q_shift_o == 0) ? {DATA_WIDTH{1'b0}} : + (($signed({{(DATA_WIDTH-1){1'b0}},1'b1}) <<< (q_shift_o-1'b1)) + - (q_raw_data_i < 0 ? 1'b1 : 1'b0)); + wire signed [DATA_WIDTH-1:0] k_offset = + (k_shift_o == 0) ? {DATA_WIDTH{1'b0}} : + (($signed({{(DATA_WIDTH-1){1'b0}},1'b1}) <<< (k_shift_o-1'b1)) + - (k_raw_data_i < 0 ? 1'b1 : 1'b0)); + + wire signed [7:0] quantized_q; + wire signed [7:0] quantized_k; + quantization_unit #( + .PSUM_WIDTH(DATA_WIDTH), .MANT_WIDTH(25), + .OFFSET_WIDTH(DATA_WIDTH), .SHIFT_WIDTH(SHIFT_WIDTH), .OUT_WIDTH(8) + ) u_quant_q ( + .clk_i(clk_i), .rst_n(rst_ni), .quant_mant(25'sd1), + .psum_data(q_raw_data_i), .quant_offset(q_offset), + .current_shift(q_shift_o), .quantized_value(quantized_q) + ); + quantization_unit #( + .PSUM_WIDTH(DATA_WIDTH), .MANT_WIDTH(25), + .OFFSET_WIDTH(DATA_WIDTH), .SHIFT_WIDTH(SHIFT_WIDTH), .OUT_WIDTH(8) + ) u_quant_k ( + .clk_i(clk_i), .rst_n(rst_ni), .quant_mant(25'sd1), + .psum_data(k_raw_data_i), .quant_offset(k_offset), + .current_shift(k_shift_o), .quantized_value(quantized_k) + ); + + integer i; + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state <= IDLE; + scan_index <= 0; + feed_index <= 0; + q_max_abs <= 0; + k_max_abs <= 0; + q_shift_o <= 0; + k_shift_o <= 0; + valid_pipe <= 0; + addr_pipe0 <= 0; + addr_pipe1 <= 0; + addr_pipe2 <= 0; + busy_o <= 0; + done_o <= 0; + for (i=0; i q_max_abs) q_max_abs <= q_abs_now; + if (k_abs_now > k_max_abs) k_max_abs <= k_abs_now; + if (scan_index == TOTAL-1) begin + state <= PICK_SHIFT; + end else begin + scan_index <= scan_index + 1'b1; + end + end + PICK_SHIFT: begin + q_shift_o <= choose_shift(q_max_abs); + k_shift_o <= choose_shift(k_max_abs); + feed_index <= 0; + state <= FEED; + end + FEED: begin + if (feed_index == TOTAL-1) + state <= DRAIN; + else + feed_index <= feed_index + 1'b1; + end + DRAIN: begin + if (valid_pipe == 3'b000) begin + state <= IDLE; + busy_o <= 0; + done_o <= 1; + end + end + default: state <= IDLE; + endcase + end + end +endmodule diff --git a/test/cocotb_attention_qkt/analyze_qk_quantization_v2.py b/test/cocotb_attention_qkt/analyze_qk_quantization_v2.py new file mode 100644 index 00000000..282ac7e1 --- /dev/null +++ b/test/cocotb_attention_qkt/analyze_qk_quantization_v2.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python3 +"""Compare INT8 requantization candidates on verified OpenEye Q/K projection data. + +Place at test/cocotb_attention_qkt/analyze_qk_quantization.py and run from the +OpenEye repository root: + python test/cocotb_attention_qkt/analyze_qk_quantization.py \ + test/cocotb_attention_qkt/data/qk_raw_projection.npz + +The saved NPZ must contain two 2-D integer arrays named q_raw and k_raw. +""" + +import argparse +import csv +from pathlib import Path +import sys + +import numpy as np + +# Import the actual Phase-0 quantization reference from the project rather +# than silently creating another potentially divergent specification. +ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(ROOT / "src")) +from open_eye.attention_scheduler import requantize_pow2 # noqa: E402 + + +def quantize_power_of_two(raw, per_row): + raw = np.asarray(raw, dtype=np.int64) + if per_row: + rows = [requantize_pow2(row) for row in raw] + q = np.stack([pair[0] for pair in rows]) + shifts = np.array([pair[1] for pair in rows], dtype=np.int64) + else: + q, shift = requantize_pow2(raw) + shifts = np.full(raw.shape[0], shift, dtype=np.int64) + # inverse scale = 2**shift: approximate raw = q * inverse scale + inverse_scales = np.power(2.0, shifts.astype(np.float64)) + return q, inverse_scales, {"shift": shifts.tolist()} + + +def quantize_existing_openeye(raw): + """Calibrated per-row quantization using the existing RTL formula. + + quantized_value = (mant * (psum + offset)) >>> exponent + + offset = 0, exponent = 20 (when scaling needed), and mantissa is a + positive 25-bit signed integer. The scale is bounded to avoid output + overflow since the RTL does not saturate. + + This models Verilog signed arithmetic right-shift with Python/NumPy >>. + """ + raw = np.asarray(raw, dtype=np.int64) + result = np.empty_like(raw) + inverse_scales = np.empty(raw.shape[0], dtype=np.float64) + mantissas = [] + exponents = [] + for idx, row in enumerate(raw): + max_abs = int(np.max(np.abs(row))) if row.size else 0 + if max_abs <= 127: + mant, exponent = 1, 0 # Already representable exactly as INT8 + else: + exponent = 20 + mant = (127 << exponent) // max_abs + assert 0 < mant < (1 << 24), "Mantissa must fit signed 25-bit" + q_row = (row * mant) >> exponent + assert np.all((-128 <= q_row) & (q_row <= 127)), ( + "Unsafe quantizer configuration: signed INT8 overflow" + ) + result[idx] = q_row + inverse_scales[idx] = (2**exponent) / mant + mantissas.append(mant) + exponents.append(exponent) + return result, inverse_scales, { + "mantissa": mantissas, "exponent": exponents, "offset": [0] * len(mantissas) + } + + +def quantize_openeye_per_tensor_pow2(raw): + """Bit-exact model of the existing quantization_unit.v in pow2 mode. + + quant_mant=1, quant_offset=0, exponent=dynamic shift chosen to avoid + signed INT8 overflow. Verilog signed >>> corresponds to NumPy >>, + which rounds toward negative infinity (not nearest). + """ + raw = np.asarray(raw, dtype=np.int64) + max_abs = int(np.max(np.abs(raw))) if raw.size else 0 + shift = 0 + while max_abs > (127 << shift): + shift += 1 + quant = raw >> shift + assert np.all((-128 <= quant) & (quant <= 127)), "INT8 overflow" + return quant, np.full(raw.shape[0], float(2**shift)), { + "mantissa": [1] * raw.shape[0], + "exponent": [shift] * raw.shape[0], + "offset": [0] * raw.shape[0], + } + + +def quantize_openeye_per_tensor_mantissa(raw): + """Bit-exact arithmetic of existing RTL with one calibrated scale/tensor. + + Finds a representable 25-bit signed mantissa and shift; this is an + illustrative max-absolute-value calibration, not an optimized solution. + """ + raw = np.asarray(raw, dtype=np.int64) + max_abs = int(np.max(np.abs(raw))) if raw.size else 0 + if max_abs <= 127: + mantissa, exponent = 1, 0 + else: + exponent = 20 + mantissa = (127 << exponent) // max_abs + assert 0 < mantissa < (1 << 24), "Mantissa does not fit signed 25 bits" + quant = (raw * mantissa) >> exponent + assert np.all((-128 <= quant) & (quant <= 127)), "INT8 overflow" + return quant, np.full(raw.shape[0], (2**exponent) / mantissa), { + "mantissa": [mantissa] * raw.shape[0], + "exponent": [exponent] * raw.shape[0], + "offset": [0] * raw.shape[0], + } + + +def evaluate(label, q_raw, k_raw, converter): + q8, q_invscale, q_param = converter(q_raw) + k8, k_invscale, k_param = converter(k_raw) + + q_recon = q8.astype(np.float64) * q_invscale[:, None] + k_recon = k8.astype(np.float64) * k_invscale[:, None] + s_ref = q_raw.astype(np.float64) @ k_raw.astype(np.float64).T + # The following correctly uses distinct per-row scales for Q and K. + s_int = q8.astype(np.int64) @ k8.astype(np.int64).T + s_recon = s_int.astype(np.float64) * q_invscale[:, None] * k_invscale[None, :] + error = s_recon - s_ref + q_zero = int(np.count_nonzero((q_raw != 0) & (q8 == 0))) + k_zero = int(np.count_nonzero((k_raw != 0) & (k8 == 0))) + denom = float(np.linalg.norm(s_ref)) + relative_error = float(np.linalg.norm(error)) / denom if denom else float(np.linalg.norm(error)) + result = { + "method": label, + "q_lost_nonzero": q_zero, + "k_lost_nonzero": k_zero, + "q_mae": float(np.mean(np.abs(q_recon - q_raw))), + "k_mae": float(np.mean(np.abs(k_recon - k_raw))), + "score_mae": float(np.mean(np.abs(error))), + "score_max_abs_error": float(np.max(np.abs(error))), + "score_rel_frobenius_pct": relative_error * 100.0, + } + return result, q_param, k_param + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("input", type=Path, help="NPZ with integer q_raw and k_raw") + args = parser.parse_args() + if not args.input.is_file(): + parser.error(f"Input not found: {args.input} (run the projection Cocotb test to export it)") + with np.load(args.input, allow_pickle=False) as data: + q_raw = np.asarray(data["q_raw"], dtype=np.int64) + k_raw = np.asarray(data["k_raw"], dtype=np.int64) + if q_raw.ndim != 2 or k_raw.ndim != 2 or q_raw.shape[1] != k_raw.shape[1]: + parser.error(f"Expected compatible 2D matrices, got Q={q_raw.shape}, K={k_raw.shape}") + if np.max(np.abs(q_raw)) > 524288 or np.max(np.abs(k_raw)) > 524288: + parser.error("Input contains values outside the expected signed 20-bit range") + + methods = [ + ("Per-tensor Pow2", lambda raw: quantize_power_of_two(raw, False)), + ("Per-row Pow2", lambda raw: quantize_power_of_two(raw, True)), + ("Per-row OpenEye mantissa/exp", quantize_existing_openeye), + ("Per-tensor OpenEye m=1 / shift", quantize_openeye_per_tensor_pow2), + ("Per-tensor OpenEye mantissa/exp", quantize_openeye_per_tensor_mantissa), + ] + print(f"Projection data: Q={q_raw.shape}, K={k_raw.shape}") + print(f"Original nonzero values: Q={np.count_nonzero(q_raw)}, K={np.count_nonzero(k_raw)}") + print(f"Max absolute: Q={np.max(np.abs(q_raw))}, K={np.max(np.abs(k_raw))}\n") + + rows = [] + for name, converter in methods: + result, q_param, k_param = evaluate(name, q_raw, k_raw, converter) + rows.append(result) + print(name) + print(f" New zeros: Q={result['q_lost_nonzero']}, K={result['k_lost_nonzero']}") + print(f" Reconstructed Q/K MAE: {result['q_mae']:.5g} / {result['k_mae']:.5g}") + print(f" QK^T score MAE: {result['score_mae']:.5g}") + print(f" QK^T relative Frobenius error: {result['score_rel_frobenius_pct']:.5g}%") + print(f" Q parameters: {q_param}") + print(f" K parameters: {k_param}\n") + + outfile = args.input.parent / "qk_quantization_comparison.csv" + with outfile.open("w", encoding="utf-8", newline="") as f: + writer = csv.DictWriter(f, fieldnames=list(rows[0])) + writer.writeheader() + writer.writerows(rows) + print(f"Saved summary to: {outfile}") + print("Note: This is a numerical comparison; it does not yet test the RTL controller/feedback.") + + +if __name__ == "__main__": + main() diff --git a/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py b/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py index c37d2565..9b06cc80 100644 --- a/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py +++ b/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py @@ -3,7 +3,6 @@ # Verifies DMA streams, GEMV results, and selector stability. from pathlib import Path - import cocotb import numpy as np from cocotb.clock import Clock @@ -313,4 +312,16 @@ async def test_twelve_projection_gemvs(dut): f"expected={expected}, actual={actual}" ) - dut._log.info("Independent Q/K/V address test PASSED") \ No newline at end of file + dut._log.info("Independent Q/K/V address test PASSED") + + + data_dir = Path(__file__).resolve().parent / "data" + data_dir.mkdir(parents=True, exist_ok=True) + + np.savez( + data_dir / "qk_raw_projection.npz", + q_raw=np.asarray(x @ weights["q"], dtype=np.int64), + k_raw=np.asarray(x @ weights["k"], dtype=np.int64), + ) + + dut._log.info("Q/K raw matrices exported for quantization analysis") \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_qk_quantization_controller_tb.py b/test/cocotb_attention_qkt/attention_qk_quantization_controller_tb.py new file mode 100644 index 00000000..4209429f --- /dev/null +++ b/test/cocotb_attention_qkt/attention_qk_quantization_controller_tb.py @@ -0,0 +1,126 @@ +"""Verify dynamic RTL shifts, correct pipeline writeback, and independent Q8/K8 reads.""" +import sys +from pathlib import Path + +import cocotb +import numpy as np +from cocotb.triggers import Timer + +REPO_ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(REPO_ROOT / "src")) +from open_eye.attention_scheduler import requantize_pow2 # noqa: E402 + + +def signed(raw, bits): + raw &= (1 << bits) - 1 + return raw - (1 << bits) if raw & (1 << (bits-1)) else raw + + +async def tick(dut): + dut.clk_i.value = 0 + await Timer(5, unit="ns") + dut.clk_i.value = 1 + await Timer(5, unit="ns") + + +async def load_and_run(dut, q, k, label): + q = np.asarray(q, dtype=np.int64).reshape(4, 8) + k = np.asarray(k, dtype=np.int64).reshape(4, 8) + assert np.max(np.abs(q)) <= (1 << 19) + assert np.max(np.abs(k)) <= (1 << 19) + for idx in range(32): + dut.raw_wr_index_i.value = idx + dut.raw_wr_q_data_i.value = int(q.flat[idx]) & ((1 << 20)-1) + dut.raw_wr_k_data_i.value = int(k.flat[idx]) & ((1 << 20)-1) + dut.raw_wr_en_i.value = 1 + await tick(dut) + dut.raw_wr_en_i.value = 0 + + golden_q, qshift = requantize_pow2(q) + golden_k, kshift = requantize_pow2(k) + dut.start_i.value = 1 + await tick(dut) + dut.start_i.value = 0 + assert int(dut.busy_o.value) == 1 + completed = False + for cycle in range(120): + await tick(dut) + if int(dut.done_o.value): + completed = True + break + assert completed, f"{label}: controller did not finish within 120 clocks" + assert int(dut.busy_o.value) == 0 + assert int(dut.q_shift_o.value) == qshift, f"{label}: Q shift" + assert int(dut.k_shift_o.value) == kshift, f"{label}: K shift" + + for qt in range(4): + for qf in range(8): + # Intentionally read unrelated Q and K addresses in the same cycle. + kt, kf = (qt + 1) % 4, (qf + 3) % 8 + dut.q8_rd_token_i.value = qt + dut.q8_rd_feature_i.value = qf + dut.k8_rd_token_i.value = kt + dut.k8_rd_feature_i.value = kf + await Timer(1, unit="ns") + qseen = signed(int(dut.q8_data_o.value), 8) + kseen = signed(int(dut.k8_data_o.value), 8) + assert qseen == golden_q[qt, qf], ( + f"{label} Q[{qt},{qf}] expected={golden_q[qt,qf]} got={qseen}" + ) + assert kseen == golden_k[kt, kf], ( + f"{label} K[{kt},{kf}] expected={golden_k[kt,kf]} got={kseen}" + ) + + dut._log.info("PASS %s: Q-shift=%s, K-shift=%s, cycles=%s, 64/64 values match", + label, qshift, kshift, cycle + 1) + + if label == "real-projection": + s_ref = q.astype(np.float64) @ k.astype(np.float64).T + s_rec = (golden_q @ golden_k.T).astype(np.float64) * (2**(qshift+kshift)) + rel = np.linalg.norm(s_rec-s_ref)/np.linalg.norm(s_ref)*100 + dut._log.info("Real QK^T score reconstructed relative Frobenius error = %.6f%%", rel) + assert abs(rel - 0.45688) < 0.001, f"unexpected baseline: {rel}" + + +@cocotb.test() +async def test_existing_openeye_quantizer_with_rtl_controller(dut): + dut.clk_i.value = 0 + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.raw_wr_en_i.value = 0 + dut.raw_wr_index_i.value = 0 + dut.raw_wr_q_data_i.value = 0 + dut.raw_wr_k_data_i.value = 0 + dut.q8_rd_token_i.value = 0 + dut.q8_rd_feature_i.value = 0 + dut.k8_rd_token_i.value = 0 + dut.k8_rd_feature_i.value = 0 + await tick(dut) + dut.rst_ni.value = 1 + + data_file = Path(__file__).resolve().parent / "data" / "qk_raw_projection.npz" + if not data_file.exists(): + raise FileNotFoundError(f"Please run your Projection test first: {data_file}") + with np.load(data_file, allow_pickle=False) as data: + await load_and_run(dut, data["q_raw"], data["k_raw"], "real-projection") + + # Shift=0; no rounding or writeback address can be incorrect. + q = np.arange(-16, 16, dtype=np.int64).reshape(4, 8) + k = -q + await load_and_run(dut, q, k, "shift-zero") + + # Signed-20 extreme and small entries; catch abs(-524288) overflow. + q = np.array([-524288, 524287, 1, -1, 31, -31, 32, -32] * 4).reshape(4, 8) + k = np.array([524287, -524288, -7, 7, 63, -63, 64, -64] * 4).reshape(4, 8) + await load_and_run(dut, q, k, "20-bit-extremes") + + # Zero-only input must give zero shift and zero output, without stale data. + z = np.zeros((4, 8), dtype=np.int64) + await load_and_run(dut, z, z, "all-zero") + + # Different shifts for Q and K, deliberately placed maxima at LAST address. + q = np.array([3, -6, 18, -27] * 8, dtype=np.int64).reshape(4,8) + k = np.array([30, -50, 210, -300] * 8, dtype=np.int64).reshape(4,8) + q[-1,-1] = 127 + k[-1,-1] = 8129 + await load_and_run(dut, q, k, "independent-shifts-last-element") diff --git a/test/cocotb_attention_qkt/attention_qk_quantization_controller_test_top.v b/test/cocotb_attention_qkt/attention_qk_quantization_controller_test_top.v new file mode 100644 index 00000000..cadeaa67 --- /dev/null +++ b/test/cocotb_attention_qkt/attention_qk_quantization_controller_test_top.v @@ -0,0 +1,48 @@ +`timescale 1ns/1ps +// Isolated test wrapper. Models the EXISTING result buffer's combinational +// read ports, and allows Cocotb to preload raw matrices without OpenEye GEMVs. +module attention_qk_quantization_controller_test_top ( + input wire clk_i, + input wire rst_ni, + input wire start_i, + input wire raw_wr_en_i, + input wire [4:0] raw_wr_index_i, + input wire signed [19:0] raw_wr_q_data_i, + input wire signed [19:0] raw_wr_k_data_i, + input wire [1:0] q8_rd_token_i, + input wire [2:0] q8_rd_feature_i, + input wire [1:0] k8_rd_token_i, + input wire [2:0] k8_rd_feature_i, + output wire signed [7:0] q8_data_o, + output wire signed [7:0] k8_data_o, + output wire [6:0] q_shift_o, + output wire [6:0] k_shift_o, + output wire busy_o, + output wire done_o +); + reg signed [19:0] raw_q [0:31]; + reg signed [19:0] raw_k [0:31]; + wire [1:0] q_tok, k_tok; + wire [2:0] q_feat, k_feat; + wire signed [19:0] q_data = raw_q[{q_tok,q_feat}]; + wire signed [19:0] k_data = raw_k[{k_tok,k_feat}]; + + always @(posedge clk_i) begin + if (raw_wr_en_i) begin + raw_q[raw_wr_index_i] <= raw_wr_q_data_i; + raw_k[raw_wr_index_i] <= raw_wr_k_data_i; + end + end + + attention_qk_quantization_controller u_ctrl ( + .clk_i(clk_i), .rst_ni(rst_ni), .start_i(start_i), + .busy_o(busy_o), .done_o(done_o), + .q_raw_rd_token_o(q_tok), .q_raw_rd_feature_o(q_feat), + .k_raw_rd_token_o(k_tok), .k_raw_rd_feature_o(k_feat), + .q_raw_data_i(q_data), .k_raw_data_i(k_data), + .q8_rd_token_i(q8_rd_token_i), .q8_rd_feature_i(q8_rd_feature_i), + .k8_rd_token_i(k8_rd_token_i), .k8_rd_feature_i(k8_rd_feature_i), + .q8_data_o(q8_data_o), .k8_data_o(k8_data_o), + .q_shift_o(q_shift_o), .k_shift_o(k_shift_o) + ); +endmodule diff --git a/test/cocotb_attention_qkt/quantization_unit_tb.py b/test/cocotb_attention_qkt/quantization_unit_tb.py new file mode 100644 index 00000000..0666e351 --- /dev/null +++ b/test/cocotb_attention_qkt/quantization_unit_tb.py @@ -0,0 +1,89 @@ +"""Characterization of the unchanged OpenEye quantization_unit.v. + +Expected behavior: signed (psum + offset) * mantissa, arithmetic shift, +then 8-bit truncation (NOT rounding or saturation), with 3-stage latency. +""" + +import cocotb +from cocotb.triggers import Timer + + +def signed_bits(bits: int, width: int) -> int: + bits &= (1 << width) - 1 + return bits - (1 << width) if bits & (1 << (width - 1)) else bits + + +def reference(psum: int, mant: int, offset: int, shift: int) -> int: + # Python's right shift of signed integers rounds toward -infinity, + # like Verilog's arithmetic >>> on a signed operand. + shifted = (mant * (psum + offset)) >> shift + return signed_bits(shifted, 8) # Actual RTL truncates to 8 bits. + + +async def tick(dut, *, psum=0, mant=1, offset=0, shift=0): + """One complete clock cycle, safely sampling outputs after the edge.""" + dut.clk_i.value = 0 + dut.psum_data.value = psum & ((1 << 20) - 1) + dut.quant_mant.value = mant & ((1 << 25) - 1) + dut.quant_offset.value = offset & 0xFF + dut.current_shift.value = shift + await Timer(5, unit="ns") + dut.clk_i.value = 1 + await Timer(5, unit="ns") + return signed_bits(int(dut.quantized_value.value), 8) + + +@cocotb.test() +async def test_existing_quantizer_pipeline(dut): + """Verify sign handling, scale, zeroing, wraparound, and 3-cycle pipeline.""" + dut.clk_i.value = 0 + dut.rst_n.value = 0 + dut.psum_data.value = 0 + dut.quant_mant.value = 0 + dut.quant_offset.value = 0 + dut.current_shift.value = 0 + await tick(dut) + assert int(dut.quantized_value.value) == 0, "Reset did not clear output" + dut.rst_n.value = 1 + + # (signed 20-bit PSUM, signed 25-bit mantissa, signed 8-bit offset, shift) + vectors = [ + (0, 1, 0, 0), # Zero stays zero + (3, 1, 0, 3), # Small positive becomes ZERO + (-2, 1, 0, 3), # Arithmetic shift: -2 >>> 3 becomes -1 + (700, 1, 0, 3), # 87 (truncation, not round-to-nearest 88) + (-700, 1, 0, 3), # -88 + (12, 5, -2, 1), # Mantissa and signed offset: 25 + (200, 1, 0, 0), # 200 wraps to -56 (no saturation) + (-200, 1, 0, 0), # -200 wraps to +56 + (127, 1, 0, 0), # INT8 upper endpoint + (-128, 1, 0, 0), # INT8 lower endpoint + (400, 2, 0, 4), # More than one mantissa factor + (-400, 2, 0, 4), + (32, -3, 0, 3), # Negative mantissa + (524287, 1, 0, 13), # Max signed 20-bit PSUM + (-524288, 1, 0, 13),# Min signed 20-bit PSUM + (1, 1, 0, 7), # Positive quantization-to-zero + (-1, 1, 0, 7), # Negative floors to -1 + (0, 1, 5, 0), # Offset is added before scaling + (0, 1, -5, 0), + (700, 3, 0, 5), # Fractional multiplier 3/32 + (-700, 3, 0, 5), + ] + + # No valid_out in RTL, so associate outputs with the inputs from + # two rising edges earlier (3-stage pipeline: S1/S2/S3). + for cycle in range(len(vectors) + 2): + sample = vectors[cycle] if cycle < len(vectors) else (0, 1, 0, 0) + actual = await tick(dut, psum=sample[0], mant=sample[1], + offset=sample[2], shift=sample[3]) + if cycle >= 2: + original_index = cycle - 2 + expected = reference(*vectors[original_index]) + assert actual == expected, ( + f"Mismatch for input #{original_index} " + f"{vectors[original_index]}: expected {expected}, got {actual}" + ) + + dut._log.info("PASS: all %d signed/pipeline quantizer cases", len(vectors)) + dut._log.info("Confirmed: arithmetic shift, no rounding, no saturation") diff --git a/test/cocotb_attention_qkt/test_attention_qk_quantization_controller.py b/test/cocotb_attention_qkt/test_attention_qk_quantization_controller.py new file mode 100644 index 00000000..b3128980 --- /dev/null +++ b/test/cocotb_attention_qkt/test_attention_qk_quantization_controller.py @@ -0,0 +1,21 @@ +"""Independent RTL controller+existing quantization_unit end-to-end test.""" +from pathlib import Path +from cocotb_test.simulator import run + + +def test_qk_quantization_controller(): + test_dir = Path(__file__).resolve().parent + root = test_dir.parents[1] + run( + verilog_sources=[ + str(root / "hdl" / "quantization_unit.v"), + str(root / "hdl" / "attention_qk_quantization_controller.v"), + str(test_dir / "attention_qk_quantization_controller_test_top.v"), + ], + toplevel="attention_qk_quantization_controller_test_top", + module="attention_qk_quantization_controller_tb", + python_search=[str(test_dir)], + simulator="icarus", + sim_build=str(test_dir / ".sim_build_qk_controller"), + waves=False, + ) diff --git a/test/cocotb_attention_qkt/test_quantization_unit.py b/test/cocotb_attention_qkt/test_quantization_unit.py new file mode 100644 index 00000000..99df906e --- /dev/null +++ b/test/cocotb_attention_qkt/test_quantization_unit.py @@ -0,0 +1,27 @@ +"""Standalone pytest runner for OpenEye's *existing* quantization_unit.v.""" + +from pathlib import Path + +from cocotb_test.simulator import run + + +def test_quantization_unit(): + test_dir = Path(__file__).resolve().parent + repo_root = test_dir.parent.parent + + run( + verilog_sources=[str(repo_root / "hdl" / "quantization_unit.v")], + toplevel="quantization_unit", + module="quantization_unit_tb", + python_search=[str(test_dir)], + simulator="icarus", + parameters={ + "PSUM_WIDTH": 20, + "MANT_WIDTH": 25, + "OFFSET_WIDTH": 8, + "SHIFT_WIDTH": 7, + "OUT_WIDTH": 8, + }, + sim_build=str(test_dir / ".sim_build_quantization_unit"), + waves=False, + ) From 7ce34018ed912b22e9a11597e0a48e447510d681 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sun, 25 Oct 2026 22:55:05 +0100 Subject: [PATCH 23/36] Integrate Q/K hardware quantization with OpenEye projection --- hdl/attention_gemv_projection_openeye_top.v | 117 +++++++++++- .../attention_gemv_projection_openeye_tb.py | 176 +++++++++++++++++- .../test_attention_gemv_projection_openeye.py | 1 + 3 files changed, 287 insertions(+), 7 deletions(-) diff --git a/hdl/attention_gemv_projection_openeye_top.v b/hdl/attention_gemv_projection_openeye_top.v index 9d9ff664..79e85407 100644 --- a/hdl/attention_gemv_projection_openeye_top.v +++ b/hdl/attention_gemv_projection_openeye_top.v @@ -54,6 +54,25 @@ module attention_projection_openeye_top #( output wire [19:0] k_data_o, output wire [19:0] v_data_o, + // Quantization control interface + input wire quant_start_i, + output wire quant_busy_o, + output wire quant_done_o, + + // Quantized Q8 read interface + input wire [1:0] q8_rd_token_i, + input wire [2:0] q8_rd_feature_i, + output wire signed [7:0] q8_data_o, + + // Quantized K8 read interface + input wire [1:0] k8_rd_token_i, + input wire [2:0] k8_rd_feature_i, + output wire signed [7:0] k8_data_o, + + // Quantization scaling factors + output wire [6:0] q_shift_o, + output wire [6:0] k_shift_o, + // Debug address output wire [ADDR_WIDTH-1:0] stream_addr_o ); @@ -70,6 +89,20 @@ module attention_projection_openeye_top #( wire dma_output_valid; wire dma_output_last; wire dma_output_ready; + + //========================================================== + // Start signals for the projection and quantization operations + wire projection_start; + wire quant_start; + + assign projection_start = start_i && !quant_busy_o; + + assign quant_start = + quant_start_i && + !start_i && + !busy_o && + !adapter_busy_o && + !result_write_o; //========================================================== // Controller + DMA Adapter + ROM @@ -83,7 +116,7 @@ module attention_projection_openeye_top #( .clk_i (clk_i), .rst_ni (rst_ni), - .start_i (start_i), + .start_i (projection_start), .token_select_i (token_select_i), .projection_select_i (projection_select_i), @@ -119,6 +152,33 @@ module attention_projection_openeye_top #( .stream_addr_o (stream_addr_o) ); + + // Read addresses generated by quantization controller + wire [1:0] quant_q_rd_token; + wire [2:0] quant_q_rd_feature; + + wire [1:0] quant_k_rd_token; + wire [2:0] quant_k_rd_feature; + + // Address multiplexers + wire [1:0] raw_q_rd_token; + wire [2:0] raw_q_rd_feature; + + wire [1:0] raw_k_rd_token; + wire [2:0] raw_k_rd_feature; + + assign raw_q_rd_token = + quant_busy_o ? quant_q_rd_token : q_rd_token_i; + + assign raw_q_rd_feature = + quant_busy_o ? quant_q_rd_feature : q_rd_feature_i; + + assign raw_k_rd_token = + quant_busy_o ? quant_k_rd_token : k_rd_token_i; + + assign raw_k_rd_feature = + quant_busy_o ? quant_k_rd_feature : k_rd_feature_i; + //========================================================== // Q/K/V Projection Result Buffer //========================================================== @@ -129,7 +189,7 @@ module attention_projection_openeye_top #( .rst_ni (rst_ni), // Capture the selected operation - .start_i (start_i), + .start_i (projection_start), .token_select_i (token_select_i), .projection_select_i(projection_select_i), @@ -138,11 +198,11 @@ module attention_projection_openeye_top #( .result_addr_i (result_addr_o), .result_data_i (result_data_o), - .q_rd_token_i (q_rd_token_i), - .q_rd_feature_i (q_rd_feature_i), + .q_rd_token_i (raw_q_rd_token), + .q_rd_feature_i (raw_q_rd_feature), - .k_rd_token_i (k_rd_token_i), - .k_rd_feature_i (k_rd_feature_i), + .k_rd_token_i (raw_k_rd_token), + .k_rd_feature_i (raw_k_rd_feature), .v_rd_token_i (v_rd_token_i), .v_rd_feature_i (v_rd_feature_i), @@ -152,6 +212,51 @@ module attention_projection_openeye_top #( .v_data_o (v_data_o) ); + + //========================================================== + // Q/K Quantization Controller + //========================================================== + + attention_qk_quantization_controller #( + .NUM_TOKENS (4), + .NUM_FEATURES (8), + .DATA_WIDTH (20), + .SHIFT_WIDTH (7) + ) u_qk_quant_controller ( + + .clk_i (clk_i), + .rst_ni (rst_ni), + + // Control + .start_i (quant_start), + .busy_o (quant_busy_o), + .done_o (quant_done_o), + + // Raw Q read interface + .q_raw_rd_token_o (quant_q_rd_token), + .q_raw_rd_feature_o (quant_q_rd_feature), + .q_raw_data_i (q_data_o), + + // Raw K read interface + .k_raw_rd_token_o (quant_k_rd_token), + .k_raw_rd_feature_o (quant_k_rd_feature), + .k_raw_data_i (k_data_o), + + // Quantized Q8 read interface + .q8_rd_token_i (q8_rd_token_i), + .q8_rd_feature_i (q8_rd_feature_i), + .q8_data_o (q8_data_o), + + // Quantized K8 read interface + .k8_rd_token_i (k8_rd_token_i), + .k8_rd_feature_i (k8_rd_feature_i), + .k8_data_o (k8_data_o), + + // Scaling factors + .q_shift_o (q_shift_o), + .k_shift_o (k_shift_o) + ); + //========================================================== // Real OpenEye accelerator //========================================================== diff --git a/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py b/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py index 9b06cc80..391c05c1 100644 --- a/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py +++ b/test/cocotb_attention_qkt/attention_gemv_projection_openeye_tb.py @@ -8,6 +8,31 @@ from cocotb.clock import Clock from cocotb.triggers import RisingEdge, FallingEdge, ReadOnly, Timer +def reference_quantize(raw): + + values = np.asarray(raw, dtype=np.int64) + + max_abs = int(np.max(np.abs(values))) + + shift = 0 + while max_abs > (127 << shift): + shift += 1 + + if shift == 0: + quantized = values + else: + half = 1 << (shift - 1) + + quantized = np.where( + values >= 0, + (values + half) >> shift, + -((-values + half) >> shift) + ) + + quantized = np.clip(quantized, -128, 127) + + return quantized.astype(np.int64), shift + async def check_dense_mode(dut): fpga = dut.u_openeye @@ -79,6 +104,17 @@ async def test_twelve_projection_gemvs(dut): dut.v_rd_token_i.value = 0 dut.v_rd_feature_i.value = 0 + # Quantization controller + dut.quant_start_i.value = 0 + + # Q8 read interface + dut.q8_rd_token_i.value = 0 + dut.q8_rd_feature_i.value = 0 + + # K8 read interface + dut.k8_rd_token_i.value = 0 + dut.k8_rd_feature_i.value = 0 + cocotb.start_soon(check_dense_mode(dut)) cocotb.start_soon(Clock(dut.clk_i, 20, unit="ns").start()) @@ -324,4 +360,142 @@ async def test_twelve_projection_gemvs(dut): k_raw=np.asarray(x @ weights["k"], dtype=np.int64), ) - dut._log.info("Q/K raw matrices exported for quantization analysis") \ No newline at end of file + dut._log.info("Q/K raw matrices exported for quantization analysis") + + # ===================================================== + # Q/K Quantization Integration Test + # ===================================================== + + dut._log.info("Starting Q/K hardware quantization") + + # Python reference + q_raw = x @ weights["q"] + k_raw = x @ weights["k"] + + q8_expected, q_shift_expected = reference_quantize(q_raw) + k8_expected, k_shift_expected = reference_quantize(k_raw) + + # Start the RTL quantization controller + assert int(dut.busy_o.value) == 0 + assert int(dut.adapter_busy_o.value) == 0 + + dut.quant_start_i.value = 1 + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + dut.quant_start_i.value = 0 + + assert int(dut.quant_busy_o.value) == 1, ( + "Quantization controller did not start" + ) + + # Wait until quantization finishes + for cycle in range(160): + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + if int(dut.quant_done_o.value): + break + + else: + raise AssertionError("Q/K Quantization timeout") + + dut._log.info( + "Quantization finished after %d cycles", + cycle + 1 + ) + + # ===================================================== + # Verify Q/K shifts + # ===================================================== + + q_shift_actual = int(dut.q_shift_o.value) + k_shift_actual = int(dut.k_shift_o.value) + + assert q_shift_actual == q_shift_expected + assert k_shift_actual == k_shift_expected + + dut._log.info( + "Shift verification PASSED: Q=%d, K=%d", + q_shift_actual, + k_shift_actual + ) + + # ===================================================== + # Verify all 64 Q8/K8 elements + # ===================================================== + + q8_actual = np.zeros((4, 8), dtype=np.int64) + k8_actual = np.zeros((4, 8), dtype=np.int64) + + for token in range(4): + for feature in range(8): + + dut.q8_rd_token_i.value = token + dut.q8_rd_feature_i.value = feature + + dut.k8_rd_token_i.value = token + dut.k8_rd_feature_i.value = feature + + await Timer(1, unit="ns") + + q_value = int(dut.q8_data_o.value) & 0xFF + k_value = int(dut.k8_data_o.value) & 0xFF + + # Convert 8-bit Two's Complement + if q_value & 0x80: + q_value -= 256 + + if k_value & 0x80: + k_value -= 256 + + q8_actual[token, feature] = q_value + k8_actual[token, feature] = k_value + + assert q_value == q8_expected[token, feature], ( + f"Q8 mismatch: token={token}, feature={feature}, " + f"expected={q8_expected[token, feature]}, " + f"actual={q_value}" + ) + + assert k_value == k8_expected[token, feature], ( + f"K8 mismatch: token={token}, feature={feature}, " + f"expected={k8_expected[token, feature]}, " + f"actual={k_value}" + ) + + dut._log.info( + "Q8/K8 Buffer PASSED: all 64 elements verified" + ) + + # ===================================================== + # Quantization accuracy evaluation + # ===================================================== + + original_scores = q_raw @ k_raw.T + + quantized_scores = q8_actual @ k8_actual.T + + reconstructed_scores = ( + quantized_scores * + (1 << (q_shift_actual + k_shift_actual)) + ) + + relative_error = ( + np.linalg.norm( + (reconstructed_scores - original_scores).astype(np.float64) + ) + / + np.linalg.norm(original_scores.astype(np.float64)) + ) * 100 + + dut._log.info( + "QK^T relative quantization error: %.6f%%", + relative_error + ) + + dut._log.info( + "FULL PROJECTION -> Q/K BUFFER -> QUANTIZATION PASSED" + ) \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py b/test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py index 5c5a9c31..44214eb0 100644 --- a/test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py +++ b/test/cocotb_attention_qkt/test_attention_gemv_projection_openeye.py @@ -9,6 +9,7 @@ import open_eye.generator as generator from open_eye import hdl_dir +from sympy import root def test_attention_projection_openeye_top(): From 082cbc575f5f508eaa8bef36915c265e79f7c484 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Mon, 26 Oct 2026 19:08:12 +0100 Subject: [PATCH 24/36] test(attention): verify single QKT GEMV bit-exact on OpenEye RTL --- .../data/qkt_single_8x4/qkt_t0_dma.mem | 677 ++++++++++++++++++ .../data/qkt_single_8x4/qkt_t0_reference.npz | Bin 0 -> 1794 bytes .../prepare_qkt_single_8x4.py | 66 ++ .../qkt_single_openeye_tb.py | 115 +++ .../test_qkt_single_openeye.py | 62 ++ 5 files changed, 920 insertions(+) create mode 100644 test/cocotb_attention_qkt/data/qkt_single_8x4/qkt_t0_dma.mem create mode 100644 test/cocotb_attention_qkt/data/qkt_single_8x4/qkt_t0_reference.npz create mode 100644 test/cocotb_attention_qkt/prepare_qkt_single_8x4.py create mode 100644 test/cocotb_attention_qkt/qkt_single_openeye_tb.py create mode 100644 test/cocotb_attention_qkt/test_qkt_single_openeye.py diff --git a/test/cocotb_attention_qkt/data/qkt_single_8x4/qkt_t0_dma.mem b/test/cocotb_attention_qkt/data/qkt_single_8x4/qkt_t0_dma.mem new file mode 100644 index 00000000..916d9f49 --- /dev/null +++ b/test/cocotb_attention_qkt/data/qkt_single_8x4/qkt_t0_dma.mem @@ -0,0 +1,677 @@ +0000081882200901 +0000002800100001 +0000080000070004 +0000008000c01004 +0024108010100800 +00005220a8420101 +000900bff0010201 +0030030060180005 +0000000120004002 +0000000100000100 +10000100ff0ff000 +3fc0000000000000 +0000000100000000 +0000000000000000 +0000111111111111 +0041041041041041 +0000000000000041 +0000000000000000 +00006db6dbb6db6d +0000000000000000 +0000000000000000 +0000000000000000 +25dccddd99bd1fa3 +0000000000000000 +000002103c0d5003 +0d403a0f60880000 +000000000e002e02 +d0e30210bd0540d4 +0000000000000000 +000000b0010e50b8 +0ea0930140d90000 +000000000f009e0c +20f60f50d8030001 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000089 +0000000089000000 +0089000000008900 diff --git a/test/cocotb_attention_qkt/data/qkt_single_8x4/qkt_t0_reference.npz b/test/cocotb_attention_qkt/data/qkt_single_8x4/qkt_t0_reference.npz new file mode 100644 index 0000000000000000000000000000000000000000..17d7845f4246f6a7c74252721e982fb5da79802e GIT binary patch literal 1794 zcmdUvK`2B~6o$`ZhA>5$k`ix-M-5G)hNNtiUi1_THq&IDMl{CEBok_u_Et6;SxL%r zEGYJNh@wO`Y%H)H_qzY78A&o5Zr#5Ad+&Lj|DAKMWfnWyNevIVj%&kNj1qFwsJ|l; zO=?s{DNUVWu8)ilTN4^B(y|e<<5MxCS2y}*{DxOIrsrdcSTGWpkA-ZxJ{X*f+hRQ) z4n}RETf4lvzs;+!>c1Z4+sLv3xgSDrfH&YNcnvn=d<%Gn^&03G=z3@q>;y}}U7Q<$ z?g1aL?tl(}W#Aq5>!A0bGvE=(`S#=71=e3dE3a-VtLX!5WM$pVKU+8c-)JY|x?Lju zd+-hHfd5VCF=!v?0r|ghFQ4H2E%*$sfmdKJ;@6>zp}8J?(3~&l<;FVuc|`m<$bG>1 zRp5Mn-FEgHx)G3diMrWKQF|(3hxpc|5ydR<))jW=biKT?NhOqgQd#?kl-_Do%y)N~ znM||03gK=c5D(8xC)nJYiXmn}<_fhY%#|RY?@i497ZX}hJMnE$FS~rZ Date: Mon, 26 Oct 2026 21:07:28 +0100 Subject: [PATCH 25/36] Attention: implement QKT operand packers and DMA memory --- hdl/attention_qkt_dma_memory.v | 140 ++++++++++++++++++++++++++ hdl/attention_qkt_k8_packer.v | 178 +++++++++++++++++++++++++++++++++ hdl/attention_qkt_q8_packer.v | 153 ++++++++++++++++++++++++++++ 3 files changed, 471 insertions(+) create mode 100644 hdl/attention_qkt_dma_memory.v create mode 100644 hdl/attention_qkt_k8_packer.v create mode 100644 hdl/attention_qkt_q8_packer.v diff --git a/hdl/attention_qkt_dma_memory.v b/hdl/attention_qkt_dma_memory.v new file mode 100644 index 00000000..86e4123e --- /dev/null +++ b/hdl/attention_qkt_dma_memory.v @@ -0,0 +1,140 @@ + +`timescale 1ns/1ps + +module attention_qkt_dma_memory #( + parameter integer DMA_WIDTH = 64, + parameter integer ADDR_WIDTH = 16, + + parameter integer STATUS_WORDS = 19, + parameter integer IACT_WORDS = 4, + parameter integer WGHT_WORDS = 10, + parameter integer PSUM_WORDS = 4, + parameter integer QUANT_WORDS = 640, + + parameter TEMPLATE_FILE = "qkt_t0_dma.mem", + + parameter integer WGHT_INDEX_BITS = + (WGHT_WORDS <= 1) ? 1 : $clog2(WGHT_WORDS), + + parameter integer COUNT_BITS = + $clog2(WGHT_WORDS + 1) +)( + input wire clk_i, + input wire rst_ni, + + // Clear packed operands before a new GEMV. + input wire clear_i, + + // From Q8 activation packer + input wire [DMA_WIDTH-1:0] q8_word_i, + input wire q8_word_valid_i, + output wire q8_word_ready_o, + + // From K8 weight packer + input wire [DMA_WIDTH-1:0] k8_word_i, + input wire k8_word_valid_i, + output wire k8_word_ready_o, + input wire [WGHT_INDEX_BITS-1:0] k8_word_index_i, + + // All operands are available + output wire operands_ready_o, + + // Existing GEMV controller read interface + input wire [ADDR_WIDTH-1:0] stream_addr_i, + output reg [DMA_WIDTH-1:0] stream_data_o +); + + localparam integer IACT_START = STATUS_WORDS; + localparam integer IACT_LAST = IACT_START + IACT_WORDS - 1; + localparam integer WGHT_START = IACT_START + IACT_WORDS; + localparam integer PSUM_START = WGHT_START + WGHT_WORDS; + + localparam integer STREAM_WORDS = + PSUM_START + PSUM_WORDS + QUANT_WORDS; + + // Static QKT configuration, PSUM and quantization data. + reg [DMA_WIDTH-1:0] template_rom [0:STREAM_WORDS-1]; + + initial begin + $readmemh(TEMPLATE_FILE, template_rom); + end + + // Packed operands, not additional Q8/K8 memories. + reg [DMA_WIDTH-1:0] q8_packed; + reg [DMA_WIDTH-1:0] k8_packed [0:WGHT_WORDS-1]; + + reg q8_loaded; + reg [COUNT_BITS-1:0] wght_count; + + assign q8_word_ready_o = !q8_loaded; + + assign k8_word_ready_o = + (wght_count < WGHT_WORDS) && + (k8_word_index_i == wght_count); + + assign operands_ready_o = + q8_loaded && (wght_count == WGHT_WORDS); + + integer i; + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + q8_packed <= 0; + q8_loaded <= 0; + wght_count <= 0; + + for (i = 0; i < WGHT_WORDS; i = i + 1) + k8_packed[i] <= 0; + + end else if (clear_i) begin + q8_packed <= 0; + q8_loaded <= 0; + wght_count <= 0; + + for (i = 0; i < WGHT_WORDS; i = i + 1) + k8_packed[i] <= 0; + + end else begin + + if (q8_word_valid_i && q8_word_ready_o) begin + q8_packed <= q8_word_i; + q8_loaded <= 1'b1; + end + + if (k8_word_valid_i && k8_word_ready_o) begin + k8_packed[wght_count] <= k8_word_i; + wght_count <= wght_count + 1'b1; + end + + end + end + + // Combinational read, compatible with the existing + // attention_gemv_control_top stream interface. + always @(*) begin + stream_data_o = {DMA_WIDTH{1'b0}}; + + if (operands_ready_o && + (stream_addr_i < STREAM_WORDS)) begin + + if (stream_addr_i >= IACT_START && + stream_addr_i < WGHT_START) begin + + if (stream_addr_i == IACT_LAST) + stream_data_o = q8_packed; + else + stream_data_o = 0; + + end else if (stream_addr_i >= WGHT_START && + stream_addr_i < PSUM_START) begin + + stream_data_o = + k8_packed[stream_addr_i - WGHT_START]; + + end else begin + stream_data_o = template_rom[stream_addr_i]; + end + end + end + +endmodule diff --git a/hdl/attention_qkt_k8_packer.v b/hdl/attention_qkt_k8_packer.v new file mode 100644 index 00000000..f92eb6e1 --- /dev/null +++ b/hdl/attention_qkt_k8_packer.v @@ -0,0 +1,178 @@ + +`timescale 1ns/1ps + +module attention_qkt_k8_packer #( + parameter integer NUM_TOKENS = 4, + parameter integer NUM_FEATURES = 8, + parameter integer DMA_BITWIDTH = 64, + parameter integer TOKEN_BITS = + (NUM_TOKENS <= 1) ? 1 : $clog2(NUM_TOKENS), + parameter integer FEATURE_BITS = + (NUM_FEATURES <= 1) ? 1 : $clog2(NUM_FEATURES) +)( + input wire clk_i, + input wire rst_ni, + input wire start_i, + + // Existing K8 memory read interface + output wire [TOKEN_BITS-1:0] k8_rd_token_o, + output wire [FEATURE_BITS-1:0] k8_rd_feature_o, + input wire signed [7:0] k8_data_i, + + // Packed DMA weight words + output wire [DMA_BITWIDTH-1:0] wght_word_o, + output wire wght_word_valid_o, + input wire wght_word_ready_i, + output wire wght_word_last_o, + output reg [3:0] word_index_o, + + output reg busy_o, + output reg done_o +); + + // Current verified DenseMapper configuration: + // K8 shape: 4 x 8 + // 10 DMA words, organized in two groups of 5. + localparam integer GROUP_WORDS = 5; + localparam integer TOTAL_WORDS = 10; + localparam integer GROUP_BITS = + GROUP_WORDS * DMA_BITWIDTH; + + localparam [1:0] + IDLE = 2'd0, + READ = 2'd1, + SEND = 2'd2; + + reg [1:0] state; + + reg [TOKEN_BITS-1:0] token_index; + reg [FEATURE_BITS-1:0] feature_index; + + reg [GROUP_BITS-1:0] even_payload; + reg [GROUP_BITS-1:0] odd_payload; + + assign k8_rd_token_o = token_index; + assign k8_rd_feature_o = feature_index; + + // Bit position inside a 5-word group. + // Mapping matches Dense Row-Stationary K8 [4 x 8], + // SPARSITY_EN=1 and PARALLEL_MACS=2. + function integer weight_bit_position; + input integer token; + input integer feature; + integer pair; + begin + pair = feature / 2; + + if (token < 2) + weight_bit_position = + pair * 24 + token * 12; + + else if (pair < 2) + weight_bit_position = + 144 + pair * 24 + (token - 2) * 12; + + else + weight_bit_position = + 192 + (pair - 2) * 24 + + (token - 2) * 12; + end + endfunction + + wire [31:0] field_position = + weight_bit_position(token_index, feature_index); + + // Five 64-bit words are stored as one continuous + // bitfield, so an INT8 value can cross word boundaries. + wire [GROUP_BITS-1:0] selected_payload = + (word_index_o < GROUP_WORDS) + ? even_payload : odd_payload; + + wire [3:0] group_word_index = + (word_index_o < GROUP_WORDS) + ? word_index_o + : (word_index_o - GROUP_WORDS); + + // DenseMapper reverses the five words per group. + assign wght_word_o = + selected_payload[ + (GROUP_WORDS - 1 - group_word_index) + * DMA_BITWIDTH +: DMA_BITWIDTH + ]; + + assign wght_word_valid_o = (state == SEND); + + assign wght_word_last_o = + (state == SEND) && + (word_index_o == TOTAL_WORDS - 1); + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state <= IDLE; + token_index <= 0; + feature_index <= 0; + word_index_o <= 0; + even_payload <= 0; + odd_payload <= 0; + busy_o <= 0; + done_o <= 0; + + end else begin + done_o <= 0; + + case (state) + IDLE: begin + if (start_i) begin + token_index <= 0; + feature_index <= 0; + word_index_o <= 0; + even_payload <= 0; + odd_payload <= 0; + busy_o <= 1; + state <= READ; + end + end + + READ: begin + // Capture one K8 value per clock. + // Even and odd features are packed + // into separate DMA word groups. + if (feature_index[0]) + odd_payload[field_position +: 8] + <= k8_data_i; + else + even_payload[field_position +: 8] + <= k8_data_i; + + if (feature_index == NUM_FEATURES - 1) begin + feature_index <= 0; + + if (token_index == NUM_TOKENS - 1) + state <= SEND; + else + token_index <= token_index + 1'b1; + + end else begin + feature_index <= feature_index + 1'b1; + end + end + + SEND: begin + // Hold output stable during backpressure. + if (wght_word_ready_i) begin + if (word_index_o == TOTAL_WORDS - 1) begin + busy_o <= 0; + done_o <= 1; + state <= IDLE; + end else begin + word_index_o <= word_index_o + 1'b1; + end + end + end + + default: state <= IDLE; + endcase + end + end + +endmodule diff --git a/hdl/attention_qkt_q8_packer.v b/hdl/attention_qkt_q8_packer.v new file mode 100644 index 00000000..429f71f4 --- /dev/null +++ b/hdl/attention_qkt_q8_packer.v @@ -0,0 +1,153 @@ +`timescale 1ns/1ps + +module attention_qkt_q8_packer #( + parameter integer NUM_TOKENS = 4, + parameter integer NUM_FEATURES = 8, + + parameter integer TOKEN_BITS = + (NUM_TOKENS <= 1) ? 1 : $clog2(NUM_TOKENS), + + parameter integer FEATURE_BITS = + (NUM_FEATURES <= 1) ? 1 : $clog2(NUM_FEATURES), + + parameter integer WORDS_PER_TOKEN = + (NUM_FEATURES + 7) / 8, + + parameter integer WORD_INDEX_BITS = + (WORDS_PER_TOKEN <= 1) ? 1 : $clog2(WORDS_PER_TOKEN) +)( + input wire clk_i, + input wire rst_ni, + input wire start_i, + + input wire [TOKEN_BITS-1:0] token_i, + + // Existing Q8 memory interface + output wire [TOKEN_BITS-1:0] q8_rd_token_o, + output wire [FEATURE_BITS-1:0] q8_rd_feature_o, + input wire signed [7:0] q8_data_i, + + // 64-bit streaming interface + output reg [63:0] q8_word_o, + output reg q8_word_valid_o, + input wire q8_word_ready_i, + output reg q8_word_last_o, + + output reg [WORD_INDEX_BITS-1:0] word_index_o, + + output reg busy_o, + output reg done_o +); + + localparam [1:0] + IDLE = 2'd0, + READ = 2'd1, + SEND = 2'd2; + + reg [1:0] state; + + reg [TOKEN_BITS-1:0] selected_token; + reg [FEATURE_BITS-1:0] feature_index; + reg [2:0] byte_index; + + assign q8_rd_token_o = selected_token; + assign q8_rd_feature_o = feature_index; + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state <= IDLE; + + selected_token <= 0; + feature_index <= 0; + byte_index <= 0; + + q8_word_o <= 0; + q8_word_valid_o <= 0; + q8_word_last_o <= 0; + + word_index_o <= 0; + + busy_o <= 0; + done_o <= 0; + + end else begin + done_o <= 0; + + case (state) + + IDLE: begin + if (start_i) begin + selected_token <= token_i; + + feature_index <= 0; + byte_index <= 0; + word_index_o <= 0; + + q8_word_o <= 0; + q8_word_valid_o <= 0; + q8_word_last_o <= 0; + + busy_o <= 1; + state <= READ; + end + end + + READ: begin + + // Pack one INT8 feature per clock + q8_word_o[byte_index*8 +: 8] + <= q8_data_i; + + // Advance memory read address + if (feature_index != NUM_FEATURES-1) + feature_index <= feature_index + 1'b1; + + // Word complete or final feature reached + if ((byte_index == 3'd7) || + (feature_index == NUM_FEATURES-1)) begin + + q8_word_valid_o <= 1; + + q8_word_last_o <= + (feature_index == NUM_FEATURES-1); + + state <= SEND; + + end else begin + byte_index <= byte_index + 1'b1; + end + end + + SEND: begin + + // Hold the word until receiver accepts it + if (q8_word_valid_o && q8_word_ready_i) begin + + q8_word_valid_o <= 0; + q8_word_last_o <= 0; + + if (q8_word_last_o) begin + busy_o <= 0; + done_o <= 1; + state <= IDLE; + + end else begin + + // Prepare next 64-bit word + q8_word_o <= 0; + byte_index <= 0; + + word_index_o <= word_index_o + 1'b1; + + state <= READ; + end + end + end + + default: state <= IDLE; + + endcase + end + end + +endmodule \ No newline at end of file From 6df7b9c1763b3dc57c7b3f90fbad73d7100ae91a Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Tue, 27 Oct 2026 15:43:11 +0100 Subject: [PATCH 26/36] Attention: integrate and verify QK^T computation with OpenEye + score_buffer for storing the needed data in softmax --- hdl/attention_qkt_dma_memory.v | 7 +- hdl/attention_qkt_openeye_top.v | 365 ++++++++++++++++++ hdl/attention_qkt_score_buffer.v | 77 ++++ .../attention & test_gemv_QKt_full_openeye.py | 183 +++++++++ 4 files changed, 631 insertions(+), 1 deletion(-) create mode 100644 hdl/attention_qkt_openeye_top.v create mode 100644 hdl/attention_qkt_score_buffer.v create mode 100644 test/cocotb_attention_qkt/attention & test_gemv_QKt_full_openeye.py diff --git a/hdl/attention_qkt_dma_memory.v b/hdl/attention_qkt_dma_memory.v index 86e4123e..e02bae5f 100644 --- a/hdl/attention_qkt_dma_memory.v +++ b/hdl/attention_qkt_dma_memory.v @@ -25,6 +25,8 @@ module attention_qkt_dma_memory #( // Clear packed operands before a new GEMV. input wire clear_i, + input wire q8_reload_i, + // From Q8 activation packer input wire [DMA_WIDTH-1:0] q8_word_i, input wire q8_word_valid_i, @@ -96,7 +98,10 @@ module attention_qkt_dma_memory #( end else begin - if (q8_word_valid_i && q8_word_ready_o) begin + if (q8_reload_i) begin + q8_packed <= 0; + q8_loaded <= 1'b0; + end else if (q8_word_valid_i && q8_word_ready_o) begin q8_packed <= q8_word_i; q8_loaded <= 1'b1; end diff --git a/hdl/attention_qkt_openeye_top.v b/hdl/attention_qkt_openeye_top.v new file mode 100644 index 00000000..add94ed6 --- /dev/null +++ b/hdl/attention_qkt_openeye_top.v @@ -0,0 +1,365 @@ + +`timescale 1ns/1ps + +module attention_qkt_openeye_top #( + parameter integer NUM_TOKENS = 4, + parameter integer NUM_FEATURES = 8, + parameter integer DMA_WIDTH = 64, + parameter integer SCORE_WIDTH = 20, + parameter integer ADDR_WIDTH = 16, + parameter integer STREAM_WORDS = 677, + + parameter TEMPLATE_FILE = "qkt_t0_dma.mem", + + parameter integer TOKEN_BITS = + (NUM_TOKENS <= 1) ? 1 : $clog2(NUM_TOKENS), + + parameter integer FEATURE_BITS = + (NUM_FEATURES <= 1) ? 1 : $clog2(NUM_FEATURES), + + parameter integer SCORE_BITS = TOKEN_BITS +)( + input wire clk_i, + input wire rst_ni, + + // Start after Q/K quantization has finished. + input wire start_i, + + output wire busy_o, + output reg done_o, + output wire scores_complete_o, + + // Read interfaces to existing Q8/K8 memories. + output wire [TOKEN_BITS-1:0] q8_rd_token_o, + output wire [FEATURE_BITS-1:0] q8_rd_feature_o, + input wire signed [7:0] q8_data_i, + + output wire [TOKEN_BITS-1:0] k8_rd_token_o, + output wire [FEATURE_BITS-1:0] k8_rd_feature_o, + input wire signed [7:0] k8_data_i, + + // Read interface for future Softmax. + input wire [TOKEN_BITS-1:0] score_rd_token_i, + input wire [SCORE_BITS-1:0] score_rd_index_i, + output wire signed [SCORE_WIDTH-1:0] score_rd_data_o, + output wire score_rd_valid_o, + + // Debug + output wire [ADDR_WIDTH-1:0] stream_addr_o, + output wire [TOKEN_BITS-1:0] active_token_o +); + + // --------------------------------------------------------- + // Four consecutive GEMV executions + // --------------------------------------------------------- + + localparam [2:0] + IDLE = 3'd0, + CLEAR = 3'd1, + LOAD = 3'd2, + WAIT_PACK = 3'd3, + RUN_GEMV = 3'd4, + WAIT_GEMV = 3'd5, + RELOAD_Q8 = 3'd6; + + reg [2:0] state; + reg [TOKEN_BITS-1:0] token_index; + + assign active_token_o = token_index; + assign busy_o = (state != IDLE); + + wire clear_memory = (state == CLEAR); + wire reload_q8 = (state == RELOAD_Q8); + + wire q8_start = (state == LOAD); + wire k8_start = (state == LOAD) && + (token_index == {TOKEN_BITS{1'b0}}); + + wire gemv_start = (state == RUN_GEMV); + + // --------------------------------------------------------- + // Q8 Packer + // --------------------------------------------------------- + + wire [63:0] q8_word; + wire q8_valid; + wire q8_ready; + + attention_qkt_q8_packer #( + .NUM_TOKENS(NUM_TOKENS), + .NUM_FEATURES(NUM_FEATURES) + ) u_q8_packer ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .start_i(q8_start), + .token_i(token_index), + + .q8_rd_token_o(q8_rd_token_o), + .q8_rd_feature_o(q8_rd_feature_o), + .q8_data_i(q8_data_i), + + .q8_word_o(q8_word), + .q8_word_valid_o(q8_valid), + .q8_word_ready_i(q8_ready), + .q8_word_last_o(), + .word_index_o(), + .busy_o(), + .done_o() + ); + + // --------------------------------------------------------- + // K8 Packer: Load weights only once + // --------------------------------------------------------- + + wire [63:0] k8_word; + wire k8_valid; + wire k8_ready; + wire [3:0] k8_word_index; + + attention_qkt_k8_packer u_k8_packer ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .start_i(k8_start), + + .k8_rd_token_o(k8_rd_token_o), + .k8_rd_feature_o(k8_rd_feature_o), + .k8_data_i(k8_data_i), + + .wght_word_o(k8_word), + .wght_word_valid_o(k8_valid), + .wght_word_ready_i(k8_ready), + .wght_word_last_o(), + .word_index_o(k8_word_index), + .busy_o(), + .done_o() + ); + + // --------------------------------------------------------- + // QKT DMA Memory + // --------------------------------------------------------- + + wire operands_ready; + wire [DMA_WIDTH-1:0] stream_data; + + attention_qkt_dma_memory #( + .DMA_WIDTH(DMA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .TEMPLATE_FILE(TEMPLATE_FILE) + ) u_qkt_memory ( + .clk_i(clk_i), + .rst_ni(rst_ni), + + .clear_i(clear_memory), + .q8_reload_i(reload_q8), + + .q8_word_i(q8_word), + .q8_word_valid_i(q8_valid), + .q8_word_ready_o(q8_ready), + + .k8_word_i(k8_word), + .k8_word_valid_i(k8_valid), + .k8_word_ready_o(k8_ready), + .k8_word_index_i(k8_word_index), + + .operands_ready_o(operands_ready), + + .stream_addr_i(stream_addr_o), + .stream_data_o(stream_data) + ); + + // --------------------------------------------------------- + // Existing GEMV Controller + // --------------------------------------------------------- + + wire gemv_done; + wire gemv_busy; + wire adapter_busy; + + wire [63:0] dma_input_data; + wire dma_input_valid; + wire dma_input_ready; + + wire [63:0] dma_output_data; + wire dma_output_valid; + wire dma_output_last; + wire dma_output_ready; + + wire result_write; + wire [63:0] result_data; + wire [ADDR_WIDTH-1:0] result_addr; + + attention_dma_adapter #( + .DMA_WIDTH(DMA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH) + ) u_qkt_dma_adapter ( + .clk_i(clk_i), + .rst_ni(rst_ni), + + .gemv_start_i(gemv_start), + .gemv_done_o(gemv_done), + .busy_o(adapter_busy), + + .stream_word_count_i(STREAM_WORDS), + .stream_addr_o(stream_addr_o), + .stream_data_i(stream_data), + + .dma_ready_i(dma_input_ready), + .dma_data_o(dma_input_data), + .dma_valid_o(dma_input_valid), + + .dma_result_data_i(dma_output_data), + .dma_result_valid_i(dma_output_valid), + .dma_result_last_i(dma_output_last), + .dma_result_ready_o(dma_output_ready), + + .result_write_o(result_write), + .result_data_o(result_data), + .result_addr_o(result_addr) + ); + + // --------------------------------------------------------- + // Real OpenEye FPGA + // --------------------------------------------------------- + + OpenEye_FPGA u_openeye ( + .clk_i(clk_i), + .rst_ni(rst_ni), + + .data_dma_i(dma_input_data), + .enable_dma_i(dma_input_valid), + .ready_dma_o(dma_input_ready), + + .data_dma_o(dma_output_data), + .enable_dma_o(dma_output_valid), + .last_data_o(dma_output_last), + .ready_dma_i(dma_output_ready) + ); + + // --------------------------------------------------------- + // Score Buffer + // --------------------------------------------------------- + + // Dense output order for current K=8, N=4 mapping: + // DMA beats: 0, 1, 2, 3 + // Scores: 0, 2, 1, 3 + + localparam integer OUTPUT_COLUMNS = 2; + + localparam integer SCORES_PER_COLUMN = + (NUM_TOKENS + OUTPUT_COLUMNS - 1) / OUTPUT_COLUMNS; + + localparam integer OUTPUT_BEATS = + OUTPUT_COLUMNS * SCORES_PER_COLUMN; + + wire [ADDR_WIDTH-1:0] mapped_score_linear = + (result_addr % OUTPUT_COLUMNS) * SCORES_PER_COLUMN + + (result_addr / OUTPUT_COLUMNS); + + wire [SCORE_BITS-1:0] mapped_score_index = + mapped_score_linear[SCORE_BITS-1:0]; + + wire score_write = + result_write && + (result_addr < OUTPUT_BEATS) && + (mapped_score_linear < NUM_TOKENS); + + attention_qkt_score_buffer #( + .NUM_TOKENS(NUM_TOKENS), + .NUM_SCORES(NUM_TOKENS), + .DATA_WIDTH(SCORE_WIDTH) + ) u_score_buffer ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .clear_i(clear_memory), + + .write_en_i(score_write), + .write_token_i(token_index), + .write_score_i(mapped_score_index), + .write_data_i(result_data[SCORE_WIDTH-1:0]), + + .read_token_i(score_rd_token_i), + .read_score_i(score_rd_index_i), + .read_data_o(score_rd_data_o), + .read_valid_o(score_rd_valid_o), + .complete_o(scores_complete_o) + ); + + // --------------------------------------------------------- + // Main sequencing FSM + // --------------------------------------------------------- + + `ifndef SYNTHESIS + initial begin + if (NUM_TOKENS != 4 || + NUM_FEATURES != 8 || + DMA_WIDTH != 64 || + SCORE_WIDTH != 20 || + STREAM_WORDS != 677) begin + + $fatal(1, + "QKT configuration not yet supported by all submodules"); + end + end + `endif + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state <= IDLE; + token_index <= 0; + done_o <= 0; + end else begin + done_o <= 0; + + case (state) + + IDLE: begin + if (start_i) begin + token_index <= 0; + state <= CLEAR; + end + end + + CLEAR: begin + state <= LOAD; + end + + LOAD: begin + // Start Q8; start K8 only for token 0. + state <= WAIT_PACK; + end + + WAIT_PACK: begin + if (operands_ready) + state <= RUN_GEMV; + end + + RUN_GEMV: begin + state <= WAIT_GEMV; + end + + WAIT_GEMV: begin + if (gemv_done) begin + if (token_index == NUM_TOKENS - 1) begin + done_o <= 1'b1; + state <= IDLE; + end else begin + token_index <= token_index + 1'b1; + state <= RELOAD_Q8; + end + end + end + + RELOAD_Q8: begin + // Preserve K8, replace Q8. + state <= LOAD; + end + + default: begin + state <= IDLE; + end + + endcase + end + end + +endmodule diff --git a/hdl/attention_qkt_score_buffer.v b/hdl/attention_qkt_score_buffer.v new file mode 100644 index 00000000..d271983c --- /dev/null +++ b/hdl/attention_qkt_score_buffer.v @@ -0,0 +1,77 @@ + +`timescale 1ns/1ps + +module attention_qkt_score_buffer #( + parameter integer NUM_TOKENS = 4, + parameter integer NUM_SCORES = 4, + parameter integer DATA_WIDTH = 20, + + parameter integer TOKEN_BITS = + (NUM_TOKENS <= 1) ? 1 : $clog2(NUM_TOKENS), + + parameter integer SCORE_BITS = + (NUM_SCORES <= 1) ? 1 : $clog2(NUM_SCORES), + + parameter integer TOTAL = NUM_TOKENS * NUM_SCORES, + + parameter integer ADDR_BITS = + (TOTAL <= 1) ? 1 : $clog2(TOTAL) +)( + input wire clk_i, + input wire rst_ni, + input wire clear_i, + + // Write interface from OpenEye output controller + input wire write_en_i, + input wire [TOKEN_BITS-1:0] write_token_i, + input wire [SCORE_BITS-1:0] write_score_i, + input wire signed [DATA_WIDTH-1:0] write_data_i, + + // Read interface for future Softmax + input wire [TOKEN_BITS-1:0] read_token_i, + input wire [SCORE_BITS-1:0] read_score_i, + + output wire signed [DATA_WIDTH-1:0] read_data_o, + output wire read_valid_o, + + // All score locations have been written + output wire complete_o +); + + reg signed [DATA_WIDTH-1:0] score_mem [0:TOTAL-1]; + reg [TOTAL-1:0] valid_bits; + + wire [ADDR_BITS-1:0] write_addr = + write_token_i * NUM_SCORES + write_score_i; + + wire [ADDR_BITS-1:0] read_addr = + read_token_i * NUM_SCORES + read_score_i; + + wire write_in_range = + (write_token_i < NUM_TOKENS) && + (write_score_i < NUM_SCORES); + + wire read_in_range = + (read_token_i < NUM_TOKENS) && + (read_score_i < NUM_SCORES); + + assign read_valid_o = + read_in_range && valid_bits[read_addr]; + + assign read_data_o = + read_valid_o ? score_mem[read_addr] : {DATA_WIDTH{1'b0}}; + + assign complete_o = &valid_bits; + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + valid_bits <= {TOTAL{1'b0}}; + end else if (clear_i) begin + valid_bits <= {TOTAL{1'b0}}; + end else if (write_en_i && write_in_range) begin + score_mem[write_addr] <= write_data_i; + valid_bits[write_addr] <= 1'b1; + end + end + +endmodule diff --git a/test/cocotb_attention_qkt/attention & test_gemv_QKt_full_openeye.py b/test/cocotb_attention_qkt/attention & test_gemv_QKt_full_openeye.py new file mode 100644 index 00000000..5ff85b5f --- /dev/null +++ b/test/cocotb_attention_qkt/attention & test_gemv_QKt_full_openeye.py @@ -0,0 +1,183 @@ +"""Single-command RTL test of four hardware-driven QK^T GEMVs on OpenEye. + +Copy beside the already passing test_qkt_single_openeye.py; run with pytest. +This test begins at the existing quantized Q8/K8 interface (NOT at Projection). +It checks the REAL OpenEye_FPGA computations, Top FSM and 4x4 score buffer. +""" + +import os +import shutil +from pathlib import Path + +import cocotb +import numpy as np +from cocotb.clock import Clock +from cocotb.triggers import FallingEdge, RisingEdge, Timer, ClockCycles, with_timeout, SimTimeoutError + + +def test_qkt_full_openeye(): + """Pytest runner; generate a fresh regmap matching the earlier passing K8/N4 test.""" + import cocotb_test.simulator + import open_eye.generator as generator + import open_eye.test_utils_main as ptu + import open_eye.vh_file_creator as vh_file_creator + from open_eye import hdl_dir, test_dir + + settings = { + "PARALLEL_MACS": "2", "CLUSTER_ROWS": "2", "CLUSTER_COLUMNS": "2", + "NUM_GLB_IACT": "3", "NUM_GLB_PSUM": "4", "NUM_GLB_WGHT": "3", + "DATAFLOW": "row_stationary", "BRANCHES": "1", "BUFFER_WIDTH": "12", + "QUANT_AMOUNT": "1024", "RAM_CELLS": "32", + } + os.environ.update(settings) + + here = Path(__file__).resolve().parent + data_dir = here / "data" / "qkt_single_8x4" + image = data_dir / "qkt_t0_dma.mem" + reference = data_dir / "qkt_t0_reference.npz" + for path in (image, reference): + assert path.is_file(), f"Missing test input: {path}" + + build = Path(test_dir) / ".temp" / "qkt_full_openeye_k8_n4" + build.mkdir(parents=True, exist_ok=True) + + # Proven method from test_qkt_single_openeye.py. In particular, do NOT + # compile the repository's potentially stale hdl/dma_storage.v. + vh_file_creator.create_vh_file_from_envvars( + str(build), hdl_dir + "/", toplevel="OpenEye_FPGA" + ) + generator.create_regmap_params_vh_file( + os.path.join(test_dir, "cocotb_fpga"), str(build), str(build) + ) + assert (build / "dma_storage.v").is_file(), "Regmap generator did not create dma_storage.v" + assert (build / "regmap_params.vh").is_file(), "Missing generated regmap_params.vh" + shutil.copyfile(image, build / "qkt_t0_dma.mem") + + sources = [ + str(p) for p in ptu.get_verilog_sources(hdl_dir) + if Path(p).name != "dma_storage.v" + ] + extra_modules = ( + "attention_qkt_openeye_top.v", + "attention_qkt_q8_packer.v", + "attention_qkt_k8_packer.v", + "attention_qkt_dma_memory.v", + "attention_qkt_score_buffer.v", + "attention_dma_adapter.v", + ) + existing = {str(Path(src).resolve()) for src in sources} + for name in extra_modules: + file = Path(hdl_dir) / name + assert file.is_file(), f"Missing RTL: {file}" + if str(file.resolve()) not in existing: + sources.append(str(file)) + sources.append(str(build / "dma_storage.v")) + + cocotb_test.simulator.run( + python_search=[str(here)], + verilog_sources=sources, + toplevel="attention_qkt_openeye_top", + module="test_qkt_full_openeye", + testcase="qkt_four_gemv", + sim_build=str(build), + includes=[str(build), str(Path(hdl_dir)), str(Path(hdl_dir) / "include")], + defines={"NO_TRACE": "TRUE", "USE_INTERNAL_PARAMS_PE": "TRUE"}, + simulator="icarus", + force_compile=True, + waves=False, + extra_env={ + **settings, + "QKT_FULL_DATA_DIR": str(data_dir.resolve()), + "CLOCK_LEN": "20", "CLOCK_UNIT": "ns", + "CLOCK_DELAY_INPUT": "100", "CLOCK_DELAY_UNIT_INPUT": "ps", + "CLOCK_DELAY_OUTPUT": "100", "CLOCK_DELAY_UNIT_OUTPUT": "ps", + "LOGGER_LEVEL": "20", + }, + ) + + +async def _drive_qk_memory_read_ports(dut, q8, k8): + """Cocotb stand-in for existing asynchronous Q8/K8 memories. + + No Python computation or stream scheduling is used at runtime: DUT packers, + DMA adapter, OpenEye and FSM perform the entire four-GEMV calculation. + """ + dut.q8_data_i.value = int(q8[0, 0]) & 0xff + dut.k8_data_i.value = int(k8[0, 0]) & 0xff + while True: + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") # allow nonblocking address updates to settle + qt = int(dut.q8_rd_token_o.value) + qf = int(dut.q8_rd_feature_o.value) + kt = int(dut.k8_rd_token_o.value) + kf = int(dut.k8_rd_feature_o.value) + assert 0 <= qt < 4 and 0 <= qf < 8, f"Bad Q8 address [{qt},{qf}]" + assert 0 <= kt < 4 and 0 <= kf < 8, f"Bad K8 address [{kt},{kf}]" + dut.q8_data_i.value = int(q8[qt, qf]) & 0xff + dut.k8_data_i.value = int(k8[kt, kf]) & 0xff + + +@cocotb.test() +async def qkt_four_gemv(dut): + data_dir = Path(os.environ["QKT_FULL_DATA_DIR"]) + with np.load(data_dir / "qkt_t0_reference.npz", allow_pickle=False) as d: + q8 = d["Q8"].astype(np.int64) + k8 = d["K8"].astype(np.int64) + t0_golden = d["expected"].astype(np.int64) + + assert q8.shape == (4, 8) and k8.shape == (4, 8) + expected = q8 @ k8.T + assert expected.shape == (4, 4) + assert np.array_equal(expected[0], t0_golden), "Reference input and golden disagree" + + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.q8_data_i.value = 0 + dut.k8_data_i.value = 0 + dut.score_rd_token_i.value = 0 + dut.score_rd_index_i.value = 0 + + cocotb.start_soon(Clock(dut.clk_i, 20, unit="ns").start()) + memory_task = cocotb.start_soon(_drive_qk_memory_read_ports(dut, q8, k8)) + await ClockCycles(dut.clk_i, 10) + await FallingEdge(dut.clk_i) + dut.rst_ni.value = 1 + await ClockCycles(dut.clk_i, 20) # OpenEye's reset synchronizer + + dut._log.info("Start: four QKT GEMVs through actual OpenEye RTL") + await FallingEdge(dut.clk_i) + dut.start_i.value = 1 + await FallingEdge(dut.clk_i) + dut.start_i.value = 0 + + try: + await with_timeout(RisingEdge(dut.done_o), 10_000_000, "ns") + except SimTimeoutError as e: + raise AssertionError( + "QKT Top timed out (check its FSM, DMA adapter and OpenEye output-last). " + f"busy={dut.busy_o.value}, token={dut.active_token_o.value}, " + f"stream_addr={dut.stream_addr_o.value}" + ) from e + + await FallingEdge(dut.clk_i) + assert int(dut.scores_complete_o.value) == 1, "Top DONE but 16 score entries are not all valid" + + actual = np.zeros((4, 4), dtype=np.int64) + for token in range(4): + for score in range(4): + dut.score_rd_token_i.value = token + dut.score_rd_index_i.value = score + await Timer(1, unit="ns") + assert int(dut.score_rd_valid_o.value) == 1, ( + f"Score buffer missing S[{token},{score}]" + ) + raw = int(dut.score_rd_data_o.value) + actual[token, score] = raw - (1 << 20) if raw & (1 << 19) else raw + + dut._log.info("Expected S:\n%s", expected) + dut._log.info("Hardware S:\n%s", actual) + assert np.array_equal(actual, expected), ( + f"Bit-exact S mismatch\nExpected:\n{expected}\nActual:\n{actual}" + ) + memory_task.cancel() + dut._log.info("PASS: 4 real OpenEye GEMVs, all 16 QKT scores bit-exact") From d55e4d60a71e41e8f57d508dfdf46c5b1bf518a4 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Tue, 27 Oct 2026 21:11:36 +0100 Subject: [PATCH 27/36] Attention: complete end-to-end QKT integration --- hdl/attention_top.v | 473 ++++++++++++++++++ .../test_attention_top_e2e.py | 249 +++++++++ 2 files changed, 722 insertions(+) create mode 100644 hdl/attention_top.v create mode 100644 test/cocotb_attention_qkt/test_attention_top_e2e.py diff --git a/hdl/attention_top.v b/hdl/attention_top.v new file mode 100644 index 00000000..d99126d0 --- /dev/null +++ b/hdl/attention_top.v @@ -0,0 +1,473 @@ +`timescale 1ns / 1ps +//============================================================================= +// OpenEye single-head Q/K/V projection -> requantization -> Q*K^T +// Integration draft: exactly ONE OpenEye_FPGA and ONE attention_dma_adapter. +// Existing standalone projection/QKT top modules are intentionally NOT used. +// +// Supported geometry (first integration): 4 tokens, 8 features, +// projection stream 939 words, QKT stream 677 words, 64-bit DMA. +// NOTE: This is an unverified integration draft. See companion notes. +//============================================================================= +module attention_top #( + parameter integer DMA_WIDTH = 64, + parameter integer ADDR_WIDTH = 16, + parameter integer PROJECTION_STREAM_WORDS = 939, + parameter integer QKT_STREAM_WORDS = 677, + parameter PROJECTION_COMMON_MEM_FILE = "common_rom.mem", + parameter PROJECTION_IACT_MEM_FILE = "activation_ram.mem", + parameter PROJECTION_WGHT_MEM_FILE = "weight_ram.mem", + parameter QKT_TEMPLATE_FILE = "qkt_t0_dma.mem" +)( + input wire clk_i, + input wire rst_ni, + input wire start_i, + output wire busy_o, + output wire done_o, + output wire scores_complete_o, + + // Optional software/testbench update of projection DMA operand RAMs. + input wire iact_we_i, + input wire [ADDR_WIDTH-1:0] iact_wr_addr_i, + input wire [DMA_WIDTH-1:0] iact_wr_data_i, + input wire wght_we_i, + input wire [ADDR_WIDTH-1:0] wght_wr_addr_i, + input wire [DMA_WIDTH-1:0] wght_wr_data_i, + + // Read the final 4x4 QK^T scores; used later by Softmax. + input wire [1:0] score_rd_token_i, + input wire [1:0] score_rd_index_i, + output wire signed [19:0] score_rd_data_o, + output wire score_rd_valid_o, + + // Debug outputs for integration tests. + output wire [1:0] active_token_o, + output wire [1:0] active_projection_o, + output wire qkt_mode_o, + output wire [ADDR_WIDTH-1:0] stream_addr_o, + output wire dma_result_write_o +); + localparam [ADDR_WIDTH-1:0] PROJECTION_WORD_COUNT = PROJECTION_STREAM_WORDS; + localparam [ADDR_WIDTH-1:0] QKT_WORD_COUNT = QKT_STREAM_WORDS; + + // IMPORTANT: The legacy attention_qkt_ctrl.v is a single-GEMV controller + // and is instantiated by legacy attention_gemv_control_top.v. To preserve + // its passing tests, integration sequencing is isolated in the temporary + // attention_top_scheduler module below, until a backwards-compatible + // full-scope attention_qkt_ctrl interface has been settled. + wire projection_start; + wire quant_start; + wire qkt_memory_clear; + wire qkt_q8_reload; + wire q8_packer_start; + wire k8_packer_start; + wire gemv_start; + wire qkt_mode; + wire qkt_result_enable; + wire [1:0] token_select; + wire [1:0] projection_select; + wire quant_done; + wire operands_ready; + wire gemv_done; + + attention_top_scheduler u_scheduler ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .start_i(start_i), + .gemv_done_i(gemv_done), + .quant_done_i(quant_done), + .operands_ready_i(operands_ready), + .projection_start_o(projection_start), + .quant_start_o(quant_start), + .qkt_memory_clear_o(qkt_memory_clear), + .qkt_q8_reload_o(qkt_q8_reload), + .q8_packer_start_o(q8_packer_start), + .k8_packer_start_o(k8_packer_start), + .gemv_start_o(gemv_start), + .qkt_mode_o(qkt_mode), + .qkt_result_enable_o(qkt_result_enable), + .token_o(token_select), + .projection_o(projection_select), + .busy_o(busy_o), + .done_o(done_o) + ); + assign active_token_o = token_select; + assign active_projection_o = projection_select; + assign qkt_mode_o = qkt_mode; + + //===================== ONE SHARED DMA ADAPTER ============================ + wire [ADDR_WIDTH-1:0] stream_addr; + wire [DMA_WIDTH-1:0] projection_stream_data; + wire [DMA_WIDTH-1:0] qkt_stream_data; + wire [DMA_WIDTH-1:0] selected_stream_data = + qkt_mode ? qkt_stream_data : projection_stream_data; + wire [ADDR_WIDTH-1:0] selected_stream_word_count = + qkt_mode ? QKT_WORD_COUNT : PROJECTION_WORD_COUNT; + wire [DMA_WIDTH-1:0] dma_input_data; + wire dma_input_valid; + wire dma_input_ready; + wire [DMA_WIDTH-1:0] dma_output_data; + wire dma_output_valid; + wire dma_output_last; + wire dma_output_ready; + wire adapter_busy; + wire result_write; + wire [DMA_WIDTH-1:0] result_data; + wire [ADDR_WIDTH-1:0] result_addr; + + assign stream_addr_o = stream_addr; + assign dma_result_write_o = result_write; + + attention_dma_adapter #( + .DMA_WIDTH(DMA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH) + ) u_dma_adapter ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .gemv_start_i(gemv_start), + .gemv_done_o(gemv_done), + .busy_o(adapter_busy), + .stream_word_count_i(selected_stream_word_count), + .stream_addr_o(stream_addr), + .stream_data_i(selected_stream_data), + .dma_ready_i(dma_input_ready), + .dma_data_o(dma_input_data), + .dma_valid_o(dma_input_valid), + .dma_result_data_i(dma_output_data), + .dma_result_valid_i(dma_output_valid), + .dma_result_last_i(dma_output_last), + .dma_result_ready_o(dma_output_ready), + .result_write_o(result_write), + .result_data_o(result_data), + .result_addr_o(result_addr) + ); + + //===================== ONE SHARED OPENEYE ================================ + OpenEye_FPGA u_openeye ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .data_dma_i(dma_input_data), + .enable_dma_i(dma_input_valid), + .ready_dma_o(dma_input_ready), + .data_dma_o(dma_output_data), + .enable_dma_o(dma_output_valid), + .last_data_o(dma_output_last), + .ready_dma_i(dma_output_ready) + ); + + //===================== PROJECTION DMA MEMORY ============================= + attention_projection_memory #( + .DMA_WIDTH(DMA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .COMMON_MEM_FILE(PROJECTION_COMMON_MEM_FILE), + .ACTIVATION_MEM_FILE(PROJECTION_IACT_MEM_FILE), + .WEIGHT_MEM_FILE(PROJECTION_WGHT_MEM_FILE) + ) u_projection_memory ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .start_i(projection_start), + .busy_i(adapter_busy), + .token_select_i(token_select), + .projection_select_i(projection_select), + .addr_i(stream_addr), + .data_o(projection_stream_data), + .iact_we_i(iact_we_i), + .iact_wr_addr_i(iact_wr_addr_i), + .iact_wr_data_i(iact_wr_data_i), + .wght_we_i(wght_we_i), + .wght_wr_addr_i(wght_wr_addr_i), + .wght_wr_data_i(wght_wr_data_i) + ); + + //===================== Q/K/V RAW RESULT STORAGE ========================== + wire [1:0] quant_q_rd_token; + wire [2:0] quant_q_rd_feature; + wire [1:0] quant_k_rd_token; + wire [2:0] quant_k_rd_feature; + wire [19:0] q_raw_data; + wire [19:0] k_raw_data; + wire [19:0] v_raw_data; + wire quant_busy; + + attention_projection_result_buffer u_projection_result_buffer ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .start_i(projection_start), + .token_select_i(token_select), + .projection_select_i(projection_select), + .result_write_i(result_write && !qkt_mode), + .result_addr_i(result_addr), + .result_data_i(result_data), + .q_rd_token_i(quant_q_rd_token), + .q_rd_feature_i(quant_q_rd_feature), + .k_rd_token_i(quant_k_rd_token), + .k_rd_feature_i(quant_k_rd_feature), + .v_rd_token_i(2'd0), + .v_rd_feature_i(3'd0), + .q_data_o(q_raw_data), + .k_data_o(k_raw_data), + .v_data_o(v_raw_data) + ); + + //===================== Q/K REQUANTIZATION ================================ + wire [1:0] q8_rd_token; + wire [2:0] q8_rd_feature; + wire signed [7:0] q8_data; + wire [1:0] k8_rd_token; + wire [2:0] k8_rd_feature; + wire signed [7:0] k8_data; + wire [6:0] q_shift; + wire [6:0] k_shift; + + attention_qk_quantization_controller #( + .NUM_TOKENS(4), + .NUM_FEATURES(8), + .DATA_WIDTH(20), + .SHIFT_WIDTH(7) + ) u_quantization ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .start_i(quant_start), + .busy_o(quant_busy), + .done_o(quant_done), + .q_raw_rd_token_o(quant_q_rd_token), + .q_raw_rd_feature_o(quant_q_rd_feature), + .q_raw_data_i(q_raw_data), + .k_raw_rd_token_o(quant_k_rd_token), + .k_raw_rd_feature_o(quant_k_rd_feature), + .k_raw_data_i(k_raw_data), + .q8_rd_token_i(q8_rd_token), + .q8_rd_feature_i(q8_rd_feature), + .q8_data_o(q8_data), + .k8_rd_token_i(k8_rd_token), + .k8_rd_feature_i(k8_rd_feature), + .k8_data_o(k8_data), + .q_shift_o(q_shift), + .k_shift_o(k_shift) + ); + + //===================== QKT DMA OPERAND PACKERS =========================== + wire [DMA_WIDTH-1:0] q8_word; + wire q8_word_valid; + wire q8_word_ready; + wire q8_word_last; + wire [3:0] q8_word_index; + wire q8_packer_busy; + wire q8_packer_done; + wire [DMA_WIDTH-1:0] k8_word; + wire k8_word_valid; + wire k8_word_ready; + wire k8_word_last; + wire [3:0] k8_word_index; + wire k8_packer_busy; + wire k8_packer_done; + + // NOTE: Verify exact port names/widths against the local passing + // attention_qkt_openeye_top.v before treating this draft as final. + attention_qkt_q8_packer u_q8_packer ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .start_i(q8_packer_start), + .token_i(token_select), + .q8_rd_token_o(q8_rd_token), + .q8_rd_feature_o(q8_rd_feature), + .q8_data_i(q8_data), + .q8_word_o(q8_word), + .q8_word_valid_o(q8_word_valid), + .q8_word_ready_i(q8_word_ready), + .q8_word_last_o(q8_word_last), + .word_index_o(q8_word_index), + .busy_o(q8_packer_busy), + .done_o(q8_packer_done) + ); + + attention_qkt_k8_packer u_k8_packer ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .start_i(k8_packer_start), + .k8_rd_token_o(k8_rd_token), + .k8_rd_feature_o(k8_rd_feature), + .k8_data_i(k8_data), + .wght_word_o(k8_word), + .wght_word_valid_o(k8_word_valid), + .wght_word_ready_i(k8_word_ready), + .wght_word_last_o(k8_word_last), + .word_index_o(k8_word_index), + .busy_o(k8_packer_busy), + .done_o(k8_packer_done) + ); + + //===================== QKT DMA TEMPLATE + DYNAMIC WORDS ================== + // The validated QKT memory retains K8 after the first token, while + // q8_reload_i invalidates only the one token's Q8 operand word. + // Port names here are provisional pending inspection of local source. + attention_qkt_dma_memory #( + .TEMPLATE_FILE(QKT_TEMPLATE_FILE) + ) u_qkt_memory ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .clear_i(qkt_memory_clear), + .q8_reload_i(qkt_q8_reload), + .q8_word_i(q8_word), + .q8_word_valid_i(q8_word_valid), + .q8_word_ready_o(q8_word_ready), + .k8_word_i(k8_word), + .k8_word_valid_i(k8_word_valid), + .k8_word_ready_o(k8_word_ready), + .k8_word_index_i(k8_word_index), + .operands_ready_o(operands_ready), + .stream_addr_i(stream_addr), + .stream_data_o(qkt_stream_data) + ); + + //===================== QKT SCORE RESULT BUFFER =========================== + // OpenEye K8/N4 row-stationary output DMA beat order = 0, 2, 1, 3. + wire [1:0] mapped_score_index = {result_addr[0], result_addr[1]}; + wire score_write = qkt_result_enable && result_write && (result_addr < 4); + + attention_qkt_score_buffer #( + .NUM_TOKENS(4), + .NUM_SCORES(4), + .DATA_WIDTH(20) + ) u_qkt_score_buffer ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .clear_i(qkt_memory_clear), + .write_en_i(score_write), + .write_token_i(token_select), + .write_score_i(mapped_score_index), + .write_data_i(result_data[19:0]), + .read_token_i(score_rd_token_i), + .read_score_i(score_rd_index_i), + .read_data_o(score_rd_data_o), + .read_valid_o(score_rd_valid_o), + .complete_o(scores_complete_o) + ); + +`ifndef SYNTHESIS + initial begin + if (DMA_WIDTH != 64 || ADDR_WIDTH != 16 || + PROJECTION_STREAM_WORDS != 939 || QKT_STREAM_WORDS != 677) + $fatal(1, "attention_top: unverified geometry or DMA configuration"); + end +`endif +endmodule + +//============================================================================= +// Integration-only orchestration FSM (preserves legacy attention_qkt_ctrl). +// 12 projection GEMVs -> quantization -> 4 QKT GEMVs -> global DONE. +// No arithmetic, Python orchestration, second DMA adapter or second OpenEye. +//============================================================================= +module attention_top_scheduler ( + input wire clk_i, + input wire rst_ni, + input wire start_i, + input wire gemv_done_i, + input wire quant_done_i, + input wire operands_ready_i, + output wire projection_start_o, + output wire quant_start_o, + output wire qkt_memory_clear_o, + output wire qkt_q8_reload_o, + output wire q8_packer_start_o, + output wire k8_packer_start_o, + output wire gemv_start_o, + output wire qkt_mode_o, + output wire qkt_result_enable_o, + output wire [1:0] token_o, + output wire [1:0] projection_o, + output wire busy_o, + output reg done_o +); + localparam [3:0] + IDLE = 4'd0, + PROJ_START = 4'd1, + PROJ_WAIT = 4'd2, + QUANT_START = 4'd3, + QUANT_WAIT = 4'd4, + QKT_CLEAR = 4'd5, + QKT_PACK_START = 4'd6, + QKT_PACK_WAIT = 4'd7, + QKT_GEMV_START = 4'd8, + QKT_GEMV_WAIT = 4'd9, + QKT_RELOAD = 4'd10, + FINISH = 4'd11; + + reg [3:0] state; + reg [1:0] token; + reg [1:0] projection; + reg qkt_mode; + + assign token_o = token; + assign projection_o = projection; + assign qkt_mode_o = qkt_mode; + assign busy_o = (state != IDLE); + assign projection_start_o = (state == PROJ_START); + assign quant_start_o = (state == QUANT_START); + assign qkt_memory_clear_o = (state == QKT_CLEAR); + assign qkt_q8_reload_o = (state == QKT_RELOAD); + assign q8_packer_start_o = (state == QKT_PACK_START); + assign k8_packer_start_o = (state == QKT_PACK_START) && (token == 2'd0); + assign gemv_start_o = (state == PROJ_START) || (state == QKT_GEMV_START); + assign qkt_result_enable_o = (state == QKT_GEMV_WAIT); + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state <= IDLE; + token <= 2'd0; + projection <= 2'd0; + qkt_mode <= 1'b0; + done_o <= 1'b0; + end else begin + done_o <= 1'b0; + case (state) + IDLE: begin + if (start_i) begin + token <= 2'd0; + projection <= 2'd0; + qkt_mode <= 1'b0; + state <= PROJ_START; + end + end + PROJ_START: state <= PROJ_WAIT; + PROJ_WAIT: begin + if (gemv_done_i) begin + if (token != 2'd3) begin + token <= token + 2'd1; + state <= PROJ_START; + end else if (projection != 2'd2) begin + token <= 2'd0; + projection <= projection + 2'd1; + state <= PROJ_START; + end else begin + state <= QUANT_START; + end + end + end + QUANT_START: state <= QUANT_WAIT; + QUANT_WAIT: if (quant_done_i) begin + qkt_mode <= 1'b1; + token <= 2'd0; + state <= QKT_CLEAR; + end + QKT_CLEAR: state <= QKT_PACK_START; + QKT_PACK_START: state <= QKT_PACK_WAIT; + QKT_PACK_WAIT: if (operands_ready_i) state <= QKT_GEMV_START; + QKT_GEMV_START: state <= QKT_GEMV_WAIT; + QKT_GEMV_WAIT: if (gemv_done_i) begin + if (token == 2'd3) + state <= FINISH; + else begin + token <= token + 2'd1; + state <= QKT_RELOAD; + end + end + QKT_RELOAD: state <= QKT_PACK_START; + FINISH: begin + done_o <= 1'b1; + state <= IDLE; + end + default: state <= IDLE; + endcase + end + end +endmodule diff --git a/test/cocotb_attention_qkt/test_attention_top_e2e.py b/test/cocotb_attention_qkt/test_attention_top_e2e.py new file mode 100644 index 00000000..7003c354 --- /dev/null +++ b/test/cocotb_attention_qkt/test_attention_top_e2e.py @@ -0,0 +1,249 @@ +"""RTL end-to-end test: 12 Q/K/V Projection GEMVs -> INT8 Q/K -> 4 QK^T GEMVs. + +Run from the OpenEye repository root after copying this file into + test/cocotb_attention_qkt/test_attention_top_e2e.py + + python -m pytest test/cocotb_attention_qkt/test_attention_top_e2e.py -v -s + +Only the pre-existing .mem files are loaded by $readmemh. Python DOES NOT +orchestrate any of the 16 GEMVs or inject Q8/K8 into the DUT. The DUT's +attention_top_scheduler, DMA adapter, OpenEye FPGA, quantizer and packers do +all of that. Python is used for the independent arithmetic golden reference. +""" + +import os +import shutil +from pathlib import Path + +import cocotb +import numpy as np +from cocotb.clock import Clock +from cocotb.triggers import FallingEdge, RisingEdge, Timer, with_timeout, SimTimeoutError + + +def test_attention_top_e2e(): + import cocotb_test.simulator + import open_eye.test_utils_main as ptu + import open_eye.vh_file_creator as vh_file_creator + import open_eye.generator as generator + from open_eye import hdl_dir, test_dir + + here = Path(__file__).resolve().parent + proj_dir = here / "data" / "attention_mapper_v1" + qkt_dir = here / "data" / "qkt_single_8x4" + files = { + "common_rom.mem": proj_dir / "common_rom.mem", + "activation_ram.mem": proj_dir / "activation_ram.mem", + "weight_ram.mem": proj_dir / "weight_ram.mem", + "qkt_t0_dma.mem": qkt_dir / "qkt_t0_dma.mem", + } + for name, src in files.items(): + assert src.is_file(), f"Missing {name}: {src}" + assert (proj_dir / "inputs_used.npz").is_file(), ( + f"Missing reference tensors: {proj_dir / 'inputs_used.npz'}" + ) + # Validate the memory-image geometry expected by the current RTL. + for name, count in { + "common_rom.mem": 691, + "activation_ram.mem": 32, + "weight_ram.mem": 720, + "qkt_t0_dma.mem": 677, + }.items(): + actual = sum(bool(line.strip()) for line in files[name].read_text().splitlines()) + assert actual == count, f"{name}: expected {count} lines, got {actual}" + + # Both passing row-stationary tests use the same OpenEye configuration. + settings = { + "PARALLEL_MACS": "2", + "CLUSTER_ROWS": "2", "CLUSTER_COLUMNS": "2", + "NUM_GLB_IACT": "3", "NUM_GLB_PSUM": "4", "NUM_GLB_WGHT": "3", + "DATAFLOW": "row_stationary", "BRANCHES": "1", "BUFFER_WIDTH": "12", + "QUANT_AMOUNT": "1024", "RAM_CELLS": "32", + } + os.environ.update(settings) + + build = Path(test_dir) / ".temp" / "attention_top_e2e_k8_n4" + build.mkdir(parents=True, exist_ok=True) + vh_file_creator.create_vh_file_from_envvars( + str(build), str(hdl_dir) + os.sep, toplevel="OpenEye_FPGA" + ) + generator.create_regmap_params_vh_file( + str(Path(test_dir) / "cocotb_fpga"), str(build), str(build) + ) + for name, source in files.items(): + shutil.copyfile(source, build / name) + generated = build / "dma_storage.v" + assert generated.is_file(), "Regmap generation did not produce dma_storage.v" + + sources = [ + str(p) for p in ptu.get_verilog_sources(str(hdl_dir)) + if Path(p).name != "dma_storage.v" + ] + for name in ( + "attention_top.v", + "attention_dma_adapter.v", + "attention_projection_memory.v", + "attention_projection_result_buffer.v", + "attention_qk_quantization_controller.v", + "attention_qkt_q8_packer.v", + "attention_qkt_k8_packer.v", + "attention_qkt_dma_memory.v", + "attention_qkt_score_buffer.v", + ): + path = Path(hdl_dir) / name + assert path.is_file(), f"Missing RTL module: {path}" + if str(path.resolve()) not in {str(Path(src).resolve()) for src in sources}: + sources.append(str(path)) + sources.append(str(generated)) + + cocotb_test.simulator.run( + python_search=[str(here)], + verilog_sources=sources, + toplevel="attention_top", + module="test_attention_top_e2e", + testcase="check_complete_attention_dataflow", + sim_build=str(build), + includes=[str(build), str(hdl_dir), str(Path(hdl_dir) / "include")], + defines={"NO_TRACE": "TRUE", "USE_INTERNAL_PARAMS_PE": "TRUE"}, + simulator="icarus", + force_compile=True, + waves=False, + extra_env={ + **settings, + "ATTENTION_E2E_PROJECTION_DIR": str(proj_dir.resolve()), + }, + ) + + +def _reference_quantize(values): + """Bit-exact per-tensor pow2 rounding from passing Q/K quantization TB.""" + values = np.asarray(values, dtype=np.int64) + m = int(np.max(np.abs(values))) + shift = 0 + while m > (127 << shift): + shift += 1 + if shift: + half = 1 << (shift - 1) + values = np.where( + values >= 0, + (values + half) >> shift, + -((-values + half) >> shift), + ) + return np.clip(values, -128, 127).astype(np.int64), shift + + +@cocotb.test() +async def check_complete_attention_dataflow(dut): + projection_dir = Path(os.environ["ATTENTION_E2E_PROJECTION_DIR"]) + with np.load(projection_dir / "inputs_used.npz", allow_pickle=False) as t: + x = t["X"].astype(np.int64) + wq = t["WQ"].astype(np.int64) + wk = t["WK"].astype(np.int64) + wv = t["WV"].astype(np.int64) + q_raw, k_raw, v_raw = x @ wq, x @ wk, x @ wv + assert q_raw.shape == (4, 8) and k_raw.shape == (4, 8) + assert v_raw.shape == (4, 8) + q8, q_shift = _reference_quantize(q_raw) + k8, k_shift = _reference_quantize(k_raw) + golden_scores = q8 @ k8.T + + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.iact_we_i.value = 0 + dut.iact_wr_addr_i.value = 0 + dut.iact_wr_data_i.value = 0 + dut.wght_we_i.value = 0 + dut.wght_wr_addr_i.value = 0 + dut.wght_wr_data_i.value = 0 + dut.score_rd_token_i.value = 0 + dut.score_rd_index_i.value = 0 + + cocotb.start_soon(Clock(dut.clk_i, 20, unit="ns").start()) + for _ in range(12): + await FallingEdge(dut.clk_i) + dut.rst_ni.value = 1 + for _ in range(20): + await FallingEdge(dut.clk_i) + + # Count actual result DMA handshakes by phase (not testbench starts). + counts = {"projection": 0, "qkt": 0} + seen_proj = set() + seen_qkt = set() + finished = False + + async def monitor(): + nonlocal finished + while not finished: + await FallingEdge(dut.clk_i) + await Timer(1, unit="ns") + if int(dut.dma_result_write_o.value): + token = int(dut.active_token_o.value) + mode = int(dut.qkt_mode_o.value) + if mode: + counts["qkt"] += 1 + seen_qkt.add(token) + else: + counts["projection"] += 1 + seen_proj.add((int(dut.active_projection_o.value), token)) + + monitor_task = cocotb.start_soon(monitor()) + dut._log.info("RTL E2E START: 12 Projection -> Quantization -> 4 QKT") + await FallingEdge(dut.clk_i) + dut.start_i.value = 1 + await FallingEdge(dut.clk_i) + dut.start_i.value = 0 + + try: + await with_timeout(RisingEdge(dut.done_o), 15_000_000, "ns") + except SimTimeoutError as exc: + raise AssertionError( + "attention_top timed out: " + f"busy={dut.busy_o.value} " + f"qkt_mode={dut.qkt_mode_o.value} " + f"projection={dut.active_projection_o.value} " + f"token={dut.active_token_o.value} " + f"stream_addr={dut.stream_addr_o.value} " + f"writes={counts}" + ) from exc + await FallingEdge(dut.clk_i) + finished = True + monitor_task.cancel() + + assert int(dut.scores_complete_o.value) == 1, ( + "Global DONE but QKT score buffer is incomplete" + ) + assert seen_proj == {(p, t) for p in range(3) for t in range(4)}, ( + f"Missing projection GEMV output(s): {seen_proj}" + ) + assert seen_qkt == {0, 1, 2, 3}, f"Missing QKT GEMV(s): {seen_qkt}" + assert counts["projection"] == 384, ( + f"Expected 12*8 projection DMA result beats, got {counts['projection']}" + ) + assert counts["qkt"] == 16, ( + f"Expected 4*4 QKT DMA result beats, got {counts['qkt']}" + ) + + actual_scores = np.empty((4, 4), dtype=np.int64) + for token in range(4): + for j in range(4): + dut.score_rd_token_i.value = token + dut.score_rd_index_i.value = j + await Timer(1, unit="ns") + assert int(dut.score_rd_valid_o.value) == 1, ( + f"Missing score S[{token},{j}]" + ) + raw = int(dut.score_rd_data_o.value) + actual_scores[token, j] = raw - (1 << 20) if (raw & (1 << 19)) else raw + + dut._log.info("Expected quantization shifts: Q=%s K=%s", q_shift, k_shift) + dut._log.info("Expected score matrix:\n%s", golden_scores) + dut._log.info("Actual score matrix:\n%s", actual_scores) + assert np.array_equal(actual_scores, golden_scores), ( + f"End-to-end bit-exact mismatch\n" + f"Golden Q8:\n{q8}\nGolden K8:\n{k8}\n" + f"Expected:\n{golden_scores}\nActual:\n{actual_scores}" + ) + dut._log.info( + "PASS: single OpenEye and DMA adapter, 12 projections, " + "hardware Q/K quantization, 4 QKT GEMVs, all 16 scores bit-exact" + ) From 6139ef82971381221cf39a75b16cc927876aca9c Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Tue, 27 Oct 2026 22:13:57 +0100 Subject: [PATCH 28/36] Attention: extract global scheduler into standalone RTL module --- hdl/attention_top.v | 158 ++++++---------------------------- hdl/attention_top_scheduler.v | 121 ++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 131 deletions(-) create mode 100644 hdl/attention_top_scheduler.v diff --git a/hdl/attention_top.v b/hdl/attention_top.v index d99126d0..5d8f8ee2 100644 --- a/hdl/attention_top.v +++ b/hdl/attention_top.v @@ -1,13 +1,28 @@ `timescale 1ns / 1ps + //============================================================================= -// OpenEye single-head Q/K/V projection -> requantization -> Q*K^T -// Integration draft: exactly ONE OpenEye_FPGA and ONE attention_dma_adapter. -// Existing standalone projection/QKT top modules are intentionally NOT used. +// OpenEye Single-Head Attention Integration +// +// Hardware-controlled execution: +// 1. Q/K/V Projection (12 GEMVs) +// 2. Q/K Quantization (INT8) +// 3. QK^T Computation (4 GEMVs) +// +// Uses one shared OpenEye_FPGA and one shared DMA adapter. // -// Supported geometry (first integration): 4 tokens, 8 features, -// projection stream 939 words, QKT stream 677 words, 64-bit DMA. -// NOTE: This is an unverified integration draft. See companion notes. +// Verified: +// - End-to-end Cocotb simulation PASS +// - All 16 attention scores verified bit-exact +// +// Current configuration: +// - 4 tokens, 8 features +// - 64-bit DMA +// - Projection: 939 DMA words +// - QKT: 677 DMA words +// +// Softmax is excluded. //============================================================================= + module attention_top #( parameter integer DMA_WIDTH = 64, parameter integer ADDR_WIDTH = 16, @@ -49,11 +64,8 @@ module attention_top #( localparam [ADDR_WIDTH-1:0] PROJECTION_WORD_COUNT = PROJECTION_STREAM_WORDS; localparam [ADDR_WIDTH-1:0] QKT_WORD_COUNT = QKT_STREAM_WORDS; - // IMPORTANT: The legacy attention_qkt_ctrl.v is a single-GEMV controller - // and is instantiated by legacy attention_gemv_control_top.v. To preserve - // its passing tests, integration sequencing is isolated in the temporary - // attention_top_scheduler module below, until a backwards-compatible - // full-scope attention_qkt_ctrl interface has been settled. +// Global execution sequencing is implemented in attention_top_scheduler.v. +// Legacy attention_qkt_ctrl.v and the passing standalone tops stay unchanged. wire projection_start; wire quant_start; wire qkt_memory_clear; @@ -76,15 +88,18 @@ module attention_top #( .gemv_done_i(gemv_done), .quant_done_i(quant_done), .operands_ready_i(operands_ready), + .projection_start_o(projection_start), .quant_start_o(quant_start), .qkt_memory_clear_o(qkt_memory_clear), .qkt_q8_reload_o(qkt_q8_reload), .q8_packer_start_o(q8_packer_start), .k8_packer_start_o(k8_packer_start), + .gemv_start_o(gemv_start), .qkt_mode_o(qkt_mode), .qkt_result_enable_o(qkt_result_enable), + .token_o(token_select), .projection_o(projection_select), .busy_o(busy_o), @@ -250,7 +265,7 @@ module attention_top #( wire q8_word_valid; wire q8_word_ready; wire q8_word_last; - wire [3:0] q8_word_index; + wire q8_word_index; wire q8_packer_busy; wire q8_packer_done; wire [DMA_WIDTH-1:0] k8_word; @@ -352,122 +367,3 @@ module attention_top #( `endif endmodule -//============================================================================= -// Integration-only orchestration FSM (preserves legacy attention_qkt_ctrl). -// 12 projection GEMVs -> quantization -> 4 QKT GEMVs -> global DONE. -// No arithmetic, Python orchestration, second DMA adapter or second OpenEye. -//============================================================================= -module attention_top_scheduler ( - input wire clk_i, - input wire rst_ni, - input wire start_i, - input wire gemv_done_i, - input wire quant_done_i, - input wire operands_ready_i, - output wire projection_start_o, - output wire quant_start_o, - output wire qkt_memory_clear_o, - output wire qkt_q8_reload_o, - output wire q8_packer_start_o, - output wire k8_packer_start_o, - output wire gemv_start_o, - output wire qkt_mode_o, - output wire qkt_result_enable_o, - output wire [1:0] token_o, - output wire [1:0] projection_o, - output wire busy_o, - output reg done_o -); - localparam [3:0] - IDLE = 4'd0, - PROJ_START = 4'd1, - PROJ_WAIT = 4'd2, - QUANT_START = 4'd3, - QUANT_WAIT = 4'd4, - QKT_CLEAR = 4'd5, - QKT_PACK_START = 4'd6, - QKT_PACK_WAIT = 4'd7, - QKT_GEMV_START = 4'd8, - QKT_GEMV_WAIT = 4'd9, - QKT_RELOAD = 4'd10, - FINISH = 4'd11; - - reg [3:0] state; - reg [1:0] token; - reg [1:0] projection; - reg qkt_mode; - - assign token_o = token; - assign projection_o = projection; - assign qkt_mode_o = qkt_mode; - assign busy_o = (state != IDLE); - assign projection_start_o = (state == PROJ_START); - assign quant_start_o = (state == QUANT_START); - assign qkt_memory_clear_o = (state == QKT_CLEAR); - assign qkt_q8_reload_o = (state == QKT_RELOAD); - assign q8_packer_start_o = (state == QKT_PACK_START); - assign k8_packer_start_o = (state == QKT_PACK_START) && (token == 2'd0); - assign gemv_start_o = (state == PROJ_START) || (state == QKT_GEMV_START); - assign qkt_result_enable_o = (state == QKT_GEMV_WAIT); - - always @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - state <= IDLE; - token <= 2'd0; - projection <= 2'd0; - qkt_mode <= 1'b0; - done_o <= 1'b0; - end else begin - done_o <= 1'b0; - case (state) - IDLE: begin - if (start_i) begin - token <= 2'd0; - projection <= 2'd0; - qkt_mode <= 1'b0; - state <= PROJ_START; - end - end - PROJ_START: state <= PROJ_WAIT; - PROJ_WAIT: begin - if (gemv_done_i) begin - if (token != 2'd3) begin - token <= token + 2'd1; - state <= PROJ_START; - end else if (projection != 2'd2) begin - token <= 2'd0; - projection <= projection + 2'd1; - state <= PROJ_START; - end else begin - state <= QUANT_START; - end - end - end - QUANT_START: state <= QUANT_WAIT; - QUANT_WAIT: if (quant_done_i) begin - qkt_mode <= 1'b1; - token <= 2'd0; - state <= QKT_CLEAR; - end - QKT_CLEAR: state <= QKT_PACK_START; - QKT_PACK_START: state <= QKT_PACK_WAIT; - QKT_PACK_WAIT: if (operands_ready_i) state <= QKT_GEMV_START; - QKT_GEMV_START: state <= QKT_GEMV_WAIT; - QKT_GEMV_WAIT: if (gemv_done_i) begin - if (token == 2'd3) - state <= FINISH; - else begin - token <= token + 2'd1; - state <= QKT_RELOAD; - end - end - QKT_RELOAD: state <= QKT_PACK_START; - FINISH: begin - done_o <= 1'b1; - state <= IDLE; - end - default: state <= IDLE; - endcase - end - end -endmodule diff --git a/hdl/attention_top_scheduler.v b/hdl/attention_top_scheduler.v new file mode 100644 index 00000000..bd7222f1 --- /dev/null +++ b/hdl/attention_top_scheduler.v @@ -0,0 +1,121 @@ +`timescale 1ns / 1ps + +//============================================================================= +// Integration-only orchestration FSM (preserves legacy attention_qkt_ctrl). +// 12 projection GEMVs -> quantization -> 4 QKT GEMVs -> global DONE. +// No arithmetic, Python orchestration, second DMA adapter or second OpenEye. +//============================================================================= +module attention_top_scheduler ( + input wire clk_i, + input wire rst_ni, + input wire start_i, + input wire gemv_done_i, + input wire quant_done_i, + input wire operands_ready_i, + output wire projection_start_o, + output wire quant_start_o, + output wire qkt_memory_clear_o, + output wire qkt_q8_reload_o, + output wire q8_packer_start_o, + output wire k8_packer_start_o, + output wire gemv_start_o, + output wire qkt_mode_o, + output wire qkt_result_enable_o, + output wire [1:0] token_o, + output wire [1:0] projection_o, + output wire busy_o, + output reg done_o +); + localparam [3:0] + IDLE = 4'd0, + PROJ_START = 4'd1, + PROJ_WAIT = 4'd2, + QUANT_START = 4'd3, + QUANT_WAIT = 4'd4, + QKT_CLEAR = 4'd5, + QKT_PACK_START = 4'd6, + QKT_PACK_WAIT = 4'd7, + QKT_GEMV_START = 4'd8, + QKT_GEMV_WAIT = 4'd9, + QKT_RELOAD = 4'd10, + FINISH = 4'd11; + + reg [3:0] state; + reg [1:0] token; + reg [1:0] projection; + reg qkt_mode; + + assign token_o = token; + assign projection_o = projection; + assign qkt_mode_o = qkt_mode; + assign busy_o = (state != IDLE); + assign projection_start_o = (state == PROJ_START); + assign quant_start_o = (state == QUANT_START); + assign qkt_memory_clear_o = (state == QKT_CLEAR); + assign qkt_q8_reload_o = (state == QKT_RELOAD); + assign q8_packer_start_o = (state == QKT_PACK_START); + assign k8_packer_start_o = (state == QKT_PACK_START) && (token == 2'd0); + assign gemv_start_o = (state == PROJ_START) || (state == QKT_GEMV_START); + assign qkt_result_enable_o = (state == QKT_GEMV_WAIT); + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state <= IDLE; + token <= 2'd0; + projection <= 2'd0; + qkt_mode <= 1'b0; + done_o <= 1'b0; + end else begin + done_o <= 1'b0; + case (state) + IDLE: begin + if (start_i) begin + token <= 2'd0; + projection <= 2'd0; + qkt_mode <= 1'b0; + state <= PROJ_START; + end + end + PROJ_START: state <= PROJ_WAIT; + PROJ_WAIT: begin + if (gemv_done_i) begin + if (token != 2'd3) begin + token <= token + 2'd1; + state <= PROJ_START; + end else if (projection != 2'd2) begin + token <= 2'd0; + projection <= projection + 2'd1; + state <= PROJ_START; + end else begin + state <= QUANT_START; + end + end + end + QUANT_START: state <= QUANT_WAIT; + QUANT_WAIT: if (quant_done_i) begin + qkt_mode <= 1'b1; + token <= 2'd0; + state <= QKT_CLEAR; + end + QKT_CLEAR: state <= QKT_PACK_START; + QKT_PACK_START: state <= QKT_PACK_WAIT; + QKT_PACK_WAIT: if (operands_ready_i) state <= QKT_GEMV_START; + QKT_GEMV_START: state <= QKT_GEMV_WAIT; + QKT_GEMV_WAIT: if (gemv_done_i) begin + if (token == 2'd3) + state <= FINISH; + else begin + token <= token + 2'd1; + state <= QKT_RELOAD; + end + end + QKT_RELOAD: state <= QKT_PACK_START; + FINISH: begin + done_o <= 1'b1; + state <= IDLE; + end + default: state <= IDLE; + endcase + end + end +endmodule From 90fd201cd38afe9699147d9023a3e7f53c09aeaa Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Wed, 28 Oct 2026 16:37:57 +0100 Subject: [PATCH 29/36] Attention: archive obsolete RTL and legacy tests --- hdl/attention_gemv_openeye_top.v | 109 ---------- hdl/attention_gemv_rom.v | 26 --- hdl/attention_gemv_rom_top.v | 114 ---------- .../analyze_qk_quantization_v2.py | 196 ------------------ .../attention_gemv_control_top_tb.py | 156 -------------- .../attention_gemv_openeye_repeat_tb.py | 187 ----------------- .../attention_gemv_openeye_top_tb.py | 152 -------------- .../attention_gemv_rom_tb.py | 43 ---- .../attention_gemv_rom_top_tb.py | 95 --------- .../attention_qkt_ctrl_tb.py | 73 ------- .../quantization_unit_tb.py | 89 -------- .../test_attention_gemv_control_top.py | 26 --- .../test_attention_gemv_openeye_repeat.py | 85 -------- .../test_attention_gemv_openeye_top.py | 80 ------- .../test_attention_gemv_rom.py | 34 --- .../test_attention_gemv_rom_top.py | 37 ---- .../test_attention_qkt_ctrl.py | 20 -- .../test_attention_top_e2e.py | 2 +- .../test_quantization_unit.py | 27 --- 19 files changed, 1 insertion(+), 1550 deletions(-) delete mode 100644 hdl/attention_gemv_openeye_top.v delete mode 100644 hdl/attention_gemv_rom.v delete mode 100644 hdl/attention_gemv_rom_top.v delete mode 100644 test/cocotb_attention_qkt/analyze_qk_quantization_v2.py delete mode 100644 test/cocotb_attention_qkt/attention_gemv_control_top_tb.py delete mode 100644 test/cocotb_attention_qkt/attention_gemv_openeye_repeat_tb.py delete mode 100644 test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py delete mode 100644 test/cocotb_attention_qkt/attention_gemv_rom_tb.py delete mode 100644 test/cocotb_attention_qkt/attention_gemv_rom_top_tb.py delete mode 100644 test/cocotb_attention_qkt/attention_qkt_ctrl_tb.py delete mode 100644 test/cocotb_attention_qkt/quantization_unit_tb.py delete mode 100644 test/cocotb_attention_qkt/test_attention_gemv_control_top.py delete mode 100644 test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py delete mode 100644 test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py delete mode 100644 test/cocotb_attention_qkt/test_attention_gemv_rom.py delete mode 100644 test/cocotb_attention_qkt/test_attention_gemv_rom_top.py delete mode 100644 test/cocotb_attention_qkt/test_attention_qkt_ctrl.py delete mode 100644 test/cocotb_attention_qkt/test_quantization_unit.py diff --git a/hdl/attention_gemv_openeye_top.v b/hdl/attention_gemv_openeye_top.v deleted file mode 100644 index ead37643..00000000 --- a/hdl/attention_gemv_openeye_top.v +++ /dev/null @@ -1,109 +0,0 @@ -`timescale 1ns / 1ps - -//============================================================== -// Module: attention_gemv_openeye_top -// -// Purpose: -// Connect the verified GEMV ROM/control path to OpenEye_FPGA. -// -// Top-level integration of the GEMV controller, DMA adapter, ROM banks, -// and the real OpenEye FPGA accelerator. -// Supports hardware-controlled GEMV execution with selectable input streams. -//============================================================== - -module attention_gemv_openeye_top #( - parameter integer DMA_WIDTH = 64, - parameter integer ADDR_WIDTH = 16, - parameter integer ROM_DEPTH = 939 -)( - input wire clk_i, - input wire rst_ni, - input wire start_i, - input wire bank_select_i, - - output wire busy_o, - output wire adapter_busy_o, - output wire done_o, - - // Result interface for verification - output wire result_write_o, - output wire [DMA_WIDTH-1:0] result_data_o, - output wire [ADDR_WIDTH-1:0] result_addr_o, - - // Debug address - output wire [ADDR_WIDTH-1:0] stream_addr_o -); - - //========================================================== - // DMA connections between the adapter and OpenEye - //========================================================== - - wire [DMA_WIDTH-1:0] dma_input_data; - wire dma_input_valid; - wire dma_input_ready; - - wire [DMA_WIDTH-1:0] dma_output_data; - wire dma_output_valid; - wire dma_output_last; - wire dma_output_ready; - - //========================================================== - // Controller + DMA Adapter + ROM - //========================================================== - - attention_gemv_rom_top #( - .DMA_WIDTH (DMA_WIDTH), - .ADDR_WIDTH (ADDR_WIDTH), - .ROM_DEPTH (ROM_DEPTH) - ) u_attention_stream ( - - .clk_i (clk_i), - .rst_ni (rst_ni), - .start_i (start_i), - .bank_select_i (bank_select_i), - - .busy_o (busy_o), - .adapter_busy_o (adapter_busy_o), - .done_o (done_o), - - // Input DMA - .dma_ready_i (dma_input_ready), - .dma_data_o (dma_input_data), - .dma_valid_o (dma_input_valid), - - // Output DMA - .dma_result_data_i (dma_output_data), - .dma_result_valid_i (dma_output_valid), - .dma_result_last_i (dma_output_last), - .dma_result_ready_o (dma_output_ready), - - // Results - .result_write_o (result_write_o), - .result_data_o (result_data_o), - .result_addr_o (result_addr_o), - - .stream_addr_o (stream_addr_o) - ); - - //========================================================== - // Real OpenEye accelerator - //========================================================== - - OpenEye_FPGA u_openeye ( - - .clk_i (clk_i), - .rst_ni (rst_ni), - - // DMA input - .data_dma_i (dma_input_data), - .enable_dma_i (dma_input_valid), - .ready_dma_o (dma_input_ready), - - // DMA output - .data_dma_o (dma_output_data), - .enable_dma_o (dma_output_valid), - .last_data_o (dma_output_last), - .ready_dma_i (dma_output_ready) - ); - -endmodule \ No newline at end of file diff --git a/hdl/attention_gemv_rom.v b/hdl/attention_gemv_rom.v deleted file mode 100644 index f01241e5..00000000 --- a/hdl/attention_gemv_rom.v +++ /dev/null @@ -1,26 +0,0 @@ -`timescale 1ns / 1ps - -module attention_gemv_rom #( - parameter integer DMA_WIDTH = 64, - parameter integer ADDR_WIDTH = 16, - parameter integer ROM_DEPTH = 939, - parameter MEM_FILE = "gemv_reference.mem" -)( - input wire [ADDR_WIDTH-1:0] addr_i, - output wire [DMA_WIDTH-1:0] data_o -); - - // Memory containing the reference GEMV DMA stream - reg [DMA_WIDTH-1:0] rom [0:ROM_DEPTH-1]; - - // Initialize ROM from the hexadecimal memory file - initial begin - $readmemh(MEM_FILE, rom); - end - - // Return the requested word - assign data_o = (addr_i < ROM_DEPTH) - ? rom[addr_i] - : {DMA_WIDTH{1'b0}}; - -endmodule \ No newline at end of file diff --git a/hdl/attention_gemv_rom_top.v b/hdl/attention_gemv_rom_top.v deleted file mode 100644 index f4512e0b..00000000 --- a/hdl/attention_gemv_rom_top.v +++ /dev/null @@ -1,114 +0,0 @@ - -`timescale 1ns / 1ps - -module attention_gemv_rom_top #( - parameter integer DMA_WIDTH = 64, - parameter integer ADDR_WIDTH = 16, - parameter integer ROM_DEPTH = 939 -)( - input wire clk_i, - input wire rst_ni, - input wire start_i, - - // Select input stream: 0 = Q[0], 1 = Q[1] - input wire bank_select_i, - - output wire busy_o, - output wire adapter_busy_o, - output wire done_o, - - // DMA transmit interface - input wire dma_ready_i, - output wire [DMA_WIDTH-1:0] dma_data_o, - output wire dma_valid_o, - - // DMA receive interface - input wire [DMA_WIDTH-1:0] dma_result_data_i, - input wire dma_result_valid_i, - input wire dma_result_last_i, - output wire dma_result_ready_o, - - // Result storage interface - output wire result_write_o, - output wire [DMA_WIDTH-1:0] result_data_o, - output wire [ADDR_WIDTH-1:0] result_addr_o, - - // Debug: current ROM address - output wire [ADDR_WIDTH-1:0] stream_addr_o -); - - localparam [ADDR_WIDTH-1:0] ROM_WORD_COUNT = ROM_DEPTH; - - wire [DMA_WIDTH-1:0] rom_q0_data; - wire [DMA_WIDTH-1:0] rom_q1_data; - wire [DMA_WIDTH-1:0] stream_data_wire; - - reg active_bank_reg; - - // Latch ROM selection when a new GEMV starts - always @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) - active_bank_reg <= 1'b0; - else if (start_i && !busy_o) - active_bank_reg <= bank_select_i; - end - - // ROM bank 0: Q[0] - attention_gemv_rom #( - .DMA_WIDTH (DMA_WIDTH), - .ADDR_WIDTH (ADDR_WIDTH), - .ROM_DEPTH (ROM_DEPTH), - .MEM_FILE ("gemv_reference.mem") - ) u_rom_q0 ( - .addr_i (stream_addr_o), - .data_o (rom_q0_data) - ); - - // ROM bank 1: Q[1] - attention_gemv_rom #( - .DMA_WIDTH (DMA_WIDTH), - .ADDR_WIDTH (ADDR_WIDTH), - .ROM_DEPTH (ROM_DEPTH), - .MEM_FILE ("gemv_q1_reference.mem") - ) u_rom_q1 ( - .addr_i (stream_addr_o), - .data_o (rom_q1_data) - ); - - // Select one ROM using the latched bank - assign stream_data_wire = active_bank_reg - ? rom_q1_data - : rom_q0_data; - - // Existing controller + DMA adapter - attention_gemv_control_top #( - .DMA_WIDTH (DMA_WIDTH), - .ADDR_WIDTH (ADDR_WIDTH) - ) u_control_top ( - .clk_i (clk_i), - .rst_ni (rst_ni), - - .start_i (start_i), - .busy_o (busy_o), - .done_o (done_o), - .adapter_busy_o (adapter_busy_o), - - .stream_word_count_i (ROM_WORD_COUNT), - .stream_addr_o (stream_addr_o), - .stream_data_i (stream_data_wire), - - .dma_ready_i (dma_ready_i), - .dma_data_o (dma_data_o), - .dma_valid_o (dma_valid_o), - - .dma_result_data_i (dma_result_data_i), - .dma_result_valid_i (dma_result_valid_i), - .dma_result_last_i (dma_result_last_i), - .dma_result_ready_o (dma_result_ready_o), - - .result_write_o (result_write_o), - .result_data_o (result_data_o), - .result_addr_o (result_addr_o) - ); - -endmodule \ No newline at end of file diff --git a/test/cocotb_attention_qkt/analyze_qk_quantization_v2.py b/test/cocotb_attention_qkt/analyze_qk_quantization_v2.py deleted file mode 100644 index 282ac7e1..00000000 --- a/test/cocotb_attention_qkt/analyze_qk_quantization_v2.py +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env python3 -"""Compare INT8 requantization candidates on verified OpenEye Q/K projection data. - -Place at test/cocotb_attention_qkt/analyze_qk_quantization.py and run from the -OpenEye repository root: - python test/cocotb_attention_qkt/analyze_qk_quantization.py \ - test/cocotb_attention_qkt/data/qk_raw_projection.npz - -The saved NPZ must contain two 2-D integer arrays named q_raw and k_raw. -""" - -import argparse -import csv -from pathlib import Path -import sys - -import numpy as np - -# Import the actual Phase-0 quantization reference from the project rather -# than silently creating another potentially divergent specification. -ROOT = Path(__file__).resolve().parents[2] -sys.path.insert(0, str(ROOT / "src")) -from open_eye.attention_scheduler import requantize_pow2 # noqa: E402 - - -def quantize_power_of_two(raw, per_row): - raw = np.asarray(raw, dtype=np.int64) - if per_row: - rows = [requantize_pow2(row) for row in raw] - q = np.stack([pair[0] for pair in rows]) - shifts = np.array([pair[1] for pair in rows], dtype=np.int64) - else: - q, shift = requantize_pow2(raw) - shifts = np.full(raw.shape[0], shift, dtype=np.int64) - # inverse scale = 2**shift: approximate raw = q * inverse scale - inverse_scales = np.power(2.0, shifts.astype(np.float64)) - return q, inverse_scales, {"shift": shifts.tolist()} - - -def quantize_existing_openeye(raw): - """Calibrated per-row quantization using the existing RTL formula. - - quantized_value = (mant * (psum + offset)) >>> exponent - - offset = 0, exponent = 20 (when scaling needed), and mantissa is a - positive 25-bit signed integer. The scale is bounded to avoid output - overflow since the RTL does not saturate. - - This models Verilog signed arithmetic right-shift with Python/NumPy >>. - """ - raw = np.asarray(raw, dtype=np.int64) - result = np.empty_like(raw) - inverse_scales = np.empty(raw.shape[0], dtype=np.float64) - mantissas = [] - exponents = [] - for idx, row in enumerate(raw): - max_abs = int(np.max(np.abs(row))) if row.size else 0 - if max_abs <= 127: - mant, exponent = 1, 0 # Already representable exactly as INT8 - else: - exponent = 20 - mant = (127 << exponent) // max_abs - assert 0 < mant < (1 << 24), "Mantissa must fit signed 25-bit" - q_row = (row * mant) >> exponent - assert np.all((-128 <= q_row) & (q_row <= 127)), ( - "Unsafe quantizer configuration: signed INT8 overflow" - ) - result[idx] = q_row - inverse_scales[idx] = (2**exponent) / mant - mantissas.append(mant) - exponents.append(exponent) - return result, inverse_scales, { - "mantissa": mantissas, "exponent": exponents, "offset": [0] * len(mantissas) - } - - -def quantize_openeye_per_tensor_pow2(raw): - """Bit-exact model of the existing quantization_unit.v in pow2 mode. - - quant_mant=1, quant_offset=0, exponent=dynamic shift chosen to avoid - signed INT8 overflow. Verilog signed >>> corresponds to NumPy >>, - which rounds toward negative infinity (not nearest). - """ - raw = np.asarray(raw, dtype=np.int64) - max_abs = int(np.max(np.abs(raw))) if raw.size else 0 - shift = 0 - while max_abs > (127 << shift): - shift += 1 - quant = raw >> shift - assert np.all((-128 <= quant) & (quant <= 127)), "INT8 overflow" - return quant, np.full(raw.shape[0], float(2**shift)), { - "mantissa": [1] * raw.shape[0], - "exponent": [shift] * raw.shape[0], - "offset": [0] * raw.shape[0], - } - - -def quantize_openeye_per_tensor_mantissa(raw): - """Bit-exact arithmetic of existing RTL with one calibrated scale/tensor. - - Finds a representable 25-bit signed mantissa and shift; this is an - illustrative max-absolute-value calibration, not an optimized solution. - """ - raw = np.asarray(raw, dtype=np.int64) - max_abs = int(np.max(np.abs(raw))) if raw.size else 0 - if max_abs <= 127: - mantissa, exponent = 1, 0 - else: - exponent = 20 - mantissa = (127 << exponent) // max_abs - assert 0 < mantissa < (1 << 24), "Mantissa does not fit signed 25 bits" - quant = (raw * mantissa) >> exponent - assert np.all((-128 <= quant) & (quant <= 127)), "INT8 overflow" - return quant, np.full(raw.shape[0], (2**exponent) / mantissa), { - "mantissa": [mantissa] * raw.shape[0], - "exponent": [exponent] * raw.shape[0], - "offset": [0] * raw.shape[0], - } - - -def evaluate(label, q_raw, k_raw, converter): - q8, q_invscale, q_param = converter(q_raw) - k8, k_invscale, k_param = converter(k_raw) - - q_recon = q8.astype(np.float64) * q_invscale[:, None] - k_recon = k8.astype(np.float64) * k_invscale[:, None] - s_ref = q_raw.astype(np.float64) @ k_raw.astype(np.float64).T - # The following correctly uses distinct per-row scales for Q and K. - s_int = q8.astype(np.int64) @ k8.astype(np.int64).T - s_recon = s_int.astype(np.float64) * q_invscale[:, None] * k_invscale[None, :] - error = s_recon - s_ref - q_zero = int(np.count_nonzero((q_raw != 0) & (q8 == 0))) - k_zero = int(np.count_nonzero((k_raw != 0) & (k8 == 0))) - denom = float(np.linalg.norm(s_ref)) - relative_error = float(np.linalg.norm(error)) / denom if denom else float(np.linalg.norm(error)) - result = { - "method": label, - "q_lost_nonzero": q_zero, - "k_lost_nonzero": k_zero, - "q_mae": float(np.mean(np.abs(q_recon - q_raw))), - "k_mae": float(np.mean(np.abs(k_recon - k_raw))), - "score_mae": float(np.mean(np.abs(error))), - "score_max_abs_error": float(np.max(np.abs(error))), - "score_rel_frobenius_pct": relative_error * 100.0, - } - return result, q_param, k_param - - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("input", type=Path, help="NPZ with integer q_raw and k_raw") - args = parser.parse_args() - if not args.input.is_file(): - parser.error(f"Input not found: {args.input} (run the projection Cocotb test to export it)") - with np.load(args.input, allow_pickle=False) as data: - q_raw = np.asarray(data["q_raw"], dtype=np.int64) - k_raw = np.asarray(data["k_raw"], dtype=np.int64) - if q_raw.ndim != 2 or k_raw.ndim != 2 or q_raw.shape[1] != k_raw.shape[1]: - parser.error(f"Expected compatible 2D matrices, got Q={q_raw.shape}, K={k_raw.shape}") - if np.max(np.abs(q_raw)) > 524288 or np.max(np.abs(k_raw)) > 524288: - parser.error("Input contains values outside the expected signed 20-bit range") - - methods = [ - ("Per-tensor Pow2", lambda raw: quantize_power_of_two(raw, False)), - ("Per-row Pow2", lambda raw: quantize_power_of_two(raw, True)), - ("Per-row OpenEye mantissa/exp", quantize_existing_openeye), - ("Per-tensor OpenEye m=1 / shift", quantize_openeye_per_tensor_pow2), - ("Per-tensor OpenEye mantissa/exp", quantize_openeye_per_tensor_mantissa), - ] - print(f"Projection data: Q={q_raw.shape}, K={k_raw.shape}") - print(f"Original nonzero values: Q={np.count_nonzero(q_raw)}, K={np.count_nonzero(k_raw)}") - print(f"Max absolute: Q={np.max(np.abs(q_raw))}, K={np.max(np.abs(k_raw))}\n") - - rows = [] - for name, converter in methods: - result, q_param, k_param = evaluate(name, q_raw, k_raw, converter) - rows.append(result) - print(name) - print(f" New zeros: Q={result['q_lost_nonzero']}, K={result['k_lost_nonzero']}") - print(f" Reconstructed Q/K MAE: {result['q_mae']:.5g} / {result['k_mae']:.5g}") - print(f" QK^T score MAE: {result['score_mae']:.5g}") - print(f" QK^T relative Frobenius error: {result['score_rel_frobenius_pct']:.5g}%") - print(f" Q parameters: {q_param}") - print(f" K parameters: {k_param}\n") - - outfile = args.input.parent / "qk_quantization_comparison.csv" - with outfile.open("w", encoding="utf-8", newline="") as f: - writer = csv.DictWriter(f, fieldnames=list(rows[0])) - writer.writeheader() - writer.writerows(rows) - print(f"Saved summary to: {outfile}") - print("Note: This is a numerical comparison; it does not yet test the RTL controller/feedback.") - - -if __name__ == "__main__": - main() diff --git a/test/cocotb_attention_qkt/attention_gemv_control_top_tb.py b/test/cocotb_attention_qkt/attention_gemv_control_top_tb.py deleted file mode 100644 index 9b33a8c2..00000000 --- a/test/cocotb_attention_qkt/attention_gemv_control_top_tb.py +++ /dev/null @@ -1,156 +0,0 @@ -import cocotb -from cocotb.clock import Clock -from cocotb.triggers import RisingEdge, Timer - - -async def tick(dut): - await RisingEdge(dut.clk_i) - await Timer(1, unit="ns") - - -@cocotb.test() -async def test_gemv_integration(dut): - - # ================================================== - # 1. Initialize signals - # ================================================== - - dut.clk_i.value = 0 - dut.rst_ni.value = 0 - - dut.start_i.value = 0 - - dut.stream_word_count_i.value = 3 - dut.stream_data_i.value = 0 - - dut.dma_ready_i.value = 0 - - dut.dma_result_data_i.value = 0 - dut.dma_result_valid_i.value = 0 - dut.dma_result_last_i.value = 0 - - cocotb.start_soon( - Clock(dut.clk_i, 10, unit="ns").start() - ) - - await tick(dut) - - # Release reset - dut.rst_ni.value = 1 - await tick(dut) - - assert int(dut.busy_o.value) == 0 - assert int(dut.adapter_busy_o.value) == 0 - - # ================================================== - # 2. Start the main controller - # ================================================== - - dut.start_i.value = 1 - await tick(dut) - dut.start_i.value = 0 - - assert int(dut.busy_o.value) == 1 - - # Controller generates GEMV start pulse - await tick(dut) - - # Adapter receives the pulse on the next edge - await tick(dut) - - assert int(dut.adapter_busy_o.value) == 1 - - # ================================================== - # 3. Test WAIT_READY - # ================================================== - - # OpenEye is not ready yet - for _ in range(3): - await tick(dut) - - assert int(dut.dma_valid_o.value) == 0 - assert int(dut.adapter_busy_o.value) == 1 - - # Simulate OpenEye becoming ready - dut.dma_ready_i.value = 1 - await tick(dut) - - # ================================================== - # 4. Test DMA input transmission - # ================================================== - - input_words = [0x11, 0x22, 0x33] - - for address, word in enumerate(input_words): - - # Simulated combinational word source - dut.stream_data_i.value = word - await Timer(1, unit="ns") - - assert int(dut.stream_addr_o.value) == address - assert int(dut.dma_valid_o.value) == 1 - assert int(dut.dma_data_o.value) == word - - await tick(dut) - - assert int(dut.dma_valid_o.value) == 0 - assert int(dut.dma_result_ready_o.value) == 1 - - # Main controller must still be waiting - assert int(dut.busy_o.value) == 1 - - # ================================================== - # 5. Simulate results from OpenEye - # ================================================== - - received = {} - - for address, word in enumerate([0xAA, 0xBB]): - - dut.dma_result_data_i.value = word - dut.dma_result_valid_i.value = 1 - dut.dma_result_last_i.value = int(address == 1) - - await Timer(1, unit="ns") - - assert int(dut.result_write_o.value) == 1 - assert int(dut.result_addr_o.value) == address - assert int(dut.result_data_o.value) == word - - received[address] = int(dut.result_data_o.value) - - await tick(dut) - - dut.dma_result_valid_i.value = 0 - dut.dma_result_last_i.value = 0 - - assert received == {0: 0xAA, 1: 0xBB} - - # Adapter has completed, but the main controller - # has not yet processed the completion signal. - assert int(dut.adapter_busy_o.value) == 0 - assert int(dut.busy_o.value) == 1 - assert int(dut.done_o.value) == 0 - - # ================================================== - # 6. Verify main controller completion - # ================================================== - - # Main controller detects the adapter's done pulse - await tick(dut) - - assert int(dut.done_o.value) == 0 - - # Main controller executes its DONE state - await tick(dut) - - assert int(dut.done_o.value) == 1 - assert int(dut.busy_o.value) == 0 - assert int(dut.adapter_busy_o.value) == 0 - - # Completion must last exactly one clock - await tick(dut) - - assert int(dut.done_o.value) == 0 - - dut._log.info("GEMV controller + DMA adapter integration PASSED") \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_gemv_openeye_repeat_tb.py b/test/cocotb_attention_qkt/attention_gemv_openeye_repeat_tb.py deleted file mode 100644 index 74e09d08..00000000 --- a/test/cocotb_attention_qkt/attention_gemv_openeye_repeat_tb.py +++ /dev/null @@ -1,187 +0,0 @@ -# Multi-GEMV integration test without resetting the hardware. -# Executes Q[0] and Q[1] using selectable ROM banks. -# Verifies input streams, output results, and bank selection stability. - -from pathlib import Path - -import cocotb -from cocotb.clock import Clock -from cocotb.triggers import RisingEdge, FallingEdge, Timer - - -@cocotb.test() -async def test_two_distinct_gemvs(dut): - - data_dir = Path(__file__).resolve().parent / "data" - -# Reference data for both GEMV operations - gemv_cases = [ - ( - 0, - "gemv_reference.mem", - "gemv_expected_output.txt", - ), - ( - 1, - "gemv_q1_reference.mem", - "gemv_q1_expected_output.txt", - ), - ] - - # Initialize hardware only once - dut.clk_i.value = 0 - dut.rst_ni.value = 0 - dut.start_i.value = 0 - dut.bank_select_i.value = 0 - - cocotb.start_soon(Clock(dut.clk_i, 20, unit="ns").start()) - - for _ in range(8): - await RisingEdge(dut.clk_i) - await Timer(1, unit="ns") - - dut.rst_ni.value = 1 - - for _ in range(8): - await RisingEdge(dut.clk_i) - await Timer(1, unit="ns") - - # Execute three independent GEMVs without another reset - for run_id, (bank, input_file, output_file) in enumerate(gemv_cases): - - input_words = [ - int(line, 16) - for line in (data_dir / input_file).read_text().splitlines() - if line.strip() - ] - - expected = [ - int(line) - for line in (data_dir / output_file).read_text().splitlines() - if line.strip() - ] - - assert len(input_words) == 939 - assert len(expected) == 8 - - # Continue with the existing ready-wait loop... - - # Allow controller to return to IDLE - for _ in range(3): - await FallingEdge(dut.clk_i) - await Timer(1, unit="ns") - - # Wait until OpenEye can accept a new stream - for _ in range(200): - await FallingEdge(dut.clk_i) - await Timer(1, unit="ns") - - if (int(dut.u_openeye.ready_dma_o.value) == 1 - and int(dut.busy_o.value) == 0): - break - else: - raise AssertionError( - f"GEMV {run_id + 1}: OpenEye not ready" - ) - - dut._log.info("Starting GEMV %d", run_id + 1) - - # Select the ROM bank before starting the GEMV - dut.bank_select_i.value = bank - - # Send one start pulse - dut.start_i.value = 1 - - await FallingEdge(dut.clk_i) - await Timer(1, unit="ns") - - dut.start_i.value = 0 - - sent_count = 0 - raw_results = [] - - # Monitor this GEMV - for cycle in range(2500): - - await FallingEdge(dut.clk_i) - await Timer(1, unit="ns") - - if int(dut.u_openeye.enable_dma_i.value): - - assert sent_count < 939, ( - f"GEMV {run_id + 1}: Extra input word" - ) - - actual_word = int(dut.u_openeye.data_dma_i.value) - - assert actual_word == input_words[sent_count], ( - f"GEMV {run_id + 1}: " - f"Input mismatch at word {sent_count}" - ) - - sent_count += 1 - - # Try changing the external bank during transmission - if sent_count == 100: - dut.bank_select_i.value = 1 - bank - - if sent_count == 200: - dut.bank_select_i.value = bank - - if int(dut.result_write_o.value): - - address = int(dut.result_addr_o.value) - word = int(dut.result_data_o.value) - - assert address == len(raw_results), ( - f"GEMV {run_id + 1}: Result address mismatch" - ) - - raw_results.append(word) - - if int(dut.done_o.value): - break - - else: - raise AssertionError( - f"GEMV {run_id + 1} timeout: " - f"sent={sent_count}/939, " - f"results={len(raw_results)}" - ) - - assert sent_count == 939 - assert len(raw_results) == 32 - - # Decode signed 20-bit PSUM values - decoded = [] - - for word in raw_results: - value = word & ((1 << 20) - 1) - - if value & (1 << 19): - value -= 1 << 20 - - decoded.append(value) - - # Restore logical output ordering - actual = [0] * 32 - - for beat, value in enumerate(decoded): - filter_index = (beat % 2) * 16 + (beat // 2) - actual[filter_index] = value - - assert actual[:8] == expected, ( - f"GEMV {run_id + 1}: " - f"Expected {expected}, got {actual[:8]}" - ) - - assert actual[8:] == [0] * 24, ( - f"GEMV {run_id + 1}: Padding mismatch" - ) - - dut._log.info( - "GEMV %d PASSED: cycles=%d, inputs=%d, outputs=%d", - run_id + 1, cycle + 1, sent_count, len(raw_results) - ) - - dut._log.info("Both Q[0] and Q[1] GEMVs PASSED") diff --git a/test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py b/test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py deleted file mode 100644 index 04c3e092..00000000 --- a/test/cocotb_attention_qkt/attention_gemv_openeye_top_tb.py +++ /dev/null @@ -1,152 +0,0 @@ -# Single-GEMV integration test for the real OpenEye accelerator. -# Verifies DMA input streaming and Q[0] results against golden references. - -from pathlib import Path - -import cocotb -from cocotb.clock import Clock -from cocotb.triggers import RisingEdge, FallingEdge, Timer - - -@cocotb.test() -async def test_one_real_gemv(dut): - - data_dir = Path(__file__).resolve().parent / "data" - - # Golden input stream - input_words = [ - int(line, 16) - for line in - (data_dir / "gemv_reference.mem").read_text().splitlines() - if line.strip() - ] - - # Golden mathematical output - expected = [ - int(line) - for line in - (data_dir / "gemv_expected_output.txt").read_text().splitlines() - if line.strip() - ] - - assert len(input_words) == 939 - assert len(expected) == 8 - - # Initialize hardware - dut.clk_i.value = 0 - dut.rst_ni.value = 0 - dut.start_i.value = 0 - - cocotb.start_soon( - Clock(dut.clk_i, 20, unit="ns").start() - ) - - # Reset - for _ in range(6): - await RisingEdge(dut.clk_i) - await Timer(1, unit="ns") - - dut.rst_ni.value = 1 - - # Allow OpenEye reset synchronizer to settle - for _ in range(4): - await RisingEdge(dut.clk_i) - await Timer(1, unit="ns") - - # Start one GEMV - dut.start_i.value = 1 - - await RisingEdge(dut.clk_i) - await Timer(1, unit="ns") - - dut.start_i.value = 0 - - sent_count = 0 - raw_results = [] - - # Wait for the GEMV to finish - for cycle in range(2500): - - await FallingEdge(dut.clk_i) - await Timer(1, unit="ns") - - # Monitor input words entering OpenEye - if int(dut.u_openeye.enable_dma_i.value): - - assert sent_count < len(input_words), ( - "More than 939 input words transmitted" - ) - - actual_word = int(dut.u_openeye.data_dma_i.value) - expected_word = input_words[sent_count] - - assert actual_word == expected_word, ( - f"Input mismatch at word {sent_count}: " - f"expected {expected_word:016X}, " - f"got {actual_word:016X}" - ) - - sent_count += 1 - - # Capture results accepted by our DMA adapter - if int(dut.result_write_o.value): - - address = int(dut.result_addr_o.value) - word = int(dut.result_data_o.value) - - assert address == len(raw_results), ( - f"Unexpected result address: {address}" - ) - - raw_results.append(word) - - if int(dut.done_o.value): - break - - else: - raise AssertionError( - f"GEMV timeout: sent={sent_count}/939, " - f"results={len(raw_results)}" - ) - - assert sent_count == 939, ( - f"Only {sent_count} input words transmitted" - ) - - # The 32 padded output values use one DMA word each - assert len(raw_results) == 32, ( - f"Expected 32 result words, got {len(raw_results)}" - ) - - # Decode signed 20-bit PSUM values - decoded = [] - - for word in raw_results: - raw = word & ((1 << 20) - 1) - - if raw & (1 << 19): - raw -= 1 << 20 - - decoded.append(raw) - - # OpenEye interleaves its two cluster columns - actual = [0] * 32 - - for beat, value in enumerate(decoded): - filter_index = (beat % 2) * 16 + (beat // 2) - actual[filter_index] = value - - assert actual[:8] == expected, ( - f"GEMV mismatch:\n" - f"Expected: {expected}\n" - f"Actual: {actual[:8]}" - ) - - assert actual[8:] == [0] * 24, ( - "Nonzero values found in padded outputs" - ) - - dut._log.info("Input words transmitted: %d", sent_count) - dut._log.info("DMA result words received: %d", len(raw_results)) - dut._log.info("GEMV result: %s", actual[:8]) - dut._log.info("Real OpenEye GEMV integration PASSED") \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_gemv_rom_tb.py b/test/cocotb_attention_qkt/attention_gemv_rom_tb.py deleted file mode 100644 index a30988ae..00000000 --- a/test/cocotb_attention_qkt/attention_gemv_rom_tb.py +++ /dev/null @@ -1,43 +0,0 @@ -from pathlib import Path - -import cocotb -from cocotb.triggers import Timer - - -@cocotb.test() -async def test_gemv_rom(dut): - - # Read the original reference file - test_dir = Path(__file__).resolve().parent - mem_file = test_dir / "data" / "gemv_reference.mem" - - words = [ - int(line.strip(), 16) - for line in mem_file.read_text().splitlines() - if line.strip() - ] - - assert len(words) == 939 - - # Verify every ROM address - for address, expected_word in enumerate(words): - - dut.addr_i.value = address - - await Timer(1, unit="ns") - - actual_word = int(dut.data_o.value) - - assert actual_word == expected_word, ( - f"ROM mismatch at address {address}: " - f"expected {expected_word:016X}, " - f"got {actual_word:016X}" - ) - - # Verify an out-of-range address returns zero - dut.addr_i.value = len(words) - await Timer(1, unit="ns") - - assert int(dut.data_o.value) == 0 - - dut._log.info("ROM verification PASSED: 939 words checked") \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_gemv_rom_top_tb.py b/test/cocotb_attention_qkt/attention_gemv_rom_top_tb.py deleted file mode 100644 index 2b47ca2f..00000000 --- a/test/cocotb_attention_qkt/attention_gemv_rom_top_tb.py +++ /dev/null @@ -1,95 +0,0 @@ -from pathlib import Path - -import cocotb -from cocotb.clock import Clock -from cocotb.triggers import RisingEdge, Timer - - -async def tick(dut): - await RisingEdge(dut.clk_i) - await Timer(1, unit="ns") - - -@cocotb.test() -async def test_rom_adapter_stream(dut): - - # Load expected DMA words - test_dir = Path(__file__).resolve().parent - mem_file = test_dir / "data" / "gemv_reference.mem" - - expected_words = [ - int(line.strip(), 16) - for line in mem_file.read_text().splitlines() - if line.strip() - ] - - assert len(expected_words) == 939 - - # Initialize signals - dut.clk_i.value = 0 - dut.rst_ni.value = 0 - dut.start_i.value = 0 - dut.dma_ready_i.value = 0 - - dut.dma_result_data_i.value = 0 - dut.dma_result_valid_i.value = 0 - dut.dma_result_last_i.value = 0 - - cocotb.start_soon( - Clock(dut.clk_i, 10, unit="ns").start() - ) - - # Reset - await tick(dut) - await tick(dut) - - dut.rst_ni.value = 1 - await tick(dut) - - # Start one GEMV - dut.start_i.value = 1 - await tick(dut) - dut.start_i.value = 0 - - # DMA is not ready yet - for _ in range(4): - await tick(dut) - assert int(dut.dma_valid_o.value) == 0 - - # Allow transmission - dut.dma_ready_i.value = 1 - await tick(dut) - - # Verify all 939 transmitted words - for address, expected_word in enumerate(expected_words): - - actual_address = int(dut.stream_addr_o.value) - actual_word = int(dut.dma_data_o.value) - valid = int(dut.dma_valid_o.value) - - assert valid == 1, f"DMA not valid at word {address}" - - assert actual_address == address, ( - f"Address mismatch: expected {address}, " - f"got {actual_address}" - ) - - assert actual_word == expected_word, ( - f"Data mismatch at address {address}: " - f"expected {expected_word:016X}, " - f"got {actual_word:016X}" - ) - - await tick(dut) - - # Input transfer must be finished - assert int(dut.dma_valid_o.value) == 0 - - # Adapter should now be waiting for OpenEye results - assert int(dut.dma_result_ready_o.value) == 1 - assert int(dut.done_o.value) == 0 - - dut._log.info( - "ROM + DMA Adapter PASSED: %d words transmitted", - len(expected_words) - ) \ No newline at end of file diff --git a/test/cocotb_attention_qkt/attention_qkt_ctrl_tb.py b/test/cocotb_attention_qkt/attention_qkt_ctrl_tb.py deleted file mode 100644 index 6db215f4..00000000 --- a/test/cocotb_attention_qkt/attention_qkt_ctrl_tb.py +++ /dev/null @@ -1,73 +0,0 @@ -import cocotb -from cocotb.clock import Clock -from cocotb.triggers import RisingEdge, Timer - - -async def tick(dut): - """Wait for one rising clock edge and updated RTL outputs.""" - await RisingEdge(dut.clk_i) - await Timer(1, unit="ns") - - -@cocotb.test() -async def test_controller(dut): - - dut.clk_i.value = 0 - dut.rst_ni.value = 0 - dut.start_i.value = 0 - dut.gemv_done_i.value = 0 - - cocotb.start_soon(Clock(dut.clk_i, 10, unit="ns").start()) - - # Test 1: Reset - await tick(dut) - assert int(dut.busy_o.value) == 0 - assert int(dut.done_o.value) == 0 - assert int(dut.gemv_start_o.value) == 0 - - dut.rst_ni.value = 1 - - # Test 2: Start a GEMV operation - dut.start_i.value = 1 - await tick(dut) - - assert int(dut.busy_o.value) == 1 - - dut.start_i.value = 0 - await tick(dut) - - assert int(dut.gemv_start_o.value) == 1 - - # Test 3: Wait for GEMV completion - await tick(dut) - assert int(dut.gemv_start_o.value) == 0 - assert int(dut.busy_o.value) == 1 - - for _ in range(3): - await tick(dut) - assert int(dut.done_o.value) == 0 - - # Test 4: Simulate GEMV completion - dut.gemv_done_i.value = 1 - await tick(dut) - dut.gemv_done_i.value = 0 - - await tick(dut) - - assert int(dut.done_o.value) == 1 - assert int(dut.busy_o.value) == 0 - - # Test 5: Completion pulse must end - await tick(dut) - assert int(dut.done_o.value) == 0 - - # Test 6: Controller accepts another operation - dut.start_i.value = 1 - await tick(dut) - - dut.start_i.value = 0 - await tick(dut) - - assert int(dut.gemv_start_o.value) == 1 - - dut._log.info("Attention QKT controller FSM test PASSED") \ No newline at end of file diff --git a/test/cocotb_attention_qkt/quantization_unit_tb.py b/test/cocotb_attention_qkt/quantization_unit_tb.py deleted file mode 100644 index 0666e351..00000000 --- a/test/cocotb_attention_qkt/quantization_unit_tb.py +++ /dev/null @@ -1,89 +0,0 @@ -"""Characterization of the unchanged OpenEye quantization_unit.v. - -Expected behavior: signed (psum + offset) * mantissa, arithmetic shift, -then 8-bit truncation (NOT rounding or saturation), with 3-stage latency. -""" - -import cocotb -from cocotb.triggers import Timer - - -def signed_bits(bits: int, width: int) -> int: - bits &= (1 << width) - 1 - return bits - (1 << width) if bits & (1 << (width - 1)) else bits - - -def reference(psum: int, mant: int, offset: int, shift: int) -> int: - # Python's right shift of signed integers rounds toward -infinity, - # like Verilog's arithmetic >>> on a signed operand. - shifted = (mant * (psum + offset)) >> shift - return signed_bits(shifted, 8) # Actual RTL truncates to 8 bits. - - -async def tick(dut, *, psum=0, mant=1, offset=0, shift=0): - """One complete clock cycle, safely sampling outputs after the edge.""" - dut.clk_i.value = 0 - dut.psum_data.value = psum & ((1 << 20) - 1) - dut.quant_mant.value = mant & ((1 << 25) - 1) - dut.quant_offset.value = offset & 0xFF - dut.current_shift.value = shift - await Timer(5, unit="ns") - dut.clk_i.value = 1 - await Timer(5, unit="ns") - return signed_bits(int(dut.quantized_value.value), 8) - - -@cocotb.test() -async def test_existing_quantizer_pipeline(dut): - """Verify sign handling, scale, zeroing, wraparound, and 3-cycle pipeline.""" - dut.clk_i.value = 0 - dut.rst_n.value = 0 - dut.psum_data.value = 0 - dut.quant_mant.value = 0 - dut.quant_offset.value = 0 - dut.current_shift.value = 0 - await tick(dut) - assert int(dut.quantized_value.value) == 0, "Reset did not clear output" - dut.rst_n.value = 1 - - # (signed 20-bit PSUM, signed 25-bit mantissa, signed 8-bit offset, shift) - vectors = [ - (0, 1, 0, 0), # Zero stays zero - (3, 1, 0, 3), # Small positive becomes ZERO - (-2, 1, 0, 3), # Arithmetic shift: -2 >>> 3 becomes -1 - (700, 1, 0, 3), # 87 (truncation, not round-to-nearest 88) - (-700, 1, 0, 3), # -88 - (12, 5, -2, 1), # Mantissa and signed offset: 25 - (200, 1, 0, 0), # 200 wraps to -56 (no saturation) - (-200, 1, 0, 0), # -200 wraps to +56 - (127, 1, 0, 0), # INT8 upper endpoint - (-128, 1, 0, 0), # INT8 lower endpoint - (400, 2, 0, 4), # More than one mantissa factor - (-400, 2, 0, 4), - (32, -3, 0, 3), # Negative mantissa - (524287, 1, 0, 13), # Max signed 20-bit PSUM - (-524288, 1, 0, 13),# Min signed 20-bit PSUM - (1, 1, 0, 7), # Positive quantization-to-zero - (-1, 1, 0, 7), # Negative floors to -1 - (0, 1, 5, 0), # Offset is added before scaling - (0, 1, -5, 0), - (700, 3, 0, 5), # Fractional multiplier 3/32 - (-700, 3, 0, 5), - ] - - # No valid_out in RTL, so associate outputs with the inputs from - # two rising edges earlier (3-stage pipeline: S1/S2/S3). - for cycle in range(len(vectors) + 2): - sample = vectors[cycle] if cycle < len(vectors) else (0, 1, 0, 0) - actual = await tick(dut, psum=sample[0], mant=sample[1], - offset=sample[2], shift=sample[3]) - if cycle >= 2: - original_index = cycle - 2 - expected = reference(*vectors[original_index]) - assert actual == expected, ( - f"Mismatch for input #{original_index} " - f"{vectors[original_index]}: expected {expected}, got {actual}" - ) - - dut._log.info("PASS: all %d signed/pipeline quantizer cases", len(vectors)) - dut._log.info("Confirmed: arithmetic shift, no rounding, no saturation") diff --git a/test/cocotb_attention_qkt/test_attention_gemv_control_top.py b/test/cocotb_attention_qkt/test_attention_gemv_control_top.py deleted file mode 100644 index 85bb8cb7..00000000 --- a/test/cocotb_attention_qkt/test_attention_gemv_control_top.py +++ /dev/null @@ -1,26 +0,0 @@ -from pathlib import Path -import cocotb_test.simulator - - -def test_attention_gemv_control_top(): - - root = Path(__file__).resolve().parents[2] - test_dir = Path(__file__).resolve().parent - - cocotb_test.simulator.run( - verilog_sources=[ - str(root / "hdl" / "attention_qkt_ctrl.v"), - str(root / "hdl" / "attention_dma_adapter.v"), - str(root / "hdl" / "attention_gemv_control_top.v"), - ], - - toplevel="attention_gemv_control_top", - module="attention_gemv_control_top_tb", - - python_search=[str(test_dir)], - sim_build=str(test_dir / ".sim_build"), - - simulator="icarus", - force_compile=True, - waves=True, - ) diff --git a/test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py b/test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py deleted file mode 100644 index 1a71a4da..00000000 --- a/test/cocotb_attention_qkt/test_attention_gemv_openeye_repeat.py +++ /dev/null @@ -1,85 +0,0 @@ -import os -import shutil -from pathlib import Path - -import cocotb_test.simulator - -import open_eye.test_utils_main as ptu -import open_eye.vh_file_creator as vh_creator -import open_eye.generator as generator - -from open_eye import hdl_dir - - -def test_attention_gemv_openeye_top(): - - root = Path(__file__).resolve().parents[2] - test_dir = Path(__file__).resolve().parent - - build_dir = test_dir / ".sim_build_openeye_repeat" - build_dir.mkdir(parents=True, exist_ok=True) - - # Match the configuration of the original Attention test - config = { - "CLUSTER_ROWS": "2", - "CLUSTER_COLUMNS": "2", - "NUM_GLB_IACT": "3", - "NUM_GLB_PSUM": "4", - "NUM_GLB_WGHT": "3", - "DATAFLOW": "row stationary", - "BRANCHES": "1", - "BUFFER_WIDTH": "12", - "QUANT_AMOUNT": "1024", - "RAM_CELLS": "32", - } - - os.environ.update(config) - - # Generate the exact OpenEye parameter headers - vh_creator.create_vh_file_from_envvars( - str(build_dir), - str(hdl_dir) + os.sep, - toplevel="OpenEye_FPGA" - ) - - # Generate the register-map decoder - generator.create_regmap_params_vh_file( - str(root / "test" / "cocotb_fpga"), - str(build_dir), - str(build_dir) - ) - - # Copy the reference DMA stream for $readmemh - shutil.copyfile( - test_dir / "data" / "gemv_reference.mem", - build_dir / "gemv_reference.mem" - ) - - shutil.copyfile( - test_dir / "data" / "gemv_q1_reference.mem", - build_dir / "gemv_q1_reference.mem" - ) - - # Compile the actual OpenEye hardware sources - sources = [ - src for src in ptu.get_verilog_sources(str(hdl_dir)) - if os.path.basename(src) != "dma_storage.v" - ] - - # Use the decoder generated for this exact configuration - sources.append(str(build_dir / "dma_storage.v")) - - cocotb_test.simulator.run( - verilog_sources=sources, - toplevel="attention_gemv_openeye_top", - module="attention_gemv_openeye_repeat_tb", - python_search=[str(test_dir)], - sim_build=str(build_dir), - simulator="icarus", - defines={ - "NO_TRACE": "TRUE", - "USE_INTERNAL_PARAMS_PE": "TRUE", - }, - force_compile=True, - waves=True, - ) \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py b/test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py deleted file mode 100644 index a5ae284f..00000000 --- a/test/cocotb_attention_qkt/test_attention_gemv_openeye_top.py +++ /dev/null @@ -1,80 +0,0 @@ -import os -import shutil -from pathlib import Path - -import cocotb_test.simulator - -import open_eye.test_utils_main as ptu -import open_eye.vh_file_creator as vh_creator -import open_eye.generator as generator - -from open_eye import hdl_dir - - -def test_attention_gemv_openeye_top(): - - root = Path(__file__).resolve().parents[2] - test_dir = Path(__file__).resolve().parent - - build_dir = test_dir / ".sim_build_openeye" - build_dir.mkdir(parents=True, exist_ok=True) - - # Match the configuration of the original Attention test - config = { - "CLUSTER_ROWS": "2", - "CLUSTER_COLUMNS": "2", - "NUM_GLB_IACT": "3", - "NUM_GLB_PSUM": "4", - "NUM_GLB_WGHT": "3", - "DATAFLOW": "row stationary", - "BRANCHES": "1", - "BUFFER_WIDTH": "12", - "QUANT_AMOUNT": "1024", - "RAM_CELLS": "32", - } - - os.environ.update(config) - - # Generate the exact OpenEye parameter headers - vh_creator.create_vh_file_from_envvars( - str(build_dir), - str(hdl_dir) + os.sep, - toplevel="OpenEye_FPGA" - ) - - # Generate the register-map decoder - generator.create_regmap_params_vh_file( - str(root / "test" / "cocotb_fpga"), - str(build_dir), - str(build_dir) - ) - - # Copy the reference DMA stream for $readmemh - shutil.copyfile( - test_dir / "data" / "gemv_reference.mem", - build_dir / "gemv_reference.mem" - ) - - # Compile the actual OpenEye hardware sources - sources = [ - src for src in ptu.get_verilog_sources(str(hdl_dir)) - if os.path.basename(src) != "dma_storage.v" - ] - - # Use the decoder generated for this exact configuration - sources.append(str(build_dir / "dma_storage.v")) - - cocotb_test.simulator.run( - verilog_sources=sources, - toplevel="attention_gemv_openeye_top", - module="attention_gemv_openeye_top_tb", - python_search=[str(test_dir)], - sim_build=str(build_dir), - simulator="icarus", - defines={ - "NO_TRACE": "TRUE", - "USE_INTERNAL_PARAMS_PE": "TRUE", - }, - force_compile=True, - waves=True, - ) \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_gemv_rom.py b/test/cocotb_attention_qkt/test_attention_gemv_rom.py deleted file mode 100644 index d13a9758..00000000 --- a/test/cocotb_attention_qkt/test_attention_gemv_rom.py +++ /dev/null @@ -1,34 +0,0 @@ -from pathlib import Path -import shutil - -import cocotb_test.simulator - - -def test_attention_gemv_rom(): - - root = Path(__file__).resolve().parents[2] - test_dir = Path(__file__).resolve().parent - - build_dir = test_dir / ".sim_build" - build_dir.mkdir(parents=True, exist_ok=True) - - # Copy memory initialization file into simulation directory - shutil.copyfile( - test_dir / "data" / "gemv_reference.mem", - build_dir / "gemv_reference.mem" - ) - - cocotb_test.simulator.run( - verilog_sources=[ - str(root / "hdl" / "attention_gemv_rom.v") - ], - - toplevel="attention_gemv_rom", - module="attention_gemv_rom_tb", - - python_search=[str(test_dir)], - sim_build=str(build_dir), - - simulator="icarus", - force_compile=True - ) \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_gemv_rom_top.py b/test/cocotb_attention_qkt/test_attention_gemv_rom_top.py deleted file mode 100644 index db22ae8f..00000000 --- a/test/cocotb_attention_qkt/test_attention_gemv_rom_top.py +++ /dev/null @@ -1,37 +0,0 @@ -from pathlib import Path -import shutil - -import cocotb_test.simulator - - -def test_attention_gemv_rom_top(): - - root = Path(__file__).resolve().parents[2] - test_dir = Path(__file__).resolve().parent - - build_dir = test_dir / ".sim_build" - build_dir.mkdir(parents=True, exist_ok=True) - - shutil.copyfile( - test_dir / "data" / "gemv_reference.mem", - build_dir / "gemv_reference.mem" - ) - - cocotb_test.simulator.run( - verilog_sources=[ - str(root / "hdl" / "attention_qkt_ctrl.v"), - str(root / "hdl" / "attention_dma_adapter.v"), - str(root / "hdl" / "attention_gemv_control_top.v"), - str(root / "hdl" / "attention_gemv_rom.v"), - str(root / "hdl" / "attention_gemv_rom_top.v"), - ], - - toplevel="attention_gemv_rom_top", - module="attention_gemv_rom_top_tb", - python_search=[str(test_dir)], - sim_build=str(build_dir), - - simulator="icarus", - force_compile=True, - waves=True, - ) \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_qkt_ctrl.py b/test/cocotb_attention_qkt/test_attention_qkt_ctrl.py deleted file mode 100644 index f68f944a..00000000 --- a/test/cocotb_attention_qkt/test_attention_qkt_ctrl.py +++ /dev/null @@ -1,20 +0,0 @@ -from pathlib import Path -import cocotb_test.simulator - - -def test_attention_qkt_ctrl(): - - root = Path(__file__).resolve().parents[2] - test_dir = Path(__file__).resolve().parent - - cocotb_test.simulator.run( - verilog_sources=[ - str(root / "hdl" / "attention_qkt_ctrl.v") - ], - toplevel="attention_qkt_ctrl", - module="attention_qkt_ctrl_tb", - python_search=[str(test_dir)], - sim_build=str(test_dir / ".sim_build"), - simulator="icarus", - force_compile=True, - ) \ No newline at end of file diff --git a/test/cocotb_attention_qkt/test_attention_top_e2e.py b/test/cocotb_attention_qkt/test_attention_top_e2e.py index 7003c354..6405ae2f 100644 --- a/test/cocotb_attention_qkt/test_attention_top_e2e.py +++ b/test/cocotb_attention_qkt/test_attention_top_e2e.py @@ -217,7 +217,7 @@ async def monitor(): ) assert seen_qkt == {0, 1, 2, 3}, f"Missing QKT GEMV(s): {seen_qkt}" assert counts["projection"] == 384, ( - f"Expected 12*8 projection DMA result beats, got {counts['projection']}" + f"Expected 12*32 projection DMA result beats, got {counts['projection']}" ) assert counts["qkt"] == 16, ( f"Expected 4*4 QKT DMA result beats, got {counts['qkt']}" diff --git a/test/cocotb_attention_qkt/test_quantization_unit.py b/test/cocotb_attention_qkt/test_quantization_unit.py deleted file mode 100644 index 99df906e..00000000 --- a/test/cocotb_attention_qkt/test_quantization_unit.py +++ /dev/null @@ -1,27 +0,0 @@ -"""Standalone pytest runner for OpenEye's *existing* quantization_unit.v.""" - -from pathlib import Path - -from cocotb_test.simulator import run - - -def test_quantization_unit(): - test_dir = Path(__file__).resolve().parent - repo_root = test_dir.parent.parent - - run( - verilog_sources=[str(repo_root / "hdl" / "quantization_unit.v")], - toplevel="quantization_unit", - module="quantization_unit_tb", - python_search=[str(test_dir)], - simulator="icarus", - parameters={ - "PSUM_WIDTH": 20, - "MANT_WIDTH": 25, - "OFFSET_WIDTH": 8, - "SHIFT_WIDTH": 7, - "OUT_WIDTH": 8, - }, - sim_build=str(test_dir / ".sim_build_quantization_unit"), - waves=False, - ) From c183aa308fd432ad4a3f408993fac6369a72b35e Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sun, 1 Nov 2026 15:32:03 +0100 Subject: [PATCH 30/36] Attention : Add and verify Softmax: Scaling + Exponential LUT --- hdl/attention_softmax_exp.v | 163 ++++++++++++++++++ .../run_softmax_exp.py | 16 ++ .../softmax_exp_reference.py | 49 ++++++ .../test_softmax_exp_cocotb.py | 63 +++++++ 4 files changed, 291 insertions(+) create mode 100644 hdl/attention_softmax_exp.v create mode 100644 test/cocotb_attention_softmax/run_softmax_exp.py create mode 100644 test/cocotb_attention_softmax/softmax_exp_reference.py create mode 100644 test/cocotb_attention_softmax/test_softmax_exp_cocotb.py diff --git a/hdl/attention_softmax_exp.v b/hdl/attention_softmax_exp.v new file mode 100644 index 00000000..c8c257cc --- /dev/null +++ b/hdl/attention_softmax_exp.v @@ -0,0 +1,163 @@ +`timescale 1ns / 1ps +// Standalone stage 1 for 4-way row-parallel Softmax: +// max subtraction -> shift-aware Q4.12 scaling -> 65-entry exp LUT. +// Does NOT change OpenEye, score buffer, or scheduler. +// Packed inputs: scores_i[19:0] is score 0, scores_i[39:20] score 1, etc. +// Packed outputs: exp_values_o[15:0] is E0, [31:16] E1, etc. +// All ROM outputs are unsigned Q1.15: encoded 1.0 = 32768. +// Numerical test convention: Q20_real = Q20/4096, K20_real = K20/4096. +// Therefore: L_q12 = round((score - max)*2^(q_shift+k_shift-12)/sqrt(8)). +// Constant 23170/65536 approximates 1/sqrt(8). +// q_shift,k_shift are 0..13 for the existing 20-bit Q/K quantizer. +module attention_softmax_exp ( + input wire clk_i, + input wire rst_ni, + input wire valid_i, + input wire [79:0] scores_i, + input wire [6:0] q_shift_i, + input wire [6:0] k_shift_i, + output reg valid_o, + output reg [63:0] exp_values_o +); + function [15:0] lut_exp; + input [6:0] addr; + begin + case (addr) + 7'd0: lut_exp = 16'd32768; + 7'd1: lut_exp = 16'd28918; + 7'd2: lut_exp = 16'd25520; + 7'd3: lut_exp = 16'd22521; + 7'd4: lut_exp = 16'd19875; + 7'd5: lut_exp = 16'd17539; + 7'd6: lut_exp = 16'd15479; + 7'd7: lut_exp = 16'd13660; + 7'd8: lut_exp = 16'd12055; + 7'd9: lut_exp = 16'd10638; + 7'd10: lut_exp = 16'd9388; + 7'd11: lut_exp = 16'd8285; + 7'd12: lut_exp = 16'd7312; + 7'd13: lut_exp = 16'd6452; + 7'd14: lut_exp = 16'd5694; + 7'd15: lut_exp = 16'd5025; + 7'd16: lut_exp = 16'd4435; + 7'd17: lut_exp = 16'd3914; + 7'd18: lut_exp = 16'd3454; + 7'd19: lut_exp = 16'd3048; + 7'd20: lut_exp = 16'd2690; + 7'd21: lut_exp = 16'd2374; + 7'd22: lut_exp = 16'd2095; + 7'd23: lut_exp = 16'd1849; + 7'd24: lut_exp = 16'd1631; + 7'd25: lut_exp = 16'd1440; + 7'd26: lut_exp = 16'd1271; + 7'd27: lut_exp = 16'd1121; + 7'd28: lut_exp = 16'd990; + 7'd29: lut_exp = 16'd873; + 7'd30: lut_exp = 16'd771; + 7'd31: lut_exp = 16'd680; + 7'd32: lut_exp = 16'd600; + 7'd33: lut_exp = 16'd530; + 7'd34: lut_exp = 16'd467; + 7'd35: lut_exp = 16'd412; + 7'd36: lut_exp = 16'd364; + 7'd37: lut_exp = 16'd321; + 7'd38: lut_exp = 16'd283; + 7'd39: lut_exp = 16'd250; + 7'd40: lut_exp = 16'd221; + 7'd41: lut_exp = 16'd195; + 7'd42: lut_exp = 16'd172; + 7'd43: lut_exp = 16'd152; + 7'd44: lut_exp = 16'd134; + 7'd45: lut_exp = 16'd118; + 7'd46: lut_exp = 16'd104; + 7'd47: lut_exp = 16'd92; + 7'd48: lut_exp = 16'd81; + 7'd49: lut_exp = 16'd72; + 7'd50: lut_exp = 16'd63; + 7'd51: lut_exp = 16'd56; + 7'd52: lut_exp = 16'd49; + 7'd53: lut_exp = 16'd43; + 7'd54: lut_exp = 16'd38; + 7'd55: lut_exp = 16'd34; + 7'd56: lut_exp = 16'd30; + 7'd57: lut_exp = 16'd26; + 7'd58: lut_exp = 16'd23; + 7'd59: lut_exp = 16'd21; + 7'd60: lut_exp = 16'd18; + 7'd61: lut_exp = 16'd16; + 7'd62: lut_exp = 16'd14; + 7'd63: lut_exp = 16'd12; + 7'd64: lut_exp = 16'd11; + default: lut_exp = 16'd0; + endcase + end + endfunction + + function [15:0] exp_from_score; + input signed [19:0] score; + input signed [19:0] row_max; + input [7:0] total_shift; + reg signed [20:0] diff; + reg [20:0] distance; + reg [36:0] product; + reg [36:0] magnitude_q12; + reg [7:0] right_shift; + reg [6:0] address; + begin + diff = $signed({score[19], score}) - $signed({row_max[19], row_max}); + if (diff >= 0) begin + // Exactly e^0 for the row maximum (also handles all-equal rows). + exp_from_score = 16'd32768; + end else if (total_shift > 8'd26) begin + // Invalid shift combination for this 20-bit-quantizer baseline. + // This guard avoids a negative shift count; legitimate inputs never reach it. + exp_from_score = 16'd0; + end else begin + distance = -diff; + product = distance * 37'd23170; + // Q4.12 magnitude with round-to-nearest, ties up: + // abs(delta) * (23170/65536) * 2^(total_shift-12) * 4096 + right_shift = 8'd28 - total_shift; + magnitude_q12 = (product + (37'd1 << (right_shift - 1'b1))) >> right_shift; + if (magnitude_q12 > 37'd32768) begin + // x < -8 -> exp(x) approximated as zero, NOT exp(-8). + exp_from_score = 16'd0; + end else begin + // 0.125 spacing = 512 units in Q4.12; nearest-neighbor lookup. + address = (magnitude_q12 + 37'd256) >> 9; + // Due to input range, address stays in [0, 64]. + exp_from_score = lut_exp(address); + end + end + end + endfunction + + reg signed [19:0] row_max; + reg [7:0] total_shift; + reg [63:0] exp_next; + integer i; + always @(*) begin + row_max = $signed(scores_i[19:0]); + for (i = 1; i < 4; i = i + 1) begin + if ($signed(scores_i[i*20 +: 20]) > row_max) + row_max = $signed(scores_i[i*20 +: 20]); + end + total_shift = {1'b0, q_shift_i} + {1'b0, k_shift_i}; + exp_next = 64'd0; + for (i = 0; i < 4; i = i + 1) + exp_next[i*16 +: 16] = exp_from_score( + $signed(scores_i[i*20 +: 20]), row_max, total_shift + ); + end + + // One registered output per valid input row; no busy state or row storage yet. + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + valid_o <= 1'b0; + exp_values_o <= 64'd0; + end else begin + valid_o <= valid_i; + if (valid_i) exp_values_o <= exp_next; + end + end +endmodule diff --git a/test/cocotb_attention_softmax/run_softmax_exp.py b/test/cocotb_attention_softmax/run_softmax_exp.py new file mode 100644 index 00000000..873303f0 --- /dev/null +++ b/test/cocotb_attention_softmax/run_softmax_exp.py @@ -0,0 +1,16 @@ +"""Run with: python -m pytest run_softmax_exp.py -v -s""" +from pathlib import Path +from open_eye import hdl_dir +import os + + +def test_softmax_exp(): + from cocotb_test.simulator import run + here = Path(__file__).resolve().parent + run(verilog_sources=[str(Path(hdl_dir) / 'attention_softmax_exp.v')], + toplevel='attention_softmax_exp', + module='test_softmax_exp_cocotb', + python_search=[str(here)], + sim_build=str(here / 'sim_build'), + simulator='icarus', + force_compile=True) diff --git a/test/cocotb_attention_softmax/softmax_exp_reference.py b/test/cocotb_attention_softmax/softmax_exp_reference.py new file mode 100644 index 00000000..6ef88152 --- /dev/null +++ b/test/cocotb_attention_softmax/softmax_exp_reference.py @@ -0,0 +1,49 @@ +"""Bit-accurate software model for standalone OpenEye Softmax scaling+EXP stage.""" +import math + +LUT = [math.floor(math.exp(-i/8) * 32768 + 0.5) for i in range(65)] + + +def exp_row(scores, q_shift, k_shift): + assert len(scores) == 4 + assert all(-(1 << 19) <= v < (1 << 19) for v in scores) + assert 0 <= q_shift <= 13 and 0 <= k_shift <= 13 + max_score = max(scores) + shift_right = 28 - (q_shift + k_shift) + out = [] + for score in scores: + if score == max_score: + out.append(32768) + continue + magnitude = max_score - score + q12_abs = (magnitude * 23170 + (1 << (shift_right - 1))) >> shift_right + if q12_abs > 32768: + out.append(0) + else: + addr = (q12_abs + 256) >> 9 + out.append(LUT[addr]) + return out + + +def softmax_ref(scores, q_shift, k_shift): + """Floating-point reference using convention Q20_real=Q20/4096.""" + beta = 2 ** (q_shift + k_shift) / (4096**2 * math.sqrt(8)) + m = max(scores) + terms = [math.exp((v - m) * beta) for v in scores] + return [x / sum(terms) for x in terms] + + +if __name__ == '__main__': + import numpy as np + from pathlib import Path + path = Path(__file__).resolve().parent / 'data' / 'qkt_t0_reference.npz' + with np.load(path, allow_pickle=False) as f: + score_matrix = f['Q8'].astype(np.int64) @ f['K8'].astype(np.int64).T + qs, ks = int(f['q_shift']), int(f['k_shift']) + for row in score_matrix: + exp = exp_row([int(x) for x in row], qs, ks) + print('scores:', row.tolist(), 'E_Q1.15:', exp, 'normalized:', [round(x/sum(exp), 6) for x in exp]) + assert exp_row([int(x) for x in score_matrix[0]], 6, 6) == [13660, 3914, 32768, 13660] + assert exp_row([0,0,0,0], 6, 6) == [32768]*4 + assert exp_row([0,-100000,-200000,-300000], 6, 6) == [32768,0,0,0] + print('PASS: Python reference and deterministic checks (not RTL simulation)') diff --git a/test/cocotb_attention_softmax/test_softmax_exp_cocotb.py b/test/cocotb_attention_softmax/test_softmax_exp_cocotb.py new file mode 100644 index 00000000..41f0ee77 --- /dev/null +++ b/test/cocotb_attention_softmax/test_softmax_exp_cocotb.py @@ -0,0 +1,63 @@ +"""Standalone Cocotb test of attention_softmax_exp (not the full Attention RTL).""" +import random +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import FallingEdge, RisingEdge, Timer +from softmax_exp_reference import exp_row + + +def pack_row(values): + return sum((int(v) & ((1 << 20) - 1)) << (20*i) for i,v in enumerate(values)) + + +@cocotb.test() +async def check_scaling_and_exp(dut): + dut.rst_ni.value = 0 + dut.valid_i.value = 0 + dut.scores_i.value = 0 + dut.q_shift_i.value = 0 + dut.k_shift_i.value = 0 + cocotb.start_soon(Clock(dut.clk_i, 10, unit='ns').start()) + for _ in range(3): + await FallingEdge(dut.clk_i) + dut.rst_ni.value = 1 + + from pathlib import Path + import numpy as np + ref_path = Path(__file__).resolve().parent.parent / "cocotb_attention_qkt"/ "data"/ "qkt_single_8x4"/ "qkt_t0_reference.npz" + with np.load(ref_path, allow_pickle=False) as f: + matrix = f['Q8'].astype(np.int64) @ f['K8'].astype(np.int64).T + qs,ks = int(f['q_shift']), int(f['k_shift']) + cases = [(list(map(int,row)),qs,ks) for row in matrix] + cases += [ + ([0,0,0,0],6,6), + ([100,-100000,-200000,-300000],6,6), + ([-524288,-500000,524287,0],13,13), + ([-1,-2,-3,-4],0,0), + ([1,1,1,1],0,0), + ([524287,-524288,7,-8],5,9), + ] + rng = random.Random(37) + cases += [([rng.randrange(-(1<<19),1<<19) for _ in range(4)], + rng.randrange(14),rng.randrange(14)) for _ in range(100)] + + for row,q,k in cases: + await FallingEdge(dut.clk_i) + dut.scores_i.value = pack_row(row) + dut.q_shift_i.value = q + dut.k_shift_i.value = k + dut.valid_i.value = 1 + await RisingEdge(dut.clk_i) + await Timer(1,unit='ns') + assert int(dut.valid_o.value) == 1 + got = int(dut.exp_values_o.value) + actual = [(got >> (16*i)) & 0xFFFF for i in range(4)] + expected = exp_row(row,q,k) + assert actual == expected, f'row={row}, shift={q},{k}: {actual} != {expected}' + + await FallingEdge(dut.clk_i) + dut.valid_i.value = 0 + await RisingEdge(dut.clk_i) + await Timer(1,unit='ns') + assert int(dut.valid_o.value) == 0 + dut._log.info('PASS: 110 scaling/EXP cases including baseline, extremes and random') From 675c6a281563fd1a9893c9eaa2db2fac6e77f6ff Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sun, 1 Nov 2026 18:58:08 +0100 Subject: [PATCH 31/36] Attention : add and verify Softmax : Normalization with only one devider(exp/sum) --- hdl/attention_softmax_divider.v | 110 +++++++++++++++++ .../run_softmax_divider.py | 20 ++++ .../test_softmax_divider_cocotb.py | 113 ++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 hdl/attention_softmax_divider.v create mode 100644 test/cocotb_attention_softmax/run_softmax_divider.py create mode 100644 test/cocotb_attention_softmax/test_softmax_divider_cocotb.py diff --git a/hdl/attention_softmax_divider.v b/hdl/attention_softmax_divider.v new file mode 100644 index 00000000..3b5c94e5 --- /dev/null +++ b/hdl/attention_softmax_divider.v @@ -0,0 +1,110 @@ +`timescale 1ns / 1ps + +module attention_softmax_divider ( + input wire clk_i, + input wire rst_ni, + input wire start_i, + + input wire [15:0] exp_i, + input wire [17:0] sum_i, + + output wire busy_o, + output reg done_o, + output reg [15:0] probability_o +); + + // FSM State Definitions + localparam [1:0] IDLE = 2'd0; + localparam [1:0] DIVIDE = 2'd1; + localparam [1:0] DONE = 2'd2; + + reg [1:0] state; + + // Registers for Division Operation + reg [18:0] remainder; + reg [17:0] divisor; + reg [15:0] quotient; + reg [4:0] bit_count; + + + assign busy_o = (state == DIVIDE); + + wire [18:0] shifted_remainder; + wire quotient_bit; + wire [18:0] next_remainder; + wire [15:0] next_quotient; + wire round_up; + + assign shifted_remainder = remainder << 1; + + assign quotient_bit = + (shifted_remainder >= {1'b0, divisor}); + + assign next_remainder = quotient_bit + ? shifted_remainder - {1'b0, divisor} + : shifted_remainder; + + assign next_quotient = {quotient[14:0], quotient_bit}; + + assign round_up = + ({next_remainder, 1'b0} >= {2'b00, divisor}); + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state <= IDLE; + remainder <= 19'd0; + divisor <= 18'd0; + quotient <= 16'd0; + bit_count <= 5'd0; + probability_o <= 16'd0; + done_o <= 1'b0; + end else begin + done_o <= 1'b0; + + case (state) + + IDLE: begin + if (start_i) begin + if (sum_i == 0) begin + probability_o <= 16'd0; + state <= DONE; + end else if (exp_i == 0) begin + probability_o <= 16'd0; + state <= DONE; + end else if ({2'b00, exp_i} >= sum_i) begin + probability_o <= 16'd32768; + state <= DONE; + end else begin + remainder <= {3'b000, exp_i}; + divisor <= sum_i; + quotient <= 16'd0; + bit_count <= 5'd0; + state <= DIVIDE; + end + end + end + + DIVIDE: begin + remainder <= next_remainder; + quotient <= next_quotient; + + if (bit_count == 5'd14) begin + probability_o <= next_quotient + + (round_up ? 16'd1 : 16'd0); + state <= DONE; + end else begin + bit_count <= bit_count + 1'b1; + end + end + + DONE: begin + done_o <= 1'b1; + state <= IDLE; + end + + default: state <= IDLE; + + endcase + end + end +endmodule \ No newline at end of file diff --git a/test/cocotb_attention_softmax/run_softmax_divider.py b/test/cocotb_attention_softmax/run_softmax_divider.py new file mode 100644 index 00000000..ac4160fd --- /dev/null +++ b/test/cocotb_attention_softmax/run_softmax_divider.py @@ -0,0 +1,20 @@ +from pathlib import Path +from cocotb_test.simulator import run + + +def test_softmax_divider(): + + here = Path(__file__).resolve().parent + project_root = here.parent.parent + + run( + verilog_sources=[ + str(project_root / "hdl" / "attention_softmax_divider.v") + ], + toplevel="attention_softmax_divider", + module="test_softmax_divider_cocotb", + python_search=[str(here)], + sim_build=str(here / "sim_build_divider"), + simulator="icarus", + force_compile=True + ) \ No newline at end of file diff --git a/test/cocotb_attention_softmax/test_softmax_divider_cocotb.py b/test/cocotb_attention_softmax/test_softmax_divider_cocotb.py new file mode 100644 index 00000000..c380c76b --- /dev/null +++ b/test/cocotb_attention_softmax/test_softmax_divider_cocotb.py @@ -0,0 +1,113 @@ +import random +import cocotb + +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, FallingEdge, Timer + + +def reference_probability(exp, total): + if total == 0 or exp == 0: + return 0 + + if exp >= total: + return 32768 + + # UQ1.15, round-to-nearest, ties up + return (exp * 32768 + total // 2) // total + + +async def check_division(dut, exp, total): + + expected = reference_probability(exp, total) + + # Apply inputs before the rising clock edge + await FallingEdge(dut.clk_i) + + dut.exp_i.value = exp + dut.sum_i.value = total + dut.start_i.value = 1 + + # Divider receives start + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + # Remove start after one clock + await FallingEdge(dut.clk_i) + dut.start_i.value = 0 + + # Wait for division to finish + for cycle in range(20): + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + if int(dut.done_o.value) == 1: + actual = int(dut.probability_o.value) + + assert actual == expected, ( + f"exp={exp}, sum={total}: " + f"expected={expected}, actual={actual}" + ) + + # done_o must be a one-cycle pulse + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + assert int(dut.done_o.value) == 0 + return + + raise AssertionError( + f"Divider timeout: exp={exp}, sum={total}" + ) + + +@cocotb.test() +async def test_softmax_divider(dut): + + cocotb.start_soon( + Clock(dut.clk_i, 10, unit="ns").start() + ) + + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.exp_i.value = 0 + dut.sum_i.value = 0 + + await Timer(25, unit="ns") + await FallingEdge(dut.clk_i) + dut.rst_ni.value = 1 + + # Basic and boundary cases + cases = [ + (3, 8), + (1, 2), + (1, 3), + (2, 3), + (0, 64002), + (32768, 32768), + (32768, 131072), + (13660, 64002), + (3914, 64002), + (32768, 64002), + (1, 0), # Division by zero protection + (10, 9), # Invalid numerator > denominator + ] + + for exp, total in cases: + await check_division(dut, exp, total) + + # Random 4-element exponential rows + rng = random.Random(42) + + for _ in range(25): + row = [rng.randint(0, 32768) for _ in range(4)] + + # Max subtraction guarantees at least one exp(0) = 1 + row[rng.randrange(4)] = 32768 + + total = sum(row) + + for exp in row: + await check_division(dut, exp, total) + + dut._log.info("All divider test cases passed") \ No newline at end of file From 9342e54cfab6687aa4b1e60e7ae96174840debfb Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sun, 1 Nov 2026 19:13:12 +0100 Subject: [PATCH 32/36] Attention : add and verify Sotmax : Four devider in parallel with a shared Sum --- hdl/attention_softmax_normalize.v | 108 ++++++++++++++ .../run_softmax_normalize.py | 21 +++ .../test_softmax_normalize_cocotb.py | 133 ++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100644 hdl/attention_softmax_normalize.v create mode 100644 test/cocotb_attention_softmax/run_softmax_normalize.py create mode 100644 test/cocotb_attention_softmax/test_softmax_normalize_cocotb.py diff --git a/hdl/attention_softmax_normalize.v b/hdl/attention_softmax_normalize.v new file mode 100644 index 00000000..9c8d7e8a --- /dev/null +++ b/hdl/attention_softmax_normalize.v @@ -0,0 +1,108 @@ +module attention_softmax_normalize ( + input wire clk_i, + input wire rst_ni, + input wire start_i, + + input wire [63:0] exp_values_i, + + output wire [63:0] probabilities_o, + output wire busy_o, + output wire done_o +); + + wire [17:0] sum_next; + + assign sum_next = + {2'b00, exp_values_i[15:0]} + + {2'b00, exp_values_i[31:16]} + + {2'b00, exp_values_i[47:32]} + + {2'b00, exp_values_i[63:48]}; + + reg [63:0] exp_row_reg; + reg [17:0] sum_reg; + + localparam [1:0] + IDLE = 2'd0, + LAUNCH = 2'd1, + WAIT = 2'd2, + DONE = 2'd3; + + reg [1:0] state; + reg [3:0] done_seen; + + assign divider_start = (state == LAUNCH); + + assign busy_o = (state == LAUNCH) || (state == WAIT); + + assign done_o = (state == DONE); + + wire [3:0] divider_done; + wire [3:0] divider_busy; + wire divider_start; + + genvar lane; + + generate + for (lane = 0; lane < 4; lane = lane + 1) begin : GEN_DIVIDER + + attention_softmax_divider u_divider ( + + .clk_i (clk_i), + .rst_ni (rst_ni), + .start_i (divider_start), + + .exp_i (exp_row_reg[lane*16 +: 16]), + .sum_i (sum_reg), + + .busy_o (divider_busy[lane]), + .done_o (divider_done[lane]), + + .probability_o (probabilities_o[lane*16 +: 16]) + ); + + end + endgenerate + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state <= IDLE; + exp_row_reg <= 64'd0; + sum_reg <= 18'd0; + done_seen <= 4'b0000; + end else begin + + case (state) + + IDLE: begin + if (start_i) begin + exp_row_reg <= exp_values_i; + sum_reg <= sum_next; + done_seen <= 4'b0000; + state <= LAUNCH; + end + end + + LAUNCH: begin + state <= WAIT; + end + + WAIT: begin + done_seen <= done_seen | divider_done; + + if (&(done_seen | divider_done)) begin + state <= DONE; + end + end + + DONE: begin + state <= IDLE; + end + + default: begin + state <= IDLE; + end + + endcase + end + end +endmodule \ No newline at end of file diff --git a/test/cocotb_attention_softmax/run_softmax_normalize.py b/test/cocotb_attention_softmax/run_softmax_normalize.py new file mode 100644 index 00000000..5e641150 --- /dev/null +++ b/test/cocotb_attention_softmax/run_softmax_normalize.py @@ -0,0 +1,21 @@ +from pathlib import Path +from cocotb_test.simulator import run + + +def test_softmax_normalize(): + + here = Path(__file__).resolve().parent + project_root = here.parent.parent + + run( + verilog_sources=[ + str(project_root / "hdl" / "attention_softmax_divider.v"), + str(project_root / "hdl" / "attention_softmax_normalize.v"), + ], + toplevel="attention_softmax_normalize", + module="test_softmax_normalize_cocotb", + python_search=[str(here)], + sim_build=str(here / "sim_build_normalize"), + simulator="icarus", + force_compile=True, + ) \ No newline at end of file diff --git a/test/cocotb_attention_softmax/test_softmax_normalize_cocotb.py b/test/cocotb_attention_softmax/test_softmax_normalize_cocotb.py new file mode 100644 index 00000000..fb3134ee --- /dev/null +++ b/test/cocotb_attention_softmax/test_softmax_normalize_cocotb.py @@ -0,0 +1,133 @@ +import random +import cocotb + +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, FallingEdge, Timer + + +def reference_probability(exp, total): + if total == 0 or exp == 0: + return 0 + + if exp >= total: + return 32768 + + return (exp * 32768 + total // 2) // total + + +async def check_row(dut, exp_values): + total = sum(exp_values) + + expected = [ + reference_probability(exp, total) + for exp in exp_values + ] + + # Pack four 16-bit exponential values into 64 bits + packed_input = sum( + int(exp) << (16 * i) + for i, exp in enumerate(exp_values) + ) + + await FallingEdge(dut.clk_i) + + dut.exp_values_i.value = packed_input + dut.start_i.value = 1 + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + assert int(dut.busy_o.value) == 1, ( + "Normalizer did not start" + ) + + await FallingEdge(dut.clk_i) + dut.start_i.value = 0 + + # Wait for all four dividers + for cycle in range(30): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + if int(dut.done_o.value) == 1: + + actual_packed = int(dut.probabilities_o.value) + + actual = [ + (actual_packed >> (16 * i)) & 0xFFFF + for i in range(4) + ] + + assert actual == expected, ( + f"Input: {exp_values}\n" + f"Sum: {total}\n" + f"Expected: {expected}\n" + f"Actual: {actual}" + ) + + assert int(dut.busy_o.value) == 0 + + # Verify one-cycle done pulse + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + assert int(dut.done_o.value) == 0 + + return + + raise AssertionError( + f"Normalization timeout: {exp_values}" + ) + + +@cocotb.test() +async def test_softmax_normalize(dut): + + cocotb.start_soon( + Clock(dut.clk_i, 10, unit="ns").start() + ) + + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.exp_values_i.value = 0 + + await Timer(25, unit="ns") + await FallingEdge(dut.clk_i) + dut.rst_ni.value = 1 + + # Real data from our first Softmax row + await check_row( + dut, [13660, 3914, 32768, 13660] + ) + + # Boundary and special cases + cases = [ + [32768, 0, 0, 0], + [0, 32768, 0, 0], + [32768, 32768, 0, 0], + [32768, 32768, 32768, 32768], + [32768, 0, 2000, 5000], + [32768, 1, 1, 1], + [0, 0, 0, 0], + ] + + for row in cases: + await check_row(dut, row) + + # Random rows + rng = random.Random(42) + + for _ in range(100): + row = [ + rng.randint(0, 32768) + for _ in range(4) + ] + + # At least one exponential must equal exp(0) + row[rng.randrange(4)] = 32768 + + await check_row(dut, row) + + dut._log.info( + "All 108 normalization test cases passed" + ) \ No newline at end of file From b237a24abb071e4ffaffbad098b9576780f88b39 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Sun, 1 Nov 2026 19:52:21 +0100 Subject: [PATCH 33/36] Attention : add and verify Softmax : End to End Unit Test for a whole complete row --- hdl/attention_softmax_row.v | 124 ++++++++++++++ .../run_softmax_row.py | 23 +++ .../test_softmax_row_cocotb.py | 161 ++++++++++++++++++ 3 files changed, 308 insertions(+) create mode 100644 hdl/attention_softmax_row.v create mode 100644 test/cocotb_attention_softmax/run_softmax_row.py create mode 100644 test/cocotb_attention_softmax/test_softmax_row_cocotb.py diff --git a/hdl/attention_softmax_row.v b/hdl/attention_softmax_row.v new file mode 100644 index 00000000..146662b7 --- /dev/null +++ b/hdl/attention_softmax_row.v @@ -0,0 +1,124 @@ + +`timescale 1ns / 1ps + +module attention_softmax_row ( + input wire clk_i, + input wire rst_ni, + input wire start_i, + + input wire [79:0] scores_i, + input wire [6:0] q_shift_i, + input wire [6:0] k_shift_i, + + output wire [63:0] probabilities_o, + output wire busy_o, + output wire done_o +); + + // FSM states + localparam [2:0] + IDLE = 3'd0, + EXP_START = 3'd1, + EXP_WAIT = 3'd2, + NORM_WAIT = 3'd3, + DONE = 3'd4; + + reg [2:0] state; + + // Registered inputs + reg [79:0] scores_reg; + reg [6:0] q_shift_reg; + reg [6:0] k_shift_reg; + + // Exponential interface + wire [63:0] exp_values; + wire exp_valid; + wire exp_start; + + // Normalization interface + wire norm_start; + wire norm_done; + wire norm_busy; + + assign exp_start = (state == EXP_START); + assign norm_start = (state == EXP_WAIT) && exp_valid; + + assign busy_o = (state != IDLE) && (state != DONE); + assign done_o = (state == DONE); + + + // Stage 1: Scaling + Exponential + attention_softmax_exp u_exp ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .valid_i (exp_start), + + .scores_i (scores_reg), + .q_shift_i (q_shift_reg), + .k_shift_i (k_shift_reg), + + .valid_o (exp_valid), + .exp_values_o (exp_values) + ); + + + // Stage 2: Normalization + attention_softmax_normalize u_normalize ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .start_i (norm_start), + + .exp_values_i (exp_values), + + .probabilities_o (probabilities_o), + .busy_o (norm_busy), + .done_o (norm_done) + ); + + + // Row controller + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state <= IDLE; + scores_reg <= 80'd0; + q_shift_reg <= 7'd0; + k_shift_reg <= 7'd0; + end else begin + case (state) + + IDLE: begin + if (start_i) begin + scores_reg <= scores_i; + q_shift_reg <= q_shift_i; + k_shift_reg <= k_shift_i; + state <= EXP_START; + end + end + + EXP_START: begin + state <= EXP_WAIT; + end + + EXP_WAIT: begin + if (exp_valid) + state <= NORM_WAIT; + end + + NORM_WAIT: begin + if (norm_done) + state <= DONE; + end + + DONE: begin + state <= IDLE; + end + + default: begin + state <= IDLE; + end + + endcase + end + end + +endmodule diff --git a/test/cocotb_attention_softmax/run_softmax_row.py b/test/cocotb_attention_softmax/run_softmax_row.py new file mode 100644 index 00000000..67c72df2 --- /dev/null +++ b/test/cocotb_attention_softmax/run_softmax_row.py @@ -0,0 +1,23 @@ + +from pathlib import Path +from cocotb_test.simulator import run + + +def test_softmax_row(): + here = Path(__file__).resolve().parent + project_root = here.parent.parent + + run( + verilog_sources=[ + str(project_root / "hdl" / "attention_softmax_exp.v"), + str(project_root / "hdl" / "attention_softmax_divider.v"), + str(project_root / "hdl" / "attention_softmax_normalize.v"), + str(project_root / "hdl" / "attention_softmax_row.v"), + ], + toplevel="attention_softmax_row", + module="test_softmax_row_cocotb", + python_search=[str(here)], + sim_build=str(here / "sim_build_row"), + simulator="icarus", + force_compile=True, + ) diff --git a/test/cocotb_attention_softmax/test_softmax_row_cocotb.py b/test/cocotb_attention_softmax/test_softmax_row_cocotb.py new file mode 100644 index 00000000..2e8c3bad --- /dev/null +++ b/test/cocotb_attention_softmax/test_softmax_row_cocotb.py @@ -0,0 +1,161 @@ + +import random +from pathlib import Path + +import numpy as np +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import FallingEdge, RisingEdge, Timer + +from softmax_exp_reference import exp_row + + +def pack_scores(scores): + # Pack four signed 20-bit scores into 80 bits. + return sum( + (int(score) & 0xFFFFF) << (20 * i) + for i, score in enumerate(scores) + ) + + +def reference_row(scores, q_shift, k_shift): + # Bit-exact exponential reference. + exp_values = exp_row(scores, q_shift, k_shift) + total = sum(exp_values) + + if total == 0: + return [0] * 4 + + # Same integer rounding as the divider RTL. + return [ + min(32768, (exp * 32768 + total // 2) // total) + for exp in exp_values + ] + + +async def check_row(dut, scores, q_shift, k_shift): + expected = reference_row(scores, q_shift, k_shift) + + # Start a new row. + await FallingEdge(dut.clk_i) + + dut.scores_i.value = pack_scores(scores) + dut.q_shift_i.value = q_shift + dut.k_shift_i.value = k_shift + dut.start_i.value = 1 + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + assert int(dut.busy_o.value) == 1, "Row did not start" + + # Remove start and change external inputs. + # The row module must use its registered values. + await FallingEdge(dut.clk_i) + + dut.start_i.value = 0 + dut.scores_i.value = 0 + dut.q_shift_i.value = 0 + dut.k_shift_i.value = 0 + + # Wait for complete row normalization. + for cycle in range(40): + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + if int(dut.done_o.value) == 1: + packed = int(dut.probabilities_o.value) + + actual = [ + (packed >> (16 * i)) & 0xFFFF + for i in range(4) + ] + + assert actual == expected, ( + f"Scores: {scores}\n" + f"Shifts: {q_shift}, {k_shift}\n" + f"Expected: {expected}\n" + f"Actual: {actual}" + ) + + assert int(dut.busy_o.value) == 0 + + # done_o must last exactly one clock cycle. + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + assert int(dut.done_o.value) == 0 + return + + raise AssertionError( + f"Softmax row timeout: scores={scores}" + ) + + +@cocotb.test() +async def test_softmax_row(dut): + cocotb.start_soon( + Clock(dut.clk_i, 10, unit="ns").start() + ) + + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.scores_i.value = 0 + dut.q_shift_i.value = 0 + dut.k_shift_i.value = 0 + + await Timer(25, unit="ns") + await FallingEdge(dut.clk_i) + dut.rst_ni.value = 1 + + # Reuse existing QKT reference data. + ref_path = ( + Path(__file__).resolve().parent.parent + / "cocotb_attention_qkt" + / "data" + / "qkt_single_8x4" + / "qkt_t0_reference.npz" + ) + + with np.load(ref_path, allow_pickle=False) as f: + matrix = ( + f["Q8"].astype(np.int64) + @ f["K8"].astype(np.int64).T + ) + q_shift = int(f["q_shift"]) + k_shift = int(f["k_shift"]) + + # Test all 4 rows from the real QKT test data. + for row in matrix: + await check_row( + dut, [int(x) for x in row], q_shift, k_shift + ) + + # Boundary cases + cases = [ + ([0, 0, 0, 0], 6, 6), + ([100, 100, 100, 100], 6, 6), + ([100, -100000, -200000, -300000], 6, 6), + ([-524288, -500000, 524287, 0], 13, 13), + ([-1, -2, -3, -4], 0, 0), + ([524287, -524288, 7, -8], 5, 9), + ] + + for scores, q, k in cases: + await check_row(dut, scores, q, k) + + # Random input rows and quantization shifts. + rng = random.Random(42) + + for _ in range(100): + scores = [ + rng.randint(-(1 << 19), (1 << 19) - 1) + for _ in range(4) + ] + + q = rng.randint(0, 13) + k = rng.randint(0, 13) + + await check_row(dut, scores, q, k) + + dut._log.info("All 110 Softmax row tests passed") From 76dcca4cf597a075271cce4fd5b023ba1a774bb7 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Mon, 2 Nov 2026 12:39:07 +0100 Subject: [PATCH 34/36] Attention : add and verify the first edition of whole softmax module --- hdl/attention_softmax.v | 189 +++++++++++++++ .../run_softmax_matrix.py | 26 ++ .../test_softmax_matrix_cocotb.py | 225 ++++++++++++++++++ 3 files changed, 440 insertions(+) create mode 100644 hdl/attention_softmax.v create mode 100644 test/cocotb_attention_softmax/run_softmax_matrix.py create mode 100644 test/cocotb_attention_softmax/test_softmax_matrix_cocotb.py diff --git a/hdl/attention_softmax.v b/hdl/attention_softmax.v new file mode 100644 index 00000000..4ca64944 --- /dev/null +++ b/hdl/attention_softmax.v @@ -0,0 +1,189 @@ + +module attention_softmax ( + input wire clk_i, + input wire rst_ni, + input wire start_i, + + // Quantization shifts + input wire [6:0] q_shift_i, + input wire [6:0] k_shift_i, + + // QKT Score Buffer read interface + output wire [1:0] score_rd_token_o, + output wire [1:0] score_rd_index_o, + input wire signed [19:0] score_rd_data_i, + input wire score_rd_valid_i, + + // Probability Buffer read interface + input wire [1:0] prob_rd_token_i, + input wire [1:0] prob_rd_index_i, + output wire [15:0] prob_rd_data_o, + output wire prob_rd_valid_o, + + // Control + output wire busy_o, + output wire done_o, + output wire complete_o +); + + + localparam [2:0] + IDLE = 3'd0, + LOAD_ROW = 3'd1, + ROW_START = 3'd2, + ROW_WAIT = 3'd3, + STORE_ROW = 3'd4, + FINISH = 3'd5; + + reg [2:0] state; + + // Current position in the 4x4 matrix + reg [1:0] row_index; + reg [1:0] col_index; + + // Four 20-bit scores for the current row + reg [79:0] row_scores_reg; + + // Capture quantization shifts at start + reg [6:0] q_shift_reg; + reg [6:0] k_shift_reg; + + // Result storage: 16 probabilities + reg [15:0] probability_mem [0:15]; + reg [15:0] probability_valid; + + // Row processor interface + wire [63:0] row_probabilities; + wire row_start; + wire row_busy; + wire row_done; + + // Score Buffer read address + assign score_rd_token_o = row_index; + assign score_rd_index_o = col_index; + + // Row processor control + assign row_start = (state == ROW_START); + + assign busy_o = (state != IDLE) && (state != FINISH); + assign done_o = (state == FINISH); + + // All 16 probabilities are available + assign complete_o = &probability_valid; + + + // Row-Parallel Softmax processor + attention_softmax_row u_softmax_row ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .start_i (row_start), + + .scores_i (row_scores_reg), + .q_shift_i (q_shift_reg), + .k_shift_i (k_shift_reg), + + .probabilities_o (row_probabilities), + .busy_o (row_busy), + .done_o (row_done) + ); + + wire [3:0] prob_read_addr; + + assign prob_read_addr = { + prob_rd_token_i, + prob_rd_index_i + }; + + assign prob_rd_valid_o = probability_valid[prob_read_addr]; + + assign prob_rd_data_o = prob_rd_valid_o + ? probability_mem[prob_read_addr] + : 16'd0; + + + always @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + state <= IDLE; + row_index <= 2'd0; + col_index <= 2'd0; + row_scores_reg <= 80'd0; + q_shift_reg <= 7'd0; + k_shift_reg <= 7'd0; + probability_valid <= 16'd0; + end else begin + case (state) + + IDLE: begin + if (start_i) begin + row_index <= 2'd0; + col_index <= 2'd0; + row_scores_reg <= 80'd0; + q_shift_reg <= q_shift_i; + k_shift_reg <= k_shift_i; + probability_valid <= 16'd0; + state <= LOAD_ROW; + end + end + + LOAD_ROW: begin + if (score_rd_valid_i) begin + row_scores_reg[col_index*20 +: 20] + <= score_rd_data_i; + + if (col_index == 2'd3) begin + col_index <= 2'd0; + state <= ROW_START; + end else begin + col_index <= col_index + 1'b1; + end + end + end + + ROW_START: begin + state <= ROW_WAIT; + end + + ROW_WAIT: begin + if (row_done) begin + state <= STORE_ROW; + end + end + + STORE_ROW: begin + probability_mem[{row_index, 2'b00}] + <= row_probabilities[15:0]; + + probability_mem[{row_index, 2'b01}] + <= row_probabilities[31:16]; + + probability_mem[{row_index, 2'b10}] + <= row_probabilities[47:32]; + + probability_mem[{row_index, 2'b11}] + <= row_probabilities[63:48]; + + probability_valid[{row_index, 2'b00} +: 4] + <= 4'b1111; + + if (row_index == 2'd3) begin + state <= FINISH; + end else begin + row_index <= row_index + 1'b1; + col_index <= 2'd0; + row_scores_reg <= 80'd0; + state <= LOAD_ROW; + end + end + + FINISH: begin + state <= IDLE; + end + + default: begin + state <= IDLE; + end + + endcase + end + end +endmodule diff --git a/test/cocotb_attention_softmax/run_softmax_matrix.py b/test/cocotb_attention_softmax/run_softmax_matrix.py new file mode 100644 index 00000000..269d9690 --- /dev/null +++ b/test/cocotb_attention_softmax/run_softmax_matrix.py @@ -0,0 +1,26 @@ + +from pathlib import Path +from cocotb_test.simulator import run + + +def test_softmax_matrix(): + + here = Path(__file__).resolve().parent + project_root = here.parent.parent + + run( + verilog_sources=[ + str(project_root / "hdl" / "attention_softmax_exp.v"), + str(project_root / "hdl" / "attention_softmax_divider.v"), + str(project_root / "hdl" / "attention_softmax_normalize.v"), + str(project_root / "hdl" / "attention_softmax_row.v"), + str(project_root / "hdl" / "attention_softmax.v"), + ], + toplevel="attention_softmax", + module="test_softmax_matrix_cocotb", + python_search=[str(here)], + sim_build=str(here / "sim_build_matrix"), + simulator="icarus", + waves=True, + force_compile=True, + ) diff --git a/test/cocotb_attention_softmax/test_softmax_matrix_cocotb.py b/test/cocotb_attention_softmax/test_softmax_matrix_cocotb.py new file mode 100644 index 00000000..410ceac3 --- /dev/null +++ b/test/cocotb_attention_softmax/test_softmax_matrix_cocotb.py @@ -0,0 +1,225 @@ + +import random +from pathlib import Path + +import cocotb +import numpy as np + +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, FallingEdge, Timer +from softmax_exp_reference import exp_row + + +def reference_row(scores, q_shift, k_shift): + exp_values = [ + int(v) for v in exp_row(scores, q_shift, k_shift) + ] + + total = sum(exp_values) + + if total == 0: + return [0] * 4 + + return [ + min(32768, (e * 32768 + total // 2) // total) + for e in exp_values + ] + + +async def score_buffer_model(dut, model): + """ + Emulate the existing combinational score read port. + One score is available per valid clock cycle. + """ + cycle = 0 + + while True: + await FallingEdge(dut.clk_i) + + row = int(dut.score_rd_token_o.value) + col = int(dut.score_rd_index_o.value) + + score = int(model["matrix"][row][col]) + + # Signed INT20 represented as 20-bit two's complement + dut.score_rd_data_i.value = score & 0xFFFFF + + cycle += 1 + stall_every = model["stall_every"] + + valid = not ( + stall_every and cycle % stall_every == 0 + ) + + dut.score_rd_valid_i.value = int(valid) + + +async def check_matrix(dut, model, matrix, q_shift, k_shift, + stall_every=0): + + expected = [ + reference_row(row, q_shift, k_shift) + for row in matrix + ] + + model["matrix"] = matrix + model["stall_every"] = stall_every + + # One start for the entire 4x4 matrix + await FallingEdge(dut.clk_i) + + dut.q_shift_i.value = q_shift + dut.k_shift_i.value = k_shift + dut.start_i.value = 1 + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + assert int(dut.busy_o.value) == 1 + assert int(dut.complete_o.value) == 0 + + await FallingEdge(dut.clk_i) + dut.start_i.value = 0 + + # Change external shifts to verify internal registers. + dut.q_shift_i.value = 0 + dut.k_shift_i.value = 0 + + # Wait for all four rows to finish. + for cycle in range(300): + + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + if int(dut.done_o.value) == 1: + assert int(dut.complete_o.value) == 1 + assert int(dut.busy_o.value) == 0 + break + + else: + raise AssertionError("Full Softmax matrix timeout") + + # done_o must be a one-cycle pulse. + await RisingEdge(dut.clk_i) + await Timer(1, unit="ns") + + assert int(dut.done_o.value) == 0 + assert int(dut.complete_o.value) == 1 + + # Read and check all 16 stored probabilities. + actual = [] + + for row in range(4): + actual_row = [] + + for col in range(4): + await FallingEdge(dut.clk_i) + + dut.prob_rd_token_i.value = row + dut.prob_rd_index_i.value = col + + await Timer(1, unit="ns") + + assert int(dut.prob_rd_valid_o.value) == 1, ( + f"Probability missing at [{row}][{col}]" + ) + + actual_row.append( + int(dut.prob_rd_data_o.value) + ) + + actual.append(actual_row) + + assert actual == expected, ( + f"Expected:\n{expected}\n" + f"Actual:\n{actual}" + ) + + dut._log.info( + "Matrix PASS (q_shift=%d, k_shift=%d, stalls=%d)", + q_shift, k_shift, stall_every + ) + + +@cocotb.test() +async def test_full_softmax_matrix(dut): + + cocotb.start_soon( + Clock(dut.clk_i, 10, unit="ns").start() + ) + + dut.rst_ni.value = 0 + dut.start_i.value = 0 + dut.q_shift_i.value = 0 + dut.k_shift_i.value = 0 + dut.score_rd_data_i.value = 0 + dut.score_rd_valid_i.value = 0 + dut.prob_rd_token_i.value = 0 + dut.prob_rd_index_i.value = 0 + + await Timer(25, unit="ns") + await FallingEdge(dut.clk_i) + dut.rst_ni.value = 1 + + model = { + "matrix": [[0] * 4 for _ in range(4)], + "stall_every": 0, + } + + cocotb.start_soon(score_buffer_model(dut, model)) + + # Test 1: Existing QKT reference data + ref_path = ( + Path(__file__).resolve().parent.parent + / "cocotb_attention_qkt" + / "data" + / "qkt_single_8x4" + / "qkt_t0_reference.npz" + ) + + with np.load(ref_path, allow_pickle=False) as f: + scores = ( + f["Q8"].astype(np.int64) + @ f["K8"].astype(np.int64).T + ).tolist() + + q_shift = int(f["q_shift"]) + k_shift = int(f["k_shift"]) + + await check_matrix( + dut, model, scores, q_shift, k_shift + ) + + # Test 2: All-equal scores + equal_matrix = [[100] * 4 for _ in range(4)] + + await check_matrix( + dut, model, equal_matrix, 6, 6 + ) + + # Test 3: Signed 20-bit boundary values + boundary_matrix = [ + [-524288, -500000, 524287, 0], + [524287, -524288, 10, -10], + [0, 0, 0, 0], + [100, 200, 300, 400], + ] + + await check_matrix( + dut, model, boundary_matrix, 13, 13 + ) + + # Test 4: Random matrix with read-valid stalls + rng = random.Random(42) + + random_matrix = [ + [rng.randint(-20000, 20000) for _ in range(4)] + for _ in range(4) + ] + + await check_matrix( + dut, model, random_matrix, 3, 8, + stall_every=5 + ) + + dut._log.info("All full-matrix Softmax tests passed") From 8c7870a4aa48df2bcaeb1daaa3b7003a4f3ab249 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Mon, 2 Nov 2026 12:48:37 +0100 Subject: [PATCH 35/36] Attention : adding heatmap png gen code in test_softmax_matrix_cocotb.py --- .../test_softmax_matrix_cocotb.py | 67 ++++++++++++++++++- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/test/cocotb_attention_softmax/test_softmax_matrix_cocotb.py b/test/cocotb_attention_softmax/test_softmax_matrix_cocotb.py index 410ceac3..7f32ab46 100644 --- a/test/cocotb_attention_softmax/test_softmax_matrix_cocotb.py +++ b/test/cocotb_attention_softmax/test_softmax_matrix_cocotb.py @@ -4,7 +4,9 @@ import cocotb import numpy as np - +import matplotlib +matplotlib.use("Agg") # Save figures without opening a GUI +import matplotlib.pyplot as plt from cocotb.clock import Clock from cocotb.triggers import RisingEdge, FallingEdge, Timer from softmax_exp_reference import exp_row @@ -26,6 +28,62 @@ def reference_row(scores, q_shift, k_shift): ] +def plot_softmax_heatmap(scores, probabilities_fixed): + # Original QKT scores + scores = np.asarray(scores, dtype=np.int64) + + # Actual RTL probabilities: UQ1.15 -> float + probabilities_fixed = np.asarray( + probabilities_fixed, dtype=np.int64 + ) + probabilities = probabilities_fixed / 32768.0 + + fig, axes = plt.subplots( + 1, 2, figsize=(12, 5), constrained_layout=True + ) + + # Left: QKT scores + im0 = axes[0].imshow(scores) + axes[0].set_title("QKT Score Matrix (INT20)") + fig.colorbar(im0, ax=axes[0], label="Score") + + # Right: Hardware Softmax output + im1 = axes[1].imshow( + probabilities, vmin=0, vmax=1 + ) + axes[1].set_title("Hardware Softmax (UQ1.15)") + fig.colorbar(im1, ax=axes[1], label="Probability") + + for ax in axes: + ax.set_xlabel("Key Token") + ax.set_ylabel("Query Token") + ax.set_xticks(range(4)) + ax.set_yticks(range(4)) + + # Write values inside heatmap cells + for row in range(4): + for col in range(4): + axes[0].text( + col, row, str(scores[row, col]), + ha="center", va="center", fontsize=8 + ) + + axes[1].text( + col, row, f"{probabilities[row, col]:.3f}", + ha="center", va="center", fontsize=10 + ) + + output_path = ( + Path(__file__).resolve().parent + / "softmax_heatmap.png" + ) + + fig.savefig(output_path, dpi=200) + plt.close(fig) + + print(f"Heatmap saved: {output_path}") + + async def score_buffer_model(dut, model): """ Emulate the existing combinational score read port. @@ -55,7 +113,7 @@ async def score_buffer_model(dut, model): async def check_matrix(dut, model, matrix, q_shift, k_shift, - stall_every=0): + stall_every=0, save_heatmap=False): expected = [ reference_row(row, q_shift, k_shift) @@ -135,6 +193,9 @@ async def check_matrix(dut, model, matrix, q_shift, k_shift, f"Actual:\n{actual}" ) + if save_heatmap: + plot_softmax_heatmap(matrix, actual) + dut._log.info( "Matrix PASS (q_shift=%d, k_shift=%d, stalls=%d)", q_shift, k_shift, stall_every @@ -187,7 +248,7 @@ async def test_full_softmax_matrix(dut): k_shift = int(f["k_shift"]) await check_matrix( - dut, model, scores, q_shift, k_shift + dut, model, scores, q_shift, k_shift, save_heatmap=True ) # Test 2: All-equal scores From d87c27e5a1f10843b52fec9951621c64867fadb0 Mon Sep 17 00:00:00 2001 From: Amirhossein Seifadini Date: Mon, 2 Nov 2026 19:06:59 +0100 Subject: [PATCH 36/36] Attention : test and verify the Integraion of Softmax in attention_top module --- hdl/attention_top.v | 75 +++++++++++++++- hdl/attention_top_scheduler.v | 36 ++++++-- .../test_attention_top_e2e.py | 89 ++++++++++++++++++- 3 files changed, 188 insertions(+), 12 deletions(-) diff --git a/hdl/attention_top.v b/hdl/attention_top.v index 5d8f8ee2..e2eda2c2 100644 --- a/hdl/attention_top.v +++ b/hdl/attention_top.v @@ -54,6 +54,13 @@ module attention_top #( output wire signed [19:0] score_rd_data_o, output wire score_rd_valid_o, + // Softmax probability read interface + input wire [1:0] prob_rd_token_i, + input wire [1:0] prob_rd_index_i, + output wire [15:0] prob_rd_data_o, + output wire prob_rd_valid_o, + output wire softmax_complete_o, + // Debug outputs for integration tests. output wire [1:0] active_token_o, output wire [1:0] active_projection_o, @@ -81,6 +88,22 @@ module attention_top #( wire operands_ready; wire gemv_done; + wire softmax_start; + wire softmax_done; + wire softmax_busy; + + // Softmax Score Buffer read requests + wire [1:0] softmax_score_rd_token; + wire [1:0] softmax_score_rd_index; + + // Shared Score Buffer read response + wire signed [19:0] score_buffer_rd_data; + wire score_buffer_rd_valid; + + // Selected read address + wire [1:0] selected_score_rd_token; + wire [1:0] selected_score_rd_index; + attention_top_scheduler u_scheduler ( .clk_i(clk_i), .rst_ni(rst_ni), @@ -103,6 +126,9 @@ module attention_top #( .token_o(token_select), .projection_o(projection_select), .busy_o(busy_o), + .softmax_start_o(softmax_start), + .scores_complete_i(scores_complete_o), + .softmax_done_i(softmax_done), .done_o(done_o) ); assign active_token_o = token_select; @@ -339,6 +365,17 @@ module attention_top #( wire [1:0] mapped_score_index = {result_addr[0], result_addr[1]}; wire score_write = qkt_result_enable && result_write && (result_addr < 4); + assign selected_score_rd_token = + softmax_busy ? softmax_score_rd_token + : score_rd_token_i; + + assign selected_score_rd_index = + softmax_busy ? softmax_score_rd_index + : score_rd_index_i; + + assign score_rd_data_o = score_buffer_rd_data; + assign score_rd_valid_o = score_buffer_rd_valid; + attention_qkt_score_buffer #( .NUM_TOKENS(4), .NUM_SCORES(4), @@ -351,13 +388,43 @@ module attention_top #( .write_token_i(token_select), .write_score_i(mapped_score_index), .write_data_i(result_data[19:0]), - .read_token_i(score_rd_token_i), - .read_score_i(score_rd_index_i), - .read_data_o(score_rd_data_o), - .read_valid_o(score_rd_valid_o), + .read_token_i(selected_score_rd_token), + .read_score_i(selected_score_rd_index), + .read_data_o(score_buffer_rd_data), + .read_valid_o(score_buffer_rd_valid), .complete_o(scores_complete_o) ); + + //===================== ATTENTION SOFTMAX =============================== + + attention_softmax u_softmax ( + .clk_i(clk_i), + .rst_ni(rst_ni), + .start_i(softmax_start), + + // Quantization shifts + .q_shift_i(q_shift), + .k_shift_i(k_shift), + + // QKT Score Buffer read interface + .score_rd_token_o(softmax_score_rd_token), + .score_rd_index_o(softmax_score_rd_index), + .score_rd_data_i(score_buffer_rd_data), + .score_rd_valid_i(score_buffer_rd_valid), + + // Probability read interface + .prob_rd_token_i(prob_rd_token_i), + .prob_rd_index_i(prob_rd_index_i), + .prob_rd_data_o(prob_rd_data_o), + .prob_rd_valid_o(prob_rd_valid_o), + + // Control + .busy_o(softmax_busy), + .done_o(softmax_done), + .complete_o(softmax_complete_o) + ); + `ifndef SYNTHESIS initial begin if (DMA_WIDTH != 64 || ADDR_WIDTH != 16 || diff --git a/hdl/attention_top_scheduler.v b/hdl/attention_top_scheduler.v index bd7222f1..8f61146e 100644 --- a/hdl/attention_top_scheduler.v +++ b/hdl/attention_top_scheduler.v @@ -12,6 +12,8 @@ module attention_top_scheduler ( input wire gemv_done_i, input wire quant_done_i, input wire operands_ready_i, + input wire scores_complete_i, + input wire softmax_done_i, output wire projection_start_o, output wire quant_start_o, output wire qkt_memory_clear_o, @@ -24,6 +26,7 @@ module attention_top_scheduler ( output wire [1:0] token_o, output wire [1:0] projection_o, output wire busy_o, + output wire softmax_start_o, output reg done_o ); localparam [3:0] @@ -38,6 +41,8 @@ module attention_top_scheduler ( QKT_GEMV_START = 4'd8, QKT_GEMV_WAIT = 4'd9, QKT_RELOAD = 4'd10, + SOFTMAX_START = 4'd12, + SOFTMAX_WAIT = 4'd13, FINISH = 4'd11; reg [3:0] state; @@ -57,6 +62,8 @@ module attention_top_scheduler ( assign k8_packer_start_o = (state == QKT_PACK_START) && (token == 2'd0); assign gemv_start_o = (state == PROJ_START) || (state == QKT_GEMV_START); assign qkt_result_enable_o = (state == QKT_GEMV_WAIT); + assign softmax_start_o = + (state == SOFTMAX_START) && scores_complete_i; always @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin @@ -101,15 +108,30 @@ module attention_top_scheduler ( QKT_PACK_START: state <= QKT_PACK_WAIT; QKT_PACK_WAIT: if (operands_ready_i) state <= QKT_GEMV_START; QKT_GEMV_START: state <= QKT_GEMV_WAIT; - QKT_GEMV_WAIT: if (gemv_done_i) begin - if (token == 2'd3) - state <= FINISH; - else begin - token <= token + 2'd1; - state <= QKT_RELOAD; + QKT_GEMV_WAIT: begin + if (gemv_done_i) begin + if (token == 2'd3) begin + // All four QKT GEMVs have finished. + state <= SOFTMAX_START; + end else begin + token <= token + 2'd1; + state <= QKT_RELOAD; + end end end - QKT_RELOAD: state <= QKT_PACK_START; + QKT_RELOAD: begin + state <= QKT_PACK_START; + end + SOFTMAX_START: begin + // Do not start until all 16 scores are valid. + if (scores_complete_i) + state <= SOFTMAX_WAIT; + end + SOFTMAX_WAIT: begin + // Wait until the entire 4x4 Softmax has completed. + if (softmax_done_i) + state <= FINISH; + end FINISH: begin done_o <= 1'b1; state <= IDLE; diff --git a/test/cocotb_attention_qkt/test_attention_top_e2e.py b/test/cocotb_attention_qkt/test_attention_top_e2e.py index 6405ae2f..7c6bd1d2 100644 --- a/test/cocotb_attention_qkt/test_attention_top_e2e.py +++ b/test/cocotb_attention_qkt/test_attention_top_e2e.py @@ -89,6 +89,11 @@ def test_attention_top_e2e(): "attention_qkt_k8_packer.v", "attention_qkt_dma_memory.v", "attention_qkt_score_buffer.v", + "attention_softmax_exp.v", + "attention_softmax_divider.v", + "attention_softmax_normalize.v", + "attention_softmax_row.v", + "attention_softmax.v", ): path = Path(hdl_dir) / name assert path.is_file(), f"Missing RTL module: {path}" @@ -97,7 +102,7 @@ def test_attention_top_e2e(): sources.append(str(generated)) cocotb_test.simulator.run( - python_search=[str(here)], + python_search=[str(here), str(here.parent / "cocotb_attention_softmax")], verilog_sources=sources, toplevel="attention_top", module="test_attention_top_e2e", @@ -134,6 +139,7 @@ def _reference_quantize(values): @cocotb.test() async def check_complete_attention_dataflow(dut): + from softmax_exp_reference import exp_row projection_dir = Path(os.environ["ATTENTION_E2E_PROJECTION_DIR"]) with np.load(projection_dir / "inputs_used.npz", allow_pickle=False) as t: x = t["X"].astype(np.int64) @@ -157,6 +163,8 @@ async def check_complete_attention_dataflow(dut): dut.wght_wr_data_i.value = 0 dut.score_rd_token_i.value = 0 dut.score_rd_index_i.value = 0 + dut.prob_rd_token_i.value = 0 + dut.prob_rd_index_i.value = 0 cocotb.start_soon(Clock(dut.clk_i, 20, unit="ns").start()) for _ in range(12): @@ -243,7 +251,86 @@ async def monitor(): f"Golden Q8:\n{q8}\nGolden K8:\n{k8}\n" f"Expected:\n{golden_scores}\nActual:\n{actual_scores}" ) + # Reference Softmax using the existing fixed-point EXP LUT model + golden_probabilities = [] + + for row in golden_scores: + exp_values = [ + int(v) for v in exp_row( + [int(score) for score in row], + q_shift, + k_shift + ) + ] + + total = sum(exp_values) + assert total > 0 + + probabilities = [ + (exp * 32768 + total // 2) // total + for exp in exp_values + ] + + golden_probabilities.append(probabilities) + + golden_probabilities = np.asarray( + golden_probabilities, dtype=np.int64 + ) + + # Global DONE must imply that Softmax is complete. + assert int(dut.softmax_complete_o.value) == 1, ( + "Global DONE but Softmax probability buffer is incomplete" + ) + + actual_probabilities = np.empty((4, 4), dtype=np.int64) + + for token in range(4): + for j in range(4): + dut.prob_rd_token_i.value = token + dut.prob_rd_index_i.value = j + + await Timer(1, unit="ns") + + assert int(dut.prob_rd_valid_o.value) == 1, ( + f"Missing probability P[{token},{j}]" + ) + + actual_probabilities[token, j] = int( + dut.prob_rd_data_o.value + ) + dut._log.info( "PASS: single OpenEye and DMA adapter, 12 projections, " "hardware Q/K quantization, 4 QKT GEMVs, all 16 scores bit-exact" ) + dut._log.info( + "Expected Softmax probabilities (UQ1.15):\n%s", + golden_probabilities + ) + + dut._log.info( + "Actual RTL Softmax probabilities (UQ1.15):\n%s", + actual_probabilities + ) + + assert np.array_equal( + actual_probabilities, + golden_probabilities + ), ( + f"Softmax End-to-End mismatch\n" + f"Expected:\n{golden_probabilities}\n" + f"Actual:\n{actual_probabilities}" + ) + + # Each normalized row should sum to approximately 1.0. + for token in range(4): + row_sum = int(actual_probabilities[token].sum()) + + assert abs(row_sum - 32768) <= 2, ( + f"Invalid probability sum in row {token}: {row_sum}" + ) + + dut._log.info( + "PASS: 12 projections, quantization, 4 QKT GEMVs, " + "16 scores and 16 Softmax probabilities" + ) \ No newline at end of file