From b44a3a201ee2b524f31aa93abfe4abd8b756a533 Mon Sep 17 00:00:00 2001 From: Wojciech Kosior Date: Sat, 21 Nov 2020 21:35:54 +0100 Subject: add miscellaneous module, which controls led2 and button2 and provides a timer; include a testbench for timer and led --- design/miscellaneous_slave.v | 133 +++++++++++++++++++++++++++++++++++++++++++ design/soc.v | 31 ++++++---- 2 files changed, 153 insertions(+), 11 deletions(-) create mode 100644 design/miscellaneous_slave.v (limited to 'design') 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 */ -- cgit v1.2.3