module TIMER (CLK_I,RST_I,ADR_I,DAT_I,DAT_O,STB_I,WE_I,ACK_O,IRQ_O); parameter INIT_RELOAD = 0; input CLK_I, RST_I, STB_I, WE_I; input [1:0] ADR_I; input [31:0] DAT_I; output [31:0] DAT_O; output ACK_O, IRQ_O; reg [31:0] RELOAD = INIT_RELOAD; reg [31:0] COUNTER = INIT_RELOAD; reg [63:0] TIMEBASE = 64'd0; wire ZERO = ~|COUNTER; assign ACK_O = STB_I; assign IRQ_O = ZERO & ~RST_I; reg [31:0] DAT_O; always @* begin case (ADR_I) 2'd0: DAT_O <= COUNTER; 2'd1: DAT_O <= RELOAD; 2'd2: DAT_O <= TIMEBASE[63:32]; 2'd3: DAT_O <= TIMEBASE[31:0]; endcase end always @(posedge CLK_I) begin if (RST_I) begin RELOAD <= INIT_RELOAD; COUNTER <= INIT_RELOAD; TIMEBASE <= 64'd0; end else begin if (STB_I & WE_I & ~ADR_I[1] & ~ADR_I[0]) COUNTER <= DAT_I; else if (ZERO | RST_I) COUNTER <= RELOAD; else COUNTER <= COUNTER - 1; if (STB_I & WE_I & ~ADR_I[1] & ADR_I[0]) RELOAD <= DAT_I; if (STB_I & WE_I & ADR_I[1] & ~ADR_I[0]) TIMEBASE <= { DAT_I, 32'd0 }; else if (STB_I & WE_I & ADR_I[1] & ADR_I[0]) TIMEBASE <= { TIMEBASE[63:32], DAT_I }; else TIMEBASE <= TIMEBASE + 1; end end endmodule