]>
Commit | Line | Data |
---|---|---|
1 | `define IN_CLK 8388608 | |
2 | `define OUT_CLK 57600 | |
3 | `define CLK_DIV `IN_CLK / `OUT_CLK | |
4 | `define DATA_ADDR 16'hFF52 | |
5 | `define STAT_ADDR 16'hFF53 | |
6 | ||
7 | module UART( | |
8 | input clk, | |
9 | input wr, | |
10 | input rd, | |
11 | input [15:0] addr, | |
12 | inout [7:0] data, | |
13 | output reg serial = 1, | |
14 | input serialrx); | |
15 | ||
16 | wire data_decode = (addr == `DATA_ADDR); | |
17 | wire stat_decode = (addr == `STAT_ADDR); | |
18 | reg data_latch = 0; | |
19 | reg stat_latch = 0; | |
20 | ||
21 | reg [7:0] tx_data = 0; | |
22 | reg [15:0] tx_clkdiv = 0; | |
23 | reg [3:0] tx_state = 4'b0000; | |
24 | reg tx_busy = 0; | |
25 | wire tx_newdata = (wr) && (!tx_busy) && data_decode; | |
26 | ||
27 | reg rx_hasdata = 0; | |
28 | reg [15:0] rx_clkdiv = 0; | |
29 | reg [3:0] rx_state = 4'b0000; | |
30 | reg [7:0] rx_data; | |
31 | ||
32 | assign data = (stat_latch) ? {6'b0, rx_hasdata, tx_busy} : | |
33 | (data_latch) ? rx_data : | |
34 | 8'bzzzzzzzz; | |
35 | ||
36 | always @(posedge clk) | |
37 | begin | |
38 | data_latch <= rd && data_decode; | |
39 | stat_latch <= rd && stat_decode; | |
40 | if(tx_newdata) begin | |
41 | tx_data <= data; | |
42 | tx_state <= 4'b0000; | |
43 | tx_busy <= 1; | |
44 | end else if (tx_clkdiv == 0) begin | |
45 | tx_state <= tx_state + 1; | |
46 | if (tx_busy) | |
47 | case (tx_state) | |
48 | 4'b0000: serial <= 0; | |
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]; | |
57 | 4'b1001: serial <= 1; | |
58 | 4'b1010: tx_busy <= 0; | |
59 | default: $stop; | |
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. */ | |
72 | 4'b0010: rx_data[0] <= serialrx; | |
73 | 4'b0011: rx_data[1] <= serialrx; | |
74 | 4'b0100: rx_data[2] <= serialrx; | |
75 | 4'b0101: rx_data[3] <= serialrx; | |
76 | 4'b0110: rx_data[4] <= serialrx; | |
77 | 4'b0111: rx_data[5] <= serialrx; | |
78 | 4'b1000: rx_data[6] <= serialrx; | |
79 | 4'b1001: rx_data[7] <= serialrx; | |
80 | 4'b1010: begin end /* Expect a 1 */ | |
81 | endcase | |
82 | end | |
83 | ||
84 | rx_hasdata <= (rx_hasdata && ~(rd && data_decode)) || ((rx_state == 4'b1010) && (tx_clkdiv == 0)); | |
85 | ||
86 | if(tx_newdata || (tx_clkdiv == `CLK_DIV)) | |
87 | tx_clkdiv <= 0; | |
88 | else | |
89 | tx_clkdiv <= tx_clkdiv + 1; | |
90 | ||
91 | if ((rx_state == 0) && (serialrx == 0) /*&& (rx_hasdata == 0)*/) /* Wait half a period before advancing. */ | |
92 | rx_clkdiv <= `CLK_DIV / 2 + `CLK_DIV / 4; | |
93 | else if (rx_clkdiv == `CLK_DIV) | |
94 | rx_clkdiv <= 0; | |
95 | else | |
96 | rx_clkdiv <= rx_clkdiv + 1; | |
97 | end | |
98 | endmodule |