rtl: perips: rewrite uart module
Signed-off-by: liangkangnan <liangkangnan@163.com>pull/4/head
parent
cba47c1f64
commit
58f180a92f
12
rtl.flist
12
rtl.flist
|
@ -37,9 +37,14 @@
|
|||
../rtl/perips/ram.sv
|
||||
../rtl/perips/rom.sv
|
||||
../rtl/perips/timer.sv
|
||||
../rtl/perips/uart.sv
|
||||
../rtl/perips/machine_timer.sv
|
||||
../rtl/perips/rvic.sv
|
||||
../rtl/perips/uart/uart_reg_pkg.sv
|
||||
../rtl/perips/uart/uart_reg_top.sv
|
||||
../rtl/perips/uart/uart_core.sv
|
||||
../rtl/perips/uart/uart_rx.sv
|
||||
../rtl/perips/uart/uart_top.sv
|
||||
../rtl/perips/uart/uart_tx.sv
|
||||
|
||||
../rtl/sys_bus/obi_interconnect.sv
|
||||
../rtl/sys_bus/obi_interconnect_master_sel.sv
|
||||
|
@ -52,3 +57,8 @@
|
|||
../rtl/utils/gen_ram.sv
|
||||
../rtl/utils/cdc_2phase.sv
|
||||
../rtl/utils/sync_fifo.sv
|
||||
../rtl/utils/clk_div.sv
|
||||
../rtl/utils/edge_detect.sv
|
||||
../rtl/utils/prim_subreg.sv
|
||||
../rtl/utils/prim_subreg_arb.sv
|
||||
../rtl/utils/prim_subreg_ext.sv
|
||||
|
|
|
@ -37,9 +37,9 @@
|
|||
// Timer
|
||||
`define TIMER_ADDR_MASK ~32'hffff
|
||||
`define TIMER_ADDR_BASE 32'h40000000
|
||||
// UART
|
||||
`define UART_ADDR_MASK ~32'hffff
|
||||
`define UART_ADDR_BASE 32'h50000000
|
||||
// UART0
|
||||
`define UART0_ADDR_MASK ~32'hffff
|
||||
`define UART0_ADDR_BASE 32'h50000000
|
||||
// Machine Timer
|
||||
`define MTIMER_ADDR_MASK ~32'hffff
|
||||
`define MTIMER_ADDR_BASE 32'hA0000000
|
||||
|
|
|
@ -1,425 +0,0 @@
|
|||
/*
|
||||
Copyright 2020 Blue Liang, liangkangnan@163.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
`include "../core/defines.sv"
|
||||
|
||||
// 串口收发模块(默认: 115200, 8,N,1)
|
||||
module uart(
|
||||
|
||||
input wire clk,
|
||||
input wire rst_n,
|
||||
input wire[31:0] addr_i,
|
||||
input wire[31:0] data_i,
|
||||
input wire[3:0] sel_i,
|
||||
input wire we_i,
|
||||
output wire[31:0] data_o,
|
||||
|
||||
output wire tx_pin,
|
||||
input wire rx_pin
|
||||
|
||||
);
|
||||
|
||||
// 波特率115200bps
|
||||
localparam BAUD_115200 = `CPU_CLOCK_HZ / 115200;
|
||||
|
||||
localparam S_IDLE = 4'b0001;
|
||||
localparam S_START = 4'b0010;
|
||||
localparam S_SEND_BYTE = 4'b0100;
|
||||
localparam S_STOP = 4'b1000;
|
||||
|
||||
|
||||
reg[3:0] state;
|
||||
reg[3:0] next_state;
|
||||
reg[15:0] cycle_cnt;
|
||||
reg tx_bit;
|
||||
reg[3:0] bit_cnt;
|
||||
|
||||
reg rx_q0;
|
||||
reg rx_q1;
|
||||
wire rx_negedge;
|
||||
reg rx_start; // RX使能
|
||||
reg[3:0] rx_clk_edge_cnt; // clk沿的个数
|
||||
reg rx_clk_edge_level; // clk沿电平
|
||||
reg rx_done;
|
||||
reg[15:0] rx_clk_cnt;
|
||||
reg[15:0] rx_div_cnt;
|
||||
reg[7:0] rx_data;
|
||||
reg rx_over;
|
||||
|
||||
// 寄存器(偏移)地址
|
||||
localparam UART_CTRL = 8'h0;
|
||||
localparam UART_STATUS = 8'h4;
|
||||
localparam UART_BAUD = 8'h8;
|
||||
localparam UART_TXDATA = 8'hc;
|
||||
localparam UART_RXDATA = 8'h10;
|
||||
|
||||
// UART控制寄存器,可读可写
|
||||
// bit[0]: UART TX使能, 1: enable, 0: disable
|
||||
// bit[1]: UART RX使能, 1: enable, 0: disable
|
||||
reg[31:0] uart_ctrl;
|
||||
|
||||
// UART状态寄存器
|
||||
// 只读,bit[0]: TX空闲状态标志, 1: busy, 0: idle
|
||||
// 可读可写,bit[1]: RX接收完成标志, 1: over, 0: receiving
|
||||
reg[31:0] uart_status;
|
||||
|
||||
// UART波特率寄存器(分频系数),可读可写
|
||||
reg[31:0] uart_baud;
|
||||
|
||||
// UART发送数据寄存器,可读可写
|
||||
reg[31:0] uart_tx;
|
||||
|
||||
// UART接收数据寄存器,只读
|
||||
reg[31:0] uart_rx;
|
||||
|
||||
wire wen = we_i;
|
||||
wire ren = (~we_i);
|
||||
wire write_reg_ctrl_en = wen & (addr_i[7:0] == UART_CTRL);
|
||||
wire write_reg_status_en = wen & (addr_i[7:0] == UART_STATUS);
|
||||
wire write_reg_baud_en = wen & (addr_i[7:0] == UART_BAUD);
|
||||
wire write_reg_txdata_en = wen & (addr_i[7:0] == UART_TXDATA);
|
||||
wire tx_start = write_reg_txdata_en & sel_i[0] & uart_ctrl[0] & (~uart_status[0]);
|
||||
wire rx_recv_over = uart_ctrl[1] & rx_over;
|
||||
|
||||
assign tx_pin = tx_bit;
|
||||
|
||||
|
||||
// 写uart_rxdata
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
uart_rx <= 32'h0;
|
||||
end else begin
|
||||
// 接收完成时,保存接收到的数据
|
||||
if (rx_recv_over) begin
|
||||
uart_rx[7:0] <= rx_data;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 写uart_txdata
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
uart_tx <= 32'h0;
|
||||
end else begin
|
||||
// 开始发送时,保存要发送的数据
|
||||
if (tx_start) begin
|
||||
uart_tx[7:0] <= data_i[7:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 写uart_status
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
uart_status <= 32'h0;
|
||||
end else begin
|
||||
if (write_reg_status_en & sel_i[0]) begin
|
||||
// 写RX完成标志
|
||||
uart_status[1] <= data_i[1];
|
||||
end else begin
|
||||
// 开始发送数据时,置位TX忙标志
|
||||
if (tx_start) begin
|
||||
uart_status[0] <= 1'b1;
|
||||
// 发送完成时,清TX忙标志
|
||||
end else if ((state == S_STOP) & (cycle_cnt == uart_baud[15:0])) begin
|
||||
uart_status[0] <= 1'b0;
|
||||
// 接收完成,置位接收完成标志
|
||||
end
|
||||
if (rx_recv_over) begin
|
||||
uart_status[1] <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 写uart_ctrl
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
uart_ctrl <= 32'h0;
|
||||
end else begin
|
||||
if (write_reg_ctrl_en & sel_i[0]) begin
|
||||
uart_ctrl[7:0] <= data_i[7:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 写uart_baud
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
uart_baud <= BAUD_115200;
|
||||
end else begin
|
||||
if (write_reg_baud_en) begin
|
||||
if (sel_i[0]) begin
|
||||
uart_baud[7:0] <= data_i[7:0];
|
||||
end
|
||||
if (sel_i[1]) begin
|
||||
uart_baud[15:8] <= data_i[15:8];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reg[31:0] data_r;
|
||||
|
||||
// 读寄存器
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
data_r <= 32'h0;
|
||||
end else begin
|
||||
if (ren) begin
|
||||
case (addr_i[7:0])
|
||||
UART_CTRL: data_r <= uart_ctrl;
|
||||
UART_STATUS: data_r <= uart_status;
|
||||
UART_BAUD: data_r <= uart_baud;
|
||||
UART_RXDATA: data_r <= uart_rx;
|
||||
default: data_r <= 32'h0;
|
||||
endcase
|
||||
end else begin
|
||||
data_r <= 32'h0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign data_o = data_r;
|
||||
|
||||
// *************************** TX发送 ****************************
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
state <= S_IDLE;
|
||||
end else begin
|
||||
state <= next_state;
|
||||
end
|
||||
end
|
||||
|
||||
always @ (*) begin
|
||||
case (state)
|
||||
S_IDLE: begin
|
||||
if (tx_start) begin
|
||||
next_state = S_START;
|
||||
end else begin
|
||||
next_state = S_IDLE;
|
||||
end
|
||||
end
|
||||
S_START: begin
|
||||
if (cycle_cnt == uart_baud[15:0]) begin
|
||||
next_state = S_SEND_BYTE;
|
||||
end else begin
|
||||
next_state = S_START;
|
||||
end
|
||||
end
|
||||
S_SEND_BYTE: begin
|
||||
if ((cycle_cnt == uart_baud[15:0]) & (bit_cnt == 4'd7)) begin
|
||||
next_state = S_STOP;
|
||||
end else begin
|
||||
next_state = S_SEND_BYTE;
|
||||
end
|
||||
end
|
||||
S_STOP: begin
|
||||
if (cycle_cnt == uart_baud[15:0]) begin
|
||||
next_state = S_IDLE;
|
||||
end else begin
|
||||
next_state = S_STOP;
|
||||
end
|
||||
end
|
||||
default: begin
|
||||
next_state = S_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// cycle_cnt
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
cycle_cnt <= 16'h0;
|
||||
end else begin
|
||||
if (state == S_IDLE) begin
|
||||
cycle_cnt <= 16'h0;
|
||||
end else begin
|
||||
if (cycle_cnt == uart_baud[15:0]) begin
|
||||
cycle_cnt <= 16'h0;
|
||||
end else begin
|
||||
cycle_cnt <= cycle_cnt + 16'h1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// bit_cnt
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
bit_cnt <= 4'h0;
|
||||
end else begin
|
||||
case (state)
|
||||
S_IDLE: begin
|
||||
bit_cnt <= 4'h0;
|
||||
end
|
||||
S_SEND_BYTE: begin
|
||||
if (cycle_cnt == uart_baud[15:0]) begin
|
||||
bit_cnt <= bit_cnt + 4'h1;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// tx_bit
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
tx_bit <= 1'b0;
|
||||
end else begin
|
||||
case (state)
|
||||
S_IDLE, S_STOP: begin
|
||||
tx_bit <= 1'b1;
|
||||
end
|
||||
S_START: begin
|
||||
tx_bit <= 1'b0;
|
||||
end
|
||||
S_SEND_BYTE: begin
|
||||
tx_bit <= uart_tx[bit_cnt];
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
// *************************** RX接收 ****************************
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_q0 <= 1'b0;
|
||||
rx_q1 <= 1'b0;
|
||||
end else begin
|
||||
rx_q0 <= rx_pin;
|
||||
rx_q1 <= rx_q0;
|
||||
end
|
||||
end
|
||||
|
||||
// 下降沿检测(检测起始信号)
|
||||
assign rx_negedge = rx_q1 & (~rx_q0);
|
||||
|
||||
// 产生开始接收数据信号,接收期间一直有效
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_start <= 1'b0;
|
||||
end else begin
|
||||
if (uart_ctrl[1]) begin
|
||||
if (rx_negedge) begin
|
||||
rx_start <= 1'b1;
|
||||
end else if (rx_clk_edge_cnt == 4'd9) begin
|
||||
rx_start <= 1'b0;
|
||||
end
|
||||
end else begin
|
||||
rx_start <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_div_cnt <= 16'h0;
|
||||
end else begin
|
||||
// 第一个时钟沿只需波特率分频系数的一半
|
||||
if (rx_start == 1'b1 && rx_clk_edge_cnt == 4'h0) begin
|
||||
rx_div_cnt <= {1'b0, uart_baud[15:1]};
|
||||
end else begin
|
||||
rx_div_cnt <= uart_baud[15:0];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 对时钟进行计数
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_clk_cnt <= 16'h0;
|
||||
end else if (rx_start == 1'b1) begin
|
||||
// 计数达到分频值
|
||||
if (rx_clk_cnt == rx_div_cnt) begin
|
||||
rx_clk_cnt <= 16'h0;
|
||||
end else begin
|
||||
rx_clk_cnt <= rx_clk_cnt + 16'h1;
|
||||
end
|
||||
end else begin
|
||||
rx_clk_cnt <= 16'h0;
|
||||
end
|
||||
end
|
||||
|
||||
// 每当时钟计数达到分频值时产生一个上升沿脉冲
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_clk_edge_cnt <= 4'h0;
|
||||
rx_clk_edge_level <= 1'b0;
|
||||
end else if (rx_start == 1'b1) begin
|
||||
// 计数达到分频值
|
||||
if (rx_clk_cnt == rx_div_cnt) begin
|
||||
// 时钟沿个数达到最大值
|
||||
if (rx_clk_edge_cnt == 4'd9) begin
|
||||
rx_clk_edge_cnt <= 4'h0;
|
||||
rx_clk_edge_level <= 1'b0;
|
||||
end else begin
|
||||
// 时钟沿个数加1
|
||||
rx_clk_edge_cnt <= rx_clk_edge_cnt + 4'h1;
|
||||
// 产生上升沿脉冲
|
||||
rx_clk_edge_level <= 1'b1;
|
||||
end
|
||||
end else begin
|
||||
rx_clk_edge_level <= 1'b0;
|
||||
end
|
||||
end else begin
|
||||
rx_clk_edge_cnt <= 4'h0;
|
||||
rx_clk_edge_level <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// bit序列
|
||||
always @ (posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rx_data <= 8'h0;
|
||||
rx_over <= 1'b0;
|
||||
end else begin
|
||||
if (rx_start == 1'b1) begin
|
||||
// 上升沿
|
||||
if (rx_clk_edge_level == 1'b1) begin
|
||||
case (rx_clk_edge_cnt)
|
||||
// 起始位
|
||||
1: begin
|
||||
|
||||
end
|
||||
// 第1位数据位
|
||||
2: begin
|
||||
if (rx_pin) begin
|
||||
rx_data <= 8'h80;
|
||||
end else begin
|
||||
rx_data <= 8'h0;
|
||||
end
|
||||
end
|
||||
// 剩余数据位
|
||||
3, 4, 5, 6, 7, 8, 9: begin
|
||||
rx_data <= {rx_pin, rx_data[7:1]};
|
||||
// 最后一位接收完成,置位接收完成标志
|
||||
if (rx_clk_edge_cnt == 4'h9) begin
|
||||
rx_over <= 1'b1;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end else begin
|
||||
rx_data <= 8'h0;
|
||||
rx_over <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,107 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
{ name: "uart",
|
||||
clocking: [{clock: "clk_i", reset: "rst_ni"}],
|
||||
bus_interfaces: [
|
||||
{ protocol: "tlul", direction: "device" }
|
||||
],
|
||||
regwidth: "32",
|
||||
registers: [
|
||||
{ name: "CTRL",
|
||||
desc: "UART control register",
|
||||
swaccess: "rw",
|
||||
hwaccess: "hro",
|
||||
hwqe: "true",
|
||||
fields: [
|
||||
{ bits: "0",
|
||||
name: "TX_EN",
|
||||
desc: "TX enable"
|
||||
}
|
||||
{ bits: "1",
|
||||
name: "RX_EN",
|
||||
desc: "RX enable"
|
||||
}
|
||||
{ bits: "2",
|
||||
name: "TX_FIFO_EMPTY_INT_EN",
|
||||
desc: "Generate interrupt signal when tx fifo empty"
|
||||
}
|
||||
{ bits: "3",
|
||||
name: "RX_FIFO_NOT_EMPTY_INT_EN",
|
||||
desc: "Generate interrupt signal when rx fifo not empty"
|
||||
}
|
||||
{ bits: "4",
|
||||
name: "TX_FIFO_RST",
|
||||
desc: "Reset tx fifo",
|
||||
swaccess: "r0w1c"
|
||||
}
|
||||
{ bits: "5",
|
||||
name: "RX_FIFO_RST",
|
||||
desc: "Reset rx fifo",
|
||||
swaccess: "r0w1c"
|
||||
}
|
||||
{ bits: "31:16",
|
||||
name: "BAUD_DIV",
|
||||
desc: "Baud rate divider count",
|
||||
resval: "0xD9"
|
||||
}
|
||||
]
|
||||
}
|
||||
{ name: "STATUS"
|
||||
desc: "UART status register"
|
||||
swaccess: "ro"
|
||||
hwaccess: "hrw"
|
||||
hwext: "true"
|
||||
hwre: "true"
|
||||
fields: [
|
||||
{ bits: "0"
|
||||
name: "TXFULL"
|
||||
desc: "TX FIFO is full"
|
||||
}
|
||||
{ bits: "1"
|
||||
name: "RXFULL"
|
||||
desc: "RX FIFO is full"
|
||||
}
|
||||
{ bits: "2"
|
||||
name: "TXEMPTY"
|
||||
desc: "TX FIFO is empty"
|
||||
resval: "1"
|
||||
}
|
||||
{ bits: "3"
|
||||
name: "RXEMPTY"
|
||||
desc: "RX FIFO is empty"
|
||||
resval: "1"
|
||||
}
|
||||
{ bits: "4"
|
||||
name: "TXIDLE"
|
||||
desc: "TX FIFO is empty and all bits have been transmitted"
|
||||
resval: "1"
|
||||
}
|
||||
{ bits: "5"
|
||||
name: "RXIDLE"
|
||||
desc: "RX is idle"
|
||||
resval: "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
{ name: "TXDATA",
|
||||
desc: "UART TX data register",
|
||||
swaccess: "wo",
|
||||
hwaccess: "hro",
|
||||
hwqe: "true",
|
||||
fields: [
|
||||
{ bits: "7:0" }
|
||||
]
|
||||
}
|
||||
{ name: "RXDATA",
|
||||
desc: "UART RX data register",
|
||||
swaccess: "ro",
|
||||
hwaccess: "hrw",
|
||||
hwext: "true",
|
||||
hwre: "true",
|
||||
fields: [
|
||||
{ bits: "7:0" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
module uart_core # (
|
||||
parameter int unsigned TX_FIFO_DEPTH = 8,
|
||||
parameter int unsigned RX_FIFO_DEPTH = 8
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
output logic tx_pin_o,
|
||||
input logic rx_pin_i,
|
||||
output logic irq_o,
|
||||
|
||||
input logic reg_we_i,
|
||||
input logic reg_re_i,
|
||||
input logic [31:0] reg_wdata_i,
|
||||
input logic [ 3:0] reg_be_i,
|
||||
input logic [31:0] reg_addr_i,
|
||||
output logic [31:0] reg_rdata_o
|
||||
);
|
||||
|
||||
import uart_reg_pkg::*;
|
||||
|
||||
uart_reg_pkg::uart_reg2hw_t reg2hw;
|
||||
uart_reg_pkg::uart_hw2reg_t hw2reg;
|
||||
|
||||
logic tx_enable;
|
||||
logic rx_enable;
|
||||
logic [15:0] baud_div;
|
||||
logic tx_fifo_empty_int_en;
|
||||
logic rx_fifo_not_empty_int_en;
|
||||
logic tx_fifo_rst;
|
||||
logic rx_fifo_rst;
|
||||
logic tx_idle;
|
||||
logic rx_idle;
|
||||
logic rx_error;
|
||||
logic tx_fifo_full;
|
||||
logic rx_fifo_full;
|
||||
logic tx_fifo_empty;
|
||||
logic rx_fifo_empty;
|
||||
logic tx_we;
|
||||
logic [7:0] tx_wdata;
|
||||
logic [7:0] rx_rdata;
|
||||
logic rx_rvalid;
|
||||
logic tx_fifo_pop;
|
||||
logic rx_fifo_pop;
|
||||
logic tx_fifo_push;
|
||||
logic rx_fifo_push;
|
||||
logic [7:0] tx_fifo_data_out;
|
||||
logic [7:0] rx_fifo_data_out;
|
||||
logic [7:0] tx_fifo_data_in;
|
||||
logic [7:0] rx_fifo_data_in;
|
||||
|
||||
// 波特率分频系数
|
||||
assign baud_div = reg2hw.ctrl.baud_div.q;
|
||||
|
||||
// TX
|
||||
assign tx_enable = reg2hw.ctrl.tx_en.q;
|
||||
assign tx_fifo_empty_int_en = reg2hw.ctrl.tx_fifo_empty_int_en.q;
|
||||
// 写1清TX fifo
|
||||
assign tx_fifo_rst = reg2hw.ctrl.tx_fifo_rst.qe & reg2hw.ctrl.tx_fifo_rst.q;
|
||||
|
||||
assign hw2reg.status.txidle.d = tx_enable ? (tx_idle & tx_fifo_empty) : 1'b1;
|
||||
assign hw2reg.status.txfull.d = tx_fifo_full;
|
||||
assign hw2reg.status.txempty.d = tx_fifo_empty;
|
||||
|
||||
// TX开始发送数据
|
||||
assign tx_we = tx_enable & (!tx_fifo_empty) & tx_idle;
|
||||
// 要发送的数据
|
||||
assign tx_wdata = tx_fifo_data_out;
|
||||
// 取出fifo数据
|
||||
assign tx_fifo_pop = tx_enable & (!tx_fifo_empty) & tx_idle;
|
||||
// 可以先push完数据再使能TX
|
||||
assign tx_fifo_push = reg2hw.txdata.qe & (!tx_fifo_full);
|
||||
// 要压入fifo的数据
|
||||
assign tx_fifo_data_in = reg2hw.txdata.q;
|
||||
|
||||
// RX
|
||||
assign rx_enable = reg2hw.ctrl.rx_en.q;
|
||||
assign rx_fifo_not_empty_int_en = reg2hw.ctrl.rx_fifo_not_empty_int_en.q;
|
||||
// 写1清RX fifo
|
||||
assign rx_fifo_rst = reg2hw.ctrl.rx_fifo_rst.qe & reg2hw.ctrl.rx_fifo_rst.q;
|
||||
|
||||
assign hw2reg.status.rxidle.d = rx_enable ? rx_idle : 1'b1;
|
||||
assign hw2reg.status.rxfull.d = rx_fifo_full;
|
||||
assign hw2reg.status.rxempty.d = rx_fifo_empty;
|
||||
assign hw2reg.rxdata.d = rx_fifo_data_out;
|
||||
|
||||
// 将接收到的数据压入fifo
|
||||
assign rx_fifo_push = (~rx_fifo_full) & rx_rvalid;
|
||||
// 要压入的数据
|
||||
assign rx_fifo_data_in = rx_rdata;
|
||||
// 可以在不使能RX的情况下直接读RX fifo里面的数据
|
||||
assign rx_fifo_pop = reg2hw.rxdata.re & (~rx_fifo_empty);
|
||||
|
||||
// 中断信号
|
||||
assign irq_o = (tx_enable & tx_fifo_empty_int_en & tx_fifo_empty) |
|
||||
(rx_enable & rx_fifo_not_empty_int_en & (~rx_fifo_empty));
|
||||
|
||||
// TX byte
|
||||
uart_tx u_uart_tx (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.enable_i (tx_enable),
|
||||
.parity_en_i(1'b0),
|
||||
.parity_i (1'b1),
|
||||
.we_i (tx_we),
|
||||
.wdata_i (tx_wdata),
|
||||
.div_ratio_i(baud_div),
|
||||
.idle_o (tx_idle),
|
||||
.tx_bit_o (tx_pin_o)
|
||||
);
|
||||
|
||||
// TX FIFO
|
||||
sync_fifo #(
|
||||
.DATA_WIDTH(8),
|
||||
.DEPTH(TX_FIFO_DEPTH)
|
||||
) u_tx_fifo (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.flush_i (tx_fifo_rst),
|
||||
.testmode_i (1'b0),
|
||||
.full_o (tx_fifo_full),
|
||||
.empty_o (tx_fifo_empty),
|
||||
.usage_o (),
|
||||
.data_i (tx_fifo_data_in),
|
||||
.push_i (tx_fifo_push),
|
||||
.data_o (tx_fifo_data_out),
|
||||
.pop_i (tx_fifo_pop)
|
||||
);
|
||||
|
||||
// RX byte
|
||||
uart_rx u_uart_rx (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.enable_i (rx_enable),
|
||||
.parity_en_i (1'b0),
|
||||
.parity_odd_i (1'b1),
|
||||
.div_ratio_i (baud_div),
|
||||
.rx_i (rx_pin_i),
|
||||
.idle_o (rx_idle),
|
||||
.err_o (rx_error),
|
||||
.rdata_o (rx_rdata),
|
||||
.rvalid_o (rx_rvalid)
|
||||
);
|
||||
|
||||
// RX FIFO
|
||||
sync_fifo #(
|
||||
.DATA_WIDTH(8),
|
||||
.DEPTH(RX_FIFO_DEPTH)
|
||||
) u_rx_fifo (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.flush_i (rx_fifo_rst),
|
||||
.testmode_i (1'b0),
|
||||
.full_o (rx_fifo_full),
|
||||
.empty_o (rx_fifo_empty),
|
||||
.usage_o (),
|
||||
.data_i (rx_fifo_data_in),
|
||||
.push_i (rx_fifo_push),
|
||||
.data_o (rx_fifo_data_out),
|
||||
.pop_i (rx_fifo_pop)
|
||||
);
|
||||
|
||||
uart_reg_top u_uart_reg_top (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.reg2hw (reg2hw),
|
||||
.hw2reg (hw2reg),
|
||||
.reg_we (reg_we_i),
|
||||
.reg_re (reg_re_i),
|
||||
.reg_wdata (reg_wdata_i),
|
||||
.reg_be (reg_be_i),
|
||||
.reg_addr (reg_addr_i),
|
||||
.reg_rdata (reg_rdata_o)
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,154 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Register Package auto-generated by `reggen` containing data structure
|
||||
|
||||
package uart_reg_pkg;
|
||||
|
||||
// Address widths within the block
|
||||
parameter int BlockAw = 4;
|
||||
|
||||
////////////////////////////
|
||||
// Typedefs for registers //
|
||||
////////////////////////////
|
||||
|
||||
typedef struct packed {
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} tx_en;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} rx_en;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} tx_fifo_empty_int_en;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} rx_fifo_not_empty_int_en;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} tx_fifo_rst;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic qe;
|
||||
} rx_fifo_rst;
|
||||
struct packed {
|
||||
logic [15:0] q;
|
||||
logic qe;
|
||||
} baud_div;
|
||||
} uart_reg2hw_ctrl_reg_t;
|
||||
|
||||
typedef struct packed {
|
||||
struct packed {
|
||||
logic q;
|
||||
logic re;
|
||||
} txfull;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic re;
|
||||
} rxfull;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic re;
|
||||
} txempty;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic re;
|
||||
} rxempty;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic re;
|
||||
} txidle;
|
||||
struct packed {
|
||||
logic q;
|
||||
logic re;
|
||||
} rxidle;
|
||||
} uart_reg2hw_status_reg_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [7:0] q;
|
||||
logic qe;
|
||||
} uart_reg2hw_txdata_reg_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [7:0] q;
|
||||
logic re;
|
||||
} uart_reg2hw_rxdata_reg_t;
|
||||
|
||||
typedef struct packed {
|
||||
struct packed {
|
||||
logic d;
|
||||
} txfull;
|
||||
struct packed {
|
||||
logic d;
|
||||
} rxfull;
|
||||
struct packed {
|
||||
logic d;
|
||||
} txempty;
|
||||
struct packed {
|
||||
logic d;
|
||||
} rxempty;
|
||||
struct packed {
|
||||
logic d;
|
||||
} txidle;
|
||||
struct packed {
|
||||
logic d;
|
||||
} rxidle;
|
||||
} uart_hw2reg_status_reg_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [7:0] d;
|
||||
} uart_hw2reg_rxdata_reg_t;
|
||||
|
||||
// Register -> HW type
|
||||
typedef struct packed {
|
||||
uart_reg2hw_ctrl_reg_t ctrl; // [58:30]
|
||||
uart_reg2hw_status_reg_t status; // [29:18]
|
||||
uart_reg2hw_txdata_reg_t txdata; // [17:9]
|
||||
uart_reg2hw_rxdata_reg_t rxdata; // [8:0]
|
||||
} uart_reg2hw_t;
|
||||
|
||||
// HW -> register type
|
||||
typedef struct packed {
|
||||
uart_hw2reg_status_reg_t status; // [13:8]
|
||||
uart_hw2reg_rxdata_reg_t rxdata; // [7:0]
|
||||
} uart_hw2reg_t;
|
||||
|
||||
// Register offsets
|
||||
parameter logic [BlockAw-1:0] UART_CTRL_OFFSET = 4'h0;
|
||||
parameter logic [BlockAw-1:0] UART_STATUS_OFFSET = 4'h4;
|
||||
parameter logic [BlockAw-1:0] UART_TXDATA_OFFSET = 4'h8;
|
||||
parameter logic [BlockAw-1:0] UART_RXDATA_OFFSET = 4'hc;
|
||||
|
||||
// Reset values for hwext registers and their fields
|
||||
parameter logic [5:0] UART_STATUS_RESVAL = 6'h3c;
|
||||
parameter logic [0:0] UART_STATUS_TXEMPTY_RESVAL = 1'h1;
|
||||
parameter logic [0:0] UART_STATUS_RXEMPTY_RESVAL = 1'h1;
|
||||
parameter logic [0:0] UART_STATUS_TXIDLE_RESVAL = 1'h1;
|
||||
parameter logic [0:0] UART_STATUS_RXIDLE_RESVAL = 1'h1;
|
||||
parameter logic [7:0] UART_RXDATA_RESVAL = 8'h0;
|
||||
|
||||
// Register index
|
||||
typedef enum int {
|
||||
UART_CTRL,
|
||||
UART_STATUS,
|
||||
UART_TXDATA,
|
||||
UART_RXDATA
|
||||
} uart_id_e;
|
||||
|
||||
// Register width information to check illegal writes
|
||||
parameter logic [3:0] UART_PERMIT [4] = '{
|
||||
4'b1111, // index[0] UART_CTRL
|
||||
4'b0001, // index[1] UART_STATUS
|
||||
4'b0001, // index[2] UART_TXDATA
|
||||
4'b0001 // index[3] UART_RXDATA
|
||||
};
|
||||
|
||||
endpackage
|
||||
|
|
@ -0,0 +1,473 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Register Top module auto-generated by `reggen`
|
||||
|
||||
|
||||
module uart_reg_top (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
// To HW
|
||||
output uart_reg_pkg::uart_reg2hw_t reg2hw, // Write
|
||||
input uart_reg_pkg::uart_hw2reg_t hw2reg, // Read
|
||||
|
||||
input logic reg_we,
|
||||
input logic reg_re,
|
||||
input logic [31:0] reg_wdata,
|
||||
input logic [ 3:0] reg_be,
|
||||
input logic [31:0] reg_addr,
|
||||
output logic [31:0] reg_rdata
|
||||
);
|
||||
|
||||
import uart_reg_pkg::* ;
|
||||
|
||||
localparam int AW = 4;
|
||||
localparam int DW = 32;
|
||||
localparam int DBW = DW/8; // Byte Width
|
||||
|
||||
logic reg_error;
|
||||
logic addrmiss, wr_err;
|
||||
|
||||
logic [DW-1:0] reg_rdata_next;
|
||||
|
||||
assign reg_rdata = reg_rdata_next;
|
||||
assign reg_error = wr_err;
|
||||
|
||||
// Define SW related signals
|
||||
// Format: <reg>_<field>_{wd|we|qs}
|
||||
// or <reg>_{wd|we|qs} if field == 1 or 0
|
||||
logic ctrl_we;
|
||||
logic ctrl_tx_en_qs;
|
||||
logic ctrl_tx_en_wd;
|
||||
logic ctrl_rx_en_qs;
|
||||
logic ctrl_rx_en_wd;
|
||||
logic ctrl_tx_fifo_empty_int_en_qs;
|
||||
logic ctrl_tx_fifo_empty_int_en_wd;
|
||||
logic ctrl_rx_fifo_not_empty_int_en_qs;
|
||||
logic ctrl_rx_fifo_not_empty_int_en_wd;
|
||||
logic ctrl_tx_fifo_rst_wd;
|
||||
logic ctrl_rx_fifo_rst_wd;
|
||||
logic [15:0] ctrl_baud_div_qs;
|
||||
logic [15:0] ctrl_baud_div_wd;
|
||||
logic status_re;
|
||||
logic status_txfull_qs;
|
||||
logic status_rxfull_qs;
|
||||
logic status_txempty_qs;
|
||||
logic status_rxempty_qs;
|
||||
logic status_txidle_qs;
|
||||
logic status_rxidle_qs;
|
||||
logic txdata_we;
|
||||
logic [7:0] txdata_wd;
|
||||
logic rxdata_re;
|
||||
logic [7:0] rxdata_qs;
|
||||
|
||||
// Register instances
|
||||
// R[ctrl]: V(False)
|
||||
|
||||
// F[tx_en]: 0:0
|
||||
prim_subreg #(
|
||||
.DW (1),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_tx_en (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_tx_en_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (1'b0),
|
||||
.d ('0),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.tx_en.qe),
|
||||
.q (reg2hw.ctrl.tx_en.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_tx_en_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[rx_en]: 1:1
|
||||
prim_subreg #(
|
||||
.DW (1),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_rx_en (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_rx_en_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (1'b0),
|
||||
.d ('0),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.rx_en.qe),
|
||||
.q (reg2hw.ctrl.rx_en.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_rx_en_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[tx_fifo_empty_int_en]: 2:2
|
||||
prim_subreg #(
|
||||
.DW (1),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_tx_fifo_empty_int_en (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_tx_fifo_empty_int_en_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (1'b0),
|
||||
.d ('0),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.tx_fifo_empty_int_en.qe),
|
||||
.q (reg2hw.ctrl.tx_fifo_empty_int_en.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_tx_fifo_empty_int_en_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[rx_fifo_not_empty_int_en]: 3:3
|
||||
prim_subreg #(
|
||||
.DW (1),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_rx_fifo_not_empty_int_en (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_rx_fifo_not_empty_int_en_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (1'b0),
|
||||
.d ('0),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.rx_fifo_not_empty_int_en.qe),
|
||||
.q (reg2hw.ctrl.rx_fifo_not_empty_int_en.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_rx_fifo_not_empty_int_en_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[tx_fifo_rst]: 4:4
|
||||
prim_subreg #(
|
||||
.DW (1),
|
||||
.SWACCESS("W1C"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_tx_fifo_rst (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_tx_fifo_rst_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (1'b0),
|
||||
.d ('0),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.tx_fifo_rst.qe),
|
||||
.q (reg2hw.ctrl.tx_fifo_rst.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs ()
|
||||
);
|
||||
|
||||
|
||||
// F[rx_fifo_rst]: 5:5
|
||||
prim_subreg #(
|
||||
.DW (1),
|
||||
.SWACCESS("W1C"),
|
||||
.RESVAL (1'h0)
|
||||
) u_ctrl_rx_fifo_rst (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_rx_fifo_rst_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (1'b0),
|
||||
.d ('0),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.rx_fifo_rst.qe),
|
||||
.q (reg2hw.ctrl.rx_fifo_rst.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs ()
|
||||
);
|
||||
|
||||
|
||||
// F[baud_div]: 31:16
|
||||
prim_subreg #(
|
||||
.DW (16),
|
||||
.SWACCESS("RW"),
|
||||
.RESVAL (16'hd9)
|
||||
) u_ctrl_baud_div (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (ctrl_we),
|
||||
.wd (ctrl_baud_div_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (1'b0),
|
||||
.d ('0),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.ctrl.baud_div.qe),
|
||||
.q (reg2hw.ctrl.baud_div.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs (ctrl_baud_div_qs)
|
||||
);
|
||||
|
||||
|
||||
// R[status]: V(True)
|
||||
|
||||
// F[txfull]: 0:0
|
||||
prim_subreg_ext #(
|
||||
.DW (1)
|
||||
) u_status_txfull (
|
||||
.re (status_re),
|
||||
.we (1'b0),
|
||||
.wd ('0),
|
||||
.d (hw2reg.status.txfull.d),
|
||||
.qre (reg2hw.status.txfull.re),
|
||||
.qe (),
|
||||
.q (reg2hw.status.txfull.q),
|
||||
.qs (status_txfull_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[rxfull]: 1:1
|
||||
prim_subreg_ext #(
|
||||
.DW (1)
|
||||
) u_status_rxfull (
|
||||
.re (status_re),
|
||||
.we (1'b0),
|
||||
.wd ('0),
|
||||
.d (hw2reg.status.rxfull.d),
|
||||
.qre (reg2hw.status.rxfull.re),
|
||||
.qe (),
|
||||
.q (reg2hw.status.rxfull.q),
|
||||
.qs (status_rxfull_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[txempty]: 2:2
|
||||
prim_subreg_ext #(
|
||||
.DW (1)
|
||||
) u_status_txempty (
|
||||
.re (status_re),
|
||||
.we (1'b0),
|
||||
.wd ('0),
|
||||
.d (hw2reg.status.txempty.d),
|
||||
.qre (reg2hw.status.txempty.re),
|
||||
.qe (),
|
||||
.q (reg2hw.status.txempty.q),
|
||||
.qs (status_txempty_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[rxempty]: 3:3
|
||||
prim_subreg_ext #(
|
||||
.DW (1)
|
||||
) u_status_rxempty (
|
||||
.re (status_re),
|
||||
.we (1'b0),
|
||||
.wd ('0),
|
||||
.d (hw2reg.status.rxempty.d),
|
||||
.qre (reg2hw.status.rxempty.re),
|
||||
.qe (),
|
||||
.q (reg2hw.status.rxempty.q),
|
||||
.qs (status_rxempty_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[txidle]: 4:4
|
||||
prim_subreg_ext #(
|
||||
.DW (1)
|
||||
) u_status_txidle (
|
||||
.re (status_re),
|
||||
.we (1'b0),
|
||||
.wd ('0),
|
||||
.d (hw2reg.status.txidle.d),
|
||||
.qre (reg2hw.status.txidle.re),
|
||||
.qe (),
|
||||
.q (reg2hw.status.txidle.q),
|
||||
.qs (status_txidle_qs)
|
||||
);
|
||||
|
||||
|
||||
// F[rxidle]: 5:5
|
||||
prim_subreg_ext #(
|
||||
.DW (1)
|
||||
) u_status_rxidle (
|
||||
.re (status_re),
|
||||
.we (1'b0),
|
||||
.wd ('0),
|
||||
.d (hw2reg.status.rxidle.d),
|
||||
.qre (reg2hw.status.rxidle.re),
|
||||
.qe (),
|
||||
.q (reg2hw.status.rxidle.q),
|
||||
.qs (status_rxidle_qs)
|
||||
);
|
||||
|
||||
|
||||
// R[txdata]: V(False)
|
||||
|
||||
prim_subreg #(
|
||||
.DW (8),
|
||||
.SWACCESS("WO"),
|
||||
.RESVAL (8'h0)
|
||||
) u_txdata (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
|
||||
// from register interface
|
||||
.we (txdata_we),
|
||||
.wd (txdata_wd),
|
||||
|
||||
// from internal hardware
|
||||
.de (1'b0),
|
||||
.d ('0),
|
||||
|
||||
// to internal hardware
|
||||
.qe (reg2hw.txdata.qe),
|
||||
.q (reg2hw.txdata.q),
|
||||
|
||||
// to register interface (read)
|
||||
.qs ()
|
||||
);
|
||||
|
||||
|
||||
// R[rxdata]: V(True)
|
||||
|
||||
prim_subreg_ext #(
|
||||
.DW (8)
|
||||
) u_rxdata (
|
||||
.re (rxdata_re),
|
||||
.we (1'b0),
|
||||
.wd ('0),
|
||||
.d (hw2reg.rxdata.d),
|
||||
.qre (reg2hw.rxdata.re),
|
||||
.qe (),
|
||||
.q (reg2hw.rxdata.q),
|
||||
.qs (rxdata_qs)
|
||||
);
|
||||
|
||||
|
||||
logic [3:0] addr_hit;
|
||||
always_comb begin
|
||||
addr_hit = '0;
|
||||
addr_hit[0] = (reg_addr == UART_CTRL_OFFSET);
|
||||
addr_hit[1] = (reg_addr == UART_STATUS_OFFSET);
|
||||
addr_hit[2] = (reg_addr == UART_TXDATA_OFFSET);
|
||||
addr_hit[3] = (reg_addr == UART_RXDATA_OFFSET);
|
||||
end
|
||||
|
||||
assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ;
|
||||
|
||||
// Check sub-word write is permitted
|
||||
always_comb begin
|
||||
wr_err = (reg_we &
|
||||
((addr_hit[0] & (|(UART_PERMIT[0] & ~reg_be))) |
|
||||
(addr_hit[1] & (|(UART_PERMIT[1] & ~reg_be))) |
|
||||
(addr_hit[2] & (|(UART_PERMIT[2] & ~reg_be))) |
|
||||
(addr_hit[3] & (|(UART_PERMIT[3] & ~reg_be)))));
|
||||
end
|
||||
|
||||
assign ctrl_we = addr_hit[0] & reg_we & !reg_error;
|
||||
|
||||
assign ctrl_tx_en_wd = reg_wdata[0];
|
||||
|
||||
assign ctrl_rx_en_wd = reg_wdata[1];
|
||||
|
||||
assign ctrl_tx_fifo_empty_int_en_wd = reg_wdata[2];
|
||||
|
||||
assign ctrl_rx_fifo_not_empty_int_en_wd = reg_wdata[3];
|
||||
|
||||
assign ctrl_tx_fifo_rst_wd = reg_wdata[4];
|
||||
|
||||
assign ctrl_rx_fifo_rst_wd = reg_wdata[5];
|
||||
|
||||
assign ctrl_baud_div_wd = reg_wdata[31:16];
|
||||
assign status_re = addr_hit[1] & reg_re & !reg_error;
|
||||
assign txdata_we = addr_hit[2] & reg_we & !reg_error;
|
||||
|
||||
assign txdata_wd = reg_wdata[7:0];
|
||||
assign rxdata_re = addr_hit[3] & reg_re & !reg_error;
|
||||
|
||||
// Read data return
|
||||
always_comb begin
|
||||
reg_rdata_next = '0;
|
||||
unique case (1'b1)
|
||||
addr_hit[0]: begin
|
||||
reg_rdata_next[0] = ctrl_tx_en_qs;
|
||||
reg_rdata_next[1] = ctrl_rx_en_qs;
|
||||
reg_rdata_next[2] = ctrl_tx_fifo_empty_int_en_qs;
|
||||
reg_rdata_next[3] = ctrl_rx_fifo_not_empty_int_en_qs;
|
||||
reg_rdata_next[4] = '0;
|
||||
reg_rdata_next[5] = '0;
|
||||
reg_rdata_next[31:16] = ctrl_baud_div_qs;
|
||||
end
|
||||
|
||||
addr_hit[1]: begin
|
||||
reg_rdata_next[0] = status_txfull_qs;
|
||||
reg_rdata_next[1] = status_rxfull_qs;
|
||||
reg_rdata_next[2] = status_txempty_qs;
|
||||
reg_rdata_next[3] = status_rxempty_qs;
|
||||
reg_rdata_next[4] = status_txidle_qs;
|
||||
reg_rdata_next[5] = status_rxidle_qs;
|
||||
end
|
||||
|
||||
addr_hit[2]: begin
|
||||
reg_rdata_next[7:0] = '0;
|
||||
end
|
||||
|
||||
addr_hit[3]: begin
|
||||
reg_rdata_next[7:0] = rxdata_qs;
|
||||
end
|
||||
|
||||
default: begin
|
||||
reg_rdata_next = '1;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
// Unused signal tieoff
|
||||
|
||||
// wdata / byte enable are not always fully used
|
||||
// add a blanket unused statement to handle lint waivers
|
||||
logic unused_wdata;
|
||||
logic unused_be;
|
||||
assign unused_wdata = ^reg_wdata;
|
||||
assign unused_be = ^reg_be;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
module uart_rx (
|
||||
input logic clk_i, // 时钟信号
|
||||
input logic rst_ni, // 异步复位信号,低电平有效
|
||||
input logic enable_i, // RX模块使能信号
|
||||
input logic parity_en_i, // 校验使能
|
||||
input logic parity_odd_i, // 奇校验
|
||||
input logic [15:0] div_ratio_i, // 波特率分频系数
|
||||
input logic rx_i, // 来自RX引脚的信号
|
||||
output logic idle_o, // RX模块空闲
|
||||
output logic err_o, // 接收出错,帧出错或者校验出错
|
||||
output logic [7:0] rdata_o, // 接收到的一个字节数据
|
||||
output logic rvalid_o // 有效接收到一个字节数据
|
||||
);
|
||||
|
||||
logic tick;
|
||||
logic rx;
|
||||
logic rx_start;
|
||||
logic clk_div_rst_n_d, clk_div_rst_n_q;
|
||||
logic idle_d, idle_q;
|
||||
logic rx_valid_d, rx_valid_q;
|
||||
logic [10:0] shift_reg_d, shift_reg_q;
|
||||
logic [3:0] bit_cnt_d, bit_cnt_q;
|
||||
logic [15:0] baud_div_d, baud_div_q;
|
||||
|
||||
|
||||
always_comb begin
|
||||
if (!enable_i) begin
|
||||
rx_valid_d = 1'b0;
|
||||
shift_reg_d = '0;
|
||||
idle_d = 1'b1;
|
||||
bit_cnt_d = '0;
|
||||
baud_div_d = '0;
|
||||
clk_div_rst_n_d = 1'b1;
|
||||
end else begin
|
||||
rx_valid_d = 1'b0;
|
||||
shift_reg_d = shift_reg_q;
|
||||
idle_d = idle_q;
|
||||
bit_cnt_d = bit_cnt_q;
|
||||
baud_div_d = baud_div_q;
|
||||
clk_div_rst_n_d = 1'b1;
|
||||
if (rx_start & idle_q) begin
|
||||
bit_cnt_d = parity_en_i ? 4'd11 : 4'd10;
|
||||
shift_reg_d = '0;
|
||||
idle_d = 1'b0;
|
||||
// 起始位,采中间值
|
||||
baud_div_d = {1'b0, div_ratio_i[15:1]};
|
||||
clk_div_rst_n_d = 1'b0;
|
||||
end else if (tick && (!idle_q)) begin
|
||||
shift_reg_d = {rx, shift_reg_q[10:1]};
|
||||
bit_cnt_d = bit_cnt_q - 1'b1;
|
||||
idle_d = (bit_cnt_q == 4'h1);
|
||||
rx_valid_d = (bit_cnt_q == 4'h1);
|
||||
baud_div_d = div_ratio_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
rx_valid_q <= 1'b0;
|
||||
shift_reg_q <= '0;
|
||||
idle_q <= 1'b1;
|
||||
bit_cnt_q <= '0;
|
||||
baud_div_q <= '0;
|
||||
clk_div_rst_n_q <= 1'b1;
|
||||
end else begin
|
||||
rx_valid_q <= rx_valid_d;
|
||||
shift_reg_q <= shift_reg_d;
|
||||
idle_q <= idle_d;
|
||||
bit_cnt_q <= bit_cnt_d;
|
||||
baud_div_q <= baud_div_d;
|
||||
clk_div_rst_n_q <= clk_div_rst_n_d;
|
||||
end
|
||||
end
|
||||
|
||||
assign idle_o = idle_q;
|
||||
assign rvalid_o = rx_valid_q;
|
||||
assign rdata_o = parity_en_i ? shift_reg_q[8:1] : shift_reg_q[9:2];
|
||||
assign err_o = rx_valid_q & (~shift_reg_q[10]);
|
||||
|
||||
edge_detect u_edge_detect(
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.sig_i (rx_i),
|
||||
.sig_o (rx),
|
||||
.re_o (),
|
||||
.fe_o (rx_start)
|
||||
);
|
||||
|
||||
clk_div #(
|
||||
.RATIO_WIDTH(16)
|
||||
) u_clk_div (
|
||||
.clk_i(clk_i),
|
||||
.rst_ni(rst_ni || clk_div_rst_n_q),
|
||||
.en_i(rx_start || (!idle_q)),
|
||||
.ratio_i(baud_div_q),
|
||||
.clk_o(tick)
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
module uart_top (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
||||
input logic rx_i,
|
||||
output logic tx_o,
|
||||
output logic irq_o,
|
||||
|
||||
// OBI总线接口信号
|
||||
input logic req_i,
|
||||
input logic we_i,
|
||||
input logic [ 3:0] be_i,
|
||||
input logic [31:0] addr_i,
|
||||
input logic [31:0] data_i,
|
||||
output logic [31:0] data_o
|
||||
);
|
||||
|
||||
logic re;
|
||||
logic we;
|
||||
logic [31:0] addr;
|
||||
logic [31:0] reg_rdata;
|
||||
|
||||
// 读信号
|
||||
assign re = req_i & (!we_i);
|
||||
// 写信号
|
||||
assign we = req_i & we_i;
|
||||
// 去掉基地址
|
||||
assign addr = {16'h0, addr_i[15:0]};
|
||||
|
||||
uart_core u_uart_core (
|
||||
.clk_i (clk_i),
|
||||
.rst_ni (rst_ni),
|
||||
.tx_pin_o (tx_o),
|
||||
.rx_pin_i (rx_i),
|
||||
.irq_o (irq_o),
|
||||
.reg_we_i (we),
|
||||
.reg_re_i (re),
|
||||
.reg_wdata_i(data_i),
|
||||
.reg_be_i (be_i),
|
||||
.reg_addr_i (addr),
|
||||
.reg_rdata_o(reg_rdata)
|
||||
);
|
||||
|
||||
always_ff @(posedge clk_i) begin
|
||||
data_o <= reg_rdata;
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
module uart_tx (
|
||||
input logic clk_i, // 时钟输入
|
||||
input logic rst_ni, // 异步复位信号,低电平有效
|
||||
input logic enable_i, // TX模块使能信号
|
||||
input logic parity_en_i, // 校验使能
|
||||
input logic parity_i, // 校验方式:奇校验还是偶检验
|
||||
input logic we_i, // 开始发送数据
|
||||
input logic [7:0] wdata_i, // 要发送的一个字节数据
|
||||
input logic [15:0] div_ratio_i, // 波特率分频系数
|
||||
output logic idle_o, // TX模块空闲
|
||||
output logic tx_bit_o // 要发送的1 bit数据
|
||||
);
|
||||
|
||||
logic [3:0] bit_cnt_d, bit_cnt_q;
|
||||
logic [10:0] shift_reg_d, shift_reg_q;
|
||||
logic tx_d, tx_q;
|
||||
logic tick;
|
||||
|
||||
always_comb begin
|
||||
if (!enable_i) begin
|
||||
bit_cnt_d = 4'h0;
|
||||
shift_reg_d = 11'h7ff;
|
||||
tx_d = 1'b1;
|
||||
end else begin
|
||||
bit_cnt_d = bit_cnt_q;
|
||||
shift_reg_d = shift_reg_q;
|
||||
tx_d = tx_q;
|
||||
if (we_i) begin
|
||||
// LSB first
|
||||
shift_reg_d = {1'b1, (parity_en_i ? parity_i : 1'b1), wdata_i, 1'b0};
|
||||
bit_cnt_d = (parity_en_i ? 4'd11 : 4'd10);
|
||||
end else if ((bit_cnt_q != 4'h0) && tick) begin
|
||||
// 右移1位
|
||||
shift_reg_d = {1'b1, shift_reg_q[10:1]};
|
||||
tx_d = shift_reg_q[0];
|
||||
bit_cnt_d = bit_cnt_q - 4'h1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
bit_cnt_q <= 4'h0;
|
||||
shift_reg_q <= 11'h7ff;
|
||||
tx_q <= 1'b1;
|
||||
end else begin
|
||||
bit_cnt_q <= bit_cnt_d;
|
||||
shift_reg_q <= shift_reg_d;
|
||||
tx_q <= tx_d;
|
||||
end
|
||||
end
|
||||
|
||||
assign idle_o = (bit_cnt_q == 4'h0);
|
||||
assign tx_bit_o = tx_q;
|
||||
|
||||
clk_div #(
|
||||
.RATIO_WIDTH(16)
|
||||
) u_clk_div (
|
||||
.clk_i(clk_i),
|
||||
.rst_ni(rst_ni || (~we_i)),
|
||||
.en_i(we_i || (bit_cnt_q != 4'h0)),
|
||||
.ratio_i(div_ratio_i),
|
||||
.clk_o(tick)
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -57,7 +57,7 @@ module tinyriscv_soc_top #(
|
|||
localparam int JtagDevice = 2;
|
||||
localparam int Mtimer = 3;
|
||||
localparam int Gpio = 4;
|
||||
localparam int Uart = 5;
|
||||
localparam int Uart0 = 5;
|
||||
localparam int Rvic = 6;
|
||||
`ifdef VERILATOR
|
||||
localparam int SimCtrl = 7;
|
||||
|
@ -106,6 +106,7 @@ module tinyriscv_soc_top #(
|
|||
wire[7:0] int_id;
|
||||
|
||||
wire mtimer_irq;
|
||||
wire uart0_irq;
|
||||
|
||||
wire[1:0] io_in;
|
||||
wire[31:0] gpio_ctrl;
|
||||
|
@ -114,6 +115,7 @@ module tinyriscv_soc_top #(
|
|||
always @ (*) begin
|
||||
irq_src = 32'h0;
|
||||
irq_src[0] = mtimer_irq;
|
||||
irq_src[1] = uart0_irq;
|
||||
end
|
||||
|
||||
`ifdef VERILATOR
|
||||
|
@ -222,19 +224,21 @@ module tinyriscv_soc_top #(
|
|||
.reg_data(gpio_data)
|
||||
);
|
||||
|
||||
assign slave_addr_mask[Uart] = `UART_ADDR_MASK;
|
||||
assign slave_addr_base[Uart] = `UART_ADDR_BASE;
|
||||
// 5.串口模块
|
||||
uart u_uart(
|
||||
.clk (clk),
|
||||
.rst_n (ndmreset_n),
|
||||
.addr_i (slave_addr[Uart]),
|
||||
.data_i (slave_wdata[Uart]),
|
||||
.sel_i (slave_be[Uart]),
|
||||
.we_i (slave_we[Uart]),
|
||||
.data_o (slave_rdata[Uart]),
|
||||
.tx_pin (uart_tx_pin),
|
||||
.rx_pin (uart_rx_pin)
|
||||
assign slave_addr_mask[Uart0] = `UART0_ADDR_MASK;
|
||||
assign slave_addr_base[Uart0] = `UART0_ADDR_BASE;
|
||||
// 5.串口0模块
|
||||
uart_top uart0 (
|
||||
.clk_i (clk),
|
||||
.rst_ni (ndmreset_n),
|
||||
.rx_i (uart_rx_pin),
|
||||
.tx_o (uart_tx_pin),
|
||||
.irq_o (uart0_irq),
|
||||
.req_i (slave_req[Uart0]),
|
||||
.we_i (slave_we[Uart0]),
|
||||
.be_i (slave_be[Uart0]),
|
||||
.addr_i (slave_addr[Uart0]),
|
||||
.data_i (slave_wdata[Uart0]),
|
||||
.data_o (slave_rdata[Uart0])
|
||||
);
|
||||
|
||||
assign slave_addr_mask[Rvic] = `RVIC_ADDR_MASK;
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
module clk_div #(
|
||||
parameter int unsigned RATIO_WIDTH = 32
|
||||
)(
|
||||
input logic clk_i, // clock
|
||||
input logic rst_ni, // asynchronous reset active low
|
||||
input logic en_i, // enable clock divider
|
||||
input logic [RATIO_WIDTH-1:0] ratio_i, // divider ratio
|
||||
output logic clk_o // divided clock out
|
||||
);
|
||||
|
||||
logic [RATIO_WIDTH-1:0] counter_q;
|
||||
logic clk_q;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (~rst_ni) begin
|
||||
clk_q <= 1'b0;
|
||||
counter_q <= '0;
|
||||
end else begin
|
||||
clk_q <= 1'b0;
|
||||
if (en_i) begin
|
||||
if (counter_q == (ratio_i - 1)) begin
|
||||
clk_q <= 1'b1;
|
||||
counter_q <= '0;
|
||||
end else begin
|
||||
counter_q <= counter_q + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign clk_o = clk_q;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
Copyright 2021 Blue Liang, liangkangnan@163.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// 上升沿、下降沿检测
|
||||
module edge_detect (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
input logic sig_i,
|
||||
output logic sig_o,
|
||||
output logic re_o,
|
||||
output logic fe_o
|
||||
);
|
||||
|
||||
logic sig, sig_q;
|
||||
|
||||
assign sig_o = sig_q;
|
||||
assign fe_o = (~sig) & sig_q;
|
||||
assign re_o = sig & (~sig_q);
|
||||
|
||||
always_ff @(posedge clk_i, negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
sig_q <= 1'b0;
|
||||
end else begin
|
||||
sig_q <= sig;
|
||||
end
|
||||
end
|
||||
|
||||
gen_ticks_sync #(
|
||||
.DP(2),
|
||||
.DW(1)
|
||||
) u_sync (
|
||||
.clk(clk_i),
|
||||
.rst_n(rst_ni),
|
||||
.din(sig_i),
|
||||
.dout(sig)
|
||||
);
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Register slice conforming to Comportibility guide.
|
||||
|
||||
module prim_subreg #(
|
||||
parameter int DW = 32 ,
|
||||
parameter SWACCESS = "RW", // {RW, RO, WO, W1C, W1S, W0C, RC}
|
||||
parameter logic [DW-1:0] RESVAL = '0 // Reset value
|
||||
) (
|
||||
input clk_i,
|
||||
input rst_ni,
|
||||
|
||||
// From SW: valid for RW, WO, W1C, W1S, W0C, RC
|
||||
// In case of RC, Top connects Read Pulse to we
|
||||
input we,
|
||||
input [DW-1:0] wd,
|
||||
|
||||
// From HW: valid for HRW, HWO
|
||||
input de,
|
||||
input [DW-1:0] d,
|
||||
|
||||
// output to HW and Reg Read
|
||||
output logic qe,
|
||||
output logic [DW-1:0] q,
|
||||
output logic [DW-1:0] qs
|
||||
);
|
||||
|
||||
logic wr_en;
|
||||
logic [DW-1:0] wr_data;
|
||||
|
||||
prim_subreg_arb #(
|
||||
.DW ( DW ),
|
||||
.SWACCESS ( SWACCESS )
|
||||
) wr_en_data_arb (
|
||||
.we,
|
||||
.wd,
|
||||
.de,
|
||||
.d,
|
||||
.q,
|
||||
.wr_en,
|
||||
.wr_data
|
||||
);
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
qe <= 1'b0;
|
||||
end else begin
|
||||
qe <= we;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
q <= RESVAL;
|
||||
end else if (wr_en) begin
|
||||
q <= wr_data;
|
||||
end
|
||||
end
|
||||
|
||||
assign qs = q;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Write enable and data arbitration logic for register slice conforming to Comportibility guide.
|
||||
|
||||
module prim_subreg_arb #(
|
||||
parameter int DW = 32 ,
|
||||
parameter SWACCESS = "RW" // {RW, RO, WO, W1C, W1S, W0C, RC}
|
||||
) (
|
||||
// From SW: valid for RW, WO, W1C, W1S, W0C, RC.
|
||||
// In case of RC, top connects read pulse to we.
|
||||
input we,
|
||||
input [DW-1:0] wd,
|
||||
|
||||
// From HW: valid for HRW, HWO.
|
||||
input de,
|
||||
input [DW-1:0] d,
|
||||
|
||||
// From register: actual reg value.
|
||||
input [DW-1:0] q,
|
||||
|
||||
// To register: actual write enable and write data.
|
||||
output logic wr_en,
|
||||
output logic [DW-1:0] wr_data
|
||||
);
|
||||
|
||||
if ((SWACCESS == "RW") || (SWACCESS == "WO")) begin : gen_w
|
||||
assign wr_en = we | de;
|
||||
assign wr_data = (we == 1'b1) ? wd : d; // SW higher priority
|
||||
// Unused q - Prevent lint errors.
|
||||
logic [DW-1:0] unused_q;
|
||||
assign unused_q = q;
|
||||
end else if (SWACCESS == "RO") begin : gen_ro
|
||||
assign wr_en = de;
|
||||
assign wr_data = d;
|
||||
// Unused we, wd, q - Prevent lint errors.
|
||||
logic unused_we;
|
||||
logic [DW-1:0] unused_wd;
|
||||
logic [DW-1:0] unused_q;
|
||||
assign unused_we = we;
|
||||
assign unused_wd = wd;
|
||||
assign unused_q = q;
|
||||
end else if (SWACCESS == "W1S") begin : gen_w1s
|
||||
// If SWACCESS is W1S, then assume hw tries to clear.
|
||||
// So, give a chance HW to clear when SW tries to set.
|
||||
// If both try to set/clr at the same bit pos, SW wins.
|
||||
assign wr_en = we | de;
|
||||
assign wr_data = (de ? d : q) | (we ? wd : '0);
|
||||
end else if (SWACCESS == "W1C") begin : gen_w1c
|
||||
// If SWACCESS is W1C, then assume hw tries to set.
|
||||
// So, give a chance HW to set when SW tries to clear.
|
||||
// If both try to set/clr at the same bit pos, SW wins.
|
||||
assign wr_en = we | de;
|
||||
assign wr_data = (de ? d : q) & (we ? ~wd : '1);
|
||||
end else if (SWACCESS == "W0C") begin : gen_w0c
|
||||
assign wr_en = we | de;
|
||||
assign wr_data = (de ? d : q) & (we ? wd : '1);
|
||||
end else if (SWACCESS == "RC") begin : gen_rc
|
||||
// This swtype is not recommended but exists for compatibility.
|
||||
// WARN: we signal is actually read signal not write enable.
|
||||
assign wr_en = we | de;
|
||||
assign wr_data = (de ? d : q) & (we ? '0 : '1);
|
||||
// Unused wd - Prevent lint errors.
|
||||
logic [DW-1:0] unused_wd;
|
||||
assign unused_wd = wd;
|
||||
end else begin : gen_hw
|
||||
assign wr_en = de;
|
||||
assign wr_data = d;
|
||||
// Unused we, wd, q - Prevent lint errors.
|
||||
logic unused_we;
|
||||
logic [DW-1:0] unused_wd;
|
||||
logic [DW-1:0] unused_q;
|
||||
assign unused_we = we;
|
||||
assign unused_wd = wd;
|
||||
assign unused_q = q;
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright lowRISC contributors.
|
||||
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Register slice conforming to Comportibility guide.
|
||||
|
||||
module prim_subreg_ext #(
|
||||
parameter int unsigned DW = 32
|
||||
) (
|
||||
input re,
|
||||
input we,
|
||||
input [DW-1:0] wd,
|
||||
|
||||
input [DW-1:0] d,
|
||||
|
||||
// output to HW and Reg Read
|
||||
output logic qe,
|
||||
output logic qre,
|
||||
output logic [DW-1:0] q,
|
||||
output logic [DW-1:0] qs
|
||||
);
|
||||
|
||||
assign qs = d;
|
||||
assign q = wd;
|
||||
assign qe = we;
|
||||
assign qre = re;
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue