From 9e4969c3fb971290fc089b08804bbdcc9e084e5f Mon Sep 17 00:00:00 2001 From: Bob Li Date: Sun, 1 Feb 2026 21:42:47 -0500 Subject: [PATCH 01/32] Added test for ready signal --- test/test.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/test/test.py b/test/test.py index fa7f92c..3b81f8b 100644 --- a/test/test.py +++ b/test/test.py @@ -3,7 +3,7 @@ import cocotb from cocotb.clock import Clock -from cocotb.triggers import ClockCycles +from cocotb.triggers import ClockCycles, RisingEdge @cocotb.test() @@ -38,3 +38,58 @@ async def test_project(dut): # Keep testing the module by changing the input values, waiting for # one or more clock cycles, and asserting the expected output values. + +@cocotb.test() +async def ready_test(dut): + + dut._log_info("Reset") + dut.rst_n.value = 0 + await ClockCycles(dut.clk, 10, unit = "us") + dut.rst_n.value = 1 + dut._log.info("Testing Ready Signals") + + #initially, set all ready values to 0, this means that all the values are not ready + dut.mem_ready.value = 0 + dut.sha_ready.value = 0 + dut.aes_ready.value = 0 + dut.ctrl_ready.value = 0 + dut._log.info("All infos not set to ready") + #wait for rising edge and check if the bus is not ready + await RisingEdge(dut.clk) + assert dut.bus_ready.value == 0 + dut._log.info("Passed all not ready test") + + #now set the mem to be ready + dut.mem_ready.value = 1 + dut._log.info("mem is set to ready") + #wait for rising edge to check + await RisingEdge(dut.clk) + assert dut.bus_ready.value == 1 + + #reset the mem and set the sha back to ready + dut.mem_ready.value = 0 + dut.sha_ready.value = 1 + dut._log.info("sha is set to ready") + #wait for rising edge to check + await RisingEdge(dut.clk) + assert dut.bus_ready.value == 1 + + #reset the sha and set the aes back to ready + dut.sha_ready.value = 0 + dut.aes_ready.value = 1 + dut._log.info("aes is set to ready") + #wait for rising edge to check + await RisingEdge(dut.clk) + assert dut.bus_ready.value == 1 + + #set control to ready and aes back + dut.ctrl_ready.value = 1 + dut.aes_ready.value = 0 + dut._log.info("ctrl is set to ready") + #wait for rising edge and check + await RisingEdge(dut.clk) + assert dut.bus_ready.value == 1 + + + + From 1893910dc0e4d03e1c8eae1cf0ea01b3f7575ffd Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Mon, 2 Feb 2026 11:25:09 -0500 Subject: [PATCH 02/32] Create databus_ctrl.v lets have fun with github ide --- src/databus_ctrl.v | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/databus_ctrl.v diff --git a/src/databus_ctrl.v b/src/databus_ctrl.v new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/databus_ctrl.v @@ -0,0 +1 @@ + From a523df8d9b1af11903cd55448c0d079626453b5d Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Mon, 2 Feb 2026 11:28:39 -0500 Subject: [PATCH 03/32] github ide is not fun --- src/databus_ctrl.v | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/databus_ctrl.v b/src/databus_ctrl.v index 8b13789..288c6dd 100644 --- a/src/databus_ctrl.v +++ b/src/databus_ctrl.v @@ -1 +1,7 @@ +`default_net_type none +`timescale 1ns/1ps +module data_bus_ctrl () + + +endmodule From 7c01ece905231e7292061bee166f1d5491bed85d Mon Sep 17 00:00:00 2001 From: Bob Li Date: Mon, 2 Feb 2026 15:41:32 -0500 Subject: [PATCH 04/32] wrote new test for data transmission --- test/test.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/test/test.py b/test/test.py index 3b81f8b..cf6aef2 100644 --- a/test/test.py +++ b/test/test.py @@ -39,6 +39,8 @@ async def test_project(dut): # Keep testing the module by changing the input values, waiting for # one or more clock cycles, and asserting the expected output values. + +#test for the ready signals @cocotb.test() async def ready_test(dut): @@ -90,6 +92,58 @@ async def ready_test(dut): await RisingEdge(dut.clk) assert dut.bus_ready.value == 1 +#test for bus sending data +@cocotb.test() +async def data_transmission_test(dut): + #reset everything first + dut._log_info("Reset") + dut.rst_n.value = 0 + await ClockCycles(dut.clk, 10, unit = "us") + dut.rst_n.value = 1 + dut._log.info("Testing Ready Signals") + + #we test this module by crafting a destination and crafting a dummy hashed value to send to the module + dut.READY.value = 1 + dut.ctrl_ready.value = 0 + dut.sha_ready.value = 0 + dut.aes_ready.value = 0 + dut.mem_ready.value = 1 + #now we decide that we want to do a wr_res, say we need to make a dummy address + dummy_addr = 0x001234 + #now we craft the fake opcode needed for the command/driving + op_code = 0b10100010 + #crafting the header as per the beats architecture required + dut.header.value = [dummy_addr >> 16 & 0xFF, dummy_addr >> 8 & 0xFF, dummy_addr >> 0 & 0xFF, op_code] + #now we set up a test payload + payload = [0xDE,0xAD,0xBE,0xEF, 0x11,0x22,0x33,0x44] + await RisingEdge(dut.clk) + for beats in dut.header.value: + #send the beats of the data 1 by 1 + dut.ctrl_data = beats + #set the control valid back to true + dut.ctrl_valid.value = 1 + #wait for handshaking signals + while(True): + await RisingEdge(dut.clk) + if(dut.ctrl_ready.value): + break + dut.ctrl_valid.value = 0 + #send payload data in + for data in payload: + dut.aes_data.value = data + dut.aes_valid.value = 1 + while(True): + await RisingEdge(dut.clk) + if(dut.aes_ready.value): + break + dut.aes_ready.value = 0 + + #check whether the header was captured and matches + for load in payload: + await RisingEdge(dut.clk) + if dut.bus_valid.value and dut.bus_ready.value: + assert dut.bus_data.value == load + From 9b09f735c95c7ce30c4ec08aeb7e5b7a0af7202b Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Mon, 2 Feb 2026 18:28:10 -0500 Subject: [PATCH 05/32] github ide is not fun this can be 1 cycle delayed --- src/data_bus_ctrl.v | 173 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 src/data_bus_ctrl.v diff --git a/src/data_bus_ctrl.v b/src/data_bus_ctrl.v new file mode 100644 index 0000000..7ee4ff3 --- /dev/null +++ b/src/data_bus_ctrl.v @@ -0,0 +1,173 @@ +`default_nettype none +`timescale 1ns/1ps + +module data_bus_ctrl ( + input wire clk, + input wire rst_n, + // data bus handshake + input wire [7:0] data_on_bus, + input wire valid_on_bus, + input wire ready_on_bus, + + // ack bus handshake + input wire[1:0] id_on_ack, + input wire ready_on_ack, + input wire valid_on_ack, + + // one hot? could be encoded? no it will be encoded yes 0b11 means nobody read + output reg [1:0] rd_grant, + // encoded + output reg [1:0] owner +); + //src/dest ids + localparam [1:0] ctrl_id = 2'b11, mem_id = 2'b00, aes_id = 2'b10, sha_id = 2'b01; + + // opcode type + localparam [1:0] hash_op = 2'b11; + // ? tbd + // default control ? after opcode byte handshaked goes to tansmission, back when ack bus handshake + localparam [3:0] idle = 4'b0, addr = 4'b1, module_transmission = 4'b2; + + // owner of the bus + // reg [1:0] owner, n_owner; + reg [1:0] n_owner; + // state of the bus + reg [1:0] state, n_state; + + // counter if mem include + reg [1:0] coutner, n_counter; + + // slice opcode + wire [1:0] dest, src, opcode; + // latch src and dest + reg[1:0] dest_latch, src_latch, n_dest_latch, n_src_latch; + // latch opcode ? maybe? + // reg[1:0] opcode_latch, n_opcode_latch; + assign dest = data_on_bus[5:4], src = data_on_bus[3:2], opcode = data_on_bus[1:0]; + + // handshakes on data/ack bus + wire data_bus_fire, ack_bus_fire; + assign data_bus_fire = valid_on_bus && ready_on_bus; + assign ack_bus_fire = valid_on_ack && ready_on_ack && (id_on_ack == src_latch); + + always @(posedge clk or negedge rst_n) begin + if (!rst_n) begin + owner <= 0; + state <= 0; + coutner <= 0; + + // opcode_latch <= 0; + dest_latch <= 0; + src_latch <= 0; + + end else begin + owner <= n_owner; + state <= n_state; + coutner <= n_counter; + + // opcode_latch <= n_opcode_latch; + dest_latch <= n_dest_latch; + src_latch <= n_src_latch; + + end + end + + // next state/owner computing + always @(*) begin + // comb default + n_owner = owner; + n_state = state; + + n_counter = counter; + + // n_opcode_latch = opcode_latch; + n_dest_latch = dest_latch; + n_src_latch = src_latch; + + case (state) + // when ctrl owns the bus by default + idle: begin + n_counter = 0; + n_opcode_latch = 0; + n_dest_latch = 0; + n_src_latch = 0; + n_owner = ctrl_id + if(valid_on_bus) begin + // keep same + if (opcode == hash_op) begin + n_state = idle; //???????? + end else begin + // handshake + n_state = ready_on_bus ? addr : idle; + n_owner = ready_on_bus ? ctrl_id : owner; + + // n_opcode_latch = ready_on_bus ? opcode : 0; + n_src_latch = ready_on_bus ? src : 0; + n_dest_latch = ready_on_bus ? dest : 0; + end + + end + + + end + // when src/dest contains mem, count 3 handshake update ownership + addr: begin + // count the handshake + n_counter = data_bus_fire ? counter + 1: counter; + + // when 2 beat handshaked and the third handshake + if (counter == 2 && data_bus_fire) begin + n_state = module_transmission; + n_owner = src_latch; + // reset~ counter + n_counter = 0; + + end + end + // src module now owns the bus and ownership will be return upon ack handshake on ack bus + module_transmission: begin + n_counter = 0; + n_owner = src_latch; + + if (ack_bus_fire) begin + n_owner = ctrl_id; + n_state = idle; + n_src_latch = 0; + n_dest_latch = 0; + // n_opcode_latch = 0; + end + + end + + + default:; + endcase + + end + + // comb rd grant + always @(*) begin + case (state) + // idle + idle: begin + rd_grant = ctrl_id; + if (valid_on_bus) begin + rd_grant = dest; + end + end + // addr + addr: begin + rd_grant = dest_latch; + end + // module_transmission + module_transmission: begin + rd_grant = dest_latch; + if (ack_bus_fire) begin + rd_grant = ctrl_id; + end + end + default: + endcase + end + +endmodule \ No newline at end of file From e7f70dccf50f6611cb15ba8ec121e0b61bb69d39 Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Tue, 3 Feb 2026 07:29:00 +0800 Subject: [PATCH 06/32] github ide is not fun this can be 1 cycle delayed --- src/databus_ctrl.v | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 src/databus_ctrl.v diff --git a/src/databus_ctrl.v b/src/databus_ctrl.v deleted file mode 100644 index 288c6dd..0000000 --- a/src/databus_ctrl.v +++ /dev/null @@ -1,7 +0,0 @@ -`default_net_type none -`timescale 1ns/1ps - -module data_bus_ctrl () - - -endmodule From 89254554349119acc029aa563ec22d40a4807e47 Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Wed, 4 Feb 2026 10:32:05 -0500 Subject: [PATCH 07/32] hopfully works IDK --- src/data_bus_ctrl.v | 131 ++++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 64 deletions(-) diff --git a/src/data_bus_ctrl.v b/src/data_bus_ctrl.v index 7ee4ff3..96fde28 100644 --- a/src/data_bus_ctrl.v +++ b/src/data_bus_ctrl.v @@ -14,35 +14,37 @@ module data_bus_ctrl ( input wire ready_on_ack, input wire valid_on_ack, - // one hot? could be encoded? no it will be encoded yes 0b11 means nobody read - output reg [1:0] rd_grant, + // 1hot + output reg [3:0] rd_grant, // encoded - output reg [1:0] owner + output reg [1:0] data_sel, + output reg [1:0] rdy_sel ); //src/dest ids localparam [1:0] ctrl_id = 2'b11, mem_id = 2'b00, aes_id = 2'b10, sha_id = 2'b01; - + // module one hot encode + localparam [3:0] ctrl_1hot = 4'b1000, aes_1hot = 4'b0100, sha_1hot = 4'b0010, mem_1hot = 4'b0001; // opcode type localparam [1:0] hash_op = 2'b11; // ? tbd // default control ? after opcode byte handshaked goes to tansmission, back when ack bus handshake - localparam [3:0] idle = 4'b0, addr = 4'b1, module_transmission = 4'b2; + localparam [1:0] idle = 2'd0, hash_op_wait_ready = 2'd1, addr = 2'd2, module_transmission = 2'd3; - // owner of the bus - // reg [1:0] owner, n_owner; - reg [1:0] n_owner; + // mux sel + reg [1:0] n_data_sel, n_rdy_sel; + // rd grant + reg [1:0] n_rd_grant; // state of the bus reg [1:0] state, n_state; // counter if mem include - reg [1:0] coutner, n_counter; + reg [1:0] counter, n_counter; // slice opcode wire [1:0] dest, src, opcode; // latch src and dest reg[1:0] dest_latch, src_latch, n_dest_latch, n_src_latch; - // latch opcode ? maybe? - // reg[1:0] opcode_latch, n_opcode_latch; + assign dest = data_on_bus[5:4], src = data_on_bus[3:2], opcode = data_on_bus[1:0]; // handshakes on data/ack bus @@ -50,37 +52,39 @@ module data_bus_ctrl ( assign data_bus_fire = valid_on_bus && ready_on_bus; assign ack_bus_fire = valid_on_ack && ready_on_ack && (id_on_ack == src_latch); + // sequential always @(posedge clk or negedge rst_n) begin if (!rst_n) begin - owner <= 0; state <= 0; - coutner <= 0; + counter <= 0; + + data_sel <= 0; + rd_grant <= 0; - // opcode_latch <= 0; dest_latch <= 0; src_latch <= 0; end else begin - owner <= n_owner; state <= n_state; - coutner <= n_counter; + counter <= n_counter; + + data_sel <= n_data_sel; + rd_grant <= n_rd_grant; - // opcode_latch <= n_opcode_latch; dest_latch <= n_dest_latch; src_latch <= n_src_latch; - end end - // next state/owner computing + // next state/sel computing always @(*) begin // comb default - n_owner = owner; n_state = state; - n_counter = counter; - // n_opcode_latch = opcode_latch; + n_data_sel = data_sel; + n_rd_grant = rd_grant; + n_dest_latch = dest_latch; n_src_latch = src_latch; @@ -88,28 +92,53 @@ module data_bus_ctrl ( // when ctrl owns the bus by default idle: begin n_counter = 0; - n_opcode_latch = 0; n_dest_latch = 0; n_src_latch = 0; - n_owner = ctrl_id + // control owns the bus by default + n_data_sel = ctrl_id; + n_rd_grant = ctrl_1hot; + if(valid_on_bus) begin // keep same if (opcode == hash_op) begin - n_state = idle; //???????? + n_rd_grant = (dest == aes_id) ? aes_1hot : (dest == sha_id) ? sha_1hot : 4'b0000; + n_rdy_sel = dest;//should never be 4'b0000 otherwise control is cooked + n_state = hash_op_wait_ready; end else begin // handshake n_state = ready_on_bus ? addr : idle; - n_owner = ready_on_bus ? ctrl_id : owner; + n_rdy_sel = dest; + + n_rd_grant = (dest == aes_id) ? aes_1hot : (dest == sha_id) ? sha_1hot : (dest == mem_id) ? mem_1hot: ctrl_1hot; // dest decode + // let source module + if (!ready_on_bus) begin + case (src) + mem_id: n_rd_grant |= mem_1hot; + aes_id: n_rd_grant |= aes_1hot; + sha_id: n_rd_grant |= sha_1hot; + default:; + endcase + end + + if (ready_on_bus) begin + case (src) + aes_id: n_rd_grant &= ~aes_1hot; + sha_id: n_rd_grant &= ~sha_1hot; + default:; + endcase + end - // n_opcode_latch = ready_on_bus ? opcode : 0; n_src_latch = ready_on_bus ? src : 0; n_dest_latch = ready_on_bus ? dest : 0; end - - end - - + end end + // when the opcode is xx xx xx 11 hashing operation, wait for fire (ideally 1 cycle but could more than that if the sha/aes is not ready) + hash_op_wait_ready: begin + if (data_bus_fire) begin + n_state = idle; + end + end // when src/dest contains mem, count 3 handshake update ownership addr: begin // count the handshake @@ -118,7 +147,8 @@ module data_bus_ctrl ( // when 2 beat handshaked and the third handshake if (counter == 2 && data_bus_fire) begin n_state = module_transmission; - n_owner = src_latch; + n_data_sel = src_latch; + n_rdy_sel = dest_latch; // reset~ counter n_counter = 0; @@ -127,47 +157,20 @@ module data_bus_ctrl ( // src module now owns the bus and ownership will be return upon ack handshake on ack bus module_transmission: begin n_counter = 0; - n_owner = src_latch; + n_data_sel = src_latch; + n_rdy_sel = dest_latch; if (ack_bus_fire) begin - n_owner = ctrl_id; + n_data_sel = ctrl_id; + n_rdy_sel = ctrl_id; n_state = idle; n_src_latch = 0; n_dest_latch = 0; - // n_opcode_latch = 0; end - end - default:; endcase end - - // comb rd grant - always @(*) begin - case (state) - // idle - idle: begin - rd_grant = ctrl_id; - if (valid_on_bus) begin - rd_grant = dest; - end - end - // addr - addr: begin - rd_grant = dest_latch; - end - // module_transmission - module_transmission: begin - rd_grant = dest_latch; - if (ack_bus_fire) begin - rd_grant = ctrl_id; - end - end - default: - endcase - end - -endmodule \ No newline at end of file +endmodule \ No newline at end of file From 0ded74172b06c28327b2c31b5cc8b91703aef720 Mon Sep 17 00:00:00 2001 From: Pengyu Ji Date: Wed, 4 Feb 2026 11:05:06 -0500 Subject: [PATCH 08/32] Created data bus module interface Verilog file --- src/data_bus_module_interface.v | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/data_bus_module_interface.v diff --git a/src/data_bus_module_interface.v b/src/data_bus_module_interface.v new file mode 100644 index 0000000..2a156c9 --- /dev/null +++ b/src/data_bus_module_interface.v @@ -0,0 +1,5 @@ +module data_bus_module_interface( + +); + +endmodule \ No newline at end of file From e75ad5a6dfaabcc4f88dfa3ea21200d06c1b246c Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Wed, 4 Feb 2026 11:22:49 -0500 Subject: [PATCH 09/32] no it doesnt work yet --- src/data_bus_ctrl.v | 49 ++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/data_bus_ctrl.v b/src/data_bus_ctrl.v index 96fde28..4a6b81b 100644 --- a/src/data_bus_ctrl.v +++ b/src/data_bus_ctrl.v @@ -14,16 +14,15 @@ module data_bus_ctrl ( input wire ready_on_ack, input wire valid_on_ack, - // 1hot - output reg [3:0] rd_grant, + // encoded + output reg [1:0] rdy_rd_grant, // ready read grant + output reg [1:0] dv_rd_grant, // data/valid read grant // encoded output reg [1:0] data_sel, output reg [1:0] rdy_sel ); //src/dest ids localparam [1:0] ctrl_id = 2'b11, mem_id = 2'b00, aes_id = 2'b10, sha_id = 2'b01; - // module one hot encode - localparam [3:0] ctrl_1hot = 4'b1000, aes_1hot = 4'b0100, sha_1hot = 4'b0010, mem_1hot = 4'b0001; // opcode type localparam [1:0] hash_op = 2'b11; // ? tbd @@ -33,7 +32,7 @@ module data_bus_ctrl ( // mux sel reg [1:0] n_data_sel, n_rdy_sel; // rd grant - reg [1:0] n_rd_grant; + reg [1:0] n_rdy_rd_grant, n_dv_rd_grant; // state of the bus reg [1:0] state, n_state; @@ -59,7 +58,8 @@ module data_bus_ctrl ( counter <= 0; data_sel <= 0; - rd_grant <= 0; + rdy_rd_grant <= 0; + dv_rd_grant <= 0; dest_latch <= 0; src_latch <= 0; @@ -69,7 +69,8 @@ module data_bus_ctrl ( counter <= n_counter; data_sel <= n_data_sel; - rd_grant <= n_rd_grant; + rdy_rd_grant <= n_rdy_rd_grant; + dv_rd_grant <= n_dv_rd_grant; dest_latch <= n_dest_latch; src_latch <= n_src_latch; @@ -83,7 +84,8 @@ module data_bus_ctrl ( n_counter = counter; n_data_sel = data_sel; - n_rd_grant = rd_grant; + n_rdy_rd_grant = rdy_rd_grant; + n_dv_rd_grant = dv_rd_grant; n_dest_latch = dest_latch; n_src_latch = src_latch; @@ -96,12 +98,12 @@ module data_bus_ctrl ( n_src_latch = 0; // control owns the bus by default n_data_sel = ctrl_id; - n_rd_grant = ctrl_1hot; + n_rdy_rd_grant = ctrl_1hot; if(valid_on_bus) begin // keep same if (opcode == hash_op) begin - n_rd_grant = (dest == aes_id) ? aes_1hot : (dest == sha_id) ? sha_1hot : 4'b0000; + n_rdy_rd_grant = dest; n_rdy_sel = dest;//should never be 4'b0000 otherwise control is cooked n_state = hash_op_wait_ready; end else begin @@ -109,21 +111,21 @@ module data_bus_ctrl ( n_state = ready_on_bus ? addr : idle; n_rdy_sel = dest; - n_rd_grant = (dest == aes_id) ? aes_1hot : (dest == sha_id) ? sha_1hot : (dest == mem_id) ? mem_1hot: ctrl_1hot; // dest decode - // let source module + n_rdy_rd_grant = dest; + // let source module see opcode, if not mem only 1byte for handshake if (!ready_on_bus) begin case (src) - mem_id: n_rd_grant |= mem_1hot; - aes_id: n_rd_grant |= aes_1hot; - sha_id: n_rd_grant |= sha_1hot; + mem_id: n_rdy_rd_grant |= mem_1hot; + aes_id: n_rdy_rd_grant |= aes_1hot; + sha_id: n_rdy_rd_grant |= sha_1hot; default:; endcase end - + // clear src module read if not mem after handshake if (ready_on_bus) begin case (src) - aes_id: n_rd_grant &= ~aes_1hot; - sha_id: n_rd_grant &= ~sha_1hot; + aes_id: n_rdy_rd_grant &= ~aes_1hot; + sha_id: n_rdy_rd_grant &= ~sha_1hot; default:; endcase end @@ -133,10 +135,11 @@ module data_bus_ctrl ( end end end - // when the opcode is xx xx xx 11 hashing operation, wait for fire (ideally 1 cycle but could more than that if the sha/aes is not ready) + // when the opcode is xx xx xx 11 hashing operation, wait for fire (ideally 1 cycle but could more than that if sha/aes is not ready) hash_op_wait_ready: begin if (data_bus_fire) begin n_state = idle; + n_rdy_rd_grant = ctrl_1hot; end end // when src/dest contains mem, count 3 handshake update ownership @@ -151,7 +154,11 @@ module data_bus_ctrl ( n_rdy_sel = dest_latch; // reset~ counter n_counter = 0; - + // rd grant decode + case (dest_latch) + : + default: + endcase end end // src module now owns the bus and ownership will be return upon ack handshake on ack bus @@ -173,4 +180,4 @@ module data_bus_ctrl ( endcase end -endmodule \ No newline at end of file +endmodule From 4b07f89838502e2c6d581ad7653b69c514a24398 Mon Sep 17 00:00:00 2001 From: Bob Li Date: Wed, 4 Feb 2026 13:12:36 -0500 Subject: [PATCH 10/32] added ownership non_participant_test --- test/test.py | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/test/test.py b/test/test.py index cf6aef2..cc4217f 100644 --- a/test/test.py +++ b/test/test.py @@ -144,6 +144,105 @@ async def data_transmission_test(dut): if dut.bus_valid.value and dut.bus_ready.value: assert dut.bus_data.value == load +#a test for testing the non-participants in the databus driving disconnecting +@cocotb.test() +async def non_participant_test(dut): + #reset everything first + dut._log_info("Reset") + dut.rst_n.value = 0 + await ClockCycles(dut.clk, 10, unit = "us") + dut.rst_n.value = 1 + dut._log.info("Starting non_participant_test") + + # first let's test the WR command which needs the use of mem and the use of aes + # conveniently as it appears to be our last test: + dut._log.info("Testing ") + dut.READY.value = 1 + dut.ctrl_ready.value = 0 + dut.sha_ready.value = 0 + dut.aes_ready.value = 0 + dut.mem_ready.value = 1 + #now we decide that we want to do a wr_res, say we need to make a dummy address + dummy_addr = 0x001234 + #now we craft the fake opcode needed for the command/driving + op_code = 0b10100010 + #crafting the header as per the beats architecture required + dut.header.value = [dummy_addr >> 16 & 0xFF, dummy_addr >> 8 & 0xFF, dummy_addr >> 0 & 0xFF, op_code] + #now we set up a test payload + payload = [0xDE,0xAD,0xBE,0xEF, 0x11,0x22,0x33,0x44] + await RisingEdge(dut.clk) + for beats in dut.header.value: + #send the beats of the data 1 by 1 + dut.ctrl_data = beats + #set the control valid back to true + dut.ctrl_valid.value = 1 + #wait for handshaking signals + while(True): + await RisingEdge(dut.clk) + if(dut.ctrl_ready.value): + break + dut.ctrl_valid.value = 0 + #send payload data in + for data in payload: + dut.aes_data.value = data + dut.aes_valid.value = 1 + while(True): + await RisingEdge(dut.clk) + if(dut.aes_ready.value): + break + dut.aes_ready.value = 0 + + #check whether any other non_participants are participating + for _ in payload: + await RisingEdge(dut.clk) + assert dut.sha_data.value == 0 + assert dut.ctrl_data.value == 0 + + #now test the hashops, this doesn't require actual address + #reset before starting a new test: + dut._log_info("Reset") + dut.rst_n.value = 0 + await ClockCycles(dut.clk, 10, unit = "us") + dut.rst_n.value = 1 + dut._log_info("Testing/Logging for HashOp") + #turn on neccessary ports + dut.mem_ready.value = 1 + dut.aes_ready.value = 1 + #constructt the op code for aes to begin an encoding process + op_code = 0b10100011 + dut.header.value = [dummy_addr >> 16 & 0xFF, dummy_addr >> 8 & 0xFF, dummy_addr >> 0 & 0xFF, op_code] + #now we set up a test payload + payload = [0xDE,0xAD,0xBE,0xEF, 0x11,0x22,0x33,0x44] + await RisingEdge(dut.clk) + for beats in dut.header.value: + #send the beats of the data 1 by 1 + dut.ctrl_data = beats + #set the control valid back to true + dut.ctrl_valid.value = 1 + #wait for handshaking signals + while(True): + await RisingEdge(dut.clk) + if(dut.ctrl_ready.value): + break + dut.ctrl_valid.value = 0 + #send payload data in + for data in payload: + dut.aes_data.value = data + dut.aes_valid.value = 1 + while(True): + await RisingEdge(dut.clk) + if(dut.aes_ready.value): + break + dut.aes_ready.value = 0 + #check whether any other non_participants are participating + for _ in payload: + await RisingEdge(dut.clk) + assert dut.sha_data.value == 0 + assert dut.ctrl_data.value == 0 + assert dut.memory_data.value == 0 +@cocotb.test() +async def ownership_transfer_test(dut): + \ No newline at end of file From 2613089e0c64ad08f8740653a5c4d8c09eb2fa54 Mon Sep 17 00:00:00 2001 From: Bob Li Date: Wed, 4 Feb 2026 13:26:39 -0500 Subject: [PATCH 11/32] tried adding ownership transfer test --- test/test.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/test/test.py b/test/test.py index cc4217f..39f582c 100644 --- a/test/test.py +++ b/test/test.py @@ -242,7 +242,40 @@ async def non_participant_test(dut): assert dut.memory_data.value == 0 - +#test to see whether the ownership is transfered during operations @cocotb.test() async def ownership_transfer_test(dut): - \ No newline at end of file + #first reset the databus + dut._log_info("Reset") + dut.rst_n.value = 0 + await ClockCycles(dut.clk, 10, unit = "us") + dut.rst_n.value = 1 + #upon resetting then we have to send valid 4 beat data from control + #sending an op_code from read_txt, then bus should transfer to memory + #memory and aes should be set to ready and valid for transfer? + dut._log_info("Starting ownership transfer test") + dut.mem_ready.value = 1 + dut.mem_valid.value = 1 + dut.aes_ready.value = 1 + dut.aes_valid.value = 1 + dut.ctrl_ready.value = 1 + dut.ctrl_valid.value = 1 + dummy_addr = 0x001234 + op_code = 0b10100001 + dut.header.value = [dummy_addr >> 16 & 0xFF, dummy_addr >> 8 & 0xFF, dummy_addr >> 0 & 0xFF, op_code] + #now control send 4 beats + await RisingEdge(dut.clk) + for beats in dut.header.value: + #send the beats of the data 1 by 1 + dut.ctrl_data = beats + #set the control valid back to true + dut.ctrl_valid.value = 1 + #wait for handshaking signals + while(True): + await RisingEdge(dut.clk) + if(dut.ctrl_ready.value): + break + dut.ctrl_valid.value = 0 + #now check the bus_owner, should be control + assert dut.bus_owner.value == 0b00 + From ac42548f5d58fd9233fe893d512c29f7127363b5 Mon Sep 17 00:00:00 2001 From: Bob Li Date: Wed, 4 Feb 2026 13:42:52 -0500 Subject: [PATCH 12/32] tried a first version of owner_release test --- test/test.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test.py b/test/test.py index 39f582c..201c036 100644 --- a/test/test.py +++ b/test/test.py @@ -279,3 +279,21 @@ async def ownership_transfer_test(dut): #now check the bus_owner, should be control assert dut.bus_owner.value == 0b00 +@cocotb.test() +async def owner_release(dut): + #reset everything first + dut._log_info("Reset") + dut.rst_n.value = 0 + await ClockCycles(dut.clk, 10, unit = "us") + dut.rst_n.value = 1 + dut._log.info("Starting non_participant_test") + #assume that memory currently has the ownership of the bus + dut.bus_owner.value = 0b00 + #now memory has to ack + dut.ctrl_ready.value = 1 + dut.mem_ready.value = 1 + #now the memory has to ack: + dut.ack_ready_to_mem.value = 1 + await RisingEdge(dut.clk) + assert dut.bus_owner.value == 0b11 + From 0bf967f44f675758c2a9af30a26e5a2b2974997d Mon Sep 17 00:00:00 2001 From: Pengyu Ji Date: Wed, 4 Feb 2026 15:16:04 -0500 Subject: [PATCH 13/32] data_bus_module_interface v1 --- src/data_bus_module_interface.v | 43 +++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/data_bus_module_interface.v b/src/data_bus_module_interface.v index 2a156c9..137062f 100644 --- a/src/data_bus_module_interface.v +++ b/src/data_bus_module_interface.v @@ -1,5 +1,44 @@ -module data_bus_module_interface( - +module data_bus_module_interface ( + // input from global arbiter + input [3:0] rd_grant, + input [7:0] data_in, + + // output to the global arbiter + output reg [7:0] data_out, + output reg rdy_out, // do we need rdy? + output reg valid_out, + + // input from the module (e.g. from SHA, AES) + input [7:0] data_from_module, + input valid_from_module, + + // output to the module + output reg [7:0] data_to_module, + output reg valid_to_module ); +always @(*) begin + // defaults + valid_out = 1'b0; + valid_to_module = 1'b0; + + data_to_module = data_in; + + // if the rd_grant signal to a module is valid, + // then the data send to the module is also valid + if (rd_grant[0] == 1'b1) begin + valid_to_module = 1'b1; + end + + data_out = data_from_module; + + // if the data from module is valid, + // then the data_out to the global arbiter is also valid + if (valid_from_module == 1'b1) begin + valid_out = 1'b1; + end +end + + + endmodule \ No newline at end of file From 874f853519418aa8b55b6c98bb6fe06e2937ec5b Mon Sep 17 00:00:00 2001 From: Pengyu Ji Date: Thu, 5 Feb 2026 13:15:37 -0500 Subject: [PATCH 14/32] data_bus_module_interface v2 --- src/data_bus_module_interface.v | 34 +++++++++------------------------ 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/src/data_bus_module_interface.v b/src/data_bus_module_interface.v index 137062f..cb7b075 100644 --- a/src/data_bus_module_interface.v +++ b/src/data_bus_module_interface.v @@ -1,42 +1,26 @@ module data_bus_module_interface ( // input from global arbiter - input [3:0] rd_grant, - input [7:0] data_in, + input rd_grant, + input [9:0] data_in, // [9]:ready, [8]:valid, [7:0]:data // output to the global arbiter - output reg [7:0] data_out, - output reg rdy_out, // do we need rdy? - output reg valid_out, + output reg [9:0] data_out, // input from the module (e.g. from SHA, AES) - input [7:0] data_from_module, - input valid_from_module, + input [9:0] data_from_module, // output to the module - output reg [7:0] data_to_module, - output reg valid_to_module + output reg [9:0] data_to_module, ); always @(*) begin - // defaults - valid_out = 1'b0; - valid_to_module = 1'b0; - data_to_module = data_in; - - // if the rd_grant signal to a module is valid, - // then the data send to the module is also valid - if (rd_grant[0] == 1'b1) begin - valid_to_module = 1'b1; - end + // if rd_grant is high, pass the data_in to the module + if (rd_grant) data_to_module = data_in; + // if rd_grant is low, manually change the valid bit of the data to 0 + else data_to_module = {data_in[9], 1'b0, data_in[7:0]}; data_out = data_from_module; - - // if the data from module is valid, - // then the data_out to the global arbiter is also valid - if (valid_from_module == 1'b1) begin - valid_out = 1'b1; - end end From cacdda50ebc47af0bbbc572fca8f5b04be49a8d0 Mon Sep 17 00:00:00 2001 From: Pengyu Ji Date: Thu, 5 Feb 2026 13:19:57 -0500 Subject: [PATCH 15/32] data_bus_module_interface v2 fixed typo --- src/data_bus_module_interface.v | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/data_bus_module_interface.v b/src/data_bus_module_interface.v index cb7b075..72cd6ff 100644 --- a/src/data_bus_module_interface.v +++ b/src/data_bus_module_interface.v @@ -23,6 +23,4 @@ always @(*) begin data_out = data_from_module; end - - endmodule \ No newline at end of file From c665ba3df1d69eb7c4fd2e26400ee9a4503d391b Mon Sep 17 00:00:00 2001 From: Ayoung Eun Date: Wed, 11 Feb 2026 17:07:59 -0500 Subject: [PATCH 16/32] Added small functions and modified info.yaml --- info.yaml | 53 ++++++++++++++++++++++++--------------------- src/data_bus_ctrl.v | 21 ++++++++++++++---- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/info.yaml b/info.yaml index 50bb751..d76034f 100644 --- a/info.yaml +++ b/info.yaml @@ -1,9 +1,9 @@ # Tiny Tapeout project information project: - title: "" # Project title + title: "Interconnect Data Bus" # Project title author: "" # Your name discord: "" # Your discord username, for communication and automatically assigning you a Tapeout role (optional) - description: "" # One line description of what your project does + description: "Trasnfer data between modules" # One line description of what your project does language: "Verilog" # other examples include SystemVerilog, Amaranth, VHDL, etc clock_hz: 0 # Clock frequency in Hz (or 0 if not applicable) @@ -18,38 +18,41 @@ project: # Don't forget to also update `PROJECT_SOURCES` in test/Makefile. source_files: - "project.v" + - "data_bus_ctrl.v" + - "data_bus_module_interface.v" + - "ack_bus_arbiter.v" # The pinout of your project. Leave unused pins blank. DO NOT delete or add any pins. pinout: # Inputs - ui[0]: "" - ui[1]: "" - ui[2]: "" - ui[3]: "" - ui[4]: "" - ui[5]: "" - ui[6]: "" - ui[7]: "" + ui[0]: "ui_in0" # corresponds to ui_in[0] in project.v + ui[1]: "ui_in1" # ui_in[1] + ui[2]: "ui_in2" # ui_in[2] + ui[3]: "ui_in3" # ui_in[3] + ui[4]: "ui_in4" # ui_in[4] + ui[5]: "ui_in5" # ui_in[5] + ui[6]: "ui_in6" # ui_in[6] + ui[7]: "ui_in7" # ui_in[7] # Outputs - uo[0]: "" - uo[1]: "" - uo[2]: "" - uo[3]: "" - uo[4]: "" - uo[5]: "" - uo[6]: "" - uo[7]: "" + uo[0]: "uo_out0" # corresponds to uo_out[0] + uo[1]: "uo_out1" + uo[2]: "uo_out2" + uo[3]: "uo_out3" + uo[4]: "uo_out4" + uo[5]: "uo_out5" + uo[6]: "uo_out6" + uo[7]: "uo_out7" # Bidirectional pins - uio[0]: "" - uio[1]: "" - uio[2]: "" - uio[3]: "" - uio[4]: "" - uio[5]: "" + uio[0]: "" # uio_out[0] + uio[1]: "" # uio_out[1] + uio[2]: "" # uio_out[2] + uio[3]: "" # uio_out[3] + uio[4]: "" # uio_out[4] + uio[5]: "" # uio_out[5] uio[6]: "" uio[7]: "" # Do not change! -yaml_version: 6 +yaml_version: 6 \ No newline at end of file diff --git a/src/data_bus_ctrl.v b/src/data_bus_ctrl.v index 4a6b81b..8631b32 100644 --- a/src/data_bus_ctrl.v +++ b/src/data_bus_ctrl.v @@ -100,7 +100,7 @@ module data_bus_ctrl ( n_data_sel = ctrl_id; n_rdy_rd_grant = ctrl_1hot; - if(valid_on_bus) begin + if(valid_on_bus && legal_mapping(opcode, src, dest)) begin // keep same if (opcode == hash_op) begin n_rdy_rd_grant = dest; @@ -110,7 +110,6 @@ module data_bus_ctrl ( // handshake n_state = ready_on_bus ? addr : idle; n_rdy_sel = dest; - n_rdy_rd_grant = dest; // let source module see opcode, if not mem only 1byte for handshake if (!ready_on_bus) begin @@ -129,7 +128,6 @@ module data_bus_ctrl ( default:; endcase end - n_src_latch = ready_on_bus ? src : 0; n_dest_latch = ready_on_bus ? dest : 0; end @@ -178,6 +176,21 @@ module data_bus_ctrl ( default:; endcase - end + + function legal_mapping; + input [1:0] opcode, src, dest; + begin + case (opcode) + 2'b00, 2'b01: // RD_KEY, RD_TEXT + legal_mapping = (src == mem_id) && (dest == aes_id || dest == sha_id); + 2'b10: // WR_RES + legal_mapping = (dest == mem_id) && (src == aes_id || src == sha_id); + 2'b11: // HASH_OP + legal_mapping = (src == aes_id || src == sha_id); + default: + legal_mapping = 1'b0; + endcase + end + endfunction endmodule From 8be584551de6eef8a4557b0546741d97eea78925 Mon Sep 17 00:00:00 2001 From: Bob Li Date: Wed, 11 Feb 2026 19:32:28 -0500 Subject: [PATCH 17/32] added fake control unit prayz it works --- test/test.py | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/test/test.py b/test/test.py index 201c036..7ca0420 100644 --- a/test/test.py +++ b/test/test.py @@ -5,6 +5,30 @@ from cocotb.clock import Clock from cocotb.triggers import ClockCycles, RisingEdge +# + +#custom control module +async def control_module(dut, dest, src): + # a very dummy version of this module + # basically an output of 1 or drive data_on_bus as 1 + while(True): + await RisingEdge(dut.clk) + if(dut.valid_on_bus.value == True and dut.rdy_dest.value == True): + # ready to receive opcode + value = 0 + #wait for 3 cycles to receive opcode + for i in range(2): + value = dut.data_on_bus.value + value << 3 + await RisingEdge(dut.clk) + #wait for 2 more rising edge to skip the beats + for i in range(2): + await RisingEdge(dut.clk) + dut.dv_sel.value = src + dut.rdy_sel.value = dest + return value + + @cocotb.test() async def test_project(dut): @@ -41,9 +65,14 @@ async def test_project(dut): #test for the ready signals +# stuff to change: +# 1. reference the bus owner +# 2. check the ready signal on the module to be ready (1) +# 3. send 4 beat transactions to switch ownership +# 4. check ready @cocotb.test() async def ready_test(dut): - + assert True dut._log_info("Reset") dut.rst_n.value = 0 await ClockCycles(dut.clk, 10, unit = "us") @@ -289,7 +318,7 @@ async def owner_release(dut): dut._log.info("Starting non_participant_test") #assume that memory currently has the ownership of the bus dut.bus_owner.value = 0b00 - #now memory has to ack + #set ready values, unsure whether neccessary dut.ctrl_ready.value = 1 dut.mem_ready.value = 1 #now the memory has to ack: @@ -297,3 +326,7 @@ async def owner_release(dut): await RisingEdge(dut.clk) assert dut.bus_owner.value == 0b11 +@cocotb.test() +async def stray_ack(dut): + #firstly, reset the file + dut._log_info("reset") \ No newline at end of file From e0ec0513e403f4625e898008bf5b344d0f632e87 Mon Sep 17 00:00:00 2001 From: Bob Li Date: Wed, 11 Feb 2026 19:40:49 -0500 Subject: [PATCH 18/32] updated fake/simulated control module with custom set_ready functions --- test/test.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/test.py b/test/test.py index 7ca0420..eafa6d4 100644 --- a/test/test.py +++ b/test/test.py @@ -8,6 +8,16 @@ # #custom control module + +async def set_ready(dut, module): + if(module == 0b00): + dut.mem_ready.value = 1 + elif(module == 0b01): + dut.sha_ready.value = 1 + elif(module == 0b10): + dut.aes_ready.value = 1 + else: + dut.ctrl_ready.value = 1 async def control_module(dut, dest, src): # a very dummy version of this module # basically an output of 1 or drive data_on_bus as 1 @@ -26,6 +36,8 @@ async def control_module(dut, dest, src): await RisingEdge(dut.clk) dut.dv_sel.value = src dut.rdy_sel.value = dest + set_ready(dest) + set_ready(src) return value @@ -66,7 +78,7 @@ async def test_project(dut): #test for the ready signals # stuff to change: -# 1. reference the bus owner +# 1. reference the bus owner dv_sel # 2. check the ready signal on the module to be ready (1) # 3. send 4 beat transactions to switch ownership # 4. check ready From 507d938ba3959089118e33d3cde228abe262d0a6 Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Sat, 28 Feb 2026 16:00:35 +0800 Subject: [PATCH 19/32] HOPE IT WORKS --- src/data_bus_ctrl.v | 163 +++++++++++++++++++++++++++----------------- 1 file changed, 101 insertions(+), 62 deletions(-) diff --git a/src/data_bus_ctrl.v b/src/data_bus_ctrl.v index 8631b32..b24f8a1 100644 --- a/src/data_bus_ctrl.v +++ b/src/data_bus_ctrl.v @@ -7,35 +7,45 @@ module data_bus_ctrl ( // data bus handshake input wire [7:0] data_on_bus, input wire valid_on_bus, - input wire ready_on_bus, + + // ready signal from module + input wire rdy_mem, + input wire rdy_aes, + input wire rdy_sha, // ack bus handshake input wire[1:0] id_on_ack, input wire ready_on_ack, input wire valid_on_ack, - // encoded - output reg [1:0] rdy_rd_grant, // ready read grant - output reg [1:0] dv_rd_grant, // data/valid read grant + // 1bit per signal + output reg [3:0] rdy_rd_grant, // ready read grant + output reg [3:0] dv_rd_grant, // data/valid read grant // encoded output reg [1:0] data_sel, - output reg [1:0] rdy_sel + + // ready output + output reg rdy_to_owner + // output reg [1:0] rdy_sel ); //src/dest ids localparam [1:0] ctrl_id = 2'b11, mem_id = 2'b00, aes_id = 2'b10, sha_id = 2'b01; - // opcode type - localparam [1:0] hash_op = 2'b11; - // ? tbd + // ? tbd + localparam [3:0] mem_1b = (4'b0001 << mem_id); + localparam [3:0] sha_1b = (4'b0001 << sha_id); + localparam [3:0] aes_1b = (4'b0001 << aes_id); + localparam [3:0] ctrl_1b = (4'b0001 << ctrl_id); // default control ? after opcode byte handshaked goes to tansmission, back when ack bus handshake localparam [1:0] idle = 2'd0, hash_op_wait_ready = 2'd1, addr = 2'd2, module_transmission = 2'd3; // mux sel - reg [1:0] n_data_sel, n_rdy_sel; + reg [1:0] n_data_sel; // rd grant - reg [1:0] n_rdy_rd_grant, n_dv_rd_grant; + reg [3:0] n_rdy_rd_grant, n_dv_rd_grant; + // rdy output + reg n_rdy_to_owner; // state of the bus reg [1:0] state, n_state; - // counter if mem include reg [1:0] counter, n_counter; @@ -43,14 +53,34 @@ module data_bus_ctrl ( wire [1:0] dest, src, opcode; // latch src and dest reg[1:0] dest_latch, src_latch, n_dest_latch, n_src_latch; - assign dest = data_on_bus[5:4], src = data_on_bus[3:2], opcode = data_on_bus[1:0]; // handshakes on data/ack bus wire data_bus_fire, ack_bus_fire; - assign data_bus_fire = valid_on_bus && ready_on_bus; + assign data_bus_fire = valid_on_bus && rdy_to_owner; assign ack_bus_fire = valid_on_ack && ready_on_ack && (id_on_ack == src_latch); + // opcode format matching + wire rd_key_fire, rd_txt_fire, wr_txt_fire, hash_fire; + assign rd_key_fire = (opcode == 2'b00) && (dest == aes_id) && (src == mem_id); + assign rd_txt_fire = (opcode == 2'b01) && ((dest == aes_id) || (dest == sha_id)) && (src == mem_id); + assign wr_txt_fire = (opcode == 2'b10) && (dest == mem_id) && ((src == aes_id) || (src == sha_id)); + assign hash_fire = (opcode == 2'b11) && ((dest == aes_id) || (dest == sha_id)); + + // src ready and dest ready only for opcode + wire src_rdy, dest_rdy; + + + always @(*) begin + if (state == idle) begin + src_rdy = (src == mem_id) ? rdy_mem : (src == aes_id) ? rdy_aes : (src == sha_id) ? rdy_sha : 0; + dest_rdy = (dest == mem_id) ? rdy_mem : (dest == aes_id) ? rdy_aes : (dest == sha_id) ? rdy_sha : 0; + end else begin + src_rdy = (src_latch == mem_id) ? rdy_mem : (src_latch == aes_id) ? rdy_aes : (src_latch == sha_id) ? rdy_sha : 0; + dest_rdy = (dest_latch == mem_id) ? rdy_mem : (dest_latch == aes_id) ? rdy_aes : (dest_latch == sha_id) ? rdy_sha : 0; + end + end + // sequential always @(posedge clk or negedge rst_n) begin if (!rst_n) begin @@ -64,6 +94,7 @@ module data_bus_ctrl ( dest_latch <= 0; src_latch <= 0; + // rdy_to_owner <= 0; end else begin state <= n_state; counter <= n_counter; @@ -74,6 +105,8 @@ module data_bus_ctrl ( dest_latch <= n_dest_latch; src_latch <= n_src_latch; + + // rdy_to_owner <= n_rdy_to_owner; end end @@ -90,6 +123,8 @@ module data_bus_ctrl ( n_dest_latch = dest_latch; n_src_latch = src_latch; + // n_rdy_to_owner = rdy_to_owner; + case (state) // when ctrl owns the bus by default idle: begin @@ -98,38 +133,33 @@ module data_bus_ctrl ( n_src_latch = 0; // control owns the bus by default n_data_sel = ctrl_id; - n_rdy_rd_grant = ctrl_1hot; + // default + rdy_to_owner = 1; + // CTRL RD + n_rdy_rd_grant = ctrl_1b; + n_dv_rd_grant = ctrl_1b; - if(valid_on_bus && legal_mapping(opcode, src, dest)) begin + if(valid_on_bus) begin // keep same - if (opcode == hash_op) begin - n_rdy_rd_grant = dest; - n_rdy_sel = dest;//should never be 4'b0000 otherwise control is cooked + if (hash_fire) begin + // id to 1hot decode + n_dv_rd_grant = (dest == aes_id) ? aes_1b : (dest == sha_id) ? sha_1b : ctrl_1b; + + rdy_to_owner = (dest == aes_id) ? rdy_aes : (dest == sha_id) ? rdy_sha :0;//should never be 0 otherwise control is cooked n_state = hash_op_wait_ready; - end else begin + end else if(rd_key_fire || rd_txt_fire || wr_txt_fire) begin // handshake - n_state = ready_on_bus ? addr : idle; - n_rdy_sel = dest; - n_rdy_rd_grant = dest; + n_state = rdy_to_owner ? addr : idle; + rdy_to_owner = src_rdy & dest_rdy; // let source module see opcode, if not mem only 1byte for handshake - if (!ready_on_bus) begin - case (src) - mem_id: n_rdy_rd_grant |= mem_1hot; - aes_id: n_rdy_rd_grant |= aes_1hot; - sha_id: n_rdy_rd_grant |= sha_1hot; - default:; - endcase - end - // clear src module read if not mem after handshake - if (ready_on_bus) begin - case (src) - aes_id: n_rdy_rd_grant &= ~aes_1hot; - sha_id: n_rdy_rd_grant &= ~sha_1hot; - default:; - endcase - end - n_src_latch = ready_on_bus ? src : 0; - n_dest_latch = ready_on_bus ? dest : 0; + n_src_latch = rdy_to_owner ? src : 0; + n_dest_latch = rdy_to_owner ? dest : 0; + // set src + n_dv_rd_grant = set(src); + n_dv_rd_grant = set(dest); + + end else begin + // ggs end end end @@ -137,7 +167,7 @@ module data_bus_ctrl ( hash_op_wait_ready: begin if (data_bus_fire) begin n_state = idle; - n_rdy_rd_grant = ctrl_1hot; + n_rdy_rd_grant = ctrl_1b; end end // when src/dest contains mem, count 3 handshake update ownership @@ -149,25 +179,23 @@ module data_bus_ctrl ( if (counter == 2 && data_bus_fire) begin n_state = module_transmission; n_data_sel = src_latch; - n_rdy_sel = dest_latch; - // reset~ counter + rdy_to_owner = dest_rdy; + // reset counter n_counter = 0; - // rd grant decode - case (dest_latch) - : - default: - endcase + // rd grant reset + n_dv_rd_grant = clr(src); end end // src module now owns the bus and ownership will be return upon ack handshake on ack bus module_transmission: begin n_counter = 0; n_data_sel = src_latch; - n_rdy_sel = dest_latch; + rdy_to_owner = dest_rdy; if (ack_bus_fire) begin n_data_sel = ctrl_id; - n_rdy_sel = ctrl_id; + rdy_to_owner = 1; + n_dv_rd_grant = clr(dest); n_state = idle; n_src_latch = 0; n_dest_latch = 0; @@ -176,21 +204,32 @@ module data_bus_ctrl ( default:; endcase - end - function legal_mapping; - input [1:0] opcode, src, dest; + end + // set decode based on id + function [3:0] set; + input [1:0] id; begin - case (opcode) - 2'b00, 2'b01: // RD_KEY, RD_TEXT - legal_mapping = (src == mem_id) && (dest == aes_id || dest == sha_id); - 2'b10: // WR_RES - legal_mapping = (dest == mem_id) && (src == aes_id || src == sha_id); - 2'b11: // HASH_OP - legal_mapping = (src == aes_id || src == sha_id); - default: - legal_mapping = 1'b0; + case (id) + mem_id: set |= mem_1b; + ctrl_id: set |= ctrl_1b; + aes_id: set |= aes_1b; + sha_id: set |= sha_id; + default: ; endcase end endfunction + //clr decode based on id + function [3:0] clr; + input [1:0] id; + begin + case (id) + mem_id: set &= (~mem_1b); + ctrl_id: set &= (~ctrl_1b); + aes_id: set &= (~aes_1b); + sha_id: set &= (~sha_id); + default: ; + endcase + end + endfunction endmodule From c94bdc298c41a327bf3d2bfb83a55b507af88caf Mon Sep 17 00:00:00 2001 From: ayoungeun Date: Wed, 25 Mar 2026 18:44:40 -0400 Subject: [PATCH 20/32] Fixed typos in test.py --- test/test.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/test/test.py b/test/test.py index eafa6d4..bd178ba 100644 --- a/test/test.py +++ b/test/test.py @@ -85,9 +85,9 @@ async def test_project(dut): @cocotb.test() async def ready_test(dut): assert True - dut._log_info("Reset") + dut._log.info("Reset") dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10, unit = "us") + await ClockCycles(dut.clk, 10) dut.rst_n.value = 1 dut._log.info("Testing Ready Signals") @@ -137,9 +137,9 @@ async def ready_test(dut): @cocotb.test() async def data_transmission_test(dut): #reset everything first - dut._log_info("Reset") + dut._log.info("Reset") dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10, unit = "us") + await ClockCycles(dut.clk, 10) dut.rst_n.value = 1 dut._log.info("Testing Ready Signals") @@ -189,9 +189,9 @@ async def data_transmission_test(dut): @cocotb.test() async def non_participant_test(dut): #reset everything first - dut._log_info("Reset") + dut._log.info("Reset") dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10, unit = "us") + await ClockCycles(dut.clk, 10) dut.rst_n.value = 1 dut._log.info("Starting non_participant_test") @@ -241,11 +241,11 @@ async def non_participant_test(dut): #now test the hashops, this doesn't require actual address #reset before starting a new test: - dut._log_info("Reset") + dut._log.info("Reset") dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10, unit = "us") + await ClockCycles(dut.clk, 10) dut.rst_n.value = 1 - dut._log_info("Testing/Logging for HashOp") + dut._log.info("Testing/Logging for HashOp") #turn on neccessary ports dut.mem_ready.value = 1 dut.aes_ready.value = 1 @@ -287,14 +287,14 @@ async def non_participant_test(dut): @cocotb.test() async def ownership_transfer_test(dut): #first reset the databus - dut._log_info("Reset") + dut._log.info("Reset") dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10, unit = "us") + await ClockCycles(dut.clk, 10) dut.rst_n.value = 1 #upon resetting then we have to send valid 4 beat data from control #sending an op_code from read_txt, then bus should transfer to memory #memory and aes should be set to ready and valid for transfer? - dut._log_info("Starting ownership transfer test") + dut._log.info("Starting ownership transfer test") dut.mem_ready.value = 1 dut.mem_valid.value = 1 dut.aes_ready.value = 1 @@ -323,9 +323,9 @@ async def ownership_transfer_test(dut): @cocotb.test() async def owner_release(dut): #reset everything first - dut._log_info("Reset") + dut._log.info("Reset") dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10, unit = "us") + await ClockCycles(dut.clk, 10) dut.rst_n.value = 1 dut._log.info("Starting non_participant_test") #assume that memory currently has the ownership of the bus @@ -341,4 +341,4 @@ async def owner_release(dut): @cocotb.test() async def stray_ack(dut): #firstly, reset the file - dut._log_info("reset") \ No newline at end of file + dut._log.info("reset") \ No newline at end of file From b8658102a8ea19885ac169b51267d7cea4f28359 Mon Sep 17 00:00:00 2001 From: ayoungeun Date: Wed, 25 Mar 2026 18:45:47 -0400 Subject: [PATCH 21/32] modified set decode based on id function slightly, changed signal type of src_rdy, dest_rdy --- src/data_bus_ctrl.v | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/data_bus_ctrl.v b/src/data_bus_ctrl.v index b24f8a1..5378597 100644 --- a/src/data_bus_ctrl.v +++ b/src/data_bus_ctrl.v @@ -68,7 +68,7 @@ module data_bus_ctrl ( assign hash_fire = (opcode == 2'b11) && ((dest == aes_id) || (dest == sha_id)); // src ready and dest ready only for opcode - wire src_rdy, dest_rdy; + reg src_rdy, dest_rdy; always @(*) begin @@ -210,11 +210,12 @@ module data_bus_ctrl ( function [3:0] set; input [1:0] id; begin + set = dv_rd_grant; case (id) - mem_id: set |= mem_1b; - ctrl_id: set |= ctrl_1b; - aes_id: set |= aes_1b; - sha_id: set |= sha_id; + mem_id: set = set | mem_1b; + ctrl_id: set = set | ctrl_1b; + aes_id: set = set | aes_1b; + sha_id: set = set | sha_1b; default: ; endcase end @@ -223,11 +224,12 @@ module data_bus_ctrl ( function [3:0] clr; input [1:0] id; begin + clr = dv_rd_grant; case (id) - mem_id: set &= (~mem_1b); - ctrl_id: set &= (~ctrl_1b); - aes_id: set &= (~aes_1b); - sha_id: set &= (~sha_id); + mem_id: clr = clr & (~mem_1b); + ctrl_id: clr = clr & (~ctrl_1b); + aes_id: clr = clr & (~aes_1b); + sha_id: clr = clr & (~sha_1b); default: ; endcase end From 2cc2c74ee7fd406299b9d1b355e7bd618a00bdc4 Mon Sep 17 00:00:00 2001 From: ayoungeun Date: Wed, 25 Mar 2026 18:46:08 -0400 Subject: [PATCH 22/32] Fixed typo and backward assignments --- src/ack_bus_module_interface.v | 10 +++++----- src/data_bus_module_interface.v | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ack_bus_module_interface.v b/src/ack_bus_module_interface.v index 6ec81f3..6a42094 100644 --- a/src/ack_bus_module_interface.v +++ b/src/ack_bus_module_interface.v @@ -1,18 +1,18 @@ module ack_bus_module_interface ( input wire ACK_READY, output wire ACK_READY_TO_MODULE, - input wire MODULE_SIDE_ACK_VAILD, + input wire MODULE_SIDE_ACK_VALID, output wire ACK_VALID, input wire [1:0] MODULE_SIDE_MODULE_SOURCE_ID, output wire [1:0] MODULE_SOURCE_ID ); //READY -//MODULE_SIDE_ACK_VALID->ACK_VAILD +//MODULE_SIDE_ACK_VALID->ACK_VALID - assign ACK_READY=ACK_READY_TO_MODULE; - assign ACK_VAILD=MODULE_SIDE_ACK_VAILD; - assign MODULE_SOURCE_ID=MODULE_SIDE_MODULE_SOURCE_ID; + assign ACK_READY_TO_MODULE = ACK_READY; + assign ACK_VALID = MODULE_SIDE_ACK_VALID; + assign MODULE_SOURCE_ID = MODULE_SIDE_MODULE_SOURCE_ID; //This is an example of what the interfacing should look like, realistically the central ack_bus module will take care of all the interfacing //We can refer back to this in the future diff --git a/src/data_bus_module_interface.v b/src/data_bus_module_interface.v index 72cd6ff..57cea80 100644 --- a/src/data_bus_module_interface.v +++ b/src/data_bus_module_interface.v @@ -10,7 +10,7 @@ module data_bus_module_interface ( input [9:0] data_from_module, // output to the module - output reg [9:0] data_to_module, + output reg [9:0] data_to_module ); always @(*) begin From 0d3ecb7c00ab85a8c8584697bc84c260a610ec54 Mon Sep 17 00:00:00 2001 From: ayoungeun Date: Wed, 25 Mar 2026 18:46:25 -0400 Subject: [PATCH 23/32] backward assignment fixed --- src/ack_bus_arbiter.v | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ack_bus_arbiter.v b/src/ack_bus_arbiter.v index 923d03e..ea4081e 100644 --- a/src/ack_bus_arbiter.v +++ b/src/ack_bus_arbiter.v @@ -32,28 +32,28 @@ always @(*) begin ack_valid_n = 1'b1; winner_source_id = 2'b11; //CTRL has default ownship of the bus - if (ack_ready_to_ctrl == 1'b1) begin + if (ack_valid_from_ctrl == 1'b1) begin //CTRL module is asserting ack {ack_ready_to_ctrl, ack_ready_to_aes, ack_ready_to_sha, ack_ready_to_mem} = 4'b1000; ack_valid_n = 1'b0; winner_source_id = 2'b11; end - else if (ack_ready_to_aes == 1'b1) begin + else if (ack_valid_from_aes == 1'b1) begin //AES module is asserting ack {ack_ready_to_ctrl, ack_ready_to_aes, ack_ready_to_sha, ack_ready_to_mem} = 4'b0100; ack_valid_n = 1'b0; winner_source_id = 2'b10; end - else if (ack_ready_to_sha == 1'b1) begin + else if (ack_valid_from_sha == 1'b1) begin //SHA module is asserting ack {ack_ready_to_ctrl, ack_ready_to_aes, ack_ready_to_sha, ack_ready_to_mem} = 4'b0010; ack_valid_n = 1'b0; winner_source_id = 2'b01; end - else if (ack_ready_to_mem == 1'b1) begin + else if (ack_valid_from_mem == 1'b1) begin //MEM module is asserting ack {ack_ready_to_ctrl, ack_ready_to_aes, ack_ready_to_sha, ack_ready_to_mem} = 4'b0001; ack_valid_n = 1'b0; From c044e168ec24d06462c8e3fef9aec534bba4fced Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Sat, 25 Apr 2026 14:47:10 +0800 Subject: [PATCH 24/32] maybe works --- src/ack_bus_module_interface.v | 2 +- src/data_bus_ctrl.v | 50 ++++---- src/data_bus_module_interface.v | 33 +++-- src/global_arbiter.v | 219 ++++++++++++++++++++++++++++++++ 4 files changed, 268 insertions(+), 36 deletions(-) create mode 100644 src/global_arbiter.v diff --git a/src/ack_bus_module_interface.v b/src/ack_bus_module_interface.v index 6a42094..34858b5 100644 --- a/src/ack_bus_module_interface.v +++ b/src/ack_bus_module_interface.v @@ -30,4 +30,4 @@ How to use: ACK Bus: The Ack bus receive the signals and -*/ +*/ \ No newline at end of file diff --git a/src/data_bus_ctrl.v b/src/data_bus_ctrl.v index 5378597..0ca3e6c 100644 --- a/src/data_bus_ctrl.v +++ b/src/data_bus_ctrl.v @@ -1,5 +1,4 @@ `default_nettype none -`timescale 1ns/1ps module data_bus_ctrl ( input wire clk, @@ -42,8 +41,6 @@ module data_bus_ctrl ( reg [1:0] n_data_sel; // rd grant reg [3:0] n_rdy_rd_grant, n_dv_rd_grant; - // rdy output - reg n_rdy_to_owner; // state of the bus reg [1:0] state, n_state; // counter if mem include @@ -145,18 +142,19 @@ module data_bus_ctrl ( // id to 1hot decode n_dv_rd_grant = (dest == aes_id) ? aes_1b : (dest == sha_id) ? sha_1b : ctrl_1b; - rdy_to_owner = (dest == aes_id) ? rdy_aes : (dest == sha_id) ? rdy_sha :0;//should never be 0 otherwise control is cooked + n_dest_latch = dest; // remember AES or SHA + rdy_to_owner = 0; //stall for 1 cycle n_state = hash_op_wait_ready; end else if(rd_key_fire || rd_txt_fire || wr_txt_fire) begin // handshake - n_state = rdy_to_owner ? addr : idle; rdy_to_owner = src_rdy & dest_rdy; + n_state = rdy_to_owner ? addr : idle; // let source module see opcode, if not mem only 1byte for handshake n_src_latch = rdy_to_owner ? src : 0; n_dest_latch = rdy_to_owner ? dest : 0; // set src - n_dv_rd_grant = set(src); - n_dv_rd_grant = set(dest); + n_dv_rd_grant = set(n_dv_rd_grant, src); + n_dv_rd_grant = set(n_dv_rd_grant, dest); end else begin // ggs @@ -165,25 +163,31 @@ module data_bus_ctrl ( end // when the opcode is xx xx xx 11 hashing operation, wait for fire (ideally 1 cycle but could more than that if sha/aes is not ready) hash_op_wait_ready: begin - if (data_bus_fire) begin + rdy_to_owner = dest_rdy; //should never be 0 otherwise control is cooked + if (valid_on_bus && dest_rdy) begin n_state = idle; n_rdy_rd_grant = ctrl_1b; + n_dv_rd_grant = ctrl_1b; + + n_dest_latch = 0; //reset latch end end // when src/dest contains mem, count 3 handshake update ownership addr: begin + // only mem needs handshake + rdy_to_owner = rdy_mem; + // count the handshake n_counter = data_bus_fire ? counter + 1: counter; - // when 2 beat handshaked and the third handshake if (counter == 2 && data_bus_fire) begin n_state = module_transmission; n_data_sel = src_latch; - rdy_to_owner = dest_rdy; + // reset counter n_counter = 0; // rd grant reset - n_dv_rd_grant = clr(src); + n_dv_rd_grant = clr(n_dv_rd_grant, src_latch); end end // src module now owns the bus and ownership will be return upon ack handshake on ack bus @@ -195,7 +199,7 @@ module data_bus_ctrl ( if (ack_bus_fire) begin n_data_sel = ctrl_id; rdy_to_owner = 1; - n_dv_rd_grant = clr(dest); + n_dv_rd_grant = clr(n_dv_rd_grant, dest_latch); n_state = idle; n_src_latch = 0; n_dest_latch = 0; @@ -208,30 +212,32 @@ module data_bus_ctrl ( end // set decode based on id function [3:0] set; + input [3:0] grant; input [1:0] id; begin - set = dv_rd_grant; + set = grant; case (id) - mem_id: set = set | mem_1b; + mem_id: set = set | mem_1b; ctrl_id: set = set | ctrl_1b; - aes_id: set = set | aes_1b; - sha_id: set = set | sha_1b; + aes_id: set = set | aes_1b; + sha_id: set = set | sha_1b; default: ; endcase end endfunction //clr decode based on id function [3:0] clr; + input [3:0] grant; input [1:0] id; begin - clr = dv_rd_grant; + clr = grant; case (id) - mem_id: clr = clr & (~mem_1b); + mem_id: clr = clr & (~mem_1b); ctrl_id: clr = clr & (~ctrl_1b); - aes_id: clr = clr & (~aes_1b); - sha_id: clr = clr & (~sha_1b); + aes_id: clr = clr & (~aes_1b); + sha_id: clr = clr & (~sha_1b); default: ; endcase - end + end endfunction -endmodule +endmodule \ No newline at end of file diff --git a/src/data_bus_module_interface.v b/src/data_bus_module_interface.v index 57cea80..9fb5b67 100644 --- a/src/data_bus_module_interface.v +++ b/src/data_bus_module_interface.v @@ -1,26 +1,33 @@ module data_bus_module_interface ( // input from global arbiter - input rd_grant, - input [9:0] data_in, // [9]:ready, [8]:valid, [7:0]:data + input wire rdy_rd_grant, + input wire dv_rd_grant, - // output to the global arbiter - output reg [9:0] data_out, + // global bus into this local interface + input wire [9:0] data_in, // [9]:ready, [8]:valid, [7:0]:data - // input from the module (e.g. from SHA, AES) - input [9:0] data_from_module, + // local module drives this into arbiter + input wire [9:0] data_from_module, - // output to the module - output reg [9:0] data_to_module + // this interface drives into global arbiter + output reg [9:0] data_out, + + // this interface drives into module + output reg [9:0] data_to_module ); always @(*) begin + // module's outgoing data/valid/ready always forwarded to global side + data_out = data_from_module; - // if rd_grant is high, pass the data_in to the module - if (rd_grant) data_to_module = data_in; - // if rd_grant is low, manually change the valid bit of the data to 0 - else data_to_module = {data_in[9], 1'b0, data_in[7:0]}; + // ready bit is controlled by ready-read grant + data_to_module[9] = rdy_rd_grant ? data_in[9] : 1'b0; - data_out = data_from_module; + // valid bit is controlled by data/valid-read grant + data_to_module[8] = dv_rd_grant ? data_in[8] : 1'b0; + + // data can be passed through or zeroed; valid=0 means ignore it anyway + data_to_module[7:0] = data_in[7:0]; end endmodule \ No newline at end of file diff --git a/src/global_arbiter.v b/src/global_arbiter.v new file mode 100644 index 0000000..ea3a75a --- /dev/null +++ b/src/global_arbiter.v @@ -0,0 +1,219 @@ +`default_nettype none + +module global_arbiter ( + input wire clk, + input wire rst_n, + + // mem + + // mem -> data bus + input wire [7:0] data_in_mem, + input wire valid_in_mem, + output wire ready_out_mem, + + // data bus -> mem + output wire [7:0] data_out_mem, + output wire valid_out_mem, + input wire ready_in_mem, + + // read grants to mem local data bus interface + output wire rdy_rd_grant_mem, + output wire dv_rd_grant_mem, + + // mem -> ack bus + input wire [1:0] ack_id_in_mem, + input wire ack_valid_in_mem, + output wire ack_ready_out_mem, + + // aes + + // aes -> data bus + input wire [7:0] data_in_aes, + input wire valid_in_aes, + output wire ready_out_aes, + + // data bus -> aes + output wire [7:0] data_out_aes, + output wire valid_out_aes, + input wire ready_in_aes, + + // read grants to aes local data bus interface + output wire rdy_rd_grant_aes, + output wire dv_rd_grant_aes, + + // aes -> ack bus + input wire [1:0] ack_id_in_aes, + input wire ack_valid_in_aes, + output wire ack_ready_out_aes, + + // sha + + // sha -> data bus + input wire [7:0] data_in_sha, + input wire valid_in_sha, + output wire ready_out_sha, + + // data bus -> sha + output wire [7:0] data_out_sha, + output wire valid_out_sha, + input wire ready_in_sha, + + // read grants to sha local data bus interface + output wire rdy_rd_grant_sha, + output wire dv_rd_grant_sha, + + // sha -> ack bus + input wire [1:0] ack_id_in_sha, + input wire ack_valid_in_sha, + output wire ack_ready_out_sha, + + // ctrl + + // ctrl -> data bus + // ctrl owns the bus by default and sends opcode/address bytes + input wire [7:0] data_in_ctrl, + input wire valid_in_ctrl, + output wire ready_out_ctrl, + + // read grant to ctrl local data bus interface + // ctrl needs to see ready, but does not need data/valid from data bus + output wire rdy_rd_grant_ctrl, + + // ctrl -> ack bus + input wire [1:0] ack_id_in_ctrl, + input wire ack_valid_in_ctrl, + output wire ack_ready_out_ctrl +); + + // local IDs + // bit mapping: + // mem = 00 -> bit 0 + // sha = 01 -> bit 1 + // aes = 10 -> bit 2 + // ctrl = 11 -> bit 3 + + localparam [1:0] MEM_ID = 2'b00; + localparam [1:0] SHA_ID = 2'b01; + localparam [1:0] AES_ID = 2'b10; + localparam [1:0] CTRL_ID = 2'b11; + + + // internal data bus wires + + wire [7:0] data_on_bus; + wire valid_on_bus; + wire rdy_to_owner; + wire [1:0] data_sel; + + wire [3:0] rdy_rd_grant; + wire [3:0] dv_rd_grant; + + + // internal ack bus wires + // ack arbiter outputs active-low valid, data_bus_ctrl wants active-high valid + + wire ack_valid_n; + wire valid_on_ack; + wire ready_on_ack; + wire [1:0] id_on_ack; + + assign valid_on_ack = ~ack_valid_n; + assign ready_on_ack = 1'b1; // ack bus is always ready in this version + assign id_on_ack = winner_source_id; + + wire [1:0] winner_source_id; + + // data bus owner mux + // data_sel chooses who is currently driving data_on_bus/valid_on_bus + + assign data_on_bus = (data_sel == MEM_ID) ? data_in_mem : (data_sel == SHA_ID) ? data_in_sha : (data_sel == AES_ID) ? data_in_aes : + (data_sel == CTRL_ID) ? data_in_ctrl : 8'h00; + + assign valid_on_bus = (data_sel == MEM_ID) ? valid_in_mem : (data_sel == SHA_ID) ? valid_in_sha : (data_sel == AES_ID) ? valid_in_aes : + (data_sel == CTRL_ID) ? valid_in_ctrl :1'b0; + + // data bus outputs to modules + // data is broadcast, valid is gated by dv_rd_grant + + assign data_out_mem = data_on_bus; + assign data_out_sha = data_on_bus; + assign data_out_aes = data_on_bus; + + assign valid_out_mem = dv_rd_grant[0] ? valid_on_bus : 1'b0; + assign valid_out_sha = dv_rd_grant[1] ? valid_on_bus : 1'b0; + assign valid_out_aes = dv_rd_grant[2] ? valid_on_bus : 1'b0; + + // ctrl does not receive data/valid from data bus, so no data_out_ctrl/valid_out_ctrl + + // ready outputs to modules + // rdy_to_owner is broadcast only to whoever has ready-read grant + + assign ready_out_mem = rdy_rd_grant[0] ? rdy_to_owner : 1'b0; + assign ready_out_sha = rdy_rd_grant[1] ? rdy_to_owner : 1'b0; + assign ready_out_aes = rdy_rd_grant[2] ? rdy_to_owner : 1'b0; + assign ready_out_ctrl = rdy_rd_grant[3] ? rdy_to_owner : 1'b0; + + // expose grant bits + + assign rdy_rd_grant_mem = rdy_rd_grant[0]; + assign rdy_rd_grant_sha = rdy_rd_grant[1]; + assign rdy_rd_grant_aes = rdy_rd_grant[2]; + assign rdy_rd_grant_ctrl = rdy_rd_grant[3]; + + assign dv_rd_grant_mem = dv_rd_grant[0]; + assign dv_rd_grant_sha = dv_rd_grant[1]; + assign dv_rd_grant_aes = dv_rd_grant[2]; + + // data bus controller + // controls data_sel, read grants, and ready-to-current-owner + + data_bus_ctrl u_data_bus_ctrl ( + .clk (clk), + .rst_n (rst_n), + + // current data bus + .data_on_bus (data_on_bus), + .valid_on_bus (valid_on_bus), + + // ready from destination modules + .rdy_mem (ready_in_mem), + .rdy_aes (ready_in_aes), + .rdy_sha (ready_in_sha), + + // ack bus handshake + .id_on_ack (id_on_ack), + .ready_on_ack (ready_on_ack), + .valid_on_ack (valid_on_ack), + + // grants and bus owner select + .rdy_rd_grant (rdy_rd_grant), + .dv_rd_grant (dv_rd_grant), + .data_sel (data_sel), + + // ready back to current owner + .rdy_to_owner (rdy_to_owner) + ); + + + // ack bus arbiter + // chooses one ack source and sends winner ID to data_bus_ctrl + + ack_bus_arbiter u_ack_bus_arbiter ( + // ack valid requests from modules + .ack_valid_from_ctrl (ack_valid_in_ctrl), + .ack_valid_from_aes (ack_valid_in_aes), + .ack_valid_from_sha (ack_valid_in_sha), + .ack_valid_from_mem (ack_valid_in_mem), + + // ready back to winning module + .ack_ready_to_ctrl (ack_ready_out_ctrl), + .ack_ready_to_aes (ack_ready_out_aes), + .ack_ready_to_sha (ack_ready_out_sha), + .ack_ready_to_mem (ack_ready_out_mem), + + // shared ack bus result + .ack_valid_n (ack_valid_n), + .winner_source_id (winner_source_id) + ); + +endmodule \ No newline at end of file From b1d262812188403d0ef36e5db3c4fae6b63f7ed7 Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Sat, 25 Apr 2026 15:00:55 +0800 Subject: [PATCH 25/32] add ready read grant to src --- src/data_bus_ctrl.v | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/data_bus_ctrl.v b/src/data_bus_ctrl.v index 0ca3e6c..ab7bbfa 100644 --- a/src/data_bus_ctrl.v +++ b/src/data_bus_ctrl.v @@ -183,7 +183,8 @@ module data_bus_ctrl ( if (counter == 2 && data_bus_fire) begin n_state = module_transmission; n_data_sel = src_latch; - + // set ready read grant to src module + n_rdy_rd_grant = set(4'b0000, src_latch); // reset counter n_counter = 0; // rd grant reset From f37b54e859c394c0157ea5248d22363ed7b46ef9 Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Sat, 25 Apr 2026 15:13:07 +0800 Subject: [PATCH 26/32] Update project.v --- src/project.v | 200 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 190 insertions(+), 10 deletions(-) diff --git a/src/project.v b/src/project.v index cd6f740..5c45a28 100644 --- a/src/project.v +++ b/src/project.v @@ -10,18 +10,198 @@ module tt_um_example ( output wire [7:0] uo_out, // Dedicated outputs input wire [7:0] uio_in, // IOs: Input path output wire [7:0] uio_out, // IOs: Output path - output wire [7:0] uio_oe, // IOs: Enable path (active high: 0=input, 1=output) - input wire ena, // always 1 when the design is powered, so you can ignore it - input wire clk, // clock - input wire rst_n // reset_n - low to reset + output wire [7:0] uio_oe, // IOs: Enable path + input wire ena, + input wire clk, + input wire rst_n ); + // Wired by ChatGPT too lazy to wire + // ============================================================ + // TinyTapeout pin mapping for quick smoke test + // ============================================================ - // All output pins must be assigned. If not used, assign to 0. - assign uo_out = ui_in + uio_in; // Example: ou_out is the sum of ui_in and uio_in - assign uio_out = 0; - assign uio_oe = 0; + // ui_in[7:0] is reused as the byte driven by ctrl/mem. + // During opcode/address phase, ctrl owns bus. + // During mem transmission phase, mem owns bus. + wire [7:0] test_data_byte; + assign test_data_byte = ui_in; - // List all unused inputs to prevent warnings - wire _unused = &{ena, clk, rst_n, 1'b0}; + // uio_in controls valid/ready/ack test signals + wire valid_in_ctrl; + wire valid_in_mem; + wire ready_in_mem; + wire ready_in_aes; + wire ready_in_sha; + wire ack_valid_in_mem; + wire ack_valid_in_aes; + wire ack_valid_in_sha; + + assign valid_in_ctrl = uio_in[0]; + assign valid_in_mem = uio_in[1]; + assign ready_in_mem = uio_in[2]; + assign ready_in_aes = uio_in[3]; + assign ready_in_sha = uio_in[4]; + assign ack_valid_in_mem = uio_in[5]; + assign ack_valid_in_aes = uio_in[6]; + assign ack_valid_in_sha = uio_in[7]; + + // ctrl ack unused for now + wire ack_valid_in_ctrl; + assign ack_valid_in_ctrl = 1'b0; + + // uio pins are only inputs in this wrapper + assign uio_oe = 8'b0000_0000; + assign uio_out = 8'b0000_0000; + + + // ============================================================ + // Wires from global arbiter + // ============================================================ + + wire ready_out_mem; + wire ready_out_aes; + wire ready_out_sha; + wire ready_out_ctrl; + + wire [7:0] data_out_mem; + wire [7:0] data_out_aes; + wire [7:0] data_out_sha; + + wire valid_out_mem; + wire valid_out_aes; + wire valid_out_sha; + + wire rdy_rd_grant_mem; + wire rdy_rd_grant_aes; + wire rdy_rd_grant_sha; + wire rdy_rd_grant_ctrl; + + wire dv_rd_grant_mem; + wire dv_rd_grant_aes; + wire dv_rd_grant_sha; + + wire ack_ready_out_mem; + wire ack_ready_out_aes; + wire ack_ready_out_sha; + wire ack_ready_out_ctrl; + + + // ============================================================ + // Debug outputs to TinyTapeout pins + // ============================================================ + + assign uo_out[0] = ready_out_ctrl; + assign uo_out[1] = ready_out_mem; + assign uo_out[2] = ready_out_aes; + assign uo_out[3] = ready_out_sha; + assign uo_out[4] = dv_rd_grant_mem; + assign uo_out[5] = dv_rd_grant_aes; + assign uo_out[6] = dv_rd_grant_sha; + assign uo_out[7] = ack_ready_out_mem; + + + // ============================================================ + // Your actual arbiter/interconnect + // ============================================================ + + global_arbiter u_global_arbiter ( + .clk (clk), + .rst_n (rst_n), + + // ======================================================== + // mem + // ======================================================== + + // mem -> data bus + .data_in_mem (test_data_byte), + .valid_in_mem (valid_in_mem), + .ready_out_mem (ready_out_mem), + + // data bus -> mem + .data_out_mem (data_out_mem), + .valid_out_mem (valid_out_mem), + .ready_in_mem (ready_in_mem), + + // grants + .rdy_rd_grant_mem (rdy_rd_grant_mem), + .dv_rd_grant_mem (dv_rd_grant_mem), + + // mem -> ack bus + .ack_id_in_mem (2'b00), + .ack_valid_in_mem (ack_valid_in_mem), + .ack_ready_out_mem(ack_ready_out_mem), + + + // ======================================================== + // aes + // ======================================================== + + // aes -> data bus + // not driving AES data in this lazy smoke test + .data_in_aes (8'h00), + .valid_in_aes (1'b0), + .ready_out_aes (ready_out_aes), + + // data bus -> aes + .data_out_aes (data_out_aes), + .valid_out_aes (valid_out_aes), + .ready_in_aes (ready_in_aes), + + // grants + .rdy_rd_grant_aes (rdy_rd_grant_aes), + .dv_rd_grant_aes (dv_rd_grant_aes), + + // aes -> ack bus + .ack_id_in_aes (2'b10), + .ack_valid_in_aes (ack_valid_in_aes), + .ack_ready_out_aes(ack_ready_out_aes), + + + // ======================================================== + // sha + // ======================================================== + + // sha -> data bus + // not driving SHA data in this lazy smoke test + .data_in_sha (8'h00), + .valid_in_sha (1'b0), + .ready_out_sha (ready_out_sha), + + // data bus -> sha + .data_out_sha (data_out_sha), + .valid_out_sha (valid_out_sha), + .ready_in_sha (ready_in_sha), + + // grants + .rdy_rd_grant_sha (rdy_rd_grant_sha), + .dv_rd_grant_sha (dv_rd_grant_sha), + + // sha -> ack bus + .ack_id_in_sha (2'b01), + .ack_valid_in_sha (ack_valid_in_sha), + .ack_ready_out_sha(ack_ready_out_sha), + + + // ======================================================== + // ctrl + // ======================================================== + + // ctrl -> data bus + .data_in_ctrl (test_data_byte), + .valid_in_ctrl (valid_in_ctrl), + .ready_out_ctrl (ready_out_ctrl), + + // ctrl grant + .rdy_rd_grant_ctrl (rdy_rd_grant_ctrl), + + // ctrl -> ack bus + .ack_id_in_ctrl (2'b11), + .ack_valid_in_ctrl (ack_valid_in_ctrl), + .ack_ready_out_ctrl (ack_ready_out_ctrl) + ); + + // ena is unused; TinyTapeout keeps it high when powered + wire _unused; + assign _unused = ena; endmodule From cddbcf5807772f2cbd408b76871ad01b162a683f Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Sun, 26 Apr 2026 00:43:27 +0800 Subject: [PATCH 27/32] updated tt top --- src/data_bus_ctrl.v | 13 +- src/global_arbiter.v | 212 +++++++++------------------- src/interconnect.v | 329 +++++++++++++++++++++++++++++++++++++++++++ src/project.v | 131 +++++++++++------ 4 files changed, 490 insertions(+), 195 deletions(-) create mode 100644 src/interconnect.v diff --git a/src/data_bus_ctrl.v b/src/data_bus_ctrl.v index ab7bbfa..9046c51 100644 --- a/src/data_bus_ctrl.v +++ b/src/data_bus_ctrl.v @@ -53,8 +53,7 @@ module data_bus_ctrl ( assign dest = data_on_bus[5:4], src = data_on_bus[3:2], opcode = data_on_bus[1:0]; // handshakes on data/ack bus - wire data_bus_fire, ack_bus_fire; - assign data_bus_fire = valid_on_bus && rdy_to_owner; + wire ack_bus_fire; assign ack_bus_fire = valid_on_ack && ready_on_ack && (id_on_ack == src_latch); // opcode format matching @@ -148,10 +147,10 @@ module data_bus_ctrl ( end else if(rd_key_fire || rd_txt_fire || wr_txt_fire) begin // handshake rdy_to_owner = src_rdy & dest_rdy; - n_state = rdy_to_owner ? addr : idle; + n_state = (src_rdy & dest_rdy) ? addr : idle; // let source module see opcode, if not mem only 1byte for handshake - n_src_latch = rdy_to_owner ? src : 0; - n_dest_latch = rdy_to_owner ? dest : 0; + n_src_latch = (src_rdy & dest_rdy) ? src : 0; + n_dest_latch = (src_rdy & dest_rdy) ? dest : 0; // set src n_dv_rd_grant = set(n_dv_rd_grant, src); n_dv_rd_grant = set(n_dv_rd_grant, dest); @@ -178,9 +177,9 @@ module data_bus_ctrl ( rdy_to_owner = rdy_mem; // count the handshake - n_counter = data_bus_fire ? counter + 1: counter; + n_counter = (valid_on_bus && rdy_mem) ? counter + 1: counter; // when 2 beat handshaked and the third handshake - if (counter == 2 && data_bus_fire) begin + if (counter == 2 && valid_on_bus && rdy_mem) begin n_state = module_transmission; n_data_sel = src_latch; // set ready read grant to src module diff --git a/src/global_arbiter.v b/src/global_arbiter.v index ea3a75a..6652dd6 100644 --- a/src/global_arbiter.v +++ b/src/global_arbiter.v @@ -4,85 +4,41 @@ module global_arbiter ( input wire clk, input wire rst_n, - // mem - - // mem -> data bus - input wire [7:0] data_in_mem, - input wire valid_in_mem, - output wire ready_out_mem, - - // data bus -> mem - output wire [7:0] data_out_mem, - output wire valid_out_mem, - input wire ready_in_mem, - - // read grants to mem local data bus interface - output wire rdy_rd_grant_mem, - output wire dv_rd_grant_mem, - - // mem -> ack bus - input wire [1:0] ack_id_in_mem, - input wire ack_valid_in_mem, - output wire ack_ready_out_mem, - - // aes - - // aes -> data bus - input wire [7:0] data_in_aes, - input wire valid_in_aes, - output wire ready_out_aes, - - // data bus -> aes - output wire [7:0] data_out_aes, - output wire valid_out_aes, - input wire ready_in_aes, - - // read grants to aes local data bus interface - output wire rdy_rd_grant_aes, - output wire dv_rd_grant_aes, - - // aes -> ack bus - input wire [1:0] ack_id_in_aes, - input wire ack_valid_in_aes, - output wire ack_ready_out_aes, - - // sha - - // sha -> data bus - input wire [7:0] data_in_sha, - input wire valid_in_sha, - output wire ready_out_sha, - - // data bus -> sha - output wire [7:0] data_out_sha, - output wire valid_out_sha, - input wire ready_in_sha, - - // read grants to sha local data bus interface - output wire rdy_rd_grant_sha, - output wire dv_rd_grant_sha, - - // sha -> ack bus - input wire [1:0] ack_id_in_sha, - input wire ack_valid_in_sha, - output wire ack_ready_out_sha, - - // ctrl - - // ctrl -> data bus - // ctrl owns the bus by default and sends opcode/address bytes - input wire [7:0] data_in_ctrl, - input wire valid_in_ctrl, - output wire ready_out_ctrl, - - // read grant to ctrl local data bus interface - // ctrl needs to see ready, but does not need data/valid from data bus - output wire rdy_rd_grant_ctrl, - - // ctrl -> ack bus - input wire [1:0] ack_id_in_ctrl, - input wire ack_valid_in_ctrl, - output wire ack_ready_out_ctrl + // data local interfaces -> global arbiter + // packed format: + // [9] ready + // [8] valid + // [7:0] data + input wire [9:0] data_from_mem, + input wire [9:0] data_from_sha, + input wire [9:0] data_from_aes, + input wire [9:0] data_from_ctrl, + + // global arbiter -> all data local interfaces + output wire [9:0] data_to_locals, + + // read grants to data local interfaces + // bit mapping: + // [0] mem + // [1] sha + // [2] aes + // [3] ctrl + output wire [3:0] rdy_rd_grant, + output wire [3:0] dv_rd_grant, + + // ack local interfaces -> global arbiter + input wire ack_valid_from_mem, + input wire ack_valid_from_sha, + input wire ack_valid_from_aes, + input wire ack_valid_from_ctrl, + + // global arbiter -> ack local interfaces + output wire ack_ready_to_mem, + output wire ack_ready_to_sha, + output wire ack_ready_to_aes, + output wire ack_ready_to_ctrl, + // ack bus exposed to ctrl + output wire [2:0] ack_bus_to_ctrl ); // local IDs @@ -97,7 +53,6 @@ module global_arbiter ( localparam [1:0] AES_ID = 2'b10; localparam [1:0] CTRL_ID = 2'b11; - // internal data bus wires wire [7:0] data_on_bus; @@ -105,65 +60,31 @@ module global_arbiter ( wire rdy_to_owner; wire [1:0] data_sel; - wire [3:0] rdy_rd_grant; - wire [3:0] dv_rd_grant; + // data_sel chooses who is currently driving the shared data bus + assign data_on_bus = (data_sel == MEM_ID) ? data_from_mem[7:0] : (data_sel == SHA_ID) ? data_from_sha[7:0] : + (data_sel == AES_ID) ? data_from_aes[7:0] : (data_sel == CTRL_ID) ? data_from_ctrl[7:0] : 8'h00; + assign valid_on_bus = (data_sel == MEM_ID) ? data_from_mem[8] : (data_sel == SHA_ID) ? data_from_sha[8] : + (data_sel == AES_ID) ? data_from_aes[8] : (data_sel == CTRL_ID) ? data_from_ctrl[8] : 1'b0; - // internal ack bus wires - // ack arbiter outputs active-low valid, data_bus_ctrl wants active-high valid + // broadcast shared data bus back to all DATA_LOCAL interfaces + assign data_to_locals = {rdy_to_owner, valid_on_bus, data_on_bus}; + // internal ack bus wires + // ack_bus_arbiter uses active-low valid + // data_bus_ctrl expects active-high valid wire ack_valid_n; wire valid_on_ack; wire ready_on_ack; wire [1:0] id_on_ack; + wire [1:0] winner_source_id; assign valid_on_ack = ~ack_valid_n; - assign ready_on_ack = 1'b1; // ack bus is always ready in this version + assign ready_on_ack = 1; // forced to 1 since just need to check ack and winner for databus ctrl assign id_on_ack = winner_source_id; - wire [1:0] winner_source_id; - - // data bus owner mux - // data_sel chooses who is currently driving data_on_bus/valid_on_bus - - assign data_on_bus = (data_sel == MEM_ID) ? data_in_mem : (data_sel == SHA_ID) ? data_in_sha : (data_sel == AES_ID) ? data_in_aes : - (data_sel == CTRL_ID) ? data_in_ctrl : 8'h00; - - assign valid_on_bus = (data_sel == MEM_ID) ? valid_in_mem : (data_sel == SHA_ID) ? valid_in_sha : (data_sel == AES_ID) ? valid_in_aes : - (data_sel == CTRL_ID) ? valid_in_ctrl :1'b0; - - // data bus outputs to modules - // data is broadcast, valid is gated by dv_rd_grant - - assign data_out_mem = data_on_bus; - assign data_out_sha = data_on_bus; - assign data_out_aes = data_on_bus; - - assign valid_out_mem = dv_rd_grant[0] ? valid_on_bus : 1'b0; - assign valid_out_sha = dv_rd_grant[1] ? valid_on_bus : 1'b0; - assign valid_out_aes = dv_rd_grant[2] ? valid_on_bus : 1'b0; - - // ctrl does not receive data/valid from data bus, so no data_out_ctrl/valid_out_ctrl - - // ready outputs to modules - // rdy_to_owner is broadcast only to whoever has ready-read grant - - assign ready_out_mem = rdy_rd_grant[0] ? rdy_to_owner : 1'b0; - assign ready_out_sha = rdy_rd_grant[1] ? rdy_to_owner : 1'b0; - assign ready_out_aes = rdy_rd_grant[2] ? rdy_to_owner : 1'b0; - assign ready_out_ctrl = rdy_rd_grant[3] ? rdy_to_owner : 1'b0; - - // expose grant bits - - assign rdy_rd_grant_mem = rdy_rd_grant[0]; - assign rdy_rd_grant_sha = rdy_rd_grant[1]; - assign rdy_rd_grant_aes = rdy_rd_grant[2]; - assign rdy_rd_grant_ctrl = rdy_rd_grant[3]; - - assign dv_rd_grant_mem = dv_rd_grant[0]; - assign dv_rd_grant_sha = dv_rd_grant[1]; - assign dv_rd_grant_aes = dv_rd_grant[2]; - + // broadcast ack bus to ctrl + assign ack_bus_to_ctrl = {ack_valid_n, winner_source_id}; // data bus controller // controls data_sel, read grants, and ready-to-current-owner @@ -171,14 +92,14 @@ module global_arbiter ( .clk (clk), .rst_n (rst_n), - // current data bus + // current shared data bus .data_on_bus (data_on_bus), .valid_on_bus (valid_on_bus), - // ready from destination modules - .rdy_mem (ready_in_mem), - .rdy_aes (ready_in_aes), - .rdy_sha (ready_in_sha), + // ready from modules through DATA_LOCAL interfaces + .rdy_mem (data_from_mem[9]), + .rdy_aes (data_from_aes[9]), + .rdy_sha (data_from_sha[9]), // ack bus handshake .id_on_ack (id_on_ack), @@ -190,26 +111,25 @@ module global_arbiter ( .dv_rd_grant (dv_rd_grant), .data_sel (data_sel), - // ready back to current owner + // ready back to current data bus owner .rdy_to_owner (rdy_to_owner) ); - // ack bus arbiter // chooses one ack source and sends winner ID to data_bus_ctrl ack_bus_arbiter u_ack_bus_arbiter ( - // ack valid requests from modules - .ack_valid_from_ctrl (ack_valid_in_ctrl), - .ack_valid_from_aes (ack_valid_in_aes), - .ack_valid_from_sha (ack_valid_in_sha), - .ack_valid_from_mem (ack_valid_in_mem), - - // ready back to winning module - .ack_ready_to_ctrl (ack_ready_out_ctrl), - .ack_ready_to_aes (ack_ready_out_aes), - .ack_ready_to_sha (ack_ready_out_sha), - .ack_ready_to_mem (ack_ready_out_mem), + // ack valid requests from ACK_LOCAL interfaces + .ack_valid_from_ctrl (ack_valid_from_ctrl), + .ack_valid_from_aes (ack_valid_from_aes), + .ack_valid_from_sha (ack_valid_from_sha), + .ack_valid_from_mem (ack_valid_from_mem), + + // ready back to ACK_LOCAL interfaces + .ack_ready_to_ctrl (ack_ready_to_ctrl), + .ack_ready_to_aes (ack_ready_to_aes), + .ack_ready_to_sha (ack_ready_to_sha), + .ack_ready_to_mem (ack_ready_to_mem), // shared ack bus result .ack_valid_n (ack_valid_n), diff --git a/src/interconnect.v b/src/interconnect.v new file mode 100644 index 0000000..54e876c --- /dev/null +++ b/src/interconnect.v @@ -0,0 +1,329 @@ +`default_nettype none + +module interconnect_top ( + input wire clk, + input wire rst_n, + + // mem + + // mem -> data bus + input wire [7:0] data_in_mem, + input wire valid_in_mem, + output wire ready_out_mem, + + // data bus -> mem + output wire [7:0] data_out_mem, + output wire valid_out_mem, + input wire ready_in_mem, + + // debug / visible grants to mem DATA_LOCAL + output wire rdy_rd_grant_mem, + output wire dv_rd_grant_mem, + + // mem -> ack bus + input wire [1:0] ack_id_in_mem, + input wire ack_valid_in_mem, + output wire ack_ready_out_mem, + + // shs + + // sha -> data bus + input wire [7:0] data_in_sha, + input wire valid_in_sha, + output wire ready_out_sha, + + // data bus -> sha + output wire [7:0] data_out_sha, + output wire valid_out_sha, + input wire ready_in_sha, + + // debug / visible grants to sha DATA_LOCAL + output wire rdy_rd_grant_sha, + output wire dv_rd_grant_sha, + + // sha -> ack bus + input wire [1:0] ack_id_in_sha, + input wire ack_valid_in_sha, + output wire ack_ready_out_sha, + + // aes + + // aes -> data bus + input wire [7:0] data_in_aes, + input wire valid_in_aes, + output wire ready_out_aes, + + // data bus -> aes + output wire [7:0] data_out_aes, + output wire valid_out_aes, + input wire ready_in_aes, + + // debug / visible grants to aes DATA_LOCAL + output wire rdy_rd_grant_aes, + output wire dv_rd_grant_aes, + + // aes -> ack bus + input wire [1:0] ack_id_in_aes, + input wire ack_valid_in_aes, + output wire ack_ready_out_aes, + + // ctrl + + // ctrl -> data bus + // ctrl owns the bus by default and sends opcode/address bytes + input wire [7:0] data_in_ctrl, + input wire valid_in_ctrl, + output wire ready_out_ctrl, + + // ctrl only needs ready read grant + output wire rdy_rd_grant_ctrl, + + // ctrl -> ack bus + input wire [1:0] ack_id_in_ctrl, + input wire ack_valid_in_ctrl, + output wire ack_ready_out_ctrl, + // ack bus exposed to ctrl + output wire [2:0] ack_out_ctrl +); + + // packed data bus format: + // [9] ready + // [8] valid + // [7:0] data + wire [9:0] data_to_locals; + + wire [9:0] data_from_mem_local; + wire [9:0] data_from_sha_local; + wire [9:0] data_from_aes_local; + wire [9:0] data_from_ctrl_local; + + wire [9:0] data_to_mem_local; + wire [9:0] data_to_sha_local; + wire [9:0] data_to_aes_local; + wire [9:0] data_to_ctrl_local; + + + // grant wires from global arbiter core + // bit mapping: + // [0] mem + // [1] sha + // [2] aes + // [3] ctrl + wire [3:0] rdy_rd_grant; + wire [3:0] dv_rd_grant; + + assign rdy_rd_grant_mem = rdy_rd_grant[0]; + assign rdy_rd_grant_sha = rdy_rd_grant[1]; + assign rdy_rd_grant_aes = rdy_rd_grant[2]; + assign rdy_rd_grant_ctrl = rdy_rd_grant[3]; + + assign dv_rd_grant_mem = dv_rd_grant[0]; + assign dv_rd_grant_sha = dv_rd_grant[1]; + assign dv_rd_grant_aes = dv_rd_grant[2]; + + + // ctrl does not expose dv_rd_grant_ctrl because ctrl does not read data/valid + + // mem DATA_LOCAL + data_bus_module_interface u_mem_data_local ( + .rdy_rd_grant (rdy_rd_grant[0]), + .dv_rd_grant (dv_rd_grant[0]), + + // from GLOBAL_ARB to local interface + .data_in (data_to_locals), + + // from MEM module to local interface + .data_from_module ({ready_in_mem, valid_in_mem, data_in_mem}), + + // from local interface to GLOBAL_ARB + .data_out (data_from_mem_local), + + // from local interface to MEM module + .data_to_module (data_to_mem_local) + ); + + assign ready_out_mem = data_to_mem_local[9]; + assign valid_out_mem = data_to_mem_local[8]; + assign data_out_mem = data_to_mem_local[7:0]; + + // sha DATA_LOCAL + data_bus_module_interface u_sha_data_local ( + .rdy_rd_grant (rdy_rd_grant[1]), + .dv_rd_grant (dv_rd_grant[1]), + + // from GLOBAL_ARB to local interface + .data_in (data_to_locals), + + // from SHA module to local interface + .data_from_module ({ready_in_sha, valid_in_sha, data_in_sha}), + + // from local interface to GLOBAL_ARB + .data_out (data_from_sha_local), + + // from local interface to SHA module + .data_to_module (data_to_sha_local) + ); + + assign ready_out_sha = data_to_sha_local[9]; + assign valid_out_sha = data_to_sha_local[8]; + assign data_out_sha = data_to_sha_local[7:0]; + + // aes DATA_LOCAL + data_bus_module_interface u_aes_data_local ( + .rdy_rd_grant (rdy_rd_grant[2]), + .dv_rd_grant (dv_rd_grant[2]), + + // from GLOBAL_ARB to local interface + .data_in (data_to_locals), + + // from AES module to local interface + .data_from_module ({ready_in_aes, valid_in_aes, data_in_aes}), + + // from local interface to GLOBAL_ARB + .data_out (data_from_aes_local), + + // from local interface to AES module + .data_to_module (data_to_aes_local) + ); + + assign ready_out_aes = data_to_aes_local[9]; + assign valid_out_aes = data_to_aes_local[8]; + assign data_out_aes = data_to_aes_local[7:0]; + + + // ctrl DATA_LOCAL + // ctrl sends opcode/address bytes and only reads ready + data_bus_module_interface u_ctrl_data_local ( + .rdy_rd_grant (rdy_rd_grant[3]), + .dv_rd_grant (dv_rd_grant[3]), + + // from GLOBAL_ARB to local interface + .data_in (data_to_locals), + + // ctrl does not provide a ready input as a receiver + // ctrl only drives valid/data and reads ready_out_ctrl + .data_from_module ({1'b0, valid_in_ctrl, data_in_ctrl}), + + // from local interface to GLOBAL_ARB + .data_out (data_from_ctrl_local), + + // from local interface to CTRL module + .data_to_module (data_to_ctrl_local) + ); + + assign ready_out_ctrl = data_to_ctrl_local[9]; + + + // ack local interface wires + wire ack_valid_from_mem_local; + wire ack_valid_from_sha_local; + wire ack_valid_from_aes_local; + wire ack_valid_from_ctrl_local; + + wire ack_ready_to_mem_local; + wire ack_ready_to_sha_local; + wire ack_ready_to_aes_local; + wire ack_ready_to_ctrl_local; + + wire [1:0] ack_id_from_mem_local; + wire [1:0] ack_id_from_sha_local; + wire [1:0] ack_id_from_aes_local; + wire [1:0] ack_id_from_ctrl_local; + + wire [2:0] ack_bus_to_ctrl; + assign ack_out_ctrl = ack_bus_to_ctrl; + + // mem ACK_LOCAL + ack_bus_module_interface u_mem_ack_local ( + .ACK_READY (ack_ready_to_mem_local), + .ACK_READY_TO_MODULE (ack_ready_out_mem), + + .MODULE_SIDE_ACK_VALID (ack_valid_in_mem), + .ACK_VALID (ack_valid_from_mem_local), + + .MODULE_SIDE_MODULE_SOURCE_ID (ack_id_in_mem), + .MODULE_SOURCE_ID (ack_id_from_mem_local) + ); + + // sha ACK_LOCAL + ack_bus_module_interface u_sha_ack_local ( + .ACK_READY (ack_ready_to_sha_local), + .ACK_READY_TO_MODULE (ack_ready_out_sha), + + .MODULE_SIDE_ACK_VALID (ack_valid_in_sha), + .ACK_VALID (ack_valid_from_sha_local), + + .MODULE_SIDE_MODULE_SOURCE_ID (ack_id_in_sha), + .MODULE_SOURCE_ID (ack_id_from_sha_local) + ); + + + // aes ACK + ack_bus_module_interface u_aes_ack_local ( + .ACK_READY (ack_ready_to_aes_local), + .ACK_READY_TO_MODULE (ack_ready_out_aes), + + .MODULE_SIDE_ACK_VALID (ack_valid_in_aes), + .ACK_VALID (ack_valid_from_aes_local), + + .MODULE_SIDE_MODULE_SOURCE_ID (ack_id_in_aes), + .MODULE_SOURCE_ID (ack_id_from_aes_local) + ); + + + // ctrl ACK + ack_bus_module_interface u_ctrl_ack_local ( + .ACK_READY (ack_ready_to_ctrl_local), + .ACK_READY_TO_MODULE (ack_ready_out_ctrl), + + .MODULE_SIDE_ACK_VALID (ack_valid_in_ctrl), + .ACK_VALID (ack_valid_from_ctrl_local), + + .MODULE_SIDE_MODULE_SOURCE_ID (ack_id_in_ctrl), + .MODULE_SOURCE_ID (ack_id_from_ctrl_local) + ); + + // contains data_bus_ctrl + ack_bus_arbiter + global_arbiter u_global_arbiter ( + .clk (clk), + .rst_n (rst_n), + + // DATA_LOCALs -> GLOBAL_ARB + .data_from_mem (data_from_mem_local), + .data_from_sha (data_from_sha_local), + .data_from_aes (data_from_aes_local), + .data_from_ctrl (data_from_ctrl_local), + + // GLOBAL_ARB -> DATA_LOCALs + .data_to_locals (data_to_locals), + + // grants to DATA_LOCALs + .rdy_rd_grant (rdy_rd_grant), + .dv_rd_grant (dv_rd_grant), + + // ACK_LOCALs -> GLOBAL_ARB + .ack_valid_from_mem (ack_valid_from_mem_local), + .ack_valid_from_sha (ack_valid_from_sha_local), + .ack_valid_from_aes (ack_valid_from_aes_local), + .ack_valid_from_ctrl (ack_valid_from_ctrl_local), + + // GLOBAL_ARB -> ACK_LOCALs + .ack_ready_to_mem (ack_ready_to_mem_local), + .ack_ready_to_sha (ack_ready_to_sha_local), + .ack_ready_to_aes (ack_ready_to_aes_local), + .ack_ready_to_ctrl (ack_ready_to_ctrl_local), + + .ack_bus_to_ctrl (ack_bus_to_ctrl) + ); + + + // unused ack source id wires + wire _unused_ack_ids; + assign _unused_ack_ids = ^{ + ack_id_from_mem_local, + ack_id_from_sha_local, + ack_id_from_aes_local, + ack_id_from_ctrl_local + }; + +endmodule \ No newline at end of file diff --git a/src/project.v b/src/project.v index 5c45a28..8cf7bce 100644 --- a/src/project.v +++ b/src/project.v @@ -3,6 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 */ + +// wire by ChatGPT `default_nettype none module tt_um_example ( @@ -15,47 +17,64 @@ module tt_um_example ( input wire clk, input wire rst_n ); - // Wired by ChatGPT too lazy to wire + + // ============================================================ + // TinyTapeout quick smoke-test pin mapping // ============================================================ - // TinyTapeout pin mapping for quick smoke test + // + // ui_in[7:0] = test byte driven by CTRL and MEM + // + // uio_in[0] = valid_in_ctrl + // uio_in[1] = valid_in_mem + // uio_in[2] = ready_in_mem + // uio_in[3] = ready_in_aes + // uio_in[4] = ready_in_sha + // uio_in[5] = ack_valid_in_mem + // uio_in[6] = ack_valid_in_aes + // uio_in[7] = ack_valid_in_sha + // + // uo_out[0] = ready_out_ctrl + // uo_out[1] = ready_out_mem + // uo_out[2] = ready_out_aes + // uo_out[3] = ready_out_sha + // uo_out[4] = dv_rd_grant_mem + // uo_out[5] = dv_rd_grant_aes + // uo_out[6] = dv_rd_grant_sha + // uo_out[7] = ack_ready_out_mem // ============================================================ - // ui_in[7:0] is reused as the byte driven by ctrl/mem. - // During opcode/address phase, ctrl owns bus. - // During mem transmission phase, mem owns bus. wire [7:0] test_data_byte; assign test_data_byte = ui_in; - // uio_in controls valid/ready/ack test signals wire valid_in_ctrl; wire valid_in_mem; + wire ready_in_mem; wire ready_in_aes; wire ready_in_sha; + wire ack_valid_in_mem; wire ack_valid_in_aes; wire ack_valid_in_sha; - assign valid_in_ctrl = uio_in[0]; - assign valid_in_mem = uio_in[1]; - assign ready_in_mem = uio_in[2]; - assign ready_in_aes = uio_in[3]; - assign ready_in_sha = uio_in[4]; + assign valid_in_ctrl = uio_in[0]; + assign valid_in_mem = uio_in[1]; + + assign ready_in_mem = uio_in[2]; + assign ready_in_aes = uio_in[3]; + assign ready_in_sha = uio_in[4]; + assign ack_valid_in_mem = uio_in[5]; assign ack_valid_in_aes = uio_in[6]; assign ack_valid_in_sha = uio_in[7]; - // ctrl ack unused for now - wire ack_valid_in_ctrl; - assign ack_valid_in_ctrl = 1'b0; - - // uio pins are only inputs in this wrapper + // uio pins are inputs only for this smoke-test wrapper assign uio_oe = 8'b0000_0000; assign uio_out = 8'b0000_0000; // ============================================================ - // Wires from global arbiter + // Wires from interconnect // ============================================================ wire ready_out_mem; @@ -85,31 +104,34 @@ module tt_um_example ( wire ack_ready_out_sha; wire ack_ready_out_ctrl; + wire[2:0] ack_bus_out_ctrl; // ============================================================ - // Debug outputs to TinyTapeout pins + // Debug outputs // ============================================================ assign uo_out[0] = ready_out_ctrl; assign uo_out[1] = ready_out_mem; assign uo_out[2] = ready_out_aes; assign uo_out[3] = ready_out_sha; + assign uo_out[4] = dv_rd_grant_mem; assign uo_out[5] = dv_rd_grant_aes; assign uo_out[6] = dv_rd_grant_sha; + assign uo_out[7] = ack_ready_out_mem; // ============================================================ - // Your actual arbiter/interconnect + // Interconnect // ============================================================ - global_arbiter u_global_arbiter ( + interconnect_top u_interconnect ( .clk (clk), .rst_n (rst_n), // ======================================================== - // mem + // MEM // ======================================================== // mem -> data bus @@ -127,17 +149,17 @@ module tt_um_example ( .dv_rd_grant_mem (dv_rd_grant_mem), // mem -> ack bus - .ack_id_in_mem (2'b00), - .ack_valid_in_mem (ack_valid_in_mem), - .ack_ready_out_mem(ack_ready_out_mem), + .ack_id_in_mem (2'b00), + .ack_valid_in_mem (ack_valid_in_mem), + .ack_ready_out_mem (ack_ready_out_mem), // ======================================================== - // aes + // AES // ======================================================== // aes -> data bus - // not driving AES data in this lazy smoke test + // AES does not drive data in this lazy smoke test .data_in_aes (8'h00), .valid_in_aes (1'b0), .ready_out_aes (ready_out_aes), @@ -152,17 +174,17 @@ module tt_um_example ( .dv_rd_grant_aes (dv_rd_grant_aes), // aes -> ack bus - .ack_id_in_aes (2'b10), - .ack_valid_in_aes (ack_valid_in_aes), - .ack_ready_out_aes(ack_ready_out_aes), + .ack_id_in_aes (2'b10), + .ack_valid_in_aes (ack_valid_in_aes), + .ack_ready_out_aes (ack_ready_out_aes), // ======================================================== - // sha + // SHA // ======================================================== // sha -> data bus - // not driving SHA data in this lazy smoke test + // SHA does not drive data in this lazy smoke test .data_in_sha (8'h00), .valid_in_sha (1'b0), .ready_out_sha (ready_out_sha), @@ -177,13 +199,13 @@ module tt_um_example ( .dv_rd_grant_sha (dv_rd_grant_sha), // sha -> ack bus - .ack_id_in_sha (2'b01), - .ack_valid_in_sha (ack_valid_in_sha), - .ack_ready_out_sha(ack_ready_out_sha), + .ack_id_in_sha (2'b01), + .ack_valid_in_sha (ack_valid_in_sha), + .ack_ready_out_sha (ack_ready_out_sha), // ======================================================== - // ctrl + // CTRL // ======================================================== // ctrl -> data bus @@ -191,17 +213,42 @@ module tt_um_example ( .valid_in_ctrl (valid_in_ctrl), .ready_out_ctrl (ready_out_ctrl), - // ctrl grant + // ctrl ready-read grant .rdy_rd_grant_ctrl (rdy_rd_grant_ctrl), - // ctrl -> ack bus + // ctrl does not write ack in this smoke test .ack_id_in_ctrl (2'b11), - .ack_valid_in_ctrl (ack_valid_in_ctrl), - .ack_ready_out_ctrl (ack_ready_out_ctrl) + .ack_valid_in_ctrl (1'b0), + .ack_ready_out_ctrl (ack_ready_out_ctrl), + + .ack_out_ctrl(ack_bus_out_ctrl) ); - // ena is unused; TinyTapeout keeps it high when powered + + // ============================================================ + // Unused signals + // ============================================================ + wire _unused; - assign _unused = ena; + assign _unused = ^{ + ena, + + data_out_mem, + data_out_aes, + data_out_sha, + + valid_out_mem, + valid_out_aes, + valid_out_sha, + + rdy_rd_grant_mem, + rdy_rd_grant_aes, + rdy_rd_grant_sha, + rdy_rd_grant_ctrl, + + ack_ready_out_aes, + ack_ready_out_sha, + ack_ready_out_ctrl + }; -endmodule +endmodule \ No newline at end of file From 3cbe8dce15a464083fec003c16fa7b86c7e2902a Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Sun, 26 Apr 2026 00:44:16 +0800 Subject: [PATCH 28/32] tb --- test/test.py | 540 +++++++++++++++++++++------------------------------ 1 file changed, 222 insertions(+), 318 deletions(-) diff --git a/test/test.py b/test/test.py index bd178ba..8c3d7d9 100644 --- a/test/test.py +++ b/test/test.py @@ -1,344 +1,248 @@ -# SPDX-FileCopyrightText: © 2024 Tiny Tapeout -# SPDX-License-Identifier: Apache-2.0 - import cocotb from cocotb.clock import Clock -from cocotb.triggers import ClockCycles, RisingEdge - -# - -#custom control module - -async def set_ready(dut, module): - if(module == 0b00): - dut.mem_ready.value = 1 - elif(module == 0b01): - dut.sha_ready.value = 1 - elif(module == 0b10): - dut.aes_ready.value = 1 - else: - dut.ctrl_ready.value = 1 -async def control_module(dut, dest, src): - # a very dummy version of this module - # basically an output of 1 or drive data_on_bus as 1 - while(True): - await RisingEdge(dut.clk) - if(dut.valid_on_bus.value == True and dut.rdy_dest.value == True): - # ready to receive opcode - value = 0 - #wait for 3 cycles to receive opcode - for i in range(2): - value = dut.data_on_bus.value - value << 3 - await RisingEdge(dut.clk) - #wait for 2 more rising edge to skip the beats - for i in range(2): - await RisingEdge(dut.clk) - dut.dv_sel.value = src - dut.rdy_sel.value = dest - set_ready(dest) - set_ready(src) - return value - - - -@cocotb.test() -async def test_project(dut): - dut._log.info("Start") - - # Set the clock period to 10 us (100 KHz) - clock = Clock(dut.clk, 10, units="us") - cocotb.start_soon(clock.start()) - - # Reset - dut._log.info("Reset") - dut.ena.value = 1 - dut.ui_in.value = 0 - dut.uio_in.value = 0 - dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10) - dut.rst_n.value = 1 +from cocotb.triggers import ClockCycles, Timer, ReadOnly, RisingEdge, FallingEdge - dut._log.info("Test project behavior") +# uio_in bit mapping +VALID_CTRL = 1 << 0 +VALID_MEM = 1 << 1 +READY_MEM = 1 << 2 +READY_AES = 1 << 3 +READY_SHA = 1 << 4 +ACK_MEM = 1 << 5 +ACK_AES = 1 << 6 +ACK_SHA = 1 << 7 - # Set the input values you want to test - dut.ui_in.value = 20 - dut.uio_in.value = 30 +# IDs +MEM = 0b00 +SHA = 0b01 +AES = 0b10 +CTRL = 0b11 + +# opcodes +OP_RD_KEY = 0b00 +OP_RD_TXT = 0b01 +OP_WR_TXT = 0b10 +OP_HASH = 0b11 + + +def enc_opcode(dest, src, op): + return ((dest & 0b11) << 4) | ((src & 0b11) << 2) | (op & 0b11) - # Wait for one clock cycle to see the output values - await ClockCycles(dut.clk, 1) - # The following assersion is just an example of how to check the output values. - # Change it to match the actual expected output of your module: - assert dut.uo_out.value == 50 +def get_bit(sig, idx): + return (int(sig.value) >> idx) & 1 - # Keep testing the module by changing the input values, waiting for - # one or more clock cycles, and asserting the expected output values. +async def settle(): + await Timer(1, "ns") + await ReadOnly() -#test for the ready signals -# stuff to change: -# 1. reference the bus owner dv_sel -# 2. check the ready signal on the module to be ready (1) -# 3. send 4 beat transactions to switch ownership -# 4. check ready -@cocotb.test() -async def ready_test(dut): - assert True - dut._log.info("Reset") + +async def reset_dut(dut): dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10) + dut.ui_in.value = 0 + dut.uio_in.value = 0 + + await ClockCycles(dut.clk, 5) + dut.rst_n.value = 1 - dut._log.info("Testing Ready Signals") - - #initially, set all ready values to 0, this means that all the values are not ready - dut.mem_ready.value = 0 - dut.sha_ready.value = 0 - dut.aes_ready.value = 0 - dut.ctrl_ready.value = 0 - dut._log.info("All infos not set to ready") - #wait for rising edge and check if the bus is not ready + await ClockCycles(dut.clk, 2) + # IMPORTANT: do not call settle() here + # because settle() ends in ReadOnly phase + + +@cocotb.test(timeout_time=100, timeout_unit="us") +async def interconnect_smoke_test(dut): + cocotb.start_soon(Clock(dut.clk, 10, "ns").start()) + + dut._log.info("Reset start") + await reset_dut(dut) + dut._log.info("Reset done") + + # uo_out mapping: + # [0] ready_out_ctrl + # [1] ready_out_mem + # [2] ready_out_aes + # [3] ready_out_sha + # [4] dv_rd_grant_mem + # [5] dv_rd_grant_aes + # [6] dv_rd_grant_sha + # [7] ack_ready_out_mem + + dut._log.info("Check reset: ctrl should be ready") + await settle() + assert get_bit(dut.uo_out, 0) == 1, "After reset, ready_out_ctrl should be 1" + + # leave ReadOnly phase before driving await RisingEdge(dut.clk) - assert dut.bus_ready.value == 0 - dut._log.info("Passed all not ready test") - #now set the mem to be ready - dut.mem_ready.value = 1 - dut._log.info("mem is set to ready") - #wait for rising edge to check + dut._log.info("Test invalid opcode") + + # invalid hash: dest=MEM is invalid for hash + invalid_op = enc_opcode(MEM, MEM, OP_HASH) + + dut.ui_in.value = invalid_op + dut.uio_in.value = VALID_CTRL + await settle() + + assert get_bit(dut.uo_out, 0) == 1, "Invalid opcode should keep ctrl ready high" + assert get_bit(dut.uo_out, 4) == 0, "Invalid opcode should not grant MEM dv" + assert get_bit(dut.uo_out, 5) == 0, "Invalid opcode should not grant AES dv" + assert get_bit(dut.uo_out, 6) == 0, "Invalid opcode should not grant SHA dv" + + # leave ReadOnly phase before driving await RisingEdge(dut.clk) - assert dut.bus_ready.value == 1 - #reset the mem and set the sha back to ready - dut.mem_ready.value = 0 - dut.sha_ready.value = 1 - dut._log.info("sha is set to ready") - #wait for rising edge to check + dut.uio_in.value = 0 + dut.ui_in.value = 0 + await ClockCycles(dut.clk, 2) + + dut._log.info("Test hash opcode to AES") + + # hash to AES: dest=AES, src=MEM/don't-care, op=HASH + hash_aes = enc_opcode(AES, MEM, OP_HASH) + + # AES not ready first; ctrl valid high + dut.ui_in.value = hash_aes + dut.uio_in.value = VALID_CTRL + await settle() + + assert get_bit(dut.uo_out, 0) == 0, "Hash should stall ctrl for grant setup" + + # leave ReadOnly phase before clocking/checking next registered grant await RisingEdge(dut.clk) - assert dut.bus_ready.value == 1 + await settle() - #reset the sha and set the aes back to ready - dut.sha_ready.value = 0 - dut.aes_ready.value = 1 - dut._log.info("aes is set to ready") - #wait for rising edge to check + assert get_bit(dut.uo_out, 5) == 1, "Hash should grant AES dv after stall cycle" + assert get_bit(dut.uo_out, 0) == 0, "Ctrl should stay stalled while AES not ready" + + # leave ReadOnly phase before driving AES ready await RisingEdge(dut.clk) - assert dut.bus_ready.value == 1 - - #set control to ready and aes back - dut.ctrl_ready.value = 1 - dut.aes_ready.value = 0 - dut._log.info("ctrl is set to ready") - #wait for rising edge and check + + # Now AES becomes ready, ctrl should be allowed to handshake + dut.uio_in.value = VALID_CTRL | READY_AES + await settle() + + assert get_bit(dut.uo_out, 0) == 1, "Ctrl ready should rise when AES ready" + + # leave ReadOnly phase and take handshake edge await RisingEdge(dut.clk) - assert dut.bus_ready.value == 1 -#test for bus sending data -@cocotb.test() -async def data_transmission_test(dut): - #reset everything first - dut._log.info("Reset") - dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10) - dut.rst_n.value = 1 - dut._log.info("Testing Ready Signals") - - #we test this module by crafting a destination and crafting a dummy hashed value to send to the module - dut.READY.value = 1 - dut.ctrl_ready.value = 0 - dut.sha_ready.value = 0 - dut.aes_ready.value = 0 - dut.mem_ready.value = 1 - #now we decide that we want to do a wr_res, say we need to make a dummy address - dummy_addr = 0x001234 - #now we craft the fake opcode needed for the command/driving - op_code = 0b10100010 - #crafting the header as per the beats architecture required - dut.header.value = [dummy_addr >> 16 & 0xFF, dummy_addr >> 8 & 0xFF, dummy_addr >> 0 & 0xFF, op_code] - #now we set up a test payload - payload = [0xDE,0xAD,0xBE,0xEF, 0x11,0x22,0x33,0x44] + # ctrl drops valid + dut.uio_in.value = READY_AES + await ClockCycles(dut.clk, 1) + await settle() + + assert get_bit(dut.uo_out, 5) == 0, "AES dv grant should clear after hash handshake" + + dut._log.info("PASS: reset + invalid opcode + hash opcode smoke test") + +@cocotb.test(timeout_time=100, timeout_unit="us") +async def mem_to_aes_smoke_test(dut): + cocotb.start_soon(Clock(dut.clk, 10, "ns").start()) + + dut._log.info("Reset start") + await reset_dut(dut) + dut._log.info("Reset done") + + # uo_out mapping: + # [0] ready_out_ctrl + # [1] ready_out_mem + # [2] ready_out_aes + # [3] ready_out_sha + # [4] dv_rd_grant_mem + # [5] dv_rd_grant_aes + # [6] dv_rd_grant_sha + # [7] ack_ready_out_mem + + await settle() + assert get_bit(dut.uo_out, 0) == 1, "After reset, ctrl should be ready" + + dut._log.info("Test rd_txt MEM -> AES") + + rd_txt_mem_to_aes = enc_opcode(AES, MEM, OP_RD_TXT) # 0x21 + + # Opcode phase + await FallingEdge(dut.clk) + dut.ui_in.value = rd_txt_mem_to_aes + dut.uio_in.value = VALID_CTRL | READY_MEM | READY_AES + + await settle() + assert get_bit(dut.uo_out, 0) == 1, "Opcode phase: ctrl should see ready high" + + # Opcode handshake await RisingEdge(dut.clk) - for beats in dut.header.value: - #send the beats of the data 1 by 1 - dut.ctrl_data = beats - #set the control valid back to true - dut.ctrl_valid.value = 1 - #wait for handshaking signals - while(True): - await RisingEdge(dut.clk) - if(dut.ctrl_ready.value): - break - dut.ctrl_valid.value = 0 - #send payload data in - for data in payload: - dut.aes_data.value = data - dut.aes_valid.value = 1 - while(True): - await RisingEdge(dut.clk) - if(dut.aes_ready.value): - break - dut.aes_ready.value = 0 - - #check whether the header was captured and matches - for load in payload: - await RisingEdge(dut.clk) - if dut.bus_valid.value and dut.bus_ready.value: - assert dut.bus_data.value == load - -#a test for testing the non-participants in the databus driving disconnecting -@cocotb.test() -async def non_participant_test(dut): - #reset everything first - dut._log.info("Reset") - dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10) - dut.rst_n.value = 1 - dut._log.info("Starting non_participant_test") - - # first let's test the WR command which needs the use of mem and the use of aes - # conveniently as it appears to be our last test: - dut._log.info("Testing ") - dut.READY.value = 1 - dut.ctrl_ready.value = 0 - dut.sha_ready.value = 0 - dut.aes_ready.value = 0 - dut.mem_ready.value = 1 - #now we decide that we want to do a wr_res, say we need to make a dummy address - dummy_addr = 0x001234 - #now we craft the fake opcode needed for the command/driving - op_code = 0b10100010 - #crafting the header as per the beats architecture required - dut.header.value = [dummy_addr >> 16 & 0xFF, dummy_addr >> 8 & 0xFF, dummy_addr >> 0 & 0xFF, op_code] - #now we set up a test payload - payload = [0xDE,0xAD,0xBE,0xEF, 0x11,0x22,0x33,0x44] + + # Address byte 0 + await FallingEdge(dut.clk) + dut.ui_in.value = 0xAA + dut.uio_in.value = VALID_CTRL | READY_MEM | READY_AES + + await settle() + assert get_bit(dut.uo_out, 0) == 1, "Addr byte 0: ctrl should be ready" + assert get_bit(dut.uo_out, 4) == 1, "After opcode: MEM dv grant should be high" + assert get_bit(dut.uo_out, 5) == 1, "After opcode: AES dv grant should be high" + + # Address byte 0 handshakes. await RisingEdge(dut.clk) - for beats in dut.header.value: - #send the beats of the data 1 by 1 - dut.ctrl_data = beats - #set the control valid back to true - dut.ctrl_valid.value = 1 - #wait for handshaking signals - while(True): - await RisingEdge(dut.clk) - if(dut.ctrl_ready.value): - break - dut.ctrl_valid.value = 0 - #send payload data in - for data in payload: - dut.aes_data.value = data - dut.aes_valid.value = 1 - while(True): - await RisingEdge(dut.clk) - if(dut.aes_ready.value): - break - dut.aes_ready.value = 0 - - #check whether any other non_participants are participating - for _ in payload: - await RisingEdge(dut.clk) - assert dut.sha_data.value == 0 - assert dut.ctrl_data.value == 0 - - #now test the hashops, this doesn't require actual address - #reset before starting a new test: - dut._log.info("Reset") - dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10) - dut.rst_n.value = 1 - dut._log.info("Testing/Logging for HashOp") - #turn on neccessary ports - dut.mem_ready.value = 1 - dut.aes_ready.value = 1 - #constructt the op code for aes to begin an encoding process - op_code = 0b10100011 - dut.header.value = [dummy_addr >> 16 & 0xFF, dummy_addr >> 8 & 0xFF, dummy_addr >> 0 & 0xFF, op_code] - #now we set up a test payload - payload = [0xDE,0xAD,0xBE,0xEF, 0x11,0x22,0x33,0x44] + # Address byte 1 + await FallingEdge(dut.clk) + dut.ui_in.value = 0xBB + dut.uio_in.value = VALID_CTRL | READY_MEM | READY_AES + + await settle() + assert get_bit(dut.uo_out, 0) == 1, "Addr byte 1: ctrl should be ready" + + # Address byte 1 handshakes. await RisingEdge(dut.clk) - for beats in dut.header.value: - #send the beats of the data 1 by 1 - dut.ctrl_data = beats - #set the control valid back to true - dut.ctrl_valid.value = 1 - #wait for handshaking signals - while(True): - await RisingEdge(dut.clk) - if(dut.ctrl_ready.value): - break - dut.ctrl_valid.value = 0 - #send payload data in - for data in payload: - dut.aes_data.value = data - dut.aes_valid.value = 1 - while(True): - await RisingEdge(dut.clk) - if(dut.aes_ready.value): - break - dut.aes_ready.value = 0 - #check whether any other non_participants are participating - for _ in payload: - await RisingEdge(dut.clk) - assert dut.sha_data.value == 0 - assert dut.ctrl_data.value == 0 - assert dut.memory_data.value == 0 - - -#test to see whether the ownership is transfered during operations -@cocotb.test() -async def ownership_transfer_test(dut): - #first reset the databus - dut._log.info("Reset") - dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10) - dut.rst_n.value = 1 - #upon resetting then we have to send valid 4 beat data from control - #sending an op_code from read_txt, then bus should transfer to memory - #memory and aes should be set to ready and valid for transfer? - dut._log.info("Starting ownership transfer test") - dut.mem_ready.value = 1 - dut.mem_valid.value = 1 - dut.aes_ready.value = 1 - dut.aes_valid.value = 1 - dut.ctrl_ready.value = 1 - dut.ctrl_valid.value = 1 - dummy_addr = 0x001234 - op_code = 0b10100001 - dut.header.value = [dummy_addr >> 16 & 0xFF, dummy_addr >> 8 & 0xFF, dummy_addr >> 0 & 0xFF, op_code] - #now control send 4 beats + # Address byte 2 + await FallingEdge(dut.clk) + dut.ui_in.value = 0xCC + dut.uio_in.value = VALID_CTRL | READY_MEM | READY_AES + + await settle() + assert get_bit(dut.uo_out, 0) == 1, "Addr byte 2: ctrl should be ready" + + # Address byte 2 handshakes. await RisingEdge(dut.clk) - for beats in dut.header.value: - #send the beats of the data 1 by 1 - dut.ctrl_data = beats - #set the control valid back to true - dut.ctrl_valid.value = 1 - #wait for handshaking signals - while(True): - await RisingEdge(dut.clk) - if(dut.ctrl_ready.value): - break - dut.ctrl_valid.value = 0 - #now check the bus_owner, should be control - assert dut.bus_owner.value == 0b00 - -@cocotb.test() -async def owner_release(dut): - #reset everything first - dut._log.info("Reset") - dut.rst_n.value = 0 - await ClockCycles(dut.clk, 10) - dut.rst_n.value = 1 - dut._log.info("Starting non_participant_test") - #assume that memory currently has the ownership of the bus - dut.bus_owner.value = 0b00 - #set ready values, unsure whether neccessary - dut.ctrl_ready.value = 1 - dut.mem_ready.value = 1 - #now the memory has to ack: - dut.ack_ready_to_mem.value = 1 + + # Module transmission phase + await settle() + + assert get_bit(dut.uo_out, 1) == 1, "Module transmission: MEM should see ready" + assert get_bit(dut.uo_out, 4) == 0, "Module transmission: MEM dv grant should be cleared" + assert get_bit(dut.uo_out, 5) == 1, "Module transmission: AES dv grant should stay high" + + dut._log.info("MEM drives data, then sends ack") + + # MEM drives one data byte + await FallingEdge(dut.clk) + dut.ui_in.value = 0x5A + dut.uio_in.value = VALID_MEM | READY_AES + + await settle() + assert get_bit(dut.uo_out, 1) == 1, "MEM transmission: MEM should see ready from AES" + + # MEM asserts ack + await FallingEdge(dut.clk) + dut.ui_in.value = 0x5A + dut.uio_in.value = VALID_MEM | READY_AES | ACK_MEM + + await settle() + assert get_bit(dut.uo_out, 7) == 1, "MEM ack: ack_ready_out_mem should assert" + + # Ack is observed on this rising edge. + await RisingEdge(dut.clk) + + # Drop MEM valid/ack + await FallingEdge(dut.clk) + dut.uio_in.value = READY_AES + dut.ui_in.value = 0 + await RisingEdge(dut.clk) - assert dut.bus_owner.value == 0b11 + await settle() + + assert get_bit(dut.uo_out, 0) == 1, "After MEM ack: ctrl should be ready again" + assert get_bit(dut.uo_out, 5) == 0, "After MEM ack: AES dv grant should clear" -@cocotb.test() -async def stray_ack(dut): - #firstly, reset the file - dut._log.info("reset") \ No newline at end of file + dut._log.info("PASS: rd_txt MEM -> AES smoke test") \ No newline at end of file From 635d6b5f58868553dc987f6b3efe07fd18645e39 Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Sun, 26 Apr 2026 00:46:31 +0800 Subject: [PATCH 29/32] Update info.yaml --- info.yaml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/info.yaml b/info.yaml index d76034f..5e7a6e0 100644 --- a/info.yaml +++ b/info.yaml @@ -1,8 +1,8 @@ # Tiny Tapeout project information project: title: "Interconnect Data Bus" # Project title - author: "" # Your name - discord: "" # Your discord username, for communication and automatically assigning you a Tapeout role (optional) + author: "1" # Your name + discord: "2" # Your discord username, for communication and automatically assigning you a Tapeout role (optional) description: "Trasnfer data between modules" # One line description of what your project does language: "Verilog" # other examples include SystemVerilog, Amaranth, VHDL, etc clock_hz: 0 # Clock frequency in Hz (or 0 if not applicable) @@ -21,6 +21,9 @@ project: - "data_bus_ctrl.v" - "data_bus_module_interface.v" - "ack_bus_arbiter.v" + - "ack_bus_module_interface.v" + - "global_arbiter.v" + - "interconnect.v" # The pinout of your project. Leave unused pins blank. DO NOT delete or add any pins. pinout: @@ -55,4 +58,4 @@ pinout: uio[7]: "" # Do not change! -yaml_version: 6 \ No newline at end of file +yaml_version: 6 From 8d0c5dea3bde80181de01e846a51207c515c215b Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Sun, 26 Apr 2026 00:52:28 +0800 Subject: [PATCH 30/32] Update Makefile --- test/Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index bb64345..5dabca5 100644 --- a/test/Makefile +++ b/test/Makefile @@ -5,7 +5,14 @@ SIM ?= icarus TOPLEVEL_LANG ?= verilog SRC_DIR = $(PWD)/../src -PROJECT_SOURCES = project.v +PROJECT_SOURCES = \ +project.v \ +interconnect.v \ +global_arbiter.v \ +ack_bus_module_interface.v \ +data_bus_ctrl.v \ +ack_bus_module_interface.v \ +ack_bus_arbiter.v ifneq ($(GATES),yes) From d997029efd3f7b953725c0dd8f094fdda3d42d03 Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Sun, 26 Apr 2026 00:53:40 +0800 Subject: [PATCH 31/32] Update info.md --- docs/info.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/info.md b/docs/info.md index ce1f04c..30ea064 100644 --- a/docs/info.md +++ b/docs/info.md @@ -9,12 +9,12 @@ You can also include images in this folder and reference them in the markdown. E ## How it works -Explain how your project works +it does not work ## How to test -Explain how to use your project +by inspection ## External hardware -List external hardware used in your project (e.g. PMOD, LED display, etc), if any +ATP From acd46666fccf9a64fae91d3d0de7666424e6ff2f Mon Sep 17 00:00:00 2001 From: Ryan Chen <95063591+1RyanChen1@users.noreply.github.com> Date: Sun, 26 Apr 2026 00:56:47 +0800 Subject: [PATCH 32/32] typo fixed --- test/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Makefile b/test/Makefile index 5dabca5..cd5a8fc 100644 --- a/test/Makefile +++ b/test/Makefile @@ -11,7 +11,7 @@ interconnect.v \ global_arbiter.v \ ack_bus_module_interface.v \ data_bus_ctrl.v \ -ack_bus_module_interface.v \ +data_bus_module_interface.v \ ack_bus_arbiter.v ifneq ($(GATES),yes)