`define IN_CLK 8388608
-`define OUT_CLK 9600
+`define OUT_CLK 57600
`define CLK_DIV `IN_CLK / `OUT_CLK
-`define MMAP_ADDR 16'hFF50
+`define DATA_ADDR 16'hFF52
+`define STAT_ADDR 16'hFF53
module UART(
input clk,
input rd,
input [15:0] addr,
inout [7:0] data,
- output reg serial = 1);
-
- wire decode = (addr == `MMAP_ADDR);
-
- wire [7:0] odata;
- assign data = (rd && decode) ? odata : 8'bzzzzzzzz;
+ output reg serial = 1,
+ input serialrx);
- reg [7:0] data_stor = 0;
- reg [15:0] clkdiv = 0;
- reg have_data = 0;
- reg data_end = 0;
- reg [3:0] diqing = 4'b0000;
+ 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;
- wire new = (wr) && (!have_data) && decode;
+ reg rx_hasdata = 0;
+ reg [15:0] rx_clkdiv = 0;
+ reg [3:0] rx_state = 4'b0000;
+ reg [7:0] rx_data;
- assign odata = have_data ? 8'b1 : 8'b0;
+ assign data = (stat_latch) ? {6'b0, rx_hasdata, tx_busy} :
+ (data_latch) ? rx_data :
+ 8'bzzzzzzzz;
- always @ (negedge clk)
+ always @(posedge clk)
begin
- /* deal with diqing */
- if(new) begin
- data_stor <= data;
- have_data <= 1;
- diqing <= 4'b0000;
- end else if (clkdiv == 0) begin
- diqing <= diqing + 1;
- if (have_data)
- case (diqing)
+ 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 <= data_stor[0];
- 4'b0010: serial <= data_stor[1];
- 4'b0011: serial <= data_stor[2];
- 4'b0100: serial <= data_stor[3];
- 4'b0101: serial <= data_stor[4];
- 4'b0110: serial <= data_stor[5];
- 4'b0111: serial <= data_stor[6];
- 4'b1000: serial <= data_stor[7];
+ 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: have_data <= 0;
+ 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[0] <= serialrx;
+ 4'b0011: rx_data[1] <= serialrx;
+ 4'b0100: rx_data[2] <= serialrx;
+ 4'b0101: rx_data[3] <= serialrx;
+ 4'b0110: rx_data[4] <= serialrx;
+ 4'b0111: rx_data[5] <= serialrx;
+ 4'b1000: rx_data[6] <= serialrx;
+ 4'b1001: rx_data[7] <= serialrx;
+ 4'b1010: begin end /* Expect a 1 */
endcase
end
+
+ rx_hasdata <= (rx_hasdata && ~(rd && data_decode)) || ((rx_state == 4'b1010) && (tx_clkdiv == 0));
- /* deal with clkdiv */
- if((new && !have_data) || clkdiv == `CLK_DIV)
- clkdiv <= 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
- clkdiv <= clkdiv + 1;
+ rx_clkdiv <= rx_clkdiv + 1;
end
endmodule