aboutsummaryrefslogtreecommitdiff
/*
 * This wb slave controls a button, a LED and timer.
 *
 * | *WISHBONE DATASHEET*                                                      |
 * |---------------------------------------------------------------------------|
 * | *Description*                   | *Specification*                         |
 * |---------------------------------+-----------------------------------------|
 * | General description             | miscellaneous peripherals core          |
 * |---------------------------------+-----------------------------------------|
 * | Supported cycles                | SLAVE, pipelined READ/WRITE             |
 * |---------------------------------+-----------------------------------------|
 * | Data port, size                 | 16-bit                                  |
 * | Data port, granularity          | 16-bit                                  |
 * | Data port, maximum operand size | 16-bit                                  |
 * | Data transfer ordering          | Big endian and/or little endian         |
 * | Data transfer ordering          | Undefined                               |
 * | Address port, size              | 3                                       |
 * |---------------------------------+-----------------------------------------|
 * | Clock frequency constraints     | NONE                                    |
 * |---------------------------------+-----------------------------------------|
 * |                                 | *Signal name*    | *WISHBONE Equiv.*    |
 * |                                 |------------------+----------------------|
 * |                                 | ACK_O            | ACK_O                |
 * |                                 | ADR_I            | ADR_I()              |
 * | Supported signal list and cross | CLK_I            | CLK_I                |
 * |     reference to equivalent     | DAT_I            | DAT_I()              |
 * |     WISHBONE signals            | DAT_O            | DAT_O()              |
 * |                                 | STB_I            | STB_I                |
 * |                                 | WE_I             | WE_I                 |
 * |                                 | RST_I            | RST_I                |
 * |                                 | STALL_O          | STALL_O              |
 * |---------------------------------+-----------------------------------------|
 * | Special requirements            | NONE                                    |
 *
 * Registers and their addresses:
 *   button2 clicks    - address 1
 *   led2 state        - address 3
 *   timer (low bits)  - address 4
 *   timer (high bits) - address 5
 * Addresses 0, 2, 6 and 7 are not used (undefined contents).
 *
 * The button register resets to 0. Its content increases by 1
 * every time button is clicked. Button register can also be set to an arbitrary
 * value by writing to it.
 *
 * Writing any non-0 value to led register causes led to be turned on.
 * Writing 0 to led register causes led to be turned off. Reading
 * led register gives hFFFF if led is on or h0000 otherwire. Led is
 * switched off on reset.
 *
 * Timer has 32 bits and increases by one every clock tick. It starts
 * with value 0 on reset. Low 16 bits of timer and high 16 bits of timer are
 * available at addresses 4 and 5, respectively. Those addresses can also be
 * written to, if one desires to set the clock to a certain value. Care must
 * be taken when reading the timer, because between the read of first
 * and second half, the bottom part might overlap to 0, causing the high part
 * to increase by 1. Because of that, the correct procedure is to read one of
 * timer registers twice and compare the values. Of course, when measuring
 * very short or very long times, it might be justifiable to only read one half
 * of the timer.
 */

`default_nettype none

module miscellaneous_slave
  #(
    /*
     * Assuming CLK_I is 12.5 MHz, we'd need around 22 and half a bit
     * to achieve half-second cooldown. Passig a lower value here makes
     * it easier to create a simulation that uses buttons and also manages
     * to finish running b4 trumpets for the last judgement sound...
     */
    parameter BUTTON_COOLDOWN_BITS = 17
    )
   (
    output wire        ACK_O,
    input wire 	       CLK_I,
    input wire [2:0]   ADR_I,
    input wire [15:0]  DAT_I,
    output wire [15:0] DAT_O,
    input wire 	       RST_I,
    input wire 	       STB_I,
    input wire 	       WE_I,
    output wire        STALL_O,

    /* Non-wishbone */
    /* no button1, since it is reserved to be used as reset button */
    input wire 	       button2,
    /* no led2, since it is reserved for signalling when cpu stops operating */
    output wire        led2
    );

   reg [15:0] 	       button2_clicks;
   reg [1:0] 	       button2_latched;
   /*
    * After button is released we measure a cooldown time b4 recording another
    * click. Without this, a single button click could be recorded as many
    * clicks (I know from my own experience with the board).
    */
   reg [BUTTON_COOLDOWN_BITS-1:0] button2_cooldown;

   reg 		       led2_state;
   assign led2 = ~led2_state;

   reg [31:0] 	       timer_count;

   reg [15:0] output_data;
   reg 	      ack;

   assign DAT_O = output_data;
   assign ACK_O = ack;
   assign STALL_O = 0;

   always @ (posedge CLK_I) begin
      /* Latch and also invert button signals (the inputs are active low) */
      button2_latched <= {button2_latched[0], ~button2};

      if (!button2_cooldown && button2_latched == 2'b01)
	button2_clicks <= button2_clicks + 1; /* might get overwritten below */

      if (button2_latched[0])
	button2_cooldown <= -1;
      else if (button2_cooldown)
	button2_cooldown <= button2_cooldown - 1; /* might get overwritten below */

      output_data <= 16'hXXXX; /* might get overwritten below */

      if (RST_I) begin
	 ack <= 0;
	 button2_clicks <= 0;
	 button2_cooldown <= -1;
	 led2_state <= 0;
	 timer_count <= 0;
      end else begin
	 ack <= STB_I;

	 timer_count <= timer_count + 1;

	 if (STB_I) begin
	    case (ADR_I)
	      1 : begin
		 output_data <= button2_clicks;
		 if (WE_I)
		   button2_clicks <= DAT_I;
	      end
	      3 : begin
		 output_data <= {16{led2_state}};
		 if (WE_I)
		   led2_state <= DAT_I != 0;
	      end
	      4 : begin
		 output_data <= timer_count[15:0];
		 if (WE_I)
		   timer_count[15:0] <= DAT_I;
	      end
	      5 : begin
		 output_data <= timer_count[31:16];
		 if (WE_I)
		   timer_count[31:16] <= DAT_I;
	      end
	    endcase // case (ADR_I)
	 end // if (STB_I)
      end // else: !if(RST_I)
   end // always @ (posedge CLK_I)
endmodule // miscellaneous