]>
Commit | Line | Data |
---|---|---|
7d9d69c7 | 1 | `define IN_CLK 8388608 |
bf3f2c5f | 2 | `define OUT_CLK 19200 |
a0267255 | 3 | `define CLK_DIV `IN_CLK / `OUT_CLK |
1eefdc8e JW |
4 | `define DATA_ADDR 16'hFF52 |
5 | `define STAT_ADDR 16'hFF53 | |
a0267255 JW |
6 | |
7 | module UART( | |
8 | input clk, | |
9 | input wr, | |
10 | input rd, | |
11 | input [15:0] addr, | |
a85b19a7 | 12 | inout [7:0] data, |
298e8085 JW |
13 | output reg serial = 1, |
14 | input serialrx); | |
a8f4468d | 15 | |
1eefdc8e JW |
16 | wire data_decode = (addr == `DATA_ADDR); |
17 | wire stat_decode = (addr == `STAT_ADDR); | |
18 | reg data_latch = 0; | |
19 | reg stat_latch = 0; | |
a85b19a7 | 20 | |
1eefdc8e JW |
21 | reg [7:0] tx_data = 0; |
22 | reg [15:0] tx_clkdiv = 0; | |
298e8085 JW |
23 | reg [3:0] tx_state = 4'b0000; |
24 | reg tx_busy = 0; | |
1eefdc8e | 25 | wire tx_newdata = (wr) && (!tx_busy) && data_decode; |
a85b19a7 | 26 | |
298e8085 JW |
27 | reg rx_hasdata = 0; |
28 | reg [15:0] rx_clkdiv = 0; | |
29 | reg [3:0] rx_state = 4'b0000; | |
bf3f2c5f | 30 | reg [7:0] rx_data, rx_data_tmp; |
298e8085 JW |
31 | |
32 | assign data = (stat_latch) ? {6'b0, rx_hasdata, tx_busy} : | |
33 | (data_latch) ? rx_data : | |
1eefdc8e | 34 | 8'bzzzzzzzz; |
a0267255 | 35 | |
1eefdc8e | 36 | always @(posedge clk) |
a0267255 | 37 | begin |
1eefdc8e JW |
38 | data_latch <= rd && data_decode; |
39 | stat_latch <= rd && stat_decode; | |
1eefdc8e JW |
40 | if(tx_newdata) begin |
41 | tx_data <= data; | |
42 | tx_state <= 4'b0000; | |
298e8085 | 43 | tx_busy <= 1; |
1eefdc8e JW |
44 | end else if (tx_clkdiv == 0) begin |
45 | tx_state <= tx_state + 1; | |
46 | if (tx_busy) | |
47 | case (tx_state) | |
7d9d69c7 | 48 | 4'b0000: serial <= 0; |
1eefdc8e JW |
49 | 4'b0001: serial <= tx_data[0]; |
50 | 4'b0010: serial <= tx_data[1]; | |
51 | 4'b0011: serial <= tx_data[2]; | |
52 | 4'b0100: serial <= tx_data[3]; | |
53 | 4'b0101: serial <= tx_data[4]; | |
54 | 4'b0110: serial <= tx_data[5]; | |
55 | 4'b0111: serial <= tx_data[6]; | |
56 | 4'b1000: serial <= tx_data[7]; | |
7d9d69c7 | 57 | 4'b1001: serial <= 1; |
298e8085 | 58 | 4'b1010: tx_busy <= 0; |
a0267255 | 59 | default: $stop; |
298e8085 JW |
60 | endcase |
61 | end | |
62 | ||
63 | if ((rx_state == 0) && (serialrx == 0) /*&& (rx_hasdata == 0)*/) /* Kick off. */ | |
64 | rx_state <= 4'b0001; | |
65 | else if ((rx_state != 4'b0000) && (rx_clkdiv == 0)) begin | |
66 | if (rx_state != 4'b1010) | |
67 | rx_state <= rx_state + 1; | |
68 | else | |
69 | rx_state <= 0; | |
70 | case (rx_state) | |
71 | 4'b0001: begin end /* Twiddle thumbs -- this is the end of the half bit. */ | |
bf3f2c5f JW |
72 | 4'b0010: rx_data_tmp[0] <= serialrx; |
73 | 4'b0011: rx_data_tmp[1] <= serialrx; | |
74 | 4'b0100: rx_data_tmp[2] <= serialrx; | |
75 | 4'b0101: rx_data_tmp[3] <= serialrx; | |
76 | 4'b0110: rx_data_tmp[4] <= serialrx; | |
77 | 4'b0111: rx_data_tmp[5] <= serialrx; | |
78 | 4'b1000: rx_data_tmp[6] <= serialrx; | |
79 | 4'b1001: rx_data_tmp[7] <= serialrx; | |
80 | 4'b1010: if (serialrx == 1) begin | |
81 | rx_data <= rx_data_tmp; /* Expect a 1 */ | |
82 | rx_hasdata <= 1; | |
83 | end | |
a0267255 JW |
84 | endcase |
85 | end | |
298e8085 | 86 | |
bf3f2c5f JW |
87 | if (rd && data_decode) |
88 | rx_hasdata <= 0; | |
a0267255 | 89 | |
298e8085 | 90 | if(tx_newdata || (tx_clkdiv == `CLK_DIV)) |
1eefdc8e | 91 | tx_clkdiv <= 0; |
a0267255 | 92 | else |
1eefdc8e | 93 | tx_clkdiv <= tx_clkdiv + 1; |
298e8085 JW |
94 | |
95 | if ((rx_state == 0) && (serialrx == 0) /*&& (rx_hasdata == 0)*/) /* Wait half a period before advancing. */ | |
96 | rx_clkdiv <= `CLK_DIV / 2 + `CLK_DIV / 4; | |
97 | else if (rx_clkdiv == `CLK_DIV) | |
98 | rx_clkdiv <= 0; | |
99 | else | |
100 | rx_clkdiv <= rx_clkdiv + 1; | |
a0267255 JW |
101 | end |
102 | endmodule |