Files
retroSoC/rtl/ip/native/serial/uart.sv
T
maksyuki fb3621e6b8 feat: add QSPI Flash and Flash Read Binder modules
- Introduced  for handling QSPI flash memory operations, including command and address handling.
- Added  to interface with the C++ flash memory implementation, allowing for read operations via DPI-C.
- Created  for the flash memory implementation, supporting initialization, reading, and memory copying.
- Updated  to integrate the new QSPI Flash module and connect it with the existing system.
- Refactored file paths in various filelists and scripts to accommodate the new directory structure under .
- Enhanced the Python scripts for generating memory maps and preparing the environment for the new structure.
- Adjusted test scripts to reflect changes in the directory structure and ensure compatibility with the new modules.
2026-07-20 16:50:57 +08:00

195 lines
6.2 KiB
Systemverilog

/*
* Ravenna - A full example SoC using PicoRV32 in ASIC
*
* Copyright (C) 2017 Clifford Wolf <clifford@clifford.at>
* Copyright (C) 2018,2019 Tim Edwards <tim@efabless.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
// -- Adaptable modifications are redistributed under compatible License --
//
// 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.
`ifndef NMI_UART_DEF_SV
`define NMI_UART_DEF_SV
// verilog_format: off
`define NMI_UART_DIV 8'h00
`define NMI_UART_DAT 8'h04
// verilog_format: on
`endif
module nmi_uart (
// verilog_format: off
input logic clk_i,
input logic rst_n_i,
nmi_if.slave nmi,
uart_if.dut uart
// verilog_format: on
);
logic s_nmi_wr_hdshk, s_nmi_rd_hdshk;
logic s_nmi_ready_d, s_nmi_ready_q;
logic s_nmi_rdata_en;
logic [31:0] s_nmi_rdata_d, s_nmi_rdata_q;
logic s_uart_div_en;
logic [31:0] s_uart_div_d, s_uart_div_q;
logic s_send_dat_wait;
logic s_uart_dat_en;
// register
logic [ 3:0] r_recv_state;
logic [31:0] r_recv_divcnt;
logic [ 7:0] r_recv_pattern;
logic [ 7:0] r_recv_buf_data;
logic r_recv_buf_valid;
logic [ 9:0] r_send_pattern;
logic [ 3:0] r_send_bitcnt;
logic [31:0] r_send_divcnt;
logic r_send_dummy;
assign s_nmi_wr_hdshk = nmi.valid && (~s_nmi_ready_q) && (|nmi.wstrb);
assign s_nmi_rd_hdshk = nmi.valid && (~s_nmi_ready_q) && (~(|nmi.wstrb));
assign nmi.ready = s_nmi_ready_q;
assign nmi.rdata = s_nmi_rdata_q;
assign uart.tx_o = r_send_pattern[0];
assign uart.irq_o = r_recv_buf_valid;
assign s_uart_div_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NMI_UART_DIV;
always_comb begin
s_uart_div_d = s_uart_div_q;
if (nmi.wstrb[0]) s_uart_div_d[7:0] = nmi.wdata[7:0];
if (nmi.wstrb[1]) s_uart_div_d[15:8] = nmi.wdata[15:8];
if (nmi.wstrb[2]) s_uart_div_d[23:16] = nmi.wdata[23:16];
if (nmi.wstrb[3]) s_uart_div_d[31:24] = nmi.wdata[31:24];
end
dfferh #(32) u_uart_div_dfferh (
clk_i,
rst_n_i,
s_uart_div_en,
s_uart_div_d,
s_uart_div_q
);
assign s_uart_dat_en = s_nmi_wr_hdshk && nmi.addr[7:0] == `NMI_UART_DAT;
assign s_send_dat_wait = s_uart_dat_en && nmi.wstrb[0] && ((|r_send_bitcnt) || r_send_dummy);
assign s_nmi_ready_d = nmi.valid && (~s_nmi_ready_q) && (~s_send_dat_wait);
dffr #(1) u_nmi_ready_dffr (
clk_i,
rst_n_i,
s_nmi_ready_d,
s_nmi_ready_q
);
assign s_nmi_rdata_en = s_nmi_rd_hdshk;
always_comb begin
s_nmi_rdata_d = s_nmi_rdata_q;
unique case (nmi.addr[7:0])
`NMI_UART_DIV: s_nmi_rdata_d = s_uart_div_q;
`NMI_UART_DAT: s_nmi_rdata_d = r_recv_buf_valid ? {24'd0, r_recv_buf_data} : '1;
default: s_nmi_rdata_d = s_nmi_rdata_q;
endcase
end
dffer #(32) u_nmi_rdata_dffer (
clk_i,
rst_n_i,
s_nmi_rdata_en,
s_nmi_rdata_d,
s_nmi_rdata_q
);
always_ff @(posedge clk_i, negedge rst_n_i) begin
if (!rst_n_i) begin
r_recv_state <= '0;
r_recv_divcnt <= '0;
r_recv_pattern <= '0;
r_recv_buf_data <= '0;
r_recv_buf_valid <= '0;
end else begin
r_recv_divcnt <= r_recv_divcnt + 1'b1;
if (s_uart_dat_en) r_recv_buf_valid <= '0;
case (r_recv_state)
4'd0: begin
if (!uart.rx_i) r_recv_state <= 4'b1;
r_recv_divcnt <= '0;
end
4'd1: begin
if (2 * r_recv_divcnt > s_uart_div_q) begin
r_recv_state <= 4'd2;
r_recv_divcnt <= '0;
end
end
4'd10: begin
if (r_recv_divcnt > s_uart_div_q) begin
r_recv_buf_data <= r_recv_pattern;
r_recv_buf_valid <= 1'b1;
r_recv_state <= '0;
end
end
default: begin
if (r_recv_divcnt > s_uart_div_q) begin
r_recv_pattern <= {uart.rx_i, r_recv_pattern[7:1]};
r_recv_state <= r_recv_state + 1'b1;
r_recv_divcnt <= '0;
end
end
endcase
end
end
always_ff @(posedge clk_i, negedge rst_n_i) begin
if (!rst_n_i) begin
r_send_pattern <= '1;
r_send_bitcnt <= '0;
r_send_divcnt <= '0;
r_send_dummy <= 1'b1;
end else begin
if (s_uart_div_en) r_send_dummy <= 1'b1;
r_send_divcnt <= r_send_divcnt + 1'b1;
if (r_send_dummy && (~(|r_send_bitcnt))) begin
r_send_pattern <= '1;
r_send_bitcnt <= 4'd15;
r_send_divcnt <= '0;
r_send_dummy <= '0;
end else if (s_uart_dat_en && nmi.wstrb[0] && (~(|r_send_bitcnt))) begin
r_send_pattern <= {1'b1, nmi.wdata[7:0], 1'b0};
`ifndef SYNTHESIS
`ifdef SIMU_VERILATOR
$write("%c", nmi.wdata[7:0]); // NOTE: just for verilator sim
`endif
`endif
r_send_bitcnt <= 4'd10;
r_send_divcnt <= '0;
end else if (r_send_divcnt > s_uart_div_q && (|r_send_bitcnt)) begin
r_send_pattern <= {1'b1, r_send_pattern[9:1]};
r_send_bitcnt <= r_send_bitcnt - 1'b1;
r_send_divcnt <= '0;
end
end
end
endmodule