349 lines
7.6 KiB
Verilog
349 lines
7.6 KiB
Verilog
//
|
|
//
|
|
// File Name : uart_and_loader.v
|
|
// Used on :
|
|
// Author : MicroCore Labs
|
|
// Creation : 5/3/16
|
|
// Code Type : Synthesizable
|
|
//
|
|
// Description:
|
|
// ============
|
|
//
|
|
// Fixed 9600 baud rate UART
|
|
// Also a Program ROM loader that decodes Intel-Hex format
|
|
//
|
|
//
|
|
// RS232 control characters:
|
|
//
|
|
// '{' = Put the CPU into RESET and enable the loader
|
|
// '}' = Take the CPU out of RESET
|
|
//
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
module uart_and_loader
|
|
(
|
|
input CLK,
|
|
input RST_n,
|
|
|
|
input [1:0] ADDRESS,
|
|
input [7:0] DATA_IN,
|
|
output [7:0] DATA_OUT,
|
|
input STROBE_RD,
|
|
input STROBE_WR,
|
|
|
|
input UART_RX,
|
|
output UART_TX,
|
|
output UART_INT,
|
|
|
|
output reg [15:0] LOADER_ADDR,
|
|
output reg [7:0] LOADER_DATA,
|
|
output reg LOADER_WR,
|
|
output RESET_OUT
|
|
|
|
|
|
|
|
);
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
// Internal Signals
|
|
|
|
reg RX_STATE = 'h0;
|
|
reg uart_rx_d = 1'b1;
|
|
reg uart_rx_d1 = 1'b1;
|
|
reg uart_rx_d2 = 1'b1;
|
|
reg bit_clk = 'h0;
|
|
reg bit_clk_d = 'h0;
|
|
reg rx_havebyte = 'h0;
|
|
reg host_tx_go = 'h0;
|
|
reg host_tx_go_d = 'h0;
|
|
reg rx_byte_available = 'h0;
|
|
reg reset_out_int = 'h0;
|
|
reg [7:0] tx_byte = 8'hFF;
|
|
reg [10:0] tx_count = 'h0;
|
|
reg [10:0] tx_shift_out = 11'b111_1111_1111;
|
|
reg [8:0] rx_byte = 9'b1111_1111_1;
|
|
reg [13:0] rx_count = 'h0;
|
|
reg [4:0] rx_bits = 'h0;
|
|
reg [13:0] prescaler = 'h0;
|
|
reg [3:0] loader_state = 'h0;
|
|
reg [7:0] loader_bytes = 'h0;
|
|
reg [15:0] loader_adder_int = 'h0;
|
|
wire [1:0] uart_status;
|
|
wire [3:0] hex_nibble ;
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// Combinationals
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
assign UART_TX = tx_shift_out[0];
|
|
|
|
assign UART_INT = rx_byte_available;
|
|
|
|
assign DATA_OUT = (ADDRESS==2'h0) ? rx_byte[7:0] :
|
|
(ADDRESS==2'h1) ? uart_status :
|
|
8'hEE;
|
|
|
|
assign uart_status[1] = (tx_count[9:0]==10'b0000000000) ? 1'b0 : 1'b1; // 1=TX_BUSY
|
|
assign uart_status[0] = rx_byte_available;
|
|
|
|
|
|
assign hex_nibble = (rx_byte[6]==1'b0) ? rx_byte[3:0] : rx_byte[3:0] + 4'h9;
|
|
|
|
assign RESET_OUT = reset_out_int;
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// UART Controller
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
always @(posedge CLK)
|
|
begin : STATE_MACHINE
|
|
|
|
begin
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// Host interface and prescaler
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
// Prescaler fixed for 9600 baud - Xilinx 100Mhz = 14'h28B0
|
|
if (prescaler[13:0]==14'h28B0)
|
|
begin
|
|
bit_clk <= ~ bit_clk;
|
|
prescaler <= 'h0;
|
|
end
|
|
else
|
|
begin
|
|
prescaler <= prescaler + 1'b1;
|
|
end
|
|
|
|
bit_clk_d <= bit_clk;
|
|
|
|
|
|
// Address: 0x0 - RO - RX_BYTE - reading clears the RX_HAS_BYTE bit
|
|
// 0x1 - RO - UART status [1]=TX_BUSY [0]=RX_HAS_BYTE
|
|
// 0x2 - WO - TX Byte - Sends the TX byte over UART
|
|
|
|
|
|
// Writes to Registers
|
|
if (STROBE_WR==1'b1 && ADDRESS[1:0]==2'h2)
|
|
begin
|
|
host_tx_go <= 1'b1;
|
|
tx_byte <= DATA_IN;
|
|
end
|
|
else
|
|
begin
|
|
host_tx_go <= 1'b0;
|
|
end
|
|
|
|
|
|
if (rx_havebyte==1'b1)
|
|
begin
|
|
rx_byte_available <= 1'b1;
|
|
end
|
|
else if (STROBE_RD==1'b1 && ADDRESS[1:0]==2'h0)
|
|
begin
|
|
rx_byte_available <= 1'b0;
|
|
end
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// RX Controller
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
uart_rx_d <= UART_RX;
|
|
uart_rx_d1 <= uart_rx_d;
|
|
uart_rx_d2 <= uart_rx_d1;
|
|
|
|
|
|
case (RX_STATE) // synthesis parallel_case
|
|
|
|
1'h0 : begin
|
|
// Debounce signals
|
|
rx_havebyte <= 1'b0;
|
|
rx_bits <= 'h0;
|
|
|
|
// Look for start bit
|
|
if (uart_rx_d2==1'b0)
|
|
begin
|
|
rx_count <= rx_count + 1'b1;
|
|
end
|
|
|
|
// Count half-way into the start bit
|
|
if (rx_count==14'h1458)
|
|
begin
|
|
rx_count <= 'h0;
|
|
rx_byte <= 9'b1_11111111;
|
|
RX_STATE <= 1'h1;
|
|
end
|
|
end
|
|
|
|
|
|
1'h1 : begin
|
|
rx_count <= rx_count + 1'b1;
|
|
|
|
// Count complete bit-times
|
|
if (rx_count==14'h28B0)
|
|
begin
|
|
rx_byte[8:0] <= { uart_rx_d2 , rx_byte[8:1] };
|
|
rx_bits <= rx_bits + 1'b1;
|
|
rx_count <= 'h0;
|
|
end
|
|
|
|
// Complete byte has been shifted in
|
|
if (rx_bits==4'h9)
|
|
begin
|
|
rx_havebyte <= 1'b1;
|
|
RX_STATE <= 1'h0;
|
|
end
|
|
end
|
|
|
|
default : ;
|
|
endcase
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// TX Controller
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
// Load transmit shifter on rising edge of host request
|
|
host_tx_go_d <= host_tx_go;
|
|
if (host_tx_go_d==1'b0 && host_tx_go==1'b1)
|
|
begin
|
|
tx_shift_out <= { 1'b1 , tx_byte , 1'b0 , 1'b1 };
|
|
tx_count <= 11'b11111111111;
|
|
end
|
|
|
|
// Otherwise shift out bits at each bit clock.
|
|
// When tx_count is all zeros tye byte has been sent.
|
|
else
|
|
begin
|
|
if (bit_clk_d != bit_clk)
|
|
begin
|
|
tx_shift_out[10:0] <= { 1'b1 , tx_shift_out[10:1] };
|
|
tx_count[10:0] <= { 1'b0 , tx_count[10:1] };
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// Program ROM Loader
|
|
//
|
|
// Snoops the RX line at 9600 baud and decodes Intel-Hex format
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
// Perform the steps as each byte is received
|
|
//
|
|
if (rx_havebyte==1'b1)
|
|
begin
|
|
|
|
// '{' asserts RESET_OUT
|
|
if (rx_byte[7:0] == 8'h7B)
|
|
begin
|
|
reset_out_int <= 1'b1;
|
|
end
|
|
|
|
// '}' deasserts RESET_OUT
|
|
if (rx_byte[7:0] == 8'h7D)
|
|
begin
|
|
reset_out_int <= 1'b0;
|
|
end
|
|
|
|
|
|
loader_state <= loader_state + 1'b1;
|
|
|
|
case (loader_state) // synthesis parallel_case
|
|
|
|
|
|
// Stay in state-0 until the ':' character is received and RESET_OUT is asserted
|
|
//
|
|
4'h0: begin
|
|
if (reset_out_int==1'b1 && rx_byte[7:0] == 8'h3A)
|
|
begin
|
|
loader_state <= 4'h1;
|
|
end
|
|
else
|
|
begin
|
|
loader_state <= 4'h0;
|
|
end
|
|
end
|
|
|
|
|
|
// Decode the number of bytes in the Intel-Hex string
|
|
//
|
|
4'h1: begin loader_bytes[7:4] <= hex_nibble; end
|
|
4'h2: begin loader_bytes[3:0] <= hex_nibble; end
|
|
|
|
|
|
// Decode the start Address for the following bytes
|
|
//
|
|
4'h3: begin loader_adder_int[15:12] <= hex_nibble; end
|
|
4'h4: begin loader_adder_int[11:8] <= hex_nibble; end
|
|
4'h5: begin loader_adder_int[7:4] <= hex_nibble; end
|
|
4'h6: begin loader_adder_int[3:0] <= hex_nibble; end
|
|
|
|
|
|
// Ignore the Record Type for now
|
|
//
|
|
4'h7: ;
|
|
4'h8: ;
|
|
|
|
|
|
// Load bytes and increment the loader address until loader_bytes reaches zero
|
|
//
|
|
4'h9: begin
|
|
LOADER_WR <= 1'b0;
|
|
LOADER_ADDR <= loader_adder_int;
|
|
LOADER_DATA[7:4] <= hex_nibble;
|
|
if (loader_bytes == 8'h00)
|
|
begin
|
|
loader_state <= 4'h0;
|
|
end
|
|
end
|
|
|
|
4'hA: begin
|
|
LOADER_WR <= 1'b1;
|
|
LOADER_DATA[3:0] <= hex_nibble;
|
|
loader_adder_int <= loader_adder_int + 1'b1;
|
|
loader_bytes <= loader_bytes - 1'b1;
|
|
loader_state <= 4'h9;
|
|
end
|
|
|
|
default : ;
|
|
endcase
|
|
|
|
end
|
|
|
|
|
|
end
|
|
end
|
|
|
|
endmodule
|