aboutsummaryrefslogtreecommitdiff
path: root/design/miscellaneous_slave.v
blob: 7274db7a494c301630978c61af015e5d6e74529c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * This wb slave controls buttons, LEDs (only one LED, actually) and timer.
 *
 * 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