]> Joshua Wise's Git repositories - fpgaboy.git/blobdiff - Timer.v
First cut at timer
[fpgaboy.git] / Timer.v
diff --git a/Timer.v b/Timer.v
new file mode 100644 (file)
index 0000000..0481614
--- /dev/null
+++ b/Timer.v
@@ -0,0 +1,65 @@
+`define ADDR_DIV  16'hFF04
+`define ADDR_TIMA 16'hFF05
+`define ADDR_TMA  16'hFF06
+`define ADDR_TAC  16'hFF07
+
+module Timer(
+       input clk,
+       input wr,
+       input rd,
+       input [15:0] addr,
+       inout [7:0] data,
+       output reg irq);
+
+       reg [7:0] tima = 0, tma = 0, tac = 0, div = 0;
+       reg ovf = 0;
+       reg [9:0] clkdv;
+
+       wire is_tima = addr == `ADDR_TIMA;
+       wire is_tma  = addr == `ADDR_TMA;
+       wire is_tac  = addr == `ADDR_TAC;
+
+       assign data = rd ?
+                        is_tima ? tima :
+                        is_tma ? tma :
+                        is_tac ? tac :
+                        8'bzzzzzzzz :
+                     8'bzzzzzzzz;
+
+       wire cksel = tac[2] ?
+                       (tac[1:0] == 2'b00) ? (clkdv == 10'b0)     :
+                       (tac[1:0] == 2'b01) ? (clkdv[3:0] == 4'b0) :
+                       (tac[1:0] == 2'b10) ? (clkdv[5:0] == 6'b0) :
+                       (clkdv[7:0] == 8'b0) :
+                    0;
+
+       always @ (negedge clk) 
+       begin
+               if(wr) begin
+                       case(addr)
+                       `ADDR_DIV: div <= 8'b0;
+                       `ADDR_TIMA: tima <= data;
+                       `ADDR_TMA: tma <= data;
+                       `ADDR_TAC: tac <= data;
+                       endcase
+               end
+               else begin
+                       if(ovf) begin
+                               tima <= tma;
+                               ovf <= 0;
+                               irq <= 1;
+                       end
+                       else begin
+                               if(cksel)
+                                       {ovf,tima} <= {1'b0,tima} + 1;
+                               if(irq)
+                                       irq <= 0;
+                       end
+
+                       if(clkdv[7:0] == 8'b0)
+                               div <= div + 1;
+               end
+               clkdv <= clkdv + 1;
+       end
+
+endmodule
This page took 0.023058 seconds and 4 git commands to generate.