aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--design/miscellaneous_slave.v133
-rw-r--r--design/soc.v31
-rw-r--r--tests/soc_measure_time/Makefile8
-rw-r--r--tests/soc_measure_time/instructions.s.tcl57
-rw-r--r--tests/soc_measure_time/test.v82
5 files changed, 300 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 */
diff --git a/tests/soc_measure_time/Makefile b/tests/soc_measure_time/Makefile
new file mode 100644
index 0000000..3f76875
--- /dev/null
+++ b/tests/soc_measure_time/Makefile
@@ -0,0 +1,8 @@
+DEPENDS = instructions.mem sram.v vga_display.v flash_memory.v \
+ soc_with_peripherals.v ../../design/*.v messages.vh
+
+IVFLAGS = -DROM_WORDS_COUNT=$(call FILE_LINES,instructions.mem)
+
+TOP = soc_test
+
+include ../../Makefile.test
diff --git a/tests/soc_measure_time/instructions.s.tcl b/tests/soc_measure_time/instructions.s.tcl
new file mode 100644
index 0000000..b1f8511
--- /dev/null
+++ b/tests/soc_measure_time/instructions.s.tcl
@@ -0,0 +1,57 @@
+## also look at stack_machine_cond_jump test
+
+## we're going to write numbers from 0 to 639 at addresses h100000 to h1009FC
+## and then write non-zero value at h100A00
+
+# this will translate to 2 16-bit instructions
+set_sp h100000
+
+## load current value of timer, in a loop
+## this is address 4 we later jump to
+# this will translate to 2 16-bit instructions
+loadwzx h1C0008
+
+## loop until timer exceeds 500
+# this will translate to 2 16-bit instructions
+const 500
+# this will translate to 1 16-bit instruction
+lt
+# this will translate to 1 16-bit instruction
+cond_jump 4
+
+## now, light led2
+# this will translate to 1 16-bit instruction
+const 1
+# this will translate to 2 16-bit instructions
+storew h1C0006
+
+## second loop, analogous to the first one
+## this is address 22 we later jump to
+# this will translate to 2 16-bit instructions
+loadwzx h1C0008
+
+## loop until timer exceeds 1000
+# this will translate to 2 16-bit instructions
+const 1000
+# this will translate to 1 16-bit instruction
+lt
+# this will translate to 1 16-bit instruction
+cond_jump 22
+
+## now, switch led2 off
+# this will translate to 1 16-bit instruction
+const 0
+# this will translate to 2 16-bit instructions
+storew h1C0006
+
+## third loop, analogous to the first two
+## this is address 40 we later jump to
+loadwzx h1C0008
+
+## loop until timer exceeds 1500
+const 1500
+lt
+cond_jump 40
+
+## finish operation (will also put led1 on)
+halt
diff --git a/tests/soc_measure_time/test.v b/tests/soc_measure_time/test.v
new file mode 100644
index 0000000..b4f1082
--- /dev/null
+++ b/tests/soc_measure_time/test.v
@@ -0,0 +1,82 @@
+`default_nettype none
+`timescale 1ns/1ns
+
+`include "messages.vh"
+
+`ifndef SIMULATION
+ `error_SIMULATION_not_defined
+; /* Cause syntax error */
+`endif
+
+module soc_test();
+ wire [9:0] image_writes;
+
+ reg clock_100mhz;
+ reg reset;
+
+ wire led1;
+ wire led2;
+
+ soc_with_peripherals
+ #(
+ .FONT_FILE("../../design/font.mem"),
+ .EMBEDDED_ROM_FILE("instructions.mem")
+ ) soc
+ (
+ .clock_100mhz(clock_100mhz),
+
+ .button1(!reset),
+ .button2(1'b1),
+
+ .led1(led1),
+ .led2(led2),
+
+ .image_writes(image_writes)
+ );
+
+ integer i;
+ integer current_time;
+
+ initial begin
+ reset <= 1;
+ clock_100mhz <= 0;
+
+ for (i = 0; i < 25_000; i++) begin
+ #5;
+
+ if (clock_100mhz)
+ reset <= 0;
+
+ clock_100mhz <= ~clock_100mhz;
+
+ /*
+ * Soc's clock is 12.5 MHz. One tick of that clock takes 80 ns.
+ * This means 1000th, 2000th and 3000th ticks happen at
+ * 80_000, 160_000 and 240_000 ns, respectively.
+ */
+ current_time = $time;
+ if (current_time < 40_000) begin
+ if (!led2) begin
+ `MSG(("error: led2 on before 1000 timer ticks passed"));
+ $finish;
+ end
+ end
+ if (current_time > 50_000 && current_time < 80_000) begin
+ if (led2) begin
+ `MSG(("error: led2 not on, while it should be"));
+ $finish;
+ end
+ end
+ if (current_time > 130_000) begin
+ if (!led2) begin
+ `MSG(("error: led2 hasn't been switched off on time"));
+ $finish;
+ end
+ end
+ end // for (i = 0; i < 12_500; i++)
+
+ if (led1)
+ `MSG(("error: stack machine in soc hasn't finished working in 125us"));
+ $finish;
+ end // initial begin
+endmodule // soc_test