332620bde94fa765a5cbdb4cd376d1bc0ff80f41
[fpgaboy.git] / Uart.v
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
This page took 0.017217 seconds and 2 git commands to generate.