Files
retroSoC/rtl/ip/native/peripheral/dma_core.sv
T
maksyuki 0a6055134e feat: refactor NMI interface and enhance performance logging
- Updated NMI interface references from  to  in multiple files for consistency.
- Added a new script  to convert UART performance records into structured JSON format.
- Enhanced the README documentation to include details about the new performance log parser.
- Implemented tests for the new performance log parser to ensure correct functionality.
- Added new test cases for DMA error handling and SDRAM data integrity to improve coverage.
- Updated existing test cases to accommodate changes in the NMI interface and added performance metrics.
- Refactored bus fault testbench to include fault code checks and improved error handling.
- Adjusted memory map generation and pin mapping tests to reflect recent changes in RTL structure.
2026-08-02 10:21:09 +08:00

283 lines
7.8 KiB
Systemverilog

// Copyright (c) 2023-2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
// retroSoC is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`include "soc_nmi_defs.svh"
module dma_core (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
input logic [2:0] mode_i,
input logic [31:0] srcaddr_i,
input logic srcincr_i,
input logic [31:0] dstaddr_i,
input logic dstincr_i,
input logic [31:0] xferlen_i,
input logic start_i,
input logic stop_i,
input logic reset_i,
output logic done_o,
output logic error_o,
output logic [2:0] error_code_o,
output logic [31:0] error_addr_o,
output logic [1:0] fsm_o,
dma_hw_trg_if.dut hw_trg,
soc_nmi_if.master nmi
// verilog_format: on
);
// mode val
// 7-5: resv
// 4: xpi rx fifo trg
// 3: xpi tx fifo trg
// 2: i2s rx fifo trg
// 1: i2s tx fifo trg
// 0: sft trg
localparam SFT_TRG = 3'd0;
localparam HWT_I2S_TX_TRG = 3'd1;
localparam HWT_I2S_RX_TRG = 3'd2;
localparam HWT_QSPI_TX_TRG = 3'd3;
localparam HWT_QSPI_RX_TRG = 3'd4;
localparam FSM_IDLE = 2'd0;
localparam FSM_XFER = 2'd1;
localparam FSM_DONE = 2'd2;
logic [1:0] s_fsm_d, s_fsm_q;
logic [31:0] s_xfer_cnt_d, s_xfer_cnt_q;
logic [31:0] s_src_addr_d, s_src_addr_q;
logic [31:0] s_dst_addr_d, s_dst_addr_q;
logic [31:0] s_rd_data_d, s_rd_data_q;
logic s_xfer_type_d, s_xfer_type_q; // 0: rd 1: wr
logic s_xfer_done_d, s_xfer_done_q;
logic s_ctrl_stop_d, s_ctrl_stop_q;
// Registered NMI master outputs
logic s_nmi_valid_d, s_nmi_valid_q;
logic [31:0] s_nmi_addr_d, s_nmi_addr_q;
logic [31:0] s_nmi_wdata_d, s_nmi_wdata_q;
logic [3:0] s_nmi_wstrb_d, s_nmi_wstrb_q;
assign fsm_o = s_fsm_q;
assign nmi.valid = s_nmi_valid_q;
assign nmi.addr = s_nmi_addr_q;
assign nmi.wdata = s_nmi_wdata_q;
assign nmi.wstrb = s_nmi_wstrb_q;
always_comb begin
s_fsm_d = s_fsm_q;
s_src_addr_d = s_src_addr_q;
s_dst_addr_d = s_dst_addr_q;
s_rd_data_d = s_rd_data_q;
s_xfer_cnt_d = s_xfer_cnt_q;
s_xfer_type_d = s_xfer_type_q;
s_xfer_done_d = s_xfer_done_q;
// nmi if (registered outputs)
s_nmi_valid_d = '0;
s_nmi_addr_d = s_nmi_addr_q;
s_nmi_wdata_d = s_nmi_wdata_q;
s_nmi_wstrb_d = '0;
// common
done_o = '0;
error_o = 1'b0;
error_code_o = `SOC_NMI_RESP_OK;
error_addr_o = s_nmi_addr_q;
unique case (s_fsm_q)
FSM_IDLE: begin
if (start_i) begin
s_fsm_d = FSM_XFER;
s_src_addr_d = srcaddr_i;
s_dst_addr_d = dstaddr_i;
s_xfer_cnt_d = '0;
s_xfer_type_d = 1'b0;
s_xfer_done_d = 1'b1;
end
end
FSM_XFER: begin
if (~s_ctrl_stop_q) begin
if (~s_xfer_type_q) begin
unique case (mode_i)
HWT_I2S_RX_TRG: begin
if (~hw_trg.i2s_rx_proc && s_xfer_done_q) s_nmi_valid_d = 1'b0;
else s_nmi_valid_d = 1'b1;
end
HWT_QSPI_RX_TRG: begin
if (~hw_trg.qspi_rx_proc && s_xfer_done_q) s_nmi_valid_d = 1'b0;
else s_nmi_valid_d = 1'b1;
end
default: s_nmi_valid_d = 1'b1;
endcase
s_nmi_addr_d = s_src_addr_q;
if (nmi.valid && nmi.ready) begin
s_nmi_valid_d = 1'b0;
if (nmi.resp_err) begin
s_fsm_d = FSM_IDLE;
error_o = 1'b1;
error_code_o = nmi.resp_code;
end else begin
s_xfer_type_d = 1'b1;
s_xfer_done_d = 1'b1;
s_rd_data_d = nmi.rdata;
end
end else if (nmi.valid) begin
s_xfer_done_d = 1'b0;
end
end else begin
unique case (mode_i)
HWT_I2S_TX_TRG: begin
if (~hw_trg.i2s_tx_proc && s_xfer_done_q) s_nmi_valid_d = 1'b0;
else s_nmi_valid_d = 1'b1;
end
HWT_QSPI_TX_TRG: begin
if (~hw_trg.qspi_tx_proc && s_xfer_done_q) s_nmi_valid_d = 1'b0;
else s_nmi_valid_d = 1'b1;
end
default: s_nmi_valid_d = 1'b1;
endcase
s_nmi_addr_d = s_dst_addr_q;
s_nmi_wdata_d = s_rd_data_q;
s_nmi_wstrb_d = '1;
if (nmi.valid && nmi.ready) begin
s_nmi_valid_d = 1'b0;
if (nmi.resp_err) begin
s_fsm_d = FSM_IDLE;
error_o = 1'b1;
error_code_o = nmi.resp_code;
end else begin
s_xfer_type_d = 1'b0;
s_xfer_done_d = 1'b1;
// when src rd+wr xfer done
if ((s_xfer_cnt_q + 32'd1) == xferlen_i) begin
s_xfer_cnt_d = '0;
s_fsm_d = FSM_DONE;
end else begin
s_xfer_cnt_d = s_xfer_cnt_q + 1'b1;
if (srcincr_i) s_src_addr_d = s_src_addr_q + 32'd4;
if (dstincr_i) s_dst_addr_d = s_dst_addr_q + 32'd4;
end
end
end else if (nmi.valid) s_xfer_done_d = 1'b0;
end
end else begin
if (reset_i) s_fsm_d = FSM_IDLE;
end
end
FSM_DONE: begin
done_o = 1'b1;
s_fsm_d = FSM_IDLE;
end
default: begin
s_fsm_d = s_fsm_q;
s_src_addr_d = s_src_addr_q;
s_dst_addr_d = s_dst_addr_q;
s_rd_data_d = s_rd_data_q;
s_xfer_cnt_d = s_xfer_cnt_q;
s_xfer_type_d = s_xfer_type_q;
s_xfer_done_d = s_xfer_done_q;
// nmi if
s_nmi_valid_d = '0;
s_nmi_addr_d = '0;
s_nmi_wdata_d = '0;
s_nmi_wstrb_d = '0;
// common
done_o = '0;
error_o = 1'b0;
error_code_o = `SOC_NMI_RESP_OK;
error_addr_o = s_nmi_addr_q;
end
endcase
end
dffr #(2) u_fsm_dffr (
clk_i,
rst_n_i,
s_fsm_d,
s_fsm_q
);
dffr #(32) u_xfer_cnt_dffr (
clk_i,
rst_n_i,
s_xfer_cnt_d,
s_xfer_cnt_q
);
dffr #(32) u_src_addr_dffr (
clk_i,
rst_n_i,
s_src_addr_d,
s_src_addr_q
);
dffr #(32) u_dst_addr_dffr (
clk_i,
rst_n_i,
s_dst_addr_d,
s_dst_addr_q
);
dffr #(32) u_rd_data_dffr (
clk_i,
rst_n_i,
s_rd_data_d,
s_rd_data_q
);
dffr #(1) u_xfer_type_dffr (
clk_i,
rst_n_i,
s_xfer_type_d,
s_xfer_type_q
);
dffr #(1) u_xfer_done_dffr (
clk_i,
rst_n_i,
s_xfer_done_d,
s_xfer_done_q
);
// control the xfer
always_comb begin
s_ctrl_stop_d = s_ctrl_stop_q;
if (stop_i) s_ctrl_stop_d = ~s_ctrl_stop_q;
end
dffr #(1) u_ctrl_stop_dffr (
clk_i,
rst_n_i,
s_ctrl_stop_d,
s_ctrl_stop_q
);
// Registered NMI master outputs
dffr #(1) u_nmi_valid_dffr (
clk_i,
rst_n_i,
s_nmi_valid_d,
s_nmi_valid_q
);
dffr #(32) u_nmi_addr_dffr (
clk_i,
rst_n_i,
s_nmi_addr_d,
s_nmi_addr_q
);
dffr #(32) u_nmi_wdata_dffr (
clk_i,
rst_n_i,
s_nmi_wdata_d,
s_nmi_wdata_q
);
dffr #(4) u_nmi_wstrb_dffr (
clk_i,
rst_n_i,
s_nmi_wstrb_d,
s_nmi_wstrb_q
);
endmodule