]>
Commit | Line | Data |
---|---|---|
1 | `define ADDR_DIV 16'hFF04 | |
2 | `define ADDR_TIMA 16'hFF05 | |
3 | `define ADDR_TMA 16'hFF06 | |
4 | `define ADDR_TAC 16'hFF07 | |
5 | ||
6 | module Timer( | |
7 | input clk, | |
8 | input wr, | |
9 | input rd, | |
10 | input [15:0] addr, | |
11 | inout [7:0] data, | |
12 | output reg irq = 0); | |
13 | ||
14 | reg [7:0] tima = 0, tma = 0, tac = 0, div = 0; | |
15 | reg ovf = 0; | |
16 | reg [9:0] clkdv = 0; | |
17 | ||
18 | wire is_tima = addr == `ADDR_TIMA; | |
19 | wire is_tma = addr == `ADDR_TMA; | |
20 | wire is_tac = addr == `ADDR_TAC; | |
21 | ||
22 | assign data = rd ? | |
23 | is_tima ? tima : | |
24 | is_tma ? tma : | |
25 | is_tac ? tac : | |
26 | 8'bzzzzzzzz : | |
27 | 8'bzzzzzzzz; | |
28 | ||
29 | wire cksel = tac[2] ? | |
30 | (tac[1:0] == 2'b00) ? (clkdv == 10'b0) : | |
31 | (tac[1:0] == 2'b01) ? (clkdv[3:0] == 4'b0) : | |
32 | (tac[1:0] == 2'b10) ? (clkdv[5:0] == 6'b0) : | |
33 | (clkdv[7:0] == 8'b0) : | |
34 | 0; | |
35 | ||
36 | always @ (posedge clk) | |
37 | begin | |
38 | if(wr) begin | |
39 | case(addr) | |
40 | `ADDR_DIV: div <= 8'b0; | |
41 | `ADDR_TIMA: tima <= data; | |
42 | `ADDR_TMA: tma <= data; | |
43 | `ADDR_TAC: tac <= data; | |
44 | endcase | |
45 | end | |
46 | else begin | |
47 | if(ovf) begin | |
48 | tima <= tma; | |
49 | ovf <= 0; | |
50 | irq <= 1; | |
51 | end | |
52 | else begin | |
53 | if(cksel) | |
54 | {ovf,tima} <= {1'b0,tima} + 1; | |
55 | if(irq) | |
56 | irq <= 0; | |
57 | end | |
58 | ||
59 | if(clkdv[7:0] == 8'b0) | |
60 | div <= div + 1; | |
61 | end | |
62 | clkdv <= clkdv + 1; | |
63 | end | |
64 | ||
65 | endmodule |