//---------------------------------------------------------------------------
//
// Wishbone Timer
//
// Register Description:
//
//    0x00 TCR0
//    0x04 COMPARE0
//    0x08 COUNTER0
//    0x0C TCR1
//    0x10 COMPARE1
//    0x14 COUNTER1
//
// TCRx:  
//    +-------------------+-------+-------+-------+-------+
//    |     28'b0         |  EN   |  AR   | IRQEN |  TRIG |
//    +-------------------+-------+-------+-------+-------+
//
//   EN i  (rw)   if set to '1', COUNTERX counts upwards until it reaches
//                COMPAREX
//   AR    (rw)   AutoRecwstartload -- if COUNTER reaches COMPAREX, shall we 
//                restart at 1, or disable this counter?
//   IRQEN (rw)   Indicate interrupt condition when triggered?
//   TRIG  (ro)   
//
//---------------------------------------------------------------------------

module wb_timer #(
	parameter          clk_freq = 50000000
) (
	input              clk,
	input              reset,
	// Wishbone interface
	input              wb_stb_i,
	input              wb_cyc_i,
	output             wb_ack_o,
	input              wb_we_i,
	input       [31:0] wb_adr_i,
	input        [3:0] wb_sel_i,
	input       [31:0] wb_dat_i,
	output reg  [31:0] wb_dat_o,
	//
	output       [1:0] intr
);

//---------------------------------------------------------------------------
// 
//---------------------------------------------------------------------------

reg irqen0, irqen1;
reg trig0, trig1;
reg en0, en1;
reg ar0, ar1;

wire [31:0] tcr0 = { 28'b0, en0, ar0, irqen0, trig0 };
wire [31:0] tcr1 = { 28'b0, en1, ar1, irqen1, trig1 };

reg  [31:0] counter0;
reg  [31:0] counter1;

reg  [31:0] compare0;
reg  [31:0] compare1;

wire match0 = (counter0 == compare0);
wire match1 = (counter1 == compare1);

assign intr = { trig1, trig0 };

reg  ack;
assign wb_ack_o = wb_stb_i & wb_cyc_i & ack;

wire wb_rd = wb_stb_i & wb_cyc_i & ~wb_we_i;
wire wb_wr = wb_stb_i & wb_cyc_i &  wb_we_i;

always @(posedge clk)
begin
	if (reset) begin
		ack      <= 0;
		en0      <= 0;
		en1      <= 0;
		ar0      <= 0;
		ar1      <= 0;
		trig0    <= 0;
		trig1    <= 0;
		counter0 <= 0;
		counter1 <= 0;
		compare0 <= 32'hFFFFFFFF;
		compare1 <= 32'hFFFFFFFF;
	end else begin

		// Handle counter 0
		if ( en0 & ~match0) counter0 <= counter0 + 1;
		if ( en0 &  match0) trig0    <= 1;
		if ( ar0 &  match0) counter0 <= 1;
		if (~ar0 &  match0) en0      <= 0;

		// Handle counter 1
		if ( en1 & ~match1) counter1 <= counter1 + 1;
		if ( en1 &  match1) trig1    <= 1;
		if ( ar1 &  match1) counter1 <= 1;
		if (~ar1 &  match1) en1      <= 0;

		// Handle WISHBONE access
		ack    <= 0;

		if (wb_rd & ~ack) begin           // read cycle
			ack <= 1;

			case (wb_adr_i[7:0])
			'h00: wb_dat_o <= tcr0;
			'h04: wb_dat_o <= compare0;
			'h08: wb_dat_o <= counter0;
			'h0c: wb_dat_o <= tcr1;
			'h10: wb_dat_o <= compare1;
			'h14: wb_dat_o <= counter1;
			default: wb_dat_o <= 32'b0;
			endcase
		end else if (wb_wr & ~ack ) begin // write cycle
			ack <= 1;

			case (wb_adr_i[7:0])
			'h00: begin
				trig0   <= 0;
				irqen0  <= wb_dat_i[1];
				ar0     <= wb_dat_i[2];
				en0     <= wb_dat_i[3];
			end
			'h04: compare0 <= wb_dat_i;
			'h08: counter0 <= wb_dat_i;
			'h0c: begin
				trig1   <= 0;
				irqen1  <= wb_dat_i[1];
				ar1     <= wb_dat_i[2];
				en1     <= wb_dat_i[3];
			end
			'h10: compare1 <= wb_dat_i;
			'h14: counter1 <= wb_dat_i;
			endcase
		end
	end
end


endmodule