`define IN_CLK 8388608 `define OUT_CLK 57600 `define CLK_DIV `IN_CLK / `OUT_CLK `define DATA_ADDR 16'hFF52 `define STAT_ADDR 16'hFF53 module UART( input clk, input wr, input rd, input [15:0] addr, inout [7:0] data, output reg serial = 1, input serialrx); wire data_decode = (addr == `DATA_ADDR); wire stat_decode = (addr == `STAT_ADDR); reg data_latch = 0; reg stat_latch = 0; reg [7:0] tx_data = 0; reg [15:0] tx_clkdiv = 0; reg [3:0] tx_state = 4'b0000; reg tx_busy = 0; wire tx_newdata = (wr) && (!tx_busy) && data_decode; reg rx_hasdata = 0; reg [15:0] rx_clkdiv = 0; reg [3:0] rx_state = 4'b0000; reg [7:0] rx_data, rx_data_tmp; assign data = (stat_latch) ? {6'b0, rx_hasdata, tx_busy} : (data_latch) ? rx_data : 8'bzzzzzzzz; always @(posedge clk) begin data_latch <= rd && data_decode; stat_latch <= rd && stat_decode; if(tx_newdata) begin tx_data <= data; tx_state <= 4'b0000; tx_busy <= 1; end else if (tx_clkdiv == 0) begin tx_state <= tx_state + 1; if (tx_busy) case (tx_state) 4'b0000: serial <= 0; 4'b0001: serial <= tx_data[0]; 4'b0010: serial <= tx_data[1]; 4'b0011: serial <= tx_data[2]; 4'b0100: serial <= tx_data[3]; 4'b0101: serial <= tx_data[4]; 4'b0110: serial <= tx_data[5]; 4'b0111: serial <= tx_data[6]; 4'b1000: serial <= tx_data[7]; 4'b1001: serial <= 1; 4'b1010: tx_busy <= 0; default: $stop; endcase end if ((rx_state == 0) && (serialrx == 0) /*&& (rx_hasdata == 0)*/) /* Kick off. */ rx_state <= 4'b0001; else if ((rx_state != 4'b0000) && (rx_clkdiv == 0)) begin if (rx_state != 4'b1010) rx_state <= rx_state + 1; else rx_state <= 0; case (rx_state) 4'b0001: begin end /* Twiddle thumbs -- this is the end of the half bit. */ 4'b0010: rx_data_tmp[0] <= serialrx; 4'b0011: rx_data_tmp[1] <= serialrx; 4'b0100: rx_data_tmp[2] <= serialrx; 4'b0101: rx_data_tmp[3] <= serialrx; 4'b0110: rx_data_tmp[4] <= serialrx; 4'b0111: rx_data_tmp[5] <= serialrx; 4'b1000: rx_data_tmp[6] <= serialrx; 4'b1001: rx_data_tmp[7] <= serialrx; 4'b1010: if (serialrx == 1) begin rx_data <= rx_data_tmp; /* Expect a 1 */ rx_hasdata <= 1; end endcase end if (rd && data_decode) rx_hasdata <= 0; if(tx_newdata || (tx_clkdiv == `CLK_DIV)) tx_clkdiv <= 0; else tx_clkdiv <= tx_clkdiv + 1; if ((rx_state == 0) && (serialrx == 0) /*&& (rx_hasdata == 0)*/) /* Wait half a period before advancing. */ rx_clkdiv <= `CLK_DIV / 2 + `CLK_DIV / 4; else if (rx_clkdiv == `CLK_DIV) rx_clkdiv <= 0; else rx_clkdiv <= rx_clkdiv + 1; end endmodule