首次提交

This commit is contained in:
eesimple
2026-03-06 16:22:17 +08:00
commit b8fe9f77ec
465 changed files with 115939 additions and 0 deletions

74
uart/uart.sv Normal file
View File

@@ -0,0 +1,74 @@
// Copyright 2017 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the “License”); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this 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
#(
parameter integer CLOCK_FREQUENCY = 50e6,
parameter integer BAUD_RATE = 115200,
parameter logic CFG_PARITY_EN = 1'b0, // 0: disable parity; 1: enable parity
parameter logic CFG_EVEN_PARITY = 1'b0, // 0: odd parity; 1: even parity
parameter logic CFG_STOP_BIT = 1'b0 // 0: 1 stop bit; 1: 2 stop bit
)
(
input logic clk,
input logic rstn,
input logic rx_i, // Receiver input
output logic tx_o, // Transmitter output
output logic rx_valid,
output logic [7:0] rx_data,
input logic rx_ready,
input logic tx_valid,
input logic [7:0] tx_data,
output logic tx_ready
);
// register addresses
// TODO: check that stop bits are really not necessary here
uart_rx uart_rx_i
(
.clk_i ( clk ),
.rstn_i ( rstn ),
.rx_i ( rx_i ),
.cfg_en_i ( 1'b1 ),
.cfg_div_i ( CLOCK_FREQUENCY/BAUD_RATE ),
.cfg_parity_en_i ( CFG_PARITY_EN ),
.cfg_even_parity_i ( CFG_EVEN_PARITY ),
.busy_o ( ),
.parity_error_o ( ),
.overrun_o ( ),
.err_clr_i ( 1'b1 ),
.rx_data_o ( rx_data ),
.rx_valid_o ( rx_valid ),
.rx_ready_i ( rx_ready )
);
uart_tx uart_tx_i
(
.clk_i ( clk ),
.rstn_i ( rstn ),
.tx_o ( tx_o ),
.busy_o ( ),
.cfg_en_i ( 1'b1 ),
.cfg_div_i ( CLOCK_FREQUENCY/BAUD_RATE ),
.cfg_parity_en_i ( CFG_PARITY_EN ),
.cfg_even_parity_i ( CFG_EVEN_PARITY ),
.cfg_stop_bits_i ( CFG_STOP_BIT ),
.tx_data_i ( tx_data ),
.tx_valid_i ( tx_valid ),
.tx_ready_o ( tx_ready )
);
endmodule

172
uart/uart_rx.sv Normal file
View File

@@ -0,0 +1,172 @@
module uart_rx (
input logic clk_i,
input logic rstn_i,
input logic rx_i,
input logic [15:0] cfg_div_i,
input logic cfg_en_i,
input logic cfg_parity_en_i,
input logic cfg_even_parity_i,
output logic busy_o,
output logic parity_error_o,
output logic overrun_o,
input logic err_clr_i,
output logic [7:0] rx_data_o,
output logic rx_valid_o,
input logic rx_ready_i
);
enum logic [2:0] {IDLE,START_BIT,DATA,PARITY,STOP_BIT} CS, NS;
logic [7:0] reg_data;
logic [2:0] reg_rx_sync;
logic [2:0] reg_bit_count;
logic parity_bit;
logic [15:0] baud_cnt;
logic baudgen_en;
logic bit_done;
logic start_bit;
logic s_rx_fall;
assign busy_o = (CS != IDLE);
always_comb begin
NS = CS;
baudgen_en = 1'b0;
start_bit = 1'b0;
case(CS)
IDLE: begin
if (s_rx_fall) begin
NS = START_BIT;
baudgen_en = 1'b1;
start_bit = 1'b1;
end
end
START_BIT: begin
baudgen_en = 1'b1;
start_bit = 1'b1;
if (bit_done)
NS = DATA;
end
DATA: begin
baudgen_en = 1'b1;
if (bit_done) begin
if (reg_bit_count == 3'h7) begin
if (cfg_parity_en_i)
NS = PARITY;
else
NS = STOP_BIT;
end
end
end
PARITY: begin
baudgen_en = 1'b1;
if (bit_done) begin
NS = STOP_BIT;
end
end
STOP_BIT: begin
baudgen_en = 1'b1;
if (bit_done) begin
NS = IDLE;
end
end
default:
NS = IDLE;
endcase
end
always_ff @(posedge clk_i or negedge rstn_i)
begin
if (rstn_i == 1'b0) begin
CS <= IDLE;
reg_data <= 8'hFF;
reg_bit_count <= 'h0;
parity_bit <= 1'b0;
parity_error_o <= 1'b0;
rx_valid_o <= 1'b0;
overrun_o <= 1'b0;
end else begin
if(cfg_en_i)
CS <= NS;
else
CS <= IDLE;
rx_valid_o <= 0;
case (CS)
START_BIT:
parity_bit <= ~cfg_even_parity_i;
DATA:
if (bit_done) begin
parity_bit <= parity_bit ^ reg_rx_sync[2];
reg_data <= {reg_rx_sync[2],reg_data[7:1]};
if (reg_bit_count == 3'h7)
reg_bit_count <= 'h0;
else
reg_bit_count <= reg_bit_count + 1;
end
PARITY:
if (bit_done)
if(parity_bit != reg_rx_sync[2])
parity_error_o <= 1'b1;
else
parity_error_o <= 1'b0;
STOP_BIT:
if (bit_done) begin
rx_valid_o <= 1'b1;
overrun_o <= ~rx_ready_i;
end
endcase
end
end
assign s_rx_fall = ~reg_rx_sync[1] & reg_rx_sync[2];
always_ff @(posedge clk_i or negedge rstn_i) begin
if (rstn_i == 1'b0)
reg_rx_sync <= 3'b111;
else begin
if (cfg_en_i)
reg_rx_sync <= {reg_rx_sync[1:0],rx_i};
else
reg_rx_sync <= 3'b111;
end
end
always_ff @(posedge clk_i or negedge rstn_i) begin
if (rstn_i == 1'b0) begin
baud_cnt <= 'h0;
bit_done <= 1'b0;
end else begin
if(baudgen_en) begin
if(!start_bit && (baud_cnt == cfg_div_i)) begin
baud_cnt <= 'h0;
bit_done <= 1'b1;
end else if(start_bit && (baud_cnt == {1'b0,cfg_div_i[15:1]})) begin
baud_cnt <= 'h0;
bit_done <= 1'b1;
end else begin
baud_cnt <= baud_cnt + 1;
bit_done <= 1'b0;
end
end else begin
baud_cnt <= 'h0;
bit_done <= 1'b0;
end
end
end
assign rx_data_o = reg_data;
endmodule

146
uart/uart_tx.sv Normal file
View File

@@ -0,0 +1,146 @@
module uart_tx (
input logic clk_i,
input logic rstn_i,
output logic tx_o,
output logic busy_o,
input logic cfg_en_i,
input logic [15:0] cfg_div_i,
input logic cfg_parity_en_i,
input logic cfg_even_parity_i,
input logic cfg_stop_bits_i,
input logic [7:0] tx_data_i,
input logic tx_valid_i,
output logic tx_ready_o
);
enum logic [2:0] {IDLE,START_BIT,DATA,PARITY,STOP_BIT_FIRST,STOP_BIT_LAST} CS,NS;
logic [7:0] reg_data;
logic [2:0] reg_bit_count;
logic parity_bit;
logic [15:0] baud_cnt;
logic baudgen_en;
logic bit_done;
assign busy_o = (CS != IDLE);
always_comb begin
NS = CS;
tx_o = 1'b1;
tx_ready_o = 1'b0;
baudgen_en = 1'b0;
case(CS)
IDLE: begin
if (cfg_en_i)
tx_ready_o = 1'b1;
if (tx_valid_i) begin
NS = START_BIT;
end
end
START_BIT: begin
tx_o = 1'b0;
baudgen_en = 1'b1;
if (bit_done)
NS = DATA;
end
DATA: begin
tx_o = reg_data[0];
baudgen_en = 1'b1;
if (bit_done) begin
if (reg_bit_count == 3'h7) begin
if (cfg_parity_en_i) begin
NS = PARITY;
end else begin
NS = STOP_BIT_FIRST;
end
end
end
end
PARITY: begin
tx_o = parity_bit;
baudgen_en = 1'b1;
if (bit_done)
NS = STOP_BIT_FIRST;
end
STOP_BIT_FIRST: begin
tx_o = 1'b1;
baudgen_en = 1'b1;
if (bit_done) begin
if (cfg_stop_bits_i)
NS = STOP_BIT_LAST;
else
NS = IDLE;
end
end
STOP_BIT_LAST: begin
tx_o = 1'b1;
baudgen_en = 1'b1;
if (bit_done) begin
NS = IDLE;
end
end
default:
NS = IDLE;
endcase
end
always_ff @(posedge clk_i or negedge rstn_i) begin
if (rstn_i == 1'b0) begin
CS <= IDLE;
reg_data <= 8'hFF;
reg_bit_count <= 'h0;
parity_bit <= 1'b0;
end else begin
if(cfg_en_i)
CS <= NS;
else
CS <= IDLE;
case (CS)
IDLE:
if (tx_valid_i)
reg_data <= tx_data_i;
START_BIT:
parity_bit <= ~cfg_even_parity_i;
DATA:
if (bit_done) begin
parity_bit <= parity_bit ^ reg_data[0];
if (reg_bit_count == 3'h7)
reg_bit_count <= 'h0;
else begin
reg_bit_count <= reg_bit_count + 1;
reg_data <= {1'b1,reg_data[7:1]};
end
end
endcase
end
end
always_ff @(posedge clk_i or negedge rstn_i) begin
if (rstn_i == 1'b0) begin
baud_cnt <= 'h0;
bit_done <= 1'b0;
end else begin
if(baudgen_en) begin
if(baud_cnt == cfg_div_i) begin
baud_cnt <= 'h0;
bit_done <= 1'b1;
end else begin
baud_cnt <= baud_cnt + 1;
bit_done <= 1'b0;
end
end else begin
baud_cnt <= 'h0;
bit_done <= 1'b0;
end
end
end
endmodule