146 lines
4.1 KiB
Systemverilog
146 lines
4.1 KiB
Systemverilog
|
|
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 |