Last active
June 6, 2017 12:10
-
-
Save buttercutter/8966ac00db796ede35fa82512053f7ba to your computer and use it in GitHub Desktop.
Tx UART in verilog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Tx_TOP(clk, reset, start, i_data, serial_out) // UART transmitter : parallel input, serial output | |
input clk; // 48MHz | |
input reset; | |
input start; // i_data is valid, so start transmission | |
input[7:0] i_data; | |
output serial_out; | |
wire baud_out; // 16*baudrate clock | |
wire serial_data; // output from serializer (TxUART) | |
TxUART tx (.clk(baud_out), .reset(0), .start_tx(start), .i_data(i_data), .o_data(serial_data)); | |
baud_generator bg (.clk(clk), .baud_out(baud_out)); | |
shift_register sreg (.clk(baud_out), .reset(0), .data_in(serial_data), .data_out(serial_out)); | |
// FIFO tx_fifo (clk, reset, enqueue, dequeue, flush, i_value, almost_full, almost_empty, o_value); | |
endmodule | |
// credit: Adapted from http://zipcpu.com/blog/2017/06/02/generating-timing.html | |
module (clk, baud_out) // we are trying to obtain baud_out = clk/(9600*16) | |
input clk; | |
output baud_out; | |
wire ck_stb; | |
reg[17:0] counter; | |
always @(posedge clk) | |
{ck_stb, counter} <= counter + 18'd(9600 << 4); // 9600 * 16 | |
assign baud_out = ck_stb; | |
endmodule | |
`define Tx_IDLE_BIT 0; | |
`define Tx_START_BIT 1; | |
`define Tx_DATA_BITS < `Tx_PARITY_BIT; | |
`define Tx_PARITY_BIT 10; | |
`define Tx_STOP_BIT 11; | |
module TxUART(clk, reset, start_tx, i_data, o_data) | |
input clk, reset, start_tx; | |
input[7:0] i_data; | |
output reg o_data; | |
reg[3:0] state, next_state; | |
wire parity_bit; | |
always @(posedge clk) | |
begin | |
if (reset) | |
state <= `Tx_IDLE_BIT; | |
else | |
state <= next_state; | |
end | |
always @(*) | |
begin : tx_fsm | |
case(state) | |
`Tx_IDLE_BIT : next_state = (start_tx == 1) ? Tx_START_BIT : `Tx_IDLE_BIT; | |
o_data = 1; | |
`Tx_START_BIT : next_state = `Tx_DATA_BIT; | |
o_data = 0; | |
`Tx_DATA_BITS : next_state = state + 1; | |
o_data = i_data[state-2]; | |
`Tx_PARITY_BIT : next_state = `Tx_STOP_BIT; | |
o_data = parity_bit; | |
`Tx_STOP_BIT : next_state = `Tx_IDLE_BIT; | |
o_data = 1; | |
default : next_state = `Tx_IDLE_BIT; | |
o_data = 1; | |
endcase | |
end | |
assign parity_bit = ^i_data; // even parity http://www.asic-world.com/examples/verilog/parity.html | |
endmodule | |
// credit: Adapted from http://zipcpu.com/blog/2017/06/02/generating-timing.html | |
module baud_generator(clk, baud_out) // we are trying to obtain baud_out = clk/(9600*16) | |
input clk; | |
output baud_out; | |
wire ck_stb; | |
reg[17:0] counter; | |
always @(posedge clk) | |
{ck_stb, counter} <= counter + 18'd(9600 << 4); // 9600 * 16 | |
assign baud_out = ck_stb; | |
endmodule | |
// Credit: Adapted from http://www.referencedesigner.com/tutorials/verilog/verilog_32.php | |
module shift_register(clk, reset, data_in, data_out) // cascade of 10 registers | |
parameter N=10; | |
input wire clk, reset; | |
input wire data_in; | |
output wire data_out; | |
reg [N-1:0] r_reg; | |
wire [N-1:0] r_next; | |
always @(posedge clk) | |
begin | |
if (reset) | |
r_reg <= 0; | |
else | |
r_reg <= r_next; | |
end | |
assign r_next = {data_in, r_reg[N-1:1]}; | |
assign data_out = r_reg[0]; | |
endmodule | |
// Adapted from https://github.com/jbush001/NyuziProcessor/blob/master/hardware/core/sync_fifo.sv | |
module FIFO (clk, reset, enqueue, dequeue, flush, i_value, almost_full, almost_empty, o_value) | |
input clk, reset, enqueue, dequeue, flush, i_value; | |
output almost_full, almost_empty, o_value; | |
parameter SIZE = 22; | |
parameter ALMOST_FULL_THRESHOLD = SIZE; | |
parameter ALMOST_EMPTY_THRESHOLD = 1); | |
reg[4:0] head, tail, count; | |
assign almost_full = count >= ALMOST_FULL_THRESHOLD; | |
assign almost_empty = count >= ALMOST_EMPTY_THRESHOLD; | |
assign o_value = data[head]; | |
always @(posedge clk) | |
begin | |
if (reset) begin | |
head <= 0; | |
tail <= 0; | |
count <= 0; | |
end | |
else begin | |
if (flush) begin | |
head <= 0; | |
tail <= 0; | |
count <= 0; | |
end | |
else begin | |
if (enqueue) begin | |
tail <= tail + 1; | |
data[tail] <= i_value; | |
end | |
if (dequeue) begin | |
head <= head + 1; | |
end | |
if (enqueue && !dequeue) | |
count <= count + 1; | |
else if (dequeue && !enqueue) | |
count <= count - 1; | |
end | |
end | |
end | |
endmodule |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment