IP
[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, rx_data_tmp;
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_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
84                         endcase
85                 end
86                 
87                 if (rd && data_decode)
88                         rx_hasdata <= 0;
89
90                 if(tx_newdata || (tx_clkdiv == `CLK_DIV))
91                         tx_clkdiv <= 0;
92                 else
93                         tx_clkdiv <= tx_clkdiv + 1;
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;
101         end
102 endmodule
This page took 0.024032 seconds and 4 git commands to generate.