23 Commits

Author SHA1 Message Date
2e4817fea6 set sysclk to 60Mhz 2026-07-14 22:50:44 +08:00
c4f34426e6 fix: typo 2026-07-14 22:50:34 +08:00
459d08fa65 Update matmul fast-start software image 2026-07-14 20:43:02 +08:00
0d0c6d0376 Optimize matmul DMA with chained 256-beat bursts 2026-07-14 20:40:43 +08:00
f3af271788 Optimize matmul CRC pipeline and expose DMA cycles 2026-07-14 18:21:45 +08:00
7c60da78cb optimize 2026-07-13 07:10:30 +08:00
886ae8ad3f Sync fast SRAM read burst controller 2026-07-06 00:19:25 +08:00
4c0646a514 Optimize asm matmul crc software path 2026-07-06 00:16:23 +08:00
1540087071 Optimize matmul CRC-only path 2026-07-04 16:13:26 +08:00
094157ff05 Outputting LF instead of CRLF ,resulted in a 0.25ms improvement 2026-07-02 01:26:51 +08:00
297b93b828 优化sram的写路径,待验证 2026-07-02 00:36:59 +08:00
ed2876b3a8 Pipeline external SRAM reads 2026-07-02 00:23:57 +08:00
baf3f6f696 Avoid DSP in matmul master path 2026-07-01 23:30:11 +08:00
fd03aaaaa1 Add matmul AXI master path 2026-07-01 23:13:28 +08:00
2b6e29f761 Pipeline matmul bank chaining 2026-07-01 22:41:31 +08:00
ceff12eaf1 Fix CDMA sequencer declaration order 2026-07-01 22:15:31 +08:00
dd8d9c8f5f Add CDMA matmul sequencer 2026-07-01 21:59:57 +08:00
2080a700e9 chore(sdk): update axi_ram.mif and mlkem_test.bin
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-01 21:18:05 +08:00
c7b052b5dd test(mlkem): update test vectors for golden-vector verification
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-01 21:18:00 +08:00
dde6a46b49 fix(asm): add uart_putdec and confreg_time.h to user-sample
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-07-01 21:17:55 +08:00
38f2051f04 fix: typo 2026-07-01 21:03:46 +08:00
d72cda97b9 Fix CDMA channel start timing 2026-07-01 20:34:33 +08:00
09fc1aeb44 Add CDMA endpoint path for matmul transfers 2026-07-01 20:15:55 +08:00
20 changed files with 3592 additions and 12376 deletions

24
.gitattributes vendored Normal file
View File

@@ -0,0 +1,24 @@
* text=auto eol=lf
# Binary artifacts
*.bin -text
*.elf -text
*.o -text
*.a -text
*.so -text
*.dll -text
*.exe -text
# Documents and images
*.pdf -text
*.png -text
*.jpg -text
*.jpeg -text
*.gif -text
*.bmp -text
*.ico -text
# FPGA packaged IP/checkpoints can be binary archives.
*.xcix -text
*.dcp -text
*.bit -text

View File

@@ -113,7 +113,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// FIFO parameter defines // FIFO parameter defines
`define UART_FIFO_WIDTH 8 `define UART_FIFO_WIDTH 8
`define UART_FIFO_DEPTH 16 `define UART_FIFO_DEPTH 32
`define UART_FIFO_POINTER_W 4 `define UART_FIFO_POINTER_W 5
`define UART_FIFO_COUNTER_W 5 `define UART_FIFO_COUNTER_W 6
`define UART_FIFO_REC_WIDTH 11 `define UART_FIFO_REC_WIDTH 11

View File

