`timescale 1ns/1ps

module testbench ();
   
   // DECLARE SIGNALS
   reg  clk;
   reg 	rst_l;

   // Simulated row/col for keypress position:
   reg [3:0]  row_pressed;
   reg [3:0]  col_pressed;
   
   // Interface wires:
   wire [3:0]  row_wire;
   wire [3:0]  col_wire;
   wire [15:0] keys;
   wire        refresh;
   
   integer     clk_count     = 0;   
   integer     refresh_count = 0;

   // The row wire can be pulled down only if the column wire matches
   // the column where the button is pressed:
   assign row_wire[0] = &(col_wire===col_pressed) ? row_pressed[0] : 1 ;
   assign row_wire[1] = &(col_wire===col_pressed) ? row_pressed[1] : 1 ;
   assign row_wire[2] = &(col_wire===col_pressed) ? row_pressed[2] : 1 ;
   assign row_wire[3] = &(col_wire===col_pressed) ? row_pressed[3] : 1 ;
   
   
   // KEYPAD MODULE
   keypad #(.N(300_000)) kypd
     (
      .clk(clk),
      .rst_l(rst_l),
      .col(col_wire),
      .row(row_wire),
      .keys(keys)
      );

   // Timing to change key value every
   // refresh interval
   clock_divider #(.N(1_200_000)) clkdiv
   (.clk(clk),.rst_l(rst_l),.div_clk(refresh));
   
   
   // INITIAL SIGNAL CONFIGURATION:
   initial begin
      clk   = 0;
      rst_l = 0;  // start up in reset condition

      // Initially no button is pressed, we will start
      // pressing buttons in column zero:
      row_pressed   = 4'b1111;   
      col_pressed   = 4'bZZZ0;
      
      clk_count     = 0;
      refresh_count = 0;
   end

   // GENERATE CLOCK:
   initial forever #10 clk = ~clk;
   

   // CREATE STIMULI:
   always @(posedge clk) begin
      // Control the reset behavior:
      if (!rst_l) begin
	 rst_l <= 1;
	 row_pressed   <= 4'b1111; // No key pressed, all rows HIGH	 
      end
      else begin
	 if (refresh) begin
	    case (row_pressed)
	      4'b1111: row_pressed <= 4'b1110; // first row_pressed
	      4'b1110: row_pressed <= 4'b1101; // second row_pressed
	      4'b1101: row_pressed <= 4'b1011; // third row_pressed
	      4'b1011: row_pressed <= 4'b0111; // fourth row_pressed
	      4'b0111: // After the last row, we change column and 
		begin  // start going through the rows again:
		   row_pressed <= 4'b1111; 
		   
		   case (col_pressed)
		     4'bZZZ0 : col_pressed <= 4'bZZ0Z;
		     4'bZZ0Z : col_pressed <= 4'bZ0ZZ;
		     4'bZ0ZZ : col_pressed <= 4'b0ZZZ;
		     4'b0ZZZ : col_pressed <= 4'bZZZ0;
		   endcase // case (col_pressed)
		end
	    endcase
	 end
      end
   end

   // WRITE OUTPUT TO CONSOLE:
   integer fid;
   initial fid = $fopen("test_result.txt", "w");
   
   always @(posedge clk) begin
      if (kypd.scan) begin
	 $write("clk: %d", clk_count);      
	 $write("\tpressed(col: %b", col_pressed);
	 $write(", row: %b)", row_pressed);
	 $write("\twire(col: %b", col_wire);
	 $write(", row: %b)", row_wire);
	 $write("\tkeys: %b", keys);
	 $write("\n");
	 
	 $fwrite(fid,"clk:  %d", clk_count);
	 $fwrite(fid,"\tcol: %b", col_wire);
	 $fwrite(fid,"\trow: %b", row_wire);
	 $fwrite(fid,"\tkeys: %b", keys);
	 $fwrite(fid,"\n");
      end
   end

   // DEFINE WHEN TO TERMINATE SIMULATION:
   // we want to test all button positions, but it
   // takes a full refresh cycle for each button,
   // so we want to terminate after at least 20
   // refresh events:
   always @(posedge clk) begin
      clk_count <= clk_count + 1;
      if (refresh)
	refresh_count <= refresh_count + 1;
      
      if (refresh_count == 21) begin
	 $fclose(fid);
	 $finish;
      end
   end

   
endmodule // testbench
