//===========================
// uart_top.v - Top Level
//===========================
module uart_top #(
parameter CLK_FREQ = 50000000, // 50 MHz
parameter BAUD_RATE = 9600,
parameter FIFO_DEPTH = 16
)(
input wire clk,
input wire rst,
input wire rx,
output wire tx,
input wire [7:0] tx_data,
input wire tx_wr,
output wire tx_full,
output wire [7:0] rx_data,
output wire rx_valid,
input wire rx_rd,
output wire framing_error
);
wire baud_tick;
wire tx_fifo_empty, tx_fifo_rd;
wire [7:0] tx_fifo_data;
wire rx_fifo_full, rx_fifo_wr;
wire [7:0] rx_fifo_in;
// Baud rate generator
baud_gen #(
.CLK_FREQ(CLK_FREQ),
.BAUD_RATE(BAUD_RATE)
) baud_inst (
.clk(clk),
.rst(rst),
.baud_tick(baud_tick)
);
// TX FIFO
fifo #(
.WIDTH(8),
.DEPTH(FIFO_DEPTH)
) tx_fifo (
.clk(clk),
.rst(rst),
.wr_en(tx_wr),
.rd_en(tx_fifo_rd),
.din(tx_data),
.dout(tx_fifo_data),
.empty(tx_fifo_empty),
.full(tx_full)
);
// UART TX
uart_tx uart_tx_inst (
.clk(clk),
.rst(rst),
.tx_start(~tx_fifo_empty),
.baud_tick(baud_tick),
.tx_data(tx_fifo_data),
.tx(tx),
.tx_done(tx_fifo_rd)
);
// UART RX
uart_rx uart_rx_inst (
.clk(clk),
.rst(rst),
.baud_tick(baud_tick),
.rx(rx),
.rx_data(rx_fifo_in),
.rx_valid(rx_fifo_wr),
.framing_error(framing_error)
);
// RX FIFO
fifo #(
.WIDTH(8),
.DEPTH(FIFO_DEPTH)
) rx_fifo (
.clk(clk),
.rst(rst),
.wr_en(rx_fifo_wr),
.rd_en(rx_rd),
.din(rx_fifo_in),
.dout(rx_data),
.empty(),
.full()
);
assign rx_valid = rx_fifo_wr;
endmodule
//===========================
// baud_gen.v - Baud Rate Generator
//===========================
module baud_gen #(
parameter CLK_FREQ = 50000000,
parameter BAUD_RATE = 9600
)(
input wire clk,
input wire rst,
output reg baud_tick
);
localparam integer COUNT_MAX = CLK_FREQ / BAUD_RATE;
reg [31:0] count;
always @(posedge clk or posedge rst) begin
if (rst) begin
count <= 0;
baud_tick <= 0;
end else begin
if (count == COUNT_MAX - 1) begin
count <= 0;
baud_tick <= 1;
end else begin
count <= count + 1;
baud_tick <= 0;
end
end
end
endmodule
//===========================
// fifo.v - Simple Synchronous FIFO
//===========================
module fifo #(parameter WIDTH=8, DEPTH=16)(
input wire clk,
input wire rst,
input wire wr_en,
input wire rd_en,
input wire [WIDTH-1:0] din,
output reg [WIDTH-1:0] dout,
output wire empty,
output wire full
);
reg [WIDTH-1:0] mem [0:DEPTH-1];
reg [$clog2(DEPTH):0] wr_ptr = 0;
reg [$clog2(DEPTH):0] rd_ptr = 0;
reg [$clog2(DEPTH)+1:0] count = 0;
assign empty = (count == 0);
assign full = (count == DEPTH);
always @(posedge clk or posedge rst) begin
if (rst) begin
wr_ptr <= 0;
rd_ptr <= 0;
count <= 0;
end else begin
if (wr_en && !full) begin
mem[wr_ptr] <= din;
wr_ptr <= wr_ptr + 1;
count <= count + 1;
end
if (rd_en && !empty) begin
dout <= mem[rd_ptr];
rd_ptr <= rd_ptr + 1;
count <= count - 1;
end
end
end
endmodule
//===========================
// uart_tx.v - UART Transmitter
//===========================
module uart_tx (
input wire clk,
input wire rst,
input wire tx_start,
input wire baud_tick,
input wire [7:0] tx_data,
output reg tx,
output reg tx_done
);
reg [3:0] bit_idx = 0;
reg [9:0] shift_reg;
reg tx_busy = 0;
always @(posedge clk or posedge rst) begin
if (rst) begin
tx <= 1;
tx_busy <= 0;
bit_idx <= 0;
tx_done <= 0;
end else begin
tx_done <= 0;
if (tx_start && !tx_busy) begin
shift_reg <= {1'b1, tx_data, 1'b0}; // {Stop, Data, Start}
tx_busy <= 1;
bit_idx <= 0;
end else if (baud_tick && tx_busy) begin
tx <= shift_reg[0];
shift_reg <= shift_reg >> 1;
bit_idx <= bit_idx + 1;
if (bit_idx == 9) begin
tx_busy <= 0;
tx_done <= 1;
end
end
end
end
endmodule
//===========================
// uart_rx.v - UART Receiver with Framing Error
//===========================
module uart_rx (
input wire clk,
input wire rst,
input wire baud_tick,
input wire rx,
output reg [7:0] rx_data,
output reg rx_valid,
output reg framing_error // NEW output
);
reg [3:0] bit_idx = 0;
reg [7:0] shift_reg;
reg rx_busy = 0;
reg [1:0] rx_sync;
// Double sync the RX line to avoid metastability
always @(posedge clk) begin
rx_sync <= {rx_sync[0], rx};
end
always @(posedge clk or posedge rst) begin
if (rst) begin
rx_busy <= 0;
bit_idx <= 0;
rx_valid <= 0;
framing_error <= 0;
end else begin
rx_valid <= 0;
framing_error <= 0;
if (!rx_busy && !rx_sync[1]) begin
// Detected start bit (falling edge)
rx_busy <= 1;
bit_idx <= 0;
end else if (baud_tick && rx_busy) begin
bit_idx <= bit_idx + 1;
// Sample 8 data bits
if (bit_idx >= 1 && bit_idx <= 8) begin
shift_reg <= {rx_sync[1], shift_reg[7:1]};
end
// Sample stop bit and check framing
if (bit_idx == 9) begin
if (rx_sync[1] == 1'b1) begin
// Valid stop bit
rx_data <= shift_reg;
rx_valid <= 1;
end else begin
// Stop bit is low → framing error
framing_error <= 1;
end
rx_busy <= 0;
end
end
end
end
endmodule