aboutsummaryrefslogtreecommitdiff
path: root/design
diff options
context:
space:
mode:
Diffstat (limited to 'design')
-rw-r--r--design/miscellaneous_slave.v133
-rw-r--r--design/soc.v31
2 files changed, 153 insertions, 11 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
diff --git a/design/soc.v b/design/soc.v
index b395404..4171f1d 100644
--- a/design/soc.v
+++ b/design/soc.v
@@ -6,7 +6,7 @@
* slave 2 - VGA text-mode controller
* slave 3 - SPI master controller
* slave 4 - UART controller (yet to be added)
- * slave 5 - miscellaneous registers (yet to be added)
+ * slave 5 - miscellaneous registers
*
* The memory map from stack machine's viewpoint is as follows:
* h000000 - h0001FF - embedded RAM
@@ -24,7 +24,7 @@
* h140208 - h1403FF - undefined (actually, repetitions of SPI regs)
* h140400 - h17FFFF - undefined (actually, repetitions of SPI memory & regs)
* h180000 - h1BFFFF - UART (not implemented yet)
- * h1C0000 - h1FFFFF - miscellaneous peripherals (not implemented yet)
+ * h1C0000 - h1FFFFF - miscellaneous peripherals
*/
`default_nettype none
@@ -213,18 +213,28 @@ module soc
.ss_n(spi_ss_n)
);
- /*
- * Slaves 4 and 5 will be UART controller and miscellaneous registers,
- * but for now - they're omitted
- */
+ miscellaneous_slave slave5
+ (
+ .ACK_O(S5_ACK_O),
+ .CLK_I(CLK),
+ .ADR_I(S5_ADR_I[2:0]),
+ .DAT_I(S5_DAT_I),
+ .DAT_O(S5_DAT_O),
+ .RST_I(RST),
+ .STB_I(S5_STB_I),
+ .WE_I(S5_WE_I),
+ .STALL_O(S5_STALL_O),
+
+ /* Non-wishbone */
+ .button2(button2),
+ .led2(led2)
+ );
+
+ /* Slaves 4 will be UART controller but for now - it's omitted */
assign S4_ACK_O = 1;
assign S4_DAT_O = 0;
assign S4_STALL_O = 0;
- assign S5_ACK_O = 1;
- assign S5_DAT_O = 0;
- assign S5_STALL_O = 0;
-
intercon intercon
(
.CLK(CLK),
@@ -312,7 +322,6 @@ module soc
assign RST = reset;
assign led1 = !M_finished;
- assign led2 = !M_finished;
`ifdef SIMULATION
/* avoid undefined values */