aboutsummaryrefslogtreecommitdiff
path: root/npm-shrinkwrap.json
AgeCommit message (Collapse)Author
2015-10-13upgrade yargs 3.5.4 -> 3.10.0Damian Krzeminski
we need a version with better support for 'array' params see: https://github.com/bcoe/yargs/pull/164
2015-10-07Pin dependencies with npm shrinkwrapSpainTrain
* Use `npm run shrinkwrap` to create a shrinkwrap file with all dependencies pinned * Update dependency `source-map` to latest (Closes #738)
>-rw-r--r--Makefile127
-rw-r--r--README.txt94
-rw-r--r--design/div.v70
-rw-r--r--design/font.mem1795
-rw-r--r--design/intercon.v142
-rw-r--r--design/stack_machine.v353
-rw-r--r--design/vga.v241
-rw-r--r--include/macroasm.vh33
-rw-r--r--include/messages.vh18
-rw-r--r--models/master.v223
-rw-r--r--models/slave.v146
-rw-r--r--models/vga_display.v203
-rw-r--r--src/Makefile21
-rw-r--r--src/example.v1226
-rw-r--r--src/letter_A.pngbin201 -> 0 bytes-rw-r--r--src/letter_B.pngbin200 -> 0 bytes-rw-r--r--src/letter_C.pngbin202 -> 0 bytes-rw-r--r--src/letter_D.pngbin206 -> 0 bytes-rw-r--r--src/letter_E.pngbin186 -> 0 bytes-rw-r--r--src/letter_F.pngbin184 -> 0 bytes-rw-r--r--src/mapping.pcf62
-rw-r--r--src/number_0.pngbin211 -> 0 bytes-rw-r--r--src/number_1.pngbin184 -> 0 bytes-rw-r--r--src/number_2.pngbin208 -> 0 bytes-rw-r--r--src/number_3.pngbin212 -> 0 bytes-rw-r--r--src/number_4.pngbin198 -> 0 bytes-rw-r--r--src/number_5.pngbin209 -> 0 bytes-rw-r--r--src/number_6.pngbin210 -> 0 bytes-rw-r--r--src/number_7.pngbin205 -> 0 bytes-rw-r--r--src/number_8.pngbin202 -> 0 bytes-rw-r--r--src/number_9.pngbin212 -> 0 bytes-rwxr-xr-xtclasm.tcl337
-rw-r--r--tests/div/test.v108
-rw-r--r--tests/intercon/operations.memv63
-rw-r--r--tests/intercon/test.v216
-rw-r--r--tests/self/operations.memv25
-rw-r--r--tests/self/test.v114
-rwxr-xr-xtests/stack_machine_add/instructions.s.tcl20
l---------tests/stack_machine_add/test.v1
-rw-r--r--tests/stack_machine_add/words_to_verify.mem9
-rwxr-xr-xtests/stack_machine_div/instructions.s.tcl23
l---------tests/stack_machine_div/test.v1
-rw-r--r--tests/stack_machine_div/words_to_verify.mem12
-rwxr-xr-xtests/stack_machine_load_store/instructions.s.tcl109
l---------tests/stack_machine_load_store/test.v1
-rw-r--r--tests/stack_machine_load_store/words_to_verify.mem12
-rwxr-xr-xtests/stack_machine_mul/instructions.s.tcl42
l---------tests/stack_machine_mul/test.v1
-rw-r--r--tests/stack_machine_mul/words_to_verify.mem19
-rwxr-xr-xtests/stack_machine_multiinstructions_load_store/instructions.s.tcl32
l---------tests/stack_machine_multiinstructions_load_store/test.v1
l---------tests/stack_machine_multiinstructions_load_store/words_to_verify.mem1
-rwxr-xr-xtests/stack_machine_store/instructions.s.tcl29
-rw-r--r--tests/stack_machine_store/test.v148
-rw-r--r--tests/stack_machine_store/words_to_verify.mem3
-rwxr-xr-xtests/stack_machine_sub/instructions.s.tcl21
l---------tests/stack_machine_sub/test.v1
-rw-r--r--tests/stack_machine_sub/words_to_verify.mem9
-rw-r--r--tests/vga/VGAdump_expected.ppm38403
-rw-r--r--tests/vga/test.v252
-rw-r--r--tools/VGAdump2ppm.c45
61 files changed, 43501 insertions, 1311 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..21346c7
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,127 @@
+CC = gcc
+CFLAGS = -std=c89 -pedantic -Wall -Werror -O2
+
+IV = iverilog
+
+IVFLAGS = -Iinclude/ -DSIMULATION
+# The macroassembly header file is somewhat different thing, but I don't know
+# what place would be more suitable for it than include/ dir
+MACROASM_FLAGS := -Iinclude/ -E
+
+# It made sense to just list all of those in this variable
+# and then prepend stack_machine_ to each element
+STACK_MACHINE_TESTS := \
+ store \
+ load_store \
+ multiinstructions_load_store \
+ add \
+ sub \
+ div \
+ mul
+
+# Add other tests here if You need
+TESTS := \
+ self \
+ intercon \
+ div \
+ vga \
+ $(addprefix stack_machine_,$(STACK_MACHINE_TESTS))
+
+# For each of these Makefile will attempt to generate VGAdump.ppm
+# and compare it to VGAdump_expected.ppm inside that test's directory
+TESTS_WITH_VGA := vga
+
+# Short C programs
+TOOLS := VGAdump2ppm
+
+ifdef DEBUG
+IVFLAGS += -DDEBUG
+DBG&SAVE = tee "$(1)"
+else
+DBG&SAVE = cat > "$(1)" # putting cat through pipe - what an animal cruelty!
+endif
+
+TEST_TARGETS := $(addprefix test_,$(TESTS))
+VGA_TEST_TARGETS := $(addprefix test_,$(TESTS_WITH_VGA))
+
+TEST_LOGS := $(foreach TEST,$(TESTS),tests/$(TEST)/report.log)
+
+TOOLS_TARGETS := $(addprefix tools/,$(TOOLS))
+
+GENERATED_MEM_FILES := $(shell find tests/ -name "*.s.tcl")
+GENERATED_MEM_FILES := $(basename $(basename $(GENERATED_MEM_FILES)))
+GENERATED_MEM_FILES += $(basename $(shell find tests/ -name "*.memv"))
+GENERATED_MEM_FILES := $(addsuffix .mem,$(GENERATED_MEM_FILES))
+
+# TODO: check if this function can be changed to use $(shell grep ...)
+FILE_LINES = `grep -E '^[[:space:]]*[^[:space:]/]' -c $(1)`
+
+test : $(TEST_TARGETS)
+
+tests/%.mem : tests/%.memv
+ $(IV) $(MACROASM_FLAGS) $^ -o $@
+
+tests/%.mem : tests/%.s.tcl tclasm.tcl
+ $< > $@
+
+tests/self/test.vvp : tests/self/operations.mem tests/self/test.v \
+ models/slave.v models/master.v include/messages.vh
+ $(IV) $(IVFLAGS) -s self_test \
+ -DMASTER_OPERATIONS_COUNT=$(call FILE_LINES,$<) \
+ $(filter %.v,$^) -o $@
+
+tests/intercon/test.vvp : tests/intercon/operations.mem tests/intercon/test.v \
+ models/slave.v models/master.v design/intercon.v \
+ include/messages.vh
+ $(IV) $(IVFLAGS) -s intercon_test \
+ -DMASTER_OPERATIONS_COUNT=$(call FILE_LINES,$<) \
+ $(filter %.v,$^) -o $@
+
+tests/div/test.vvp : tests/div/test.v design/div.v include/messages.vh
+ $(IV) $(IVFLAGS) -s div_test $(filter %.v,$^) -o $@
+
+tests/vga/test.vvp : tests/vga/test.v design/vga.v models/vga_display.v \
+ include/messages.vh
+ $(IV) $(IVFLAGS) -s vga_test $^ -o $@
+
+tests/stack_machine_%/test.vvp : tests/stack_machine_%/instructions.mem \
+ tests/stack_machine_%/words_to_verify.mem \
+ tests/stack_machine_%/test.v models/slave.v \
+ design/stack_machine.v design/div.v include/messages.vh
+ $(IV) $(IVFLAGS) -s stack_machine_test \
+ -DINSTRUCTIONS_COUNT=$(call FILE_LINES,$<) \
+ -DWORDS_TO_VERIFY_COUNT=$(call FILE_LINES,$(filter %fy.mem,$^)) \
+ $(filter %.v,$^) -o $@
+
+
+$(foreach TEST,$(TESTS_WITH_VGA),tests/$(TEST)/report.log) \
+$(foreach TEST,$(TESTS_WITH_VGA),tests/$(TEST)/VGAdump.ppm) : design/font.mem
+
+tests/%/VGAdump.mem tests/%/report.log : tests/%/test.vvp
+ cd $(dir $<) && vvp $(notdir $<) | $(call DBG&SAVE,report.log)
+
+tests/%/VGAdump.ppm : tests/%/VGAdump.mem tools/VGAdump2ppm
+ grep -v // < $< | ./tools/VGAdump2ppm > $@
+
+$(VGA_TEST_TARGETS) : test_% : tests/%/VGAdump_expected.ppm tests/%/VGAdump.ppm
+$(TEST_TARGETS) : test_% : tests/%/report.log
+ if grep error $<; then false; fi
+ if [ "$(filter $@,$(VGA_TEST_TARGETS))" != "" ]; then \
+ diff $(dir $<)VGAdump.ppm $(dir $<)VGAdump_expected.ppm; \
+ fi
+
+tools : $(TOOLS_TARGETS)
+
+$(TOOLS_TARGETS) : tools/% : tools/%.c
+ $(CC) $(CFLAGS) $^ -o $@
+
+clean :
+ -find tests/ -name "*.vvp" -delete
+ -find tests/ -name "*.log" -delete
+ -find tests/ -name "VGAdump.mem" -delete
+ -find tests/ -name "VGAdump.ppm" -delete
+ -rm $(GENERATED_MEM_FILES)
+ -rm tests
+ -rm $(TOOLS_TARGETS)
+
+.PHONY : tools test $(TEST_TARGETS)
diff --git a/README.txt b/README.txt
index 976a54a..e887b47 100644
--- a/README.txt
+++ b/README.txt
@@ -1,2 +1,92 @@
-This repository shall contain the the code for 'Laboratory station based on programmable logic device for WebAssembly execution evaluation' developed as my engineering thesis at AGH University of Science and Technology in Cracov, Poland.
-The project is going to utilize the Verilog HDL. Icarus Verilog Simulator shall be used for simulation and test benches, while Yosys, arachne-pnr/nextpnr and icestorm are the tools chosen for synthesis, p&r and bitstream generation for Olimex's iCE40HX8K-EVB FPGA.
+## About
+This repository shall contain the the code for 'Laboratory station based on
+programmable logic device for WebAssembly execution evaluation' developed as my
+engineering thesis at AGH University of Science and Technology in Cracov,
+Poland.
+
+The project utilizes Verilog HDL. Icarus Verilog Simulator is used for
+simulation and test benches, while Yosys, arachne-pnr/nextpnr and icestorm are
+the tools chosen for synthesis, p&r and bitstream generation for Olimex's
+iCE40HX8K-EVB FPGA.
+
+## Technical choices
+I'm using one of few FPGAs with fully libre toolchain. SystemVerilog and VHDL
+are not yet (officially) supported in Yosys, so I'm using Verilog2005.
+
+I'm writing my own stack machine CPU for the job. Another option would be to
+run an existing register-based CPU (picorv32?) on the FPGA and interpret Wasm
+on it. Despite my thesis' topis is broad anough it would allow that, I didn't
+go this way, because:
+ - there'd be nothing innovative in this approach,
+ - I'd end up mostly copying other's code, ending up with a copy-paster's
+ thesis...
+
+I'm trying to use Wishbone pipelined interconnect for CPU and other components,
+but right now I'm not yet claiming compatibility (at some point I will add
+those datasheets...).
+
+WebAsm binary format was not designed for direct execution, so I'm instead
+creating a minimal stack machine, that would allow almost 1:1 translation of
+Wasm code to it's own instruction format. I still think it's possible to make
+a CPU, that would execute Wasm directly - it's just matter of a bit more
+effort. Right now I'm not describing the instruction format of my stack
+machine, because it is likely to change.
+
+The stack machine is and will be limited. That's why some more complex Wasm
+instructions (e.g. 64-bit operations, maybe float operations) have to be
+replaced with calls to software routines.
+
+The goal is to write some minimal "bootloader", that would translate Wasm
+to my stack machine's instructions on-device.
+
+The SPI chip on iCE40HX8K-EVB is 2MB big. The configuration stored on it is
+below 137KB. I'm going to use the remaining memory to store the actual Wasm
+code for execution.
+
+The initial booting code will be preloaded to embedded RAM (iCE40HX8K has such
+feature and Yosys supports it).
+
+I'm using VGA (640x480@60Hz) with self-created text mode for communicating to
+the outside. UART is also planned.
+
+I wrote an assembly for my stack machine (tclasm.tcl). The actual assembly
+instructions are expressed in terms of tcl command executions, so we could call
+it pseudo-assembly. Before embracing tcl, I needed a way to express memory
+reads and writes for some test benches and created a simple macroassembly
+(include/macroasm.vh). I probably should have used tcl from the beginning...
+
+Everything is done through a (rather complex) Makefile.
+
+## Project structure
+ - Makefile - needs no explaination...
+ - design/ - Verilog sources, that will get synthesized for FPGA
+ - models/ - Verilog modules used in testing
+ - tests/ - benches, each in its own subdirectory
+ - include/ - Verilog header files for inclusion
+ - tools/ - small C programs
+ - COPYING - 0BSD license
+ - README.txt - You're reading it
+
+## Project status
+I'm a huge bit delayed with the work (should have had a working prototype in
+June...), but I'm working on it.
+
+I had a previous approach to the problem in July. Work was going extremely
+slowly and I felt, that my code was really bad. This is also because I haven't
+had any serious hardware design experience before. Now, I started anew. My
+current approach is less CISCy. I'm also doing everything in the simulator,
+with test benches for every module and plans to get it to run on the FPGA once
+the design is able to display something through VGA. That's different from my
+previous approach, where I was trying to make something run on the board and
+then write tests for it. I'm now determined to use Wishbone, because I believe
+it helps me keep the design clean.
+
+My stack machine is currently able to do some operations like memory accesses,
+addition and unsigned division, but it's not yet ready to have Wasm translated
+for it. I'm also thinking about radically changing its design...
+
+### Thoughts
+It's indeed an interesting project, but from practical point of view - it's
+still going to be more efficient to JIT-compile Wasm on a register-based
+architecture... Perhaps it'd be more useful to optimize an exisiting processor
+(OpenRISC, OpenSPARC, RiscV) for that?
diff --git a/design/div.v b/design/div.v
new file mode 100644
index 0000000..10db627
--- /dev/null
+++ b/design/div.v
@@ -0,0 +1,70 @@
+`default_nettype none
+
+module div
+ #(
+ parameter WIDTH = 16
+ )
+ (
+ input wire clock,
+ input wire start,
+
+ input wire [WIDTH-1 : 0] dividend,
+ input wire [WIDTH-1 : 0] divisor,
+
+ output wire [WIDTH-1 : 0] quotient,
+ output wire [WIDTH-1 : 0] remainder,
+
+ output wire done
+ );
+
+ reg [$clog2(WIDTH)-1 : 0] steps;
+ reg [2*WIDTH : 0] work_reg;
+ reg [WIDTH-1 : 0] divisor_latched;
+
+ wire [WIDTH+1 : 0] work_remainder;
+ wire work_remainder_sign;
+ assign work_remainder = work_reg[2*WIDTH : WIDTH-1];
+ assign work_remainder_sign = work_remainder[WIDTH + 1];
+
+ /*
+ * The following variable represents quotient using digits 1 and -1,
+ * where -1 is internally represented as 0
+ */
+`define MINUS_ONE 1'b0
+`define PLUS_ONE 1'b1
+
+ wire [WIDTH-1 : 0] work_quotient;
+ assign work_quotient = work_reg[WIDTH-1 : 0];
+
+ reg work_quotient_ready;
+
+ always @ (posedge clock) begin
+ if (start) begin
+ steps <= WIDTH - 1;
+ work_reg <= dividend;
+ divisor_latched <= divisor;
+ work_quotient_ready <= 0;
+ end else begin
+ if (steps)
+ steps <= steps - 1;
+ else
+ work_quotient_ready <= 1;
+
+ if (!work_quotient_ready) begin
+ work_reg[WIDTH-1 : 1] <= work_reg[WIDTH-2 : 0];
+
+ if (work_remainder_sign) begin /* work remainder negative */
+ work_reg[0] <= `MINUS_ONE; /* Filling up quotient */
+ work_reg[2*WIDTH : WIDTH] <= work_remainder + divisor_latched;
+ end else begin /* work remainder equal 0 or positive */
+ work_reg[0] <= `PLUS_ONE; /* Filling up quotient */
+ work_reg[2*WIDTH : WIDTH] <= work_remainder - divisor_latched;
+ end
+ end
+ end
+ end // always @ (posedge clock)
+
+ assign quotient = work_quotient - ~work_quotient - work_remainder_sign;
+ assign remainder = (work_remainder >> 1) + (work_remainder_sign ? divisor_latched : 0);
+ assign done = work_quotient_ready && !start;
+endmodule // div
diff --git a/design/font.mem b/design/font.mem
new file mode 100644
index 0000000..5e62f0e
--- /dev/null
+++ b/design/font.mem
@@ -0,0 +1,1795 @@
+// all characters, that are not displayed, are shown as space
+
+// ASCII 0 - NULL (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 1 - SOH (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 2 - STX (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 3 - ETX (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 4 - EOT (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 5 - ENQ (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 6 - ACK (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 7 - BEL '\a' (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 8 - BS '\b' (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 9 - HT '\t' (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 10 - LF '\n' (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 11 - VT '\v' (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 12 - FF '\f' (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 13 - CR '\r' (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 14 - SO (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 15 - SI (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 16 - DLE (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 17 - DC1 (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 18 - DC2 (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 19 - DC3 (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 20 - DC4 (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 21 - NAK (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 22 - SYN (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 23 - ETB (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 24 - CAN (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 25 - EM (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 26 - SUB (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 27 - ESC (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 28 - FS (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 29 - GS (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 30 - US (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 31 - RS (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 32 - SPACE
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+
+// ASCII 33 - !
+00000000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00000000
+00000000
+00001000
+00001000
+00000000
+
+// ASCII 34 - "
+00000000
+00010100
+00010100
+00010100
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+// ASCII 35 - #
+00000000
+00010010
+00010010
+00010010
+00100100
+01111110
+00100100
+00100100
+00100100
+00100100
+01111110
+00100100
+01001000
+01001000
+01001000
+00000000
+
+// ASCII 36 - $
+00000000
+00001000
+00011100
+00101010
+01001000
+01001000
+00101000
+00011000
+00001100
+00001010
+00001010
+00001010
+01001010
+00111100
+00001000
+00000000
+
+// ASCII 37 - %
+00000000
+00000000
+00100010
+01010010
+00100100
+00000100
+00001000
+00001000
+00010000
+00010000
+00100000
+00100100
+01001010
+01000100
+00000000
+00000000
+
+// ASCII 38 - &
+00000000
+00110000
+01001000
+01001000
+01001000
+01001000
+00110000
+00110000
+00010000
+00101000
+00101000
+01000100
+01000110
+01000100
+00111010
+00000000
+
+// ASCII 39 - '
+00000000
+00001000
+00001000
+00001000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+// ASCII 40 - (
+00000000
+00000100
+00001000
+00001000
+00001000
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00001000
+00001000
+00001000
+00000100
+00000000
+
+// ASCII 41 - )
+00000000
+00100000
+00010000
+00010000
+00010000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00010000
+00010000
+00010000
+00100000
+00000000
+
+// ASCII 42 - *
+00000000
+00101010
+00011100
+00101010
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+// ASCII 43 - +
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00001000
+00001000
+00111110
+00001000
+00001000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+// ASCII 44 - ,
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00001000
+00001000
+00110000
+00000000
+
+// ASCII 45 - -
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+01111110
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+// ASCII 46 - .
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00001000
+00001000
+00000000
+00000000
+
+// ASCII 47 - /
+00000000
+00000010
+00000010
+00000100
+00000100
+00000100
+00001000
+00001000
+00010000
+00010000
+00100000
+00100000
+00100000
+01000000
+01000000
+00000000
+
+// ASCII 48 - 0
+00000000
+00011000
+00100100
+00100100
+01000110
+01001010
+01001010
+01001010
+01010010
+01010010
+01010010
+01100010
+00100100
+00100100
+00011000
+00000000
+
+// ASCII 49 - 1
+00000000
+00001000
+00011000
+00111000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00000000
+
+// ASCII 50 - 2
+00000000
+00111000
+01000100
+00000010
+00000010
+00000010
+00000010
+00000100
+00001000
+00010000
+00100000
+00100000
+01000000
+01000000
+01111110
+00000000
+
+// ASCII 51 - 3
+00000000
+00111000
+01000100
+00000010
+00000010
+00000010
+00000100
+00011000
+00000100
+00000010
+00000010
+00000010
+00000010
+01000100
+00111000
+00000000
+
+// ASCII 52 - 4
+00000000
+00001000
+00001000
+00010000
+00010000
+00100000
+00100000
+01000100
+01111110
+00000100
+00000100
+00000100
+00000100
+00000100
+00000100
+00000000
+
+// ASCII 53 - 5
+00000000
+01111100
+01000000
+01000000
+01000000
+01000000
+01111000
+00000100
+00000010
+00000010
+00000010
+00000010
+00000010
+01000100
+00111000
+00000000
+
+// ASCII 54 - 6
+00000000
+00001100
+00010000
+00100000
+00100000
+01000000
+01000000
+01011000
+01100100
+01000010
+01000010
+01000010
+01000010
+00100100
+00011000
+00000000
+
+// ASCII 55 - 7
+00000000
+01111110
+00000010
+00000100
+00000100
+00001000
+00001000
+00111100
+00010000
+00010000
+00010000
+00100000
+00100000
+00100000
+00100000
+00000000
+
+// ASCII 56 - 8
+00000000
+00011000
+00100100
+01000010
+01000010
+01000010
+00100100
+00011000
+00100100
+01000010
+01000010
+01000010
+01000010
+00100100
+00011000
+00000000
+
+// ASCII 57 - 9
+00000000
+00011000
+00100100
+01000010
+01000010
+01000010
+01000010
+00100110
+00011010
+00000010
+00000010
+00000100
+00000100
+00001000
+00110000
+00000000
+
+// ASCII 58 - :
+00000000
+00000000
+00000000
+00000000
+00001000
+00001000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00001000
+00001000
+00000000
+00000000
+
+// ASCII 59 - ;
+00000000
+00000000
+00000000
+00000000
+00001000
+00001000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00001000
+00001000
+00110000
+00000000
+
+// ASCII 60 - <
+00000000
+00000000
+00000000
+00000010
+00000100
+00001000
+00010000
+00100000
+01000000
+00100000
+00010000
+00001000
+00000100
+00000010
+00000000
+00000000
+
+// ASCII 61 - =
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+01111110
+00000000
+00000000
+01111110
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+// ASCII 62 - >
+00000000
+00000000
+00000000
+01000000
+00100000
+00010000
+00001000
+00000100
+00000010
+00000100
+00001000
+00010000
+00100000
+01000000
+00000000
+00000000
+
+// ASCII 63 - ?
+00000000
+00111100
+01000010
+00000010
+00000010
+00000100
+00001000
+00001000
+00001000
+00001000
+00000000
+00000000
+00001000
+00001000
+00000000
+00000000
+
+// ASCII 64 - @
+00000000
+00000000
+00011000
+00100100
+01000010
+01000010
+01001110
+01010010
+01010010
+01010010
+01010010
+01011110
+01000000
+01000000
+00111100
+00000000
+
+// ASCII 65 - A
+00000000
+00011000
+00100100
+00100100
+00100100
+01000010
+01000010
+01000010
+01111110
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+00000000
+
+// ASCII 66 - B
+00000000
+01111000
+01000100
+01000010
+01000010
+01000010
+01000100
+01111000
+01000100
+01000010
+01000010
+01000010
+01000010
+01000100
+01111000
+00000000
+
+// ASCII 67 - C
+00000000
+00011100
+00100010
+00100000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+00100000
+00100010
+00011100
+00000000
+
+// ASCII 68 - D
+00000000
+01110000
+01001000
+01000100
+01000100
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000100
+01000100
+01001000
+01110000
+00000000
+
+// ASCII 69 - E
+00000000
+01111110
+01000000
+01000000
+01000000
+01000000
+01000000
+01111000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01111110
+00000000
+
+// ASCII 70 - F
+00000000
+01111110
+01000000
+01000000
+01000000
+01000000
+01000000
+01111000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+00000000
+
+// ASCII 71 - G
+00000000
+00011100
+00100010
+00100000
+01000000
+01000000
+01000000
+01000000
+01001110
+01000010
+01000010
+01000010
+00100010
+00100010
+00011110
+00000000
+
+// ASCII 72 - H
+00000000
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01111110
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+00000000
+
+// ASCII 73 - I
+00000000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00000000
+
+// ASCII 74 - J
+00000000
+00011110
+00000010
+00000010
+00000010
+00000010
+00000010
+00000010
+00000010
+00000010
+00000010
+00000010
+00000010
+01000010
+00111100
+00000000
+
+// ASCII 75 - K
+00000000
+01000010
+01000100
+01000100
+01001000
+01001000
+01010000
+01010000
+01110000
+01001000
+01001000
+01000100
+01000100
+01000010
+01000010
+00000000
+
+// ASCII 76 - L
+00000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01111110
+00000000
+
+// ASCII 77 - M
+00000000
+01000010
+01000010
+01100110
+01011010
+01001010
+01001010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+00000000
+
+// ASCII 78 - N
+00000000
+01000010
+01100010
+01100010
+01010010
+01010010
+01010010
+01010010
+01001010
+01001010
+01001010
+01001010
+01000110
+01000110
+01000010
+00000000
+
+// ASCII 79 - O
+00000000
+00011000
+00100100
+00100100
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+00100100
+00100100
+00011000
+00000000
+
+// ASCII 80 - P
+00000000
+01111000
+01000100
+01000010
+01000010
+01000010
+01000100
+01111000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+00000000
+
+// ASCII 81 - Q
+00000000
+00011000
+00100100
+00100100
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01001010
+00101100
+00100100
+00011010
+00000000
+
+// ASCII 82 - R
+00000000
+01111000
+01000100
+01000010
+01000010
+01000010
+01000100
+01111000
+01001000
+01000100
+01000100
+01000100
+01000010
+01000010
+01000010
+00000000
+
+// ASCII 83 - S
+00000000
+00011100
+00100010
+01000000
+01000000
+01000000
+00100000
+00010000
+00001000
+00000100
+00000010
+00000010
+00000010
+01000010
+00111100
+00000000
+
+// ASCII 84 - T
+00000000
+00111110
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00000000
+
+// ASCII 85 - U
+00000000
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+00111100
+00000000
+
+// ASCII 86 - V
+00000000
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+00100100
+00100100
+00100100
+00100100
+00100100
+00011000
+00011000
+00000000
+
+// ASCII 87 - W
+00000000
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01000010
+01001010
+01001010
+01001010
+01011010
+00100100
+00100100
+00100100
+00000000
+
+// ASCII 88 - X
+00000000
+01000010
+01000010
+00100100
+00100100
+00100100
+00011000
+00011000
+00011000
+00011000
+00100100
+00100100
+00100100
+01000010
+01000010
+00000000
+
+// ASCII 89 - Y
+00000000
+00100010
+00100010
+00100010
+00010100
+00010100
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00000000
+
+// ASCII 90 - Z
+00000000
+01111110
+00000010
+00000010
+00000100
+00000100
+00001000
+00001000
+00010000
+00010000
+00100000
+00100000
+01000000
+01000000
+01111110
+00000000
+
+// ASCII 91 - [
+00000000
+00011100
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00011100
+00000000
+
+// ASCII 92 - \
+00000000
+01000000
+01000000
+00100000
+00100000
+00100000
+00010000
+00010000
+00001000
+00001000
+00000100
+00000100
+00000100
+00000010
+00000010
+00000000
+
+// ASCII 93 - ]
+00000000
+00111000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00111000
+00000000
+
+// ASCII 94 - ^
+00000000
+00011000
+00100100
+01000010
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+// ASCII 95 - _
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+01111110
+00000000
+
+// ASCII 96 - `
+00000000
+00110000
+00001100
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+// ASCII 97 - a
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00111100
+01000010
+00000010
+00011110
+00100010
+01000010
+01000110
+00111010
+00000000
+
+// ASCII 98 - b
+00000000
+00000000
+00000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01011100
+01100010
+01000010
+01000010
+01100010
+01011100
+00000000
+
+// ASCII 99 - c
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00111100
+01000010
+01000000
+01000000
+01000010
+00111100
+00000000
+
+// ASCII 100 - d
+00000000
+00000000
+00000000
+00000010
+00000010
+00000010
+00000010
+00000010
+00000010
+00111010
+01000110
+01000010
+01000010
+01000110
+00111010
+00000000
+
+// ASCII 101 - e
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00111100
+01000010
+01111110
+01000000
+01000010
+00111100
+00000000
+
+// ASCII 102 - f
+00000000
+00000000
+00000000
+00001100
+00010000
+00010000
+00010000
+00111100
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00000000
+
+// ASCII 103 - g
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00111010
+01000110
+01000010
+01000110
+00111010
+00000010
+00000010
+00111100
+00000000
+
+// ASCII 104 - h
+00000000
+00000000
+00000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01111100
+01000010
+01000010
+01000010
+01000010
+00000000
+
+// ASCII 105 - i
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00001000
+00001000
+00000000
+00001000
+00001000
+00001000
+00001000
+00001000
+00000000
+
+// ASCII 106 - j
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00001000
+00001000
+00000000
+00111000
+00001000
+00001000
+00001000
+00110000
+00000000
+
+// ASCII 107 - k
+00000000
+00000000
+00000000
+01000000
+01000000
+01000000
+01000100
+01001000
+01010000
+01100000
+01010000
+01010000
+01001000
+01001000
+01000100
+00000000
+
+// ASCII 108 - l
+00000000
+00000000
+00000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01000000
+00110000
+00000000
+
+// ASCII 109 - m
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+01100100
+01011010
+01011010
+01011010
+01011010
+01011010
+00000000
+
+// ASCII 110 - n
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+01011100
+01100010
+01000010
+01000010
+01000010
+00000000
+
+// ASCII 111 - o
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00111100
+01000010
+01000010
+01000010
+01000010
+00111100
+00000000
+
+// ASCII 112 - p
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+01011100
+01100010
+01000010
+01000010
+01100010
+01011100
+01000000
+01000000
+00000000
+
+// ASCII 113 - q
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00111010
+01000110
+01000010
+01000010
+01000110
+00111010
+00000010
+00000010
+00000000
+
+// ASCII 114 - r
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00101100
+00110000
+00100000
+00100000
+00100000
+00100000
+00100000
+00000000
+
+// ASCII 115 - s
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00111100
+01000010
+01000000
+00111100
+00000010
+01000010
+00111100
+00000000
+
+// ASCII 116 - t
+00000000
+00000000
+00000000
+00100000
+00100000
+01111000
+00100000
+00100000
+00100000
+00100000
+00100000
+00100000
+00100000
+00100000
+00011000
+00000000
+
+// ASCII 117 - u
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+01000010
+01000010
+01000010
+01000010
+01000110
+00111010
+00000000
+
+// ASCII 118 - v
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+01000010
+01000010
+00100100
+00100100
+00011000
+00011000
+00000000
+
+// ASCII 119 - w
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+01000010
+01000010
+01011010
+01011010
+00100100
+00100100
+00000000
+
+// ASCII 120 - x
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+01000010
+00100100
+00011000
+00011000
+00100100
+01000010
+00000000
+
+// ASCII 121 - y
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00100010
+00100010
+00010010
+00001100
+00001000
+00110000
+00000000
+
+// ASCII 122 - z
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+01111110
+00000100
+00001000
+00010000
+00100000
+01111110
+00000000
+
+// ASCII 123 - {
+00000000
+00001100
+00010000
+00010000
+00010000
+00010000
+00010000
+00100000
+00100000
+00010000
+00010000
+00010000
+00010000
+00010000
+00001100
+00000000
+
+// ASCII 123 - |
+00000000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00000000
+00000000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00000000
+
+// ASCII 124 - }
+00000000
+00110000
+00001000
+00001000
+00001000
+00001000
+00001000
+00000100
+00000100
+00001000
+00001000
+00001000
+00001000
+00001000
+00110000
+00000000
+
+// ASCII 125 - ~
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00110010
+01001100
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+// ASCII 127 - DEL (not displayed)
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/design/intercon.v b/design/intercon.v
new file mode 100644
index 0000000..bf908af
--- /dev/null
+++ b/design/intercon.v
@@ -0,0 +1,142 @@
+`default_nettype none
+
+module intercon
+ (
+ input wire CLK,
+ input wire RST,
+
+ input wire S0_ACK_O,
+ output wire S0_CLK_I,
+ output wire [17:0] S0_ADR_I,
+ output wire [15:0] S0_DAT_I,
+ input wire [15:0] S0_DAT_O,
+ output wire S0_RST_I,
+ output wire S0_STB_I,
+ output wire S0_WE_I,
+ input wire S0_STALL_O,
+
+ input wire S1_ACK_O,
+ output wire S1_CLK_I,
+ output wire [17:0] S1_ADR_I,
+ output wire [15:0] S1_DAT_I,
+ input wire [15:0] S1_DAT_O,
+ output wire S1_RST_I,
+ output wire S1_STB_I,
+ output wire S1_WE_I,
+ input wire S1_STALL_O,
+
+ input wire S2_ACK_O,
+ output wire S2_CLK_I,
+ output wire [17:0] S2_ADR_I,
+ output wire [15:0] S2_DAT_I,
+ input wire [15:0] S2_DAT_O,
+ output wire S2_RST_I,
+ output wire S2_STB_I,
+ output wire S2_WE_I,
+ input wire S2_STALL_O,
+
+ input wire S3_ACK_O,
+ output wire S3_CLK_I,
+ output wire [17:0] S3_ADR_I,
+ output wire [15:0] S3_DAT_I,
+ input wire [15:0] S3_DAT_O,
+ output wire S3_RST_I,
+ output wire S3_STB_I,
+ output wire S3_WE_I,
+ input wire S3_STALL_O,
+
+ output wire M_ACK_I,
+ output wire M_CLK_I,
+ input wire [19:0] M_ADR_O,
+ input wire [15:0] M_DAT_O,
+ output wire [15:0] M_DAT_I,
+ output wire M_RST_I,
+ input wire M_STB_O,
+ input wire M_CYC_O,
+ input wire M_WE_O,
+ output wire M_STALL_I
+ );
+
+ wire [0:3] acks;
+ wire [0:3] stalls;
+ wire [15:0] datas [0:3];
+ assign acks = {S0_ACK_O, S1_ACK_O, S2_ACK_O, S3_ACK_O};
+ assign stalls = {S0_STALL_O, S1_STALL_O, S2_STALL_O, S3_STALL_O};
+ assign datas[0] = S0_DAT_O;
+ assign datas[1] = S1_DAT_O;
+ assign datas[2] = S2_DAT_O;
+ assign datas[3] = S3_DAT_O;
+
+ reg [1:0] commands_awaiting;
+ reg [1:0] slave_last_accessed;
+
+ wire operation_requested;
+ wire working;
+ wire [1:0] slave_accessed;
+ wire slave_switch;
+ wire [1:0] commands_awaiting_next_tick;
+ assign operation_requested = M_STB_O && M_CYC_O;
+ assign working = commands_awaiting || operation_requested;
+ assign slave_accessed = commands_awaiting ? slave_last_accessed :
+ M_ADR_O[19:18];
+ assign M_ACK_I = acks[slave_accessed] && working;
+ assign M_DAT_I = datas[slave_accessed];
+ assign slave_switch = slave_accessed != M_ADR_O[19:18];
+ assign M_STALL_I = stalls[slave_accessed] || slave_switch ||
+ (commands_awaiting == 3 && !M_ACK_I);
+ assign commands_awaiting_next_tick
+ = commands_awaiting - M_ACK_I + (operation_requested && !M_STALL_I);
+
+`ifdef SIMULATION
+ /* anything could be latched here, this is just to avoid undefined values */
+ initial begin
+ slave_last_accessed <= 0;
+ commands_awaiting <= 2; /* It is supposed to be driven low by RST */
+ end
+`endif
+
+ always @ (posedge CLK) begin
+ slave_last_accessed <= slave_accessed;
+
+ if (RST)
+ commands_awaiting <= 0;
+ else
+ commands_awaiting <= commands_awaiting_next_tick;
+ end
+
+ assign S0_CLK_I = CLK;
+ assign S1_CLK_I = CLK;
+ assign S2_CLK_I = CLK;
+ assign S3_CLK_I = CLK;
+ assign M_CLK_I = CLK;
+
+ assign S0_RST_I = RST;
+ assign S1_RST_I = RST;
+ assign S2_RST_I = RST;
+ assign S3_RST_I = RST;
+ assign M_RST_I = RST;
+
+ assign S0_ADR_I = M_ADR_O[17:0];
+ assign S1_ADR_I = M_ADR_O[17:0];
+ assign S2_ADR_I = M_ADR_O[17:0];
+ assign S3_ADR_I = M_ADR_O[17:0];
+
+ assign S0_DAT_I = M_DAT_O;
+ assign S1_DAT_I = M_DAT_O;
+ assign S2_DAT_I = M_DAT_O;
+ assign S3_DAT_I = M_DAT_O;
+
+ wire pass_strobe;
+ assign pass_strobe = operation_requested && !slave_switch &&
+ (commands_awaiting != 3 || M_ACK_I);
+
+ assign S0_STB_I = slave_accessed == 0 && pass_strobe;
+ assign S1_STB_I = slave_accessed == 1 && pass_strobe;
+ assign S2_STB_I = slave_accessed == 2 && pass_strobe;
+ assign S3_STB_I = slave_accessed == 3 && pass_strobe;
+
+ assign S0_WE_I = M_WE_O;
+ assign S1_WE_I = M_WE_O;
+ assign S2_WE_I = M_WE_O;
+ assign S3_WE_I = M_WE_O;
+endmodule // intercon
diff --git a/design/stack_machine.v b/design/stack_machine.v
new file mode 100644
index 0000000..1fddb18
--- /dev/null
+++ b/design/stack_machine.v
@@ -0,0 +1,353 @@
+`default_nettype none
+
+module stack_machine
+ (
+ input wire ACK_I,
+ input wire CLK_I,
+ output reg [19:0] ADR_O,
+ input wire [15:0] DAT_I,
+ output reg [15:0] DAT_O,
+ input wire RST_I,
+ output reg STB_O,
+ output reg CYC_O,
+ output reg WE_O,
+ input wire STALL_I,
+
+ /* non-wishbone */
+ output wire finished
+ );
+
+ reg [19:0] pc;
+ reg [19:0] sp;
+
+ reg [15:0] instr;
+
+ reg [31:0] r0;
+ reg [31:0] r1;
+ reg [31:0] im;
+
+ parameter STEP_START = 0;
+ parameter STEP_LOADING_INSTRUCTION = 1;
+ parameter STEP_PARSING_INSTRUCTION = 2;
+ parameter STEP_LOAD_OR_STORE = 3;
+ parameter STEP_PERFORM_OPERATION = 4;
+ reg [2:0] step;
+
+ reg [15:0] DAT_I_latched;
+ reg [15:0] instruction_latched;
+ reg instruction_just_received;
+ wire [15:0] instruction;
+ assign instruction = instruction_just_received ?
+ DAT_I_latched : instruction_latched;
+
+ /* Results of instruction parsing */
+ wire shift_immediate; /* only if modify_immediate is true */
+ assign shift_immediate = instruction[11];
+
+ /* only if shift_immediate is true */
+ wire [10:0] immediate_bits_to_shift;
+ assign immediate_bits_to_shift = instruction[10:0];
+
+ /* only if shift_immediate is false */
+ wire set_immediate;
+ assign set_immediate = instruction[10];
+
+ /* only if (set_immediate && !shift_immediate) is true */
+ wire [31:0] immediate_value_to_set;
+ assign immediate_value_to_set = {{22{instruction[9]}}, instruction[9:0]};
+
+ /* only if (!set_immediate && !shift_immediate) is true */
+ wire add_immediate;
+ assign add_immediate = instruction[9];
+
+ /* only if (add_immediate && !set_immediate && !shift_immediate) is true */
+ wire [9:0] immediate_value_to_add;
+ assign immediate_value_to_add = instruction[8:0];
+
+
+ wire [31:0] new_im;
+ assign new_im = shift_immediate ? {im[20:0], immediate_bits_to_shift} :
+ set_immediate ? immediate_value_to_set :
+ add_immediate ? im + immediate_value_to_add : im;
+
+
+ wire shift_regs;
+ assign shift_regs = instruction[12];
+
+
+ wire load_or_store;
+ assign load_or_store = instruction[15];
+
+ wire [19:0] addr_to_use; /* only if load_or_store is true */
+ /* The implementation is currently unable to make non-aligned accesses */
+ assign addr_to_use = new_im / 2 + (immediate_addressing ? 0 : sp);
+
+ wire load; /* only if load_or_store is true */
+ assign load = instruction[14];
+
+ wire store; /* only if load_or_store is true */
+ assign store = !load;
+
+ wire immediate_addressing; /* only if load_or_store is true */
+ assign immediate_addressing = instruction[13];
+ wire sp_addressing; /* only if load_or_store is true */
+ assign sp_addressing = !immediate_addressing;
+
+ wire load_or_store_r0; /* only if load_or_store is true */
+ assign load_or_store_r0 = instruction[12];
+
+ wire load_or_store_r1; /* only if load_or_store is true */
+ assign load_or_store_r1 = !load_or_store_r0;
+
+
+ /* only if load_or_store is false */
+ wire cond_jump;
+ assign cond_jump = instruction[14:13] == 2'b11;
+
+ /* only if load_or_store is false */
+ wire jump;
+ assign jump = instruction[14:13] == 2'b10;
+
+ /* only if load_or_store is false */
+ wire exchange_r1_im;
+ assign exchange_r1_im = instruction[14:13] == 2'b01;
+
+ /* only if load_or_store is false */
+ wire immediate_modification;
+ assign immediate_modification
+ = instruction[14:13] == 0 &&
+ (shift_immediate || set_immediate || add_immediate);
+
+ wire extended_instruction; /* only if load_or_store is false */
+ assign extended_instruction = instruction[14:13] == 0 && ! shift_immediate &&
+ !set_immediate && !add_immediate;
+
+ /* only if (!load_or_store && extended_instruction) is true */
+ wire [8:0] extended_instruction_bits;
+ assign extended_instruction_bits = instruction[8:0];
+
+ /* extended instructions */
+ parameter INSTR_MUL = 9'd6;
+ parameter INSTR_DIV = 9'd5;
+ parameter INSTR_SUB = 9'd4;
+ parameter INSTR_ADD = 9'd3;
+ parameter INSTR_SET_SP = 9'd2;
+ parameter INSTR_HALT = 9'd1;
+ parameter INSTR_NOP = 9'd0;
+
+ /* module for division */
+ wire [31:0] div_quotient;
+ wire [31:0] div_remainder;
+ wire div_done;
+
+ div
+ #(
+ .WIDTH(32)
+ ) div
+ (
+ .clock(CLK_I),
+ .start(step == STEP_PARSING_INSTRUCTION),
+ .dividend(r0),
+ .divisor(r1),
+
+ .quotient(div_quotient),
+ .remainder(div_remainder),
+ .done(div_done)
+ );
+
+ assign finished = !load_or_store && extended_instruction &&
+ extended_instruction_bits == INSTR_HALT;
+
+
+ reg [15:0] second_word_to_store;
+
+ /*
+ * Variables necessary to know where we are when transferring
+ * a sequence of words through wishbone
+ */
+ reg first_command_sent;
+ reg first_ack_received;
+
+ /* Informs us, that DAT_I_latched should be moved to r0 or r1 */
+ reg load_half_of_r0;
+ reg load_half_of_r1;
+
+`ifdef SIMULATION
+ /*
+ * RST should still be used when powering up, even in benches;
+ * this is just to avoid undefined values
+ */
+ initial begin
+ ADR_O <= 0;
+ STB_O <= 0;
+ CYC_O <= 0;
+ WE_O <= 0;
+
+ r0 <= 0;
+ r1 <= 0;
+ im <= 0;
+ pc <= 0;
+ sp <= 20'h40000;
+ step <= STEP_START;
+ instruction_latched <= 0;
+ instruction_just_received <= 0;
+ end
+`endif
+
+ always @ (posedge CLK_I) begin
+ DAT_I_latched <= DAT_I;
+
+ /*
+ * Later part of this always block sets them to 1 under certain
+ * conditions, which takes precedence over this assignment
+ */
+ load_half_of_r0 <= 0;
+ load_half_of_r1 <= 0;
+ instruction_just_received <= 0;
+
+ if (RST_I) begin
+ STB_O <= 0;
+ CYC_O <= 0;
+
+ pc <= 0;
+ sp <= 20'h40000;
+ step <= STEP_START;
+ end else begin
+ case (step)
+ STEP_START : begin
+ ADR_O <= pc;
+ STB_O <= 1;
+ CYC_O <= 1;
+ WE_O <= 0;
+ step <= STEP_LOADING_INSTRUCTION;
+ pc <= pc + 1;
+ end
+ STEP_LOADING_INSTRUCTION : begin
+ if (!STALL_I)
+ STB_O <= 0;
+
+ if (ACK_I) begin
+ instruction_just_received <= 1;
+ step <= STEP_PARSING_INSTRUCTION;
+ CYC_O <= 0;
+ end
+ end // case: STEP_LOADING_INSTRUCTION
+ STEP_PARSING_INSTRUCTION : begin
+ im <= new_im;
+ instruction_latched <= instruction;
+
+ first_command_sent <= 0;
+ first_ack_received <= 0;
+
+ if (shift_regs)
+ {r0, r1} <= {r1, r0}; /* magic! */
+
+ if (load_or_store) begin
+ CYC_O <= 1;
+ STB_O <= 1;
+ WE_O <= store;
+ ADR_O <= addr_to_use;
+
+ /* Even if not a store, setting these won't break anything */
+ DAT_O <= load_or_store_r0 ? r0[15:0] : r1[15:0];
+ second_word_to_store <= load_or_store_r0 ?
+ r0[31:16] : r1[31:16];
+
+ if (load_or_store_r0)
+ sp <= sp + (load ? 2 : -2);
+
+ step <= STEP_LOAD_OR_STORE;
+ end else begin // if (load_or_store)
+ if (immediate_modification) begin
+ step <= STEP_START;
+ end else if (exchange_r1_im || extended_instruction) begin
+ step <= STEP_PERFORM_OPERATION;
+ end else if (jump) begin
+ pc <= new_im / 2;
+ step <= STEP_START;
+ end else if (cond_jump) begin
+ if (r1 != 0)
+ pc <= new_im / 2;
+
+ step <= STEP_START;
+ end else begin
+`ifdef SIMULATION
+ $display("operation not implemented yet");
+`endif
+ step <= STEP_START;
+ end
+ end // else: !if(load_or_store)
+ end // case: STEP_PARSING_INSTRUCTION
+ STEP_LOAD_OR_STORE : begin
+ if (!STALL_I) begin
+ ADR_O <= ADR_O + 1;
+
+ DAT_O <= second_word_to_store;
+
+ if (!first_command_sent)
+ first_command_sent <= 1;
+ else
+ STB_O <= 0;
+ end // if (!STALL_I)
+
+ if (ACK_I) begin
+ if (load) begin
+ if (load_or_store_r0)
+ load_half_of_r0 <= 1;
+ else
+ load_half_of_r1 <= 1;
+ end
+
+ if (!first_ack_received)
+ first_ack_received <= 1;
+ else
+ step <= STEP_START;
+ end // if (ACK_I)
+ end // case: STEP_LOAD_OR_STORE
+ STEP_PERFORM_OPERATION : begin
+ step <= STEP_START; /* unless overwritten in case block below */
+
+ if (extended_instruction) begin
+ case (extended_instruction_bits)
+ INSTR_NOP :
+ ;
+ INSTR_HALT :
+ step <= step; /* stay in this step forever */
+ INSTR_SET_SP :
+ sp <= im / 2;
+ INSTR_ADD :
+ r0 <= r0 + r1;
+ INSTR_SUB :
+ r0 <= r0 - r1;
+ INSTR_DIV : begin
+ {r0, r1} <= {div_quotient, div_remainder};
+ if (!div_done)
+ step <= step;
+ end
+ INSTR_MUL :
+ r0 <= r0 * r1;
+ default : begin
+`ifdef SIMULATION
+ $display("operation not implemented yet");
+`endif
+ end
+ endcase // case (extended_instruction_bits)
+ end else if (exchange_r1_im) begin
+ {r1, im} <= {im, r1};
+ end else begin
+`ifdef SIMULATION
+ $display("operation not implemented yet");
+`endif
+ end
+ end // case: STEP_PERFORM_OPERATION
+ endcase // case (step)
+ end // else: !if(RST_I)
+
+ if (load_half_of_r0)
+ r0 <= {DAT_I_latched, r0[31:16]};
+
+ if (load_half_of_r1)
+ r1 <= {DAT_I_latched, r1[31:16]};
+ end // always @ (posedge CLK_I)
+
+endmodule // stack_machine
diff --git a/design/vga.v b/design/vga.v
new file mode 100644
index 0000000..4b71b28
--- /dev/null
+++ b/design/vga.v
@@ -0,0 +1,241 @@
+`default_nettype none
+
+ module vga
+ #(
+ parameter FONT_FILE = "font.mem"
+ )
+ (
+ output wire ACK_O,
+ input wire CLK_I,
+ input wire [10: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 */
+ input wire clock_25mhz,
+ output reg h_sync,
+ output reg v_sync,
+ output reg [2:0] red,
+ output reg [2:0] green,
+ output reg [2:0] blue
+ );
+
+ reg powered_on;
+
+ parameter LINES = V_ACTIVE_VIDEO / 16; /* 30 */
+ parameter LINE_LENGTH = H_ACTIVE_VIDEO / 8; /* 80 */
+ parameter CHARACTERS_ON_SCREEN = LINE_LENGTH * LINES; /* 2400 */
+
+ /*
+ * We want to store 2400 characters in memory. 2 chars go into one 16-bit
+ * word, so wee need a 1200x16 array. One embedded RAM block in iCE40 FPGAs
+ * is able to store 256x16 bits. This means, instead of choosing 1200 as
+ * array size, we can choose 1280, which is a multiple of 256.
+ */
+ reg [15:0] text_memory [1279 : 0];
+
+ /*
+ * Enable writes to text_memory using wishbone interface.
+ * (no reads for now)
+ */
+
+ reg ack;
+
+ assign DAT_O = {16{powered_on}};
+ assign ACK_O = ack;
+ assign STALL_O = 1'b0;
+
+ always @ (posedge CLK_I) begin
+ ack <= STB_I && !RST_I;
+
+ if (STB_I && WE_I) begin
+ if (ADR_I < 1280)
+ text_memory[ADR_I] <= DAT_I;
+ else
+ powered_on <= DAT_I != 16'b0;
+ end
+ end
+
+ /* Non-wishbone part - generate 640x480 60Hz VGA output */
+
+ reg powered_on_latched;
+
+ always @ (posedge clock_25mhz)
+ powered_on_latched <= powered_on;
+
+ parameter H_POLARITY = 1'b0;
+ parameter H_FRONT_PORCH = 8;
+ parameter H_SYNC = 96;
+ parameter H_BACK_PORCH = 40;
+ parameter H_LEFT_BORDER = 8;
+ parameter H_ACTIVE_VIDEO = 640;
+ parameter H_RIGHT_BORDER = 8;
+
+ reg [9:0] h_counter;
+
+ parameter H_STAGE_RB_OR_FP = 0; /* right border of front porch */
+ parameter H_STAGE_SYNC = 1;
+ parameter H_STAGE_BP_OR_LB = 2; /* back porch or left border */
+ parameter H_STAGE_ACTIVE_VIDEO = 3;
+
+ reg [1:0] h_stage;
+
+ always @ (posedge clock_25mhz) begin
+ if (powered_on_latched) begin
+ if ((h_stage == H_STAGE_RB_OR_FP &&
+ h_counter + 1 == H_RIGHT_BORDER + H_FRONT_PORCH) ||
+ (h_stage == H_STAGE_SYNC &&
+ h_counter + 1 == H_SYNC) ||
+ (h_stage == H_STAGE_BP_OR_LB &&
+ h_counter + 1 == H_BACK_PORCH + H_LEFT_BORDER) ||
+ (h_stage == H_STAGE_ACTIVE_VIDEO &&
+ h_counter + 1 == H_ACTIVE_VIDEO)) begin
+ h_stage <= h_stage + 1;
+ h_counter <= 0;
+ end else begin // if ((h_stage == H_STAGE_RB_OR_FP &&...
+ h_counter <= h_counter + 1;
+ end
+ end else begin // if (powered_on_latched)
+ h_stage <= H_STAGE_RB_OR_FP;
+ h_counter <= H_RIGHT_BORDER;
+ end // else: !if(powered_on_latched)
+ end // always @ (posedge clock_25mhz)
+
+ wire end_of_line;
+ assign end_of_line = h_stage == H_STAGE_RB_OR_FP &&
+ h_counter + 1 == H_RIGHT_BORDER;
+
+ parameter V_POLARITY = 1'b1;
+ parameter V_FRONT_PORCH = 2;
+ parameter V_SYNC = 2;
+ parameter V_BACK_PORCH = 25;
+ parameter V_TOP_BORDER = 8;
+ parameter V_ACTIVE_VIDEO = 480;
+ parameter V_BOTTOM_BORDER = 8;
+
+ reg [8:0] v_counter;
+
+ parameter V_STAGE_BB_OR_FP = 0; /* bottom border of front porch */
+ parameter V_STAGE_SYNC = 1;
+ parameter V_STAGE_BP_OR_TB = 2; /* back porch or top border */
+ parameter V_STAGE_ACTIVE_VIDEO = 3;
+
+ reg [1:0] v_stage;
+
+ always @ (posedge clock_25mhz) begin
+ if (powered_on_latched) begin
+ if (end_of_line) begin
+ if ((v_stage == V_STAGE_BB_OR_FP &&
+ v_counter + 1 == V_BOTTOM_BORDER + V_FRONT_PORCH) ||
+ (v_stage == V_STAGE_SYNC &&
+ v_counter + 1 == V_SYNC) ||
+ (v_stage == V_STAGE_BP_OR_TB &&
+ v_counter + 1 == V_BACK_PORCH + V_TOP_BORDER) ||
+ (v_stage == V_STAGE_ACTIVE_VIDEO &&
+ v_counter + 1 == V_ACTIVE_VIDEO)) begin
+ v_stage <= v_stage + 1;
+ v_counter <= 0;
+ end else begin // if ((v_stage == V_STAGE_BB_OR_FP &&...
+ v_counter <= v_counter + 1;
+ end
+ end // if (end_of_line)
+ end else begin // if (powered_on_latched)
+ v_stage <= V_STAGE_BB_OR_FP;
+ v_counter <= V_BOTTOM_BORDER;
+ end // else: !if(powered_on_latched)
+ end // always @ (posedge clock_25mhz)
+
+ reg [0:7] font [128 * 16 - 1 : 0];
+
+ initial begin
+ $readmemb(FONT_FILE, font, 0, 128 * 16 - 1);
+ end
+
+ wire [6:0] char_x;
+ wire [4:0] char_y;
+ wire [12:0] char_flat_idx;
+ wire [15:0] text_memory_field;
+ wire [7:0] char;
+ assign char_x = h_counter / 8;
+ assign char_y = v_counter / 16;
+ assign char_flat_idx = char_x + char_y * LINE_LENGTH;
+ assign text_memory_field = text_memory[char_flat_idx[12:1]];
+ assign char = char_flat_idx[0] ?
+ text_memory_field[15:8] : text_memory_field[7:0];
+
+ wire [0:7] replacement_char [0:16];
+ assign replacement_char[0] = 8'b00000000;
+ assign replacement_char[1] = 8'b00011000;
+ assign replacement_char[2] = 8'b00111100;
+ assign replacement_char[3] = 8'b01100110;
+ assign replacement_char[4] = 8'b01011010;
+ assign replacement_char[5] = 8'b01111010;
+ assign replacement_char[6] = 8'b01111010;
+ assign replacement_char[7] = 8'b01111010;
+ assign replacement_char[8] = 8'b01110110;
+ assign replacement_char[9] = 8'b01101110;
+ assign replacement_char[10] = 8'b01101110;
+ assign replacement_char[11] = 8'b01111110;
+ assign replacement_char[12] = 8'b01101110;
+ assign replacement_char[13] = 8'b00111100;
+ assign replacement_char[14] = 8'b00011000;
+ assign replacement_char[15] = 8'b00000000;
+
+ wire [2:0] char_pixel_x;
+ wire [3:0] char_pixel_y;
+ wire pixel_on;
+ wire display_on;
+ assign char_pixel_x = h_counter % 8;
+ assign char_pixel_y = v_counter % 16;
+ /* Replace non-ASCII characters (i.e. chars with values above 127) */
+ assign pixel_on = char[7] ? replacement_char[char_pixel_y][char_pixel_x] :
+ font[char[6:0] * 16 + char_pixel_y][char_pixel_x];
+ assign display_on = h_stage == H_STAGE_ACTIVE_VIDEO &&
+ v_stage == V_STAGE_ACTIVE_VIDEO;
+
+ parameter FG_COLOR = {3'b010, 3'b111, 3'b101};
+ parameter BG_COLOR = {3'b000, 3'b000, 3'b111};
+
+ always @ (posedge clock_25mhz) begin
+ if (h_stage == H_STAGE_SYNC)
+ h_sync <= H_POLARITY;
+ else
+ h_sync <= ~H_POLARITY;
+
+ if (v_stage == V_STAGE_SYNC)
+ v_sync <= V_POLARITY;
+ else
+ v_sync <= ~V_POLARITY;
+
+ if (!display_on)
+ {red, green, blue} <= 9'b0;
+ else if (pixel_on)
+ {red, green, blue} <= FG_COLOR;
+ else
+ {red, green, blue} <= BG_COLOR;
+ end // always @ (posedge clock_25mhz)
+
+`ifdef SIMULATION
+ /* avoid undefined values */
+ initial begin
+ powered_on <= 0;
+ powered_on_latched <= 0;
+ ack <= 0;
+
+ h_sync <= ~H_POLARITY;
+ v_sync <= ~V_POLARITY;
+ {red, green, blue} <= 9'b0;
+
+ h_counter <= 0;
+ h_stage <= H_STAGE_RB_OR_FP;
+
+ v_counter <= 0;
+ v_stage <= V_STAGE_BB_OR_FP;
+ end
+`endif
+endmodule // vga
+
diff --git a/include/macroasm.vh b/include/macroasm.vh
new file mode 100644
index 0000000..0c63ea7
--- /dev/null
+++ b/include/macroasm.vh
@@ -0,0 +1,33 @@
+`define C(comment) // make comments that disapper after preprocessing
+
+`C((
+This file implements a kind of macro assembly to generate instructions for our
+wishbone master mock module. The instructions specify what commands the master
+should send to its wishbone interface and what intervals it should put in
+between. $readmemh() is used to "load" the preprocessed instructions into
+the simulation.
+
+This header should be `included in the file with macroassembly operations.
+
+To generate the actual memory file you can for example use the -E flag to
+IVerilog, like this:
+$ iverilog -E some_operations.memv -o some_operations.mem
+
+I should have probably used some other tool for this job... POSIX shell, maybe?
+
+operations:
+ 0 - read
+ 1 - write
+ 2 - wait (CYC_O high and STB_O low for one tick)
+ 3 - deselect (CYC_O low for one tick)
+))
+
+`define READ(addr, expected_data) 0``addr``expected_data
+`define WRITE(addr, data) 1``addr``data
+`define WAIT 2xxxxxxxxx
+`define DESELECT 3xxxxxxxxx
+
+`C((
+We have to take care to use the correct number of digits for addresses and
+datas - the macros don't validate their arguments!
+))
diff --git a/include/messages.vh b/include/messages.vh
new file mode 100644
index 0000000..83ab6a4
--- /dev/null
+++ b/include/messages.vh
@@ -0,0 +1,18 @@
+`ifndef MESSAGES_VH
+ `define MESSAGES_VH 1
+
+ `define MSG(msg) \
+ if (1) begin \
+ $write("[%0t] ", $time); \
+ $display msg; \
+ end else
+
+ `ifdef DEBUG
+ `define DBG(msg) `MSG(msg)
+ `else
+ `define DBG(msg) if (1) begin end else
+ `endif
+
+`endif
+
+// Use like this: DBG(("Wishbone master: a = %x, b = %x", a, b))
diff --git a/models/master.v b/models/master.v
new file mode 100644
index 0000000..b728bda
--- /dev/null
+++ b/models/master.v
@@ -0,0 +1,223 @@
+/* A wishbone slave testing module (a "mock") */
+`default_nettype none
+
+`include "messages.vh"
+
+`ifndef SIMULATION
+ `error_SIMULATION_not_defined
+; /* Cause syntax error */
+`else
+
+module master_model
+ #(
+ parameter MASTER_NR = -1,
+ parameter OPERATIONS_FILE = "master_operations.mem",
+ parameter OPERATIONS_COUNT = 10
+ )
+ (
+ input wire ACK_I,
+ input wire CLK_I,
+ output wire [19:0] ADR_O,
+ input wire [15:0] DAT_I,
+ output wire [15:0] DAT_O,
+ input wire RST_I,
+ output wire STB_O,
+ output wire CYC_O,
+ output wire WE_O,
+ input wire STALL_I,
+
+ /* Non-wishbone */
+ output wire finished
+ );
+
+ parameter
+ OP_READ = 0,
+ OP_WRITE = 1,
+ OP_WAIT = 2, /* Keep CYC_O high, but STB_O low for 1 tick */
+ OP_DESELECT = 3; /* Drive CYC_O low for one tick */
+
+ /*
+ * Bits 39:36 specify type of the operation; bits 35:16 contain the
+ * address for read wnd write operations (may contain garbage otherwise);
+ * bits 15:0 contain data to write (for write operation) or expected data
+ * (for read operation) or are irrelevant (for other operations)
+ */
+ reg [39:0] operations [OPERATIONS_COUNT - 1 : 0];
+ /*
+ * This will allow us to check whether read operation returned proper data;
+ * bit 16 tells us whether the corresponding command was a read; if not,
+ * bits 15:0 don't matter; if yes bits 15:0 contain the data we should
+ * receive from that read operation
+ */
+ reg [16:0] expected_results [OPERATIONS_COUNT - 1 : 0];
+
+ integer i, j;
+
+ initial begin
+ $readmemh(OPERATIONS_FILE, operations, 0, OPERATIONS_COUNT - 1);
+
+ j = 0;
+ for (i = 0; i < OPERATIONS_COUNT; i++) begin
+ if (operations[i][39:36] == OP_READ ||
+ operations[i][39:36] == OP_WRITE) begin
+ if (operations[i][39:36] == OP_READ)
+ expected_results[j] <= {1'b1, operations[i][15:0]};
+ else
+ expected_results[j] <= {1'b0, 16'bx};
+
+ j++;
+ end
+ end
+ end
+
+ reg [31:0] operations_performed;
+ reg [31:0] commands_sent;
+ reg [31:0] commands_acknowledged;
+
+ /* Those are irrelevant if RST_I is high */
+ wire command_successful;
+ wire wait_successful;
+ wire deselect_successful;
+ wire [2:0] current_operation_type;
+ wire operation_successful;
+ wire [31:0] operations_performed_next_tick;
+ wire [39:0] operation_to_perform;
+ wire acknowledgement_successful;
+ wire [31:0] commands_sent_next_tick;
+ wire [31:0] commands_acknowledged_next_tick;
+ wire [31:0] acknowledgements_needed;
+
+ assign command_successful = CYC_O && STB_O && !STALL_I;
+ assign wait_successful = !STB_O && !STALL_I;
+ assign deselect_successful = !CYC_O;
+ assign current_operation_type = operations[operations_performed][39:36];
+ assign operation_successful
+ = operations_performed < OPERATIONS_COUNT &&
+ ((current_operation_type == OP_READ && command_successful) ||
+ (current_operation_type == OP_WRITE && command_successful) ||
+ (current_operation_type == OP_WAIT && wait_successful) ||
+ (current_operation_type == OP_DESELECT && deselect_successful));
+ assign operations_performed_next_tick
+ = operations_performed + operation_successful;
+ assign operation_to_perform = operations[operations_performed_next_tick];
+
+ assign commands_sent_next_tick = commands_sent + command_successful;
+ assign acknowledgement_successful
+ = CYC_O && ACK_I && commands_sent_next_tick > commands_acknowledged;
+ assign commands_acknowledged_next_tick
+ = commands_acknowledged + acknowledgement_successful;
+ assign acknowledgements_needed
+ = commands_sent_next_tick - commands_acknowledged_next_tick;
+
+ reg strobe;
+ assign STB_O = strobe;
+
+ reg cycle;
+ assign CYC_O = cycle;
+
+ reg write_enable;
+ assign WE_O = write_enable;
+
+ reg [15:0] output_data;
+ assign DAT_O = output_data;
+
+ reg [19:0] addr;
+ assign ADR_O = addr;
+
+ reg done;
+ assign finished = done;
+
+ initial begin
+ strobe <= 0;
+ cycle <= 0;
+ operations_performed <= 0;
+ commands_sent <= 0;
+ commands_acknowledged <= 0;
+ done <= 0;
+ end
+
+ always @ (posedge CLK_I) begin
+ if (RST_I) begin
+ strobe <= 0;
+ cycle <= 0;
+ operations_performed <= 0;
+ commands_sent <= 0;
+ commands_acknowledged <= 0;
+ done <= 0;
+ end else begin
+ /* debug messages */
+ if (command_successful) begin
+ case (current_operation_type)
+ OP_READ : begin
+ `DBG(("Master %0d: sent read command at h%x", MASTER_NR,
+ operations[operations_performed][35:16]));
+ end
+ OP_WRITE : begin
+ `DBG(("Master %0d: sent write command of h%x at h%x",
+ MASTER_NR, operations[operations_performed][15:0],
+ operations[operations_performed][35:16]));
+ end
+ default :
+ `MSG(("Master %0d: error: bug in test bench", MASTER_NR));
+ endcase // case (current_operation_type)
+ end // if (command_successful)
+
+ if (acknowledgement_successful) begin
+ if (expected_results[commands_acknowledged][16])
+ `DBG(("Master %0d: acknowledged read of h%x", MASTER_NR, DAT_I));
+ else
+ `DBG(("Master %0d: acknowledged write", MASTER_NR));
+ end
+
+ operations_performed <= operations_performed_next_tick;
+ commands_sent <= commands_sent_next_tick;
+ commands_acknowledged <= commands_acknowledged_next_tick;
+
+ if (operations_performed_next_tick == OPERATIONS_COUNT) begin
+ strobe <= 0;
+
+ if (acknowledgements_needed == 0) begin
+ cycle <= 0;
+ done <= 1;
+ end
+ end else begin
+ operations_performed <= operations_performed_next_tick;
+
+ case (operation_to_perform[39:36])
+ OP_READ : begin
+ cycle <= 1;
+ strobe <= 1;
+ write_enable <= 0;
+ addr <= operation_to_perform[35:16];
+ end
+ OP_WRITE : begin
+ cycle <= 1;
+ strobe <= 1;
+ write_enable <= 1;
+ addr <= operation_to_perform[35:16];
+ output_data <= operation_to_perform[15:0];
+ end
+ OP_WAIT : begin
+ cycle <= 1;
+ strobe <= 0;
+ end
+ OP_DESELECT : begin
+ cycle <= acknowledgements_needed > 0;
+ strobe <= 0;
+ end
+ endcase // case (operation_to_perform[39:36])
+ end // else: !if(operations_performed_next_tick == OPERATIONS_COUNT)
+
+ if (acknowledgement_successful) begin
+ if (expected_results[commands_acknowledged][15:0] !== DAT_I &&
+ expected_results[commands_acknowledged][16]) begin
+ `MSG(("Master %0d: error: read h%x instead of h%x",
+ MASTER_NR, DAT_I,
+ expected_results[commands_acknowledged][15:0]));
+ end
+ end
+ end // else: !if(RST_I)
+ end // always @ (posedge CLK_I)
+endmodule // master_model
+
+`endif // !`ifndef SIMULATION
diff --git a/models/slave.v b/models/slave.v
new file mode 100644
index 0000000..bae3485
--- /dev/null
+++ b/models/slave.v
@@ -0,0 +1,146 @@
+/* A wishbone slave testing module (a "mock") */
+`default_nettype none
+
+`include "messages.vh"
+
+`ifndef SIMULATION
+ `error_SIMULATION_not_defined
+; /* Cause syntax error */
+`else
+
+module memory_slave_model
+ #(
+ parameter SLAVE_NR = -1,
+ /* Changing the following 3 allows us to make it function as ROM */
+ parameter WRITABLE = 1,
+ parameter WORDS_TO_INITIALIZE = 0,
+ parameter INITIAL_CONTENTS_FILE = "some_file.mem"
+ )
+ (
+ output wire ACK_O,
+ input wire CLK_I,
+ input wire [17: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
+ );
+
+ /*
+ * A simple memory slave should be most useful for testing purposes;
+ * WARNING! The 'memory' variable might be referenced from outside the module
+ * by testbench code - be careful when changing or removing it
+ */
+ reg [15:0] memory [2**18 - 1 : 0];
+
+ integer seed; /* For random stall times and acknowledge times */
+
+ parameter MAX_STALL_TIME = 7;
+ parameter MAX_ACK_WAIT_TIME = 7;
+
+ reg [2:0] stall_time_left;
+ reg [2:0] acknowledge_time_left;
+
+ /*
+ * Bit 34 contains latched WE_I; bits 33:16 contain latched ADR_I;
+ * bits 15:0 contain latched DAT_I
+ */
+ reg [34:0] command_pipeline [15:0];
+ reg [3:0] pipeline_oldest_element;
+ reg [4:0] pipeline_elements_count;
+ wire [3:0] pipeline_index_to_insert;
+ assign pipeline_index_to_insert = (pipeline_oldest_element +
+ pipeline_elements_count) % 16;
+
+ reg stall;
+
+ /* Those are irrelevant if RST_I is high */
+ wire pipeline_space_left;
+ wire can_accept;
+ wire new_command_accepted;
+ wire command_available_for_acknowledging;
+ wire command_acknowledged;
+ wire [34:0] incoming_command;
+ wire [34:0] command_to_process;
+
+ assign pipeline_space_left = pipeline_elements_count < 16;
+ assign can_accept = pipeline_space_left && stall_time_left == 0;
+ assign new_command_accepted = STB_I && can_accept;
+ assign command_available_for_acknowledging = pipeline_elements_count ||
+ new_command_accepted;
+ assign command_acknowledged = acknowledge_time_left == 0 &&
+ command_available_for_acknowledging;
+ assign incoming_command = STB_I ? {WE_I, ADR_I, DAT_I} : 35'bx;
+ assign command_to_process = pipeline_elements_count ?
+ command_pipeline[pipeline_oldest_element] :
+ incoming_command;
+
+ /* Finally, drive the outputs */
+
+ /*
+ * command_to_process[34] is low when it's a read command; only drive data
+ * outputs for read commands
+ */
+ assign DAT_O = (command_acknowledged && !command_to_process[34]) ?
+ memory[command_to_process[33:16]] : 16'bx;
+
+
+ assign STALL_O = !can_accept;
+
+ assign ACK_O = command_acknowledged;
+
+ initial begin
+ pipeline_oldest_element <= 0;
+ pipeline_elements_count <= 0;
+ seed <= SLAVE_NR;
+ stall_time_left <= 0;
+ acknowledge_time_left <= 0;
+
+ if (WORDS_TO_INITIALIZE)
+ $readmemb(INITIAL_CONTENTS_FILE, memory, 0, WORDS_TO_INITIALIZE - 1);
+ end
+
+ always @ (posedge CLK_I) begin
+ if (RST_I) begin
+ pipeline_oldest_element <= 0;
+ pipeline_elements_count <= 0;
+ end else begin
+ if (new_command_accepted) begin
+ stall_time_left <= $urandom(seed) % (MAX_STALL_TIME + 1);
+ command_pipeline[pipeline_index_to_insert] = incoming_command;
+ end else begin
+ if (stall_time_left)
+ stall_time_left <= stall_time_left - 1;
+ end
+
+ if (command_acknowledged) begin
+ acknowledge_time_left <= $urandom(seed) % (MAX_ACK_WAIT_TIME + 1);
+ pipeline_oldest_element <= pipeline_oldest_element + 1;
+
+ if (command_to_process[34]) begin /* Write command */
+ if (WRITABLE) begin
+ memory[command_to_process[33:16]] <= command_to_process[15:0];
+ `DBG(("Slave %0d: write of h%x at h%x", SLAVE_NR,
+ command_to_process[15:0], command_to_process[31:16]));
+ end else begin
+ `DBG(({"Slave %0d: error: write of h%x at h%x ",
+ "(read-only) memory"}, SLAVE_NR,
+ command_to_process[15:0], command_to_process[31:16]));
+ end
+ end else begin /* Read command */
+ `DBG(("Slave %0d: read of h%x at h%x", SLAVE_NR,
+ DAT_O, command_to_process[31:16]));
+ end
+ end else if (command_available_for_acknowledging) begin
+ acknowledge_time_left <= acknowledge_time_left - 1;
+ end
+
+ pipeline_elements_count <= pipeline_elements_count +
+ new_command_accepted - command_acknowledged;
+ end
+ end
+endmodule // memory_slave_model
+
+`endif // !`ifndef SIMULATION
diff --git a/models/vga_display.v b/models/vga_display.v
new file mode 100644
index 0000000..bb683e2
--- /dev/null
+++ b/models/vga_display.v
@@ -0,0 +1,203 @@
+`default_nettype none
+`timescale 1ns/1ns
+
+`include "messages.vh"
+
+`ifndef SIMULATION
+ `error_SIMULATION_not_defined
+; /* Cause syntax error */
+`endif
+
+module VGA_640_480_60Hz(
+ input wire horizontal_sync,
+ input wire vertical_sync,
+
+ input wire [2:0] red,
+ input wire [2:0] green,
+ input wire [2:0] blue,
+
+ output reg [9:0] image_writes
+ );
+ initial
+ image_writes <= 0;
+
+ parameter FRONT_PORCH = 0;
+ parameter SYNC_PULSE = 1;
+ parameter BACK_PORCH = 2;
+ parameter ACTIVE_VIDEO = 3;
+ parameter UNKNOWN_STATE = 4;
+
+ integer h_state;
+ integer v_state;
+ initial begin
+ h_state <= UNKNOWN_STATE;
+ v_state <= UNKNOWN_STATE;
+ end
+
+ parameter H_SYNC_POLARITY = 1'b0;
+ parameter H_FRONT_PORCH_LENGTH = 16;
+ parameter H_SYNC_PULSE_LENGTH = 96;
+ parameter H_BACK_PORCH_LENGTH = 48;
+ parameter H_ACTIVE_VIDEO_LENGTH = 640;
+
+ parameter V_SYNC_POLARITY = 1'b1;
+ parameter V_FRONT_PORCH_LENGTH = 10;
+ parameter V_SYNC_PULSE_LENGTH = 2;
+ parameter V_BACK_PORCH_LENGTH = 33;
+ parameter V_ACTIVE_VIDEO_LENGTH = 480;
+
+ reg [8:0] picture
+ [V_ACTIVE_VIDEO_LENGTH - 1 : 0]
+ [H_ACTIVE_VIDEO_LENGTH - 1 : 0];
+
+ integer h_counter, v_counter;
+
+ reg error;
+
+ wire unexpected_h_sync_pulse;
+ wire missing_h_sync_pulse;
+ assign unexpected_h_sync_pulse = horizontal_sync == H_SYNC_POLARITY &&
+ h_state != SYNC_PULSE;
+ assign missing_h_sync_pulse = horizontal_sync != H_SYNC_POLARITY &&
+ h_state == SYNC_PULSE;
+
+ wire unexpected_v_sync_pulse;
+ wire missing_v_sync_pulse;
+ assign unexpected_v_sync_pulse = vertical_sync == V_SYNC_POLARITY &&
+ v_state != SYNC_PULSE;
+ assign missing_v_sync_pulse = vertical_sync != V_SYNC_POLARITY &&
+ v_state == SYNC_PULSE;
+
+ wire new_line;
+ assign new_line = h_state == BACK_PORCH &&
+ h_counter + 1 == H_BACK_PORCH_LENGTH;
+
+ wire new_screen;
+ assign new_screen = v_state == BACK_PORCH &&
+ v_counter + 1 == V_BACK_PORCH_LENGTH && new_line;
+
+ always #40 begin
+ /* First, horizontal stuff */
+ if (unexpected_h_sync_pulse) begin
+ h_state <= SYNC_PULSE;
+ h_counter <= 1;
+
+ if (h_state != UNKNOWN_STATE) begin
+ `MSG(({"VGA: error: unexpected horizontal sync pulse signal ",
+ "(tick %0d; state %0d)"}, h_counter, h_state));
+ end
+ end else if (missing_h_sync_pulse) begin
+ h_state <= BACK_PORCH;
+ h_counter <= 1;
+
+ `MSG(({"VGA: error: missing expected horizontal sync pulse signal ",
+ "(tick %0d of sync pulse)"}, h_counter));
+ end else begin
+ case (h_state)
+ FRONT_PORCH : begin
+ if (h_counter + 1 != H_FRONT_PORCH_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= SYNC_PULSE;
+ h_counter <= 0;
+ end
+ end
+ SYNC_PULSE : begin
+ if (h_counter + 1 != H_SYNC_PULSE_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= BACK_PORCH;
+ h_counter <= 0;
+ end
+ end
+ BACK_PORCH : begin
+ if (h_counter + 1 != H_BACK_PORCH_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= ACTIVE_VIDEO;
+ h_counter <= 0;
+ end
+ end
+ ACTIVE_VIDEO : begin
+ if (v_state == ACTIVE_VIDEO) begin
+ picture[v_counter][h_counter] <= {red, green, blue};
+ end
+
+ if (h_counter + 1 != H_ACTIVE_VIDEO_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= FRONT_PORCH;
+ h_counter <= 0;
+ end
+ end // case: ACTIVE_VIDEO
+ endcase // case (h_state)
+ end // else: !if(missing_h_sync_pulse)
+
+
+ /* Vertical stuff is almost entirely the same as horizontal */
+ if (new_line) begin
+ if (unexpected_v_sync_pulse) begin
+ v_state <= SYNC_PULSE;
+ v_counter <= 1;
+
+ if (v_state != UNKNOWN_STATE) begin
+ `MSG(({"VGA: error: unexpected vertical sync pulse signal ",
+ "(line %0d; state %0d)"}, v_counter, v_state));
+ end
+ end else if (missing_v_sync_pulse) begin
+ v_state <= BACK_PORCH;
+ v_counter <= 1;
+
+ `MSG(({"VGA: error: missing expected vertical sync pulse signal ",
+ "(line %0d of sync pulse)"}, v_counter));
+ end else begin
+ case (v_state)
+ FRONT_PORCH : begin
+ if (v_counter + 1 != V_FRONT_PORCH_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= SYNC_PULSE;
+ v_counter <= 0;
+ end
+ end
+ SYNC_PULSE : begin
+ if (v_counter + 1 != V_SYNC_PULSE_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= BACK_PORCH;
+ v_counter <= 0;
+ end
+ end
+ BACK_PORCH : begin
+ if (v_counter + 1 != V_BACK_PORCH_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= ACTIVE_VIDEO;
+ v_counter <= 0;
+ end
+ end
+ ACTIVE_VIDEO : begin
+ if (v_counter + 1 != V_ACTIVE_VIDEO_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= FRONT_PORCH;
+ v_counter <= 0;
+
+ if (!error) begin
+ $writememb("VGAdump.mem", picture);
+ `DBG(("VGA: written VGAdump.mem"));
+ image_writes <= image_writes + 1;
+ end
+ end // else: !if(v_counter + 1 != V_ACTIVE_VIDEO_LENGTH)
+ end // case: ACTIVE_VIDEO
+ endcase // case (v_state)
+ end // else: !if(missing_v_sync_pulse)
+ end // if (new_line)
+
+ if (unexpected_h_sync_pulse || unexpected_h_sync_pulse ||
+ ((unexpected_v_sync_pulse || missing_v_sync_pulse) && new_line))
+ error <= 1;
+ else if (new_screen)
+ error <= 0;
+ end // always #40
+endmodule // VGA_640_480_60Hz
diff --git a/src/Makefile b/src/Makefile
deleted file mode 100644
index c528906..0000000
--- a/src/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-all : example.bin
-
-example.blif : example.v
- git-yosys -p 'synth_ice40 -top top -blif example.blif' example.v
-
-example.json : example.v
- git-yosys -p 'synth_ice40 -top top -json example.json' example.v
-
-example.asc : example.json mapping.pcf
- git-nextpnr-ice40 --hx8k --asc example.asc --pcf mapping.pcf --json example.json --package ct256
-
-example.bin : example.asc
- git-icepack example.asc example.bin
-
-prog : example.bin
- sudo iceprogduino example.bin
-
-clean :
- -rm example.bin example.asc example.blif example.json
-
-.PHONY : clean all
diff --git a/src/example.v b/src/example.v
deleted file mode 100644
index c588dba..0000000
--- a/src/example.v
+++ /dev/null
@@ -1,1226 +0,0 @@
-`default_nettype none
-
-module hex_print(input wire [3:0] halfbyte,
- input wire [7:0] x,
- input wire [15:0] y,
-
- output wire pixel
- );
- wire [0:7] number_0 [15:0];
- wire [0:7] number_1 [15:0];
- wire [0:7] number_2 [15:0];
- wire [0:7] number_3 [15:0];
- wire [0:7] number_4 [15:0];
- wire [0:7] number_5 [15:0];
- wire [0:7] number_6 [15:0];
- wire [0:7] number_7 [15:0];
- wire [0:7] number_8 [15:0];
- wire [0:7] number_9 [15:0];
-
- wire [0:7] letter_A [15:0];
- wire [0:7] letter_B [15:0];
- wire [0:7] letter_C [15:0];
- wire [0:7] letter_D [15:0];
- wire [0:7] letter_E [15:0];
- wire [0:7] letter_F [15:0];
-
- assign number_0[0] = 8'b00000000;
- assign number_0[1] = 8'b00011000;
- assign number_0[2] = 8'b00100100;
- assign number_0[3] = 8'b00100100;
- assign number_0[4] = 8'b01000110;
- assign number_0[5] = 8'b01001010;
- assign number_0[6] = 8'b01001010;
- assign number_0[7] = 8'b01001010;
- assign number_0[8] = 8'b01010010;
- assign number_0[9] = 8'b01010010;
- assign number_0[10] = 8'b01010010;
- assign number_0[11] = 8'b01100010;
- assign number_0[12] = 8'b00100100;
- assign number_0[13] = 8'b00100100;
- assign number_0[14] = 8'b00011000;
- assign number_0[15] = 8'b00000000;
-
- assign number_1[0] = 8'b00000000;
- assign number_1[1] = 8'b00001000;
- assign number_1[2] = 8'b00011000;
- assign number_1[3] = 8'b00111000;
- assign number_1[4] = 8'b00001000;
- assign number_1[5] = 8'b00001000;
- assign number_1[6] = 8'b00001000;
- assign number_1[7] = 8'b00001000;
- assign number_1[8] = 8'b00001000;
- assign number_1[9] = 8'b00001000;
- assign number_1[10] = 8'b00001000;
- assign number_1[11] = 8'b00001000;
- assign number_1[12] = 8'b00001000;
- assign number_1[13] = 8'b00001000;
- assign number_1[14] = 8'b00001000;
- assign number_1[15] = 8'b00000000;
-
- assign number_2[0] = 8'b00000000;
- assign number_2[1] = 8'b00111000;
- assign number_2[2] = 8'b01000100;
- assign number_2[3] = 8'b00000010;
- assign number_2[4] = 8'b00000010;
- assign number_2[5] = 8'b00000010;
- assign number_2[6] = 8'b00000010;
- assign number_2[7] = 8'b00000100;
- assign number_2[8] = 8'b00001000;
- assign number_2[9] = 8'b00010000;
- assign number_2[10] = 8'b00100000;
- assign number_2[11] = 8'b00100000;
- assign number_2[12] = 8'b01000000;
- assign number_2[13] = 8'b01000000;
- assign number_2[14] = 8'b01111110;
- assign number_2[15] = 8'b00000000;
-
- assign number_3[0] = 8'b00000000;
- assign number_3[1] = 8'b00111000;
- assign number_3[2] = 8'b01000100;
- assign number_3[3] = 8'b00000010;
- assign number_3[4] = 8'b00000010;
- assign number_3[5] = 8'b00000010;
- assign number_3[6] = 8'b00000100;
- assign number_3[7] = 8'b00011000;
- assign number_3[8] = 8'b00000100;
- assign number_3[9] = 8'b00000010;
- assign number_3[10] = 8'b00000010;
- assign number_3[11] = 8'b00000010;
- assign number_3[12] = 8'b00000010;
- assign number_3[13] = 8'b01000100;
- assign number_3[14] = 8'b00111000;
- assign number_3[15] = 8'b00000000;
-
- assign number_4[0] = 8'b00000000;
- assign number_4[1] = 8'b00001000;
- assign number_4[2] = 8'b00001000;
- assign number_4[3] = 8'b00010000;
- assign number_4[4] = 8'b00010000;
- assign number_4[5] = 8'b00100000;
- assign number_4[6] = 8'b00100000;
- assign number_4[7] = 8'b01000100;
- assign number_4[8] = 8'b01111110;
- assign number_4[9] = 8'b00000100;
- assign number_4[10] = 8'b00000100;
- assign number_4[11] = 8'b00000100;
- assign number_4[12] = 8'b00000100;
- assign number_4[13] = 8'b00000100;
- assign number_4[14] = 8'b00000100;
- assign number_4[15] = 8'b00000000;
-
- assign number_5[0] = 8'b00000000;
- assign number_5[1] = 8'b01111100;
- assign number_5[2] = 8'b01000000;
- assign number_5[3] = 8'b01000000;
- assign number_5[4] = 8'b01000000;
- assign number_5[5] = 8'b01000000;
- assign number_5[6] = 8'b01111000;
- assign number_5[7] = 8'b00000100;
- assign number_5[8] = 8'b00000010;
- assign number_5[9] = 8'b00000010;
- assign number_5[10] = 8'b00000010;
- assign number_5[11] = 8'b00000010;
- assign number_5[12] = 8'b00000010;
- assign number_5[13] = 8'b01000100;
- assign number_5[14] = 8'b00111000;
- assign number_5[15] = 8'b00000000;
-
- assign number_6[0] = 8'b00000000;
- assign number_6[1] = 8'b00001100;
- assign number_6[2] = 8'b00010000;
- assign number_6[3] = 8'b00100000;
- assign number_6[4] = 8'b00100000;
- assign number_6[5] = 8'b01000000;
- assign number_6[6] = 8'b01000000;
- assign number_6[7] = 8'b01011000;
- assign number_6[8] = 8'b01100100;
- assign number_6[9] = 8'b01000010;
- assign number_6[10] = 8'b01000010;
- assign number_6[11] = 8'b01000010;
- assign number_6[12] = 8'b01000010;
- assign number_6[13] = 8'b00100100;
- assign number_6[14] = 8'b00011000;
- assign number_6[15] = 8'b00000000;
-
- assign number_7[0] = 8'b00000000;
- assign number_7[1] = 8'b01111110;
- assign number_7[2] = 8'b00000010;
- assign number_7[3] = 8'b00000100;
- assign number_7[4] = 8'b00000100;
- assign number_7[5] = 8'b00001000;
- assign number_7[6] = 8'b00001000;
- assign number_7[7] = 8'b00111100;
- assign number_7[8] = 8'b00010000;
- assign number_7[9] = 8'b00010000;
- assign number_7[10] = 8'b00010000;
- assign number_7[11] = 8'b00100000;
- assign number_7[12] = 8'b00100000;
- assign number_7[13] = 8'b00100000;
- assign number_7[14] = 8'b00100000;
- assign number_7[15] = 8'b00000000;
-
- assign number_8[0] = 8'b00000000;
- assign number_8[1] = 8'b00011000;
- assign number_8[2] = 8'b00100100;
- assign number_8[3] = 8'b01000010;
- assign number_8[4] = 8'b01000010;
- assign number_8[5] = 8'b01000010;
- assign number_8[6] = 8'b00100100;
- assign number_8[7] = 8'b00011000;
- assign number_8[8] = 8'b00100100;
- assign number_8[9] = 8'b01000010;
- assign number_8[10] = 8'b01000010;
- assign number_8[11] = 8'b01000010;
- assign number_8[12] = 8'b01000010;
- assign number_8[13] = 8'b00100100;
- assign number_8[14] = 8'b00011000;
- assign number_8[15] = 8'b00000000;
-
- assign number_9[0] = 8'b00000000;
- assign number_9[1] = 8'b00011000;
- assign number_9[2] = 8'b00100100;
- assign number_9[3] = 8'b01000010;
- assign number_9[4] = 8'b01000010;
- assign number_9[5] = 8'b01000010;
- assign number_9[6] = 8'b01000010;
- assign number_9[7] = 8'b00100110;
- assign number_9[8] = 8'b00011010;
- assign number_9[9] = 8'b00000010;
- assign number_9[10] = 8'b00000010;
- assign number_9[11] = 8'b00000100;
- assign number_9[12] = 8'b00000100;
- assign number_9[13] = 8'b00001000;
- assign number_9[14] = 8'b00110000;
- assign number_9[15] = 8'b00000000;
-
- assign letter_A[0] = 8'b00000000;
- assign letter_A[1] = 8'b00011000;
- assign letter_A[2] = 8'b00100100;
- assign letter_A[3] = 8'b00100100;
- assign letter_A[4] = 8'b00100100;
- assign letter_A[5] = 8'b01000010;
- assign letter_A[6] = 8'b01000010;
- assign letter_A[7] = 8'b01000010;
- assign letter_A[8] = 8'b01111110;
- assign letter_A[9] = 8'b01000010;
- assign letter_A[10] = 8'b01000010;
- assign letter_A[11] = 8'b01000010;
- assign letter_A[12] = 8'b01000010;
- assign letter_A[13] = 8'b01000010;
- assign letter_A[14] = 8'b01000010;
- assign letter_A[15] = 8'b00000000;
-
- assign letter_B[0] = 8'b00000000;
- assign letter_B[1] = 8'b01111000;
- assign letter_B[2] = 8'b01000100;
- assign letter_B[3] = 8'b01000010;
- assign letter_B[4] = 8'b01000010;
- assign letter_B[5] = 8'b01000010;
- assign letter_B[6] = 8'b01000100;
- assign letter_B[7] = 8'b01111000;
- assign letter_B[8] = 8'b01000100;
- assign letter_B[9] = 8'b01000010;
- assign letter_B[10] = 8'b01000010;
- assign letter_B[11] = 8'b01000010;
- assign letter_B[12] = 8'b01000010;
- assign letter_B[13] = 8'b01000100;
- assign letter_B[14] = 8'b01111000;
- assign letter_B[15] = 8'b00000000;
-
- assign letter_C[0] = 8'b00000000;
- assign letter_C[1] = 8'b00011100;
- assign letter_C[2] = 8'b00100010;
- assign letter_C[3] = 8'b00100000;
- assign letter_C[4] = 8'b01000000;
- assign letter_C[5] = 8'b01000000;
- assign letter_C[6] = 8'b01000000;
- assign letter_C[7] = 8'b01000000;
- assign letter_C[8] = 8'b01000000;
- assign letter_C[9] = 8'b01000000;
- assign letter_C[10] = 8'b01000000;
- assign letter_C[11] = 8'b01000000;
- assign letter_C[12] = 8'b00100000;
- assign letter_C[13] = 8'b00100010;
- assign letter_C[14] = 8'b00011100;
- assign letter_C[15] = 8'b00000000;
-
- assign letter_D[0] = 8'b00000000;
- assign letter_D[1] = 8'b01110000;
- assign letter_D[2] = 8'b01001000;
- assign letter_D[3] = 8'b01000100;
- assign letter_D[4] = 8'b01000100;
- assign letter_D[5] = 8'b01000010;
- assign letter_D[6] = 8'b01000010;
- assign letter_D[7] = 8'b01000010;
- assign letter_D[8] = 8'b01000010;
- assign letter_D[9] = 8'b01000010;
- assign letter_D[10] = 8'b01000010;
- assign letter_D[11] = 8'b01000100;
- assign letter_D[12] = 8'b01000100;
- assign letter_D[13] = 8'b01001000;
- assign letter_D[14] = 8'b01110000;
- assign letter_D[15] = 8'b00000000;
-
- assign letter_E[0] = 8'b00000000;
- assign letter_E[1] = 8'b01111110;
- assign letter_E[2] = 8'b01000000;
- assign letter_E[3] = 8'b01000000;
- assign letter_E[4] = 8'b01000000;
- assign letter_E[5] = 8'b01000000;
- assign letter_E[6] = 8'b01000000;
- assign letter_E[7] = 8'b01111000;
- assign letter_E[8] = 8'b01000000;
- assign letter_E[9] = 8'b01000000;
- assign letter_E[10] = 8'b01000000;
- assign letter_E[11] = 8'b01000000;
- assign letter_E[12] = 8'b01000000;
- assign letter_E[13] = 8'b01000000;
- assign letter_E[14] = 8'b01111110;
- assign letter_E[15] = 8'b00000000;
-
- assign letter_F[0] = 8'b00000000;
- assign letter_F[1] = 8'b01111110;
- assign letter_F[2] = 8'b01000000;
- assign letter_F[3] = 8'b01000000;
- assign letter_F[4] = 8'b01000000;
- assign letter_F[5] = 8'b01000000;
- assign letter_F[6] = 8'b01000000;
- assign letter_F[7] = 8'b01111000;
- assign letter_F[8] = 8'b01000000;
- assign letter_F[9] = 8'b01000000;
- assign letter_F[10] = 8'b01000000;
- assign letter_F[11] = 8'b01000000;
- assign letter_F[12] = 8'b01000000;
- assign letter_F[13] = 8'b01000000;
- assign letter_F[14] = 8'b01000000;
- assign letter_F[15] = 8'b00000000;
-
- assign pixel = halfbyte == 0 ? number_0[y][x] :
- halfbyte == 1 ? number_1[y][x] :
- halfbyte == 2 ? number_2[y][x] :
- halfbyte == 3 ? number_3[y][x] :
- halfbyte == 4 ? number_4[y][x] :
- halfbyte == 5 ? number_5[y][x] :
- halfbyte == 6 ? number_6[y][x] :
- halfbyte == 7 ? number_7[y][x] :
- halfbyte == 8 ? number_8[y][x] :
- halfbyte == 9 ? number_9[y][x] :
- halfbyte == 10 ? letter_A[y][x] :
- halfbyte == 11 ? letter_B[y][x] :
- halfbyte == 12 ? letter_C[y][x] :
- halfbyte == 13 ? letter_D[y][x] :
- halfbyte == 14 ? letter_E[y][x] :
- letter_F[y][x];
-endmodule
-
-module vga_timing(input wire clock_50mhz,
- input wire reset,
-
- output reg h_sync,
- output reg v_sync,
- output reg display_on,
- output reg pixel_starting,
- output reg row_starting);
-
- parameter h_pixels = 640;
- parameter v_pixels = 480;
- parameter h_front_porch = 16;
- parameter v_front_porch = 10;
- parameter h_pulse = 96;
- parameter v_pulse = 2;
- parameter h_back_porch = 48;
- parameter v_back_porch = 33;
- parameter h_pol = 1'b0;
- parameter v_pol = 1'b1;
-
- parameter h_pulse_start = h_front_porch;
- parameter v_pulse_start = v_front_porch;
- parameter h_pulse_end = h_front_porch + h_pulse;
- parameter v_pulse_end = v_front_porch + v_pulse;
- parameter h_active_video_start = h_front_porch + h_pulse + h_back_porch;
- parameter v_active_video_start = v_front_porch + v_pulse + v_back_porch;
- parameter h_frame_end = h_active_video_start + h_pixels;
- parameter v_frame_end = v_active_video_start + v_pixels;
-
- reg [9:0] h_counter;
- reg [9:0] v_counter;
-
- reg divider; // 25MHz
-
- wire display_on_next_tick;
- assign display_on_next_tick = (h_counter < h_frame_end - 1) &&
- (h_counter >= h_active_video_start - 1) &&
- (v_counter < v_frame_end) &&
- (v_counter >= v_active_video_start);
-
- always @ (posedge clock_50mhz) begin
- if (reset) begin
- divider <= 1'b0;
-
- h_counter <= 0;
- v_counter <= 0;
-
- h_sync <= ~h_pol;
- v_sync <= ~v_pol;
- display_on <= 0;
- pixel_starting <= 0;
- row_starting <= 0;
- end // if (reset)
- else begin
- divider <= divider + 1;
-
- if (divider == 1'b1) begin
- display_on <= display_on_next_tick;
- pixel_starting <= display_on_next_tick;
- row_starting <= display_on_next_tick && h_counter == h_active_video_start - 1;
-
- if (h_counter < h_frame_end - 1) begin
- h_counter <= h_counter + 1;
-
- h_sync <= h_pol ^ (h_counter < h_pulse_start - 1 || h_counter >= h_pulse_end - 1);
- end
- else begin
- h_counter <= 0;
-
- if (v_counter < v_frame_end - 1) begin
- v_counter <= v_counter + 1;
-
- v_sync <= v_pol ^ (v_counter < v_pulse_start - 1 || v_counter >= v_pulse_end - 1);
- end
- else begin
- v_counter <= 0;
- end // else: !if(v_counter < v_frame_end - 1)
- end // else: !if(h_counter < h_frame_end - 1)
- end // if (divider == 1'b1)
- else begin
- pixel_starting <= 0;
- row_starting <= 0;
- end
- end // else: !if(reset)
- end // always @ (posedge clock_50mhz)
-endmodule // vga_timing
-
-module vga_pass_colors(input wire clock_50mhz,
- input wire reset,
-
- input wire h_sync_next_tick,
- input wire v_sync_next_tick,
- input wire display_on_next_tick,
- input wire pixel_on_next_tick,
-
- output reg h_sync,
- output reg v_sync,
- output reg [2:0] vga_red,
- output reg [2:0] vga_green,
- output reg [2:0] vga_blue
- );
-
- wire [8:0] color_next_tick;
- assign color_next_tick = !display_on_next_tick ? 0 :
- pixel_on_next_tick ? color1 : color2;
-
- parameter color1 = {3'b010, 3'b111, 3'b101};
- parameter color2 = {3'b000, 3'b000, 3'b111};
-
- always @ (posedge clock_50mhz) begin
- if (reset) begin
- h_sync <= 0;
- v_sync <= 0;
- vga_red <= 0;
- vga_green <= 0;
- vga_blue <= 0;
- end
- else begin
- h_sync <= h_sync_next_tick;
- v_sync <= v_sync_next_tick;
-
- vga_red <= color_next_tick[8:6];
- vga_green <= color_next_tick[5:3];
- vga_blue <= color_next_tick[2:0];
- end // else: !if(reset)
- end // always @ (posedge clock_50mhz)
-endmodule // vga_pass_colors
-
-module vga_hexmode(input wire clock_50mhz,
- input wire reset,
-
- input wire can_read,
- input wire [15:0] read_data,
-
- output wire want_to_read,
- output wire [17:0] read_addr,
-
- input wire [17:0] displayed_memory_base,
-
- output wire h_sync,
- output wire v_sync,
- output wire [2:0] vga_red,
- output wire [2:0] vga_green,
- output wire [2:0] vga_blue
- );
- wire h_sync_next_tick;
- wire v_sync_next_tick;
- wire display_on_next_tick;
- wire pixel_starting_next_tick;
- wire row_starting_next_tick;
-
- vga_timing timing(clock_50mhz, reset,
- h_sync_next_tick, v_sync_next_tick, display_on_next_tick,
- pixel_starting_next_tick, row_starting_next_tick);
-
- parameter queue_size = 4;
-
- /* will store 4 consecutive hex digits copied from read_data[15:0] */
- reg [15:0] digits_queue;
- reg [1:0] digits_in_queue;
-
- parameter words_per_line = 20;
- parameter lines = 30;
- parameter words_per_screen = words_per_line * lines;
- parameter digit_h_pixels = 8;
- parameter digit_v_pixels = 16;
- parameter word_digits = 4;
-
- reg [2:0] digit_x;
- wire [2:0] subsequent_digit_x;
- assign subsequent_digit_x = digit_x == digit_h_pixels - 1 ? 0 : digit_x + 1;
-
- reg [3:0] digit_y;
- wire [3:0] subsequent_digit_y;
- assign subsequent_digit_y = digit_y == digit_v_pixels - 1 ? 0 : digit_y + 1;
-
- wire digit_starting_next_tick;
- assign digit_starting_next_tick = pixel_starting_next_tick &&
- digit_x == digit_h_pixels - 1;
-
- wire line_starting_next_tick;
- assign line_starting_next_tick = row_starting_next_tick &&
- digit_y == digit_v_pixels - 1;
-
- reg [4:0] word_in_line;
- reg [11:0] word_idx;
- wire [11:0] subsequent_word_idx;
- assign subsequent_word_idx = word_idx == words_per_screen - 1 ?
- 0 : word_idx + 1;
-
- assign read_addr = displayed_memory_base + word_idx;
-
- reg [3:0] current_digit;
- wire [3:0] digit_next_tick;
- assign digit_next_tick = digit_starting_next_tick ?
- digits_queue[15:12] : current_digit;
-
- wire pixel_on_next_tick;
-
- hex_print hex_print(digit_next_tick,
- pixel_starting_next_tick ? subsequent_digit_x : digit_x,
- row_starting_next_tick ? subsequent_digit_y : digit_y,
- pixel_on_next_tick);
-
- vga_pass_colors color_pass(clock_50mhz, reset, h_sync_next_tick,
- v_sync_next_tick, display_on_next_tick,
- pixel_on_next_tick, h_sync, v_sync,
- vga_red, vga_green, vga_blue);
-
- /* 0 - waiting for read; 1 - reading; 2 - reading done */
- reg [1:0] reading_state;
-
- assign want_to_read = reading_state == 0 ||
- (digit_starting_next_tick &&
- digits_in_queue - 1 == 0);
-
- wire reading;
- /* If new read can start, the previous one is ignored */
- assign reading = reading_state == 1 && !(want_to_read);
-
- always @ (posedge clock_50mhz) begin
- if (reset) begin
- digits_queue <= 16'bxxxxxxxxxxxxxxxx;
- digits_in_queue <= 0;
- reading_state <= 0;
- digit_x <= digit_h_pixels - 1;
- digit_y <= digit_v_pixels - 1;
- word_in_line <= 0;
- word_idx <= 0;
- end
- else begin
- if (pixel_starting_next_tick)
- digit_x <= subsequent_digit_x;
-
- if (digit_starting_next_tick) begin
- current_digit <= digit_next_tick;
-
- /*
- * Once there's only 1 digit in the queue, word_idx shall
- * already be pointing at the next address.
- */
- if (digits_in_queue - 3 == 0) begin
- if (word_in_line == words_per_line - 1) begin
- word_in_line <= 0;
- if (digit_y == digit_v_pixels - 1)
- word_idx <= subsequent_word_idx;
- else
- word_idx <= word_idx - (words_per_line - 1);
- end
- else begin
- word_in_line <= word_in_line + 1;
- word_idx <= subsequent_word_idx;
- end
- end
-
- /*
- * Hopefully read will always finish before we pop the next digit
- * from the queue. But we still need to avoid multiple drivers.
- */
- if (!reading)
- digits_queue <= {digits_queue[11:0], 4'bxxxx};
- end
-
- if (row_starting_next_tick)
- digit_y <= subsequent_digit_y;
-
- digits_in_queue <= digits_in_queue + (reading ? queue_size : 0) -
- (digit_starting_next_tick ? 1 : 0);
-
- if (want_to_read) begin
- if (can_read)
- reading_state <= 1;
- else
- reading_state <= 0;
- end
- else if (reading_state == 1) begin
- reading_state <= 2;
- digits_queue <= read_data;
- end
- end // else: !if(reset)
- end // always @ (posedge clock_50mhz)
-endmodule
-
-module on_button_write(input wire clock_50mhz,
- input wire reset,
-
- input wire can_write,
- output reg [15:0] write_data,
-
- output wire want_to_write,
- output wire [17:0] write_addr,
-
- input wire [17:0] written_memory_base,
- input wire but
- );
- /*
- * We use a reg to snapshot (and invert) the button signal (button2).
- * If we didn't snapshot it, we'd get timing problems.
- */
- reg button_pressed;
-
- /* 0 - waiting for write, 1 - writing, 2 - write complete */
- reg [1:0] write_state;
-
- parameter cooldown_start = 25'b111111111111111111111111;
- reg [23:0] but_cooldown;
-
- reg [4:0] write_idx;
- assign write_addr = written_memory_base + write_idx;
-
- wire perform_action;
- assign perform_action = button_pressed && !but_cooldown;
- assign want_to_write = perform_action || write_state == 0;
-
- always @ (posedge clock_50mhz) begin
- if (reset) begin
- but_cooldown <= cooldown_start;
- write_data <= 16'b000100000000000;
- write_state <= 2;
- write_idx <= 0;
- button_pressed <= 0;
- end
- else begin
- button_pressed <= !but;
-
- if (perform_action)
- but_cooldown <= cooldown_start;
- else if (but_cooldown)
- but_cooldown <= but_cooldown - 1;
-
- if (want_to_write) begin
- if (can_write)
- write_state <= 1;
- else
- write_state <= 0;
- end
- else if (write_state == 1) begin
- write_state <= 2;
-
- write_data <= write_data + 1;
- write_idx <= write_idx >= 30 ? 0 : write_idx + 1;
- end
- end
- end // always @ (posedge clock_50mhz)
-endmodule
-
-module winbond_spi(input wire clock_50mhz,
- input wire reset,
-
- input wire operate,
- input wire [31:0] send_data,
- input wire [2:0] bytes_to_send,
- input wire [14:0] bytes_to_receive,
-
- output reg byte_ready,
- output reg [7:0] received_data,
- output reg operation_finished,
-
- output reg sdo,
- input wire sdi,
- output wire sck,
- output reg ss_n
- );
- reg working;
- reg operating;
-
- reg [31:0] sdo_data;
- reg [5:0] bits_to_output;
-
- parameter sending = 0;
- parameter receiving = 1;
- reg state;
-
- reg [6:0] sdi_data;
- reg [17:0] bits_to_receive;
- reg [3:0] bits_received;
- reg send_only_operation;
-
- assign sck = clock_50mhz;
-
- always @ (posedge clock_50mhz) begin
- if (reset || !operate) begin
- operating <= 0;
- byte_ready <= 0;
- operation_finished <= 0;
-
- bits_to_receive <= 18'hXXXXX;
- bits_to_output <= 6'hXX;
- sdi_data <= 7'hXX;
- sdo_data <= 32'hXXXXXXXX;
- received_data <= 8'hXX;
- send_only_operation <= 1'bx;
- state <= 1'bx;
- end
- else begin
- operating <= 1;
-
- if (!operating && operate) begin
- bits_to_receive <= bytes_to_receive * 8;
- bits_to_output <= bytes_to_send * 8;
- sdo_data <= send_data;
- send_only_operation <= bytes_to_receive == 0;
- state <= sending;
- byte_ready <= 0;
- operation_finished <= 0;
-
- sdi_data <= 7'hXX;
- received_data <= 8'hXX;
- end
- else begin
- if (operation_finished) begin
- byte_ready <= 0;
-
- bits_to_receive <= 18'hXXXXX;
- bits_to_output <= 6'hXX;
- sdi_data <= 7'hXX;
- sdo_data <= 32'hXXXXXXXX;
- received_data <= 8'hXX;
- send_only_operation <= 1'bx;
- state <= 1'bx;
- end
- else begin
- if (state == sending) begin
- byte_ready <= 0;
- bits_to_output <= bits_to_output - 1;
- sdo_data <= {sdo_data[30:0], 1'bx};
-
- if (bits_to_output - 1 == 0) begin
- state <= receiving;
- if (send_only_operation)
- operation_finished <= 1;
- end
-
- sdi_data <= 7'hXX;
- received_data <= 8'hXX;
- end // if (state == sending)
-
- if (state == receiving) begin
-
- bits_to_receive <= bits_to_receive - 1;
- sdi_data <= {sdi_data[5:0], sdi};
-
- if (bits_to_receive % 8 - 1 == 0) begin
- byte_ready <= 1;
- received_data <= {sdi_data[6:0], sdi};
- end
- else begin
- byte_ready <= 0;
- received_data <= 8'hXX;
- end
-
- if (bits_to_receive - 1 == 0)
- operation_finished <= 1;
-
- bits_to_output <= 6'hXX;
- sdo_data <= 32'hXXXXXXXX;
- end // if (state == receiving)
- end // else: !if(operation_finished)
- end // else: !if(!operating && operate)
- end // else: !if(reset || !operate)
- end // always @ (posedge clock_50mhz)
-
- always @ (negedge clock_50mhz) begin
- sdo <= sdo_data[31];
-
- if (!operating) begin
- ss_n <= 1;
- end
- else begin
- if (operation_finished)
- ss_n <= 1;
- else
- ss_n <= 0;
- end
- end // always @ (negedge clock_50mhz)
-endmodule // winbond_spi
-
-module spi_chip_powerup(input wire clock_50mhz,
- input wire reset,
-
- output reg want_spi_operation,
- output wire [31:0] spi_send_data,
- output wire [2:0] spi_bytes_to_send,
- output wire [14:0] spi_bytes_to_receive,
-
- input wire spi_operation_finished,
-
- input wire operate,
- output reg finished_operating
- );
- parameter power_up_instruction = 8'hAB;
-
- assign spi_send_data = {power_up_instruction, 24'hXXXXXX};
- assign spi_bytes_to_send = 1;
- assign spi_bytes_to_receive = 0;
-
- parameter sending_power_up = 0;
- parameter waiting = 1;
- reg state;
-
- parameter freq = 50; /* Mhz */
- parameter powerup_wait_time = 3000; /* ns */
- parameter powerup_wait_ticks = powerup_wait_time * freq / 1000;
- reg [7:0] powerup_wait_counter;
-
- reg operating;
-
- always @ (posedge clock_50mhz) begin
- if (reset || !operate) begin
- want_spi_operation <= 0;
- finished_operating <= 0;
- operating <= 0;
-
- state <= 1'bx;
- powerup_wait_counter <= 8'hXX;
- end
- else begin
- operating <= 1;
-
- if (!operating && operate) begin
- want_spi_operation <= 1;
- finished_operating <= 0;
- state <= sending_power_up;
-
- powerup_wait_counter <= 8'hXX;
- end
- else begin
- if (state == sending_power_up) begin
- finished_operating <= 0;
-
- if (spi_operation_finished) begin
- powerup_wait_counter <= powerup_wait_ticks;
- state <= waiting;
- want_spi_operation <= 0;
- end
- else begin
- want_spi_operation <= 1;
-
- powerup_wait_counter <= 8'hXX;
- end
- end // if (state == sending_power_up)
-
- if (state == waiting) begin
- want_spi_operation <= 0;
-
- if (powerup_wait_counter == 0) begin
- finished_operating <= 1;
- end
- else begin
- finished_operating <= 0;
- powerup_wait_counter <= powerup_wait_counter - 1;
- end
- end // if (state == waiting)
- end // else: !if(!operating && operate)
- end // else: !if(reset || !operate)
- end // always @ (posedge clock_50mhz)
-endmodule // spi_chip_powerup
-
-module spi_sram_copy(input wire clock_50mhz,
- input wire reset,
-
- input wire can_write,
- output reg [15:0] write_data,
-
- output wire want_to_write, /* sram memory */
- output wire [17:0] write_addr,
-
- input wire [17:0] written_memory_base,
-
- output reg want_spi_operation,
- output wire [31:0] spi_send_data,
- output wire [2:0] spi_bytes_to_send,
- output wire [14:0] spi_bytes_to_receive,
-
- input wire spi_byte_ready,
- input wire [7:0] received_byte,
-
- input wire [23:0] flash_memory_base,
-
- input wire operate,
- output reg finished_operating
- );
- parameter fast_read_instruction = 8'h0B;
-
- parameter words_to_copy = 600;
-
- assign spi_bytes_to_send = 5;
-
- reg [9:0] words_left_to_receive;
- assign spi_bytes_to_receive = words_left_to_receive * 2;
-
- reg [9:0] word_idx;
-
- assign write_addr = written_memory_base + word_idx;
-
- wire [23:0] read_addr;
- assign read_addr = flash_memory_base + 16 * word_idx;
- assign spi_send_data = {fast_read_instruction, read_addr};
-
- reg write_word_ready;
- assign want_to_write = write_word_ready;
-
- wire write_happens;
- assign write_happens = want_to_write && can_write;
-
- reg [7:0] high_byte;
- reg high_byte_received;
-
- wire word_received;
- assign word_received = high_byte_received && spi_byte_ready;
-
- /* true if next spi data word came b4 we handled the previous one :c */
- wire data_discarded;
- assign data_discarded = word_received && write_word_ready && !write_happens;
-
- reg reading_finished;
-
- reg operating;
-
- always @ (posedge clock_50mhz) begin
- if (reset || !operate) begin
- operating <= 0;
- want_spi_operation <= 0;
- finished_operating <= 0;
- write_word_ready <= 0;
-
- words_left_to_receive <= 10'hXXX;
- word_idx <= 10'hXXX;
- high_byte <= 8'hXX;
- high_byte_received <= 1'bx;
- reading_finished <= 1'bx;
- end // if (reset || !operate)
- else begin
- operating <= 1;
-
- if (operate && !operating) begin
- want_spi_operation <= 1;
- finished_operating <= 0;
- write_word_ready <= 0;
- words_left_to_receive <= words_to_copy;
- word_idx <= 0;
- reading_finished <= 0;
- high_byte_received <= 0;
-
- high_byte <= 8'hXX;
- end // if (operate && !operating)
- else if (finished_operating) begin
- want_spi_operation <= 0;
- write_word_ready <= 0;
- words_left_to_receive <= 10'hXX;
- word_idx <= 10'hXX;
- reading_finished <= 1'bx;
- high_byte_received <= 1'bx;
- high_byte <= 8'hXX;
- end
- else begin
- /*
- * if spi data comes too fast, we discard it and start reading
- * anew once we write current data
- */
- if (reading_finished)
- want_spi_operation <= 0;
- else if (data_discarded)
- want_spi_operation <= 0;
- else if (write_happens)
- want_spi_operation <= 1;
-
- if (spi_byte_ready) begin
- if (high_byte_received) begin
- high_byte_received <= 0;
-
- high_byte <= 8'hXX;
- end
- else begin
- high_byte <= received_byte;
- high_byte_received <= 1;
- end
- end // if (spi_byte_ready)
-
- if (word_received && !data_discarded) begin
- words_left_to_receive <= words_left_to_receive - 1;
- write_word_ready <= 1;
- write_data <= {high_byte, received_byte};
-
- if (words_left_to_receive - 1 == 0)
- reading_finished <= 1;
- end
- else if (write_happens) begin
- write_word_ready <= 0;
- write_data <= 16'hXXXX;
- end
- else if (!write_word_ready) begin
- write_data <= 16'hXXXX;
- end
-
- if (write_happens) begin
- word_idx <= word_idx + 1;
-
- if (reading_finished)
- finished_operating <= 1;
- end
- end // else: !if(finished_operating)
- end // else: !if(reset || !operate)
- end // always @ (posedge clock_50mhz)
-endmodule // spi_sram_copy
-
-module top(input wire clock_100mhz,
- input wire but1,
- input wire but2,
-
- output reg [17:0] sram_addr,
- inout wire [15:0] sram_io,
- output reg sram_cs_n,
- output reg sram_oe_n,
- output reg sram_we_n,
-
- output wire h_sync,
- output wire v_sync,
- output wire [2:0] vga_red,
- output wire [2:0] vga_green,
- output wire [2:0] vga_blue,
-
- output wire sdo,
- input wire sdi,
- output wire sck,
- output wire ss_n
- );
- /*
- * We use a reg to snapshot (and invert) the reset signal
- * (actually button1). If we didn't snapshot it, we'd get
- * timing problems
- */
- reg reset;
-
- reg err_disabled;
-
- reg clock_50mhz;
- /*
- * `initial` usually isn't synthesizable, but it helps run the code
- * in test-benches
- */
- initial begin
- reset <= 1;
- clock_50mhz <= 0;
- err_disabled <= 0;
- end
-
- always @ (posedge clock_100mhz)
- clock_50mhz <= clock_50mhz + 1;
-
- parameter memory_base = 18'b010101010101010101;
- parameter flash_base = 24'h000000;
-
- wire vga_io_available;
- assign vga_io_available = 1;
- wire vga_wants_io;
- wire [17:0] vga_io_addr;
-
- vga_hexmode vga(clock_50mhz, reset, vga_io_available, sram_io, vga_wants_io,
- vga_io_addr, memory_base,
- h_sync, v_sync, vga_red, vga_green, vga_blue);
-
- reg last_reset;
- always @ (posedge clock_50mhz)
- last_reset <= reset;
-
- wire spi_operation_wanted;
- wire [31:0] spi_send_data;
- wire [2:0] spi_bytes_to_send;
- wire [14:0] spi_bytes_to_receive;
- wire spi_byte_ready;
- wire [7:0] spi_received_data;
- wire spi_operation_finished;
-
- winbond_spi spi(clock_50mhz, reset, spi_operation_wanted,
- spi_send_data, spi_bytes_to_send,
- spi_bytes_to_receive, spi_byte_ready,
- spi_received_data, spi_operation_finished,
- sdo, sdi, sck, ss_n);
-
- wire chip_powerup_wants_operation;
- wire [31:0] chip_powerup_send_data;
- wire [2:0] chip_powerup_bytes_to_send;
- wire [14:0] chip_powerup_bytes_to_receive;
- wire chip_powerup_finished_operating;
-
- spi_chip_powerup chip_powerup(clock_50mhz, reset,
- chip_powerup_wants_operation,
- chip_powerup_send_data,
- chip_powerup_bytes_to_send,
- chip_powerup_bytes_to_receive,
- spi_operation_finished, !reset,
- chip_powerup_finished_operating);
-
- wire data_copy_sram_io_available;
- assign data_copy_sram_io_available = vga_io_available && !vga_wants_io;
- wire [15:0] data_copy_write_data;
- wire data_copy_wants_sram_io;
- wire [17:0] data_copy_sram_io_addr;
- wire data_copy_wants_spi_operation;
- wire [31:0] data_copy_spi_send_data;
- wire [2:0] data_copy_spi_bytes_to_send;
- wire [14:0] data_copy_spi_bytes_to_receive;
- wire data_copy_finished_operating;
-
- spi_sram_copy data_copy(clock_50mhz, reset, data_copy_sram_io_available,
- data_copy_write_data, data_copy_wants_sram_io,
- data_copy_sram_io_addr, memory_base,
- data_copy_wants_spi_operation,
- data_copy_spi_send_data, data_copy_spi_bytes_to_send,
- data_copy_spi_bytes_to_receive, spi_byte_ready,
- spi_received_data, flash_base,
- chip_powerup_finished_operating,
- data_copy_finished_operating);
-
- assign {
- spi_operation_wanted,
- spi_send_data,
- spi_bytes_to_send,
- spi_bytes_to_receive
- }
- = !chip_powerup_finished_operating ?
- {
- chip_powerup_wants_operation,
- chip_powerup_send_data,
- chip_powerup_bytes_to_send,
- chip_powerup_bytes_to_receive
- } :
- !data_copy_finished_operating ?
- {
- data_copy_wants_spi_operation,
- data_copy_spi_send_data,
- data_copy_spi_bytes_to_send,
- data_copy_spi_bytes_to_receive
- } :
- {1'b0, 32'hXXXXXXXX, 3'hX, 15'hXXXX};
-
- wire butwrite_io_available;
- assign butwrite_io_available = data_copy_sram_io_available
- && !data_copy_wants_sram_io;
-
- wire butwrite_wants_io;
- wire [17:0] butwrite_io_addr;
- wire [15:0] butwrite_write_data;
-
- on_button_write butwrite(clock_50mhz, reset, butwrite_io_available,
- butwrite_write_data, butwrite_wants_io,
- butwrite_io_addr, memory_base, but2);
-
- reg [15:0] write_data;
- reg write_in_progress;
-
- always @ (posedge clock_50mhz) begin
- reset <= !but1 || err_disabled;
-
- if (!but1)
- err_disabled <= 0;
-
- if (reset) begin
- err_disabled <= 0;
- write_in_progress <= 0;
- sram_oe_n <= 1'b1;
- sram_cs_n <= 1'b1;
- write_data <= 16'bxxxxxxxxxxxxxxxx;
- end
- else begin
- if (vga_wants_io) begin
- write_in_progress <= 0;
- sram_oe_n <= 1'b0;
- sram_cs_n <= 1'b0;
- sram_addr <= vga_io_addr;
- end
- else if (data_copy_wants_sram_io) begin
- write_in_progress <= 1;
- sram_oe_n <= 1'b1;
- sram_cs_n <= 1'b0;
- sram_addr <= data_copy_sram_io_addr;
- write_data <= data_copy_write_data;
- end
- else if (butwrite_wants_io) begin
- write_in_progress <= 1;
- sram_oe_n <= 1'b1;
- sram_cs_n <= 1'b0;
- sram_addr <= butwrite_io_addr;
- write_data <= butwrite_write_data;
- if (butwrite_io_addr > memory_base + 30)
- err_disabled <= 1;
- end
- else begin
- write_in_progress <= 0;
- sram_oe_n <= 1'b1;
- sram_cs_n <= 1'b1;
- end
- end
- end // always @ (posedge clock_50mhz)
-
- always @ (negedge clock_100mhz) begin
- if (reset) begin
- sram_we_n <= 1'b1;
- end
- else begin
- if (write_in_progress)
- sram_we_n <= !sram_we_n;
- else
- sram_we_n <= 1'b1;
- end
- end
-
- assign sram_io = sram_we_n ? 16'bzzzzzzzzzzzzzzzz : write_data;
-endmodule // top
diff --git a/src/letter_A.png b/src/letter_A.png
deleted file mode 100644
index f8787e2..0000000
--- a/src/letter_A.png
+++ /dev/null
Binary files differ
diff --git a/src/letter_B.png b/src/letter_B.png
deleted file mode 100644
index 6b47b03..0000000
--- a/src/letter_B.png
+++ /dev/null
Binary files differ
diff --git a/src/letter_C.png b/src/letter_C.png
deleted file mode 100644
index ebc0ed6..0000000
--- a/src/letter_C.png
+++ /dev/null
Binary files differ
diff --git a/src/letter_D.png b/src/letter_D.png
deleted file mode 100644
index 36ce8a5..0000000
--- a/src/letter_D.png
+++ /dev/null
Binary files differ
diff --git a/src/letter_E.png b/src/letter_E.png
deleted file mode 100644
index 826ed78..0000000
--- a/src/letter_E.png
+++ /dev/null
Binary files differ
diff --git a/src/letter_F.png b/src/letter_F.png
deleted file mode 100644
index 10df13d..0000000
--- a/src/letter_F.png
+++ /dev/null
Binary files differ
diff --git a/src/mapping.pcf b/src/mapping.pcf
deleted file mode 100644
index afdadc4..0000000
--- a/src/mapping.pcf
+++ /dev/null
@@ -1,62 +0,0 @@
-set_io clock_100mhz J3
-
-set_io but1 K11 # actually used as reset
-set_io but2 P13
-
-set_io h_sync J4
-set_io v_sync H2
-set_io vga_red[0] E3
-set_io vga_red[1] H5
-set_io vga_red[2] F3
-set_io vga_green[0] F2
-set_io vga_green[1] H6
-set_io vga_green[2] H3
-set_io vga_blue[0] F1
-set_io vga_blue[1] H4
-set_io vga_blue[2] G2
-
-set_io sram_addr[0] N6
-set_io sram_addr[1] T1
-set_io sram_addr[2] P4
-set_io sram_addr[3] R2
-set_io sram_addr[4] N5
-set_io sram_addr[5] T2
-set_io sram_addr[6] P5
-set_io sram_addr[7] R3
-set_io sram_addr[8] R5
-set_io sram_addr[9] T3
-set_io sram_addr[10] R4
-set_io sram_addr[11] M7
-set_io sram_addr[12] N7
-set_io sram_addr[13] P6
-set_io sram_addr[14] M8
-set_io sram_addr[15] T5
-set_io sram_addr[16] R6
-set_io sram_addr[17] P8
-
-set_io sram_io[0] T8
-set_io sram_io[1] P7
-set_io sram_io[2] N9
-set_io sram_io[3] T9
-set_io sram_io[4] M9
-set_io sram_io[5] R9
-set_io sram_io[6] K9
-set_io sram_io[7] P9
-set_io sram_io[8] R10
-set_io sram_io[9] L10
-set_io sram_io[10] P10
-set_io sram_io[11] N10
-set_io sram_io[12] T10
-set_io sram_io[13] T11
-set_io sram_io[14] T15
-set_io sram_io[15] T14
-
-set_io sram_cs_n T6
-set_io sram_oe_n L9
-set_io sram_we_n T7
-
-# SPI to on-board chip
-set_io sdo P12
-set_io sdi P11
-set_io sck R11
-set_io ss_n R12
diff --git a/src/number_0.png b/src/number_0.png
deleted file mode 100644
index f8a1742..0000000
--- a/src/number_0.png
+++ /dev/null
Binary files differ
diff --git a/src/number_1.png b/src/number_1.png
deleted file mode 100644
index a2b4b66..0000000
--- a/src/number_1.png
+++ /dev/null
Binary files differ
diff --git a/src/number_2.png b/src/number_2.png
deleted file mode 100644
index 0af34dd..0000000
--- a/src/number_2.png
+++ /dev/null
Binary files differ
diff --git a/src/number_3.png b/src/number_3.png
deleted file mode 100644
index 5483902..0000000
--- a/src/number_3.png
+++ /dev/null
Binary files differ
diff --git a/src/number_4.png b/src/number_4.png
deleted file mode 100644
index 3b6a6d4..0000000
--- a/src/number_4.png
+++ /dev/null
Binary files differ
diff --git a/src/number_5.png b/src/number_5.png
deleted file mode 100644
index 710cd3e..0000000
--- a/src/number_5.png
+++ /dev/null
Binary files differ
diff --git a/src/number_6.png b/src/number_6.png
deleted file mode 100644
index 36e8c3c..0000000
--- a/src/number_6.png
+++ /dev/null
Binary files differ
diff --git a/src/number_7.png b/src/number_7.png
deleted file mode 100644
index ca13f4d..0000000
--- a/src/number_7.png
+++ /dev/null
Binary files differ
diff --git a/src/number_8.png b/src/number_8.png
deleted file mode 100644
index 17b1fdc..0000000
--- a/src/number_8.png
+++ /dev/null
Binary files differ
diff --git a/src/number_9.png b/src/number_9.png
deleted file mode 100644
index f887222..0000000
--- a/src/number_9.png
+++ /dev/null
Binary files differ
diff --git a/tclasm.tcl b/tclasm.tcl
new file mode 100755
index 0000000..8c89eeb
--- /dev/null
+++ b/tclasm.tcl
@@ -0,0 +1,337 @@
+#!/bin/grep this[ ]script
+# this script is to be sourced, not executed by itself
+
+# procedures starting with "__" are internal and not to be used in asm code;
+# procedures starting with "_" are generalized procedures, that are not meant
+# to be directly used for code translated from webasm;
+# the rest are typical procedures webasm code will be mapped to
+
+proc __parse_binary {binary} {
+ set value 0
+
+ for {set bits_remaining $binary} \
+ {"$bits_remaining" != ""} \
+ {set bits_remaining [string range $bits_remaining 1 end]} {
+ set value [expr $value * 2]
+
+ if [string match 1* $bits_remaining] {
+ incr value
+ } elseif [string match 0* $bits_remaining] {
+ # nothing
+ } else {
+ error "'$binary' cannot be parsed as a binary number"
+ }
+ }
+
+ return $value
+}
+
+proc __parse_number {number} {
+ if [string match h?* $number] {
+ set value 0x[string range $number 1 end]
+ } elseif [string match b?* $number] {
+ set value [__parse_binary [string range $number 1 end]]
+ } elseif [string match {d[0123456789]?*} $number] {
+ set value [string range $number 1 end]
+ } elseif [string match {-[0123456789]*} $number] {
+ set value $number
+ } elseif [string match {[0123456789]*} $number] {
+ set value $number
+ } else {
+ error "'$number' is not a properly formatted number"
+ }
+
+ return $value
+}
+
+proc __to_binary {number length {can_be_negative -neg_ok}} {
+ if [string equal $can_be_negative -neg_ok] {
+ set can_be_negative 1
+ } elseif [string equal $can_be_negative -no_neg] {
+ set can_be_negative 0
+ } else {
+ error "'$can_be_negative' is not a valid value for the\
+ 'can_be_negative' argument"
+ }
+
+ set value [__parse_number $number]
+
+ if {$value < 0 && !$can_be_negative} {
+ error "value '$number' provided where negative values are not allowed"
+ }
+
+ if {($can_be_negative && $value >= 2 ** ($length - 1)) ||
+ $value >= 2 ** $length ||
+ $value < -(2 ** ($length - 1))} {
+ error "value '$number' doesn't fit into $length\
+ bits[expr $can_be_negative ? "{ with sign}" : "{}"]"
+ }
+
+ for {set result ""} {$length > 0} {incr length -1} {
+ set result [expr $value % 2]$result
+ set value [expr $value >> 1]
+ }
+
+ return $result
+}
+
+# example: __encode_immediate im+=213
+# __encode_immediate im<<=hAB
+# __encode_immediate im=im
+# __encode_immediate im=-33 # negative value only allowed for im=
+# __encode_immediate im<<=b1101101
+proc __encode_immediate {im_modification} {
+ if [string equal $im_modification im=im] {
+ return 000000000000
+ } elseif [string match im<<=?* $im_modification] {
+ return 1[__to_binary [string range $im_modification 5 end] 11 -no_neg]
+ } elseif [string match im=?* $im_modification] {
+ return 01[__to_binary [string range $im_modification 3 end] 10]
+ } elseif [string match im+=?* $im_modification] {
+ return 001[__to_binary [string range $im_modification 4 end] 9 -no_neg]
+ } else {
+ error "'$im_modification' is not a valid im modification"
+ }
+}
+
+# example: __encode_access_type load
+# __encode_access_type store
+proc __encode_access_type {type} {
+ if {"$type" == "load"} {
+ return 1
+ } elseif {"$type" == "store"} {
+ return 0
+ } else {
+ error "'$type' is not a valid memory access type"
+ }
+}
+
+# example: __encode_addressing @im
+# __encode_addressing @im+sp
+proc __encode_addressing {address} {
+ if {"$address" == "@im"} {
+ return 1
+ } elseif {"$address" == "@im+sp"} {
+ return 0
+ } else {
+ error "'$address' is not a valid addressing"
+ }
+}
+
+# example: __encode_reg r0
+# __encode_reg r1
+proc __encode_reg {register} {
+ if {"$register" == "r0"} {
+ return 1
+ } elseif {"$register" == "r1"} {
+ return 0
+ } else {
+ error "'$register' is not a valid register"
+ }
+v}
+
+# example: __encode_memory_access load r0 @im im=d1840
+# __encode_memory_access store r1 @im+sp im<<=b1100011
+proc __encode_memory_access {type register address {im_modification im=im}} {
+ set type [__encode_access_type $type]
+ set address [__encode_addressing $address]
+ set register [__encode_reg $register]
+ set im_modification [__encode_immediate $im_modification]
+ return 1$type$address$register$im_modification
+}
+
+# example: __encode_swap swap
+# __encode_swap no_swap
+proc __encode_swap {swap_regs} {
+ if {"$swap_regs" == "swap"} {
+ return 1
+ } elseif {"$swap_regs" == "no_swap"} {
+ return 0
+ } else {
+ error "got '$swap_regs' where 'swap' or 'no_swap' was expected"
+ }
+}
+
+# example: __encode_swap swap
+# __encode_swap no_swap
+proc __encode_cond {cond} {
+ if {"$cond" == "cond"} {
+ return 1
+ } elseif {"$cond" == "non-cond"} {
+ return 0
+ } else {
+ error "got '$cond' where 'cond' or 'non-cond' was expected"
+ }
+}
+
+# example: __encode_extended_instruction halt
+# __encode_extended_instruction nop
+proc __encode_extended_instruction {instruction} {
+ if {"$instruction" == "nop"} {
+ return [__to_binary 0 9]
+ } elseif {"$instruction" == "halt"} {
+ return [__to_binary 1 9]
+ } elseif {"$instruction" == "set_sp"} {
+ return [__to_binary 2 9]
+ } elseif {"$instruction" == "add"} {
+ return [__to_binary 3 9]
+ } elseif {"$instruction" == "sub"} {
+ return [__to_binary 4 9]
+ } elseif {"$instruction" == "div"} {
+ return [__to_binary 5 9]
+ } elseif {"$instruction" == "mul"} {
+ return [__to_binary 6 9]
+ } else {
+ error "no such extended instruction: '$instruction'"
+ }
+}
+
+# example: _load r0 @im im+=2 # negative values are *not* allowed for im+=
+# _load r1 @im im=im
+# _load r0 @im+sp # im=im is the default if not specified
+# _load r0 @im im<<=12 # 12 is the value shifted, shift is always by 11
+# _load r1 @im im=-9 # negative values are only allowed for im=
+# _load r0 @im+sp im=0 # this results in using only sp for addressing
+proc _load {register address {im_modification im=im}} {
+ puts [__encode_memory_access load $register $address $im_modification]
+}
+
+# example: _store r0 @im im+=2 # same semantics as _load
+# _store r1 @im im=im
+# _store r0 @im+sp
+# _store r0 @im im<<=12
+# _store r1 @im im=-9
+# _store r0 @im+sp im=0
+proc _store {register address {im_modification im=im}} {
+ puts [__encode_memory_access store $register $address $im_modification]
+}
+
+# example: _jump im<<=b1101011 cond swap
+# _jump im=im non-cond
+proc _jump {{im_modification im=im} {cond non-cond} {swap_regs no_swap}} {
+ set swap_regs [__encode_swap $swap_regs]
+ set cond [__encode_cond $cond]
+ puts 01$cond$swap_regs[__encode_immediate $im_modification]
+}
+
+# example: _extended_instruction nop swap # it's really no longer a true nop...
+# _extended_instruction halt
+proc _extended_instruction {instruction {swap_regs no_swap}} {
+ set swap_regs [__encode_swap $swap_regs]
+ set no_im_modification 000
+ set instruction [__encode_extended_instruction $instruction]
+ puts 000$swap_regs$no_im_modification$instruction
+}
+
+# example: _immediate im+=4 swap
+# _immediate im<<=hFF
+# _immediate im=im # this one gives the same bit result as 'nop'
+proc _immediate {im_modification {swap_regs no_swap}} {
+ set swap_regs [__encode_swap $swap_regs]
+ set im_modification [__encode_immediate $im_modification]
+ puts 000$swap_regs$im_modification
+}
+
+# example: _exchange_im im<<=b10101010101 swap
+proc _exchange_im {{im_modification im=im} {swap_regs no_swap}} {
+ set swap_regs [__encode_swap $swap_regs]
+ set im_modification [__encode_immediate $im_modification]
+ puts 001$swap_regs$im_modification
+}
+
+proc _const {command number} {
+
+ set value [expr [__parse_number $number] + 0]
+ if {$value < 2 ** 9 && $value >= -(2 ** 9)} {
+ $command im=$value
+ } elseif {$value < 2 ** 20 && $value >= -(2 ** 20)} {
+ _immediate im=[expr $value >> 11]
+ $command im<<=[expr $value & 0x7ff]
+ } elseif {$value < 2 ** 32 && $value >= -(2 ** 31)} {
+ # remove sign
+ set value [expr $value & (2 ** 32 - 1)]
+
+ _immediate im<<=[expr $value >> 22]
+ _immediate im<<=[expr ($value >> 11) & 0x7ff]
+ $command im<<=[expr $value & 0x7ff]
+ } else {
+ error "number '$number' doesn't fit in 32 bits"
+ }
+}
+
+# example: stack up
+# stack down
+proc stack {direction} {
+ if {"$direction" == "up"} {
+ _load r0 @im+sp im=4
+ } elseif {"$direction" == "down"} {
+ _store r0 @im+sp im=0
+ } else {
+ error "bad opcode: stack $direction"
+ }
+}
+
+# example: store im<<=00000000000
+proc store {{im_modification im=im}} {
+ _store r1 @im $im_modification
+}
+
+# example: load im=hDD
+proc load {{im_modification im=im}} {
+ _load r1 @im $im_modification
+}
+
+# example: jump im=h1dd
+# jump # im=im is the default if not specified
+proc jump {{im_modification im=im}} {
+ _jump $im_modification non-cond
+}
+
+# example: cond_jump im=h00FE
+# cond_jump # im=im is the default if not specified
+proc cond_jump {{im_modification im=im}} {
+ _jump $im_modification cond
+}
+
+foreach instruction {halt nop swap add sub div mul} {
+ proc $instruction {} "
+ _extended_instruction $instruction
+ "
+}
+
+proc swap {} {
+ _extended_instruction nop swap
+}
+
+
+# example: exchange_im im+=15
+proc exchange_im {{im_modification im=im}} {
+ _exchange_im $im_modification
+}
+
+# example: const -100249
+# const hDEADBEEF # automatically translates to multiple instructions
+proc const {number} {
+ _const _exchange_im $number
+}
+
+# example: immediate b11101101010000010100010 # analogous to 'const' above
+proc immediate {number} {
+ _const _immediate $number
+}
+
+# example: set_sp h2FFFE # analogous to 'const' and 'immediate' above
+proc set_sp {number} {
+ immediate $number
+ _extended_instruction set_sp
+}
+
+# example: store@ h57574
+proc store@ {address_number} {
+ _const store $address_number
+}
+
+# example: load@ h20000
+proc load@ {address_number} {
+ _const load $address_number
+}
diff --git a/tests/div/test.v b/tests/div/test.v
new file mode 100644
index 0000000..f360ebd
--- /dev/null
+++ b/tests/div/test.v
@@ -0,0 +1,108 @@
+`default_nettype none
+
+`include "messages.vh"
+
+`ifndef SIMULATION
+ `error_SIMULATION_not_defined
+; /* Cause syntax error */
+`endif
+
+module div_test();
+ reg clock;
+ reg start;
+ reg [15:0] dividend;
+ reg [15:0] divisor;
+
+ wire [15:0] quotient;
+ wire [15:0] remainder;
+ wire done;
+
+ div
+ #(
+ .WIDTH(16)
+ ) div
+ (
+ .clock(clock),
+ .start(start),
+ .dividend(dividend),
+ .divisor(divisor),
+ .quotient(quotient),
+ .remainder(remainder),
+ .done(done)
+ );
+
+ integer seed;