aboutsummaryrefslogtreecommitdiff
path: root/design/miscellaneous_slave.v
diff options
context:
space:
mode:
Diffstat (limited to 'design/miscellaneous_slave.v')
-rw-r--r--design/miscellaneous_slave.v133
1 files changed, 133 insertions, 0 deletions
diff --git a/design/miscellaneous_slave.v b/design/miscellaneous_slave.v
new file mode 100644
index 0000000..7274db7
--- /dev/null
+++ b/design/miscellaneous_slave.v
@@ -0,0 +1,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