diff options
author | Wojciech Kosior <kwojtus@protonmail.com> | 2020-11-21 21:35:54 +0100 |
---|---|---|
committer | Wojciech Kosior <kwojtus@protonmail.com> | 2020-11-21 21:35:54 +0100 |
commit | b44a3a201ee2b524f31aa93abfe4abd8b756a533 (patch) | |
tree | 3e51f9fa39e54139b913351d81fc0fe1cf299c53 /design/miscellaneous_slave.v | |
parent | 8999a1a82eddb97fa2d4aa7de12e88a3205d0e3d (diff) | |
download | AGH-engineering-thesis-b44a3a201ee2b524f31aa93abfe4abd8b756a533.tar.gz AGH-engineering-thesis-b44a3a201ee2b524f31aa93abfe4abd8b756a533.zip |
add miscellaneous module, which controls led2 and button2 and provides a timer; include a testbench for timer and led
Diffstat (limited to 'design/miscellaneous_slave.v')
-rw-r--r-- | design/miscellaneous_slave.v | 133 |
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 |