@@ -20,7 +20,8 @@
module axi2sram_sp_external #( module axi2sram_sp_external #(
parameter AXI_ID_WIDTH = 5, parameter AXI_ID_WIDTH = 5,
parameter AXI_ADDR_WIDTH = 32, parameter AXI_ADDR_WIDTH = 32,
parameter AXI_DATA_WIDTH = 32 parameter AXI_DATA_WIDTH = 32,
parameter FAST_READ_BURST = 1
)( )(
input clk, input clk,
input resetn, input resetn,
@@ -64,6 +65,7 @@ module axi2sram_sp_external #(
output reg req_o, output reg req_o,
output reg we_o, output reg we_o,
output reg [AXI_ADDR_WIDTH-1:0] addr_o, output reg [AXI_ADDR_WIDTH-1:0] addr_o,
output reg bank_o,
output reg [AXI_DATA_WIDTH/8-1:0] be_o, output reg [AXI_DATA_WIDTH/8-1:0] be_o,
output reg [AXI_DATA_WIDTH-1:0] data_o, output reg [AXI_DATA_WIDTH-1:0] data_o,
input [AXI_DATA_WIDTH-1:0] data_i input [AXI_DATA_WIDTH-1:0] data_i
@@ -95,46 +97,39 @@ module axi2sram_sp_external #(
localparam WRITE = 3'h2; localparam WRITE = 3'h2;
localparam SEND_B = 3'h3; localparam SEND_B = 3'h3;
localparam WAIT_WVALID = 3'h4; localparam WAIT_WVALID = 3'h4;
localparam WRITE_NOP = 3'h5;
localparam READ_ADDR = 3'h6; localparam READ_ADDR = 3'h6;
localparam FIXED = 2'b00; localparam FIXED = 2'b00;
localparam INCR = 2'b01; localparam INCR = 2'b01;
localparam WRAP = 2'b10; localparam WRAP = 2'b10;
localparam [AXI_ADDR_WIDTH-1:0] ADDR_INCR =
{{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1} << LOG_NR_BYTES;
reg [AXI_ADDR_WIDTH-1:0] req_addr_d, req_addr_q; reg [AXI_ADDR_WIDTH-1:0] req_addr_d, req_addr_q;
reg [7:0] cnt_d, cnt_q; reg [8:0] cnt_d, cnt_q;
reg [AXI_ADDR_WIDTH-1:0] wrap_mask_d, wrap_mask_q;
reg req_bank_d, req_bank_q;
reg [AXI_DATA_WIDTH-1:0] read_data_q;
reg read_capture;
function automatic [AXI_ADDR_WIDTH-1:0] get_wrap_boundary; wire [AXI_ADDR_WIDTH-1:0] ar_burst_bytes =
input [AXI_ADDR_WIDTH-1:0] unaligned_address; ({{(AXI_ADDR_WIDTH-8){1'b0}}, s_arlen} + {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1}) << LOG_NR_BYTES;
input [7:0] len; wire [AXI_ADDR_WIDTH-1:0] aw_burst_bytes =
begin ({{(AXI_ADDR_WIDTH-8){1'b0}}, s_awlen} + {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1}) << LOG_NR_BYTES;
get_wrap_boundary = 'h0; wire [AXI_ADDR_WIDTH-1:0] ar_wrap_mask = ar_burst_bytes - {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1};
// for wrapping transfers ax_len can only be of size 1, 3, 7 or 15 wire [AXI_ADDR_WIDTH-1:0] aw_wrap_mask = aw_burst_bytes - {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1};
if (len == 4'b1)
get_wrap_boundary[AXI_ADDR_WIDTH-1:1+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-1:1+LOG_NR_BYTES];
else if (len == 4'b11)
get_wrap_boundary[AXI_ADDR_WIDTH-1:2+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-1:2+LOG_NR_BYTES];
else if (len == 4'b111)
get_wrap_boundary[AXI_ADDR_WIDTH-1:3+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-3:2+LOG_NR_BYTES];
else if (len == 4'b1111)
get_wrap_boundary[AXI_ADDR_WIDTH-1:4+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-3:4+LOG_NR_BYTES];
end
endfunction
reg [AXI_ADDR_WIDTH-1:0] aligned_address; reg [AXI_ADDR_WIDTH-1:0] next_addr;
reg [AXI_ADDR_WIDTH-1:0] wrap_boundary; reg [AXI_ADDR_WIDTH-1:0] seq_addr;
reg [AXI_ADDR_WIDTH-1:0] upper_wrap_boundary;
reg [AXI_ADDR_WIDTH-1:0] cons_addr;
always @ (*) begin always @ (*) begin
// address generation seq_addr = req_addr_q + ADDR_INCR;
aligned_address = {ax_req_q_addr[AXI_ADDR_WIDTH-1:LOG_NR_BYTES], {{LOG_NR_BYTES}{1'b0}}}; case (ax_req_q_burst)
wrap_boundary = get_wrap_boundary(ax_req_q_addr, ax_req_q_len); FIXED: next_addr = req_addr_q;
// this will overflow INCR: next_addr = seq_addr;
upper_wrap_boundary = wrap_boundary + ((ax_req_q_len + 1) << LOG_NR_BYTES); WRAP: next_addr = (req_addr_q & ~wrap_mask_q) | (seq_addr & wrap_mask_q);
// calculate consecutive address default: next_addr = seq_addr;
cons_addr = aligned_address + (cnt_q << LOG_NR_BYTES); endcase
// Transaction attributes // Transaction attributes
// default assignments // default assignments
@@ -146,18 +141,23 @@ module axi2sram_sp_external #(
ax_req_d_burst = ax_req_q_burst; ax_req_d_burst = ax_req_q_burst;
req_addr_d = req_addr_q; req_addr_d = req_addr_q;
cnt_d = cnt_q; cnt_d = cnt_q;
wrap_mask_d = wrap_mask_q;
req_bank_d = req_bank_q;
read_capture = 1'b0;
// Memory default assignments // Memory default assignments
data_o = s_wdata; data_o = s_wdata;
be_o = s_wstrb; be_o = s_wstrb;
we_o = 1'b0; we_o = 1'b0;
req_o = 1'b0; req_o = 1'b0;
addr_o = 'h0; addr_o = 'h0;
bank_o = req_bank_q;
// AXI assignments // AXI assignments
// request // request
s_awready = 1'b0; s_awready = 1'b0;
s_arready = 1'b0; s_arready = 1'b0;
// read response channel // read response channel
s_rvalid = 1'b0; s_rvalid = 1'b0;
s_rdata = 'h0;
s_rresp = 'h0; s_rresp = 'h0;
s_rlast = 'h0; s_rlast = 'h0;
s_rid = ax_req_q_id; s_rid = ax_req_q_id;
@@ -183,14 +183,17 @@ module axi2sram_sp_external #(
ax_req_d_len = s_arlen; ax_req_d_len = s_arlen;
ax_req_d_size = s_arsize; ax_req_d_size = s_arsize;
ax_req_d_burst = s_arburst; ax_req_d_burst = s_arburst;
state_d = READ; wrap_mask_d = ar_wrap_mask;
req_bank_d = s_araddr[22];
state_d = READ_ADDR;
// we can request the first address, this saves us time // we can request the first address, this saves us time
req_o = 1'b1; req_o = 1'b1;
addr_o = s_araddr; addr_o = s_araddr;
bank_o = s_araddr[22];
// save the address // save the address
req_addr_d = s_araddr; req_addr_d = s_araddr;
// save the ar_len // save the ar_len
cnt_d = 1; cnt_d = 0;
// ------------ // ------------
// Write // Write
// ------------ // ------------
@@ -204,11 +207,14 @@ module axi2sram_sp_external #(
ax_req_d_len = s_awlen; ax_req_d_len = s_awlen;
ax_req_d_size = s_awsize; ax_req_d_size = s_awsize;
ax_req_d_burst = s_awburst; ax_req_d_burst = s_awburst;
wrap_mask_d = aw_wrap_mask;
req_bank_d = s_awaddr[22];
bank_o = s_awaddr[22];
// we've got our first w_valid so start the write process // we've got our first w_valid so start the write process
if (s_wvalid) begin if (s_wvalid) begin
req_o = 1'b1; req_o = 1'b1;
we_o = 1'b1; we_o = 1'b1;
state_d = (s_wlast) ? SEND_B : WRITE_NOP; state_d = (s_wlast) ? SEND_B : WRITE;
cnt_d = 1; cnt_d = 1;
// we still have to wait for the first w_valid to arrive // we still have to wait for the first w_valid to arrive
end else end else
@@ -230,70 +236,73 @@ module axi2sram_sp_external #(
end end
READ: begin READ: begin
// keep request to memory high
req_o = 1'b1;
addr_o = req_addr_q;
// send the response // send the response
s_rvalid = 1'b1; s_rvalid = 1'b1;
s_rdata = data_i; s_rdata = read_data_q;
s_rid = ax_req_q_id; s_rid = ax_req_q_id;
s_rlast = (cnt_q == ax_req_q_len + 1); s_rlast = (cnt_q == ({1'b0, ax_req_q_len} + 9'd1));
if (FAST_READ_BURST && !s_rlast) begin
req_o = 1'b1;
addr_o = next_addr;
end
// check that the master is ready, the slave must not wait on this // check that the master is ready, the slave must not wait on this
if (s_rready) begin if (s_rready) begin
// we sent the last byte -> go back to idle // we sent the last byte -> go back to idle
if (s_rlast) begin if (s_rlast) begin
state_d = IDLE; if (s_arvalid) begin
// we already got everything // Accept the next burst without an intervening
// IDLE cycle and start its SRAM address phase.
s_arready = 1'b1;
ax_req_d_id = s_arid;
ax_req_d_addr = s_araddr;
ax_req_d_len = s_arlen;
ax_req_d_size = s_arsize;
ax_req_d_burst = s_arburst;
wrap_mask_d = ar_wrap_mask;
req_bank_d = s_araddr[22];
req_o = 1'b1;
addr_o = s_araddr;
bank_o = s_araddr[22];
req_addr_d = s_araddr;
// ARVALID was presented during the preceding
// beat, so the async-SRAM address has a full
// cycle to settle before this capture edge.
read_capture = 1'b1;
cnt_d = 1;
state_d = READ;
end else begin
state_d = IDLE;
end
end end
else begin else begin
state_d = READ_ADDR; if (FAST_READ_BURST) begin
read_capture = 1'b1;
req_addr_d = next_addr;
cnt_d = cnt_q + 1;
state_d = READ;
end else begin
req_addr_d = next_addr;
state_d = READ_ADDR;
end
end end
end end
end end
READ_ADDR: begin READ_ADDR: begin
// keep request to memory high // Fill the read data register after the async-SRAM address has
// been stable for one full sys_clk cycle.
req_o = 1'b1; req_o = 1'b1;
// send the response addr_o = req_addr_q;
s_rvalid = 1'b0; read_capture = 1'b1;
// ----------------------------
// Next address generation
// ----------------------------
// handle the correct burst type
case (ax_req_q_burst)
FIXED, INCR: addr_o = cons_addr;
WRAP: begin
// check if the address reached warp boundary
if (cons_addr == upper_wrap_boundary) begin
addr_o = wrap_boundary;
// address warped beyond boundary
end else if (cons_addr > upper_wrap_boundary) begin
addr_o = ax_req_q_addr + ((cnt_q - ax_req_q_len) << LOG_NR_BYTES);
// we are still in the incremental regime
end else begin
addr_o = cons_addr;
end
end
endcase
// we need to change the address here for the upcoming request
// we can decrease the counter as the master has consumed the read data
cnt_d = cnt_q + 1; cnt_d = cnt_q + 1;
// save the request address for the next cycle
req_addr_d = addr_o;
state_d = READ; state_d = READ;
end end
//ext SRAM need nop between continuous write operations
WRITE_NOP: begin
s_wready = 1'b0;
state_d = WRITE;
end
// ~> we already wrote the first word here // ~> we already wrote the first word here
WRITE: begin WRITE: begin
s_wready = 1'b1; s_wready = 1'b1;
state_d = WRITE_NOP; state_d = WRITE;
// consume a word here // consume a word here
if (s_wvalid) begin if (s_wvalid) begin
@@ -303,24 +312,9 @@ module axi2sram_sp_external #(
// Next address generation // Next address generation
// ---------------------------- // ----------------------------
// handle the correct burst type // handle the correct burst type
case (ax_req_q_burst) addr_o = next_addr;
FIXED, INCR: addr_o = cons_addr;
WRAP: begin
// check if the address reached warp boundary
if (cons_addr == upper_wrap_boundary) begin
addr_o = wrap_boundary;
// address warped beyond boundary
end else if (cons_addr > upper_wrap_boundary) begin
addr_o = ax_req_q_addr + ((cnt_q - ax_req_q_len) << LOG_NR_BYTES);
// we are still in the incremental regime
end else begin
addr_o = cons_addr;
end
end
endcase
// save the request address for the next cycle // save the request address for the next cycle
req_addr_d = addr_o; req_addr_d = next_addr;
// we can decrease the counter as the master has consumed the read data // we can decrease the counter as the master has consumed the read data
cnt_d = cnt_q + 1; cnt_d = cnt_q + 1;
@@ -351,7 +345,10 @@ module axi2sram_sp_external #(
ax_req_q_len <= 8'h0; ax_req_q_len <= 8'h0;
ax_req_q_size <= 3'h0; ax_req_q_size <= 3'h0;
req_addr_q <= 'h0; req_addr_q <= 'h0;
cnt_q <= 8'h0; cnt_q <= 9'h0;
wrap_mask_q <= 'h0;
req_bank_q <= 1'b0;
read_data_q <= 'h0;
end else begin end else begin
state_q <= state_d; state_q <= state_d;
ax_req_q_addr <= ax_req_d_addr; ax_req_q_addr <= ax_req_d_addr;
@@ -361,6 +358,10 @@ module axi2sram_sp_external #(
ax_req_q_size <= ax_req_d_size; ax_req_q_size <= ax_req_d_size;
req_addr_q <= req_addr_d; req_addr_q <= req_addr_d;
cnt_q <= cnt_d; cnt_q <= cnt_d;
wrap_mask_q <= wrap_mask_d;
req_bank_q <= req_bank_d;
if (read_capture)
read_data_q <= data_i;
end end
end end
@@ -377,4 +378,3 @@ module axi2sram_sp_external #(
// end // end
endmodule endmodule

View File

@@ -101,7 +101,7 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT0_ACTUAL_FREQ">32.97872</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT0_ACTUAL_FREQ">32.97872</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_1">0000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_1">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_2">0000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_2">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_ACTUAL_FREQ">50.00000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_ACTUAL_FREQ">59.61538</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_DRIVES">BUFG</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_DRIVES">BUFG</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_DUTY_CYCLE">50.0</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_DUTY_CYCLE">50.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_MATCHED_ROUTING">false</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT1_MATCHED_ROUTING">false</spirit:configurableElementValue>
@@ -117,10 +117,10 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_DRIVES">BUFG</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_DRIVES">BUFG</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_DUTY_CYCLE">50.0</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_DUTY_CYCLE">50.0</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_MATCHED_ROUTING">false</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_MATCHED_ROUTING">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_OUT_FREQ">50.00000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_OUT_FREQ">59.61538</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_PHASE">0.000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_REQUESTED_DUTY_CYCLE">50.000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_REQUESTED_DUTY_CYCLE">50.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_REQUESTED_OUT_FREQ">50.000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_REQUESTED_OUT_FREQ">60</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_REQUESTED_PHASE">0.000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_REQUESTED_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_SEQUENCE_NUMBER">1</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_SEQUENCE_NUMBER">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_USED">1</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_CLKOUT2_USED">1</spirit:configurableElementValue>
@@ -203,7 +203,7 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIN_PORT">din</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIN_PORT">din</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVCLK">0000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVCLK">0000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE1_AUTO">1</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE1_AUTO">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE2_AUTO">0.66</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE2_AUTO">0.55</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE3_AUTO">0.33</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE3_AUTO">0.33</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE4_AUTO">0.33</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE4_AUTO">0.33</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE5_AUTO">0.33</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_DIVIDE5_AUTO">0.33</spirit:configurableElementValue>
@@ -255,7 +255,7 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT0_DUTY_CYCLE">0.500</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT0_DUTY_CYCLE">0.500</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT0_PHASE">0.000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT0_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT0_USE_FINE_PS">FALSE</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT0_USE_FINE_PS">FALSE</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_DIVIDE">31</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_DIVIDE">26</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_DUTY_CYCLE">0.500</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_DUTY_CYCLE">0.500</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_PHASE">0.000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_USE_FINE_PS">FALSE</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_MMCM_CLKOUT1_USE_FINE_PS">FALSE</spirit:configurableElementValue>
@@ -293,7 +293,7 @@
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW0A"> Output Output Phase Duty Cycle Pk-to-Pk Phase</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW0A"> Output Output Phase Duty Cycle Pk-to-Pk Phase</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW0B"> Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps)</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW0B"> Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps)</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW1">_cpu_clk__32.97872______0.000______50.0______130.093____123.600</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW1">_cpu_clk__32.97872______0.000______50.0______130.093____123.600</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW2">_sys_clk__50.00000______0.000______50.0______122.035____123.600</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW2">_sys_clk__59.61538______0.000______50.0______118.808____123.600</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW3">no_CLK_OUT3_output</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW3">no_CLK_OUT3_output</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW4">no_CLK_OUT4_output</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW4">no_CLK_OUT4_output</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW5">no_CLK_OUT5_output</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="MODELPARAM_VALUE.C_OUTCLK_SUM_ROW5">no_CLK_OUT5_output</spirit:configurableElementValue>
@@ -423,11 +423,11 @@
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_SEQUENCE_NUMBER">1</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_SEQUENCE_NUMBER">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_USED">true</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT1_USED">true</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_DRIVES">BUFG</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_DRIVES">BUFG</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_JITTER">122.035</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_JITTER">118.808</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_MATCHED_ROUTING">false</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_MATCHED_ROUTING">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_PHASE_ERROR">123.600</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_PHASE_ERROR">123.600</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_REQUESTED_DUTY_CYCLE">50.000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_REQUESTED_DUTY_CYCLE">50.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_REQUESTED_OUT_FREQ">50.000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_REQUESTED_OUT_FREQ">60</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_REQUESTED_PHASE">0.000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_REQUESTED_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_SEQUENCE_NUMBER">1</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_SEQUENCE_NUMBER">1</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_USED">true</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.CLKOUT2_USED">true</spirit:configurableElementValue>
@@ -534,7 +534,7 @@
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT0_DUTY_CYCLE">0.500</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT0_DUTY_CYCLE">0.500</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT0_PHASE">0.000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT0_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT0_USE_FINE_PS">false</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT0_USE_FINE_PS">false</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_DIVIDE">31</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_DIVIDE">26</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_DUTY_CYCLE">0.500</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_DUTY_CYCLE">0.500</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_PHASE">0.000</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_PHASE">0.000</spirit:configurableElementValue>
<spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_USE_FINE_PS">false</spirit:configurableElementValue> <spirit:configurableElementValue spirit:referenceId="PARAM_VALUE.MMCM_CLKOUT1_USE_FINE_PS">false</spirit:configurableElementValue>

View File

@@ -94,6 +94,23 @@ module snix_axil_cdma_mux #(
input logic mm2mm_rvalid, input logic mm2mm_rvalid,
output logic mm2mm_rready, output logic mm2mm_rready,
// ==========================================
// Local endpoint interface
// ==========================================
output logic ep_wr_valid,
output logic [3:0] ep_wr_id,
output logic [3:0] ep_wr_bank,
output logic [7:0] ep_wr_word_addr,
output logic [31:0] ep_wr_data,
input logic ep_wr_ready,
output logic ep_rd_valid,
output logic [3:0] ep_rd_id,
output logic [3:0] ep_rd_bank,
output logic [7:0] ep_rd_word_addr,
input logic [31:0] ep_rd_data,
input logic ep_rd_ready,
// Global Interrupt (OR'd from all channels) // Global Interrupt (OR'd from all channels)
output logic dma_finish output logic dma_finish
); );
@@ -102,6 +119,33 @@ module snix_axil_cdma_mux #(
// Local Parameters & Utilities // Local Parameters & Utilities
// ========================================== // ==========================================
localparam int CH_BITS = $clog2(PORTS); localparam int CH_BITS = $clog2(PORTS);
localparam logic [1:0] MODE_MEM2MEM = 2'd0;
localparam logic [1:0] MODE_MEM2EP = 2'd1;
localparam logic [1:0] MODE_EP2MEM = 2'd2;
localparam logic [7:0] SEQ_REG_CTRL = 8'h00;
localparam logic [7:0] SEQ_REG_STATUS = 8'h04;
localparam logic [7:0] SEQ_REG_SRC_BASE = 8'h08;
localparam logic [7:0] SEQ_REG_DST_BASE = 8'h0C;
localparam logic [7:0] SEQ_REG_GROUPS = 8'h10;
localparam logic [7:0] SEQ_REG_MAT_BASE = 8'h14;
localparam logic [7:0] SEQ_REG_SRC_STRIDE = 8'h18;
localparam logic [7:0] SEQ_REG_DST_STRIDE = 8'h1C;
localparam logic [11:0] MAT_CTRL_OFF = 12'h000;
localparam logic [11:0] MAT_STATUS_OFF = 12'h004;
localparam logic [11:0] MAT_CRC_OFF = 12'h010;
localparam logic [11:0] MAT_B0_AB_OFF = 12'h100;
localparam logic [11:0] MAT_B0_C_OFF = 12'h180;
localparam logic [11:0] MAT_B1_AB_OFF = 12'h300;
localparam logic [11:0] MAT_B1_C_OFF = 12'h380;
localparam logic [31:0] MAT_STATUS_DONE_CLR = 32'h0000_0006;
localparam logic [31:0] MAT_STATUS_DONE_BIT = 32'h0000_0002;
localparam logic [31:0] MAT_CTRL_START_B0 = 32'h0000_0001;
localparam logic [31:0] MAT_CTRL_START_B1 = 32'h0000_0002;
localparam logic [31:0] MAT_AB_BYTES = 32'd128;
localparam logic [31:0] MAT_C_BYTES = 32'd192;
// Function to safely apply WSTRB to 32-bit registers // Function to safely apply WSTRB to 32-bit registers
function automatic logic [31:0] apply_wstrb( function automatic logic [31:0] apply_wstrb(
@@ -125,12 +169,25 @@ module snix_axil_cdma_mux #(
logic [31:0] ch_len [PORTS]; logic [31:0] ch_len [PORTS];
logic [31:0] ch_tag [PORTS]; logic [31:0] ch_tag [PORTS];
logic [31:0] ch_ctrl [PORTS]; logic [31:0] ch_ctrl [PORTS];
logic [31:0] ch_mode [PORTS];
logic [31:0] ch_ep_cfg [PORTS];
logic [PORTS-1:0] ch_req; // Pending requests (Busy) logic [PORTS-1:0] ch_req; // Pending requests (Busy)
logic [PORTS-1:0] ch_done; // Completion flags logic [PORTS-1:0] ch_done; // Completion flags
logic [PORTS-1:0] arb_set_done; // From Arbiter to CSR logic [PORTS-1:0] arb_set_done; // From Arbiter to CSR
logic [31:0] seq_src_base;
logic [31:0] seq_dst_base;
logic [31:0] seq_groups;
logic [31:0] seq_mat_base;
logic [31:0] seq_src_stride;
logic [31:0] seq_dst_stride;
logic seq_busy;
logic seq_done_flag;
wire seq_start_req;
wire seq_done_clear_req;
// ========================================== // ==========================================
// Address Decoding (0x40 offset per channel) // Address Decoding (0x40 offset per channel)
// ========================================== // ==========================================
@@ -138,6 +195,14 @@ module snix_axil_cdma_mux #(
wire [5:0] wr_reg = s_axil_awaddr[5:0]; wire [5:0] wr_reg = s_axil_awaddr[5:0];
wire [CH_BITS-1:0] rd_ch = s_axil_araddr[6 +: CH_BITS]; wire [CH_BITS-1:0] rd_ch = s_axil_araddr[6 +: CH_BITS];
wire [5:0] rd_reg = s_axil_araddr[5:0]; wire [5:0] rd_reg = s_axil_araddr[5:0];
wire wr_seq_reg = (s_axil_awaddr[11:8] == 4'h2);
wire rd_seq_reg = (s_axil_araddr[11:8] == 4'h2);
wire [7:0] wr_seq_off = s_axil_awaddr[7:0];
wire [7:0] rd_seq_off = s_axil_araddr[7:0];
assign seq_start_req = do_write && wr_seq_reg && (wr_seq_off == SEQ_REG_CTRL) &&
s_axil_wstrb[0] && s_axil_wdata[0];
assign seq_done_clear_req = do_write && wr_seq_reg && (wr_seq_off == SEQ_REG_STATUS) &&
s_axil_wstrb[0] && s_axil_wdata[1];
// ========================================== // ==========================================
// AXI-Lite Slave Logic (Robust Backpressure) // AXI-Lite Slave Logic (Robust Backpressure)
@@ -197,7 +262,19 @@ module snix_axil_cdma_mux #(
end else begin end else begin
if (do_read) begin if (do_read) begin
s_axil_rvalid <= 1'b1; s_axil_rvalid <= 1'b1;
if (rd_ch < PORTS) begin if (rd_seq_reg) begin
case (rd_seq_off)
SEQ_REG_CTRL: s_axil_rdata <= {31'd0, seq_start_req};
SEQ_REG_STATUS: s_axil_rdata <= {30'd0, seq_done_flag, seq_busy};
SEQ_REG_SRC_BASE: s_axil_rdata <= seq_src_base;
SEQ_REG_DST_BASE: s_axil_rdata <= seq_dst_base;
SEQ_REG_GROUPS: s_axil_rdata <= seq_groups;
SEQ_REG_MAT_BASE: s_axil_rdata <= seq_mat_base;
SEQ_REG_SRC_STRIDE: s_axil_rdata <= seq_src_stride;
SEQ_REG_DST_STRIDE: s_axil_rdata <= seq_dst_stride;
default: s_axil_rdata <= 32'd0;
endcase
end else if (rd_ch < PORTS) begin
case (rd_reg) case (rd_reg)
6'h00: s_axil_rdata <= ch_src_addr[rd_ch]; 6'h00: s_axil_rdata <= ch_src_addr[rd_ch];
6'h04: s_axil_rdata <= ch_dst_addr[rd_ch]; 6'h04: s_axil_rdata <= ch_dst_addr[rd_ch];
@@ -205,6 +282,8 @@ module snix_axil_cdma_mux #(
6'h0C: s_axil_rdata <= ch_tag[rd_ch]; 6'h0C: s_axil_rdata <= ch_tag[rd_ch];
6'h10: s_axil_rdata <= ch_ctrl[rd_ch]; 6'h10: s_axil_rdata <= ch_ctrl[rd_ch];
6'h14: s_axil_rdata <= {30'd0, ch_done[rd_ch], ch_req[rd_ch]}; 6'h14: s_axil_rdata <= {30'd0, ch_done[rd_ch], ch_req[rd_ch]};
6'h18: s_axil_rdata <= ch_mode[rd_ch];
6'h1C: s_axil_rdata <= ch_ep_cfg[rd_ch];
default: s_axil_rdata <= 32'd0; default: s_axil_rdata <= 32'd0;
endcase endcase
end else begin end else begin
@@ -225,9 +304,16 @@ module snix_axil_cdma_mux #(
if (!rst_n) begin if (!rst_n) begin
ch_req <= '0; ch_req <= '0;
ch_done <= '0; ch_done <= '0;
seq_src_base <= 32'h0;
seq_dst_base <= 32'h0;
seq_groups <= 32'h0;
seq_mat_base <= 32'h1f50_0000;
seq_src_stride <= 32'd128;
seq_dst_stride <= 32'd192;
for (int i=0; i<PORTS; i++) begin for (int i=0; i<PORTS; i++) begin
ch_src_addr[i] <= '0; ch_dst_addr[i] <= '0; ch_src_addr[i] <= '0; ch_dst_addr[i] <= '0;
ch_len[i] <= '0; ch_tag[i] <= '0; ch_ctrl[i] <= '0; ch_len[i] <= '0; ch_tag[i] <= '0; ch_ctrl[i] <= '0;
ch_mode[i] <= '0; ch_ep_cfg[i] <= '0;
end end
end else begin end else begin
// 1. Process Hardware Status Updates (Highest Priority for Done flag) // 1. Process Hardware Status Updates (Highest Priority for Done flag)
@@ -239,12 +325,23 @@ module snix_axil_cdma_mux #(
end end
// 2. Process CPU Writes // 2. Process CPU Writes
if (do_write && wr_ch < PORTS) begin if (do_write && wr_seq_reg) begin
case (wr_seq_off)
SEQ_REG_SRC_BASE: if (!seq_busy) seq_src_base <= apply_wstrb(seq_src_base, s_axil_wdata, s_axil_wstrb);
SEQ_REG_DST_BASE: if (!seq_busy) seq_dst_base <= apply_wstrb(seq_dst_base, s_axil_wdata, s_axil_wstrb);
SEQ_REG_GROUPS: if (!seq_busy) seq_groups <= apply_wstrb(seq_groups, s_axil_wdata, s_axil_wstrb);
SEQ_REG_MAT_BASE: if (!seq_busy) seq_mat_base <= apply_wstrb(seq_mat_base, s_axil_wdata, s_axil_wstrb);
SEQ_REG_SRC_STRIDE: if (!seq_busy) seq_src_stride <= apply_wstrb(seq_src_stride, s_axil_wdata, s_axil_wstrb);
SEQ_REG_DST_STRIDE: if (!seq_busy) seq_dst_stride <= apply_wstrb(seq_dst_stride, s_axil_wdata, s_axil_wstrb);
endcase
end else if (do_write && wr_ch < PORTS) begin
case (wr_reg) case (wr_reg)
6'h00: if (!ch_req[wr_ch]) ch_src_addr[wr_ch] <= apply_wstrb(ch_src_addr[wr_ch], s_axil_wdata, s_axil_wstrb); 6'h00: if (!ch_req[wr_ch]) ch_src_addr[wr_ch] <= apply_wstrb(ch_src_addr[wr_ch], s_axil_wdata, s_axil_wstrb);
6'h04: if (!ch_req[wr_ch]) ch_dst_addr[wr_ch] <= apply_wstrb(ch_dst_addr[wr_ch], s_axil_wdata, s_axil_wstrb); 6'h04: if (!ch_req[wr_ch]) ch_dst_addr[wr_ch] <= apply_wstrb(ch_dst_addr[wr_ch], s_axil_wdata, s_axil_wstrb);
6'h08: if (!ch_req[wr_ch]) ch_len[wr_ch] <= apply_wstrb(ch_len[wr_ch], s_axil_wdata, s_axil_wstrb); 6'h08: if (!ch_req[wr_ch]) ch_len[wr_ch] <= apply_wstrb(ch_len[wr_ch], s_axil_wdata, s_axil_wstrb);
6'h0C: if (!ch_req[wr_ch]) ch_tag[wr_ch] <= apply_wstrb(ch_tag[wr_ch], s_axil_wdata, s_axil_wstrb); 6'h0C: if (!ch_req[wr_ch]) ch_tag[wr_ch] <= apply_wstrb(ch_tag[wr_ch], s_axil_wdata, s_axil_wstrb);
6'h18: if (!ch_req[wr_ch]) ch_mode[wr_ch] <= apply_wstrb(ch_mode[wr_ch], s_axil_wdata, s_axil_wstrb);
6'h1C: if (!ch_req[wr_ch]) ch_ep_cfg[wr_ch] <= apply_wstrb(ch_ep_cfg[wr_ch], s_axil_wdata, s_axil_wstrb);
6'h10: begin 6'h10: begin
ch_ctrl[wr_ch] <= apply_wstrb(ch_ctrl[wr_ch], s_axil_wdata, s_axil_wstrb); ch_ctrl[wr_ch] <= apply_wstrb(ch_ctrl[wr_ch], s_axil_wdata, s_axil_wstrb);
// Trigger Bit Processing // Trigger Bit Processing
@@ -269,7 +366,7 @@ module snix_axil_cdma_mux #(
// ========================================== // ==========================================
// Round-Robin Arbiter & Engine Driver // Round-Robin Arbiter & Engine Driver
// ========================================== // ==========================================
typedef enum logic [1:0] {IDLE, RUN} state_t; typedef enum logic [1:0] {IDLE, START, RUN} state_t;
state_t state; state_t state;
logic [CH_BITS-1:0] cur_ch; logic [CH_BITS-1:0] cur_ch;
@@ -283,6 +380,175 @@ module snix_axil_cdma_mux #(
logic [7:0] engine_len; logic [7:0] engine_len;
logic [2:0] engine_size; logic [2:0] engine_size;
logic engine_done; logic engine_done;
logic [1:0] engine_mode;
logic [3:0] engine_ep_id;
logic [3:0] engine_ep_bank;
logic [7:0] engine_ep_word_off;
logic mm2mm_start;
logic mm2mm_done;
logic ep_start;
logic ep_done;
logic [ID_WIDTH-1:0] core_awid;
logic [ADDR_WIDTH-1:0] core_awaddr;
logic [7:0] core_awlen;
logic [2:0] core_awsize;
logic [1:0] core_awburst;
logic core_awlock;
logic [3:0] core_awcache;
logic [2:0] core_awprot;
logic [3:0] core_awqos;
logic [USER_WIDTH-1:0] core_awuser;
logic core_awvalid;
logic core_awready;
logic [DATA_WIDTH-1:0] core_wdata;
logic [DATA_WIDTH/8-1:0] core_wstrb;
logic core_wlast;
logic [USER_WIDTH-1:0] core_wuser;
logic core_wvalid;
logic core_wready;
logic core_bready;
logic [ID_WIDTH-1:0] core_arid;
logic [ADDR_WIDTH-1:0] core_araddr;
logic [7:0] core_arlen;
logic [2:0] core_arsize;
logic [1:0] core_arburst;
logic core_arlock;
logic [3:0] core_arcache;
logic [2:0] core_arprot;
logic [3:0] core_arqos;
logic [USER_WIDTH-1:0] core_aruser;
logic core_arvalid;
logic core_arready;
logic core_rready;
logic [ID_WIDTH-1:0] ep_awid;
logic [ADDR_WIDTH-1:0] ep_awaddr;
logic [7:0] ep_awlen;
logic [2:0] ep_awsize;
logic [1:0] ep_awburst;
logic ep_awlock;
logic [3:0] ep_awcache;
logic [2:0] ep_awprot;
logic [3:0] ep_awqos;
logic [USER_WIDTH-1:0] ep_awuser;
logic ep_awvalid;
logic ep_awready;
logic [DATA_WIDTH-1:0] ep_wdata;
logic [DATA_WIDTH/8-1:0] ep_wstrb;
logic ep_wlast;
logic [USER_WIDTH-1:0] ep_wuser;
logic ep_wvalid;
logic ep_wready;
logic ep_bready;
logic [ID_WIDTH-1:0] ep_arid;
logic [ADDR_WIDTH-1:0] ep_araddr;
logic [7:0] ep_arlen;
logic [2:0] ep_arsize;
logic [1:0] ep_arburst;
logic ep_arlock;
logic [3:0] ep_arcache;
logic [2:0] ep_arprot;
logic [3:0] ep_arqos;
logic [USER_WIDTH-1:0] ep_aruser;
logic ep_arvalid;
logic ep_arready;
logic ep_rready;
logic [ID_WIDTH-1:0] seq_awid;
logic [ADDR_WIDTH-1:0] seq_awaddr;
logic [7:0] seq_awlen;
logic [2:0] seq_awsize;
logic [1:0] seq_awburst;
logic seq_awlock;
logic [3:0] seq_awcache;
logic [2:0] seq_awprot;
logic [3:0] seq_awqos;
logic [USER_WIDTH-1:0] seq_awuser;
logic seq_awvalid;
logic seq_awready;
logic [DATA_WIDTH-1:0] seq_wdata;
logic [DATA_WIDTH/8-1:0] seq_wstrb;
logic seq_wlast;
logic [USER_WIDTH-1:0] seq_wuser;
logic seq_wvalid;
logic seq_wready;
logic seq_bready;
logic [ID_WIDTH-1:0] seq_arid;
logic [ADDR_WIDTH-1:0] seq_araddr;
logic [7:0] seq_arlen;
logic [2:0] seq_arsize;
logic [1:0] seq_arburst;
logic seq_arlock;
logic [3:0] seq_arcache;
logic [2:0] seq_arprot;
logic [3:0] seq_arqos;
logic [USER_WIDTH-1:0] seq_aruser;
logic seq_arvalid;
logic seq_arready;
logic seq_rready;
// Hardware matmul loop sequencer state. Keep these declarations before the
// DMA routing logic because Vivado does not allow forward enum references.
typedef enum logic [4:0] {
SQ_IDLE,
SQ_CLEAR_CRC,
SQ_LOAD0,
SQ_START0,
SQ_LOAD1,
SQ_WAIT_DONE,
SQ_STORE,
SQ_CLEAR_DONE,
SQ_START_NEXT,
SQ_LOAD_NEXT,
SQ_DONE
} seq_state_t;
typedef enum logic [3:0] {
OP_IDLE,
OP_READ_ADDR,
OP_READ_DATA,
OP_WRITE_ADDR,
OP_WRITE_DATA,
OP_WRITE_RESP,
OP_REG_READ_ADDR,
OP_REG_READ_DATA,
OP_COPY_START,
OP_COPY_WAIT
} op_state_t;
seq_state_t seq_state;
op_state_t op_state;
logic op_start_copy;
logic op_start_write;
logic op_start_read;
logic op_done;
logic [31:0] op_src_addr;
logic [31:0] op_dst_addr;
logic [31:0] op_bytes;
logic [31:0] op_write_addr;
logic [31:0] op_write_data;
logic [31:0] op_read_addr;
logic [31:0] op_read_data;
logic [31:0] op_src_cur;
logic [31:0] op_dst_cur;
logic [31:0] op_bytes_left;
logic [31:0] op_data_buf;
logic op_buf_valid;
logic op_copy_store;
logic [31:0] seq_group_idx;
logic [31:0] seq_load_idx;
logic [31:0] seq_store_idx;
logic seq_compute_bank;
logic [31:0] seq_status_data;
wire use_ep_engine = (state == RUN) && (engine_mode != MODE_MEM2MEM);
wire use_seq_engine = seq_busy && (op_state != OP_IDLE) &&
(op_state != OP_COPY_START) && (op_state != OP_COPY_WAIT);
wire seq_dma_active = seq_busy && ((op_state == OP_COPY_START) || (op_state == OP_COPY_WAIT));
// Dynamic routing to the engine based on current active channel // Dynamic routing to the engine based on current active channel
assign engine_src = ch_src_addr[cur_ch]; assign engine_src = ch_src_addr[cur_ch];
@@ -290,6 +556,55 @@ module snix_axil_cdma_mux #(
assign engine_bytes = ch_len[cur_ch]; assign engine_bytes = ch_len[cur_ch];
assign engine_len = ch_ctrl[cur_ch][13:6]; assign engine_len = ch_ctrl[cur_ch][13:6];
assign engine_size = ch_ctrl[cur_ch][5:3]; assign engine_size = ch_ctrl[cur_ch][5:3];
assign engine_mode = ch_mode[cur_ch][1:0];
assign engine_ep_bank = ch_ep_cfg[cur_ch][3:0];
assign engine_ep_word_off = ch_ep_cfg[cur_ch][15:8];
assign engine_ep_id = ch_ep_cfg[cur_ch][19:16];
assign engine_done = (engine_mode == MODE_MEM2MEM) ? mm2mm_done : ep_done;
assign mm2mm_start = engine_start && (engine_mode == MODE_MEM2MEM);
assign ep_start = engine_start && (engine_mode != MODE_MEM2MEM);
assign core_awready = (!use_seq_engine && !use_ep_engine) && mm2mm_awready;
assign core_wready = (!use_seq_engine && !use_ep_engine) && mm2mm_wready;
assign core_arready = (!use_seq_engine && !use_ep_engine) && mm2mm_arready;
assign ep_awready = (!use_seq_engine && use_ep_engine) && mm2mm_awready;
assign ep_wready = (!use_seq_engine && use_ep_engine) && mm2mm_wready;
assign ep_arready = (!use_seq_engine && use_ep_engine) && mm2mm_arready;
assign seq_awready = use_seq_engine && mm2mm_awready;
assign seq_wready = use_seq_engine && mm2mm_wready;
assign seq_arready = use_seq_engine && mm2mm_arready;
assign mm2mm_awid = use_seq_engine ? seq_awid : (use_ep_engine ? ep_awid : core_awid);
assign mm2mm_awaddr = use_seq_engine ? seq_awaddr : (use_ep_engine ? ep_awaddr : core_awaddr);
assign mm2mm_awlen = use_seq_engine ? seq_awlen : (use_ep_engine ? ep_awlen : core_awlen);
assign mm2mm_awsize = use_seq_engine ? seq_awsize : (use_ep_engine ? ep_awsize : core_awsize);
assign mm2mm_awburst = use_seq_engine ? seq_awburst : (use_ep_engine ? ep_awburst : core_awburst);
assign mm2mm_awlock = use_seq_engine ? seq_awlock : (use_ep_engine ? ep_awlock : core_awlock);
assign mm2mm_awcache = use_seq_engine ? seq_awcache : (use_ep_engine ? ep_awcache : core_awcache);
assign mm2mm_awprot = use_seq_engine ? seq_awprot : (use_ep_engine ? ep_awprot : core_awprot);
assign mm2mm_awqos = use_seq_engine ? seq_awqos : (use_ep_engine ? ep_awqos : core_awqos);
assign mm2mm_awuser = use_seq_engine ? seq_awuser : (use_ep_engine ? ep_awuser : core_awuser);
assign mm2mm_awvalid = use_seq_engine ? seq_awvalid : (use_ep_engine ? ep_awvalid : core_awvalid);
assign mm2mm_wdata = use_seq_engine ? seq_wdata : (use_ep_engine ? ep_wdata : core_wdata);
assign mm2mm_wstrb = use_seq_engine ? seq_wstrb : (use_ep_engine ? ep_wstrb : core_wstrb);
assign mm2mm_wlast = use_seq_engine ? seq_wlast : (use_ep_engine ? ep_wlast : core_wlast);
assign mm2mm_wuser = use_seq_engine ? seq_wuser : (use_ep_engine ? ep_wuser : core_wuser);
assign mm2mm_wvalid = use_seq_engine ? seq_wvalid : (use_ep_engine ? ep_wvalid : core_wvalid);
assign mm2mm_bready = use_seq_engine ? seq_bready : (use_ep_engine ? ep_bready : core_bready);
assign mm2mm_arid = use_seq_engine ? seq_arid : (use_ep_engine ? ep_arid : core_arid);
assign mm2mm_araddr = use_seq_engine ? seq_araddr : (use_ep_engine ? ep_araddr : core_araddr);
assign mm2mm_arlen = use_seq_engine ? seq_arlen : (use_ep_engine ? ep_arlen : core_arlen);
assign mm2mm_arsize = use_seq_engine ? seq_arsize : (use_ep_engine ? ep_arsize : core_arsize);
assign mm2mm_arburst = use_seq_engine ? seq_arburst : (use_ep_engine ? ep_arburst : core_arburst);
assign mm2mm_arlock = use_seq_engine ? seq_arlock : (use_ep_engine ? ep_arlock : core_arlock);
assign mm2mm_arcache = use_seq_engine ? seq_arcache : (use_ep_engine ? ep_arcache : core_arcache);
assign mm2mm_arprot = use_seq_engine ? seq_arprot : (use_ep_engine ? ep_arprot : core_arprot);
assign mm2mm_arqos = use_seq_engine ? seq_arqos : (use_ep_engine ? ep_arqos : core_arqos);
assign mm2mm_aruser = use_seq_engine ? seq_aruser : (use_ep_engine ? ep_aruser : core_aruser);
assign mm2mm_arvalid = use_seq_engine ? seq_arvalid : (use_ep_engine ? ep_arvalid : core_arvalid);
assign mm2mm_rready = use_seq_engine ? seq_rready : (use_ep_engine ? ep_rready : core_rready);
always_ff @(posedge clk) begin always_ff @(posedge clk) begin
if (!rst_n) begin if (!rst_n) begin
@@ -304,7 +619,9 @@ module snix_axil_cdma_mux #(
case (state) case (state)
IDLE: begin IDLE: begin
for (int i = 0; i < PORTS; i++) begin if (seq_busy) begin
state <= IDLE;
end else for (int i = 0; i < PORTS; i++) begin
logic [CH_BITS:0] check_ch_ext; logic [CH_BITS:0] check_ch_ext;
logic [CH_BITS-1:0] check_ch; logic [CH_BITS-1:0] check_ch;
@@ -315,13 +632,17 @@ module snix_axil_cdma_mux #(
if (ch_req[check_ch] && !arb_set_done[check_ch]) begin if (ch_req[check_ch] && !arb_set_done[check_ch]) begin
cur_ch <= check_ch; cur_ch <= check_ch;
rr_ptr <= (check_ch == (PORTS - 1)) ? '0 : (check_ch + 1); rr_ptr <= (check_ch == (PORTS - 1)) ? '0 : (check_ch + 1);
engine_start <= 1'b1; state <= START;
state <= RUN;
break; break;
end end
end end
end end
START: begin
engine_start <= 1'b1;
state <= RUN;
end
RUN: begin RUN: begin
if (engine_done) begin if (engine_done) begin
arb_set_done[cur_ch] <= 1'b1; arb_set_done[cur_ch] <= 1'b1;
@@ -345,37 +666,474 @@ module snix_axil_cdma_mux #(
) u_core_engine ( ) u_core_engine (
.clk (clk), .clk (clk),
.rst_n (rst_n), .rst_n (rst_n),
.ctrl_start (engine_start), .ctrl_start ((op_state == OP_COPY_START) ? 1'b1 : mm2mm_start),
.ctrl_stop (1'b0), // Tied off; can be wired if global abort is needed .ctrl_stop (1'b0), // Tied off; can be wired if global abort is needed
.ctrl_src_addr (engine_src), .ctrl_src_addr (seq_dma_active ? op_src_cur : engine_src),
.ctrl_dst_addr (engine_dst), .ctrl_dst_addr (seq_dma_active ? op_dst_cur : engine_dst),
.ctrl_len (engine_len), .ctrl_len (seq_dma_active ? 8'd63 : engine_len),
.ctrl_size (engine_size), .ctrl_size (seq_dma_active ? 3'd2 : engine_size),
.ctrl_transfer_len (engine_bytes), .ctrl_transfer_len (seq_dma_active ? op_bytes_left : engine_bytes),
.ctrl_done (engine_done), .ctrl_done (mm2mm_done),
// AXI4 Port Connections // AXI4 Port Connections
.mm2mm_awid (mm2mm_awid), .mm2mm_awaddr (mm2mm_awaddr), .mm2mm_awid (core_awid), .mm2mm_awaddr (core_awaddr),
.mm2mm_awlen (mm2mm_awlen), .mm2mm_awsize (mm2mm_awsize), .mm2mm_awlen (core_awlen), .mm2mm_awsize (core_awsize),
.mm2mm_awburst(mm2mm_awburst),.mm2mm_awlock (mm2mm_awlock), .mm2mm_awburst(core_awburst),.mm2mm_awlock (core_awlock),
.mm2mm_awcache(mm2mm_awcache),.mm2mm_awprot (mm2mm_awprot), .mm2mm_awcache(core_awcache),.mm2mm_awprot (core_awprot),
.mm2mm_awqos (mm2mm_awqos), .mm2mm_awuser (mm2mm_awuser), .mm2mm_awqos (core_awqos), .mm2mm_awuser (core_awuser),
.mm2mm_awvalid(mm2mm_awvalid),.mm2mm_awready(mm2mm_awready), .mm2mm_awvalid(core_awvalid),.mm2mm_awready(core_awready),
.mm2mm_wdata (mm2mm_wdata), .mm2mm_wstrb (mm2mm_wstrb), .mm2mm_wdata (core_wdata), .mm2mm_wstrb (core_wstrb),
.mm2mm_wlast (mm2mm_wlast), .mm2mm_wuser (mm2mm_wuser), .mm2mm_wlast (core_wlast), .mm2mm_wuser (core_wuser),
.mm2mm_wvalid (mm2mm_wvalid), .mm2mm_wready (mm2mm_wready), .mm2mm_wvalid (core_wvalid), .mm2mm_wready (core_wready),
.mm2mm_bid (mm2mm_bid), .mm2mm_bresp (mm2mm_bresp), .mm2mm_bid (mm2mm_bid), .mm2mm_bresp (mm2mm_bresp),
.mm2mm_buser (mm2mm_buser), .mm2mm_bvalid (mm2mm_bvalid), .mm2mm_buser (mm2mm_buser), .mm2mm_bvalid (mm2mm_bvalid),
.mm2mm_bready (mm2mm_bready), .mm2mm_bready (core_bready),
.mm2mm_arid (mm2mm_arid), .mm2mm_araddr (mm2mm_araddr), .mm2mm_arid (core_arid), .mm2mm_araddr (core_araddr),
.mm2mm_arlen (mm2mm_arlen), .mm2mm_arsize (mm2mm_arsize), .mm2mm_arlen (core_arlen), .mm2mm_arsize (core_arsize),
.mm2mm_arburst(mm2mm_arburst),.mm2mm_arlock (mm2mm_arlock), .mm2mm_arburst(core_arburst),.mm2mm_arlock (core_arlock),
.mm2mm_arcache(mm2mm_arcache),.mm2mm_arprot (mm2mm_arprot), .mm2mm_arcache(core_arcache),.mm2mm_arprot (core_arprot),
.mm2mm_arqos (mm2mm_arqos), .mm2mm_aruser (mm2mm_aruser), .mm2mm_arqos (core_arqos), .mm2mm_aruser (core_aruser),
.mm2mm_arvalid(mm2mm_arvalid),.mm2mm_arready(mm2mm_arready), .mm2mm_arvalid(core_arvalid),.mm2mm_arready(core_arready),
.mm2mm_rid (mm2mm_rid), .mm2mm_rdata (mm2mm_rdata), .mm2mm_rid (mm2mm_rid), .mm2mm_rdata (mm2mm_rdata),
.mm2mm_rresp (mm2mm_rresp), .mm2mm_rlast (mm2mm_rlast), .mm2mm_rresp (mm2mm_rresp), .mm2mm_rlast (mm2mm_rlast),
.mm2mm_ruser (mm2mm_ruser), .mm2mm_rvalid (mm2mm_rvalid), .mm2mm_ruser (mm2mm_ruser), .mm2mm_rvalid (mm2mm_rvalid),
.mm2mm_rready (mm2mm_rready) .mm2mm_rready (core_rready)
); );
// ==========================================
// Hardware matmul loop sequencer
// ==========================================
wire seq_has_more_load = (seq_load_idx < seq_groups);
wire [31:0] seq_src_addr_for_load = seq_src_base + (seq_load_idx * seq_src_stride);
wire [31:0] seq_dst_addr_for_load = seq_mat_base + (seq_load_idx[0] ? MAT_B1_AB_OFF : MAT_B0_AB_OFF);
wire [31:0] seq_src_addr_for_store = seq_mat_base + (seq_store_idx[0] ? MAT_B1_C_OFF : MAT_B0_C_OFF);
wire [31:0] seq_dst_addr_for_store = seq_dst_base + (seq_store_idx * seq_dst_stride);
wire [31:0] seq_start_value_for_bank = seq_compute_bank ? MAT_CTRL_START_B1 : MAT_CTRL_START_B0;
wire [31:0] seq_start_value_for_loaded_bank =
(seq_load_idx[0] == 1'b0) ? MAT_CTRL_START_B1 : MAT_CTRL_START_B0;
assign seq_awid = '0;
assign seq_awsize = 3'd2;
assign seq_awburst = 2'b01;
assign seq_awlock = 1'b0;
assign seq_awcache = 4'b0;
assign seq_awprot = 3'b0;
assign seq_awqos = 4'b0;
assign seq_awuser = '0;
assign seq_wstrb = {{(DATA_WIDTH/8){1'b1}}};
assign seq_wuser = '0;
assign seq_arid = '0;
assign seq_arsize = 3'd2;
assign seq_arburst = 2'b01;
assign seq_arlock = 1'b0;
assign seq_arcache = 4'b0;
assign seq_arprot = 3'b0;
assign seq_arqos = 4'b0;
assign seq_aruser = '0;
assign seq_araddr = (op_state == OP_REG_READ_ADDR) ? op_read_addr : op_src_cur;
assign seq_arlen = (op_state == OP_REG_READ_ADDR) ? 8'd0 : 8'd0;
assign seq_arvalid = (op_state == OP_READ_ADDR) || (op_state == OP_REG_READ_ADDR);
assign seq_rready = (op_state == OP_REG_READ_DATA) ||
((op_state == OP_READ_DATA) && !op_buf_valid);
assign seq_awaddr = (op_state == OP_WRITE_ADDR && op_copy_store) ? op_dst_cur : op_write_addr;
assign seq_awlen = 8'd0;
assign seq_awvalid = (op_state == OP_WRITE_ADDR);
assign seq_wdata = op_copy_store ? op_data_buf : op_write_data;
assign seq_wlast = 1'b1;
assign seq_wvalid = (op_state == OP_WRITE_DATA) && (!op_copy_store || op_buf_valid);
assign seq_bready = (op_state == OP_WRITE_RESP);
always_ff @(posedge clk) begin
if (!rst_n) begin
op_state <= OP_IDLE;
op_done <= 1'b0;
op_src_cur <= '0;
op_dst_cur <= '0;
op_bytes_left <= '0;
op_data_buf <= '0;
op_buf_valid <= 1'b0;
op_copy_store <= 1'b0;
op_read_data <= '0;
end else begin
op_done <= 1'b0;
case (op_state)
OP_IDLE: begin
op_buf_valid <= 1'b0;
if (op_start_copy) begin
op_src_cur <= op_src_addr;
op_dst_cur <= op_dst_addr;
op_bytes_left <= op_bytes;
op_copy_store <= 1'b1;
op_state <= OP_COPY_START;
end else if (op_start_write) begin
op_copy_store <= 1'b0;
op_state <= OP_WRITE_ADDR;
end else if (op_start_read) begin
op_copy_store <= 1'b0;
op_state <= OP_REG_READ_ADDR;
end
end
OP_READ_ADDR: begin
if (seq_arvalid && seq_arready)
op_state <= OP_READ_DATA;
end
OP_READ_DATA: begin
if (mm2mm_rvalid && seq_rready) begin
op_data_buf <= mm2mm_rdata;
op_buf_valid <= 1'b1;
op_state <= OP_WRITE_ADDR;
end
end
OP_WRITE_ADDR: begin
if (seq_awvalid && seq_awready)
op_state <= OP_WRITE_DATA;
end
OP_WRITE_DATA: begin
if (seq_wvalid && seq_wready) begin
op_buf_valid <= 1'b0;
op_state <= OP_WRITE_RESP;
end
end
OP_WRITE_RESP: begin
if (mm2mm_bvalid && seq_bready) begin
if (op_copy_store && (op_bytes_left > 32'd4)) begin
op_src_cur <= op_src_cur + 32'd4;
op_dst_cur <= op_dst_cur + 32'd4;
op_bytes_left <= op_bytes_left - 32'd4;
op_state <= OP_READ_ADDR;
end else begin
op_done <= 1'b1;
op_state <= OP_IDLE;
end
end
end
OP_REG_READ_ADDR: begin
if (seq_arvalid && seq_arready)
op_state <= OP_REG_READ_DATA;
end
OP_REG_READ_DATA: begin
if (mm2mm_rvalid && seq_rready) begin
op_read_data <= mm2mm_rdata;
op_done <= 1'b1;
op_state <= OP_IDLE;
end
end
OP_COPY_START: begin
op_state <= OP_COPY_WAIT;
end
OP_COPY_WAIT: begin
if (mm2mm_done) begin
op_done <= 1'b1;
op_state <= OP_IDLE;
end
end
default: op_state <= OP_IDLE;
endcase
end
end
always_ff @(posedge clk) begin
if (!rst_n) begin
seq_state <= SQ_IDLE;
seq_busy <= 1'b0;
seq_done_flag <= 1'b0;
op_start_copy <= 1'b0;
op_start_write <= 1'b0;
op_start_read <= 1'b0;
op_src_addr <= '0;
op_dst_addr <= '0;
op_bytes <= '0;
op_write_addr <= '0;
op_write_data <= '0;
op_read_addr <= '0;
seq_group_idx <= '0;
seq_load_idx <= '0;
seq_store_idx <= '0;
seq_compute_bank <= 1'b0;
seq_status_data <= '0;
end else begin
op_start_copy <= 1'b0;
op_start_write <= 1'b0;
op_start_read <= 1'b0;
if (seq_done_clear_req)
seq_done_flag <= 1'b0;
case (seq_state)
SQ_IDLE: begin
seq_busy <= 1'b0;
if (seq_start_req && (seq_groups != 32'd0)) begin
seq_busy <= 1'b1;
seq_done_flag <= 1'b0;
seq_group_idx <= 32'd0;
seq_load_idx <= 32'd0;
seq_store_idx <= 32'd0;
seq_compute_bank <= 1'b0;
op_write_addr <= seq_mat_base + MAT_CRC_OFF;
op_write_data <= 32'd0;
op_start_write <= 1'b1;
seq_state <= SQ_CLEAR_CRC;
end
end
SQ_CLEAR_CRC: begin
if (op_done) begin
op_src_addr <= seq_src_base;
op_dst_addr <= seq_mat_base + MAT_B0_AB_OFF;
op_bytes <= MAT_AB_BYTES;
op_start_copy <= 1'b1;
seq_load_idx <= 32'd1;
seq_state <= SQ_LOAD0;
end
end
SQ_LOAD0: begin
if (op_done) begin
op_write_addr <= seq_mat_base + MAT_CTRL_OFF;
op_write_data <= MAT_CTRL_START_B0;
op_start_write <= 1'b1;
seq_state <= SQ_START0;
end
end
SQ_START0: begin
if (op_done) begin
if (seq_load_idx < seq_groups) begin
op_src_addr <= seq_src_base + (seq_load_idx * seq_src_stride);
op_dst_addr <= seq_mat_base + MAT_B1_AB_OFF;
op_bytes <= MAT_AB_BYTES;
op_start_copy <= 1'b1;
seq_load_idx <= seq_load_idx + 32'd1;
seq_state <= SQ_LOAD1;
end else begin
op_read_addr <= seq_mat_base + MAT_STATUS_OFF;
op_start_read <= 1'b1;
seq_state <= SQ_WAIT_DONE;
end
end
end
SQ_LOAD1: begin
if (op_done) begin
op_write_addr <= seq_mat_base + MAT_CTRL_OFF;
op_write_data <= seq_start_value_for_loaded_bank;
op_start_write <= 1'b1;
seq_state <= SQ_START_NEXT;
end
end
SQ_WAIT_DONE: begin
if (op_done) begin
seq_status_data <= op_read_data;
if ((op_read_data & MAT_STATUS_DONE_BIT) != 32'd0) begin
seq_store_idx <= seq_group_idx;
if ((seq_group_idx + 32'd1) >= seq_groups) begin
op_src_addr <= seq_mat_base + (seq_compute_bank ? MAT_B1_C_OFF : MAT_B0_C_OFF);
op_dst_addr <= seq_dst_base + (seq_group_idx * seq_dst_stride);
op_bytes <= MAT_C_BYTES;
op_start_copy <= 1'b1;
seq_state <= SQ_STORE;
end else begin
op_write_addr <= seq_mat_base + MAT_STATUS_OFF;
op_write_data <= MAT_STATUS_DONE_CLR;
op_start_write <= 1'b1;
seq_state <= SQ_CLEAR_DONE;
end
end else begin
op_read_addr <= seq_mat_base + MAT_STATUS_OFF;
op_start_read <= 1'b1;
end
end
end
SQ_STORE: begin
if (op_done) begin
if ((seq_store_idx + 32'd1) >= seq_groups) begin
seq_state <= SQ_DONE;
end else if (seq_has_more_load) begin
op_src_addr <= seq_src_addr_for_load;
op_dst_addr <= seq_dst_addr_for_load;
op_bytes <= MAT_AB_BYTES;
op_start_copy <= 1'b1;
seq_load_idx <= seq_load_idx + 32'd1;
seq_state <= SQ_LOAD_NEXT;
end else begin
op_read_addr <= seq_mat_base + MAT_STATUS_OFF;
op_start_read <= 1'b1;
seq_state <= SQ_WAIT_DONE;
end
end
end
SQ_CLEAR_DONE: begin
if (op_done) begin
seq_group_idx <= seq_group_idx + 32'd1;
seq_compute_bank <= ~seq_compute_bank;
op_src_addr <= seq_src_addr_for_store;
op_dst_addr <= seq_dst_addr_for_store;
op_bytes <= MAT_C_BYTES;
op_start_copy <= 1'b1;
seq_state <= SQ_STORE;
end
end
SQ_START_NEXT: begin
if (op_done) begin
op_read_addr <= seq_mat_base + MAT_STATUS_OFF;
op_start_read <= 1'b1;
seq_state <= SQ_WAIT_DONE;
end
end
SQ_LOAD_NEXT: begin
if (op_done) begin
op_write_addr <= seq_mat_base + MAT_CTRL_OFF;
op_write_data <= seq_start_value_for_loaded_bank;
op_start_write <= 1'b1;
seq_state <= SQ_START_NEXT;
end
end
SQ_DONE: begin
seq_busy <= 1'b0;
seq_done_flag <= 1'b1;
seq_state <= SQ_IDLE;
end
default: seq_state <= SQ_IDLE;
endcase
end
end
// ==========================================
// Endpoint transfer engine (32-bit only in this SoC integration)
// ==========================================
typedef enum logic [2:0] {EP_IDLE, EP_AR, EP_READ, EP_AW, EP_WRITE, EP_BRESP, EP_DONE} ep_state_t;
ep_state_t ep_state;
logic [31:0] ep_axi_addr;
logic [31:0] ep_bytes_left;
logic [7:0] ep_word_addr_r;
wire [7:0] ep_beats_total = (engine_bytes[31:2] == 30'd0) ? 8'd1 : engine_bytes[9:2];
wire [7:0] ep_axi_len = ep_beats_total - 8'd1;
wire ep_mode_mem2ep = (engine_mode == MODE_MEM2EP);
wire ep_mode_ep2mem = (engine_mode == MODE_EP2MEM);
always_ff @(posedge clk) begin
if (!rst_n) begin
ep_state <= EP_IDLE;
ep_done <= 1'b0;
ep_axi_addr <= '0;
ep_bytes_left <= '0;
ep_word_addr_r <= '0;
end else begin
ep_done <= 1'b0;
case (ep_state)
EP_IDLE: begin
if (ep_start) begin
ep_axi_addr <= ep_mode_mem2ep ? engine_src : engine_dst;
ep_bytes_left <= engine_bytes;
ep_word_addr_r <= engine_ep_word_off;
ep_state <= ep_mode_mem2ep ? EP_AR : EP_AW;
end
end
EP_AR: begin
if (ep_arvalid && ep_arready)
ep_state <= EP_READ;
end
EP_READ: begin
if (mm2mm_rvalid && ep_rready) begin
ep_word_addr_r <= ep_word_addr_r + 8'd1;
ep_bytes_left <= (ep_bytes_left > 32'd4) ? (ep_bytes_left - 32'd4) : 32'd0;
if (mm2mm_rlast)
ep_state <= EP_DONE;
end
end
EP_AW: begin
if (ep_awvalid && ep_awready)
ep_state <= EP_WRITE;
end
EP_WRITE: begin
if (ep_wvalid && ep_wready) begin
ep_word_addr_r <= ep_word_addr_r + 8'd1;
ep_bytes_left <= (ep_bytes_left > 32'd4) ? (ep_bytes_left - 32'd4) : 32'd0;
if (ep_wlast)
ep_state <= EP_BRESP;
end
end
EP_BRESP: begin
if (mm2mm_bvalid && ep_bready)
ep_state <= EP_DONE;
end
EP_DONE: begin
ep_done <= 1'b1;
ep_state <= EP_IDLE;
end
default: ep_state <= EP_IDLE;
endcase
end
end
assign ep_arid = '0;
assign ep_araddr = ep_axi_addr;
assign ep_arlen = ep_axi_len;
assign ep_arsize = 3'd2;
assign ep_arburst = 2'b01;
assign ep_arlock = 1'b0;
assign ep_arcache = 4'b0;
assign ep_arprot = 3'b0;
assign ep_arqos = 4'b0;
assign ep_aruser = '0;
assign ep_arvalid = (ep_state == EP_AR);
assign ep_rready = (ep_state == EP_READ) && ep_wr_ready;
assign ep_wr_valid = (ep_state == EP_READ) && mm2mm_rvalid && ep_mode_mem2ep;
assign ep_wr_id = engine_ep_id;
assign ep_wr_bank = engine_ep_bank;
assign ep_wr_word_addr = ep_word_addr_r;
assign ep_wr_data = mm2mm_rdata[31:0];
assign ep_awid = '0;
assign ep_awaddr = ep_axi_addr;
assign ep_awlen = ep_axi_len;
assign ep_awsize = 3'd2;
assign ep_awburst = 2'b01;
assign ep_awlock = 1'b0;
assign ep_awcache = 4'b0;
assign ep_awprot = 3'b0;
assign ep_awqos = 4'b0;
assign ep_awuser = '0;
assign ep_awvalid = (ep_state == EP_AW);
assign ep_wdata = ep_rd_data;
assign ep_wstrb = {{(DATA_WIDTH/8){1'b1}}};
assign ep_wlast = (ep_bytes_left <= 32'd4) && ep_wvalid;
assign ep_wuser = '0;
assign ep_wvalid = (ep_state == EP_WRITE) && ep_mode_ep2mem && ep_rd_ready;
assign ep_bready = (ep_state == EP_BRESP);
assign ep_rd_valid = (ep_state == EP_WRITE) && ep_mode_ep2mem && ep_wready;
assign ep_rd_id = engine_ep_id;
assign ep_rd_bank = engine_ep_bank;
assign ep_rd_word_addr = ep_word_addr_r;
endmodule endmodule

View File

@@ -1,8 +1,6 @@
// ═══════════════════════════════════════════════════════ // 3-stage pipelined multiplier (LUT-based, no DSP)
// 3-stage pipelined multiplier (LUT-based, no DSP) // latency=3, throughput=1 result/cycle
// latency=3, throughput=1 result/cycle (* use_dsp = "no", use_dsp48 = "no", syn_multstyle = "logic" *)
// ═══════════════════════════════════════════════════════
(* use_dsp = "no" *)
module pipelined_mult_32x32 ( module pipelined_mult_32x32 (
input clk, input clk,
input rstn, input rstn,
@@ -11,8 +9,24 @@ module pipelined_mult_32x32 (
output reg [63:0] p output reg [63:0] p
); );
reg [31:0] a_r, b_r; reg [31:0] a_r, b_r;
(* use_dsp = "no", use_dsp48 = "no", syn_multstyle = "logic" *)
reg [63:0] prod; reg [63:0] prod;
function automatic [63:0] lut_mul32;
input [31:0] lhs;
input [31:0] rhs;
integer bit_idx;
reg [63:0] acc;
begin
acc = 64'b0;
for (bit_idx = 0; bit_idx < 32; bit_idx = bit_idx + 1) begin
if (rhs[bit_idx])
acc = acc + ({32'b0, lhs} << bit_idx);
end
lut_mul32 = acc;
end
endfunction
always @(posedge clk) begin always @(posedge clk) begin
if (!rstn) begin if (!rstn) begin
a_r <= 32'b0; b_r <= 32'b0; a_r <= 32'b0; b_r <= 32'b0;
@@ -20,16 +34,14 @@ module pipelined_mult_32x32 (
end else begin end else begin
a_r <= a; // Stage 1: register inputs a_r <= a; // Stage 1: register inputs
b_r <= b; b_r <= b;
prod <= a_r * b_r; // Stage 2: LUT-based multiply prod <= lut_mul32(a_r, b_r); // Stage 2: LUT-based multiply
p <= prod; // Stage 3: register output p <= prod; // Stage 3: register output
end end
end end
endmodule endmodule
// ═══════════════════════════════════════════════════════ // AXI Burst Slave + Ping-Pong + Stream CRC32
// 矩阵乘法器顶层模块 (AXI Burst Slave + Ping-Pong + Stream CRC32)
// ═══════════════════════════════════════════════════════
module matmul_axi_slave ( module matmul_axi_slave (
input clk, input clk,
input resetn, input resetn,
@@ -80,16 +92,63 @@ module matmul_axi_slave (
output reg s_axi_rvalid, output reg s_axi_rvalid,
input s_axi_rready, input s_axi_rready,
// AXI master port for autonomous matrix stream load/store
output reg [3:0] m_axi_awid,
output reg [31:0] m_axi_awaddr,
output reg [7:0] m_axi_awlen,
output reg [2:0] m_axi_awsize,
output reg [1:0] m_axi_awburst,
output reg m_axi_awlock,
output reg [3:0] m_axi_awcache,
output reg [2:0] m_axi_awprot,
output reg m_axi_awvalid,
input m_axi_awready,
output reg [31:0] m_axi_wdata,
output reg [3:0] m_axi_wstrb,
output reg m_axi_wlast,
output reg m_axi_wvalid,
input m_axi_wready,
input [3:0] m_axi_bid,
input [1:0] m_axi_bresp,
input m_axi_bvalid,
output reg m_axi_bready,
output reg [3:0] m_axi_arid,
output reg [31:0] m_axi_araddr,
output reg [7:0] m_axi_arlen,
output reg [2:0] m_axi_arsize,
output reg [1:0] m_axi_arburst,
output reg m_axi_arlock,
output reg [3:0] m_axi_arcache,
output reg [2:0] m_axi_arprot,
output reg m_axi_arvalid,
input m_axi_arready,
input [3:0] m_axi_rid,
input [31:0] m_axi_rdata,
input [1:0] m_axi_rresp,
input m_axi_rlast,
input m_axi_rvalid,
output reg m_axi_rready,
// Interrupt output (active high level, pulsed by calc_done) // Interrupt output (active high level, pulsed by calc_done)
output intr output intr
); );
// ========================================== // ==========================================
// 内存地址映射 (Memory Map) // Memory Map
// ========================================== // ==========================================
localparam ADDR_CTRL = 12'h000; localparam ADDR_CTRL = 12'h000;
localparam ADDR_STATUS = 12'h004; localparam ADDR_STATUS = 12'h004;
localparam ADDR_CRC = 12'h010; localparam ADDR_CRC = 12'h010;
localparam ADDR_DMA_SRC_BASE = 12'h020;
localparam ADDR_DMA_DST_BASE = 12'h024;
localparam ADDR_DMA_GROUPS = 12'h028;
localparam ADDR_DMA_SRC_STRIDE = 12'h02C;
localparam ADDR_DMA_DST_STRIDE = 12'h030;
localparam ADDR_DMA_CYCLES = 12'h034;
localparam ADDR_B0_A = 12'h100; localparam ADDR_B0_A = 12'h100;
localparam ADDR_B0_B = 12'h140; localparam ADDR_B0_B = 12'h140;
@@ -100,12 +159,13 @@ module matmul_axi_slave (
localparam ADDR_B1_C = 12'h380; localparam ADDR_B1_C = 12'h380;
// ========================================== // ==========================================
// 寄存器与数据缓冲 // Registers and data buffers
// ========================================== // ==========================================
reg req_0, req_1; reg req_0, req_1;
reg busy; reg busy;
reg done; reg [1:0] done_count;
reg error; reg error;
wire done = (done_count != 2'd0);
reg [31:0] b0_a [0:15]; reg [31:0] b0_a [0:15];
reg [31:0] b0_b [0:15]; reg [31:0] b0_b [0:15];
@@ -115,6 +175,74 @@ module matmul_axi_slave (
reg [31:0] b1_b [0:15]; reg [31:0] b1_b [0:15];
reg [65:0] b1_c [0:15]; reg [65:0] b1_c [0:15];
reg [31:0] dma_src_base;
reg [31:0] dma_dst_base;
reg [31:0] dma_groups;
reg [31:0] dma_src_stride;
reg [31:0] dma_dst_stride;
// Full sys_clk cycles spent in dma_busy; held after DMA completion.
reg [31:0] dma_cycle_count;
reg dma_busy;
reg dma_done;
reg dma_compute_complete;
reg [31:0] load_group;
reg [31:0] store_group;
reg [31:0] dma_next_rd_addr;
reg [31:0] dma_next_wr_addr;
reg [31:0] completed_groups;
reg [1:0] bank_loaded;
reg [1:0] bank_store_pending;
reg [1:0] bank_storing;
reg [1:0] bank_compute_pending;
reg dma_compute_bank;
reg dma_load_bank;
reg dma_store_bank;
reg dma_start_pulse;
reg dma_done_clear_pulse;
reg dma_req0_pulse;
reg dma_req1_pulse;
function [3:0] c_elem_from_word;
input [5:0] word_idx;
begin
case (word_idx)
6'd0, 6'd1, 6'd2: c_elem_from_word = 4'd0;
6'd3, 6'd4, 6'd5: c_elem_from_word = 4'd1;
6'd6, 6'd7, 6'd8: c_elem_from_word = 4'd2;
6'd9, 6'd10, 6'd11: c_elem_from_word = 4'd3;
6'd12, 6'd13, 6'd14: c_elem_from_word = 4'd4;
6'd15, 6'd16, 6'd17: c_elem_from_word = 4'd5;
6'd18, 6'd19, 6'd20: c_elem_from_word = 4'd6;
6'd21, 6'd22, 6'd23: c_elem_from_word = 4'd7;
6'd24, 6'd25, 6'd26: c_elem_from_word = 4'd8;
6'd27, 6'd28, 6'd29: c_elem_from_word = 4'd9;
6'd30, 6'd31, 6'd32: c_elem_from_word = 4'd10;
6'd33, 6'd34, 6'd35: c_elem_from_word = 4'd11;
6'd36, 6'd37, 6'd38: c_elem_from_word = 4'd12;
6'd39, 6'd40, 6'd41: c_elem_from_word = 4'd13;
6'd42, 6'd43, 6'd44: c_elem_from_word = 4'd14;
default: c_elem_from_word = 4'd15;
endcase
end
endfunction
function [1:0] c_part_from_word;
input [5:0] word_idx;
begin
case (word_idx)
6'd0, 6'd3, 6'd6, 6'd9,
6'd12, 6'd15, 6'd18, 6'd21,
6'd24, 6'd27, 6'd30, 6'd33,
6'd36, 6'd39, 6'd42, 6'd45: c_part_from_word = 2'd0;
6'd1, 6'd4, 6'd7, 6'd10,
6'd13, 6'd16, 6'd19, 6'd22,
6'd25, 6'd28, 6'd31, 6'd34,
6'd37, 6'd40, 6'd43, 6'd46: c_part_from_word = 2'd1;
default: c_part_from_word = 2'd2;
endcase
end
endfunction
function [31:0] apply_wstrb; function [31:0] apply_wstrb;
input [31:0] old_value; input [31:0] old_value;
input [31:0] new_value; input [31:0] new_value;
@@ -130,24 +258,70 @@ module matmul_axi_slave (
// ========================================== // ==========================================
// CRC32 Engine (IEEE 802.3, polynomial 0xEDB88320) // CRC32 Engine (IEEE 802.3, polynomial 0xEDB88320)
//
// AXI-stream: single-cycle crc32_update_word (4 LUT lookup depth, ok for
// AXI timing—the bus runs at or below internal compute rate).
// DMA-calc: two 6-byte CRC steps per 66-bit C-element. A result FIFO
// absorbs the 16-cycle compute burst so the recursive CRC state never
// backpressures the multiplier under the normal DMA load cadence.
// ========================================== // ==========================================
reg [31:0] crc32_table [0:255]; reg [31:0] crc32_table [0:255];
reg [31:0] crc_reg; reg [31:0] crc_reg;
// ---- AXI-stream CRC (single-cycle) ----------------------------------
wire [31:0] crc_stream_data = s_axi_rdata; wire [31:0] crc_stream_data = s_axi_rdata;
wire crc_stream_valid = (r_state == R_DATA) && s_axi_rvalid && s_axi_rready && wire crc_axi_valid = (r_state == R_DATA) && s_axi_rvalid && s_axi_rready &&
((r_offset >= ADDR_B0_C && r_offset < (ADDR_B0_C + 12'h0C0)) || ((r_offset >= ADDR_B0_C && r_offset < (ADDR_B0_C + 12'h0C0)) ||
(r_offset >= ADDR_B1_C && r_offset < (ADDR_B1_C + 12'h0C0))); (r_offset >= ADDR_B1_C && r_offset < (ADDR_B1_C + 12'h0C0)));
wire crc_stream_valid = crc_axi_valid;
wire [31:0] crc_next = crc32_update_word(crc_reg, crc_stream_data);
wire [31:0] crc_t0, crc_c0, crc_t1, crc_c1, crc_t2, crc_c2, crc_t3, crc_next; function [31:0] crc32_update_word;
assign crc_t0 = crc32_table[(crc_reg[7:0] ^ crc_stream_data[7:0])]; input [31:0] crc_in;
assign crc_c0 = crc_t0 ^ {8'h00, crc_reg[31:8]}; input [31:0] data_in;
assign crc_t1 = crc32_table[(crc_c0[7:0] ^ crc_stream_data[15:8])]; reg [31:0] c0;
assign crc_c1 = crc_t1 ^ {8'h00, crc_c0[31:8]}; reg [31:0] c1;
assign crc_t2 = crc32_table[(crc_c1[7:0] ^ crc_stream_data[23:16])]; reg [31:0] c2;
assign crc_c2 = crc_t2 ^ {8'h00, crc_c1[31:8]}; begin
assign crc_t3 = crc32_table[(crc_c2[7:0] ^ crc_stream_data[31:24])]; c0 = crc32_table[(crc_in[7:0] ^ data_in[7:0])] ^ {8'h00, crc_in[31:8]};
assign crc_next = crc_t3 ^ {8'h00, crc_c2[31:8]}; c1 = crc32_table[(c0[7:0] ^ data_in[15:8])] ^ {8'h00, c0[31:8]};
c2 = crc32_table[(c1[7:0] ^ data_in[23:16])] ^ {8'h00, c1[31:8]};
crc32_update_word = crc32_table[(c2[7:0] ^ data_in[31:24])] ^ {8'h00, c2[31:8]};
end
endfunction
function [31:0] crc32_update_6bytes;
input [31:0] crc_in;
input [47:0] data_in;
reg [31:0] c;
integer byte_idx;
begin
c = crc_in;
for (byte_idx = 0; byte_idx < 6; byte_idx = byte_idx + 1)
c = crc32_table[(c[7:0] ^ data_in[byte_idx*8 +: 8])] ^
{8'h00, c[31:8]};
crc32_update_6bytes = c;
end
endfunction
// ---- DMA result FIFO and two-cycle recursive CRC consumer -----------
localparam CRC_FIFO_DEPTH = 32;
reg [65:0] crc_fifo [0:CRC_FIFO_DEPTH-1];
reg [4:0] crc_fifo_wr_ptr;
reg [4:0] crc_fifo_rd_ptr;
reg [5:0] crc_fifo_count;
reg crc_c66_busy;
reg [65:0] crc_c66_data;
reg [31:0] crc_c66_half;
wire crc_fifo_empty = (crc_fifo_count == 6'd0);
wire crc_fifo_push = dma_busy && acc_valid_d4;
wire crc_fifo_pop = !crc_c66_busy && !crc_fifo_empty;
wire [31:0] crc_c66_first_next =
crc32_update_6bytes(crc_reg, crc_fifo[crc_fifo_rd_ptr][47:0]);
wire [47:0] crc_c66_second_data = {30'b0, crc_c66_data[65:48]};
wire [31:0] crc_c66_final_next =
crc32_update_6bytes(crc_c66_half, crc_c66_second_data);
initial begin initial begin
crc32_table[0 ] = 32'h00000000; crc32_table[1 ] = 32'h77073096; crc32_table[0 ] = 32'h00000000; crc32_table[1 ] = 32'h77073096;
@@ -281,7 +455,7 @@ module matmul_axi_slave (
end end
// ========================================== // ==========================================
// AXI Write 通道逻辑 (支持 INCR Burst) // AXI Write (INCR Burst)
// ========================================== // ==========================================
localparam W_IDLE = 2'd0; localparam W_IDLE = 2'd0;
localparam W_DATA = 2'd1; localparam W_DATA = 2'd1;
@@ -297,15 +471,40 @@ module matmul_axi_slave (
assign s_axi_bid = w_id; assign s_axi_bid = w_id;
assign s_axi_bresp = 2'b00; assign s_axi_bresp = 2'b00;
// 前向声明引擎的状态
localparam C_IDLE = 2'd0; localparam C_IDLE = 2'd0;
localparam C_RUN = 2'd1; localparam C_RUN = 2'd1;
reg [1:0] state; reg [1:0] state;
reg cur_bank; reg cur_bank;
reg calc_done_pulse; reg calc_done_pulse;
// 【修改点 1】单独引出一个写脉冲信号给 CRC 清零用 localparam DMA_RD_IDLE = 2'd0;
localparam DMA_RD_ADDR = 2'd1;
localparam DMA_RD_DATA = 2'd2;
reg [1:0] dma_rd_state;
reg [7:0] dma_rd_count;
reg dma_rd_bank;
wire [4:0] dma_rd_group_word_idx = dma_rd_count[4:0];
wire [3:0] dma_rd_word_idx = dma_rd_count[3:0];
wire dma_rd_fill_bank = dma_rd_bank ^ dma_rd_count[5];
wire dma_rd_commit = (dma_rd_state == DMA_RD_DATA) && m_axi_rvalid && m_axi_rready;
wire dma_bank0_free = !bank_loaded[0] && !bank_compute_pending[0] && !req_0 &&
!(state == C_RUN && cur_bank == 1'b0);
wire dma_bank1_free = !bank_loaded[1] && !bank_compute_pending[1] && !req_1 &&
!(state == C_RUN && cur_bank == 1'b1);
wire dma_load_bank_free = dma_load_bank ? dma_bank1_free : dma_bank0_free;
wire dma_rd_fill_bank_free = dma_rd_fill_bank ? dma_bank1_free : dma_bank0_free;
wire dma_rd_next_bank_free = dma_rd_fill_bank ? dma_bank0_free : dma_bank1_free;
localparam DMA_WR_IDLE = 2'd0;
localparam DMA_WR_ADDR = 2'd1;
localparam DMA_WR_DATA = 2'd2;
localparam DMA_WR_RESP = 2'd3;
reg [1:0] dma_wr_state;
reg [5:0] dma_wr_count;
wire crc_clear_pulse = (w_state == W_DATA) && s_axi_wvalid && s_axi_wready && (w_offset == ADDR_CRC); wire crc_clear_pulse = (w_state == W_DATA) && s_axi_wvalid && s_axi_wready && (w_offset == ADDR_CRC);
wire done_clear_pulse = (w_state == W_DATA) && s_axi_wvalid && s_axi_wready &&
(w_offset == ADDR_STATUS) && s_axi_wdata[1];
always @(posedge clk) begin always @(posedge clk) begin
if (!resetn) begin if (!resetn) begin
@@ -315,15 +514,37 @@ module matmul_axi_slave (
s_axi_bvalid <= 1'b0; s_axi_bvalid <= 1'b0;
req_0 <= 1'b0; req_0 <= 1'b0;
req_1 <= 1'b0; req_1 <= 1'b0;
done <= 1'b0; done_count <= 2'd0;
error <= 1'b0; error <= 1'b0;
dma_src_base <= 32'd0;
dma_dst_base <= 32'd0;
dma_groups <= 32'd0;
dma_src_stride <= 32'd128;
dma_dst_stride <= 32'd192;
dma_start_pulse <= 1'b0;
dma_done_clear_pulse <= 1'b0;
end else begin end else begin
dma_start_pulse <= 1'b0;
dma_done_clear_pulse <= 1'b0;
if (dma_rd_commit) begin
if (dma_rd_fill_bank == 1'b0) begin
if (dma_rd_group_word_idx < 5'd16)
b0_a[dma_rd_word_idx] <= m_axi_rdata;
else
b0_b[dma_rd_word_idx] <= m_axi_rdata;
end else begin
if (dma_rd_group_word_idx < 5'd16)
b1_a[dma_rd_word_idx] <= m_axi_rdata;
else
b1_b[dma_rd_word_idx] <= m_axi_rdata;
end
end
if (req_0 && state == C_RUN && cur_bank == 1'b0) req_0 <= 1'b0; if (req_0 && state == C_RUN && cur_bank == 1'b0) req_0 <= 1'b0;
if (req_1 && state == C_RUN && cur_bank == 1'b1) req_1 <= 1'b0; if (req_1 && state == C_RUN && cur_bank == 1'b1) req_1 <= 1'b0;
if (dma_req0_pulse) req_0 <= 1'b1;
if (calc_done_pulse) begin if (dma_req1_pulse) req_1 <= 1'b1;
done <= 1'b1;
end
case (w_state) case (w_state)
W_IDLE: begin W_IDLE: begin
@@ -342,12 +563,23 @@ module matmul_axi_slave (
if (w_offset == ADDR_CTRL) begin if (w_offset == ADDR_CTRL) begin
if (s_axi_wdata[0]) req_0 <= 1'b1; if (s_axi_wdata[0]) req_0 <= 1'b1;
if (s_axi_wdata[1]) req_1 <= 1'b1; if (s_axi_wdata[1]) req_1 <= 1'b1;
if (s_axi_wdata[8]) dma_start_pulse <= 1'b1;
end end
else if (w_offset == ADDR_STATUS) begin else if (w_offset == ADDR_STATUS) begin
if (s_axi_wdata[1]) done <= 1'b0;
if (s_axi_wdata[2]) error <= 1'b0; if (s_axi_wdata[2]) error <= 1'b0;
if (s_axi_wdata[4]) dma_done_clear_pulse <= 1'b1;
end end
// 【修改点 2】删除 else if (w_offset == ADDR_CRC) { crc_reg <= ... } 防止多重驱动 else if (w_offset == ADDR_DMA_SRC_BASE)
dma_src_base <= apply_wstrb(dma_src_base, s_axi_wdata, s_axi_wstrb);
else if (w_offset == ADDR_DMA_DST_BASE)
dma_dst_base <= apply_wstrb(dma_dst_base, s_axi_wdata, s_axi_wstrb);
else if (w_offset == ADDR_DMA_GROUPS)
dma_groups <= apply_wstrb(dma_groups, s_axi_wdata, s_axi_wstrb);
else if (w_offset == ADDR_DMA_SRC_STRIDE)
dma_src_stride <= apply_wstrb(dma_src_stride, s_axi_wdata, s_axi_wstrb);
else if (w_offset == ADDR_DMA_DST_STRIDE)
dma_dst_stride <= apply_wstrb(dma_dst_stride, s_axi_wdata, s_axi_wstrb);
// CRC register is now managed by the pipelined CRC engine
else if (w_offset >= ADDR_B0_A && w_offset < ADDR_B0_B) else if (w_offset >= ADDR_B0_A && w_offset < ADDR_B0_B)
b0_a[(w_offset - ADDR_B0_A) >> 2] <= apply_wstrb(b0_a[(w_offset - ADDR_B0_A) >> 2], s_axi_wdata, s_axi_wstrb); b0_a[(w_offset - ADDR_B0_A) >> 2] <= apply_wstrb(b0_a[(w_offset - ADDR_B0_A) >> 2], s_axi_wdata, s_axi_wstrb);
else if (w_offset >= ADDR_B0_B && w_offset < ADDR_B0_C) else if (w_offset >= ADDR_B0_B && w_offset < ADDR_B0_C)
@@ -378,11 +610,17 @@ module matmul_axi_slave (
end end
default: w_state <= W_IDLE; default: w_state <= W_IDLE;
endcase endcase
case ({calc_done_pulse, done_clear_pulse})
2'b10: if (done_count != 2'd3) done_count <= done_count + 2'd1;
2'b01: if (done_count != 2'd0) done_count <= done_count - 2'd1;
default: done_count <= done_count;
endcase
end end
end end
// ========================================== // ==========================================
// AXI Read 通道逻辑 (支持 INCR Burst) // AXI Read (INCR Burst)
// ========================================== // ==========================================
localparam R_IDLE = 2'd0; localparam R_IDLE = 2'd0;
localparam R_DATA = 2'd1; localparam R_DATA = 2'd1;
@@ -397,13 +635,13 @@ module matmul_axi_slave (
assign s_axi_rresp = 2'b00; assign s_axi_rresp = 2'b00;
wire [5:0] c0_offset = (r_offset - ADDR_B0_C) >> 2; wire [5:0] c0_offset = (r_offset - ADDR_B0_C) >> 2;
wire [3:0] c0_elem = c0_offset / 3; wire [3:0] c0_elem = c_elem_from_word(c0_offset);
wire [1:0] c0_part = c0_offset % 3; wire [1:0] c0_part = c_part_from_word(c0_offset);
wire [65:0] target_c0 = b0_c[c0_elem]; wire [65:0] target_c0 = b0_c[c0_elem];
wire [5:0] c1_offset = (r_offset - ADDR_B1_C) >> 2; wire [5:0] c1_offset = (r_offset - ADDR_B1_C) >> 2;
wire [3:0] c1_elem = c1_offset / 3; wire [3:0] c1_elem = c_elem_from_word(c1_offset);
wire [1:0] c1_part = c1_offset % 3; wire [1:0] c1_part = c_part_from_word(c1_offset);
wire [65:0] target_c1 = b1_c[c1_elem]; wire [65:0] target_c1 = b1_c[c1_elem];
wire crc_read_en = (r_offset >= ADDR_B0_C && r_offset < (ADDR_B0_C + 12'h0C0)) || wire crc_read_en = (r_offset >= ADDR_B0_C && r_offset < (ADDR_B0_C + 12'h0C0)) ||
@@ -434,7 +672,6 @@ module matmul_axi_slave (
end end
R_DATA: begin R_DATA: begin
if (s_axi_rvalid && s_axi_rready) begin if (s_axi_rvalid && s_axi_rready) begin
// 【修改点 3】删掉直接赋值 crc_stream_valid 的逻辑,移至专用 Pipeline 块
if (r_cnt == r_len) begin if (r_cnt == r_len) begin
s_axi_rvalid <= 1'b0; s_axi_rvalid <= 1'b0;
s_axi_rlast <= 1'b0; s_axi_rlast <= 1'b0;
@@ -462,7 +699,20 @@ module matmul_axi_slave (
else if (current_r_offset == ADDR_CRC) else if (current_r_offset == ADDR_CRC)
s_axi_rdata = crc_reg ^ 32'hFFFFFFFF; s_axi_rdata = crc_reg ^ 32'hFFFFFFFF;
else if (current_r_offset == ADDR_STATUS) else if (current_r_offset == ADDR_STATUS)
s_axi_rdata = {29'b0, error, done, busy}; s_axi_rdata = {26'b0, (crc_c66_busy || !crc_fifo_empty),
dma_done, dma_busy, error, done, busy};
else if (current_r_offset == ADDR_DMA_SRC_BASE)
s_axi_rdata = dma_src_base;
else if (current_r_offset == ADDR_DMA_DST_BASE)
s_axi_rdata = dma_dst_base;
else if (current_r_offset == ADDR_DMA_GROUPS)
s_axi_rdata = dma_groups;
else if (current_r_offset == ADDR_DMA_SRC_STRIDE)
s_axi_rdata = dma_src_stride;
else if (current_r_offset == ADDR_DMA_DST_STRIDE)
s_axi_rdata = dma_dst_stride;
else if (current_r_offset == ADDR_DMA_CYCLES)
s_axi_rdata = dma_cycle_count;
else if (current_r_offset >= ADDR_B0_A && current_r_offset < ADDR_B0_B) else if (current_r_offset >= ADDR_B0_A && current_r_offset < ADDR_B0_B)
s_axi_rdata = b0_a[(current_r_offset - ADDR_B0_A) >> 2]; s_axi_rdata = b0_a[(current_r_offset - ADDR_B0_A) >> 2];
else if (current_r_offset >= ADDR_B0_B && current_r_offset < ADDR_B0_C) else if (current_r_offset >= ADDR_B0_B && current_r_offset < ADDR_B0_C)
@@ -484,19 +734,8 @@ module matmul_axi_slave (
end end
end end
// CRC register: update on each C data read beat, clear on write to 0x010
always @(posedge clk) begin
if (!resetn) begin
crc_reg <= 32'hFFFFFFFF;
end else if (crc_clear_pulse) begin
crc_reg <= 32'hFFFFFFFF;
end else if (crc_stream_valid) begin
crc_reg <= crc_next;
end
end
// ========================================== // ==========================================
// 计算引擎 (Compute FSM) // Compute FSM
// ========================================== // ==========================================
wire [63:0] mult_p [0:3]; wire [63:0] mult_p [0:3];
reg [31:0] m_in_a [0:3]; reg [31:0] m_in_a [0:3];
@@ -518,7 +757,82 @@ module matmul_axi_slave (
// Pipeline delay shift registers for accumulation (4 stages = 3 multiplier pipe + 1) // Pipeline delay shift registers for accumulation (4 stages = 3 multiplier pipe + 1)
reg [3:0] acc_idx_d1, acc_idx_d2, acc_idx_d3, acc_idx_d4; reg [3:0] acc_idx_d1, acc_idx_d2, acc_idx_d3, acc_idx_d4;
reg acc_bank_d1, acc_bank_d2, acc_bank_d3, acc_bank_d4; reg acc_bank_d1, acc_bank_d2, acc_bank_d3, acc_bank_d4;
reg acc_valid_d1, acc_valid_d2, acc_valid_d3, acc_valid_d4;
reg [4:0] pipe_cnt; reg [4:0] pipe_cnt;
wire [65:0] acc_result = ({2'b0, mult_p[0]} + {2'b0, mult_p[1]}) +
({2'b0, mult_p[2]} + {2'b0, mult_p[3]});
// Leave eight entries for results already in the multiplier pipeline.
// Under the normal DMA cadence the FIFO stays well below this threshold.
wire dma_crc_issue_ready = !dma_busy || (crc_fifo_count < 6'd24);
// DMA CRC takes priority over the software-driven AXI read stream.
always @(posedge clk) begin
if (!resetn) begin
crc_reg <= 32'hFFFFFFFF;
crc_fifo_wr_ptr <= 5'd0;
crc_fifo_rd_ptr <= 5'd0;
crc_fifo_count <= 6'd0;
crc_c66_busy <= 1'b0;
crc_c66_data <= 66'd0;
crc_c66_half <= 32'd0;
end else if (crc_clear_pulse) begin
crc_reg <= 32'hFFFFFFFF;
crc_fifo_wr_ptr <= 5'd0;
crc_fifo_rd_ptr <= 5'd0;
crc_fifo_count <= 6'd0;
crc_c66_busy <= 1'b0;
crc_c66_data <= 66'd0;
crc_c66_half <= 32'd0;
end else begin
if (crc_fifo_push) begin
crc_fifo[crc_fifo_wr_ptr] <= acc_result;
crc_fifo_wr_ptr <= crc_fifo_wr_ptr + 5'd1;
end
case ({crc_fifo_push, crc_fifo_pop})
2'b10: crc_fifo_count <= crc_fifo_count + 6'd1;
2'b01: crc_fifo_count <= crc_fifo_count - 6'd1;
default: crc_fifo_count <= crc_fifo_count;
endcase
if (crc_c66_busy) begin
crc_reg <= crc_c66_final_next;
crc_c66_busy <= 1'b0;
end else if (crc_fifo_pop) begin
crc_c66_data <= crc_fifo[crc_fifo_rd_ptr];
crc_c66_half <= crc_c66_first_next;
crc_c66_busy <= 1'b1;
crc_fifo_rd_ptr <= crc_fifo_rd_ptr + 5'd1;
end else if (crc_stream_valid) begin
crc_reg <= crc_next;
end
end
end
task start_calc_bank;
input bank;
begin
cur_bank <= bank;
busy <= 1'b1;
state <= C_RUN;
pipe_cnt <= 5'd1;
acc_idx_d1 <= 4'd0;
acc_bank_d1 <= bank;
acc_valid_d1 <= 1'b1;
if (bank == 1'b0) begin
m_in_a[0] <= b0_a[4'd0]; m_in_b[0] <= b0_b[4'd0];
m_in_a[1] <= b0_a[4'd1]; m_in_b[1] <= b0_b[4'd4];
m_in_a[2] <= b0_a[4'd2]; m_in_b[2] <= b0_b[4'd8];
m_in_a[3] <= b0_a[4'd3]; m_in_b[3] <= b0_b[4'd12];
end else begin
m_in_a[0] <= b1_a[4'd0]; m_in_b[0] <= b1_b[4'd0];
m_in_a[1] <= b1_a[4'd1]; m_in_b[1] <= b1_b[4'd4];
m_in_a[2] <= b1_a[4'd2]; m_in_b[2] <= b1_b[4'd8];
m_in_a[3] <= b1_a[4'd3]; m_in_b[3] <= b1_b[4'd12];
end
end
endtask
always @(posedge clk) begin always @(posedge clk) begin
if (!resetn) begin if (!resetn) begin
@@ -535,73 +849,334 @@ module matmul_axi_slave (
acc_bank_d2 <= 1'b0; acc_bank_d2 <= 1'b0;
acc_bank_d3 <= 1'b0; acc_bank_d3 <= 1'b0;
acc_bank_d4 <= 1'b0; acc_bank_d4 <= 1'b0;
acc_valid_d1 <= 1'b0;
acc_valid_d2 <= 1'b0;
acc_valid_d3 <= 1'b0;
acc_valid_d4 <= 1'b0;
end else begin end else begin
calc_done_pulse <= 1'b0; calc_done_pulse <= 1'b0;
// Pipeline shift: issue_idx → d1 → d2 → d3 → d4 (4 cycles total) // Pipeline shift (4 cycles total)
acc_idx_d4 <= acc_idx_d3; acc_idx_d4 <= acc_idx_d3;
acc_idx_d3 <= acc_idx_d2; acc_idx_d3 <= acc_idx_d2;
acc_idx_d2 <= acc_idx_d1; acc_idx_d2 <= acc_idx_d1;
acc_idx_d1 <= pipe_cnt[3:0]; acc_idx_d1 <= 4'd0;
acc_bank_d4 <= acc_bank_d3; acc_bank_d4 <= acc_bank_d3;
acc_bank_d3 <= acc_bank_d2; acc_bank_d3 <= acc_bank_d2;
acc_bank_d2 <= acc_bank_d1; acc_bank_d2 <= acc_bank_d1;
acc_bank_d1 <= cur_bank; acc_bank_d1 <= 1'b0;
acc_valid_d4 <= acc_valid_d3;
acc_valid_d3 <= acc_valid_d2;
acc_valid_d2 <= acc_valid_d1;
acc_valid_d1 <= 1'b0;
case (state) case (state)
C_IDLE: begin C_IDLE: begin
pipe_cnt <= 5'd0;
if (req_0) begin if (req_0) begin
cur_bank <= 1'b0; start_calc_bank(1'b0);
busy <= 1'b1;
state <= C_RUN;
end else if (req_1) begin end else if (req_1) begin
cur_bank <= 1'b1; start_calc_bank(1'b1);
busy <= 1'b1;
state <= C_RUN;
end else begin end else begin
pipe_cnt <= 5'd0;
busy <= 1'b0; busy <= 1'b0;
end end
end end
C_RUN: begin C_RUN: begin
// Issue 4 new operands every cycle (pipe_cnt 0-15, 16 rounds) // Issue one C element per cycle unless the CRC FIFO is
// approaching capacity.
if (pipe_cnt < 5'd16) begin if (pipe_cnt < 5'd16) begin
if (cur_bank == 1'b0) begin if (dma_crc_issue_ready) begin
m_in_a[0] <= b0_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b0_b[{2'd0, pipe_cnt[1:0]}]; acc_idx_d1 <= pipe_cnt[3:0];
m_in_a[1] <= b0_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b0_b[{2'd1, pipe_cnt[1:0]}]; acc_bank_d1 <= cur_bank;
m_in_a[2] <= b0_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b0_b[{2'd2, pipe_cnt[1:0]}]; acc_valid_d1 <= 1'b1;
m_in_a[3] <= b0_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b0_b[{2'd3, pipe_cnt[1:0]}]; if (cur_bank == 1'b0) begin
end else begin m_in_a[0] <= b0_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b0_b[{2'd0, pipe_cnt[1:0]}];
m_in_a[0] <= b1_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b1_b[{2'd0, pipe_cnt[1:0]}]; m_in_a[1] <= b0_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b0_b[{2'd1, pipe_cnt[1:0]}];
m_in_a[1] <= b1_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b1_b[{2'd1, pipe_cnt[1:0]}]; m_in_a[2] <= b0_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b0_b[{2'd2, pipe_cnt[1:0]}];
m_in_a[2] <= b1_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b1_b[{2'd2, pipe_cnt[1:0]}]; m_in_a[3] <= b0_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b0_b[{2'd3, pipe_cnt[1:0]}];
m_in_a[3] <= b1_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b1_b[{2'd3, pipe_cnt[1:0]}]; end else begin
m_in_a[0] <= b1_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b1_b[{2'd0, pipe_cnt[1:0]}];
m_in_a[1] <= b1_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b1_b[{2'd1, pipe_cnt[1:0]}];
m_in_a[2] <= b1_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b1_b[{2'd2, pipe_cnt[1:0]}];
m_in_a[3] <= b1_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b1_b[{2'd3, pipe_cnt[1:0]}];
end
pipe_cnt <= pipe_cnt + 5'd1;
end end
end end
// Accumulate results from 4 cycles ago (pipe_cnt 4-19) // Accumulate results from 4 cycles ago.
if (pipe_cnt >= 5'd4 && pipe_cnt < 5'd20) begin if (acc_valid_d4) begin
if (acc_bank_d4 == 1'b0) if (acc_bank_d4 == 1'b0)
b0_c[acc_idx_d4] <= ({2'b0, mult_p[0]} + {2'b0, mult_p[1]}) + b0_c[acc_idx_d4] <= acc_result;
({2'b0, mult_p[2]} + {2'b0, mult_p[3]});
else else
b1_c[acc_idx_d4] <= ({2'b0, mult_p[0]} + {2'b0, mult_p[1]}) + b1_c[acc_idx_d4] <= acc_result;
({2'b0, mult_p[2]} + {2'b0, mult_p[3]});
end end
if (pipe_cnt == 5'd20) begin if (acc_valid_d4 && acc_idx_d4 == 4'd15) begin
calc_done_pulse <= 1'b1; calc_done_pulse <= 1'b1;
busy <= 1'b0; end
state <= C_IDLE;
end else begin if (pipe_cnt >= 5'd16) begin
pipe_cnt <= pipe_cnt + 5'd1; if (dma_busy) begin
if (acc_valid_d4 && acc_idx_d4 == 4'd15) begin
if (cur_bank == 1'b0 && req_1)
start_calc_bank(1'b1);
else if (cur_bank == 1'b1 && req_0)
start_calc_bank(1'b0);
else begin
busy <= 1'b0;
state <= C_IDLE;
end
end else begin
pipe_cnt <= pipe_cnt + 5'd1;
end
end else if (cur_bank == 1'b0 && req_1) begin
start_calc_bank(1'b1);
end else if (cur_bank == 1'b1 && req_0) begin
start_calc_bank(1'b0);
end else if (acc_valid_d4 && acc_idx_d4 == 4'd15) begin
busy <= 1'b0;
state <= C_IDLE;
end else begin
pipe_cnt <= pipe_cnt + 5'd1;
end
end end
end end
endcase endcase
end end
end end
// ==========================================
// Autonomous AXI master loader with inline result CRC.
// ==========================================
always @(posedge clk) begin
if (!resetn) begin
dma_busy <= 1'b0;
dma_done <= 1'b0;
dma_compute_complete <= 1'b0;
dma_cycle_count <= 32'd0;
load_group <= 32'd0;
store_group <= 32'd0;
dma_next_rd_addr <= 32'd0;
dma_next_wr_addr <= 32'd0;
completed_groups <= 32'd0;
bank_loaded <= 2'b00;
bank_store_pending <= 2'b00;
bank_storing <= 2'b00;
bank_compute_pending <= 2'b00;
dma_compute_bank <= 1'b0;
dma_load_bank <= 1'b0;
dma_store_bank <= 1'b0;
dma_rd_state <= DMA_RD_IDLE;
dma_rd_count <= 8'd0;
dma_rd_bank <= 1'b0;
dma_wr_state <= DMA_WR_IDLE;
dma_wr_count <= 6'd0;
m_axi_arid <= 4'd0;
m_axi_araddr <= 32'd0;
m_axi_arlen <= 8'd31;
m_axi_arsize <= 3'd2;
m_axi_arburst <= 2'b01;
m_axi_arlock <= 1'b0;
m_axi_arcache <= 4'b0;
m_axi_arprot <= 3'b0;
m_axi_arvalid <= 1'b0;
m_axi_rready <= 1'b0;
m_axi_awid <= 4'd0;
m_axi_awaddr <= 32'd0;
m_axi_awlen <= 8'd47;
m_axi_awsize <= 3'd2;
m_axi_awburst <= 2'b01;
m_axi_awlock <= 1'b0;
m_axi_awcache <= 4'b0;
m_axi_awprot <= 3'b0;
m_axi_awvalid <= 1'b0;
m_axi_wdata <= 32'd0;
m_axi_wstrb <= 4'hF;
m_axi_wlast <= 1'b0;
m_axi_wvalid <= 1'b0;
m_axi_bready <= 1'b0;
dma_req0_pulse <= 1'b0;
dma_req1_pulse <= 1'b0;
end else begin
dma_req0_pulse <= 1'b0;
dma_req1_pulse <= 1'b0;
if (dma_done_clear_pulse)
dma_done <= 1'b0;
if (dma_start_pulse && !dma_busy && dma_groups != 32'd0) begin
dma_busy <= 1'b1;
dma_done <= 1'b0;
dma_compute_complete <= 1'b0;
dma_cycle_count <= 32'd0;
load_group <= 32'd0;
store_group <= 32'd0;
dma_next_rd_addr <= dma_src_base;
dma_next_wr_addr <= dma_dst_base;
completed_groups <= 32'd0;
bank_loaded <= 2'b00;
bank_store_pending <= 2'b00;
bank_storing <= 2'b00;
bank_compute_pending <= 2'b00;
dma_compute_bank <= 1'b0;
dma_load_bank <= 1'b0;
dma_store_bank <= 1'b0;
dma_rd_state <= DMA_RD_IDLE;
dma_wr_state <= DMA_WR_IDLE;
end else if (dma_busy) begin
dma_cycle_count <= dma_cycle_count + 32'd1;
end
if (dma_busy) begin
if (state == C_RUN)
bank_compute_pending[cur_bank] <= 1'b0;
if (bank_loaded[0] && !req_0 &&
!bank_compute_pending[0] && !(state == C_RUN && cur_bank == 1'b0)) begin
dma_req0_pulse <= 1'b1;
bank_loaded[0] <= 1'b0;
bank_compute_pending[0] <= 1'b1;
dma_compute_bank <= 1'b0;
end else if (bank_loaded[1] && !req_1 &&
!bank_compute_pending[1] && !(state == C_RUN && cur_bank == 1'b1)) begin
dma_req1_pulse <= 1'b1;
bank_loaded[1] <= 1'b0;
bank_compute_pending[1] <= 1'b1;
dma_compute_bank <= 1'b1;
end
end
if (calc_done_pulse && dma_busy) begin
store_group <= store_group + 32'd1;
completed_groups <= completed_groups + 32'd1;
if ((completed_groups + 32'd1) >= dma_groups)
dma_compute_complete <= 1'b1;
end
if (dma_compute_complete && crc_fifo_empty && !crc_c66_busy) begin
dma_busy <= 1'b0;
dma_done <= 1'b1;
dma_compute_complete <= 1'b0;
end
case (dma_rd_state)
DMA_RD_IDLE: begin
m_axi_arvalid <= 1'b0;
m_axi_rready <= 1'b0;
if (dma_busy && load_group < dma_groups && dma_load_bank_free) begin
dma_rd_bank <= dma_load_bank;
dma_rd_count <= 8'd0;
m_axi_araddr <= dma_next_rd_addr;
m_axi_arlen <= ((dma_src_stride == 32'd128) &&
((dma_groups - load_group) >= 32'd8)) ? 8'd255 : 8'd31;
m_axi_arsize <= 3'd2;
m_axi_arburst <= 2'b01;
m_axi_arvalid <= 1'b1;
dma_rd_state <= DMA_RD_ADDR;
end
end
DMA_RD_ADDR: begin
if (m_axi_arvalid && m_axi_arready) begin
m_axi_arvalid <= 1'b0;
m_axi_rready <= 1'b1;
dma_rd_state <= DMA_RD_DATA;
end
end
DMA_RD_DATA: begin
if (!m_axi_rready && dma_rd_fill_bank_free)
m_axi_rready <= 1'b1;
if (m_axi_rvalid && m_axi_rready) begin
// Present the next request one beat early so the SRAM
// slave can accept it together with the current RLAST.
if ((dma_rd_count == 8'd254) && dma_busy &&
((load_group + 32'd1) < dma_groups) && dma_rd_next_bank_free) begin
m_axi_araddr <= dma_next_rd_addr + dma_src_stride;
m_axi_arlen <= ((dma_src_stride == 32'd128) &&
((dma_groups - (load_group + 32'd1)) >= 32'd8)) ?
8'd255 : 8'd31;
m_axi_arvalid <= 1'b1;
end
if (dma_rd_group_word_idx == 5'd31) begin
bank_loaded[dma_rd_fill_bank] <= 1'b1;
load_group <= load_group + 32'd1;
dma_next_rd_addr <= dma_next_rd_addr + dma_src_stride;
dma_load_bank <= ~dma_load_bank;
end
if (m_axi_rlast) begin
m_axi_rready <= 1'b0;
if (dma_busy && ((load_group + 32'd1) < dma_groups) &&
dma_rd_next_bank_free) begin
dma_rd_bank <= ~dma_rd_fill_bank;
dma_rd_count <= 8'd0;
if (m_axi_arvalid && m_axi_arready) begin
m_axi_arvalid <= 1'b0;
m_axi_rready <= 1'b1;
dma_rd_state <= DMA_RD_DATA;
end else begin
m_axi_araddr <= dma_next_rd_addr + dma_src_stride;
m_axi_arlen <= ((dma_src_stride == 32'd128) &&
((dma_groups - (load_group + 32'd1)) >= 32'd8)) ?
8'd255 : 8'd31;
m_axi_arvalid <= 1'b1;
dma_rd_state <= DMA_RD_ADDR;
end
end else begin
m_axi_arvalid <= 1'b0;
dma_rd_state <= DMA_RD_IDLE;
end
end else begin
dma_rd_count <= dma_rd_count + 8'd1;
if ((dma_rd_group_word_idx == 5'd31) && !dma_rd_next_bank_free)
m_axi_rready <= 1'b0;
end
end
end
default: dma_rd_state <= DMA_RD_IDLE;
endcase
case (dma_wr_state)
DMA_WR_IDLE: begin
m_axi_awvalid <= 1'b0;
m_axi_wvalid <= 1'b0;
m_axi_bready <= 1'b0;
end
DMA_WR_ADDR: begin
m_axi_awvalid <= 1'b0;
dma_wr_state <= DMA_WR_DATA;
end
DMA_WR_DATA: begin
m_axi_wvalid <= 1'b0;
m_axi_wlast <= 1'b0;
if (dma_wr_count == 6'd47) begin
bank_storing[dma_store_bank] <= 1'b0;
dma_store_bank <= ~dma_store_bank;
store_group <= store_group + 32'd1;
completed_groups <= completed_groups + 32'd1;
if ((completed_groups + 32'd1) >= dma_groups) begin
dma_busy <= 1'b0;
dma_done <= 1'b1;
end
dma_wr_state <= DMA_WR_IDLE;
end else begin
dma_wr_count <= dma_wr_count + 6'd1;
end
end
DMA_WR_RESP: begin
m_axi_bready <= 1'b0;
dma_wr_state <= DMA_WR_IDLE;
end
default: dma_wr_state <= DMA_WR_IDLE;
endcase
end
end
assign intr = done; assign intr = done;
endmodule endmodule

View File

@@ -264,8 +264,6 @@ module mlkem_top #(
: em_we ? em_wa[PA_AW-1:0] : em_we ? em_wa[PA_AW-1:0]
: dec_v_we ? dec_v_wr[PA_AW-1:0] : dec_v_we ? dec_v_wr[PA_AW-1:0]
: (a_slot*256 + a_widx) & ((1<<PA_AW)-1); : (a_slot*256 + a_widx) & ((1<<PA_AW)-1);
assign ba_we = ...;
assign ba_wa = ...;
assign ba_wd = td_we ? td_wd : assign ba_wd = td_we ? td_wd :
em_we ? bt_rd_data : // 从 bank_t 相对槽位 0 读取 e2 em_we ? bt_rd_data : // 从 bank_t 相对槽位 0 读取 e2
dec_v_we ? cd_out : // v' 解压缩后的系数 dec_v_we ? cd_out : // v' 解压缩后的系数

View File

@@ -75,21 +75,21 @@ module axi_wrap_ram_sp_external (
output axi_bvalid , output axi_bvalid ,
input axi_bready , input axi_bready ,
//BaseRAM信号 // BaseRAM
inout [31:0] base_ram_data, //BaseRAM数据,低8位与CPLD串口控制器共享 inout [31:0] base_ram_data,
output [19:0] base_ram_addr, //BaseRAM地址 output [19:0] base_ram_addr,
output [ 3:0] base_ram_be_n, //BaseRAM字节使能,低有效。如果不使用字节使能,请保持为0 output [ 3:0] base_ram_be_n,
output base_ram_ce_n, //BaseRAM片选,低有效 output base_ram_ce_n,
output base_ram_oe_n, //BaseRAM读使能,低有效 output base_ram_oe_n,
output base_ram_we_n, //BaseRAM写使能,低有效 output base_ram_we_n,
//ExtRAM信号 // ExtRAM
inout [31:0] ext_ram_data, //ExtRAM数据 inout [31:0] ext_ram_data,
output [19:0] ext_ram_addr, //ExtRAM地址 output [19:0] ext_ram_addr,
output [ 3:0] ext_ram_be_n, //ExtRAM字节使能,低有效。如果不使用字节使能,请保持为0 output [ 3:0] ext_ram_be_n,
output ext_ram_ce_n, //ExtRAM片选,低有效 output ext_ram_ce_n,
output ext_ram_oe_n, //ExtRAM读使能,低有效 output ext_ram_oe_n,
output ext_ram_we_n //ExtRAM写使能,低有效 output ext_ram_we_n
); );
@@ -139,6 +139,7 @@ wire ram_bready ;
wire [31:0] soc_sram_addr; wire [31:0] soc_sram_addr;
wire soc_sram_cs; wire soc_sram_cs;
wire soc_sram_we; wire soc_sram_we;
wire soc_sram_bank;
wire [3:0] soc_sram_be; wire [3:0] soc_sram_be;
wire [31:0] soc_sram_wdata; wire [31:0] soc_sram_wdata;
wire [31:0] soc_sram_rdata; wire [31:0] soc_sram_rdata;
@@ -188,7 +189,8 @@ assign ram_bready = axi_bready ;
axi2sram_sp_external #( axi2sram_sp_external #(
.AXI_ID_WIDTH ( 5 ), .AXI_ID_WIDTH ( 5 ),
.AXI_ADDR_WIDTH ( 32 ), .AXI_ADDR_WIDTH ( 32 ),
.AXI_DATA_WIDTH ( 32 )) .AXI_DATA_WIDTH ( 32 ),
.FAST_READ_BURST( 1 ))
u_axi_sram_sp ( u_axi_sram_sp (
.clk ( aclk ), .clk ( aclk ),
.resetn ( aresetn ), .resetn ( aresetn ),
@@ -232,12 +234,13 @@ axi2sram_sp_external #(
.req_o ( soc_sram_cs ), .req_o ( soc_sram_cs ),
.we_o ( soc_sram_we ), .we_o ( soc_sram_we ),
.addr_o ( soc_sram_addr ), .addr_o ( soc_sram_addr ),
.bank_o ( soc_sram_bank ),
.be_o ( soc_sram_be ), .be_o ( soc_sram_be ),
.data_o ( soc_sram_wdata ), .data_o ( soc_sram_wdata ),
.data_i ( soc_sram_rdata ) .data_i ( soc_sram_rdata )
); );
wire choose_sram = soc_sram_addr[22];//1:ExtRAM 0:BaseRAM wire choose_sram = soc_sram_bank;//1:ExtRAM 0:BaseRAM
wire [3:0] be_out = soc_sram_we ? soc_sram_be : 4'b1111; wire [3:0] be_out = soc_sram_we ? soc_sram_be : 4'b1111;
assign base_ram_addr = soc_sram_addr[21:2]; assign base_ram_addr = soc_sram_addr[21:2];

View File

@@ -44,39 +44,38 @@ module soc_top #(parameter SIMULATION=1'b0)
input clk, input clk,
input reset, input reset,
//图像输出信号 output [2:0] video_red,
output [2:0] video_red, //红色像素,3位 output [2:0] video_green,
output [2:0] video_green, //绿色像素,3位 output [1:0] video_blue,
output [1:0] video_blue, //蓝色像素,2位 output video_hsync,
output video_hsync, //行同步(水平同步)信号 output video_vsync,
output video_vsync, //场同步(垂直同步)信号 output video_clk,
output video_clk, //像素时钟输出 output video_de,
output video_de, //行数据有效信号,用于区分消隐区
input [3:0] touch_btn, //BTN1~BTN4,按钮开关,按下时为1 input [3:0] touch_btn,
input [31:0] dip_sw, //32位拨码开关,拨到“ON”时为1 input [31:0] dip_sw,
output [15:0] leds, //16位LED,输出时1点亮 output [15:0] leds,
output [7:0] dpy0, //数码管低位信号,包括小数点,输出1点亮 output [7:0] dpy0,
output [7:0] dpy1, //数码管高位信号,包括小数点,输出1点亮 output [7:0] dpy1,
//BaseRAM信号 // BaseRAM signals
inout [31:0] base_ram_data, //BaseRAM数据,低8位与CPLD串口控制器共享 inout [31:0] base_ram_data,
output [19:0] base_ram_addr, //BaseRAM地址 output [19:0] base_ram_addr,
output [ 3:0] base_ram_be_n, //BaseRAM字节使能,低有效。如果不使用字节使能,请保持为0 output [ 3:0] base_ram_be_n,
output base_ram_ce_n, //BaseRAM片选,低有效 output base_ram_ce_n,
output base_ram_oe_n, //BaseRAM读使能,低有效 output base_ram_oe_n,
output base_ram_we_n, //BaseRAM写使能,低有效 output base_ram_we_n,
//ExtRAM信号 // ExtRAM signals
inout [31:0] ext_ram_data, //ExtRAM数据 inout [31:0] ext_ram_data,
output [19:0] ext_ram_addr, //ExtRAM地址 output [19:0] ext_ram_addr,
output [ 3:0] ext_ram_be_n, //ExtRAM字节使能,低有效。如果不使用字节使能,请保持为0 output [ 3:0] ext_ram_be_n,
output ext_ram_ce_n, //ExtRAM片选,低有效 output ext_ram_ce_n,
output ext_ram_oe_n, //ExtRAM读使能,低有效 output ext_ram_oe_n,
output ext_ram_we_n, //ExtRAM写使能,低有效 output ext_ram_we_n,
//------uart------- //------uart-------
inout UART_RX, //串口RX接收 inout UART_RX,
inout UART_TX //串口TX发送 inout UART_TX
); );
wire cpu_clk; wire cpu_clk;
@@ -360,7 +359,6 @@ wire [3 :0] dma_m_bid ;
wire [1 :0] dma_m_bresp ; wire [1 :0] dma_m_bresp ;
wire dma_m_bvalid ; wire dma_m_bvalid ;
wire dma_m_bready ; wire dma_m_bready ;
wire [4 :0] dma_s_arid ; wire [4 :0] dma_s_arid ;
wire [31:0] dma_s_araddr ; wire [31:0] dma_s_araddr ;
wire [7 :0] dma_s_arlen ; wire [7 :0] dma_s_arlen ;
@@ -396,7 +394,7 @@ wire [4 :0] dma_s_bid ;
wire [1 :0] dma_s_bresp ; wire [1 :0] dma_s_bresp ;
wire dma_s_bvalid ; wire dma_s_bvalid ;
wire dma_s_bready ; wire dma_s_bready ;
wire dma_finish ; wire dma_finish = 1'b0;
// reserved // reserved
wire [4 :0] axiOut_1_arid ; wire [4 :0] axiOut_1_arid ;
@@ -604,7 +602,6 @@ wire axiOut_7_bready ;
wire confreg_int; wire confreg_int;
wire matmul_intr; wire matmul_intr;
wire mlkem_intr;
AxiCrossbar_2x8 u_AxiCrossbar_2x8 ( AxiCrossbar_2x8 u_AxiCrossbar_2x8 (
.clk ( sys_clk ), .clk ( sys_clk ),
@@ -1036,8 +1033,8 @@ AxiCrossbar_2x8 u_AxiCrossbar_2x8 (
core_top u_cpu( core_top u_cpu(
.intrpt ({4'd0, mlkem_intr, matmul_intr, dma_finish, confreg_int}), //high active .intrpt ({4'd0, 1'b0, matmul_intr, dma_finish, confreg_int}), //high active
// intrpt[3]=mlkem, intrpt[2]=matmul, intrpt[1]=dma, intrpt[0]=confreg // intrpt[2]=matmul, intrpt[1]=dma, intrpt[0]=confreg
.aclk (cpu_clk ), .aclk (cpu_clk ),
.aresetn (cpu_resetn ), //low active .aresetn (cpu_resetn ), //low active
@@ -1312,13 +1309,12 @@ axi_uart_controller u_axi_uart_controller
confreg #( confreg #(
.SIMULATION(SIMULATION) .SIMULATION(SIMULATION)
) u_confreg ( ) u_confreg (
// 时钟与复位 .aclk (sys_clk),
.aclk (sys_clk), // AXI总线时钟 .aresetn (sys_resetn),
.aresetn (sys_resetn), // AXI总线复位 .cpu_clk (cpu_clk),
.cpu_clk (cpu_clk), // CPU时钟 .cpu_resetn (cpu_resetn),
.cpu_resetn (cpu_resetn), // CPU复位
// AXI写地址通道 // AXI Write Address
.s_awid (confreg_awid), .s_awid (confreg_awid),
.s_awaddr (confreg_awaddr), .s_awaddr (confreg_awaddr),
.s_awlen (confreg_awlen), .s_awlen (confreg_awlen),
@@ -1330,7 +1326,7 @@ confreg #(
.s_awvalid (confreg_awvalid), .s_awvalid (confreg_awvalid),
.s_awready (confreg_awready), .s_awready (confreg_awready),
// AXI写数据通道 // AXI Write Data
.s_wid (confreg_wid), .s_wid (confreg_wid),
.s_wdata (confreg_wdata), .s_wdata (confreg_wdata),
.s_wstrb (confreg_wstrb), .s_wstrb (confreg_wstrb),
@@ -1338,13 +1334,13 @@ confreg #(
.s_wvalid (confreg_wvalid), .s_wvalid (confreg_wvalid),
.s_wready (confreg_wready), .s_wready (confreg_wready),
// AXI写响应通道 // AXI Write Response
.s_bid (confreg_bid), .s_bid (confreg_bid),
.s_bresp (confreg_bresp), .s_bresp (confreg_bresp),
.s_bvalid (confreg_bvalid), .s_bvalid (confreg_bvalid),
.s_bready (confreg_bready), .s_bready (confreg_bready),
// AXI读地址通道 // AXI Read Address
.s_arid (confreg_arid), .s_arid (confreg_arid),
.s_araddr (confreg_araddr), .s_araddr (confreg_araddr),
.s_arlen (confreg_arlen), .s_arlen (confreg_arlen),
@@ -1356,7 +1352,7 @@ confreg #(
.s_arvalid (confreg_arvalid), .s_arvalid (confreg_arvalid),
.s_arready (confreg_arready), .s_arready (confreg_arready),
// AXI读数据通道 // AXI Read Data
.s_rid (confreg_rid), .s_rid (confreg_rid),
.s_rdata (confreg_rdata), .s_rdata (confreg_rdata),
.s_rresp (confreg_rresp), .s_rresp (confreg_rresp),
@@ -1364,19 +1360,17 @@ confreg #(
.s_rvalid (confreg_rvalid), .s_rvalid (confreg_rvalid),
.s_rready (confreg_rready), .s_rready (confreg_rready),
// IO外设接口 (与soc_top顶层引脚相连) // IO
.led (leds), // 顶层引脚名称为 .led (leds),
.dpy0 (dpy0), // 低位数码管 .dpy0 (dpy0),
.dpy1 (dpy1), // 高位数码管 .dpy1 (dpy1),
.switch (dip_sw), // 拨码开关,顶层名称为 dip_sw .switch (dip_sw),
.touch_btn (touch_btn), // 触摸按钮 .touch_btn (touch_btn),
// 中断与状态信号 .uart0_int (uart0_int),
.uart0_int (uart0_int), // UART0中断 .fft_finish (fft_finish),
.fft_finish (fft_finish), // FFT完成信号 .confreg_int(confreg_int)
.confreg_int(confreg_int) // 输出中断给CPU
); );
axi_dvi u_axi_dvi ( axi_dvi u_axi_dvi (
.s_awvalid ( dvi_awvalid ), .s_awvalid ( dvi_awvalid ),
.s_awaddr ( dvi_awaddr ), .s_awaddr ( dvi_awaddr ),
@@ -1425,54 +1419,18 @@ axi_dvi u_axi_dvi (
.video_blue ( video_blue ) .video_blue ( video_blue )
); );
// slave 6 - ML-KEM accelerator (0x1f400000, virtual 0xbf400000) // slave 6 reserved (mlkem removed)
// Bus runs at sys_clk; the core is internally clocked at sys_clk/2 (25 MHz). assign fft_arready = 1'b1;
mlkem_axi_slave u_mlkem_axi_slave ( assign fft_rid = 5'b0;
.clk (sys_clk), assign fft_rdata = 32'b0;
.resetn (sys_resetn), assign fft_rresp = 2'b0;
assign fft_rlast = 1'b0;
.s_axi_awid (fft_awid ), assign fft_rvalid = 1'b0;
.s_axi_awaddr (fft_awaddr ), assign fft_awready = 1'b1;
.s_axi_awlen (fft_awlen ), assign fft_wready = 1'b1;
.s_axi_awsize (fft_awsize ), assign fft_bid = 5'b0;
.s_axi_awburst (fft_awburst), assign fft_bresp = 2'b0;
.s_axi_awlock (fft_awlock ), assign fft_bvalid = 1'b0;
.s_axi_awcache (fft_awcache),
.s_axi_awprot (fft_awprot ),
.s_axi_awvalid (fft_awvalid),
.s_axi_awready (fft_awready),
.s_axi_wid (fft_wid ),
.s_axi_wdata (fft_wdata ),
.s_axi_wstrb (fft_wstrb ),
.s_axi_wlast (fft_wlast ),
.s_axi_wvalid (fft_wvalid),
.s_axi_wready (fft_wready),
.s_axi_bid (fft_bid ),
.s_axi_bresp (fft_bresp ),
.s_axi_bvalid (fft_bvalid),
.s_axi_bready (fft_bready),
.s_axi_arid (fft_arid ),
.s_axi_araddr (fft_araddr ),
.s_axi_arlen (fft_arlen ),
.s_axi_arsize (fft_arsize ),
.s_axi_arburst (fft_arburst),
.s_axi_arlock (fft_arlock ),
.s_axi_arcache (fft_arcache),
.s_axi_arprot (fft_arprot ),
.s_axi_arvalid (fft_arvalid),
.s_axi_arready (fft_arready),
.s_axi_rid (fft_rid ),
.s_axi_rdata (fft_rdata ),
.s_axi_rresp (fft_rresp ),
.s_axi_rlast (fft_rlast ),
.s_axi_rvalid (fft_rvalid),
.s_axi_rready (fft_rready),
.intr (mlkem_intr)
);
//slave 7 - matmul accelerator //slave 7 - matmul accelerator
matmul_axi_slave u_matmul_axi_slave ( matmul_axi_slave u_matmul_axi_slave (
@@ -1519,176 +1477,56 @@ matmul_axi_slave u_matmul_axi_slave (
.s_axi_rlast (axiOut_7_rlast ), .s_axi_rlast (axiOut_7_rlast ),
.s_axi_rvalid (axiOut_7_rvalid), .s_axi_rvalid (axiOut_7_rvalid),
.s_axi_rready (axiOut_7_rready), .s_axi_rready (axiOut_7_rready),
.m_axi_awid (dma_m_awid),
.m_axi_awaddr (dma_m_awaddr),
.m_axi_awlen (dma_m_awlen),
.m_axi_awsize (dma_m_awsize),
.m_axi_awburst (dma_m_awburst),
.m_axi_awlock (dma_m_awlock),
.m_axi_awcache (dma_m_awcache),
.m_axi_awprot (dma_m_awprot),
.m_axi_awvalid (dma_m_awvalid),
.m_axi_awready (dma_m_awready),
.m_axi_wdata (dma_m_wdata),
.m_axi_wstrb (dma_m_wstrb),
.m_axi_wlast (dma_m_wlast),
.m_axi_wvalid (dma_m_wvalid),
.m_axi_wready (dma_m_wready),
.m_axi_bid (dma_m_bid),
.m_axi_bresp (dma_m_bresp),
.m_axi_bvalid (dma_m_bvalid),
.m_axi_bready (dma_m_bready),
.m_axi_arid (dma_m_arid),
.m_axi_araddr (dma_m_araddr),
.m_axi_arlen (dma_m_arlen),
.m_axi_arsize (dma_m_arsize),
.m_axi_arburst (dma_m_arburst),
.m_axi_arlock (dma_m_arlock),
.m_axi_arcache (dma_m_arcache),
.m_axi_arprot (dma_m_arprot),
.m_axi_arvalid (dma_m_arvalid),
.m_axi_arready (dma_m_arready),
.m_axi_rid (dma_m_rid),
.m_axi_rdata (dma_m_rdata),
.m_axi_rresp (dma_m_rresp),
.m_axi_rlast (dma_m_rlast),
.m_axi_rvalid (dma_m_rvalid),
.m_axi_rready (dma_m_rready),
.intr (matmul_intr) .intr (matmul_intr)
); );
wire [31:0] cdma_s_awaddr; //slave 5 reserved (cdma adapter removed)
wire [2:0] cdma_s_awprot; assign dma_s_arready = 1'b1;
wire cdma_s_awvalid; assign dma_s_rid = 5'b0;
wire cdma_s_awready; assign dma_s_rdata = 32'b0;
wire [31:0] cdma_s_wdata; assign dma_s_rresp = 2'b0;
wire [3:0] cdma_s_wstrb; assign dma_s_rlast = 1'b0;
wire cdma_s_wvalid; assign dma_s_rvalid = 1'b0;
wire cdma_s_wready; assign dma_s_awready = 1'b1;
wire [1:0] cdma_s_bresp; assign dma_s_wready = 1'b1;
wire cdma_s_bvalid; assign dma_s_bid = 5'b0;
wire cdma_s_bready; assign dma_s_bresp = 2'b0;
wire [31:0] cdma_s_araddr; assign dma_s_bvalid = 1'b0;
wire [2:0] cdma_s_arprot;
wire cdma_s_arvalid;
wire cdma_s_arready;
wire [31:0] cdma_s_rdata;
wire [1:0] cdma_s_rresp;
wire cdma_s_rvalid;
wire cdma_s_rready;
axi_axil_adapter #(
.ADDR_WIDTH(32),
.AXI_DATA_WIDTH(32),
.AXI_ID_WIDTH(5),
.AXIL_DATA_WIDTH(32),
.CONVERT_BURST(1),
.CONVERT_NARROW_BURST(0)
)
u_axi_axil_adapter(
.clk(sys_clk),
.rst(~sys_resetn),
.s_axi_awid(dma_s_awid),
.s_axi_awaddr(dma_s_awaddr),
.s_axi_awlen(dma_s_awlen),
.s_axi_awsize(dma_s_awsize),
.s_axi_awburst(dma_s_awburst),
.s_axi_awlock(dma_s_awlock),
.s_axi_awcache(dma_s_awcache),
.s_axi_awprot(dma_s_awprot),
.s_axi_awvalid(dma_s_awvalid),
.s_axi_awready(dma_s_awready),
.s_axi_wdata(dma_s_wdata),
.s_axi_wstrb(dma_s_wstrb),
.s_axi_wlast(dma_s_wlast),
.s_axi_wvalid(dma_s_wvalid),
.s_axi_wready(dma_s_wready),
.s_axi_bid(dma_s_bid),
.s_axi_bresp(dma_s_bresp),
.s_axi_bvalid(dma_s_bvalid),
.s_axi_bready(dma_s_bready),
.s_axi_arid(dma_s_arid),
.s_axi_araddr(dma_s_araddr),
.s_axi_arlen(dma_s_arlen),
.s_axi_arsize(dma_s_arsize),
.s_axi_arburst(dma_s_arburst),
.s_axi_arlock(dma_s_arlock),
.s_axi_arcache(dma_s_arcache),
.s_axi_arprot(dma_s_arprot),
.s_axi_arvalid(dma_s_arvalid),
.s_axi_arready(dma_s_arready),
.s_axi_rid(dma_s_rid),
.s_axi_rdata(dma_s_rdata),
.s_axi_rresp(dma_s_rresp),
.s_axi_rlast(dma_s_rlast),
.s_axi_rvalid(dma_s_rvalid),
.s_axi_rready(dma_s_rready),
.m_axil_awaddr(cdma_s_awaddr),
.m_axil_awprot(cdma_s_awprot),
.m_axil_awvalid(cdma_s_awvalid),
.m_axil_awready(cdma_s_awready),
.m_axil_wdata(cdma_s_wdata),
.m_axil_wstrb(cdma_s_wstrb),
.m_axil_wvalid(cdma_s_wvalid),
.m_axil_wready(cdma_s_wready),
.m_axil_bresp(cdma_s_bresp),
.m_axil_bvalid(cdma_s_bvalid),
.m_axil_bready(cdma_s_bready),
.m_axil_araddr(cdma_s_araddr),
.m_axil_arprot(cdma_s_arprot),
.m_axil_arvalid(cdma_s_arvalid),
.m_axil_arready(cdma_s_arready),
.m_axil_rdata(cdma_s_rdata),
.m_axil_rresp(cdma_s_rresp),
.m_axil_rvalid(cdma_s_rvalid),
.m_axil_rready(cdma_s_rready)
);
// 8 通道 DMA
snix_axil_cdma_mux #(
.ADDR_WIDTH (32),
.DATA_WIDTH (32), // 适配你的 32-bit 总线
.AXIL_ADDR_WIDTH (32),
.AXIL_DATA_WIDTH (32),
.ID_WIDTH (4), // 匹配 Crossbar 的 Master ID 宽度
.USER_WIDTH (1),
.PORTS (4), // 8 个通道
.FIFO_DEPTH (64)
) u_snix_axil_cdma_mux_8ch (
.clk (sys_clk),
.rst_n (sys_resetn), // 低电平复位
// AXI-Lite 从机接口 (接 CPU 发来的配置请求)
.s_axil_awaddr (cdma_s_awaddr),
.s_axil_awvalid (cdma_s_awvalid),
.s_axil_awready (cdma_s_awready),
.s_axil_wdata (cdma_s_wdata),
.s_axil_wstrb (cdma_s_wstrb),
.s_axil_wvalid (cdma_s_wvalid),
.s_axil_wready (cdma_s_wready),
.s_axil_bresp (cdma_s_bresp),
.s_axil_bvalid (cdma_s_bvalid),
.s_axil_bready (cdma_s_bready),
.s_axil_araddr (cdma_s_araddr),
.s_axil_arvalid (cdma_s_arvalid),
.s_axil_arready (cdma_s_arready),
.s_axil_rdata (cdma_s_rdata),
.s_axil_rresp (cdma_s_rresp),
.s_axil_rvalid (cdma_s_rvalid),
.s_axil_rready (cdma_s_rready),
// AXI4 主机接口 (接 Crossbar 去搬运数据)
.mm2mm_awid (dma_m_awid),
.mm2mm_awaddr (dma_m_awaddr),
.mm2mm_awlen (dma_m_awlen),
.mm2mm_awsize (dma_m_awsize),
.mm2mm_awburst (dma_m_awburst),
.mm2mm_awlock (dma_m_awlock),
.mm2mm_awcache (dma_m_awcache),
.mm2mm_awprot (dma_m_awprot),
.mm2mm_awqos (), // 悬空即可
.mm2mm_awuser (), // 悬空即可
.mm2mm_awvalid (dma_m_awvalid),
.mm2mm_awready (dma_m_awready),
.mm2mm_wdata (dma_m_wdata),
.mm2mm_wstrb (dma_m_wstrb),
.mm2mm_wlast (dma_m_wlast),
.mm2mm_wuser (), // 悬空即可
.mm2mm_wvalid (dma_m_wvalid),
.mm2mm_wready (dma_m_wready),
.mm2mm_bid (dma_m_bid),
.mm2mm_bresp (dma_m_bresp),
.mm2mm_buser (1'b0),
.mm2mm_bvalid (dma_m_bvalid),
.mm2mm_bready (dma_m_bready),
.mm2mm_arid (dma_m_arid),
.mm2mm_araddr (dma_m_araddr),
.mm2mm_arlen (dma_m_arlen),
.mm2mm_arsize (dma_m_arsize),
.mm2mm_arburst (dma_m_arburst),
.mm2mm_arlock (dma_m_arlock),
.mm2mm_arcache (dma_m_arcache),
.mm2mm_arprot (dma_m_arprot),
.mm2mm_arqos (), // 悬空即可
.mm2mm_aruser (), // 悬空即可
.mm2mm_arvalid (dma_m_arvalid),
.mm2mm_arready (dma_m_arready),
.mm2mm_rid (dma_m_rid),
.mm2mm_rdata (dma_m_rdata),
.mm2mm_rresp (dma_m_rresp),
.mm2mm_rlast (dma_m_rlast),
.mm2mm_ruser (1'b0),
.mm2mm_rvalid (dma_m_rvalid),
.mm2mm_rready (dma_m_rready),
// 全局中断输出
.dma_finish (dma_finish)
);
endmodule endmodule

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -19,27 +19,34 @@ CFLAGS += -nostartfiles -nostdlib -nostdinc -static -fno-builtin
CFLAGS += -DCLOCKS_PER_SEC=CORE_CLOCKS_PER_SEC -D_CLOCKS_PER_SEC_=CORE_CLOCKS_PER_SEC CFLAGS += -DCLOCKS_PER_SEC=CORE_CLOCKS_PER_SEC -D_CLOCKS_PER_SEC_=CORE_CLOCKS_PER_SEC
CFLAGS += -DUSE_CPU_CLOCK_COUNT CFLAGS += -DUSE_CPU_CLOCK_COUNT
LINKER_SCRIPT ?= $(COMMON_DIR)/env/script.lds
BSP_STARTUP ?= $(COMMON_DIR)/env/start.S
BSP_USE_TRAP ?= 1
BSP_USE_DRIVERS ?= 1
#若使用 newlib , 将下面的 -lsemihost 替换为 -lgloss #若使用 newlib , 将下面的 -lsemihost 替换为 -lgloss
LDFLAGS += -T $(LINKER_SCRIPT) \ LDFLAGS += -T $(LINKER_SCRIPT) \
-Wl,--gc-sections -Wl,--check-sections \ -Wl,--gc-sections -Wl,--check-sections \
-lc -lm -lg -lsemihost -lgcc -L$(PICOLIBC_DIR)/lib -lc -lm -lg -lsemihost -lgcc -L$(PICOLIBC_DIR)/lib
LINKER_SCRIPT := $(COMMON_DIR)/env/script.lds ASM_SRCS += $(BSP_STARTUP)
ASM_SRCS += $(COMMON_DIR)/env/start.S
ifeq ($(BSP_USE_TRAP),1)
ifeq ($(TARGET), RTThread_Nano) ifeq ($(TARGET), RTThread_Nano)
else else
ASM_SRCS += $(COMMON_DIR)/env/trap_handler.S ASM_SRCS += $(COMMON_DIR)/env/trap_handler.S
endif endif
endif
ifeq ($(BSP_USE_DRIVERS),1)
C_SRCS += $(COMMON_DIR)/drivers/confreg_time.c C_SRCS += $(COMMON_DIR)/drivers/confreg_time.c
C_SRCS += $(COMMON_DIR)/drivers/core_time.c C_SRCS += $(COMMON_DIR)/drivers/core_time.c
C_SRCS += $(COMMON_DIR)/drivers/common_func.c C_SRCS += $(COMMON_DIR)/drivers/common_func.c
C_SRCS += $(COMMON_DIR)/drivers/dvi.c \ C_SRCS += $(COMMON_DIR)/drivers/dvi.c \
$(COMMON_DIR)/drivers/led.c \ $(COMMON_DIR)/drivers/led.c \
$(COMMON_DIR)/drivers/seg7.c $(COMMON_DIR)/drivers/seg7.c
endif
INCLUDES += -I./ \ INCLUDES += -I./ \
-I$(COMMON_DIR)/include \ -I$(COMMON_DIR)/include \

View File

@@ -118,7 +118,7 @@ _start:
#WRITE(li.wne,OFS_DIVISOR_LSB, divisor & 0xff); #WRITE(li.wne,OFS_DIVISOR_LSB, divisor & 0xff);
li.w t3, 0xbf20f500 li.w t3, 0xbf20f500
ld.w t3, t3, 0 ld.w t3, t3, 0
li.w t2, 0x1b li.w t2, 0x20
beq zero, t3, 1f beq zero, t3, 1f
li.w t2, 0x1 li.w t2, 0x1
1: 1:

View File

@@ -1,7 +1,8 @@
TARGET = user-sample TARGET = user-sample
MATMUL_GROUP_NUM ?= 5000 MATMUL_GROUP_NUM ?= 5000
CFLAGS += -O3 -g -DMATMUL_GROUP_NUM=$(MATMUL_GROUP_NUM) MATMUL_FAST_START ?= 1
CFLAGS += -O3 -g -DMATMUL_GROUP_NUM=$(MATMUL_GROUP_NUM) -DMATMUL_FAST_START=$(MATMUL_FAST_START)
C_SRCS := $(wildcard ./*.c ) C_SRCS := $(wildcard ./*.c )
@@ -9,6 +10,15 @@ OBJDIR = obj
COMMON_DIR = ../../bsp COMMON_DIR = ../../bsp
GCC_DIR=../../../toolchains/loongson-gnu-toolchain-8.3-x86_64-loongarch32r-linux-gnusf-v2.0 GCC_DIR=../../../toolchains/loongson-gnu-toolchain-8.3-x86_64-loongarch32r-linux-gnusf-v2.0
PICOLIBC_DIR=../../../toolchains/picolibc PICOLIBC_DIR=../../../toolchains/picolibc
ifeq ($(MATMUL_FAST_START),1)
LINKER_SCRIPT := script_matmul_fast.lds
BSP_STARTUP := start_matmul_fast.S
BSP_USE_TRAP := 0
BSP_USE_DRIVERS := 0
endif
LA32RSOC_WINDOWS_HOME?=../../../..
include ../../bsp/common.mk include ../../bsp/common.mk
# Strip picolibc: no -lc -lm -lg -lsemihost, keep -lgcc only # Strip picolibc: no -lc -lm -lg -lsemihost, keep -lgcc only

View File

@@ -9,21 +9,46 @@ typedef struct {
volatile u32 TAG; // 0x0C: software tag (ignored by HW) volatile u32 TAG; // 0x0C: software tag (ignored by HW)
volatile u32 CTRL; // 0x10: control (burst config + start) volatile u32 CTRL; // 0x10: control (burst config + start)
volatile u32 STATUS; // 0x14: status (busy, done) volatile u32 STATUS; // 0x14: status (busy, done)
volatile u32 RESV[10]; // 0x18 ~ 0x3C: padding to 0x40 bytes volatile u32 MODE; // 0x18: 0=mem2mem, 1=mem2ep, 2=ep2mem
volatile u32 EP_CFG; // 0x1C: [3:0]=bank, [15:8]=word offset, [19:16]=endpoint id
volatile u32 RESV[8]; // 0x20 ~ 0x3C: padding to 0x40 bytes
} dma_ch_regs_t; } dma_ch_regs_t;
// DMA 控制器基地址 // DMA 控制器基地址
#define CDMA_MUX_BASE 0xbf300000 #define CDMA_MUX_BASE 0xbf300000
#define DMA_CH(i) ((volatile dma_ch_regs_t*)(CDMA_MUX_BASE + (i) * 0x40)) #define DMA_CH(i) ((volatile dma_ch_regs_t*)(CDMA_MUX_BASE + (i) * 0x40))
typedef struct {
volatile u32 CTRL; // 0x200: bit0 start
volatile u32 STATUS; // 0x204: bit0 busy, bit1 done (W1C)
volatile u32 SRC_BASE; // 0x208
volatile u32 DST_BASE; // 0x20C
volatile u32 GROUPS; // 0x210
volatile u32 MAT_BASE; // 0x214
volatile u32 SRC_STRIDE; // 0x218
volatile u32 DST_STRIDE; // 0x21C
} dma_seq_regs_t;
#define DMA_SEQ ((volatile dma_seq_regs_t*)(CDMA_MUX_BASE + 0x200))
// CTRL 寄存器位定义 // CTRL 寄存器位定义
#define CTRL_START_BIT (1 << 0) #define CTRL_START_BIT (1 << 0)
#define CTRL_BURST_SIZE(x) (((x) & 0x7) << 3) // Bits [5:3]: AXI AxSIZE (0=1B, 1=2B, 2=4B, 3=8B) #define CTRL_BURST_SIZE(x) (((x) & 0x7) << 3) // Bits [5:3]: AXI AxSIZE (0=1B, 1=2B, 2=4B, 3=8B)
#define CTRL_BURST_LEN(x) (((x) & 0xFF) << 6) // Bits [13:6]: AXI AxLEN (0=1 beat, 15=16 beats) #define CTRL_BURST_LEN(x) (((x) & 0xFF) << 6) // Bits [13:6]: AXI AxLEN (0=1 beat, 15=16 beats)
#define DMA_MODE_MEM2MEM 0
#define DMA_MODE_MEM2EP 1
#define DMA_MODE_EP2MEM 2
#define DMA_EP_CFG(id, bank, word_off) \
((((id) & 0xF) << 16) | (((word_off) & 0xFF) << 8) | ((bank) & 0xF))
// STATUS 寄存器位定义 // STATUS 寄存器位定义
#define STATUS_BUSY_BIT (1 << 0) #define STATUS_BUSY_BIT (1 << 0)
#define STATUS_DONE_BIT (1 << 1) #define STATUS_DONE_BIT (1 << 1)
#define SEQ_START_BIT (1 << 0)
#define SEQ_BUSY_BIT (1 << 0)
#define SEQ_DONE_BIT (1 << 1)
void dma_start_transfer(int ch_id, u32 src, u32 dst, u32 bytes, u32 tag); void dma_start_transfer(int ch_id, u32 src, u32 dst, u32 bytes, u32 tag);
void dma_wait_polling(int ch_id); void dma_wait_polling(int ch_id);

View File

@@ -0,0 +1,89 @@
OUTPUT_ARCH(loongarch)
ENTRY(_start)
MEMORY
{
isram (rwxai) : ORIGIN = 0x1c000000, LENGTH = 512K
dsram (rwxai) : ORIGIN = 0x1c080000, LENGTH = 512K
}
SECTIONS
{
__stack_size = DEFINED(__stack_size) ? __stack_size : 4K;
.init :
{
KEEP(*(SORT_NONE(.init)))
} >isram AT>isram
. = ALIGN(16);
.text :
{
_ftext = .;
*(.text.unlikely .text.unlikely.*)
*(.text.startup .text.startup.*)
*(.text .text.*)
*(.gnu.linkonce.t.*)
} >isram AT>isram
. = ALIGN(16);
.rodata :
{
*(.rdata)
*(.rodata .rodata.*)
*(.gnu.linkonce.r.*)
*(.srodata.cst16)
*(.srodata.cst8)
*(.srodata.cst4)
*(.srodata.cst2)
*(.srodata .srodata.*)
} >isram AT>isram
. = ALIGN(16);
PROVIDE(__etext = .);
PROVIDE(_etext = .);
PROVIDE(etext = .);
PROVIDE(_data_lma = .);
.data ORIGIN(dsram) :
{
PROVIDE(_data = .);
*(.data .data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(16);
PROVIDE(__global_pointer$ = . + 0x800);
*(.sdata .sdata.*)
*(.gnu.linkonce.s.*)
. = ALIGN(16);
PROVIDE(_edata = .);
PROVIDE(edata = .);
} >dsram AT>isram
.bss :
{
PROVIDE(__bss_start = .);
*(.sbss*)
*(.sbss.*)
*(.dynsbss)
*(.scommon)
*(.bss)
*(.bss.*)
*(.dynbss)
*(.gnu.linkonce.sb.*)
*(COMMON)
. = ALIGN(16);
PROVIDE(_end = .);
PROVIDE(end = .);
} >dsram AT>dsram
PROVIDE(__heap_start = _end);
.stack ORIGIN(dsram) + LENGTH(dsram) - __stack_size :
{
PROVIDE(_heap_end = .);
PROVIDE(__heap_end = _heap_end);
PROVIDE(__heap_size = __heap_end - __heap_start);
. = __stack_size;
PROVIDE(_stack = .);
} >dsram AT>dsram
}

View File

@@ -0,0 +1,54 @@
#include "regdef.h"
.section .init
.globl _start
.type _start, @function
_start:
/* Enable direct mapped windows used by SRAM and uncached peripherals. */
li.w t0, 0x8
li.w t1, 0x18
csrxchg t0, t1, csr_crmd
csrwr zero, csr_dmw0
csrwr zero, csr_dmw1
li.w t0, 0x19
csrwr t0, csr_dmw0
li.w t0, 0xa0000009
csrwr t0, csr_dmw1
li.w t0, 0x10
li.w t1, 0x18
csrxchg t0, t1, csr_crmd
/* Polling-only benchmark: keep interrupts disabled. */
li.w t0, 0x4
csrxchg zero, t0, csr_crmd
csrwr zero, csr_prmd
csrwr zero, csr_ecfg
/* UART0 init, 115200 baud with the same divisor selection as BSP start.S. */
li.w t0, 0xbf000000
li.w t1, 0x07
st.b t1, t0, 2
li.w t1, 0x80
st.b t1, t0, 3
st.b zero, t0, 1
li.w t2, 0xbf20f500
ld.w t2, t2, 0
li.w t1, 0x20
beq zero, t2, 1f
li.w t1, 0x1
1:
st.b t1, t0, 0
li.w t1, 0x03
st.b t1, t0, 3
st.b zero, t0, 4
la.local sp, _stack
li.w a0, 0
li.w a1, 0
bl main
1:
b 1b

View File

@@ -1,213 +1,155 @@
/** /**
* user-sample - CIC-IEC 2026 Stage 3 Evaluation Program * user-sample - CIC-IEC 2026 Stage 3 Evaluation Program
* *
* (ULTIMATE PERFORMANCE DMA + PING-PONG BUFFER ARCHITECTURE v2) * Matmul AXI-master CRC-only path with fast startup and low-overhead UART output.
*
* Optimizations over v1:
* 1. Pre-fire DMA Ch0 load at loop tail → fully overlaps with IP compute
* 2. Inlined wait loops → zero function-call overhead in hot path
* 3. Inlined DMA start → skips redundant STATUS_BUSY_BIT check
* 4. XOR bank toggle → avoids g%2 recomputation per iteration
*/ */
#include <dma.h> #include <dma.h>
/* ─── UART 16550 direct access (bypasses slow printf/picolibc) ──────── */
#define UART_THR (*(volatile unsigned char *)0xbf000000) #define UART_THR (*(volatile unsigned char *)0xbf000000)
#define UART_LSR (*(volatile unsigned char *)0xbf000005) #define UART_LSR (*(volatile unsigned char *)0xbf000005)
#define LSR_THRE 0x20 #define LSR_THRE 0x20
static inline void uart_tx(unsigned char c) { static inline void uart_tx(unsigned char c)
while (!(UART_LSR & LSR_THRE)) {} {
while ((UART_LSR & LSR_THRE) == 0) {
}
UART_THR = c; UART_THR = c;
} }
static void uart_puts(const char *s) { static void uart_put_matmul_start_fifo(void)
while (*s) uart_tx(*s++); {
UART_THR = 'M';
UART_THR = 'A';
UART_THR = 'T';
UART_THR = 'M';
UART_THR = 'U';
UART_THR = 'L';
UART_THR = '_';
UART_THR = 'S';
UART_THR = 'T';
UART_THR = 'A';
UART_THR = 'R';
UART_THR = 'T';
} }
static void uart_puthex(unsigned int val) { static void uart_put_crc_prefix_fifo(void)
int i; {
for (i = 28; i >= 0; i -= 4) { UART_THR = 'M';
unsigned char nibble = (val >> i) & 0xF; UART_THR = 'A';
uart_tx(nibble < 10 ? '0' + nibble : 'a' + nibble - 10); UART_THR = 'T';
UART_THR = 'M';
UART_THR = 'U';
UART_THR = 'L';
UART_THR = '_';
UART_THR = 'C';
UART_THR = 'R';
UART_THR = 'C';
UART_THR = '3';
UART_THR = '2';
UART_THR = '=';
}
static inline void uart_wait_tx_empty(void)
{
while ((UART_LSR & LSR_THRE) == 0) {
} }
} }
/* ─── Configurable group count (default 5000) ──────────────────────── */ static inline unsigned char hex_digit(unsigned int val, int shift)
{
unsigned char nibble = (unsigned char)((val >> shift) & 0xf);
return (unsigned char)(nibble < 10 ? ('0' + nibble) : ('a' + nibble - 10));
}
static void uart_put_result_fifo(unsigned int crc)
{
uart_wait_tx_empty();
UART_THR = hex_digit(crc, 28);
UART_THR = hex_digit(crc, 24);
UART_THR = hex_digit(crc, 20);
UART_THR = hex_digit(crc, 16);
UART_THR = hex_digit(crc, 12);
UART_THR = hex_digit(crc, 8);
UART_THR = hex_digit(crc, 4);
UART_THR = hex_digit(crc, 0);
UART_THR = 'M';
UART_THR = 'A';
UART_THR = 'T';
UART_THR = 'M';
UART_THR = 'U';
UART_THR = 'L';
UART_THR = '_';
UART_THR = 'D';
UART_THR = 'O';
UART_THR = 'N';
UART_THR = 'E';
}
#ifndef MATMUL_GROUP_NUM #ifndef MATMUL_GROUP_NUM
#define MATMUL_GROUP_NUM 5000 #define MATMUL_GROUP_NUM 5000
#endif #endif
/* ─── BSP globals ─────────────────────────────────────────────────── */ #if MATMUL_FAST_START == 0
unsigned long UART_BASE = 0xbf000000; unsigned long UART_BASE = 0xbf000000;
unsigned long CONFREG_TIMER_BASE = 0xbf20f100; #endif
unsigned long CONFREG_CLOCKS_PER_SEC = 50000000L;
unsigned long CORE_CLOCKS_PER_SEC = 33000000L;
/* ─── Memory layout ────────────────────────────────────────────────── */
#define EXTRAM_BASE_PHYS 0x1c400000 #define EXTRAM_BASE_PHYS 0x1c400000
#define EXTRAM_BASE_UNCACHED (0xA0000000 | (EXTRAM_BASE_PHYS & 0x1FFFFFFF)) #define EXTRAM_BASE_UNCACHED (0xA0000000 | (EXTRAM_BASE_PHYS & 0x1FFFFFFF))
#define SRC_BASE_WORDS 0 #define SRC_BASE_WORDS 0
#define DST_BASE_WORDS (SRC_BASE_WORDS + MATMUL_GROUP_NUM * 32)
#define RESULT_WORDS (MATMUL_GROUP_NUM * 48)
/* ExtRAM Physical Addresses for DMA */
#define EXTRAM_PHYS_AB(g) (EXTRAM_BASE_PHYS + (SRC_BASE_WORDS * 4) + (g) * 128) #define EXTRAM_PHYS_AB(g) (EXTRAM_BASE_PHYS + (SRC_BASE_WORDS * 4) + (g) * 128)
#define EXTRAM_PHYS_C(g) (EXTRAM_BASE_PHYS + (DST_BASE_WORDS * 4) + (g) * 192)
/* ─── MATMUL IP registers (Ping-Pong Memory Map) ──────────────────── */
#define MATMUL_BASE_PHYS 0x1f500000 #define MATMUL_BASE_PHYS 0x1f500000
#define MATMUL_BASE_UNCACHED 0xbf500000 #define MATMUL_BASE_UNCACHED 0xbf500000
#define MATMUL_CTRL (MATMUL_BASE_UNCACHED + 0x000) #define MATMUL_CTRL (MATMUL_BASE_UNCACHED + 0x000)
#define MATMUL_STATUS (MATMUL_BASE_UNCACHED + 0x004) #define MATMUL_STATUS (MATMUL_BASE_UNCACHED + 0x004)
#define MATMUL_PHYS_B0_AB (MATMUL_BASE_PHYS + 0x100) #define MATMUL_DMA_SRC_BASE (MATMUL_BASE_UNCACHED + 0x020)
#define MATMUL_PHYS_B0_C (MATMUL_BASE_PHYS + 0x180) #define MATMUL_DMA_GROUPS (MATMUL_BASE_UNCACHED + 0x028)
#define MATMUL_PHYS_B1_AB (MATMUL_BASE_PHYS + 0x300) #define MATMUL_DMA_SRC_STRIDE (MATMUL_BASE_UNCACHED + 0x02C)
#define MATMUL_PHYS_B1_C (MATMUL_BASE_PHYS + 0x380)
#define CTRL_START_B0 0x1 #define CTRL_START_B0 0x1
#define CTRL_START_B1 0x2 #define CTRL_START_B1 0x2
#define CTRL_DMA_START (1 << 8)
#define STATUS_DONE 0x2 #define STATUS_DONE 0x2
#define STATUS_ERROR 0x4 #define STATUS_ERROR 0x4
#define STATUS_DMA_BUSY (1 << 3)
#define STATUS_DMA_DONE (1 << 4)
#define MATMUL_CRC (MATMUL_BASE_UNCACHED + 0x010) #define MATMUL_CRC (MATMUL_BASE_UNCACHED + 0x010)
/* ─── Pre-computed DMA burst control word ──────────────────────────── */
#define DMA_CTRL_VAL (CTRL_BURST_SIZE(2) | CTRL_BURST_LEN(63) | CTRL_START_BIT) #define DMA_CTRL_VAL (CTRL_BURST_SIZE(2) | CTRL_BURST_LEN(63) | CTRL_START_BIT)
#define MATMUL_EP_ID 0
/* ═══════════════════════════════════════════════════════════════════ */
int main(void) int main(void)
{ {
if (MATMUL_GROUP_NUM <= 0) return 0; if (MATMUL_GROUP_NUM <= 0) {
return 0;
}
/* ── Hot-path local volatile pointers (one-time addr calc) ──────── */ volatile unsigned int *mat_ctrl = (volatile unsigned int *)MATMUL_CTRL;
volatile unsigned int *mat_status = (volatile unsigned int *)MATMUL_STATUS; volatile unsigned int *mat_status = (volatile unsigned int *)MATMUL_STATUS;
volatile unsigned int *mat_ctrl = (volatile unsigned int *)MATMUL_CTRL; volatile unsigned int *mat_crc = (volatile unsigned int *)MATMUL_CRC;
volatile unsigned int *mat_crc = (volatile unsigned int *)MATMUL_CRC;
volatile dma_ch_regs_t *ch0 = DMA_CH(0);
volatile dma_ch_regs_t *ch1 = DMA_CH(1);
unsigned int crc; unsigned int crc;
int g, bank;
// Ping-Pong Register Address Arrays (Physical for DMA) uart_put_matmul_start_fifo();
unsigned int phys_bank_AB[2] = {MATMUL_PHYS_B0_AB, MATMUL_PHYS_B1_AB};
unsigned int phys_bank_C[2] = {MATMUL_PHYS_B0_C, MATMUL_PHYS_B1_C};
unsigned int ctrl_start[2] = {CTRL_START_B0, CTRL_START_B1};
/* ── Start marker (must be first output) ──────────────────── */ *(volatile unsigned int *)MATMUL_CRC = 0;
uart_puts("MATMUL_START\r\n"); *mat_status = STATUS_DMA_DONE | STATUS_DONE | STATUS_ERROR;
*(volatile unsigned int *)MATMUL_DMA_SRC_BASE = EXTRAM_PHYS_AB(0);
*(volatile unsigned int *)MATMUL_DMA_GROUPS = MATMUL_GROUP_NUM;
*(volatile unsigned int *)MATMUL_DMA_SRC_STRIDE = 128;
*mat_ctrl = CTRL_DMA_START;
uart_put_crc_prefix_fifo();
while (!(*mat_status & STATUS_DMA_DONE)) {}
*mat_status = STATUS_DMA_DONE;
// Reset IP state
*mat_status = STATUS_DONE | STATUS_ERROR;
*mat_crc = 0;
/* ═══════════════════════════════════════════════════════════════
* PROLOGUE: Load group 0 → Bank 0, start IP, pre-fire group 1
* ═══════════════════════════════════════════════════════════════ */
// DMA Ch0: Load group 0 A+B (128 bytes) → IP Bank 0
ch0->SRC_ADDR = EXTRAM_PHYS_AB(0);
ch0->DST_ADDR = phys_bank_AB[0];
ch0->LENGTH = 128;
ch0->CTRL = DMA_CTRL_VAL;
while (!(ch0->STATUS & STATUS_DONE_BIT)) {}
ch0->STATUS = STATUS_DONE_BIT;
// Start IP Bank 0 (group 0)
*mat_ctrl = ctrl_start[0];
// Pre-fire: DMA Ch0 load group 1 → Bank 1 (overlaps with IP compute)
if (MATMUL_GROUP_NUM > 1) {
ch0->SRC_ADDR = EXTRAM_PHYS_AB(1);
ch0->DST_ADDR = phys_bank_AB[1];
ch0->LENGTH = 128;
ch0->CTRL = DMA_CTRL_VAL;
}
/* ═══════════════════════════════════════════════════════════════
* MAIN LOOP: Fully-pipelined — pre-fire DMA load at loop tail
*
* At iteration g:
* IP is computing group (g-1) on prev_bank
* Ch0 loaded group g to cur_bank (pre-fired in iteration g-1)
*
* Pipeline:
* Ch0: | load g+1 | | load g+2 |
* Ch1: | store g-1 | | store g |
* IP : | compute g | | compute g+1 |
* ═══════════════════════════════════════════════════════════════ */
bank = 1; // cur_bank for iteration g=1; prev_bank = bank ^ 1
for (g = 1; g < MATMUL_GROUP_NUM; g++) {
int cur_bank = bank;
int prev_bank = bank ^ 1;
// 1. Wait for previous IP computation (group g-1 on prev_bank)
while (!(*mat_status & STATUS_DONE)) {}
*mat_status = STATUS_DONE;
// 2. Ensure previous DMA Ch1 store is done (group g-2)
if (g > 1) {
while (!(ch1->STATUS & STATUS_DONE_BIT)) {}
ch1->STATUS = STATUS_DONE_BIT;
}
// 3. Start DMA Ch1 store: group (g-1) result → ExtRAM
ch1->SRC_ADDR = phys_bank_C[prev_bank];
ch1->DST_ADDR = EXTRAM_PHYS_C(g - 1);
ch1->LENGTH = 192;
ch1->CTRL = DMA_CTRL_VAL;
// 4. Wait for current DMA Ch0 load (group g → cur_bank, pre-fired in iteration g-1)
while (!(ch0->STATUS & STATUS_DONE_BIT)) {}
ch0->STATUS = STATUS_DONE_BIT;
// 5. Start IP computation for current group on cur_bank
*mat_ctrl = ctrl_start[cur_bank];
// ★ 6. PRE-FIRE: DMA Ch0 load next group (g+1) → next_bank
// This runs CONCURRENTLY with IP computation started in step 5!
if (g < MATMUL_GROUP_NUM - 1) {
int next_bank = bank ^ 1;
ch0->SRC_ADDR = EXTRAM_PHYS_AB(g + 1);
ch0->DST_ADDR = phys_bank_AB[next_bank];
ch0->LENGTH = 128;
ch0->CTRL = DMA_CTRL_VAL;
}
// Toggle bank for next iteration
bank ^= 1;
}
/* ═══════════════════════════════════════════════════════════════
* EPILOGUE: Flush the final group
* ═══════════════════════════════════════════════════════════════ */
// Wait for last IP computation
while (!(*mat_status & STATUS_DONE)) {}
*mat_status = STATUS_DONE;
// Wait for previous DMA store and start/complete final store
while (!(ch1->STATUS & STATUS_DONE_BIT)) {}
ch1->STATUS = STATUS_DONE_BIT;
ch1->SRC_ADDR = phys_bank_C[(MATMUL_GROUP_NUM - 1) % 2];
ch1->DST_ADDR = EXTRAM_PHYS_C(MATMUL_GROUP_NUM - 1);
ch1->LENGTH = 192;
ch1->CTRL = DMA_CTRL_VAL;
while (!(ch1->STATUS & STATUS_DONE_BIT)) {}
ch1->STATUS = STATUS_DONE_BIT;
/* ── Read hardware CRC32 ──────────────────────────────────── */
crc = *mat_crc; crc = *mat_crc;
uart_puts("MATMUL_CRC32="); uart_put_result_fifo(crc);
uart_puthex(crc);
uart_puts("\r\nMATMUL_DONE\r\n");
return 0; return 0;
} }

View File

@@ -150,16 +150,16 @@ static void readback(uint32_t sel, uint8_t *buf, int n)
/* Arbitrary but fixed test seeds / message (32 bytes each). */ /* Arbitrary but fixed test seeds / message (32 bytes each). */
static const uint8_t SEED_D[32] = { static const uint8_t SEED_D[32] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, 0x6d,0xbb,0xc4,0x37,0x51,0x36,0xdf,0x3b,0x07,0xf7,0xc7,0x0e,0x63,0x9e,0x22,0x3e,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F 0x17,0x7e,0x7f,0xd5,0x3b,0x16,0x1b,0x3f,0x4d,0x57,0x79,0x17,0x94,0xf1,0x26,0x24
}; };
static const uint8_t SEED_Z[32] = { static const uint8_t SEED_Z[32] = {
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, 0xf6,0x96,0x48,0x40,0x48,0xec,0x21,0xf9,0x6c,0xf5,0x0a,0x56,0xd0,0x75,0x9c,0x44,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F 0x8f,0x37,0x79,0x75,0x2f,0x03,0x83,0xd3,0x74,0x49,0x69,0x06,0x94,0xcf,0x7a,0x68
}; };
static const uint8_t MSG_M[32] = { static const uint8_t MSG_M[32] = {
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, 0x20,0xa7,0xb7,0xe1,0x0f,0x70,0x49,0x6c,0xc3,0x82,0x20,0xb9,0x44,0xde,0xf6,0x99,
0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF 0xbf,0x14,0xd1,0x4e,0x55,0xcf,0x4c,0x90,0xa1,0x2c,0x1b,0x33,0xfc,0x80,0xff,0xff
}; };
static uint8_t ek[EK_BYTES]; static uint8_t ek[EK_BYTES];

Binary file not shown.