konilo

Check-in [95e971fd44]
Login

Check-in [95e971fd44]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:merge vhdl implementation into the tree; simulation with ghdl works; not tested on actual hardware yet
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | trunk
Files: files | file ages | folders
SHA3-256: 95e971fd442d40083dd5b89820806145b4840b43af8a26098d39945ee662a15a
User & Date: crc 2026-06-26 12:57:42.003
Context
2026-06-26
12:57
merge vhdl implementation into the tree; simulation with ghdl works; not tested on actual hardware yet Leaf check-in: 95e971fd44 user: crc tags: trunk
12:51
merge ilo-wasm.wat, a webassembly version of ilo for wasmtime check-in: 0d2723f940 user: crc tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to RELEASE.txt.
45
46
47
48
49
50
51

52
53
54
55
56
57
58
  - Python
  - RetroForth
  - Rust
  - Scheme
  - Smalltalk
  - Swift
  - TypeScript

  - WebAssembly
  - Zig

  - x86-native (C & assembly)
  - x86 assembly (DOS)

- Precompiled binaries for ilo for a variety of hosts:







>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  - Python
  - RetroForth
  - Rust
  - Scheme
  - Smalltalk
  - Swift
  - TypeScript
  - VHDL
  - WebAssembly
  - Zig

  - x86-native (C & assembly)
  - x86 assembly (DOS)

- Precompiled binaries for ilo for a variety of hosts:
190
191
192
193
194
195
196





197
198
199
200
201
202
203

  - new implementation: gfortran, Fortran 77

- ilo-wasm.wat

  - new implementation (webassembly; for wasmtime)






IMAGE

- dictionary data now in konilo.pali instead of being built by
  separate preprocessor
- inlined use of `tuck` (as `i dupuswpo`) at various points
- `n:to-s` save a call/return per character
- `n:limit` now falls through into `n:max`, saving a jump







>
>
>
>
>







191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

  - new implementation: gfortran, Fortran 77

- ilo-wasm.wat

  - new implementation (webassembly; for wasmtime)

- vhdl

  - new VHDL implementation (can simulate w/ghdl)
    Planned eventual fpga targets [cmod a7-35t, icepi zero]

IMAGE

- dictionary data now in konilo.pali instead of being built by
  separate preprocessor
- inlined use of `tuck` (as `i dupuswpo`) at various points
- `n:to-s` save a call/return per character
- `n:limit` now falls through into `n:max`, saving a jump
Added ilo-vm/vhdl/Makefile.














































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
SHELL := /bin/sh

.PHONY: all test ghdl-test compare synth synth-generic synth-generic-opt synth-generic-full synth-ice40 synth-ecp5 synth-xc7 synth-xc7+sram icepi-zero icepi-zero-sdram interactive clean distclean help

all: test

test: ghdl-test

ghdl-test:
	./scripts/run-ghdl-tests.sh

compare:
	./scripts/compare-c-vhdl.sh

synth:
	./scripts/synth-yosys.sh

synth-generic:
	./scripts/synth-yosys.sh generic

synth-generic-opt:
	./scripts/synth-yosys.sh generic-opt

synth-generic-full:
	./scripts/synth-yosys.sh generic-full

synth-ice40:
	./scripts/synth-yosys.sh ice40

synth-ecp5:
	./scripts/synth-yosys.sh ecp5

synth-xc7:
	./scripts/synth-yosys.sh xc7

synth-xc7+sram:
	./scripts/synth-yosys.sh xc7+sram

icepi-zero:
	./scripts/build-icepi-zero.sh

icepi-zero-sdram:
	./scripts/build-icepi-zero.sh --sdram

interactive:
	@if [ -z "$(ROM)" ]; then \
		echo "usage: make interactive ROM=path/to/ilo.rom [BLOCKS=path/to/ilo.blocks] [MODE=--sdram] [MAX_CYCLES=0] [CLOCK_PERIOD_NS=10]" >&2; \
		exit 2; \
	fi
	@set -- $(MODE) "$(ROM)"; \
	if [ -n "$(BLOCKS)" ]; then set -- "$$@" "$(BLOCKS)"; fi; \
	if [ -n "$(MAX_CYCLES)" ]; then set -- "$$@" "$(MAX_CYCLES)"; fi; \
	if [ -n "$(CLOCK_PERIOD_NS)" ]; then set -- "$$@" "$(CLOCK_PERIOD_NS)"; fi; \
	./scripts/run-ilo-rom-interactive.sh "$$@"

clean:
	rm -rf build work-obj*.cf *_tb *_top_tb *.o e~*.o scripts/__pycache__

help:
	@printf '%s\n' \
	  'Targets:' \
	  '  make test              Run the GHDL regression suite' \
	  '  make compare           Compare C VM and VHDL stack results' \
	  '  make synth             Run generic Yosys synthesis for ilo_core' \
	  '  make synth-ecp5        Run ECP5 synthesis for ilo_core' \
	  '  make synth-xc7         Run Xilinx 7-series synthesis for ilo_core' \
	  '  make synth-xc7+sram    Run Xilinx 7-series synthesis for Cmod A7 SRAM top' \
	  '  make icepi-zero        Build the ICEPI Zero smoke bitstream' \
	  '  make icepi-zero-sdram  Build the ICEPI Zero SDRAM bitstream' \
	  '  make interactive ROM=... [BLOCKS=...] [MODE=--sdram]' \
	  '  make clean             Remove generated simulation/build output'
Added ilo-vm/vhdl/constraints/cmod_a7.xdc.




































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
## ilo-vhdl Cmod A7 Rev. B constraints.
## Pin mappings are from Digilent Cmod-A7-Master.xdc.

set_property -dict { PACKAGE_PIN L17 IOSTANDARD LVCMOS33 } [get_ports { sysclk }]
create_clock -add -name sys_clk_pin -period 83.33 -waveform {0 41.66} [get_ports { sysclk }]

set_property -dict { PACKAGE_PIN A18 IOSTANDARD LVCMOS33 } [get_ports { btn[0] }]
set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { btn[1] }]

set_property -dict { PACKAGE_PIN A17 IOSTANDARD LVCMOS33 } [get_ports { led[0] }]
set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { led[1] }]
set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { led0_b }]
set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { led0_g }]
set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { led0_r }]

set_property -dict { PACKAGE_PIN J18 IOSTANDARD LVCMOS33 } [get_ports { uart_rxd_out }]
set_property -dict { PACKAGE_PIN J17 IOSTANDARD LVCMOS33 } [get_ports { uart_txd_in }]

set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[0] }]
set_property -dict { PACKAGE_PIN M19 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[1] }]
set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[2] }]
set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[3] }]
set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[4] }]
set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[5] }]
set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[6] }]
set_property -dict { PACKAGE_PIN W19 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[7] }]
set_property -dict { PACKAGE_PIN U19 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[8] }]
set_property -dict { PACKAGE_PIN V19 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[9] }]
set_property -dict { PACKAGE_PIN W18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[10] }]
set_property -dict { PACKAGE_PIN T17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[11] }]
set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[12] }]
set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[13] }]
set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[14] }]
set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[15] }]
set_property -dict { PACKAGE_PIN W16 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[16] }]
set_property -dict { PACKAGE_PIN W17 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[17] }]
set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { MemAdr[18] }]

set_property -dict { PACKAGE_PIN W15 IOSTANDARD LVCMOS33 } [get_ports { MemDB[0] }]
set_property -dict { PACKAGE_PIN W13 IOSTANDARD LVCMOS33 } [get_ports { MemDB[1] }]
set_property -dict { PACKAGE_PIN W14 IOSTANDARD LVCMOS33 } [get_ports { MemDB[2] }]
set_property -dict { PACKAGE_PIN U15 IOSTANDARD LVCMOS33 } [get_ports { MemDB[3] }]
set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { MemDB[4] }]
set_property -dict { PACKAGE_PIN V13 IOSTANDARD LVCMOS33 } [get_ports { MemDB[5] }]
set_property -dict { PACKAGE_PIN V14 IOSTANDARD LVCMOS33 } [get_ports { MemDB[6] }]
set_property -dict { PACKAGE_PIN U14 IOSTANDARD LVCMOS33 } [get_ports { MemDB[7] }]

set_property -dict { PACKAGE_PIN P19 IOSTANDARD LVCMOS33 } [get_ports { RamOEn }]
set_property -dict { PACKAGE_PIN R19 IOSTANDARD LVCMOS33 } [get_ports { RamWEn }]
set_property -dict { PACKAGE_PIN N19 IOSTANDARD LVCMOS33 } [get_ports { RamCEn }]
Added ilo-vm/vhdl/constraints/icepi_zero.lpf.




































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=ENABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;

BLOCK RESETPATHS;
BLOCK ASYNCPATHS;

# ICEPI Zero v1.3 subset for ilo-vhdl smoke top.

LOCATE COMP "clk" SITE "M1";
IOBUF  PORT "clk" IO_TYPE=LVCMOS33 PULLMODE=NONE;
FREQUENCY PORT "clk" 50 MHZ;

LOCATE COMP "usb_tx" SITE "K15";
IOBUF  PORT "usb_tx" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
LOCATE COMP "usb_rx" SITE "K16";
IOBUF  PORT "usb_rx" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;

LOCATE COMP "led[0]" SITE "E13";
IOBUF  PORT "led[0]" IO_TYPE=LVCMOS33 PULLMODE=DOWN DRIVE=4;
LOCATE COMP "led[1]" SITE "D14";
IOBUF  PORT "led[1]" IO_TYPE=LVCMOS33 PULLMODE=DOWN DRIVE=4;
LOCATE COMP "led[2]" SITE "E12";
IOBUF  PORT "led[2]" IO_TYPE=LVCMOS33 PULLMODE=DOWN DRIVE=4;
LOCATE COMP "led[3]" SITE "C13";
IOBUF  PORT "led[3]" IO_TYPE=LVCMOS33 PULLMODE=DOWN DRIVE=4;
LOCATE COMP "led[4]" SITE "D13";
IOBUF  PORT "led[4]" IO_TYPE=LVCMOS33 PULLMODE=DOWN DRIVE=4;

LOCATE COMP "button[0]" SITE "C4";
IOBUF  PORT "button[0]" IO_TYPE=LVCMOS33 PULLMODE=UP DRIVE=4;
LOCATE COMP "button[1]" SITE "C5";
IOBUF  PORT "button[1]" IO_TYPE=LVCMOS33 PULLMODE=UP DRIVE=4;

LOCATE COMP "sdram_a[0]" SITE "B10";
IOBUF  PORT "sdram_a[0]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[1]" SITE "A9";
IOBUF  PORT "sdram_a[1]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[2]" SITE "B9";
IOBUF  PORT "sdram_a[2]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[3]" SITE "A8";
IOBUF  PORT "sdram_a[3]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[4]" SITE "B8";
IOBUF  PORT "sdram_a[4]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[5]" SITE "A7";
IOBUF  PORT "sdram_a[5]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[6]" SITE "B7";
IOBUF  PORT "sdram_a[6]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[7]" SITE "A6";
IOBUF  PORT "sdram_a[7]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[8]" SITE "B6";
IOBUF  PORT "sdram_a[8]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[9]" SITE "A5";
IOBUF  PORT "sdram_a[9]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[10]" SITE "A10";
IOBUF  PORT "sdram_a[10]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[11]" SITE "B5";
IOBUF  PORT "sdram_a[11]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_a[12]" SITE "A4";
IOBUF  PORT "sdram_a[12]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;

LOCATE COMP "sdram_dq[0]" SITE "B16";
IOBUF  PORT "sdram_dq[0]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[1]" SITE "C14";
IOBUF  PORT "sdram_dq[1]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[2]" SITE "C16";
IOBUF  PORT "sdram_dq[2]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[3]" SITE "C15";
IOBUF  PORT "sdram_dq[3]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[4]" SITE "D16";
IOBUF  PORT "sdram_dq[4]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[5]" SITE "A15";
IOBUF  PORT "sdram_dq[5]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[6]" SITE "B15";
IOBUF  PORT "sdram_dq[6]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[7]" SITE "A14";
IOBUF  PORT "sdram_dq[7]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[8]" SITE "A2";
IOBUF  PORT "sdram_dq[8]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[9]" SITE "B2";
IOBUF  PORT "sdram_dq[9]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[10]" SITE "E2";
IOBUF  PORT "sdram_dq[10]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[11]" SITE "D1";
IOBUF  PORT "sdram_dq[11]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[12]" SITE "C2";
IOBUF  PORT "sdram_dq[12]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[13]" SITE "C1";
IOBUF  PORT "sdram_dq[13]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[14]" SITE "C3";
IOBUF  PORT "sdram_dq[14]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dq[15]" SITE "B1";
IOBUF  PORT "sdram_dq[15]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;

LOCATE COMP "sdram_ba[0]" SITE "A11";
IOBUF  PORT "sdram_ba[0]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_ba[1]" SITE "B11";
IOBUF  PORT "sdram_ba[1]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;

LOCATE COMP "sdram_dqm[0]" SITE "B14";
IOBUF  PORT "sdram_dqm[0]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_dqm[1]" SITE "B3";
IOBUF  PORT "sdram_dqm[1]" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;

LOCATE COMP "sdram_csn" SITE "B12";
IOBUF  PORT "sdram_csn" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_cke" SITE "B4";
IOBUF  PORT "sdram_cke" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_clk" SITE "A3";
IOBUF  PORT "sdram_clk" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_wen" SITE "A13";
IOBUF  PORT "sdram_wen" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_casn" SITE "B13";
IOBUF  PORT "sdram_casn" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
LOCATE COMP "sdram_rasn" SITE "A12";
IOBUF  PORT "sdram_rasn" IO_TYPE=LVCMOS33 PULLMODE=NONE DRIVE=4;
Added ilo-vm/vhdl/rtl/boards/cmod_a7_top.vhd.














































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.ilo_pkg.all;

entity cmod_a7_top is
  generic (
    UART_CLKS_PER_BIT : positive := 104;
    SRAM_READ_WAIT_CYCLES : natural := 1;
    SRAM_WRITE_WAIT_CYCLES : natural := 1;
    RESET_CYCLES : natural := 16
  );
  port (
    sysclk : in std_logic;
    btn : in std_logic_vector(1 downto 0);
    led : out std_logic_vector(1 downto 0);
    led0_b : out std_logic;
    led0_g : out std_logic;
    led0_r : out std_logic;

    uart_rxd_out : in  std_logic;
    uart_txd_in  : out std_logic;

    MemAdr : out unsigned(18 downto 0);
    MemDB  : inout std_logic_vector(7 downto 0);
    RamOEn : out std_logic;
    RamWEn : out std_logic;
    RamCEn : out std_logic
  );
end entity;

architecture rtl of cmod_a7_top is
  type boot_state_t is (S_RESET, S_BOOT_REQ, S_BOOT_WAIT, S_BOOT_GAP, S_RUN);
  type boot_rom_t is array (0 to 4) of cell_t;

  constant BOOT_ROM : boot_rom_t := (
    to_signed(1900801, CELL_WIDTH),
    to_signed(65, CELL_WIDTH),
    to_signed(0, CELL_WIDTH),
    to_signed(7425, CELL_WIDTH),
    to_signed(6, CELL_WIDTH)
  );

  signal reset_pipe : std_logic_vector(1 downto 0) := (others => '1');
  signal reset_sync : std_logic := '1';
  signal reset_count : natural range 0 to RESET_CYCLES := RESET_CYCLES;
  signal boot_state : boot_state_t := S_RESET;
  signal boot_index : natural range 0 to BOOT_ROM'length := 0;
  signal core_reset : std_logic := '1';

  signal mem_req   : std_logic;
  signal mem_we    : std_logic;
  signal mem_addr  : addr_t;
  signal mem_wdata : cell_t;
  signal mem_rdata : cell_t;
  signal mem_ready : std_logic;

  signal sram_req   : std_logic;
  signal sram_we    : std_logic;
  signal sram_addr  : addr_t;
  signal sram_wdata : cell_t;
  signal sram_ready : std_logic;
  signal sram_reset : std_logic;

  signal serial_tx_valid : std_logic;
  signal serial_tx_data  : std_logic_vector(7 downto 0);
  signal serial_tx_ready : std_logic;
  signal serial_rx_req   : std_logic;
  signal serial_rx_valid : std_logic;
  signal serial_rx_data  : std_logic_vector(7 downto 0);
  signal serial_rx_take  : std_logic;
  signal uart_rx_valid   : std_logic;
  signal uart_rx_data    : std_logic_vector(7 downto 0);
  signal uart_rx_take    : std_logic;
  signal uart_tx_busy    : std_logic;
  signal tx_fifo_push    : std_logic;
  signal tx_fifo_pop     : std_logic;
  signal tx_fifo_data    : std_logic_vector(7 downto 0);
  signal tx_fifo_empty   : std_logic;
  signal tx_fifo_full    : std_logic;
  signal rx_fifo_push    : std_logic;
  signal rx_fifo_pop     : std_logic;
  signal rx_fifo_empty   : std_logic;
  signal rx_fifo_full    : std_logic;

  signal block_req   : std_logic;
  signal block_ready : std_logic := '0';
  signal reload_req  : std_logic;
  signal reload_ready: std_logic;
  signal halted      : std_logic;
  signal errored     : std_logic;
  signal error_code  : unsigned(7 downto 0);
begin
  process(sysclk)
  begin
    if rising_edge(sysclk) then
      reset_pipe <= reset_pipe(0) & btn(0);
      if reset_pipe(1) = '1' then
        reset_sync <= '1';
        reset_count <= RESET_CYCLES;
      elsif reset_count = 0 then
        reset_sync <= '0';
      else
        reset_count <= reset_count - 1;
        reset_sync <= '1';
      end if;
    end if;
  end process;

  process(sysclk)
  begin
    if rising_edge(sysclk) then
      if reset_sync = '1' then
        boot_state <= S_RESET;
        boot_index <= 0;
        core_reset <= '1';
      else
        case boot_state is
          when S_RESET =>
            boot_index <= 0;
            core_reset <= '1';
            boot_state <= S_BOOT_REQ;

          when S_BOOT_REQ =>
            core_reset <= '1';
            boot_state <= S_BOOT_WAIT;

          when S_BOOT_WAIT =>
            core_reset <= '1';
            if sram_ready = '1' then
              if boot_index = BOOT_ROM'length - 1 then
                boot_state <= S_RUN;
              else
                boot_state <= S_BOOT_GAP;
              end if;
            end if;

          when S_BOOT_GAP =>
            core_reset <= '1';
            boot_index <= boot_index + 1;
            boot_state <= S_BOOT_REQ;

          when S_RUN =>
            core_reset <= '0';
        end case;
      end if;
    end if;
  end process;

  sram_req <= '1' when boot_state = S_BOOT_REQ or boot_state = S_BOOT_WAIT else mem_req;
  sram_we <= '1' when boot_state = S_BOOT_REQ or boot_state = S_BOOT_WAIT else mem_we;
  sram_addr <= to_unsigned(boot_index, sram_addr'length)
               when boot_state = S_BOOT_REQ or boot_state = S_BOOT_WAIT else mem_addr;
  sram_wdata <= BOOT_ROM(boot_index)
                when boot_state = S_BOOT_REQ or boot_state = S_BOOT_WAIT else mem_wdata;
  mem_ready <= sram_ready when boot_state = S_RUN else '0';
  sram_reset <= reset_sync;

  sram_i : entity work.ilo_sram8_controller
    generic map (
      SRAM_ADDR_WIDTH => 19,
      READ_WAIT_CYCLES => SRAM_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => SRAM_WRITE_WAIT_CYCLES
    )
    port map (
      clk => sysclk,
      reset => sram_reset,
      req => sram_req,
      we => sram_we,
      addr => sram_addr,
      wdata => sram_wdata,
      rdata => mem_rdata,
      ready => sram_ready,
      reload_req => reload_req,
      reload_ready => reload_ready,
      sram_addr => MemAdr,
      sram_data => MemDB,
      sram_ce_n => RamCEn,
      sram_oe_n => RamOEn,
      sram_we_n => RamWEn
    );

  core_i : entity work.ilo_core
    port map (
      clk => sysclk,
      reset => core_reset,
      mem_req => mem_req,
      mem_we => mem_we,
      mem_addr => mem_addr,
      mem_wdata => mem_wdata,
      mem_rdata => mem_rdata,
      mem_ready => mem_ready,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data => serial_tx_data,
      serial_tx_ready => serial_tx_ready,
      serial_rx_req => serial_rx_req,
      serial_rx_valid => serial_rx_valid,
      serial_rx_data => serial_rx_data,
      block_req => block_req,
      block_we => open,
      block_addr => open,
      block_wdata => open,
      block_rdata => CELL_ZERO,
      block_ready => block_ready,
      reload_req => reload_req,
      reload_ready => reload_ready,
      halted => halted,
      errored => errored,
      error_code => error_code
    );

  serial_tx_ready <= not tx_fifo_full;
  tx_fifo_push <= serial_tx_valid and serial_tx_ready;
  tx_fifo_pop <= '1' when tx_fifo_empty = '0' and uart_tx_busy = '0' else '0';

  tx_fifo_i : entity work.ilo_byte_fifo
    generic map (
      DEPTH => 16
    )
    port map (
      clk => sysclk,
      reset => reset_sync,
      push => tx_fifo_push,
      wdata => serial_tx_data,
      full => tx_fifo_full,
      pop => tx_fifo_pop,
      rdata => tx_fifo_data,
      empty => tx_fifo_empty
    );

  tx_i : entity work.ilo_uart_tx
    generic map (
      CLKS_PER_BIT => UART_CLKS_PER_BIT
    )
    port map (
      clk => sysclk,
      reset => reset_sync,
      data_valid => tx_fifo_pop,
      data => tx_fifo_data,
      tx => uart_txd_in,
      busy => uart_tx_busy
    );

  rx_fifo_push <= uart_rx_valid and not rx_fifo_full;
  uart_rx_take <= rx_fifo_push;
  serial_rx_take <= serial_rx_req and serial_rx_valid;
  rx_fifo_pop <= serial_rx_take;
  serial_rx_valid <= not rx_fifo_empty;

  rx_fifo_i : entity work.ilo_byte_fifo
    generic map (
      DEPTH => 16
    )
    port map (
      clk => sysclk,
      reset => reset_sync,
      push => rx_fifo_push,
      wdata => uart_rx_data,
      full => rx_fifo_full,
      pop => rx_fifo_pop,
      rdata => serial_rx_data,
      empty => rx_fifo_empty
    );

  rx_i : entity work.ilo_uart_rx
    generic map (
      CLKS_PER_BIT => UART_CLKS_PER_BIT
    )
    port map (
      clk => sysclk,
      reset => reset_sync,
      rx => uart_rxd_out,
      take => uart_rx_take,
      data_valid => uart_rx_valid,
      data => uart_rx_data
    );

  process(sysclk)
  begin
    if rising_edge(sysclk) then
      if reset_sync = '1' then
        block_ready <= '0';
      else
        block_ready <= block_req;
      end if;
    end if;
  end process;

  led(0) <= halted;
  led(1) <= errored;
  led0_r <= not errored;
  led0_g <= not halted;
  led0_b <= not uart_tx_busy;
end architecture;
Added ilo-vm/vhdl/rtl/boards/icepi_zero_sdram_top.vhd.
































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.ilo_pkg.all;

entity icepi_zero_sdram_top is
  generic (
    BOOT_IMAGE : string := "SMOKE";
    UART_CLKS_PER_BIT : positive := 434;
    RESET_CYCLES : natural := 16;
    SDRAM_INIT_WAIT_CYCLES : natural := 10000;
    SDRAM_REFRESH_INTERVAL_CYCLES : natural := 390;
    SDRAM_TRCD_CYCLES : natural := 1;
    SDRAM_TRP_CYCLES : natural := 1;
    SDRAM_TRFC_CYCLES : natural := 4;
    SDRAM_TMRD_CYCLES : natural := 2;
    SDRAM_READ_WAIT_CYCLES : natural := 3;
    SDRAM_WRITE_RECOVERY_CYCLES : natural := 2
  );
  port (
    clk : in std_logic;
    button : in std_logic_vector(1 downto 0);
    led : out std_logic_vector(4 downto 0);

    usb_rx : in std_logic;
    usb_tx : out std_logic;

    sdram_a    : out unsigned(12 downto 0);
    sdram_ba   : out unsigned(1 downto 0);
    sdram_dq   : inout std_logic_vector(15 downto 0);
    sdram_dqm  : out std_logic_vector(1 downto 0);
    sdram_csn  : out std_logic;
    sdram_cke  : out std_logic;
    sdram_clk  : out std_logic;
    sdram_wen  : out std_logic;
    sdram_casn : out std_logic;
    sdram_rasn : out std_logic
  );
end entity;

architecture rtl of icepi_zero_sdram_top is
  type boot_state_t is (S_RESET, S_PRELOAD_WAIT, S_BOOT_REQ, S_BOOT_WAIT, S_BOOT_GAP, S_RUN);
  constant UART_STRESS_TX_COUNT : natural := 20;
  constant BOOT_MAX_CELLS : natural := UART_STRESS_TX_COUNT * 3 + 6;

  function boot_length return natural is
  begin
    if BOOT_IMAGE = "PRELOADED" then
      return 0;
    end if;
    if BOOT_IMAGE = "UART_STRESS" then
      return BOOT_MAX_CELLS;
    end if;
    return 5;
  end function;

  function boot_word(index : natural) return cell_t is
    variable tx_index : natural;
  begin
    if BOOT_IMAGE = "UART_STRESS" then
      if index < UART_STRESS_TX_COUNT * 3 then
        tx_index := index / 3;
        if index mod 3 = 0 then
          return to_signed(1900801, CELL_WIDTH);
        elsif index mod 3 = 1 then
          return to_signed(65 + tx_index, CELL_WIDTH);
        end if;
        return to_signed(0, CELL_WIDTH);
      elsif index = UART_STRESS_TX_COUNT * 3 then
        return to_signed(7425, CELL_WIDTH);
      elsif index = UART_STRESS_TX_COUNT * 3 + 1 then
        return to_signed(1, CELL_WIDTH);
      elsif index = UART_STRESS_TX_COUNT * 3 + 2 then
        return to_signed(7425, CELL_WIDTH);
      elsif index = UART_STRESS_TX_COUNT * 3 + 3 then
        return to_signed(0, CELL_WIDTH);
      elsif index = UART_STRESS_TX_COUNT * 3 + 4 then
        return to_signed(7425, CELL_WIDTH);
      elsif index = UART_STRESS_TX_COUNT * 3 + 5 then
        return to_signed(6, CELL_WIDTH);
      end if;
      return CELL_ZERO;
    end if;

    case index is
      when 0 => return to_signed(1900801, CELL_WIDTH);
      when 1 => return to_signed(65, CELL_WIDTH);
      when 2 => return to_signed(0, CELL_WIDTH);
      when 3 => return to_signed(7425, CELL_WIDTH);
      when 4 => return to_signed(6, CELL_WIDTH);
      when others => return CELL_ZERO;
    end case;
  end function;

  signal reset_pipe : std_logic_vector(1 downto 0) := (others => '1');
  signal reset_sync : std_logic := '1';
  signal reset_count : natural range 0 to RESET_CYCLES := RESET_CYCLES;
  signal boot_state : boot_state_t := S_RESET;
  signal boot_index : natural range 0 to BOOT_MAX_CELLS := 0;
  signal core_reset : std_logic := '1';

  signal mem_req   : std_logic;
  signal mem_we    : std_logic;
  signal mem_addr  : addr_t;
  signal mem_wdata : cell_t;
  signal mem_rdata : cell_t;
  signal mem_ready : std_logic;

  signal sdram_req   : std_logic;
  signal sdram_we    : std_logic;
  signal sdram_addr  : addr_t;
  signal sdram_wdata : cell_t;
  signal sdram_ready : std_logic;

  signal serial_tx_valid : std_logic;
  signal serial_tx_data  : std_logic_vector(7 downto 0);
  signal serial_tx_ready : std_logic;
  signal serial_rx_req   : std_logic;
  signal serial_rx_valid : std_logic;
  signal serial_rx_data  : std_logic_vector(7 downto 0);
  signal serial_rx_take  : std_logic;
  signal uart_rx_valid   : std_logic;
  signal uart_rx_data    : std_logic_vector(7 downto 0);
  signal uart_rx_take    : std_logic;
  signal uart_tx_busy    : std_logic;
  signal tx_fifo_push    : std_logic;
  signal tx_fifo_pop     : std_logic;
  signal tx_fifo_data    : std_logic_vector(7 downto 0);
  signal tx_fifo_empty   : std_logic;
  signal tx_fifo_full    : std_logic;
  signal rx_fifo_push    : std_logic;
  signal rx_fifo_pop     : std_logic;
  signal rx_fifo_empty   : std_logic;
  signal rx_fifo_full    : std_logic;

  signal block_req   : std_logic;
  signal block_ready : std_logic := '0';
  signal core_reload_req : std_logic;
  signal sdram_reload_req : std_logic;
  signal reload_ready: std_logic;
  signal halted      : std_logic;
  signal errored     : std_logic;
  signal heartbeat   : unsigned(23 downto 0) := (others => '0');
begin
  process(clk)
  begin
    if rising_edge(clk) then
      reset_pipe <= reset_pipe(0) & not button(0);
      if reset_pipe(1) = '1' then
        reset_sync <= '1';
        reset_count <= RESET_CYCLES;
      elsif reset_count = 0 then
        reset_sync <= '0';
      else
        reset_count <= reset_count - 1;
        reset_sync <= '1';
      end if;
    end if;
  end process;

  process(clk)
  begin
    if rising_edge(clk) then
      if reset_sync = '1' then
        boot_state <= S_RESET;
        boot_index <= 0;
        core_reset <= '1';
      else
        case boot_state is
          when S_RESET =>
            boot_index <= 0;
            core_reset <= '1';
            if boot_length = 0 then
              boot_state <= S_PRELOAD_WAIT;
            else
              boot_state <= S_BOOT_REQ;
            end if;

          when S_PRELOAD_WAIT =>
            core_reset <= '1';
            if reload_ready = '1' then
              boot_state <= S_RUN;
            end if;

          when S_BOOT_REQ =>
            core_reset <= '1';
            boot_state <= S_BOOT_WAIT;

          when S_BOOT_WAIT =>
            core_reset <= '1';
            if sdram_ready = '1' then
              if boot_index = boot_length - 1 then
                boot_state <= S_RUN;
              else
                boot_state <= S_BOOT_GAP;
              end if;
            end if;

          when S_BOOT_GAP =>
            core_reset <= '1';
            boot_index <= boot_index + 1;
            boot_state <= S_BOOT_REQ;

          when S_RUN =>
            core_reset <= '0';
        end case;
      end if;
    end if;
  end process;

  sdram_req <= '1' when boot_state = S_BOOT_REQ or boot_state = S_BOOT_WAIT else mem_req;
  sdram_we <= '1' when boot_state = S_BOOT_REQ or boot_state = S_BOOT_WAIT else mem_we;
  sdram_addr <= to_unsigned(boot_index, sdram_addr'length)
                when boot_state = S_BOOT_REQ or boot_state = S_BOOT_WAIT else mem_addr;
  sdram_wdata <= boot_word(boot_index)
                 when boot_state = S_BOOT_REQ or boot_state = S_BOOT_WAIT else mem_wdata;
  mem_ready <= sdram_ready when boot_state = S_RUN else '0';
  sdram_reload_req <= '1' when boot_state = S_PRELOAD_WAIT else core_reload_req;

  mem_i : entity work.ilo_sdram_controller
    generic map (
      INIT_WAIT_CYCLES => SDRAM_INIT_WAIT_CYCLES,
      REFRESH_INTERVAL_CYCLES => SDRAM_REFRESH_INTERVAL_CYCLES,
      TRCD_CYCLES => SDRAM_TRCD_CYCLES,
      TRP_CYCLES => SDRAM_TRP_CYCLES,
      TRFC_CYCLES => SDRAM_TRFC_CYCLES,
      TMRD_CYCLES => SDRAM_TMRD_CYCLES,
      READ_WAIT_CYCLES => SDRAM_READ_WAIT_CYCLES,
      WRITE_RECOVERY_CYCLES => SDRAM_WRITE_RECOVERY_CYCLES
    )
    port map (
      clk => clk,
      reset => reset_sync,
      req => sdram_req,
      we => sdram_we,
      addr => sdram_addr,
      wdata => sdram_wdata,
      rdata => mem_rdata,
      ready => sdram_ready,
      reload_req => sdram_reload_req,
      reload_ready => reload_ready,
      sdram_a => sdram_a,
      sdram_ba => sdram_ba,
      sdram_dq => sdram_dq,
      sdram_dqm => sdram_dqm,
      sdram_csn => sdram_csn,
      sdram_cke => sdram_cke,
      sdram_clk => sdram_clk,
      sdram_wen => sdram_wen,
      sdram_casn => sdram_casn,
      sdram_rasn => sdram_rasn
    );

  core_i : entity work.ilo_core
    port map (
      clk => clk,
      reset => core_reset,
      mem_req => mem_req,
      mem_we => mem_we,
      mem_addr => mem_addr,
      mem_wdata => mem_wdata,
      mem_rdata => mem_rdata,
      mem_ready => mem_ready,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data => serial_tx_data,
      serial_tx_ready => serial_tx_ready,
      serial_rx_req => serial_rx_req,
      serial_rx_valid => serial_rx_valid,
      serial_rx_data => serial_rx_data,
      block_req => block_req,
      block_we => open,
      block_addr => open,
      block_wdata => open,
      block_rdata => CELL_ZERO,
      block_ready => block_ready,
      reload_req => core_reload_req,
      reload_ready => reload_ready,
      halted => halted,
      errored => errored,
      error_code => open
    );

  serial_tx_ready <= not tx_fifo_full;
  tx_fifo_push <= serial_tx_valid and serial_tx_ready;
  tx_fifo_pop <= '1' when tx_fifo_empty = '0' and uart_tx_busy = '0' else '0';

  tx_fifo_i : entity work.ilo_byte_fifo
    generic map (
      DEPTH => 16
    )
    port map (
      clk => clk,
      reset => reset_sync,
      push => tx_fifo_push,
      wdata => serial_tx_data,
      full => tx_fifo_full,
      pop => tx_fifo_pop,
      rdata => tx_fifo_data,
      empty => tx_fifo_empty
    );

  tx_i : entity work.ilo_uart_tx
    generic map (
      CLKS_PER_BIT => UART_CLKS_PER_BIT
    )
    port map (
      clk => clk,
      reset => reset_sync,
      data_valid => tx_fifo_pop,
      data => tx_fifo_data,
      tx => usb_tx,
      busy => uart_tx_busy
    );

  rx_fifo_push <= uart_rx_valid and not rx_fifo_full;
  uart_rx_take <= rx_fifo_push;
  serial_rx_take <= serial_rx_req and serial_rx_valid;
  rx_fifo_pop <= serial_rx_take;
  serial_rx_valid <= not rx_fifo_empty;

  rx_fifo_i : entity work.ilo_byte_fifo
    generic map (
      DEPTH => 16
    )
    port map (
      clk => clk,
      reset => reset_sync,
      push => rx_fifo_push,
      wdata => uart_rx_data,
      full => rx_fifo_full,
      pop => rx_fifo_pop,
      rdata => serial_rx_data,
      empty => rx_fifo_empty
    );

  rx_i : entity work.ilo_uart_rx
    generic map (
      CLKS_PER_BIT => UART_CLKS_PER_BIT
    )
    port map (
      clk => clk,
      reset => reset_sync,
      rx => usb_rx,
      take => uart_rx_take,
      data_valid => uart_rx_valid,
      data => uart_rx_data
    );

  process(clk)
  begin
    if rising_edge(clk) then
      if reset_sync = '1' then
        block_ready <= '0';
        heartbeat <= (others => '0');
      else
        block_ready <= block_req;
        heartbeat <= heartbeat + 1;
      end if;
    end if;
  end process;

  led(0) <= halted;
  led(1) <= errored;
  led(2) <= uart_tx_busy;
  led(3) <= heartbeat(23);
  led(4) <= not core_reset;
end architecture;
Added ilo-vm/vhdl/rtl/boards/icepi_zero_top.vhd.










































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.ilo_pkg.all;

entity icepi_zero_top is
  generic (
    UART_CLKS_PER_BIT : positive := 434;
    RESET_CYCLES : natural := 16
  );
  port (
    clk : in std_logic;
    button : in std_logic_vector(1 downto 0);
    led : out std_logic_vector(4 downto 0);

    usb_rx : in std_logic;
    usb_tx : out std_logic
  );
end entity;

architecture rtl of icepi_zero_top is
  type mem_state_t is (S_MEM_IDLE, S_MEM_READY, S_MEM_WAIT_RELEASE);
  type boot_rom_t is array (0 to 4) of cell_t;

  constant BOOT_ROM : boot_rom_t := (
    to_signed(1900801, CELL_WIDTH),
    to_signed(65, CELL_WIDTH),
    to_signed(0, CELL_WIDTH),
    to_signed(7425, CELL_WIDTH),
    to_signed(6, CELL_WIDTH)
  );

  signal reset_pipe : std_logic_vector(1 downto 0) := (others => '1');
  signal reset_sync : std_logic := '1';
  signal reset_count : natural range 0 to RESET_CYCLES := RESET_CYCLES;

  signal mem_req   : std_logic;
  signal mem_we    : std_logic;
  signal mem_addr  : addr_t;
  signal mem_wdata : cell_t;
  signal mem_rdata : cell_t := CELL_ZERO;
  signal mem_ready : std_logic := '0';
  signal mem_state : mem_state_t := S_MEM_IDLE;

  signal serial_tx_valid : std_logic;
  signal serial_tx_data  : std_logic_vector(7 downto 0);
  signal serial_tx_ready : std_logic;
  signal serial_rx_req   : std_logic;
  signal serial_rx_valid : std_logic;
  signal serial_rx_data  : std_logic_vector(7 downto 0);
  signal serial_rx_take  : std_logic;
  signal uart_rx_valid   : std_logic;
  signal uart_rx_data    : std_logic_vector(7 downto 0);
  signal uart_rx_take    : std_logic;
  signal uart_tx_busy    : std_logic;
  signal tx_fifo_push    : std_logic;
  signal tx_fifo_pop     : std_logic;
  signal tx_fifo_data    : std_logic_vector(7 downto 0);
  signal tx_fifo_empty   : std_logic;
  signal tx_fifo_full    : std_logic;
  signal rx_fifo_push    : std_logic;
  signal rx_fifo_pop     : std_logic;
  signal rx_fifo_empty   : std_logic;
  signal rx_fifo_full    : std_logic;

  signal block_req   : std_logic;
  signal block_ready : std_logic := '0';
  signal reload_req  : std_logic;
  signal reload_ready: std_logic;
  signal halted      : std_logic;
  signal errored     : std_logic;
  signal heartbeat   : unsigned(23 downto 0) := (others => '0');
begin
  process(clk)
  begin
    if rising_edge(clk) then
      reset_pipe <= reset_pipe(0) & not button(0);
      if reset_pipe(1) = '1' then
        reset_sync <= '1';
        reset_count <= RESET_CYCLES;
      elsif reset_count = 0 then
        reset_sync <= '0';
      else
        reset_count <= reset_count - 1;
        reset_sync <= '1';
      end if;
    end if;
  end process;

  process(clk)
    variable a : natural;
  begin
    if rising_edge(clk) then
      mem_ready <= '0';
      reload_ready <= '0';

      if reset_sync = '1' then
        mem_rdata <= CELL_ZERO;
        mem_state <= S_MEM_IDLE;
      elsif reload_req = '1' then
        reload_ready <= '1';
        mem_state <= S_MEM_IDLE;
      else
        case mem_state is
          when S_MEM_IDLE =>
            if mem_req = '1' then
              a := to_integer(mem_addr);
              if mem_we = '1' then
                mem_rdata <= mem_wdata;
              elsif a < BOOT_ROM'length then
                mem_rdata <= BOOT_ROM(a);
              else
                mem_rdata <= CELL_ZERO;
              end if;
              mem_ready <= '1';
              mem_state <= S_MEM_READY;
            end if;

          when S_MEM_READY =>
            mem_state <= S_MEM_WAIT_RELEASE;

          when S_MEM_WAIT_RELEASE =>
            if mem_req = '0' then
              mem_state <= S_MEM_IDLE;
            end if;
        end case;
      end if;
    end if;
  end process;

  core_i : entity work.ilo_core
    port map (
      clk => clk,
      reset => reset_sync,
      mem_req => mem_req,
      mem_we => mem_we,
      mem_addr => mem_addr,
      mem_wdata => mem_wdata,
      mem_rdata => mem_rdata,
      mem_ready => mem_ready,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data => serial_tx_data,
      serial_tx_ready => serial_tx_ready,
      serial_rx_req => serial_rx_req,
      serial_rx_valid => serial_rx_valid,
      serial_rx_data => serial_rx_data,
      block_req => block_req,
      block_we => open,
      block_addr => open,
      block_wdata => open,
      block_rdata => CELL_ZERO,
      block_ready => block_ready,
      reload_req => reload_req,
      reload_ready => reload_ready,
      halted => halted,
      errored => errored,
      error_code => open
    );

  serial_tx_ready <= not tx_fifo_full;
  tx_fifo_push <= serial_tx_valid and serial_tx_ready;
  tx_fifo_pop <= '1' when tx_fifo_empty = '0' and uart_tx_busy = '0' else '0';

  tx_fifo_i : entity work.ilo_byte_fifo
    generic map (
      DEPTH => 16
    )
    port map (
      clk => clk,
      reset => reset_sync,
      push => tx_fifo_push,
      wdata => serial_tx_data,
      full => tx_fifo_full,
      pop => tx_fifo_pop,
      rdata => tx_fifo_data,
      empty => tx_fifo_empty
    );

  tx_i : entity work.ilo_uart_tx
    generic map (
      CLKS_PER_BIT => UART_CLKS_PER_BIT
    )
    port map (
      clk => clk,
      reset => reset_sync,
      data_valid => tx_fifo_pop,
      data => tx_fifo_data,
      tx => usb_tx,
      busy => uart_tx_busy
    );

  rx_fifo_push <= uart_rx_valid and not rx_fifo_full;
  uart_rx_take <= rx_fifo_push;
  serial_rx_take <= serial_rx_req and serial_rx_valid;
  rx_fifo_pop <= serial_rx_take;
  serial_rx_valid <= not rx_fifo_empty;

  rx_fifo_i : entity work.ilo_byte_fifo
    generic map (
      DEPTH => 16
    )
    port map (
      clk => clk,
      reset => reset_sync,
      push => rx_fifo_push,
      wdata => uart_rx_data,
      full => rx_fifo_full,
      pop => rx_fifo_pop,
      rdata => serial_rx_data,
      empty => rx_fifo_empty
    );

  rx_i : entity work.ilo_uart_rx
    generic map (
      CLKS_PER_BIT => UART_CLKS_PER_BIT
    )
    port map (
      clk => clk,
      reset => reset_sync,
      rx => usb_rx,
      take => uart_rx_take,
      data_valid => uart_rx_valid,
      data => uart_rx_data
    );

  process(clk)
  begin
    if rising_edge(clk) then
      if reset_sync = '1' then
        block_ready <= '0';
        heartbeat <= (others => '0');
      else
        block_ready <= block_req;
        heartbeat <= heartbeat + 1;
      end if;
    end if;
  end process;

  led(0) <= halted;
  led(1) <= errored;
  led(2) <= uart_tx_busy;
  led(3) <= heartbeat(23);
  led(4) <= not reset_sync;
end architecture;
Added ilo-vm/vhdl/rtl/ilo_block_store.vhd.






































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

use work.ilo_pkg.all;

entity ilo_block_store is
  generic (
    BLOCK_FILE  : string := "";
    BLOCK_CELLS : natural := 1024;
    READ_WAIT_CYCLES : natural := 0;
    WRITE_WAIT_CYCLES : natural := 0;
    POISON_UNINITIALIZED : boolean := false
  );
  port (
    clk    : in  std_logic;
    req    : in  std_logic;
    we     : in  std_logic;
    addr   : in  unsigned(31 downto 0);
    wdata  : in  cell_t;
    rdata  : out cell_t;
    ready  : out std_logic
  );
end entity;

architecture rtl of ilo_block_store is
  type state_t is (S_IDLE, S_WAIT, S_READY, S_WAIT_RELEASE);
  type block_array_t is array (0 to BLOCK_CELLS - 1) of cell_t;

  signal ram       : block_array_t := (others => CELL_ZERO);
  signal rdata_reg : cell_t := CELL_ZERO;
  signal ready_reg : std_logic := '0';
  signal state      : state_t := S_IDLE;
  signal wait_count : natural := 0;

  -- synthesis translate_off
  constant POISON_CELL : cell_t := to_signed(-559038737, CELL_WIDTH); -- 0xDEADBEEF
  type block_valid_array_t is array (0 to BLOCK_CELLS - 1) of boolean;
  -- synthesis translate_on
begin
  rdata <= rdata_reg;
  ready <= ready_reg;

  process(clk)
    -- synthesis translate_off
    file f : text;
    variable l : line;
    variable v : integer;
    variable i : natural := 0;
    variable initialized : boolean := false;
    variable valid : block_valid_array_t := (others => false);
    -- synthesis translate_on
    variable a : natural;
    variable target_wait : natural;
  begin
    if rising_edge(clk) then
      -- synthesis translate_off
      if not initialized then
        if BLOCK_FILE /= "" then
          file_open(f, BLOCK_FILE, read_mode);
          while not endfile(f) and i < BLOCK_CELLS loop
            readline(f, l);
            read(l, v);
            ram(i) <= to_signed(v, CELL_WIDTH);
            valid(i) := true;
            i := i + 1;
          end loop;
          file_close(f);
        end if;
        initialized := true;
      end if;
      -- synthesis translate_on

      ready_reg <= '0';

      case state is
        when S_IDLE =>
          wait_count <= 0;
          if req = '1' then
            state <= S_WAIT;
          end if;

        when S_WAIT =>
          if we = '1' then
            target_wait := WRITE_WAIT_CYCLES;
          else
            target_wait := READ_WAIT_CYCLES;
          end if;

          if wait_count >= target_wait then
            if addr < to_unsigned(BLOCK_CELLS, addr'length) then
              a := to_integer(addr);
              if we = '1' then
                ram(a) <= wdata;
                rdata_reg <= wdata;
                -- synthesis translate_off
                valid(a) := true;
                -- synthesis translate_on
              else
                -- synthesis translate_off
                if POISON_UNINITIALIZED and not valid(a) then
                  rdata_reg <= POISON_CELL;
                else
                -- synthesis translate_on
                rdata_reg <= ram(a);
                -- synthesis translate_off
                end if;
                -- synthesis translate_on
              end if;
            else
              rdata_reg <= CELL_ZERO;
            end if;
            ready_reg <= '1';
            wait_count <= 0;
            state <= S_READY;
          else
            wait_count <= wait_count + 1;
          end if;

        when S_READY =>
          state <= S_WAIT_RELEASE;

        when S_WAIT_RELEASE =>
          if req = '0' then
            state <= S_IDLE;
          end if;
      end case;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/rtl/ilo_byte_fifo.vhd.


















































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity ilo_byte_fifo is
  generic (
    DEPTH : positive := 16
  );
  port (
    clk   : in  std_logic;
    reset : in  std_logic;

    push  : in  std_logic;
    wdata : in  std_logic_vector(7 downto 0);
    full  : out std_logic;

    pop   : in  std_logic;
    rdata : out std_logic_vector(7 downto 0);
    empty : out std_logic
  );
end entity;

architecture rtl of ilo_byte_fifo is
  type mem_t is array (0 to DEPTH - 1) of std_logic_vector(7 downto 0);

  signal mem : mem_t := (others => (others => '0'));
  signal rd_index : natural range 0 to DEPTH - 1 := 0;
  signal wr_index : natural range 0 to DEPTH - 1 := 0;
  signal count : natural range 0 to DEPTH := 0;

  function bump(index : natural) return natural is
  begin
    if index = DEPTH - 1 then
      return 0;
    end if;
    return index + 1;
  end function;
begin
  rdata <= mem(rd_index);
  empty <= '1' when count = 0 else '0';
  full <= '1' when count = DEPTH else '0';

  process(clk)
    variable do_push : boolean;
    variable do_pop : boolean;
  begin
    if rising_edge(clk) then
      if reset = '1' then
        rd_index <= 0;
        wr_index <= 0;
        count <= 0;
      else
        do_push := push = '1' and (count < DEPTH or pop = '1');
        do_pop := pop = '1' and count > 0;

        if do_push then
          mem(wr_index) <= wdata;
          wr_index <= bump(wr_index);
        end if;

        if do_pop then
          rd_index <= bump(rd_index);
        end if;

        if do_push and not do_pop then
          count <= count + 1;
        elsif do_pop and not do_push then
          count <= count - 1;
        end if;
      end if;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/rtl/ilo_core.vhd.










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.ilo_pkg.all;

entity ilo_core is
  generic (
    STRICT_ERRORS : boolean := true
  );
  port (
    clk       : in  std_logic;
    reset     : in  std_logic;

    -- On reads, mem_ready='1' means mem_rdata is valid for this rising edge.
    -- External asynchronous memories need a synchronizing/registering wrapper.
    mem_req   : out std_logic;
    mem_we    : out std_logic;
    mem_addr  : out addr_t;
    mem_wdata : out cell_t;
    mem_rdata : in  cell_t;
    mem_ready : in  std_logic;

    serial_tx_valid : out std_logic;
    serial_tx_data  : out std_logic_vector(7 downto 0);
    serial_tx_ready : in  std_logic;
    -- serial_rx_valid/data are synchronous to clk. When serial_rx_valid='1',
    -- serial_rx_data must be valid for that rising edge.
    serial_rx_req   : out std_logic;
    serial_rx_valid : in  std_logic;
    serial_rx_data  : in  std_logic_vector(7 downto 0);

    -- On reads, block_ready='1' means block_rdata is valid for this rising edge.
    block_req   : out std_logic;
    block_we    : out std_logic;
    block_addr  : out unsigned(31 downto 0);
    block_wdata : out cell_t;
    block_rdata : in  cell_t;
    block_ready : in  std_logic;

    reload_req   : out std_logic;
    reload_ready : in  std_logic;

    halted    : out std_logic;
    errored   : out std_logic;
    error_code: out unsigned(7 downto 0)
  );
end entity;

architecture rtl of ilo_core is
  type state_t is (
    S_RESET,
    S_FETCH_REQ,
    S_FETCH_WAIT,
    S_DECODE,
    S_EXECUTE,
    S_MEM_READ_REQ,
    S_MEM_READ_WAIT,
    S_MEM_WRITE_REQ,
    S_MEM_WRITE_WAIT,
    S_CP_READ_SRC_REQ,
    S_CP_READ_SRC_WAIT,
    S_CP_READ_DST_REQ,
    S_CP_READ_DST_WAIT,
    S_CY_READ_REQ,
    S_CY_READ_WAIT,
    S_CY_WRITE_REQ,
    S_CY_WRITE_WAIT,
    S_IO_WAIT,
    S_TX_WAIT,
    S_BLOCK_READ_REQ,
    S_BLOCK_READ_WAIT,
    S_BLOCK_MEM_WRITE_REQ,
    S_BLOCK_MEM_WRITE_WAIT,
    S_BLOCK_MEM_READ_REQ,
    S_BLOCK_MEM_READ_WAIT,
    S_BLOCK_WRITE_REQ,
    S_BLOCK_WRITE_WAIT,
    S_RELOAD_REQ,
    S_RELOAD_WAIT,
    S_DS_REFILL_WAIT,
    S_DS_REFILL_CAPTURE,
    S_PO_REFILL_WAIT,
    S_PO_REFILL_CAPTURE,
    S_RE_REFILL_WAIT,
    S_RE_REFILL_CAPTURE,
    S_MUL_WRITEBACK,
    S_DIV_STEP,
    S_NEXT_OPCODE,
    S_HALT,
    S_ERROR
  );

  type mem_op_t is (M_NONE, M_LI, M_FE);
  type ds_refill_target_t is (DS_REFILL_TOP, DS_REFILL_N, DS_REFILL_D2);

  constant ERR_NONE : unsigned(7 downto 0) := x"00";
  constant ERR_DSU  : unsigned(7 downto 0) := x"01";
  constant ERR_DSO  : unsigned(7 downto 0) := x"02";
  constant ERR_RSU  : unsigned(7 downto 0) := x"03";
  constant ERR_RSO  : unsigned(7 downto 0) := x"04";
  constant ERR_DBZ  : unsigned(7 downto 0) := x"05";
  constant ERR_MEM  : unsigned(7 downto 0) := x"06";
  constant ERR_BLK  : unsigned(7 downto 0) := x"07";

  subtype stack_index_t is natural range 0 to RS_DEPTH - 1;
  subtype ds_index_t is natural range 0 to DS_DEPTH - 1;

  signal state      : state_t := S_RESET;
  signal mem_op     : mem_op_t := M_NONE;
  signal ip         : unsigned(16 downto 0) := (others => '0');
  signal bundle     : std_logic_vector(31 downto 0) := (others => '0');
  signal idx        : unsigned(1 downto 0) := (others => '0');
  signal opcode     : unsigned(7 downto 0) := (others => '0');
  signal ds_mem     : ds_array_t := (others => CELL_ZERO);
  signal ds_t       : cell_t := CELL_ZERO;
  signal ds_n       : cell_t := CELL_ZERO;
  signal ds_d2      : cell_t := CELL_ZERO;
  signal rs_mem     : rs_array_t := (others => CELL_ZERO);
  signal rs_t       : cell_t := CELL_ZERO;
  signal sp         : natural range 0 to DS_DEPTH := 0;
  signal rp         : natural range 0 to RS_DEPTH := 0;
  signal halted_reg : std_logic := '0';
  signal error_reg  : std_logic := '0';
  signal err_reg    : unsigned(7 downto 0) := ERR_NONE;

  signal mem_req_reg   : std_logic := '0';
  signal mem_we_reg    : std_logic := '0';
  signal mem_addr_reg  : addr_t := (others => '0');
  signal mem_wdata_reg : cell_t := CELL_ZERO;
  signal tx_valid_reg  : std_logic := '0';
  signal tx_data_reg   : std_logic_vector(7 downto 0) := (others => '0');
  signal tx_pending_data : std_logic_vector(7 downto 0) := (others => '0');
  signal rx_req_reg    : std_logic := '0';
  signal block_req_reg   : std_logic := '0';
  signal block_we_reg    : std_logic := '0';
  signal block_addr_reg  : unsigned(31 downto 0) := (others => '0');
  signal block_wdata_reg : cell_t := CELL_ZERO;
  signal reload_req_reg  : std_logic := '0';

  signal cp_src     : addr_t := (others => '0');
  signal cp_dst     : addr_t := (others => '0');
  signal cp_len     : unsigned(31 downto 0) := (others => '0');
  signal cp_flag    : cell_t := CELL_TRUE;
  signal cp_src_val : cell_t := CELL_ZERO;
  signal cy_src     : addr_t := (others => '0');
  signal cy_dst     : addr_t := (others => '0');
  signal cy_len     : unsigned(31 downto 0) := (others => '0');
  signal cy_value   : cell_t := CELL_ZERO;
  signal io_block_base : unsigned(31 downto 0) := (others => '0');
  signal io_buffer     : addr_t := (others => '0');
  signal io_offset     : unsigned(9 downto 0) := (others => '0');
  signal io_cell       : cell_t := CELL_ZERO;
  signal div_divisor_abs  : unsigned(31 downto 0) := (others => '0');
  signal div_quotient     : unsigned(31 downto 0) := (others => '0');
  signal div_remainder    : unsigned(32 downto 0) := (others => '0');
  signal div_count        : unsigned(5 downto 0) := (others => '0');
  signal div_quot_neg     : std_logic := '0';
  signal div_rem_neg      : std_logic := '0';
  signal div_sp           : natural range 0 to DS_DEPTH := 0;
  signal mul_product      : signed(63 downto 0) := (others => '0');
  signal mul_sp           : natural range 0 to DS_DEPTH := 0;
  signal ds_rd_addr        : ds_index_t := 0;
  signal ds_rd_data        : cell_t := CELL_ZERO;
  signal ds_wr_en          : std_logic := '0';
  signal ds_wr_addr        : ds_index_t := 0;
  signal ds_wr_data        : cell_t := CELL_ZERO;
  signal ds_refill_count   : natural range 0 to 3 := 0;
  signal ds_refill_target  : ds_refill_target_t := DS_REFILL_D2;
  signal ds_refill_resume  : state_t := S_NEXT_OPCODE;
  signal rs_rd_addr        : stack_index_t := 0;
  signal rs_rd_data        : cell_t := CELL_ZERO;
  signal rs_wr_en          : std_logic := '0';
  signal rs_wr_addr        : stack_index_t := 0;
  signal rs_wr_data        : cell_t := CELL_ZERO;

  function ds_cell(
    mem   : ds_array_t;
    top   : cell_t;
    nxt  : cell_t;
    third : cell_t;
    depth : natural;
    index : natural
  ) return cell_t is
  begin
    if index = 0 or index > depth then
      return CELL_ZERO;
    elsif index = depth then
      return top;
    elsif depth >= 2 and index = depth - 1 then
      return nxt;
    elsif depth >= 3 and index = depth - 2 then
      return third;
    end if;
    return mem(index);
  end function;

  procedure ds_resume_or_refill(
    signal rd_addr : out ds_index_t;
    signal count   : out natural range 0 to 3;
    signal target  : out ds_refill_target_t;
    signal resume  : out state_t;
    signal st      : out state_t;
    reads          : natural;
    first_addr     : natural;
    first_target   : ds_refill_target_t;
    resume_state   : state_t
  ) is
  begin
    if reads = 0 then
      st <= resume_state;
    else
      rd_addr <= first_addr;
      count <= reads;
      target <= first_target;
      resume <= resume_state;
      st <= S_DS_REFILL_WAIT;
    end if;
  end procedure;

  procedure ds_push(
    signal wr_en : out std_logic;
    signal wr_addr : out ds_index_t;
    signal wr_data : out cell_t;
    signal top   : inout cell_t;
    signal nxt  : inout cell_t;
    signal third : inout cell_t;
    depth        : natural;
    value        : cell_t
  ) is
  begin
    if depth >= 3 then
      wr_addr <= depth - 2;
      wr_data <= third;
      wr_en <= '1';
    end if;
    third <= nxt;
    nxt <= top;
    top <= value;
  end procedure;

  procedure ds_drop1(
    signal rd_addr : out ds_index_t;
    signal refill_count : out natural range 0 to 3;
    signal refill_target : out ds_refill_target_t;
    signal refill_resume : out state_t;
    signal st    : out state_t;
    signal top   : inout cell_t;
    signal nxt  : inout cell_t;
    signal third : inout cell_t;
    depth        : natural;
    resume_state : state_t
  ) is
  begin
    if depth > 1 then
      top <= nxt;
    else
      top <= CELL_ZERO;
    end if;
    if depth > 2 then
      nxt <= third;
    else
      nxt <= CELL_ZERO;
    end if;
    if depth > 3 then
      ds_resume_or_refill(rd_addr, refill_count, refill_target, refill_resume, st,
                          1, depth - 3, DS_REFILL_D2, resume_state);
    else
      third <= CELL_ZERO;
      st <= resume_state;
    end if;
  end procedure;

  procedure ds_drop2(
    signal rd_addr : out ds_index_t;
    signal refill_count : out natural range 0 to 3;
    signal refill_target : out ds_refill_target_t;
    signal refill_resume : out state_t;
    signal st    : out state_t;
    signal top   : inout cell_t;
    signal nxt  : inout cell_t;
    signal third : inout cell_t;
    depth        : natural;
    resume_state : state_t
  ) is
  begin
    if depth > 2 then
      top <= third;
    else
      top <= CELL_ZERO;
    end if;
    if depth > 3 then
      ds_resume_or_refill(rd_addr, refill_count, refill_target, refill_resume, st,
                          1, depth - 3, DS_REFILL_N, resume_state);
    else
      nxt <= CELL_ZERO;
      st <= resume_state;
    end if;
    if depth > 4 then
      ds_resume_or_refill(rd_addr, refill_count, refill_target, refill_resume, st,
                          2, depth - 3, DS_REFILL_N, resume_state);
    else
      third <= CELL_ZERO;
    end if;
  end procedure;

  procedure ds_drop2_to(
    signal rd_addr : out ds_index_t;
    signal refill_count : out natural range 0 to 3;
    signal refill_target : out ds_refill_target_t;
    signal refill_resume : out state_t;
    signal st    : out state_t;
    signal top   : inout cell_t;
    signal nxt  : inout cell_t;
    signal third : inout cell_t;
    depth        : natural;
    value        : cell_t;
    resume_state : state_t
  ) is
  begin
    top <= value;
    if depth > 3 then
      ds_resume_or_refill(rd_addr, refill_count, refill_target, refill_resume, st,
                          1, depth - 3, DS_REFILL_N, resume_state);
    else
      nxt <= CELL_ZERO;
      st <= resume_state;
    end if;
    if depth > 4 then
      ds_resume_or_refill(rd_addr, refill_count, refill_target, refill_resume, st,
                          2, depth - 3, DS_REFILL_N, resume_state);
    else
      third <= CELL_ZERO;
    end if;
  end procedure;

  procedure ds_drop3(
    signal rd_addr : out ds_index_t;
    signal refill_count : out natural range 0 to 3;
    signal refill_target : out ds_refill_target_t;
    signal refill_resume : out state_t;
    signal st    : out state_t;
    signal top   : inout cell_t;
    signal nxt  : inout cell_t;
    signal third : inout cell_t;
    depth        : natural;
    resume_state : state_t
  ) is
  begin
    if depth > 3 then
      ds_resume_or_refill(rd_addr, refill_count, refill_target, refill_resume, st,
                          1, depth - 3, DS_REFILL_TOP, resume_state);
    else
      top <= CELL_ZERO;
      st <= resume_state;
    end if;
    if depth > 4 then
      ds_resume_or_refill(rd_addr, refill_count, refill_target, refill_resume, st,
                          2, depth - 3, DS_REFILL_TOP, resume_state);
    else
      nxt <= CELL_ZERO;
    end if;
    if depth > 5 then
      ds_resume_or_refill(rd_addr, refill_count, refill_target, refill_resume, st,
                          3, depth - 3, DS_REFILL_TOP, resume_state);
    else
      third <= CELL_ZERO;
    end if;
  end procedure;

  procedure ds_binary_result(
    signal rd_addr : out ds_index_t;
    signal refill_count : out natural range 0 to 3;
    signal refill_target : out ds_refill_target_t;
    signal refill_resume : out state_t;
    signal st    : out state_t;
    signal top   : inout cell_t;
    signal nxt  : inout cell_t;
    signal third : inout cell_t;
    depth        : natural;
    value        : cell_t;
    resume_state : state_t
  ) is
  begin
    top <= value;
    if depth > 2 then
      nxt <= third;
    else
      nxt <= CELL_ZERO;
    end if;
    if depth > 3 then
      ds_resume_or_refill(rd_addr, refill_count, refill_target, refill_resume, st,
                          1, depth - 3, DS_REFILL_D2, resume_state);
    else
      third <= CELL_ZERO;
      st <= resume_state;
    end if;
  end procedure;

  function valid_addr(value : cell_t) return boolean is
  begin
    return value >= to_signed(0, CELL_WIDTH) and value <= to_signed(65535, CELL_WIDTH);
  end function;

  function abs_cell(value : cell_t) return unsigned is
  begin
    if value(CELL_WIDTH - 1) = '1' then
      return unsigned(-value);
    end if;
    return unsigned(value);
  end function;

  function signed_magnitude(value : unsigned(31 downto 0); negative : std_logic) return cell_t is
    variable mag : cell_t;
  begin
    mag := signed(value);
    if negative = '1' then
      return -mag;
    end if;
    return mag;
  end function;
begin
  mem_req    <= mem_req_reg;
  mem_we     <= mem_we_reg;
  mem_addr   <= mem_addr_reg;
  mem_wdata  <= mem_wdata_reg;
  halted     <= halted_reg;
  errored    <= error_reg;
  error_code <= err_reg;
  serial_tx_valid <= tx_valid_reg;
  serial_tx_data <= tx_data_reg;
  serial_rx_req <= rx_req_reg;
  block_req <= block_req_reg;
  block_we <= block_we_reg;
  block_addr <= block_addr_reg;
  block_wdata <= block_wdata_reg;
  reload_req <= reload_req_reg;

  process(clk)
  begin
    if rising_edge(clk) then
      -- synthesis translate_off
      assert not (state = S_DS_REFILL_WAIT and ds_wr_en = '1' and ds_wr_addr = ds_rd_addr)
        report "ilo_core: data stack RAM read/write address collision"
        severity failure;
      assert not ((state = S_PO_REFILL_WAIT or state = S_RE_REFILL_WAIT) and
                  rs_wr_en = '1' and rs_wr_addr = rs_rd_addr)
        report "ilo_core: return stack RAM read/write address collision"
        severity failure;
      -- synthesis translate_on

      if ds_wr_en = '1' then
        ds_mem(ds_wr_addr) <= ds_wr_data;
      end if;
      ds_rd_data <= ds_mem(ds_rd_addr);

      if rs_wr_en = '1' then
        rs_mem(rs_wr_addr) <= rs_wr_data;
      end if;
      rs_rd_data <= rs_mem(rs_rd_addr);
    end if;
  end process;

  -- synthesis translate_off
  process(all)
  begin
    sim_debug.set_sp(sp);
    sim_debug.set_rp(rp);
    for i in 0 to DS_DEPTH loop
      sim_debug.set_ds(i, ds_cell(ds_mem, ds_t, ds_n, ds_d2, sp, i));
    end loop;
  end process;

  process(clk)
    variable prev_mem_req : std_logic := '0';
    variable prev_mem_ready : std_logic := '0';
    variable prev_mem_we : std_logic := '0';
    variable prev_mem_addr : addr_t := (others => '0');
    variable prev_mem_wdata : cell_t := CELL_ZERO;
    variable prev_block_req : std_logic := '0';
    variable prev_block_ready : std_logic := '0';
    variable prev_block_we : std_logic := '0';
    variable prev_block_addr : unsigned(31 downto 0) := (others => '0');
    variable prev_block_wdata : cell_t := CELL_ZERO;
  begin
    if rising_edge(clk) then
      if reset = '1' then
        prev_mem_req := '0';
        prev_mem_ready := '0';
        prev_mem_we := '0';
        prev_mem_addr := (others => '0');
        prev_mem_wdata := CELL_ZERO;
        prev_block_req := '0';
        prev_block_ready := '0';
        prev_block_we := '0';
        prev_block_addr := (others => '0');
        prev_block_wdata := CELL_ZERO;
      else
        if prev_mem_req = '1' and prev_mem_ready = '0' then
          assert mem_req_reg = '1'
            report "ilo_core: mem_req dropped before mem_ready"
            severity failure;
          assert mem_we_reg = prev_mem_we and mem_addr_reg = prev_mem_addr
            report "ilo_core: memory request controls changed before mem_ready"
            severity failure;
          if prev_mem_we = '1' then
            assert mem_wdata_reg = prev_mem_wdata
              report "ilo_core: memory write data changed before mem_ready"
              severity failure;
          end if;
        end if;

        if prev_block_req = '1' and prev_block_ready = '0' then
          assert block_req_reg = '1'
            report "ilo_core: block_req dropped before block_ready"
            severity failure;
          assert block_we_reg = prev_block_we and block_addr_reg = prev_block_addr
            report "ilo_core: block request controls changed before block_ready"
            severity failure;
          if prev_block_we = '1' then
            assert block_wdata_reg = prev_block_wdata
              report "ilo_core: block write data changed before block_ready"
              severity failure;
          end if;
        end if;

        prev_mem_req := mem_req_reg;
        prev_mem_ready := mem_ready;
        prev_mem_we := mem_we_reg;
        prev_mem_addr := mem_addr_reg;
        prev_mem_wdata := mem_wdata_reg;
        prev_block_req := block_req_reg;
        prev_block_ready := block_ready;
        prev_block_we := block_we_reg;
        prev_block_addr := block_addr_reg;
        prev_block_wdata := block_wdata_reg;
      end if;
    end if;
  end process;
  -- synthesis translate_on

  process(clk)
    variable op       : natural;
    variable t        : cell_t;
    variable n        : cell_t;
    variable d        : cell_t;
    variable target17 : unsigned(16 downto 0);
    variable rem_shift : unsigned(32 downto 0);
    variable quot_shift : unsigned(31 downto 0);
    variable divisor_ext : unsigned(32 downto 0);
    variable quot_cell : cell_t;
    variable rem_cell : cell_t;
  begin
    if rising_edge(clk) then
      mem_req_reg <= '0';
      mem_we_reg <= '0';
      tx_valid_reg <= '0';
      block_req_reg <= '0';
      block_we_reg <= '0';
      reload_req_reg <= '0';
      ds_wr_en <= '0';
      rs_wr_en <= '0';

      if reset = '1' then
        state      <= S_RESET;
        ip         <= (others => '0');
        idx        <= (others => '0');
        sp         <= 0;
        rp         <= 0;
        ds_t       <= CELL_ZERO;
        ds_n       <= CELL_ZERO;
        ds_d2      <= CELL_ZERO;
        rs_t       <= CELL_ZERO;
        halted_reg <= '0';
        error_reg  <= '0';
        err_reg    <= ERR_NONE;
        mem_op     <= M_NONE;
        rx_req_reg <= '0';
        reload_req_reg <= '0';
        ds_rd_addr <= 0;
        ds_wr_addr <= 0;
        ds_wr_data <= CELL_ZERO;
        ds_refill_count <= 0;
        ds_refill_resume <= S_NEXT_OPCODE;
        rs_rd_addr <= 0;
        rs_wr_addr <= 0;
        rs_wr_data <= CELL_ZERO;
      else
        case state is
          when S_RESET =>
            ip <= (others => '0');
            idx <= (others => '0');
            sp <= 0;
            rp <= 0;
            halted_reg <= '0';
            error_reg <= '0';
            err_reg <= ERR_NONE;
            mem_op <= M_NONE;
            rx_req_reg <= '0';
            reload_req_reg <= '0';
            ds_t <= CELL_ZERO;
            ds_n <= CELL_ZERO;
            ds_d2 <= CELL_ZERO;
            ds_rd_addr <= 0;
            ds_wr_addr <= 0;
            ds_wr_data <= CELL_ZERO;
            ds_refill_count <= 0;
            ds_refill_resume <= S_NEXT_OPCODE;
            rs_t <= CELL_ZERO;
            rs_rd_addr <= 0;
            rs_wr_addr <= 0;
            rs_wr_data <= CELL_ZERO;
            state <= S_FETCH_REQ;

          when S_FETCH_REQ =>
            if ip >= to_unsigned(MEM_DEPTH, ip'length) then
              state <= S_HALT;
            else
              mem_addr_reg <= ip(15 downto 0);
              mem_req_reg <= '1';
              state <= S_FETCH_WAIT;
            end if;

          when S_FETCH_WAIT =>
            mem_req_reg <= '1';
            if mem_ready = '1' then
              mem_req_reg <= '0';
              bundle <= std_logic_vector(mem_rdata);
              idx <= (others => '0');
              state <= S_DECODE;
            end if;

          when S_DECODE =>
            case idx is
              when "00" => opcode <= unsigned(bundle(7 downto 0));
              when "01" => opcode <= unsigned(bundle(15 downto 8));
              when "10" => opcode <= unsigned(bundle(23 downto 16));
              when others => opcode <= unsigned(bundle(31 downto 24));
            end case;
            state <= S_EXECUTE;

          when S_EXECUTE =>
            op := to_integer(opcode);
            t := ds_t;
            n := ds_n;
            d := ds_d2;

            case op is
              when OP_NOP =>
                state <= S_NEXT_OPCODE;

              when OP_LI =>
                if sp = DS_DEPTH then
                  err_reg <= ERR_DSO;
                  state <= S_ERROR;
                else
                  ip <= ip + 1;
                  target17 := ip + 1;
                  mem_addr_reg <= target17(15 downto 0);
                  mem_op <= M_LI;
                  state <= S_MEM_READ_REQ;
                end if;

              when OP_DU =>
                if sp = DS_DEPTH then
                  err_reg <= ERR_DSO;
                  state <= S_ERROR;
                elsif sp = 0 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                else
                  ds_push(ds_wr_en, ds_wr_addr, ds_wr_data, ds_t, ds_n, ds_d2, sp, t);
                  sp <= sp + 1;
                  state <= S_NEXT_OPCODE;
                end if;

              when OP_DR =>
                if sp = 0 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                else
                  ds_drop1(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                           ds_t, ds_n, ds_d2, sp, S_NEXT_OPCODE);
                  sp <= sp - 1;
                end if;

              when OP_SW =>
                if sp < 2 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                else
                  ds_t <= n;
                  ds_n <= t;
                  state <= S_NEXT_OPCODE;
                end if;

              when OP_PU =>
                if sp = 0 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                elsif rp = RS_DEPTH then
                  err_reg <= ERR_RSO;
                  state <= S_ERROR;
                else
                  if rp >= 1 then
                    rs_wr_addr <= rp;
                    rs_wr_data <= rs_t;
                    rs_wr_en <= '1';
                  end if;
                  rs_t <= t;
                  rp <= rp + 1;
                  ds_drop1(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                           ds_t, ds_n, ds_d2, sp, S_NEXT_OPCODE);
                  sp <= sp - 1;
                end if;

              when OP_PO =>
                if rp = 0 then
                  err_reg <= ERR_RSU;
                  state <= S_ERROR;
                elsif sp = DS_DEPTH then
                  err_reg <= ERR_DSO;
                  state <= S_ERROR;
                else
                  ds_push(ds_wr_en, ds_wr_addr, ds_wr_data, ds_t, ds_n, ds_d2, sp, rs_t);
                  sp <= sp + 1;
                  rp <= rp - 1;
                  if rp > 1 then
                    rs_rd_addr <= rp - 1;
                    state <= S_PO_REFILL_WAIT;
                  else
                    rs_t <= CELL_ZERO;
                    state <= S_NEXT_OPCODE;
                  end if;
                end if;

              when OP_JU =>
                if sp = 0 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                elsif STRICT_ERRORS and not valid_addr(t) then
                  err_reg <= ERR_MEM;
                  state <= S_ERROR;
                else
                  target17 := resize(cell_addr(t), target17'length);
                  ip <= target17 - 1;
                  ds_drop1(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                           ds_t, ds_n, ds_d2, sp, S_NEXT_OPCODE);
                  sp <= sp - 1;
                end if;

              when OP_CA =>
                if sp = 0 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                elsif rp = RS_DEPTH then
                  err_reg <= ERR_RSO;
                  state <= S_ERROR;
                elsif STRICT_ERRORS and not valid_addr(t) then
                  err_reg <= ERR_MEM;
                  state <= S_ERROR;
                else
                  if rp >= 1 then
                    rs_wr_addr <= rp;
                    rs_wr_data <= rs_t;
                    rs_wr_en <= '1';
                  end if;
                  rs_t <= signed(resize(ip, CELL_WIDTH));
                  rp <= rp + 1;
                  target17 := resize(cell_addr(t), target17'length);
                  ip <= target17 - 1;
                  ds_drop1(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                           ds_t, ds_n, ds_d2, sp, S_NEXT_OPCODE);
                  sp <= sp - 1;
                end if;

              when OP_CC =>
                if sp < 2 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                elsif n /= CELL_ZERO and rp = RS_DEPTH then
                  err_reg <= ERR_RSO;
                  state <= S_ERROR;
                elsif STRICT_ERRORS and n /= CELL_ZERO and not valid_addr(t) then
                  err_reg <= ERR_MEM;
                  state <= S_ERROR;
                else
                  if n /= CELL_ZERO then
                    if rp >= 1 then
                      rs_wr_addr <= rp;
                      rs_wr_data <= rs_t;
                      rs_wr_en <= '1';
                    end if;
                    rs_t <= signed(resize(ip, CELL_WIDTH));
                    rp <= rp + 1;
                    target17 := resize(cell_addr(t), target17'length);
                    ip <= target17 - 1;
                  end if;
                  ds_drop2(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                           ds_t, ds_n, ds_d2, sp, S_NEXT_OPCODE);
                  sp <= sp - 2;
                end if;

              when OP_CJ =>
                if sp < 2 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                elsif STRICT_ERRORS and n /= CELL_ZERO and not valid_addr(t) then
                  err_reg <= ERR_MEM;
                  state <= S_ERROR;
                else
                  if n /= CELL_ZERO then
                    target17 := resize(cell_addr(t), target17'length);
                    ip <= target17 - 1;
                  end if;
                  ds_drop2(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                           ds_t, ds_n, ds_d2, sp, S_NEXT_OPCODE);
                  sp <= sp - 2;
                end if;

              when OP_RE =>
                if rp = 0 then
                  err_reg <= ERR_RSU;
                  state <= S_ERROR;
                else
                  ip <= resize(unsigned(std_logic_vector(rs_t(16 downto 0))), ip'length);
                  rp <= rp - 1;
                  if rp > 1 then
                    rs_rd_addr <= rp - 1;
                    state <= S_RE_REFILL_WAIT;
                  else
                    rs_t <= CELL_ZERO;
                    state <= S_NEXT_OPCODE;
                  end if;
                end if;

              when OP_EQ | OP_NE | OP_LT | OP_GT =>
                if sp < 2 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                else
                  if op = OP_EQ then
                    ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                     ds_t, ds_n, ds_d2, sp, bool_cell(n = t), S_NEXT_OPCODE);
                  elsif op = OP_NE then
                    ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                     ds_t, ds_n, ds_d2, sp, bool_cell(n /= t), S_NEXT_OPCODE);
                  elsif op = OP_LT then
                    ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                     ds_t, ds_n, ds_d2, sp, bool_cell(n < t), S_NEXT_OPCODE);
                  else
                    ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                     ds_t, ds_n, ds_d2, sp, bool_cell(n > t), S_NEXT_OPCODE);
                  end if;
                  sp <= sp - 1;
                end if;

              when OP_FE =>
                if sp = 0 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                elsif STRICT_ERRORS and not valid_addr(t) then
                  err_reg <= ERR_MEM;
                  state <= S_ERROR;
                else
                  mem_addr_reg <= cell_addr(t);
                  mem_op <= M_FE;
                  state <= S_MEM_READ_REQ;
                end if;

              when OP_ST =>
                if sp < 2 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                elsif STRICT_ERRORS and not valid_addr(t) then
                  err_reg <= ERR_MEM;
                  state <= S_ERROR;
                else
                  mem_addr_reg <= cell_addr(t);
                  mem_wdata_reg <= n;
                  state <= S_MEM_WRITE_REQ;
                end if;

              when OP_AD | OP_SU | OP_MU | OP_AN | OP_OR | OP_XO | OP_SL | OP_SR =>
                if sp < 2 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                else
                  if op = OP_AD then
                    ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                     ds_t, ds_n, ds_d2, sp, n + t, S_NEXT_OPCODE);
                  elsif op = OP_SU then
                    ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                     ds_t, ds_n, ds_d2, sp, n - t, S_NEXT_OPCODE);
                  elsif op = OP_MU then
                    mul_product <= n * t;
                    mul_sp <= sp;
                    state <= S_MUL_WRITEBACK;
                  elsif op = OP_AN then
                    ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                     ds_t, ds_n, ds_d2, sp, n and t, S_NEXT_OPCODE);
                  elsif op = OP_OR then
                    ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                     ds_t, ds_n, ds_d2, sp, n or t, S_NEXT_OPCODE);
                  elsif op = OP_XO then
                    ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                     ds_t, ds_n, ds_d2, sp, n xor t, S_NEXT_OPCODE);
                  elsif op = OP_SL then
                    ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                     ds_t, ds_n, ds_d2, sp, shift_left(n, shift_amount(t)), S_NEXT_OPCODE);
                  else
                    ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                     ds_t, ds_n, ds_d2, sp, shift_right(n, shift_amount(t)), S_NEXT_OPCODE);
                  end if;
                  if op /= OP_MU then
                    sp <= sp - 1;
                  end if;
                end if;

              when OP_DI =>
                if sp < 2 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                elsif t = CELL_ZERO then
                  err_reg <= ERR_DBZ;
                  state <= S_ERROR;
                else
                  div_divisor_abs <= abs_cell(t);
                  div_quotient <= abs_cell(n);
                  div_remainder <= (others => '0');
                  div_count <= to_unsigned(32, div_count'length);
                  div_quot_neg <= n(CELL_WIDTH - 1) xor t(CELL_WIDTH - 1);
                  div_rem_neg <= n(CELL_WIDTH - 1);
                  div_sp <= sp;
                  state <= S_DIV_STEP;
                end if;

              when OP_CP =>
                if sp < 3 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                elsif STRICT_ERRORS and
                      (not valid_addr(d) or
                       not valid_addr(n) or
                       t < CELL_ZERO) then
                  err_reg <= ERR_MEM;
                  state <= S_ERROR;
                else
                  cp_src <= cell_addr(d);
                  cp_dst <= cell_addr(n);
                  cp_len <= unsigned(std_logic_vector(t));
                  cp_flag <= CELL_TRUE;
                  if t = CELL_ZERO then
                    ds_drop2_to(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                                ds_t, ds_n, ds_d2, sp, CELL_TRUE, S_NEXT_OPCODE);
                    sp <= sp - 2;
                  else
                    ds_drop2(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                             ds_t, ds_n, ds_d2, sp, S_CP_READ_SRC_REQ);
                    sp <= sp - 2;
                  end if;
                end if;

              when OP_CY =>
                if sp < 3 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                elsif STRICT_ERRORS and
                      (not valid_addr(d) or
                       not valid_addr(n) or
                       t < CELL_ZERO) then
                  err_reg <= ERR_MEM;
                  state <= S_ERROR;
                else
                  cy_src <= cell_addr(d);
                  cy_dst <= cell_addr(n);
                  cy_len <= unsigned(std_logic_vector(t));
                  sp <= sp - 3;
                  if t = CELL_ZERO then
                    ds_drop3(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                             ds_t, ds_n, ds_d2, sp, S_NEXT_OPCODE);
                  else
                    ds_drop3(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                             ds_t, ds_n, ds_d2, sp, S_CY_READ_REQ);
                  end if;
                end if;

              when OP_IO =>
                if sp = 0 then
                  err_reg <= ERR_DSU;
                  state <= S_ERROR;
                else
                  if t = to_signed(0, CELL_WIDTH) then
                    if sp < 2 then
                      err_reg <= ERR_DSU;
                      state <= S_ERROR;
                    else
                      tx_pending_data <= std_logic_vector(n(7 downto 0));
                      state <= S_TX_WAIT;
                    end if;
                  elsif t = to_signed(1, CELL_WIDTH) then
                    if sp = DS_DEPTH then
                      err_reg <= ERR_DSO;
                      state <= S_ERROR;
                    else
                      ds_drop1(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                               ds_t, ds_n, ds_d2, sp, S_IO_WAIT);
                      sp <= sp - 1;
                      rx_req_reg <= '1';
                    end if;
                  elsif t = to_signed(2, CELL_WIDTH) then
                    if sp < 3 then
                      err_reg <= ERR_DSU;
                      state <= S_ERROR;
                    elsif STRICT_ERRORS and
                          (d < CELL_ZERO or
                           not valid_addr(n) or
                           n > to_signed(64512, CELL_WIDTH)) then
                      err_reg <= ERR_MEM;
                      state <= S_ERROR;
                    else
                      io_block_base <= shift_left(unsigned(std_logic_vector(d)), 10);
                      io_buffer <= cell_addr(n);
                      io_offset <= (others => '0');
                      ds_drop3(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                               ds_t, ds_n, ds_d2, sp, S_BLOCK_READ_REQ);
                      sp <= sp - 3;
                    end if;
                  elsif t = to_signed(3, CELL_WIDTH) then
                    if sp < 3 then
                      err_reg <= ERR_DSU;
                      state <= S_ERROR;
                    elsif STRICT_ERRORS and
                          (d < CELL_ZERO or
                           not valid_addr(n) or
                           n > to_signed(64512, CELL_WIDTH)) then
                      err_reg <= ERR_MEM;
                      state <= S_ERROR;
                    else
                      io_block_base <= shift_left(unsigned(std_logic_vector(d)), 10);
                      io_buffer <= cell_addr(n);
                      io_offset <= (others => '0');
                      ds_drop3(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                               ds_t, ds_n, ds_d2, sp, S_BLOCK_MEM_READ_REQ);
                      sp <= sp - 3;
                    end if;
                  elsif t = to_signed(5, CELL_WIDTH) then
                    ds_drop1(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                             ds_t, ds_n, ds_d2, sp, S_RELOAD_REQ);
                    sp <= sp - 1;
                  elsif t = to_signed(6, CELL_WIDTH) then
                    ds_drop1(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                             ds_t, ds_n, ds_d2, sp, S_HALT);
                    sp <= sp - 1;
                  elsif t = to_signed(7, CELL_WIDTH) then
                    if sp > DS_DEPTH - 1 then
                      err_reg <= ERR_DSO;
                      state <= S_ERROR;
                    else
                      if sp >= 3 then
                        ds_wr_addr <= sp - 2;
                        ds_wr_data <= d;
                        ds_wr_en <= '1';
                      end if;
                      ds_d2 <= n;
                      ds_n <= to_signed(sp - 1, CELL_WIDTH);
                      ds_t <= to_signed(rp, CELL_WIDTH);
                      sp <= sp + 1;
                      state <= S_NEXT_OPCODE;
                    end if;
                  elsif STRICT_ERRORS then
                    err_reg <= ERR_MEM;
                    state <= S_ERROR;
                  else
                    ds_drop1(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                             ds_t, ds_n, ds_d2, sp, S_NEXT_OPCODE);
                    sp <= sp - 1;
                  end if;
                end if;

              when others =>
                state <= S_NEXT_OPCODE;
            end case;

          when S_MEM_READ_REQ =>
            mem_req_reg <= '1';
            state <= S_MEM_READ_WAIT;

          when S_MEM_READ_WAIT =>
            mem_req_reg <= '1';
            if mem_ready = '1' then
              mem_req_reg <= '0';
              if mem_op = M_LI then
                ds_push(ds_wr_en, ds_wr_addr, ds_wr_data, ds_t, ds_n, ds_d2, sp, mem_rdata);
                sp <= sp + 1;
              elsif mem_op = M_FE then
                ds_t <= mem_rdata;
              end if;
              mem_op <= M_NONE;
              state <= S_NEXT_OPCODE;
            end if;

          when S_MEM_WRITE_REQ =>
            mem_req_reg <= '1';
            mem_we_reg <= '1';
            state <= S_MEM_WRITE_WAIT;

          when S_MEM_WRITE_WAIT =>
            mem_req_reg <= '1';
            mem_we_reg <= '1';
            if mem_ready = '1' then
              mem_req_reg <= '0';
              mem_we_reg <= '0';
              ds_drop2(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                       ds_t, ds_n, ds_d2, sp, S_NEXT_OPCODE);
              sp <= sp - 2;
            end if;

          when S_CP_READ_SRC_REQ =>
            mem_addr_reg <= cp_src;
            mem_req_reg <= '1';
            state <= S_CP_READ_SRC_WAIT;

          when S_CP_READ_SRC_WAIT =>
            mem_req_reg <= '1';
            if mem_ready = '1' then
              mem_req_reg <= '0';
              cp_src_val <= mem_rdata;
              state <= S_CP_READ_DST_REQ;
            end if;

          when S_CP_READ_DST_REQ =>
            mem_addr_reg <= cp_dst;
            mem_req_reg <= '1';
            state <= S_CP_READ_DST_WAIT;

          when S_CP_READ_DST_WAIT =>
            mem_req_reg <= '1';
            if mem_ready = '1' then
              mem_req_reg <= '0';
              if cp_src_val /= mem_rdata then
                cp_flag <= CELL_ZERO;
              end if;
              if cp_len = 1 then
                if cp_src_val /= mem_rdata then
                  ds_t <= CELL_ZERO;
                else
                  ds_t <= cp_flag;
                end if;
                state <= S_NEXT_OPCODE;
              else
                cp_src <= cp_src + 1;
                cp_dst <= cp_dst + 1;
                cp_len <= cp_len - 1;
                state <= S_CP_READ_SRC_REQ;
              end if;
            end if;

          when S_CY_READ_REQ =>
            mem_addr_reg <= cy_src;
            mem_req_reg <= '1';
            state <= S_CY_READ_WAIT;

          when S_CY_READ_WAIT =>
            mem_req_reg <= '1';
            if mem_ready = '1' then
              mem_req_reg <= '0';
              cy_value <= mem_rdata;
              state <= S_CY_WRITE_REQ;
            end if;

          when S_CY_WRITE_REQ =>
            mem_addr_reg <= cy_dst;
            mem_wdata_reg <= cy_value;
            mem_req_reg <= '1';
            mem_we_reg <= '1';
            state <= S_CY_WRITE_WAIT;

          when S_CY_WRITE_WAIT =>
            mem_req_reg <= '1';
            mem_we_reg <= '1';
            if mem_ready = '1' then
              mem_req_reg <= '0';
              mem_we_reg <= '0';
              if cy_len = 1 then
                state <= S_NEXT_OPCODE;
              else
                cy_src <= cy_src + 1;
                cy_dst <= cy_dst + 1;
                cy_len <= cy_len - 1;
                state <= S_CY_READ_REQ;
              end if;
            end if;

          when S_IO_WAIT =>
            if serial_rx_valid = '1' then
              rx_req_reg <= '0';
              ds_push(ds_wr_en, ds_wr_addr, ds_wr_data,
                      ds_t, ds_n, ds_d2, sp, signed(resize(unsigned(serial_rx_data), CELL_WIDTH)));
              sp <= sp + 1;
              state <= S_NEXT_OPCODE;
            end if;

          when S_TX_WAIT =>
            if serial_tx_ready = '1' then
              tx_data_reg <= tx_pending_data;
              tx_valid_reg <= '1';
              ds_drop2(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                       ds_t, ds_n, ds_d2, sp, S_NEXT_OPCODE);
              sp <= sp - 2;
            end if;

          when S_BLOCK_READ_REQ =>
            block_addr_reg <= io_block_base + resize(io_offset, block_addr_reg'length);
            block_req_reg <= '1';
            state <= S_BLOCK_READ_WAIT;

          when S_BLOCK_READ_WAIT =>
            block_req_reg <= '1';
            if block_ready = '1' then
              block_req_reg <= '0';
              io_cell <= block_rdata;
              state <= S_BLOCK_MEM_WRITE_REQ;
            end if;

          when S_BLOCK_MEM_WRITE_REQ =>
            mem_addr_reg <= io_buffer + resize(io_offset, mem_addr_reg'length);
            mem_wdata_reg <= io_cell;
            mem_req_reg <= '1';
            mem_we_reg <= '1';
            state <= S_BLOCK_MEM_WRITE_WAIT;

          when S_BLOCK_MEM_WRITE_WAIT =>
            mem_req_reg <= '1';
            mem_we_reg <= '1';
            if mem_ready = '1' then
              mem_req_reg <= '0';
              mem_we_reg <= '0';
              if io_offset = to_unsigned(1023, io_offset'length) then
                state <= S_NEXT_OPCODE;
              else
                io_offset <= io_offset + 1;
                state <= S_BLOCK_READ_REQ;
              end if;
            end if;

          when S_BLOCK_MEM_READ_REQ =>
            mem_addr_reg <= io_buffer + resize(io_offset, mem_addr_reg'length);
            mem_req_reg <= '1';
            state <= S_BLOCK_MEM_READ_WAIT;

          when S_BLOCK_MEM_READ_WAIT =>
            mem_req_reg <= '1';
            if mem_ready = '1' then
              mem_req_reg <= '0';
              io_cell <= mem_rdata;
              state <= S_BLOCK_WRITE_REQ;
            end if;

          when S_BLOCK_WRITE_REQ =>
            block_addr_reg <= io_block_base + resize(io_offset, block_addr_reg'length);
            block_wdata_reg <= io_cell;
            block_req_reg <= '1';
            block_we_reg <= '1';
            state <= S_BLOCK_WRITE_WAIT;

          when S_BLOCK_WRITE_WAIT =>
            block_req_reg <= '1';
            block_we_reg <= '1';
            if block_ready = '1' then
              block_req_reg <= '0';
              block_we_reg <= '0';
              if io_offset = to_unsigned(1023, io_offset'length) then
                state <= S_NEXT_OPCODE;
              else
                io_offset <= io_offset + 1;
                state <= S_BLOCK_MEM_READ_REQ;
              end if;
            end if;

          when S_RELOAD_REQ =>
            reload_req_reg <= '1';
            state <= S_RELOAD_WAIT;

          when S_RELOAD_WAIT =>
            reload_req_reg <= '1';
            if reload_ready = '1' then
              reload_req_reg <= '0';
              ip <= (others => '0');
              idx <= (others => '0');
              sp <= 0;
              rp <= 0;
              ds_t <= CELL_ZERO;
              ds_n <= CELL_ZERO;
              ds_d2 <= CELL_ZERO;
              rs_t <= CELL_ZERO;
              mem_op <= M_NONE;
              rx_req_reg <= '0';
              ds_rd_addr <= 0;
              ds_wr_addr <= 0;
              ds_wr_data <= CELL_ZERO;
              ds_refill_count <= 0;
              ds_refill_resume <= S_NEXT_OPCODE;
              rs_rd_addr <= 0;
              rs_wr_addr <= 0;
              rs_wr_data <= CELL_ZERO;
              state <= S_FETCH_REQ;
            end if;

          when S_DS_REFILL_WAIT =>
            state <= S_DS_REFILL_CAPTURE;

          when S_DS_REFILL_CAPTURE =>
            case ds_refill_target is
              when DS_REFILL_TOP => ds_t <= ds_rd_data;
              when DS_REFILL_N => ds_n <= ds_rd_data;
              when DS_REFILL_D2 => ds_d2 <= ds_rd_data;
            end case;

            if ds_refill_count = 1 then
              ds_refill_count <= 0;
              state <= ds_refill_resume;
            else
              ds_refill_count <= ds_refill_count - 1;
              ds_rd_addr <= ds_rd_addr - 1;
              case ds_refill_target is
                when DS_REFILL_TOP => ds_refill_target <= DS_REFILL_N;
                when DS_REFILL_N => ds_refill_target <= DS_REFILL_D2;
                when DS_REFILL_D2 => ds_refill_target <= DS_REFILL_D2;
              end case;
              state <= S_DS_REFILL_WAIT;
            end if;

          when S_PO_REFILL_WAIT =>
            state <= S_PO_REFILL_CAPTURE;

          when S_PO_REFILL_CAPTURE =>
            rs_t <= rs_rd_data;
            state <= S_NEXT_OPCODE;

          when S_RE_REFILL_WAIT =>
            state <= S_RE_REFILL_CAPTURE;

          when S_RE_REFILL_CAPTURE =>
            rs_t <= rs_rd_data;
            state <= S_NEXT_OPCODE;

          when S_MUL_WRITEBACK =>
            ds_binary_result(ds_rd_addr, ds_refill_count, ds_refill_target, ds_refill_resume, state,
                             ds_t, ds_n, ds_d2, sp, mul_product(31 downto 0), S_NEXT_OPCODE);
            sp <= sp - 1;

          when S_DIV_STEP =>
            rem_shift := div_remainder(31 downto 0) & div_quotient(31);
            quot_shift := div_quotient(30 downto 0) & '0';
            divisor_ext := '0' & div_divisor_abs;

            if rem_shift >= divisor_ext then
              rem_shift := rem_shift - divisor_ext;
              quot_shift(0) := '1';
            end if;

            div_remainder <= rem_shift;
            div_quotient <= quot_shift;
            div_count <= div_count - 1;

            if div_count = 1 then
              quot_cell := signed_magnitude(quot_shift, div_quot_neg);
              rem_cell := signed_magnitude(rem_shift(31 downto 0), div_rem_neg);
              ds_t <= quot_cell;
              ds_n <= rem_cell;
              state <= S_NEXT_OPCODE;
            end if;

          when S_NEXT_OPCODE =>
            if idx = 3 then
              ip <= ip + 1;
              idx <= (others => '0');
              state <= S_FETCH_REQ;
            else
              idx <= idx + 1;
              state <= S_DECODE;
            end if;

          when S_HALT =>
            -- HALT and ERROR are sticky terminal states until external reset.
            halted_reg <= '1';
            state <= S_HALT;

          when S_ERROR =>
            error_reg <= '1';
            state <= S_ERROR;
        end case;
      end if;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/rtl/ilo_memory.vhd.


















































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

use work.ilo_pkg.all;

entity ilo_memory is
  generic (
    ROM_FILE : string := "";
    READ_WAIT_CYCLES : natural := 0;
    WRITE_WAIT_CYCLES : natural := 0;
    POISON_UNINITIALIZED : boolean := false
  );
  port (
    clk    : in  std_logic;
    req    : in  std_logic;
    we     : in  std_logic;
    addr   : in  addr_t;
    wdata  : in  cell_t;
    rdata  : out cell_t;
    ready  : out std_logic;
    reload_req   : in  std_logic;
    reload_ready : out std_logic
  );
end entity;

architecture rtl of ilo_memory is
  type state_t is (S_IDLE, S_WAIT, S_READY, S_WAIT_RELEASE);

  signal ram        : mem_array_t := (others => CELL_ZERO);
  signal rdata_reg  : cell_t := CELL_ZERO;
  signal ready_reg  : std_logic := '0';
  signal reload_ready_reg : std_logic := '0';
  signal state      : state_t := S_IDLE;
  signal wait_count : natural := 0;

  -- synthesis translate_off
  constant POISON_CELL : cell_t := to_signed(-559038737, CELL_WIDTH); -- 0xDEADBEEF
  type mem_valid_array_t is array (0 to MEM_DEPTH - 1) of boolean;
  -- synthesis translate_on
begin
  rdata <= rdata_reg;
  ready <= ready_reg;
  reload_ready <= reload_ready_reg;

  process(clk)
    -- synthesis translate_off
    file f : text;
    variable l : line;
    variable v : integer;
    variable i : natural := 0;
    variable initialized : boolean := false;
    variable valid : mem_valid_array_t := (others => false);
    -- synthesis translate_on
    variable a : natural;
    variable target_wait : natural;
  begin
    if rising_edge(clk) then
      -- synthesis translate_off
      if not initialized then
        if ROM_FILE /= "" then
          file_open(f, ROM_FILE, read_mode);
          while not endfile(f) and i < MEM_DEPTH loop
            readline(f, l);
            read(l, v);
            ram(i) <= to_signed(v, CELL_WIDTH);
            valid(i) := true;
            i := i + 1;
          end loop;
          file_close(f);
        end if;
        initialized := true;
      end if;
      -- synthesis translate_on

      ready_reg <= '0';
      reload_ready_reg <= '0';

      if reload_req = '1' then
        ready_reg <= '0';
        reload_ready_reg <= '1';
        state <= S_IDLE;
        wait_count <= 0;
      else
        case state is
          when S_IDLE =>
            wait_count <= 0;
            if req = '1' then
              state <= S_WAIT;
            end if;

          when S_WAIT =>
            if we = '1' then
              target_wait := WRITE_WAIT_CYCLES;
            else
              target_wait := READ_WAIT_CYCLES;
            end if;

            if wait_count >= target_wait then
              a := to_integer(addr);
              if we = '1' then
                ram(a) <= wdata;
                rdata_reg <= wdata;
                -- synthesis translate_off
                valid(a) := true;
                -- synthesis translate_on
              else
                -- synthesis translate_off
                if POISON_UNINITIALIZED and not valid(a) then
                  rdata_reg <= POISON_CELL;
                else
                -- synthesis translate_on
                rdata_reg <= ram(a);
                -- synthesis translate_off
                end if;
                -- synthesis translate_on
              end if;
              ready_reg <= '1';
              wait_count <= 0;
              state <= S_READY;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_READY =>
            state <= S_WAIT_RELEASE;

          when S_WAIT_RELEASE =>
            if req = '0' then
              state <= S_IDLE;
            end if;
        end case;
      end if;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/rtl/ilo_pkg.vhd.
















































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package ilo_pkg is
  constant CELL_WIDTH     : natural := 32;
  constant MEM_ADDR_WIDTH : natural := 16;
  constant MEM_DEPTH      : natural := 65536;
  constant DS_DEPTH       : natural := 32;
  constant RS_DEPTH       : natural := 256;

  subtype cell_t is signed(CELL_WIDTH - 1 downto 0);
  subtype addr_t is unsigned(MEM_ADDR_WIDTH - 1 downto 0);

  type mem_array_t is array (0 to MEM_DEPTH - 1) of cell_t;
  type ds_array_t is array (0 to DS_DEPTH - 1) of cell_t;
  type rs_array_t is array (0 to RS_DEPTH - 1) of cell_t;

  constant CELL_ZERO : cell_t := to_signed(0, CELL_WIDTH);
  constant CELL_TRUE : cell_t := to_signed(-1, CELL_WIDTH);

  constant OP_NOP : natural := 0;
  constant OP_LI  : natural := 1;
  constant OP_DU  : natural := 2;
  constant OP_DR  : natural := 3;
  constant OP_SW  : natural := 4;
  constant OP_PU  : natural := 5;
  constant OP_PO  : natural := 6;
  constant OP_JU  : natural := 7;
  constant OP_CA  : natural := 8;
  constant OP_CC  : natural := 9;
  constant OP_CJ  : natural := 10;
  constant OP_RE  : natural := 11;
  constant OP_EQ  : natural := 12;
  constant OP_NE  : natural := 13;
  constant OP_LT  : natural := 14;
  constant OP_GT  : natural := 15;
  constant OP_FE  : natural := 16;
  constant OP_ST  : natural := 17;
  constant OP_AD  : natural := 18;
  constant OP_SU  : natural := 19;
  constant OP_MU  : natural := 20;
  constant OP_DI  : natural := 21;
  constant OP_AN  : natural := 22;
  constant OP_OR  : natural := 23;
  constant OP_XO  : natural := 24;
  constant OP_SL  : natural := 25;
  constant OP_SR  : natural := 26;
  constant OP_CP  : natural := 27;
  constant OP_CY  : natural := 28;
  constant OP_IO  : natural := 29;

  function bool_cell(value : boolean) return cell_t;
  function cell_addr(value : cell_t) return addr_t;
  function shift_amount(value : cell_t) return natural;

  -- synthesis translate_off
  type ds_debug_array_t is array (0 to DS_DEPTH) of cell_t;

  type sim_debug_t is protected
    procedure set_sp(value : natural);
    procedure set_rp(value : natural);
    procedure set_ds(index : natural; value : cell_t);
    impure function get_sp return natural;
    impure function get_rp return natural;
    impure function get_ds(index : natural) return cell_t;
  end protected sim_debug_t;

  shared variable sim_debug : sim_debug_t;
  -- synthesis translate_on
end package;

package body ilo_pkg is
  function bool_cell(value : boolean) return cell_t is
  begin
    if value then
      return CELL_TRUE;
    end if;
    return CELL_ZERO;
  end function;

  function cell_addr(value : cell_t) return addr_t is
  begin
    return unsigned(std_logic_vector(value(15 downto 0)));
  end function;

  function shift_amount(value : cell_t) return natural is
    variable raw : unsigned(4 downto 0);
  begin
    raw := unsigned(std_logic_vector(value(4 downto 0)));
    return to_integer(raw);
  end function;

  -- synthesis translate_off
  type sim_debug_t is protected body
    variable sp_value : natural := 0;
    variable rp_value : natural := 0;
    variable ds_value : ds_debug_array_t := (others => CELL_ZERO);

    procedure set_sp(value : natural) is
    begin
      sp_value := value;
    end procedure;

    procedure set_rp(value : natural) is
    begin
      rp_value := value;
    end procedure;

    procedure set_ds(index : natural; value : cell_t) is
    begin
      if index <= DS_DEPTH then
        ds_value(index) := value;
      end if;
    end procedure;

    impure function get_sp return natural is
    begin
      return sp_value;
    end function;

    impure function get_rp return natural is
    begin
      return rp_value;
    end function;

    impure function get_ds(index : natural) return cell_t is
    begin
      if index <= DS_DEPTH then
        return ds_value(index);
      end if;
      return CELL_ZERO;
    end function;
  end protected body sim_debug_t;
  -- synthesis translate_on
end package body;
Added ilo-vm/vhdl/rtl/ilo_sdram_controller.vhd.


































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.ilo_pkg.all;

entity ilo_sdram_controller is
  generic (
    INIT_WAIT_CYCLES : natural := 10000;
    REFRESH_INTERVAL_CYCLES : natural := 390;
    TRCD_CYCLES : natural := 1;
    TRP_CYCLES : natural := 1;
    TRFC_CYCLES : natural := 4;
    TMRD_CYCLES : natural := 2;
    READ_WAIT_CYCLES : natural := 3;
    WRITE_RECOVERY_CYCLES : natural := 2
  );
  port (
    clk       : in  std_logic;
    reset     : in  std_logic;

    req       : in  std_logic;
    we        : in  std_logic;
    addr      : in  addr_t;
    wdata     : in  cell_t;
    rdata     : out cell_t;
    ready     : out std_logic;

    reload_req   : in  std_logic;
    reload_ready : out std_logic;

    sdram_a    : out unsigned(12 downto 0);
    sdram_ba   : out unsigned(1 downto 0);
    sdram_dq   : inout std_logic_vector(15 downto 0);
    sdram_dqm  : out std_logic_vector(1 downto 0);
    sdram_csn  : out std_logic;
    sdram_cke  : out std_logic;
    sdram_clk  : out std_logic;
    sdram_wen  : out std_logic;
    sdram_casn : out std_logic;
    sdram_rasn : out std_logic
  );
end entity;

architecture rtl of ilo_sdram_controller is
  type state_t is (
    S_INIT_WAIT,
    S_INIT_PRECHARGE,
    S_INIT_PRECHARGE_WAIT,
    S_INIT_REFRESH_1,
    S_INIT_REFRESH_1_WAIT,
    S_INIT_REFRESH_2,
    S_INIT_REFRESH_2_WAIT,
    S_INIT_MODE,
    S_INIT_MODE_WAIT,
    S_IDLE,
    S_REFRESH,
    S_REFRESH_WAIT,
    S_ACTIVE,
    S_ACTIVE_WAIT,
    S_READ_CMD,
    S_READ_WAIT,
    S_READ_SAMPLE,
    S_WRITE_CMD,
    S_WRITE_WAIT,
    S_DONE,
    S_WAIT_RELEASE
  );

  constant CMD_DESELECT : std_logic_vector(3 downto 0) := "1111";
  constant CMD_NOP      : std_logic_vector(3 downto 0) := "0111";
  constant CMD_ACTIVE   : std_logic_vector(3 downto 0) := "0011";
  constant CMD_READ     : std_logic_vector(3 downto 0) := "0101";
  constant CMD_WRITE    : std_logic_vector(3 downto 0) := "0100";
  constant CMD_PRECHARGE: std_logic_vector(3 downto 0) := "0010";
  constant CMD_REFRESH  : std_logic_vector(3 downto 0) := "0001";
  constant CMD_MODE     : std_logic_vector(3 downto 0) := "0000";

  signal state : state_t := S_INIT_WAIT;
  signal wait_count : natural := 0;
  signal refresh_count : natural := 0;
  signal latched_we : std_logic := '0';
  signal latched_addr : addr_t := (others => '0');
  signal latched_wdata : cell_t := CELL_ZERO;
  signal half_index : std_logic := '0';
  signal rdata_reg : cell_t := CELL_ZERO;
  signal ready_reg : std_logic := '0';
  signal reload_ready_reg : std_logic := '0';

  signal sdram_a_reg : unsigned(12 downto 0) := (others => '0');
  signal sdram_ba_reg : unsigned(1 downto 0) := (others => '0');
  signal sdram_dq_out : std_logic_vector(15 downto 0) := (others => '0');
  signal sdram_dq_drive : std_logic := '0';
  signal sdram_dqm_reg : std_logic_vector(1 downto 0) := (others => '0');
  signal sdram_cmd : std_logic_vector(3 downto 0) := CMD_DESELECT;
  signal sdram_cke_reg : std_logic := '0';

  function halfword_addr(word_addr : addr_t; half_sel : std_logic) return unsigned is
    variable result : unsigned(MEM_ADDR_WIDTH downto 0);
  begin
    result := word_addr & half_sel;
    return result;
  end function;

  function row_addr(word_addr : addr_t; half_sel : std_logic) return unsigned is
    variable h : unsigned(MEM_ADDR_WIDTH downto 0);
    variable result : unsigned(12 downto 0) := (others => '0');
  begin
    h := halfword_addr(word_addr, half_sel);
    result(5 downto 0) := h(16 downto 11);
    return result;
  end function;

  function col_addr(word_addr : addr_t; half_sel : std_logic) return unsigned is
    variable h : unsigned(MEM_ADDR_WIDTH downto 0);
    variable result : unsigned(12 downto 0) := (others => '0');
  begin
    h := halfword_addr(word_addr, half_sel);
    result(8 downto 0) := h(8 downto 0);
    result(10) := '1';
    return result;
  end function;

  function bank_addr(word_addr : addr_t; half_sel : std_logic) return unsigned is
    variable h : unsigned(MEM_ADDR_WIDTH downto 0);
  begin
    h := halfword_addr(word_addr, half_sel);
    return h(10 downto 9);
  end function;

  function select_half(value : cell_t; half_sel : std_logic) return std_logic_vector is
    variable bits : std_logic_vector(CELL_WIDTH - 1 downto 0);
  begin
    bits := std_logic_vector(value);
    if half_sel = '0' then
      return bits(15 downto 0);
    end if;
    return bits(31 downto 16);
  end function;
begin
  rdata <= rdata_reg;
  ready <= ready_reg;
  reload_ready <= reload_ready_reg;

  sdram_a <= sdram_a_reg;
  sdram_ba <= sdram_ba_reg;
  sdram_dq <= sdram_dq_out when sdram_dq_drive = '1' else (others => 'Z');
  sdram_dqm <= sdram_dqm_reg;
  sdram_csn <= sdram_cmd(3);
  sdram_rasn <= sdram_cmd(2);
  sdram_casn <= sdram_cmd(1);
  sdram_wen <= sdram_cmd(0);
  sdram_cke <= sdram_cke_reg;
  sdram_clk <= clk;

  process(clk)
    variable rbits : std_logic_vector(CELL_WIDTH - 1 downto 0);
  begin
    if rising_edge(clk) then
      ready_reg <= '0';
      reload_ready_reg <= '0';
      sdram_cmd <= CMD_NOP;
      sdram_dq_drive <= '0';
      sdram_dqm_reg <= (others => '0');

      if reset = '1' then
        state <= S_INIT_WAIT;
        wait_count <= 0;
        refresh_count <= 0;
        latched_we <= '0';
        latched_addr <= (others => '0');
        latched_wdata <= CELL_ZERO;
        half_index <= '0';
        rdata_reg <= CELL_ZERO;
        sdram_a_reg <= (others => '0');
        sdram_ba_reg <= (others => '0');
        sdram_dq_out <= (others => '0');
        sdram_cmd <= CMD_DESELECT;
        sdram_cke_reg <= '0';
      else
        if state /= S_INIT_WAIT and state /= S_INIT_PRECHARGE and
           state /= S_INIT_PRECHARGE_WAIT and state /= S_INIT_REFRESH_1 and
           state /= S_INIT_REFRESH_1_WAIT and state /= S_INIT_REFRESH_2 and
           state /= S_INIT_REFRESH_2_WAIT and state /= S_INIT_MODE and
           state /= S_INIT_MODE_WAIT and state /= S_REFRESH and
           state /= S_REFRESH_WAIT then
          if refresh_count < REFRESH_INTERVAL_CYCLES then
            refresh_count <= refresh_count + 1;
          end if;
        end if;

        case state is
          when S_INIT_WAIT =>
            sdram_cke_reg <= '1';
            if wait_count >= INIT_WAIT_CYCLES then
              wait_count <= 0;
              state <= S_INIT_PRECHARGE;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_INIT_PRECHARGE =>
            sdram_cmd <= CMD_PRECHARGE;
            sdram_a_reg <= (others => '0');
            sdram_a_reg(10) <= '1';
            wait_count <= 0;
            state <= S_INIT_PRECHARGE_WAIT;

          when S_INIT_PRECHARGE_WAIT =>
            if wait_count >= TRP_CYCLES then
              wait_count <= 0;
              state <= S_INIT_REFRESH_1;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_INIT_REFRESH_1 =>
            sdram_cmd <= CMD_REFRESH;
            wait_count <= 0;
            state <= S_INIT_REFRESH_1_WAIT;

          when S_INIT_REFRESH_1_WAIT =>
            if wait_count >= TRFC_CYCLES then
              wait_count <= 0;
              state <= S_INIT_REFRESH_2;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_INIT_REFRESH_2 =>
            sdram_cmd <= CMD_REFRESH;
            wait_count <= 0;
            state <= S_INIT_REFRESH_2_WAIT;

          when S_INIT_REFRESH_2_WAIT =>
            if wait_count >= TRFC_CYCLES then
              wait_count <= 0;
              state <= S_INIT_MODE;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_INIT_MODE =>
            sdram_cmd <= CMD_MODE;
            sdram_ba_reg <= (others => '0');
            sdram_a_reg <= (others => '0');
            sdram_a_reg(6 downto 4) <= "010";
            wait_count <= 0;
            state <= S_INIT_MODE_WAIT;

          when S_INIT_MODE_WAIT =>
            if wait_count >= TMRD_CYCLES then
              wait_count <= 0;
              refresh_count <= 0;
              state <= S_IDLE;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_IDLE =>
            if refresh_count >= REFRESH_INTERVAL_CYCLES then
              state <= S_REFRESH;
            elsif reload_req = '1' then
              reload_ready_reg <= '1';
            elsif req = '1' then
              latched_we <= we;
              latched_addr <= addr;
              latched_wdata <= wdata;
              half_index <= '0';
              state <= S_ACTIVE;
            end if;

          when S_REFRESH =>
            sdram_cmd <= CMD_REFRESH;
            wait_count <= 0;
            refresh_count <= 0;
            state <= S_REFRESH_WAIT;

          when S_REFRESH_WAIT =>
            if wait_count >= TRFC_CYCLES then
              wait_count <= 0;
              state <= S_IDLE;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_ACTIVE =>
            sdram_cmd <= CMD_ACTIVE;
            sdram_a_reg <= row_addr(latched_addr, half_index);
            sdram_ba_reg <= bank_addr(latched_addr, half_index);
            wait_count <= 0;
            state <= S_ACTIVE_WAIT;

          when S_ACTIVE_WAIT =>
            if wait_count >= TRCD_CYCLES then
              wait_count <= 0;
              if latched_we = '1' then
                state <= S_WRITE_CMD;
              else
                state <= S_READ_CMD;
              end if;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_READ_CMD =>
            sdram_cmd <= CMD_READ;
            sdram_a_reg <= col_addr(latched_addr, half_index);
            sdram_ba_reg <= bank_addr(latched_addr, half_index);
            wait_count <= 0;
            state <= S_READ_WAIT;

          when S_READ_WAIT =>
            if wait_count >= READ_WAIT_CYCLES then
              wait_count <= 0;
              state <= S_READ_SAMPLE;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_READ_SAMPLE =>
            rbits := std_logic_vector(rdata_reg);
            if half_index = '0' then
              rbits(15 downto 0) := sdram_dq;
              half_index <= '1';
              rdata_reg <= signed(rbits);
              state <= S_ACTIVE;
            else
              rbits(31 downto 16) := sdram_dq;
              rdata_reg <= signed(rbits);
              state <= S_DONE;
            end if;

          when S_WRITE_CMD =>
            sdram_cmd <= CMD_WRITE;
            sdram_a_reg <= col_addr(latched_addr, half_index);
            sdram_ba_reg <= bank_addr(latched_addr, half_index);
            sdram_dq_out <= select_half(latched_wdata, half_index);
            sdram_dq_drive <= '1';
            wait_count <= 0;
            state <= S_WRITE_WAIT;

          when S_WRITE_WAIT =>
            if wait_count >= WRITE_RECOVERY_CYCLES then
              wait_count <= 0;
              if half_index = '0' then
                half_index <= '1';
                state <= S_ACTIVE;
              else
                rdata_reg <= latched_wdata;
                state <= S_DONE;
              end if;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_DONE =>
            ready_reg <= '1';
            state <= S_WAIT_RELEASE;

          when S_WAIT_RELEASE =>
            if req = '0' then
              state <= S_IDLE;
            end if;
        end case;
      end if;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/rtl/ilo_sram8_controller.vhd.


































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.ilo_pkg.all;

entity ilo_sram8_controller is
  generic (
    SRAM_ADDR_WIDTH : natural := 19;
    READ_WAIT_CYCLES : natural := 1;
    WRITE_WAIT_CYCLES : natural := 1
  );
  port (
    clk       : in  std_logic;
    reset     : in  std_logic;

    req       : in  std_logic;
    we        : in  std_logic;
    addr      : in  addr_t;
    wdata     : in  cell_t;
    rdata     : out cell_t;
    ready     : out std_logic;

    reload_req   : in  std_logic;
    reload_ready : out std_logic;

    sram_addr : out unsigned(SRAM_ADDR_WIDTH - 1 downto 0);
    sram_data : inout std_logic_vector(7 downto 0);
    sram_ce_n : out std_logic;
    sram_oe_n : out std_logic;
    sram_we_n : out std_logic
  );
end entity;

architecture rtl of ilo_sram8_controller is
  type state_t is (
    S_IDLE,
    S_READ_SETUP,
    S_READ_WAIT,
    S_READ_SAMPLE,
    S_WRITE_SETUP,
    S_WRITE_PULSE,
    S_WRITE_HOLD,
    S_DONE,
    S_WAIT_RELEASE
  );

  signal state : state_t := S_IDLE;
  signal latched_we : std_logic := '0';
  signal latched_addr : addr_t := (others => '0');
  signal latched_wdata : cell_t := CELL_ZERO;
  signal rdata_reg : cell_t := CELL_ZERO;
  signal ready_reg : std_logic := '0';
  signal reload_ready_reg : std_logic := '0';
  signal byte_index : unsigned(1 downto 0) := (others => '0');
  signal wait_count : natural := 0;
  signal sram_addr_reg : unsigned(SRAM_ADDR_WIDTH - 1 downto 0) := (others => '0');
  signal sram_dout_reg : std_logic_vector(7 downto 0) := (others => '0');
  signal sram_drive_reg : std_logic := '0';
  signal sram_ce_n_reg : std_logic := '1';
  signal sram_oe_n_reg : std_logic := '1';
  signal sram_we_n_reg : std_logic := '1';

  function byte_addr(
    word_addr : addr_t;
    byte_sel : unsigned(1 downto 0);
    width : natural
  ) return unsigned is
    variable result : unsigned(width - 1 downto 0) := (others => '0');
    variable raw : unsigned(word_addr'length + byte_sel'length - 1 downto 0);
  begin
    raw := word_addr & byte_sel;
    result(raw'length - 1 downto 0) := raw;
    return result;
  end function;

  function select_byte(value : cell_t; byte_sel : unsigned(1 downto 0)) return std_logic_vector is
    variable bits : std_logic_vector(CELL_WIDTH - 1 downto 0);
  begin
    bits := std_logic_vector(value);
    case byte_sel is
      when "00" => return bits(7 downto 0);
      when "01" => return bits(15 downto 8);
      when "10" => return bits(23 downto 16);
      when others => return bits(31 downto 24);
    end case;
  end function;
begin
  rdata <= rdata_reg;
  ready <= ready_reg;
  reload_ready <= reload_ready_reg;

  sram_addr <= sram_addr_reg;
  sram_ce_n <= sram_ce_n_reg;
  sram_oe_n <= sram_oe_n_reg;
  sram_we_n <= sram_we_n_reg;
  sram_data <= sram_dout_reg when sram_drive_reg = '1' else (others => 'Z');

  process(clk)
    variable rbits : std_logic_vector(CELL_WIDTH - 1 downto 0);
  begin
    if rising_edge(clk) then
      ready_reg <= '0';
      reload_ready_reg <= '0';

      if reset = '1' then
        state <= S_IDLE;
        latched_we <= '0';
        latched_addr <= (others => '0');
        latched_wdata <= CELL_ZERO;
        rdata_reg <= CELL_ZERO;
        byte_index <= (others => '0');
        wait_count <= 0;
        sram_addr_reg <= (others => '0');
        sram_dout_reg <= (others => '0');
        sram_drive_reg <= '0';
        sram_ce_n_reg <= '1';
        sram_oe_n_reg <= '1';
        sram_we_n_reg <= '1';
      else
        case state is
          when S_IDLE =>
            sram_drive_reg <= '0';
            sram_ce_n_reg <= '1';
            sram_oe_n_reg <= '1';
            sram_we_n_reg <= '1';
            if reload_req = '1' then
              reload_ready_reg <= '1';
            elsif req = '1' then
              latched_we <= we;
              latched_addr <= addr;
              latched_wdata <= wdata;
              byte_index <= (others => '0');
              if we = '1' then
                state <= S_WRITE_SETUP;
              else
                state <= S_READ_SETUP;
              end if;
            end if;

          when S_READ_SETUP =>
            sram_addr_reg <= byte_addr(latched_addr, byte_index, SRAM_ADDR_WIDTH);
            sram_drive_reg <= '0';
            sram_ce_n_reg <= '0';
            sram_oe_n_reg <= '0';
            sram_we_n_reg <= '1';
            wait_count <= 0;
            state <= S_READ_WAIT;

          when S_READ_WAIT =>
            if wait_count >= READ_WAIT_CYCLES then
              state <= S_READ_SAMPLE;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_READ_SAMPLE =>
            rbits := std_logic_vector(rdata_reg);
            case byte_index is
              when "00" => rbits(7 downto 0) := sram_data;
              when "01" => rbits(15 downto 8) := sram_data;
              when "10" => rbits(23 downto 16) := sram_data;
              when others => rbits(31 downto 24) := sram_data;
            end case;
            rdata_reg <= signed(rbits);
            sram_oe_n_reg <= '1';
            sram_ce_n_reg <= '1';
            if byte_index = "11" then
              state <= S_DONE;
            else
              byte_index <= byte_index + 1;
              state <= S_READ_SETUP;
            end if;

          when S_WRITE_SETUP =>
            sram_addr_reg <= byte_addr(latched_addr, byte_index, SRAM_ADDR_WIDTH);
            sram_dout_reg <= select_byte(latched_wdata, byte_index);
            sram_drive_reg <= '1';
            sram_ce_n_reg <= '0';
            sram_oe_n_reg <= '1';
            sram_we_n_reg <= '1';
            wait_count <= 0;
            state <= S_WRITE_PULSE;

          when S_WRITE_PULSE =>
            sram_we_n_reg <= '0';
            if wait_count >= WRITE_WAIT_CYCLES then
              wait_count <= 0;
              state <= S_WRITE_HOLD;
            else
              wait_count <= wait_count + 1;
            end if;

          when S_WRITE_HOLD =>
            sram_we_n_reg <= '1';
            sram_ce_n_reg <= '1';
            sram_drive_reg <= '0';
            if byte_index = "11" then
              rdata_reg <= latched_wdata;
              state <= S_DONE;
            else
              byte_index <= byte_index + 1;
              state <= S_WRITE_SETUP;
            end if;

          when S_DONE =>
            ready_reg <= '1';
            if latched_we = '1' then
              rdata_reg <= latched_wdata;
            end if;
            state <= S_WAIT_RELEASE;

          when S_WAIT_RELEASE =>
            sram_drive_reg <= '0';
            sram_ce_n_reg <= '1';
            sram_oe_n_reg <= '1';
            sram_we_n_reg <= '1';
            if req = '0' then
              state <= S_IDLE;
            end if;
        end case;
      end if;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/rtl/ilo_system.vhd.
























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.ilo_pkg.all;

entity ilo_system is
  generic (
    ROM_FILE : string := "";
    BLOCK_FILE : string := "";
    BLOCK_CELLS : natural := 1024;
    MEM_READ_WAIT_CYCLES : natural := 0;
    MEM_WRITE_WAIT_CYCLES : natural := 0;
    BLOCK_READ_WAIT_CYCLES : natural := 0;
    BLOCK_WRITE_WAIT_CYCLES : natural := 0;
    RESET_CYCLES : natural := 4;
    STRICT_ERRORS : boolean := true;
    POISON_UNINITIALIZED : boolean := false
  );
  port (
    clk   : in  std_logic;
    reset : in  std_logic;

    serial_tx_valid : out std_logic;
    serial_tx_data  : out std_logic_vector(7 downto 0);
    serial_rx_req   : out std_logic;
    serial_rx_valid : in  std_logic;
    serial_rx_data  : in  std_logic_vector(7 downto 0);

    halted     : out std_logic;
    errored    : out std_logic;
    error_code : out unsigned(7 downto 0)
  );
end entity;

architecture rtl of ilo_system is
  signal core_reset : std_logic := '1';
  signal reset_count : natural range 0 to RESET_CYCLES := RESET_CYCLES;

  signal mem_req   : std_logic;
  signal mem_we    : std_logic;
  signal mem_addr  : addr_t;
  signal mem_wdata : cell_t;
  signal mem_rdata : cell_t;
  signal mem_ready : std_logic;

  signal block_req   : std_logic;
  signal block_we    : std_logic;
  signal block_addr  : unsigned(31 downto 0);
  signal block_wdata : cell_t;
  signal block_rdata : cell_t;
  signal block_ready : std_logic;

  signal reload_req   : std_logic;
  signal reload_ready : std_logic;
begin
  process(clk)
  begin
    if rising_edge(clk) then
      if reset = '1' then
        core_reset <= '1';
        reset_count <= RESET_CYCLES;
      elsif reset_count = 0 then
        core_reset <= '0';
      else
        reset_count <= reset_count - 1;
        core_reset <= '1';
      end if;
    end if;
  end process;

  core_i : entity work.ilo_core
    generic map (
      STRICT_ERRORS => STRICT_ERRORS
    )
    port map (
      clk => clk,
      reset => core_reset,
      mem_req => mem_req,
      mem_we => mem_we,
      mem_addr => mem_addr,
      mem_wdata => mem_wdata,
      mem_rdata => mem_rdata,
      mem_ready => mem_ready,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data => serial_tx_data,
      serial_tx_ready => '1',
      serial_rx_req => serial_rx_req,
      serial_rx_valid => serial_rx_valid,
      serial_rx_data => serial_rx_data,
      block_req => block_req,
      block_we => block_we,
      block_addr => block_addr,
      block_wdata => block_wdata,
      block_rdata => block_rdata,
      block_ready => block_ready,
      reload_req => reload_req,
      reload_ready => reload_ready,
      halted => halted,
      errored => errored,
      error_code => error_code
    );

  memory_i : entity work.ilo_memory
    generic map (
      ROM_FILE => ROM_FILE,
      READ_WAIT_CYCLES => MEM_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => MEM_WRITE_WAIT_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk => clk,
      req => mem_req,
      we => mem_we,
      addr => mem_addr,
      wdata => mem_wdata,
      rdata => mem_rdata,
      ready => mem_ready,
      reload_req => reload_req,
      reload_ready => reload_ready
    );

  block_i : entity work.ilo_block_store
    generic map (
      BLOCK_FILE => BLOCK_FILE,
      BLOCK_CELLS => BLOCK_CELLS,
      READ_WAIT_CYCLES => BLOCK_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => BLOCK_WRITE_WAIT_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk => clk,
      req => block_req,
      we => block_we,
      addr => block_addr,
      wdata => block_wdata,
      rdata => block_rdata,
      ready => block_ready
    );
end architecture;
Added ilo-vm/vhdl/rtl/ilo_uart_rx.vhd.










































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity ilo_uart_rx is
  generic (
    CLKS_PER_BIT : positive := 104
  );
  port (
    clk       : in  std_logic;
    reset     : in  std_logic;
    rx        : in  std_logic;
    take      : in  std_logic;
    data_valid: out std_logic;
    data      : out std_logic_vector(7 downto 0)
  );
end entity;

architecture rtl of ilo_uart_rx is
  type state_t is (S_IDLE, S_START, S_DATA, S_STOP);

  signal rx_meta : std_logic := '1';
  signal rx_sync : std_logic := '1';
  signal state : state_t := S_IDLE;
  signal clk_count : natural range 0 to CLKS_PER_BIT - 1 := 0;
  signal bit_index : natural range 0 to 7 := 0;
  signal shifter : std_logic_vector(7 downto 0) := (others => '0');
  signal data_reg : std_logic_vector(7 downto 0) := (others => '0');
  signal valid_reg : std_logic := '0';
begin
  data_valid <= valid_reg;
  data <= data_reg;

  process(clk)
  begin
    if rising_edge(clk) then
      rx_meta <= rx;
      rx_sync <= rx_meta;

      if reset = '1' then
        state <= S_IDLE;
        clk_count <= 0;
        bit_index <= 0;
        shifter <= (others => '0');
        data_reg <= (others => '0');
        valid_reg <= '0';
      else
        if take = '1' then
          valid_reg <= '0';
        end if;

        case state is
          when S_IDLE =>
            clk_count <= 0;
            bit_index <= 0;
            if rx_sync = '0' then
              state <= S_START;
            end if;

          when S_START =>
            if clk_count = (CLKS_PER_BIT - 1) / 2 then
              if rx_sync = '0' then
                clk_count <= 0;
                state <= S_DATA;
              else
                state <= S_IDLE;
              end if;
            else
              clk_count <= clk_count + 1;
            end if;

          when S_DATA =>
            if clk_count = CLKS_PER_BIT - 1 then
              clk_count <= 0;
              shifter(bit_index) <= rx_sync;
              if bit_index = 7 then
                bit_index <= 0;
                state <= S_STOP;
              else
                bit_index <= bit_index + 1;
              end if;
            else
              clk_count <= clk_count + 1;
            end if;

          when S_STOP =>
            if clk_count = CLKS_PER_BIT - 1 then
              clk_count <= 0;
              if valid_reg = '0' then
                data_reg <= shifter;
                valid_reg <= '1';
              end if;
              state <= S_IDLE;
            else
              clk_count <= clk_count + 1;
            end if;
        end case;
      end if;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/rtl/ilo_uart_tx.vhd.












































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity ilo_uart_tx is
  generic (
    CLKS_PER_BIT : positive := 104
  );
  port (
    clk       : in  std_logic;
    reset     : in  std_logic;
    data_valid: in  std_logic;
    data      : in  std_logic_vector(7 downto 0);
    tx        : out std_logic;
    busy      : out std_logic
  );
end entity;

architecture rtl of ilo_uart_tx is
  type state_t is (S_IDLE, S_START, S_DATA, S_STOP);

  signal state : state_t := S_IDLE;
  signal clk_count : natural range 0 to CLKS_PER_BIT - 1 := 0;
  signal bit_index : natural range 0 to 7 := 0;
  signal shifter : std_logic_vector(7 downto 0) := (others => '0');
  signal tx_reg : std_logic := '1';
begin
  tx <= tx_reg;
  busy <= '0' when state = S_IDLE else '1';

  process(clk)
  begin
    if rising_edge(clk) then
      if reset = '1' then
        state <= S_IDLE;
        clk_count <= 0;
        bit_index <= 0;
        shifter <= (others => '0');
        tx_reg <= '1';
      else
        case state is
          when S_IDLE =>
            tx_reg <= '1';
            clk_count <= 0;
            bit_index <= 0;
            if data_valid = '1' then
              shifter <= data;
              state <= S_START;
            end if;

          when S_START =>
            tx_reg <= '0';
            if clk_count = CLKS_PER_BIT - 1 then
              clk_count <= 0;
              state <= S_DATA;
            else
              clk_count <= clk_count + 1;
            end if;

          when S_DATA =>
            tx_reg <= shifter(bit_index);
            if clk_count = CLKS_PER_BIT - 1 then
              clk_count <= 0;
              if bit_index = 7 then
                bit_index <= 0;
                state <= S_STOP;
              else
                bit_index <= bit_index + 1;
              end if;
            else
              clk_count <= clk_count + 1;
            end if;

          when S_STOP =>
            tx_reg <= '1';
            if clk_count = CLKS_PER_BIT - 1 then
              clk_count <= 0;
              state <= S_IDLE;
            else
              clk_count <= clk_count + 1;
            end if;
        end case;
      end if;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/scripts/blocks-to-mem.sh.




























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh
set -eu

if [ "$#" -ne 2 ]; then
  echo "usage: $0 input.blocks output.blocks.mem" >&2
  exit 2
fi

input="$1"
output="$2"

mkdir -p "$(dirname "$output")"

od -An -td4 -w4 -v "$input" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' > "$output"
Added ilo-vm/vhdl/scripts/build-icepi-zero.sh.
















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/bin/sh
set -eu

SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
. "$SCRIPT_DIR/common.sh"

root="$VHDL_ROOT"
top="icepi_zero_top"
mode="smoke"

usage() {
  cat >&2 <<EOF
Usage: $0 [--sdram]

Build the ICEPI Zero ECP5 bitstream.

  --sdram  build icepi_zero_sdram_top instead of the internal-memory smoke top
EOF
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --sdram)
      top="icepi_zero_sdram_top"
      mode="sdram"
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      usage
      exit 2
      ;;
  esac
  shift
done

build="$root/build/icepi-zero/$mode"

missing=""
for tool in ghdl yosys nextpnr-ecp5 ecppack; do
  if ! command -v "$tool" >/dev/null 2>&1; then
    missing="${missing}${missing:+ }$tool"
  fi
done

if [ -n "$missing" ]; then
  printf 'Missing required ICEPI Zero build tools: %s\n' "$missing" >&2
  printf 'Install OSS CAD Suite and add its bin directory to PATH.\n' >&2
  printf 'Debian packages commonly include nextpnr-ice40 but not nextpnr-ecp5/ecppack.\n' >&2
  exit 1
fi

mkdir -p "$build"

verilog="$build/$top.v"
json="$build/$top.json"
config="$build/$top.config"
bit="$build/$top.bit"
log="$build/build.log"

if [ "$mode" = "sdram" ]; then
  set -- \
    "$root/rtl/ilo_pkg.vhd" \
    "$root/rtl/ilo_core.vhd" \
    "$root/rtl/ilo_sdram_controller.vhd" \
    "$root/rtl/ilo_byte_fifo.vhd" \
    "$root/rtl/ilo_uart_tx.vhd" \
    "$root/rtl/ilo_uart_rx.vhd" \
    "$root/rtl/boards/$top.vhd"
else
  set -- \
    "$root/rtl/ilo_pkg.vhd" \
    "$root/rtl/ilo_core.vhd" \
    "$root/rtl/ilo_byte_fifo.vhd" \
    "$root/rtl/ilo_uart_tx.vhd" \
    "$root/rtl/ilo_uart_rx.vhd" \
    "$root/rtl/boards/$top.vhd"
fi

echo "Translating VHDL top '$top' with GHDL..."
ghdl --synth --std=08 --out=verilog "$@" -e "$top" > "$verilog"

echo "Running Yosys ECP5 synthesis..."
yosys -p "read_verilog -nolatches $verilog; synth_ecp5 -top $top -json $json" > "$log" 2>&1
cat "$log"

echo "Running nextpnr-ecp5..."
nextpnr-ecp5 --25k --package CABGA256 --lpf "$root/constraints/icepi_zero.lpf" --json "$json" --textcfg "$config" > "$build/nextpnr.log" 2>&1
cat "$build/nextpnr.log"
cat "$build/nextpnr.log" >> "$log"

echo "Packing bitstream..."
ecppack --compress "$config" "$bit" > "$build/ecppack.log" 2>&1
cat "$build/ecppack.log"
cat "$build/ecppack.log" >> "$log"

echo "Wrote:"
echo "  $verilog"
echo "  $json"
echo "  $config"
echo "  $bit"
echo "  $log"
Added ilo-vm/vhdl/scripts/common.sh.




























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/sh

if [ -z "${SCRIPT_DIR:-}" ]; then
  SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
fi

VHDL_ROOT="${VHDL_ROOT:-$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd)}"

find_ilo_vm_root() {
  dir="$VHDL_ROOT"
  while [ "$dir" != "/" ]; do
    if [ -f "$dir/tools/pali.c" ] && [ -d "$dir/test-ilo" ]; then
      printf '%s\n' "$dir"
      return 0
    fi
    dir="$(dirname "$dir")"
  done
  return 1
}

if [ -z "${ILO_VM_ROOT:-}" ]; then
  if ILO_VM_ROOT="$(find_ilo_vm_root)"; then
    export ILO_VM_ROOT
  else
    ILO_VM_ROOT="$(CDPATH= cd -- "$VHDL_ROOT/../.." && pwd)"
    export ILO_VM_ROOT
  fi
fi

export VHDL_ROOT
Added ilo-vm/vhdl/scripts/compare-c-vhdl.sh.






















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#!/bin/sh
set -eu

SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
. "$SCRIPT_DIR/common.sh"

build="$VHDL_ROOT/build"
tool_build="$build/tools"
pali_tool="${PALI:-$ILO_VM_ROOT/tools/pali}"
ilo="${ILO:-$ILO_VM_ROOT/ilo}"
ilo_src="$ILO_VM_ROOT/ilo.c"

cd "$VHDL_ROOT"
mkdir -p "$build" "$tool_build"

if [ ! -x "$pali_tool" ]; then
  pali_tool="$tool_build/pali"
  cc "$ILO_VM_ROOT/tools/pali.c" -o "$pali_tool"
fi

if [ ! -x "$ilo" ]; then
  ilo="$tool_build/ilo"
  if [ ! -f "$ilo_src" ] && [ -f "$ILO_VM_ROOT/ilo-vm/ilo.c" ]; then
    ilo_src="$ILO_VM_ROOT/ilo-vm/ilo.c"
  fi
  cc "$ilo_src" -o "$ilo"
fi

ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_pkg.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_memory.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_block_store.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_core.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/ilo_tb.vhd"
ghdl -e --std=08 ilo_tb

if [ "$#" -eq 0 ]; then
  set -- \
    test-ilo/test-li.pali \
    test-ilo/test-du.pali \
    test-ilo/test-dr.pali \
    test-ilo/test-sw.pali \
    test-ilo/test-pu-po.pali \
    test-ilo/test-ad.pali \
    test-ilo/test-su.pali \
    test-ilo/test-mu.pali \
    test-ilo/test-di.pali \
    test-ilo/test-eq.pali \
    test-ilo/test-ne.pali \
    test-ilo/test-lt.pali \
    test-ilo/test-gt.pali \
    test-ilo/test-an.pali \
    test-ilo/test-or.pali \
    test-ilo/test-xo.pali \
    test-ilo/test-sl.pali \
    test-ilo/test-sr.pali \
    test-ilo/test-ju.pali \
    test-ilo/test-ca-re.pali \
    test-ilo/test-cc.pali \
    test-ilo/test-cj.pali \
    test-ilo/test-fe-st.pali \
    test-ilo/test-cp.pali \
    test-ilo/test-cy.pali \
    test-ilo/test-io-stack-depth.pali
fi

passed=0
failed=0

for pali in "$@"; do
  test_name="$(basename "$pali" .pali)"
  mem="$build/$test_name.mem"
  rom="$build/$test_name.rom"
  work="$build/compare-work"

  "$VHDL_ROOT/scripts/pali-to-mem.sh" "$ILO_VM_ROOT/$pali" "$mem"
  mkdir -p "$work"
  (
    cd "$work"
    "$pali_tool" "$ILO_VM_ROOT/$pali" >/dev/null
    cp ilo.rom "$rom"
  )

  c_stack="$(timeout 5s "$ilo" "$ILO_VM_ROOT/ilo.blocks" "$rom" 2>/dev/null | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"

  set +e
  vhdl_output="$(ghdl -r --std=08 ilo_tb -gROM_FILE="$mem" --assert-level=error 2>&1)"
  vhdl_status=$?
  set -e
  vhdl_stack="$(printf '%s\n' "$vhdl_output" | sed -n 's/^FINAL_STACK:[[:space:]]*//p' | tail -1 | sed 's/[[:space:]]*$//')"

  if [ "$c_stack" = "$vhdl_stack" ]; then
    printf 'PASS %s\n' "$test_name"
    passed=$((passed + 1))
  else
    printf 'FAIL %s\n' "$test_name"
    printf '  C:    %s\n' "$c_stack"
    printf '  VHDL: %s\n' "$vhdl_stack"
    printf '  ghdl exit: %s\n' "$vhdl_status"
    failed=$((failed + 1))
  fi
done

printf '\nC/VHDL compare: %d passed, %d failed\n' "$passed" "$failed"

if [ "$failed" -ne 0 ]; then
  exit 1
fi
Added ilo-vm/vhdl/scripts/pali-to-mem.sh.




























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/sh
set -eu

if [ "$#" -ne 2 ]; then
  echo "usage: $0 input.pali output.mem" >&2
  exit 2
fi

SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
. "$SCRIPT_DIR/common.sh"

input="$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
output="$(cd "$(dirname "$2")" && pwd)/$(basename "$2")"
work="$VHDL_ROOT/build/pali-work"
pali="${PALI:-$ILO_VM_ROOT/tools/pali}"

mkdir -p "$work" "$(dirname "$output")"

if [ ! -x "$pali" ]; then
  pali="$VHDL_ROOT/build/tools/pali"
  mkdir -p "$(dirname "$pali")"
  cc "$ILO_VM_ROOT/tools/pali.c" -o "$pali"
fi

(
  cd "$work"
  "$pali" "$input" >/dev/null
)

od -An -td4 -w4 -v "$work/ilo.rom" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' > "$output"
Added ilo-vm/vhdl/scripts/rom-to-mem.sh.




























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh
set -eu

if [ "$#" -ne 2 ]; then
  echo "usage: $0 input.rom output.mem" >&2
  exit 2
fi

input="$1"
output="$2"

mkdir -p "$(dirname "$output")"

od -An -td4 -w4 -v "$input" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' > "$output"
Added ilo-vm/vhdl/scripts/run-ghdl-tests.sh.
























































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
#!/bin/sh
set -eu

SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
. "$SCRIPT_DIR/common.sh"

build="$VHDL_ROOT/build"
mem_read_wait_cycles="${MEM_READ_WAIT_CYCLES:-0}"
mem_write_wait_cycles="${MEM_WRITE_WAIT_CYCLES:-0}"
block_read_wait_cycles="${BLOCK_READ_WAIT_CYCLES:-0}"
block_write_wait_cycles="${BLOCK_WRITE_WAIT_CYCLES:-0}"
sram8_read_wait_cycles="${SRAM8_READ_WAIT_CYCLES:-1}"
sram8_write_wait_cycles="${SRAM8_WRITE_WAIT_CYCLES:-1}"
sram8_output_delay_ns="${SRAM8_OUTPUT_DELAY_NS:-1}"
poison_uninitialized="${POISON_UNINITIALIZED:-false}"

tests="test-li test-du test-dr test-sw test-pu-po test-ad test-su test-mu test-di test-eq test-ne test-lt test-gt test-an test-or test-xo test-sl test-sr test-ju test-ca-re test-cc test-cj test-fe-st test-cp test-cy test-io-stack-depth"
serial_tests="test-io-emit test-io-read"
block_tests="test-io-block-read test-io-block-write"
sdram_address_tests="test-sdram-address-boundaries"
system_tests="test-ad test-cp"
sdram_timing_violations="TRCD TRP TRFC CAS WRITE_RECOVERY REFRESH_INTERVAL INIT_READ INIT_WRITE INIT_PRECHARGE_BANK INIT_REFRESH_EARLY INIT_MODE_EARLY"

passed=0
failed=0
output=""
status=0

mkdir -p "$build"

run_capture() {
  set +e
  output="$("$@" 2>&1)"
  status=$?
  set -e
}

compile_pali() {
  "$VHDL_ROOT/scripts/pali-to-mem.sh" "$1" "$2"
}

final_stack() {
  printf '%s\n' "$1" | sed -n 's/^FINAL_STACK:[[:space:]]*//p' | tail -1 | sed 's/[[:space:]]*$//'
}

serial_tx() {
  printf '%s\n' "$1" | sed -n 's/^SERIAL_TX:[[:space:]]*//p' | paste -sd ' ' -
}

core_expected() {
  case "$1" in
    test-li) printf '%s\n' "123 42" ;;
    test-du) printf '%s\n' "42 42" ;;
    test-dr) printf '%s\n' "42" ;;
    test-sw) printf '%s\n' "42 123" ;;
    test-pu-po) printf '%s\n' "42" ;;
    test-ju) printf '%s\n' "42" ;;
    test-ca-re) printf '%s\n' "999 42" ;;
    test-cc) printf '%s\n' "999 42" ;;
    test-cj) printf '%s\n' "42" ;;
    test-eq) printf '%s\n' "0 -1" ;;
    test-ne) printf '%s\n' "-1 0" ;;
    test-lt) printf '%s\n' "0 -1" ;;
    test-gt) printf '%s\n' "0 -1" ;;
    test-fe-st) printf '%s\n' "42" ;;
    test-ad) printf '%s\n' "65" ;;
    test-su) printf '%s\n' "19" ;;
    test-mu) printf '%s\n' "966" ;;
    test-di) printf '%s\n' "0 23" ;;
    test-an) printf '%s\n' "2" ;;
    test-or) printf '%s\n' "63" ;;
    test-xo) printf '%s\n' "61" ;;
    test-sl) printf '%s\n' "168" ;;
    test-sr) printf '%s\n' "10" ;;
    test-cp) printf '%s\n' "0 -1" ;;
    test-cy) printf '%s\n' "42" ;;
    test-io-stack-depth) printf '%s\n' "0 2 23 42" ;;
    *) printf '%s\n' "" ;;
  esac
}

serial_expected_stack() {
  case "$1" in
    test-io-read) printf '%s\n' "65" ;;
    *) printf '%s\n' "" ;;
  esac
}

serial_expected_tx() {
  case "$1" in
    test-io-emit) printf '%s\n' "65" ;;
    *) printf '%s\n' "" ;;
  esac
}

serial_rx_text() {
  case "$1" in
    test-io-read) printf '%s\n' "A" ;;
    *) printf '%s\n' "" ;;
  esac
}

block_expected_stack() {
  case "$1" in
    test-io-block-read) printf '%s\n' "123" ;;
    test-io-block-write) printf '%s\n' "77" ;;
    *) printf '%s\n' "" ;;
  esac
}

block_file() {
  case "$1" in
    test-io-block-read) printf '%s\n' "$VHDL_ROOT/testdata/block-read.blocks.mem" ;;
    *) printf '%s\n' "" ;;
  esac
}

sdram_address_expected_stack() {
  case "$1" in
    test-sdram-address-boundaries) printf '%s\n' "501 402 401 302 301 202 201 102 101" ;;
    *) printf '%s\n' "" ;;
  esac
}

sdram_timing_expected() {
  case "$1" in
    TRCD) printf '%s\n' "sdram_model: READ violates tRCD" ;;
    TRP) printf '%s\n' "sdram_model: ACTIVE violates tRP" ;;
    TRFC) printf '%s\n' "sdram_model: ACTIVE violates tRFC" ;;
    CAS) printf '%s\n' "sdram_model: mode register CAS latency does not match model CAS_LATENCY" ;;
    WRITE_RECOVERY) printf '%s\n' "sdram_model: ACTIVE violates write recovery" ;;
    REFRESH_INTERVAL) printf '%s\n' "sdram_model: maximum refresh interval exceeded" ;;
    INIT_READ) printf '%s\n' "sdram_model: READ before initialization complete" ;;
    INIT_WRITE) printf '%s\n' "sdram_model: WRITE before initialization complete" ;;
    INIT_PRECHARGE_BANK) printf '%s\n' "sdram_model: initialization requires PRECHARGE ALL" ;;
    INIT_REFRESH_EARLY) printf '%s\n' "sdram_model: REFRESH before expected init step" ;;
    INIT_MODE_EARLY) printf '%s\n' "sdram_model: MODE REGISTER SET before expected init step" ;;
    *) printf '%s\n' "" ;;
  esac
}

pass() {
  printf 'PASS %s\n' "$1"
  passed=$((passed + 1))
}

fail_output() {
  printf 'FAIL %s\n' "$1"
  printf '%s\n' "$output" | sed 's/^/  | /'
  failed=$((failed + 1))
}

check_stack_result() {
  label="$1"
  want="$2"
  got="$(final_stack "$output")"
  if [ "$got" = "$want" ]; then
    pass "$label"
  else
    printf 'FAIL %s\n' "$label"
    printf '  expected: %s\n' "$want"
    printf '  got:      %s\n' "$got"
    if [ "$status" -ne 1 ]; then
      printf '  ghdl exit: %s\n' "$status"
    fi
    printf '%s\n' "$output" | sed 's/^/  | /'
    failed=$((failed + 1))
  fi
}

check_serial_result() {
  label="$1"
  want_stack="$2"
  want_tx="$3"
  got_stack="$(final_stack "$output")"
  got_tx="$(serial_tx "$output")"
  if [ "$got_stack" = "$want_stack" ] && [ "$got_tx" = "$want_tx" ]; then
    pass "$label"
  else
    printf 'FAIL %s\n' "$label"
    printf '  expected stack: %s\n' "$want_stack"
    printf '  got stack:      %s\n' "$got_stack"
    printf '  expected tx:    %s\n' "$want_tx"
    printf '  got tx:         %s\n' "$got_tx"
    if [ "$status" -ne 1 ]; then
      printf '  ghdl exit: %s\n' "$status"
    fi
    printf '%s\n' "$output" | sed 's/^/  | /'
    failed=$((failed + 1))
  fi
}

run_fast_tb() {
  tb="$1"
  mem="$2"
  shift 2
  run_capture ghdl -r --std=08 "$tb" \
    -gROM_FILE="$mem" \
    -gMEM_READ_WAIT_CYCLES="$mem_read_wait_cycles" \
    -gMEM_WRITE_WAIT_CYCLES="$mem_write_wait_cycles" \
    -gBLOCK_READ_WAIT_CYCLES="$block_read_wait_cycles" \
    -gBLOCK_WRITE_WAIT_CYCLES="$block_write_wait_cycles" \
    -gPOISON_UNINITIALIZED="$poison_uninitialized" \
    "$@" --assert-level=error
}

run_strict_fast_tb() {
  tb="$1"
  mem="$2"
  shift 2
  run_capture ghdl -r --std=08 "$tb" \
    -gROM_FILE="$mem" \
    -gMEM_READ_WAIT_CYCLES="$mem_read_wait_cycles" \
    -gMEM_WRITE_WAIT_CYCLES="$mem_write_wait_cycles" \
    -gBLOCK_READ_WAIT_CYCLES="$block_read_wait_cycles" \
    -gBLOCK_WRITE_WAIT_CYCLES="$block_write_wait_cycles" \
    -gPOISON_UNINITIALIZED=true \
    "$@" --assert-level=error
}

run_sram8_tb() {
  tb="$1"
  mem="$2"
  shift 2
  run_capture ghdl -r --std=08 "$tb" \
    -gROM_FILE="$mem" \
    -gREAD_WAIT_CYCLES="$sram8_read_wait_cycles" \
    -gWRITE_WAIT_CYCLES="$sram8_write_wait_cycles" \
    -gSRAM_OUTPUT_DELAY_NS="$sram8_output_delay_ns" \
    -gBLOCK_READ_WAIT_CYCLES="$block_read_wait_cycles" \
    -gBLOCK_WRITE_WAIT_CYCLES="$block_write_wait_cycles" \
    -gPOISON_UNINITIALIZED="$poison_uninitialized" \
    "$@" --assert-level=error
}

run_strict_sram8_tb() {
  tb="$1"
  mem="$2"
  shift 2
  run_capture ghdl -r --std=08 "$tb" \
    -gROM_FILE="$mem" \
    -gREAD_WAIT_CYCLES="$sram8_read_wait_cycles" \
    -gWRITE_WAIT_CYCLES="$sram8_write_wait_cycles" \
    -gSRAM_OUTPUT_DELAY_NS="$sram8_output_delay_ns" \
    -gBLOCK_READ_WAIT_CYCLES="$block_read_wait_cycles" \
    -gBLOCK_WRITE_WAIT_CYCLES="$block_write_wait_cycles" \
    -gPOISON_UNINITIALIZED=true \
    "$@" --assert-level=error
}

ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_pkg.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_memory.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_block_store.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_core.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_system.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_sram8_controller.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_sdram_controller.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_byte_fifo.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_uart_tx.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_uart_rx.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/boards/cmod_a7_top.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/boards/icepi_zero_top.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/boards/icepi_zero_sdram_top.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/sram8_model.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/sdram_model.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/sdram_model_timing_tb.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/ilo_tb.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/ilo_system_tb.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/ilo_sram8_tb.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/ilo_sdram_tb.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/ilo_reload_tb.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/cmod_a7_top_tb.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/icepi_zero_top_tb.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/icepi_zero_sdram_top_tb.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/ilo_sdram_controller_tb.vhd"
ghdl -a --std=08 "$VHDL_ROOT/sim/ilo_sdram_terminal_tb.vhd"
ghdl -e --std=08 ilo_tb
ghdl -e --std=08 ilo_system_tb
ghdl -e --std=08 ilo_sram8_tb
ghdl -e --std=08 ilo_sdram_tb
ghdl -e --std=08 ilo_reload_tb
ghdl -e --std=08 cmod_a7_top_tb
ghdl -e --std=08 icepi_zero_top_tb
ghdl -e --std=08 icepi_zero_sdram_top_tb
ghdl -e --std=08 ilo_sdram_controller_tb
ghdl -e --std=08 sdram_model_timing_tb
ghdl -e --std=08 ilo_sdram_terminal_tb

for test in $tests; do
  mem="$build/$test.mem"
  compile_pali "$ILO_VM_ROOT/test-ilo/$test.pali" "$mem"
  run_fast_tb ilo_tb "$mem"
  check_stack_result "$test" "$(core_expected "$test")"
done

for test in $tests; do
  mem="$build/$test.mem"
  compile_pali "$ILO_VM_ROOT/test-ilo/$test.pali" "$mem"
  run_capture ghdl -r --std=08 ilo_sdram_tb -gROM_FILE="$mem" --assert-level=error
  check_stack_result "sdram:$test" "$(core_expected "$test")"
done

for test in $serial_tests; do
  mem="$build/$test.mem"
  rx_text="$(serial_rx_text "$test")"
  compile_pali "$VHDL_ROOT/testdata/$test.pali" "$mem"
  if [ -n "$rx_text" ]; then
    run_capture ghdl -r --std=08 ilo_sdram_tb -gROM_FILE="$mem" -gRX_TEXT="$rx_text" --assert-level=error
  else
    run_capture ghdl -r --std=08 ilo_sdram_tb -gROM_FILE="$mem" --assert-level=error
  fi
  check_serial_result "sdram:$test" "$(serial_expected_stack "$test")" "$(serial_expected_tx "$test")"
done

for test in $block_tests; do
  mem="$build/$test.mem"
  file="$(block_file "$test")"
  compile_pali "$VHDL_ROOT/testdata/$test.pali" "$mem"
  if [ -n "$file" ]; then
    run_capture ghdl -r --std=08 ilo_sdram_tb -gROM_FILE="$mem" -gBLOCK_FILE="$file" -gMAX_CYCLES=2000000 --assert-level=error
  else
    run_capture ghdl -r --std=08 ilo_sdram_tb -gROM_FILE="$mem" -gMAX_CYCLES=2000000 --assert-level=error
  fi
  check_stack_result "sdram:$test" "$(block_expected_stack "$test")"
done

for test in $sdram_address_tests; do
  mem="$build/$test.mem"
  compile_pali "$VHDL_ROOT/testdata/$test.pali" "$mem"
  run_capture ghdl -r --std=08 ilo_sdram_tb -gROM_FILE="$mem" -gMAX_CYCLES=2000000 --assert-level=error
  check_stack_result "sdram:$test" "$(sdram_address_expected_stack "$test")"
done

printf '\nGHDL ilo tests: %d passed, %d failed\n' "$passed" "$failed"

for test in $serial_tests; do
  mem="$build/$test.mem"
  rx_text="$(serial_rx_text "$test")"
  compile_pali "$VHDL_ROOT/testdata/$test.pali" "$mem"
  if [ -n "$rx_text" ]; then
    run_fast_tb ilo_tb "$mem" -gRX_TEXT="$rx_text"
  else
    run_fast_tb ilo_tb "$mem"
  fi
  check_serial_result "$test" "$(serial_expected_stack "$test")" "$(serial_expected_tx "$test")"
done

tx_ready_mem="$build/test-io-emit.mem"
run_fast_tb ilo_tb "$tx_ready_mem" -gTX_READY_DELAY_CYCLES=5000
check_serial_result "test-io-emit-tx-ready-delay" "" "65"

for test in $block_tests; do
  mem="$build/$test.mem"
  file="$(block_file "$test")"
  compile_pali "$VHDL_ROOT/testdata/$test.pali" "$mem"
  if [ -n "$file" ]; then
    run_fast_tb ilo_tb "$mem" -gBLOCK_FILE="$file" -gMAX_CYCLES=200000
  else
    run_fast_tb ilo_tb "$mem" -gMAX_CYCLES=200000
  fi
  check_stack_result "$test" "$(block_expected_stack "$test")"
done

for test in $system_tests; do
  mem="$build/$test.mem"
  compile_pali "$ILO_VM_ROOT/test-ilo/$test.pali" "$mem"
  run_fast_tb ilo_system_tb "$mem" -gRESET_CYCLES=7
  check_stack_result "system:$test" "$(core_expected "$test")"
done

for test in $serial_tests; do
  mem="$build/$test.mem"
  rx_text="$(serial_rx_text "$test")"
  compile_pali "$VHDL_ROOT/testdata/$test.pali" "$mem"
  if [ -n "$rx_text" ]; then
    run_fast_tb ilo_system_tb "$mem" -gRESET_CYCLES=7 -gRX_TEXT="$rx_text"
  else
    run_fast_tb ilo_system_tb "$mem" -gRESET_CYCLES=7
  fi
  check_serial_result "system:$test" "$(serial_expected_stack "$test")" "$(serial_expected_tx "$test")"
done

for test in $block_tests; do
  mem="$build/$test.mem"
  file="$(block_file "$test")"
  compile_pali "$VHDL_ROOT/testdata/$test.pali" "$mem"
  if [ -n "$file" ]; then
    run_fast_tb ilo_system_tb "$mem" -gRESET_CYCLES=7 -gBLOCK_FILE="$file" -gMAX_CYCLES=200000
  else
    run_fast_tb ilo_system_tb "$mem" -gRESET_CYCLES=7 -gMAX_CYCLES=200000
  fi
  check_stack_result "system:$test" "$(block_expected_stack "$test")"
done

for test in $tests; do
  mem="$build/$test.mem"
  compile_pali "$ILO_VM_ROOT/test-ilo/$test.pali" "$mem"
  run_sram8_tb ilo_sram8_tb "$mem"
  check_stack_result "sram8:$test" "$(core_expected "$test")"
done

for test in $serial_tests; do
  mem="$build/$test.mem"
  rx_text="$(serial_rx_text "$test")"
  compile_pali "$VHDL_ROOT/testdata/$test.pali" "$mem"
  if [ -n "$rx_text" ]; then
    run_sram8_tb ilo_sram8_tb "$mem" -gRX_TEXT="$rx_text"
  else
    run_sram8_tb ilo_sram8_tb "$mem"
  fi
  check_serial_result "sram8:$test" "$(serial_expected_stack "$test")" "$(serial_expected_tx "$test")"
done

for test in $block_tests; do
  mem="$build/$test.mem"
  file="$(block_file "$test")"
  compile_pali "$VHDL_ROOT/testdata/$test.pali" "$mem"
  if [ -n "$file" ]; then
    run_sram8_tb ilo_sram8_tb "$mem" -gBLOCK_FILE="$file" -gMAX_CYCLES=500000
  else
    run_sram8_tb ilo_sram8_tb "$mem" -gMAX_CYCLES=500000
  fi
  check_stack_result "sram8:$test" "$(block_expected_stack "$test")"
done

reload_mem="$build/test-io-reload.mem"
compile_pali "$VHDL_ROOT/testdata/test-io-reload.pali" "$reload_mem"
run_capture ghdl -r --std=08 ilo_reload_tb \
  -gROM_FILE="$reload_mem" \
  -gMEM_READ_WAIT_CYCLES="$mem_read_wait_cycles" \
  -gMEM_WRITE_WAIT_CYCLES="$mem_write_wait_cycles" \
  -gPOISON_UNINITIALIZED="$poison_uninitialized" \
  --assert-level=error
if [ "$status" -eq 0 ] && printf '%s\n' "$output" | grep -q "RELOAD PASS"; then
  pass "test-io-reload"
else
  fail_output "test-io-reload"
fi

run_capture ghdl -r --std=08 cmod_a7_top_tb --assert-level=error
if [ "$status" -eq 0 ] && printf '%s\n' "$output" | grep -q "CMOD_A7_SMOKE_TX: 65"; then
  pass "cmod-a7-smoke"
else
  fail_output "cmod-a7-smoke"
fi

run_capture ghdl -r --std=08 icepi_zero_top_tb --assert-level=error
if [ "$status" -eq 0 ] && printf '%s\n' "$output" | grep -q "ICEPI_ZERO_SMOKE_TX: 65"; then
  pass "icepi-zero-smoke"
else
  fail_output "icepi-zero-smoke"
fi

run_capture ghdl -r --std=08 icepi_zero_sdram_top_tb --assert-level=error
if [ "$status" -eq 0 ] && printf '%s\n' "$output" | grep -q "ICEPI_ZERO_SDRAM_SMOKE_TX: 65"; then
  pass "icepi-zero-sdram-smoke"
else
  fail_output "icepi-zero-sdram-smoke"
fi

run_capture ghdl -r --std=08 icepi_zero_sdram_top_tb -gTEST=UART_STRESS --assert-level=error
if [ "$status" -eq 0 ] && printf '%s\n' "$output" | grep -q "ICEPI_ZERO_SDRAM_UART_STRESS_TX: 21"; then
  pass "icepi-zero-sdram-uart-stress"
else
  fail_output "icepi-zero-sdram-uart-stress"
fi

board_boot_mem="$build/test-board-boot-preloaded.mem"
compile_pali "$VHDL_ROOT/testdata/test-board-boot-preloaded.pali" "$board_boot_mem"
run_capture ghdl -r --std=08 icepi_zero_sdram_top_tb -gTEST=PRELOADED -gBOOT_MEM_FILE="$board_boot_mem" --assert-level=error
if [ "$status" -eq 0 ] && printf '%s\n' "$output" | grep -q "ICEPI_ZERO_SDRAM_PRELOADED_BOOT_TX: 4"; then
  pass "icepi-zero-sdram-preloaded-boot"
else
  fail_output "icepi-zero-sdram-preloaded-boot"
fi

run_capture ghdl -r --std=08 icepi_zero_sdram_top_tb -gPROFILE=ICEPI --assert-level=error
if [ "$status" -eq 0 ] && printf '%s\n' "$output" | grep -q "ICEPI_ZERO_SDRAM_SMOKE_TX: 65"; then
  pass "icepi-zero-sdram-icepi-profile"
else
  fail_output "icepi-zero-sdram-icepi-profile"
fi

run_capture ghdl -r --std=08 ilo_sdram_controller_tb --assert-level=error
if [ "$status" -eq 0 ] && printf '%s\n' "$output" | grep -q "ILO_SDRAM_CONTROLLER_OK"; then
  pass "sdram-controller"
else
  fail_output "sdram-controller"
fi

for violation in $sdram_timing_violations; do
  want="$(sdram_timing_expected "$violation")"
  run_capture ghdl -r --std=08 sdram_model_timing_tb -gVIOLATION="$violation" --assert-level=error
  if [ "$status" -ne 0 ] && printf '%s\n' "$output" | grep -q "$want"; then
    pass "sdram-model-timing:$violation"
  else
    printf 'FAIL %s\n' "sdram-model-timing:$violation"
    printf '  expected assertion: %s\n' "$want"
    printf '%s\n' "$output" | sed 's/^/  | /'
    failed=$((failed + 1))
  fi
done

uninitialized_mem="$VHDL_ROOT/testdata/test-uninitialized-read.partial.mem"
for tb in ilo_tb ilo_system_tb ilo_sram8_tb; do
  case "$tb" in
    ilo_tb)
      run_strict_fast_tb "$tb" "$uninitialized_mem"
      ;;
    ilo_system_tb)
      run_strict_fast_tb "$tb" "$uninitialized_mem" -gRESET_CYCLES=7
      ;;
    *)
      run_strict_sram8_tb "$tb" "$uninitialized_mem"
      ;;
  esac
  check_stack_result "$tb:test-uninitialized-read" "-559038737"
done

printf '\nGHDL ilo tests including serial, block, and reload I/O: %d passed, %d failed\n' "$passed" "$failed"

if [ "$failed" -ne 0 ]; then
  exit 1
fi
Added ilo-vm/vhdl/scripts/run-ilo-rom-interactive.sh.
















































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/bin/sh
set -eu

use_sram8=""
use_sdram=""
case "${1:-}" in
  --sram8)
    use_sram8="1"
    shift
    ;;
  --sdram)
    use_sdram="1"
    shift
    ;;
esac

if [ "$#" -lt 1 ] || [ "$#" -gt 4 ]; then
  echo "usage: $0 [--sram8|--sdram] rom-or-mem [blocks-or-blocks-mem] [max-cycles] [clock-period-ns]" >&2
  exit 2
fi

SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
. "$SCRIPT_DIR/common.sh"

build="$VHDL_ROOT/build"
rom_input="$1"
blocks_input="${2:-}"
max_cycles="${3:-0}"
clock_period_ns="${4:-10}"
rx_fifo="$build/terminal.rx"
tx_fifo="$build/terminal.tx"
log="$build/interactive-ghdl.log"
mem="$build/interactive.mem"
blocks_mem=""
block_cells="1024"
ghdl_pid=""

cleanup() {
  if [ -n "$ghdl_pid" ] && kill -0 "$ghdl_pid" 2>/dev/null; then
    kill "$ghdl_pid" 2>/dev/null || true
    wait "$ghdl_pid" 2>/dev/null || true
  fi
  rm -f "$rx_fifo" "$tx_fifo"
}

trap cleanup EXIT INT TERM

mkdir -p "$build"
rm -f "$rx_fifo" "$tx_fifo"
mkfifo "$rx_fifo" "$tx_fifo"

if [ -n "$blocks_input" ] && [ "$#" -eq 2 ]; then
  case "$blocks_input" in
    *[!0-9]*)
      ;;
    *)
      max_cycles="$blocks_input"
      blocks_input=""
      ;;
  esac
fi

case "$clock_period_ns" in
  ''|*[!0-9]*)
    echo "error: clock-period-ns must be a positive integer" >&2
    exit 2
    ;;
  0)
    echo "error: clock-period-ns must be greater than zero" >&2
    exit 2
    ;;
esac

case "$rom_input" in
  *.mem)
    mem="$rom_input"
    ;;
  *)
    "$VHDL_ROOT/scripts/rom-to-mem.sh" "$rom_input" "$mem"
    ;;
esac

if [ -n "$blocks_input" ]; then
  case "$blocks_input" in
    *.mem)
      blocks_mem="$blocks_input"
      ;;
    *)
      blocks_mem="$build/interactive.blocks.mem"
      "$VHDL_ROOT/scripts/blocks-to-mem.sh" "$blocks_input" "$blocks_mem"
      ;;
  esac
  block_cells="$(wc -l < "$blocks_mem" | tr -d '[:space:]')"
fi

ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_pkg.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_block_store.vhd"
ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_core.vhd"

: > "$log"
if [ -n "$use_sram8" ]; then
  ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_sram8_controller.vhd"
  ghdl -a --std=08 "$VHDL_ROOT/sim/sram8_model.vhd"
  ghdl -a --std=08 "$VHDL_ROOT/sim/ilo_sram8_terminal_tb.vhd"
  ghdl -e --std=08 ilo_sram8_terminal_tb
  if [ -n "$blocks_mem" ]; then
    ghdl -r --std=08 ilo_sram8_terminal_tb \
      --max-stack-alloc=0 \
      -gROM_FILE="$mem" \
      -gBLOCK_FILE="$blocks_mem" \
      -gBLOCK_CELLS="$block_cells" \
      -gRX_FIFO="$rx_fifo" \
      -gTX_FIFO="$tx_fifo" \
      -gMAX_CYCLES="$max_cycles" \
      -gCLOCK_PERIOD_NS="$clock_period_ns" \
      --assert-level=error >"$log" 2>&1 &
  else
    ghdl -r --std=08 ilo_sram8_terminal_tb \
      --max-stack-alloc=0 \
      -gROM_FILE="$mem" \
      -gBLOCK_CELLS="$block_cells" \
      -gRX_FIFO="$rx_fifo" \
      -gTX_FIFO="$tx_fifo" \
      -gMAX_CYCLES="$max_cycles" \
      -gCLOCK_PERIOD_NS="$clock_period_ns" \
      --assert-level=error >"$log" 2>&1 &
  fi
elif [ -n "$use_sdram" ]; then
  ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_sdram_controller.vhd"
  ghdl -a --std=08 "$VHDL_ROOT/sim/sdram_model.vhd"
  ghdl -a --std=08 "$VHDL_ROOT/sim/ilo_sdram_terminal_tb.vhd"
  ghdl -e --std=08 ilo_sdram_terminal_tb
  if [ -n "$blocks_mem" ]; then
    ghdl -r --std=08 ilo_sdram_terminal_tb \
      --max-stack-alloc=0 \
      -gROM_FILE="$mem" \
      -gBLOCK_FILE="$blocks_mem" \
      -gBLOCK_CELLS="$block_cells" \
      -gRX_FIFO="$rx_fifo" \
      -gTX_FIFO="$tx_fifo" \
      -gMAX_CYCLES="$max_cycles" \
      -gCLOCK_PERIOD_NS="$clock_period_ns" \
      --assert-level=error >"$log" 2>&1 &
  else
    ghdl -r --std=08 ilo_sdram_terminal_tb \
      --max-stack-alloc=0 \
      -gROM_FILE="$mem" \
      -gBLOCK_CELLS="$block_cells" \
      -gRX_FIFO="$rx_fifo" \
      -gTX_FIFO="$tx_fifo" \
      -gMAX_CYCLES="$max_cycles" \
      -gCLOCK_PERIOD_NS="$clock_period_ns" \
      --assert-level=error >"$log" 2>&1 &
  fi
else
  ghdl -a --std=08 "$VHDL_ROOT/rtl/ilo_memory.vhd"
  ghdl -a --std=08 "$VHDL_ROOT/sim/ilo_terminal_tb.vhd"
  ghdl -e --std=08 ilo_terminal_tb
  if [ -n "$blocks_mem" ]; then
    ghdl -r --std=08 ilo_terminal_tb \
      --max-stack-alloc=0 \
      -gROM_FILE="$mem" \
      -gBLOCK_FILE="$blocks_mem" \
      -gBLOCK_CELLS="$block_cells" \
      -gRX_FIFO="$rx_fifo" \
      -gTX_FIFO="$tx_fifo" \
      -gMAX_CYCLES="$max_cycles" \
      -gCLOCK_PERIOD_NS="$clock_period_ns" \
      --assert-level=error >"$log" 2>&1 &
  else
    ghdl -r --std=08 ilo_terminal_tb \
      --max-stack-alloc=0 \
      -gROM_FILE="$mem" \
      -gBLOCK_CELLS="$block_cells" \
      -gRX_FIFO="$rx_fifo" \
      -gTX_FIFO="$tx_fifo" \
      -gMAX_CYCLES="$max_cycles" \
      -gCLOCK_PERIOD_NS="$clock_period_ns" \
      --assert-level=error >"$log" 2>&1 &
  fi
fi
ghdl_pid="$!"

python3 "$VHDL_ROOT/scripts/serial-bridge.py" --rx "$rx_fifo" --tx "$tx_fifo"
Added ilo-vm/vhdl/scripts/serial-bridge.py.
































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!/usr/bin/env python3
import argparse
import os
import select
import signal
import sys
import termios
import tty


def open_fifo(path):
    return os.open(path, os.O_RDWR | os.O_NONBLOCK)


def echo_byte(byte):
    if byte == 10:
        os.write(sys.stdout.fileno(), b"\r\n")
    elif byte == 8 or byte == 127:
        os.write(sys.stdout.fileno(), b"\b \b")
    else:
        os.write(sys.stdout.fileno(), bytes([byte]))


def write_rx(fd, data):
    for byte in data:
        if byte == 3:
            raise KeyboardInterrupt
        if byte == 13:
            byte = 10
        os.write(fd, f"{byte}\n".encode("ascii"))
        echo_byte(byte)


def drain_tx(fd, pending):
    try:
        chunk = os.read(fd, 4096)
    except BlockingIOError:
        return pending

    if not chunk:
        return pending

    pending += chunk
    while b"\n" in pending:
        line, pending = pending.split(b"\n", 1)
        line = line.strip()
        if not line:
            continue
        try:
            byte = int(line, 10) & 0xFF
        except ValueError:
            continue
        os.write(sys.stdout.fileno(), bytes([byte]))
    return pending


def main():
    parser = argparse.ArgumentParser(description="Bridge a terminal to ilo GHDL serial FIFOs.")
    parser.add_argument("--rx", required=True, help="FIFO receiving terminal input for VHDL")
    parser.add_argument("--tx", required=True, help="FIFO carrying VHDL output bytes")
    args = parser.parse_args()

    rx_fd = open_fifo(args.rx)
    tx_fd = open_fifo(args.tx)
    stdin_fd = sys.stdin.fileno()
    old_term = termios.tcgetattr(stdin_fd)
    pending_tx = b""

    def restore(*_):
        termios.tcsetattr(stdin_fd, termios.TCSADRAIN, old_term)
        os.close(rx_fd)
        os.close(tx_fd)

    signal.signal(signal.SIGTERM, restore)

    try:
        tty.setcbreak(stdin_fd)
        os.write(sys.stdout.fileno(), b"\r\n[ilo serial bridge: Ctrl-C exits]\r\n")
        while True:
            readable, _, _ = select.select([stdin_fd, tx_fd], [], [])
            if stdin_fd in readable:
                data = os.read(stdin_fd, 1024)
                if not data:
                    break
                write_rx(rx_fd, data)
            if tx_fd in readable:
                pending_tx = drain_tx(tx_fd, pending_tx)
    except KeyboardInterrupt:
        pass
    finally:
        restore()
        os.write(sys.stdout.fileno(), b"\r\n[ilo serial bridge closed]\r\n")


if __name__ == "__main__":
    main()
Added ilo-vm/vhdl/scripts/synth-yosys.sh.
















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/bin/sh
set -eu

SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
. "$SCRIPT_DIR/common.sh"

root="$VHDL_ROOT"
build="$VHDL_ROOT/build/synth"
target="${1:-generic}"
top="${2:-ilo_core}"

mkdir -p "$build"

case "$target" in
  generic|generic-opt|generic-full|ice40|ecp5|xc7)
    set -- \
      "$root/rtl/ilo_pkg.vhd" \
      "$root/rtl/ilo_core.vhd"
    ;;
  xc7+sram|xc7-sram)
    target="xc7+sram"
    top="${2:-cmod_a7_top}"
    set -- \
      "$root/rtl/ilo_pkg.vhd" \
      "$root/rtl/ilo_core.vhd" \
      "$root/rtl/ilo_sram8_controller.vhd" \
      "$root/rtl/ilo_byte_fifo.vhd" \
      "$root/rtl/ilo_uart_tx.vhd" \
      "$root/rtl/ilo_uart_rx.vhd" \
      "$root/rtl/boards/cmod_a7_top.vhd"
    ;;
  *)
    echo "usage: $0 [generic|generic-opt|generic-full|ice40|ecp5|xc7|xc7+sram] [top]" >&2
    exit 2
    ;;
esac

verilog="$build/$top.v"
json="$build/$top-$target.json"
log="$build/$top-$target.log"

echo "Translating VHDL top '$top' with GHDL..."
ghdl --synth --std=08 --out=verilog "$@" -e "$top" > "$verilog"

case "$target" in
  generic)
    yosys_script="read_verilog -nolatches $verilog; hierarchy -check -top $top; proc; stat; write_json $json"
    ;;
  generic-opt)
    yosys_script="read_verilog -nolatches $verilog; hierarchy -check -top $top; proc; opt_expr; opt_clean; check; fsm; opt; wreduce; peepopt; opt_clean; alumacc; share; opt; memory -nomap; opt_clean; stat; write_json $json"
    ;;
  generic-full)
    yosys_script="read_verilog -nolatches $verilog; synth -top $top; stat; write_json $json"
    ;;
  ice40)
    yosys_script="read_verilog -nolatches $verilog; synth_ice40 -top $top -json $json"
    ;;
  ecp5)
    yosys_script="read_verilog -nolatches $verilog; synth_ecp5 -top $top -json $json"
    ;;
  xc7|xc7+sram)
    yosys_script="read_verilog -nolatches $verilog; synth_xilinx -family xc7 -top $top; write_json $json"
    ;;
esac

echo "Running Yosys target '$target'..."
yosys -p "$yosys_script" > "$log"

echo "Wrote:"
echo "  $verilog"
echo "  $json"
echo "  $log"
echo
echo "Resource summary:"
if ! awk '
  /^[0-9]+(\.[0-9]+)*\. Printing statistics\./ {
    buf = $0 ORS
    in_stats = 1
    next
  }

  in_stats && (/^[0-9]+(\.[0-9]+)*\. Executing / || /^End of script\./) {
    last = buf
    buf = ""
    in_stats = 0
    next
  }

  in_stats {
    buf = buf $0 ORS
  }

  END {
    if (in_stats && buf != "")
      last = buf

    if (last == "")
      exit 1

    printf "%s", last
  }
' "$log"; then
  echo "No Yosys statistics block found in $log" >&2
fi
Added ilo-vm/vhdl/scripts/vivado-cmod-a7.tcl.


































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
set root [file normalize [file join [file dirname [info script]] ..]]
set build_dir [file join $root build vivado cmod-a7]
file mkdir $build_dir

create_project -force ilo_cmod_a7 $build_dir -part xc7a35tcpg236-1
set_property target_language VHDL [current_project]

add_files -norecurse [list \
  [file join $root rtl ilo_pkg.vhd] \
  [file join $root rtl ilo_core.vhd] \
  [file join $root rtl ilo_sram8_controller.vhd] \
  [file join $root rtl ilo_byte_fifo.vhd] \
  [file join $root rtl ilo_uart_tx.vhd] \
  [file join $root rtl ilo_uart_rx.vhd] \
  [file join $root rtl boards cmod_a7_top.vhd] \
]
add_files -fileset constrs_1 -norecurse [file join $root constraints cmod_a7.xdc]

set_property top cmod_a7_top [current_fileset]
update_compile_order -fileset sources_1

synth_design -top cmod_a7_top -part xc7a35tcpg236-1
write_checkpoint -force [file join $build_dir post_synth.dcp]
report_utilization -file [file join $build_dir utilization_synth.rpt]
report_timing_summary -file [file join $build_dir timing_synth.rpt]

opt_design
place_design
route_design
write_checkpoint -force [file join $build_dir post_route.dcp]
report_utilization -file [file join $build_dir utilization_route.rpt]
report_timing_summary -file [file join $build_dir timing_route.rpt]
write_bitstream -force [file join $build_dir ilo_cmod_a7.bit]
Added ilo-vm/vhdl/sim/cmod_a7_top_tb.vhd.














































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use std.env.all;

entity cmod_a7_top_tb is
end entity;

architecture sim of cmod_a7_top_tb is
  constant CLKS_PER_BIT : positive := 4;

  signal sysclk : std_logic := '0';
  signal btn : std_logic_vector(1 downto 0) := (others => '0');
  signal led : std_logic_vector(1 downto 0);
  signal led0_b : std_logic;
  signal led0_g : std_logic;
  signal led0_r : std_logic;
  signal uart_rxd_out : std_logic := '1';
  signal uart_txd_in : std_logic;
  signal sram_addr : unsigned(18 downto 0);
  signal sram_data : std_logic_vector(7 downto 0);
  signal sram_ce_n : std_logic;
  signal sram_oe_n : std_logic;
  signal sram_we_n : std_logic;
  signal done : boolean := false;
begin
  sysclk <= not sysclk after 5 ns;

  dut_i : entity work.cmod_a7_top
    generic map (
      UART_CLKS_PER_BIT => CLKS_PER_BIT,
      RESET_CYCLES => 2
    )
    port map (
      sysclk => sysclk,
      btn => btn,
      led => led,
      led0_b => led0_b,
      led0_g => led0_g,
      led0_r => led0_r,
      uart_rxd_out => uart_rxd_out,
      uart_txd_in => uart_txd_in,
      MemAdr => sram_addr,
      MemDB => sram_data,
      RamOEn => sram_oe_n,
      RamWEn => sram_we_n,
      RamCEn => sram_ce_n
    );

  sram_i : entity work.sram8_model
    generic map (
      ADDR_WIDTH => 19,
      OUTPUT_DELAY_NS => 1
    )
    port map (
      addr => sram_addr,
      data => sram_data,
      ce_n => sram_ce_n,
      oe_n => sram_oe_n,
      we_n => sram_we_n
    );

  process
  begin
    btn(0) <= '1';
    wait for 80 ns;
    wait until rising_edge(sysclk);
    btn(0) <= '0';
    wait;
  end process;

  process
    variable value : std_logic_vector(7 downto 0);
    variable l : line;
  begin
    wait until uart_txd_in = '0';
    wait for 5 ns * CLKS_PER_BIT;
    assert uart_txd_in = '0' report "UART start bit not stable" severity failure;
    for i in 0 to 7 loop
      wait for 10 ns * CLKS_PER_BIT;
      value(i) := uart_txd_in;
    end loop;
    wait for 10 ns * CLKS_PER_BIT;
    assert uart_txd_in = '1' report "UART stop bit not high" severity failure;
    assert value = x"41" report "unexpected UART byte" severity failure;

    wait until led(0) = '1';
    assert led(1) = '0' report "core errored during Cmod smoke test" severity failure;
    write(l, string'("CMOD_A7_SMOKE_TX: "));
    write(l, to_integer(unsigned(value)));
    writeline(output, l);
    done <= true;
    stop;
  end process;

  process
  begin
    wait for 100 us;
    assert done report "Cmod A7 top smoke test timeout" severity failure;
    wait;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/icepi_zero_sdram_top_tb.vhd.


































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use std.env.all;

entity icepi_zero_sdram_top_tb is
  generic (
    PROFILE : string := "FAST";
    TEST : string := "SMOKE";
    BOOT_MEM_FILE : string := ""
  );
end entity;

architecture sim of icepi_zero_sdram_top_tb is
  function profile_time(
    constant fast_value : time;
    constant icepi_value : time
  ) return time is
  begin
    if PROFILE = "ICEPI" then
      return icepi_value;
    end if;
    return fast_value;
  end function;

  function profile_natural(
    constant fast_value : natural;
    constant icepi_value : natural
  ) return natural is
  begin
    if PROFILE = "ICEPI" then
      return icepi_value;
    end if;
    return fast_value;
  end function;

  constant CLK_PERIOD : time := profile_time(10 ns, 20 ns);
  constant CLKS_PER_BIT : positive := profile_natural(4, 434);
  constant RESET_CYCLES : natural := profile_natural(2, 16);
  constant SDRAM_INIT_WAIT_CYCLES : natural := profile_natural(4, 10000);
  constant SDRAM_REFRESH_INTERVAL_CYCLES : natural := profile_natural(64, 390);
  constant SDRAM_TRCD_CYCLES : natural := 1;
  constant SDRAM_TRP_CYCLES : natural := 1;
  constant SDRAM_TRFC_CYCLES : natural := profile_natural(2, 4);
  constant SDRAM_TMRD_CYCLES : natural := profile_natural(1, 2);
  constant SDRAM_READ_WAIT_CYCLES : natural := 3;
  constant SDRAM_WRITE_RECOVERY_CYCLES : natural := profile_natural(1, 2);
  constant TIMEOUT : time := profile_time(2 ms, 13 ms);
  constant UART_STRESS_TX_COUNT : natural := 20;
  constant UART_STRESS_RX_BYTE : natural := 122;
  constant PRELOADED_TX_COUNT : natural := 4;

  function expected_tx_count return natural is
  begin
    if TEST = "PRELOADED" then
      return PRELOADED_TX_COUNT;
    end if;
    if TEST = "UART_STRESS" then
      return UART_STRESS_TX_COUNT + 1;
    end if;
    return 1;
  end function;

  function expected_uart_byte(index : natural) return std_logic_vector is
  begin
    if TEST = "PRELOADED" then
      case index is
        when 0 => return x"42";
        when 1 => return x"4F";
        when 2 => return x"4F";
        when others => return x"54";
      end case;
    end if;
    if TEST = "UART_STRESS" then
      if index < UART_STRESS_TX_COUNT then
        return std_logic_vector(to_unsigned(65 + index, 8));
      end if;
      return std_logic_vector(to_unsigned(UART_STRESS_RX_BYTE, 8));
    end if;
    return x"41";
  end function;

  procedure uart_send_byte(
    signal rx : out std_logic;
    constant value : std_logic_vector(7 downto 0)
  ) is
  begin
    rx <= '0';
    wait for CLK_PERIOD * CLKS_PER_BIT;
    for i in 0 to 7 loop
      rx <= value(i);
      wait for CLK_PERIOD * CLKS_PER_BIT;
    end loop;
    rx <= '1';
    wait for CLK_PERIOD * CLKS_PER_BIT;
  end procedure;

  procedure uart_recv_byte(
    signal tx : in std_logic;
    variable value : out std_logic_vector(7 downto 0)
  ) is
  begin
    wait until tx = '0';
    wait for (CLK_PERIOD * CLKS_PER_BIT) / 2;
    assert tx = '0' report "UART start bit not stable" severity failure;
    for i in 0 to 7 loop
      wait for CLK_PERIOD * CLKS_PER_BIT;
      value(i) := tx;
    end loop;
    wait for CLK_PERIOD * CLKS_PER_BIT;
    assert tx = '1' report "UART stop bit not high" severity failure;
  end procedure;

  signal clk : std_logic := '0';
  signal button : std_logic_vector(1 downto 0) := (others => '1');
  signal led : std_logic_vector(4 downto 0);
  signal usb_rx : std_logic := '1';
  signal usb_tx : std_logic;

  signal sdram_a : unsigned(12 downto 0);
  signal sdram_ba : unsigned(1 downto 0);
  signal sdram_dq : std_logic_vector(15 downto 0);
  signal sdram_dqm : std_logic_vector(1 downto 0);
  signal sdram_csn : std_logic;
  signal sdram_cke : std_logic;
  signal sdram_clk : std_logic;
  signal sdram_wen : std_logic;
  signal sdram_casn : std_logic;
  signal sdram_rasn : std_logic;
begin
  clk <= not clk after CLK_PERIOD / 2;

  dut_i : entity work.icepi_zero_sdram_top
    generic map (
      BOOT_IMAGE => TEST,
      UART_CLKS_PER_BIT => CLKS_PER_BIT,
      RESET_CYCLES => RESET_CYCLES,
      SDRAM_INIT_WAIT_CYCLES => SDRAM_INIT_WAIT_CYCLES,
      SDRAM_REFRESH_INTERVAL_CYCLES => SDRAM_REFRESH_INTERVAL_CYCLES,
      SDRAM_TRCD_CYCLES => SDRAM_TRCD_CYCLES,
      SDRAM_TRP_CYCLES => SDRAM_TRP_CYCLES,
      SDRAM_TRFC_CYCLES => SDRAM_TRFC_CYCLES,
      SDRAM_TMRD_CYCLES => SDRAM_TMRD_CYCLES,
      SDRAM_READ_WAIT_CYCLES => SDRAM_READ_WAIT_CYCLES,
      SDRAM_WRITE_RECOVERY_CYCLES => SDRAM_WRITE_RECOVERY_CYCLES
    )
    port map (
      clk => clk,
      button => button,
      led => led,
      usb_rx => usb_rx,
      usb_tx => usb_tx,
      sdram_a => sdram_a,
      sdram_ba => sdram_ba,
      sdram_dq => sdram_dq,
      sdram_dqm => sdram_dqm,
      sdram_csn => sdram_csn,
      sdram_cke => sdram_cke,
      sdram_clk => sdram_clk,
      sdram_wen => sdram_wen,
      sdram_casn => sdram_casn,
      sdram_rasn => sdram_rasn
    );

  sdram_i : entity work.sdram_model
    generic map (
      TRCD_CYCLES => SDRAM_TRCD_CYCLES,
      TRP_CYCLES => SDRAM_TRP_CYCLES,
      TRFC_CYCLES => SDRAM_TRFC_CYCLES,
      TMRD_CYCLES => SDRAM_TMRD_CYCLES,
      WRITE_RECOVERY_CYCLES => SDRAM_WRITE_RECOVERY_CYCLES,
      INIT_WAIT_CYCLES => SDRAM_INIT_WAIT_CYCLES,
      MAX_REFRESH_INTERVAL_CYCLES => SDRAM_REFRESH_INTERVAL_CYCLES * 2,
      MEM_FILE => BOOT_MEM_FILE
    )
    port map (
      clk => sdram_clk,
      a => sdram_a,
      ba => sdram_ba,
      dq => sdram_dq,
      dqm => sdram_dqm,
      csn => sdram_csn,
      cke => sdram_cke,
      wen => sdram_wen,
      casn => sdram_casn,
      rasn => sdram_rasn
    );

  process
  begin
    button(0) <= '0';
    wait for 80 ns;
    wait until rising_edge(clk);
    button(0) <= '1';
    wait;
  end process;

  process
  begin
    if TEST = "UART_STRESS" then
      wait until led(4) = '1';
      wait for CLK_PERIOD * CLKS_PER_BIT * 3;
      uart_send_byte(usb_rx, std_logic_vector(to_unsigned(UART_STRESS_RX_BYTE, 8)));
    end if;
    wait;
  end process;

  process
    variable value : std_logic_vector(7 downto 0);
    variable l : line;
  begin
    for i in 0 to expected_tx_count - 1 loop
      uart_recv_byte(usb_tx, value);
      assert value = expected_uart_byte(i) report "unexpected UART byte" severity failure;
    end loop;

    if led(0) /= '1' then
      wait until led(0) = '1';
    end if;
    assert led(1) = '0' report "core errored during ICEPI Zero SDRAM UART test" severity failure;
    if TEST = "PRELOADED" then
      write(l, string'("ICEPI_ZERO_SDRAM_PRELOADED_BOOT_TX: "));
      write(l, expected_tx_count);
    elsif TEST = "UART_STRESS" then
      write(l, string'("ICEPI_ZERO_SDRAM_UART_STRESS_TX: "));
      write(l, expected_tx_count);
    else
      write(l, string'("ICEPI_ZERO_SDRAM_SMOKE_TX: "));
      write(l, to_integer(unsigned(value)));
    end if;
    writeline(output, l);
    stop;
  end process;

  process
  begin
    wait for TIMEOUT;
    assert false report "ICEPI Zero SDRAM top smoke test timeout" severity failure;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/icepi_zero_top_tb.vhd.


















































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;
use std.env.all;

entity icepi_zero_top_tb is
end entity;

architecture sim of icepi_zero_top_tb is
  constant CLKS_PER_BIT : positive := 4;

  signal clk : std_logic := '0';
  signal button : std_logic_vector(1 downto 0) := (others => '1');
  signal led : std_logic_vector(4 downto 0);
  signal usb_rx : std_logic := '1';
  signal usb_tx : std_logic;
begin
  clk <= not clk after 5 ns;

  dut_i : entity work.icepi_zero_top
    generic map (
      UART_CLKS_PER_BIT => CLKS_PER_BIT,
      RESET_CYCLES => 2
    )
    port map (
      clk => clk,
      button => button,
      led => led,
      usb_rx => usb_rx,
      usb_tx => usb_tx
    );

  process
  begin
    button(0) <= '0';
    wait for 80 ns;
    wait until rising_edge(clk);
    button(0) <= '1';
    wait;
  end process;

  process
    variable value : std_logic_vector(7 downto 0);
    variable l : line;
  begin
    wait until usb_tx = '0';
    wait for 5 ns * CLKS_PER_BIT;
    assert usb_tx = '0' report "UART start bit not stable" severity failure;
    for i in 0 to 7 loop
      wait for 10 ns * CLKS_PER_BIT;
      value(i) := usb_tx;
    end loop;
    wait for 10 ns * CLKS_PER_BIT;
    assert usb_tx = '1' report "UART stop bit not high" severity failure;
    assert value = x"41" report "unexpected UART byte" severity failure;

    if led(0) /= '1' then
      wait until led(0) = '1';
    end if;
    assert led(1) = '0' report "core errored during ICEPI Zero smoke test" severity failure;
    write(l, string'("ICEPI_ZERO_SMOKE_TX: "));
    write(l, to_integer(unsigned(value)));
    writeline(output, l);
    stop;
  end process;

  process
  begin
    wait for 100 us;
    assert false report "ICEPI Zero top smoke test timeout" severity failure;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/ilo_reload_tb.vhd.
















































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.env.all;

use work.ilo_pkg.all;

entity ilo_reload_tb is
  generic (
    ROM_FILE : string := "";
    MEM_READ_WAIT_CYCLES : natural := 0;
    MEM_WRITE_WAIT_CYCLES : natural := 0;
    POISON_UNINITIALIZED : boolean := false;
    MAX_CYCLES : natural := 10000
  );
end entity;

architecture sim of ilo_reload_tb is
  signal clk        : std_logic := '0';
  signal reset      : std_logic := '1';
  signal mem_req    : std_logic;
  signal mem_we     : std_logic;
  signal mem_addr   : addr_t;
  signal mem_wdata  : cell_t;
  signal mem_rdata  : cell_t;
  signal mem_ready  : std_logic;
  signal reload_req : std_logic;
  signal reload_ready : std_logic;
  signal serial_tx_valid : std_logic;
  signal serial_tx_data  : std_logic_vector(7 downto 0);
  signal serial_rx_req   : std_logic;
  signal block_req   : std_logic;
  signal block_we    : std_logic;
  signal block_addr  : unsigned(31 downto 0);
  signal block_wdata : cell_t;
  signal halted     : std_logic;
  signal errored    : std_logic;
  signal error_code : unsigned(7 downto 0);

begin
  clk <= not clk after 5 ns;

  mem_i : entity work.ilo_memory
    generic map (
      ROM_FILE => ROM_FILE,
      READ_WAIT_CYCLES => MEM_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => MEM_WRITE_WAIT_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk => clk,
      req => mem_req,
      we => mem_we,
      addr => mem_addr,
      wdata => mem_wdata,
      rdata => mem_rdata,
      ready => mem_ready,
      reload_req => reload_req,
      reload_ready => reload_ready
    );

  core_i : entity work.ilo_core
    port map (
      clk => clk,
      reset => reset,
      mem_req => mem_req,
      mem_we => mem_we,
      mem_addr => mem_addr,
      mem_wdata => mem_wdata,
      mem_rdata => mem_rdata,
      mem_ready => mem_ready,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data => serial_tx_data,
      serial_tx_ready => '1',
      serial_rx_req => serial_rx_req,
      serial_rx_valid => '0',
      serial_rx_data => (others => '0'),
      block_req => block_req,
      block_we => block_we,
      block_addr => block_addr,
      block_wdata => block_wdata,
      block_rdata => CELL_ZERO,
      block_ready => '0',
      reload_req => reload_req,
      reload_ready => reload_ready,
      halted => halted,
      errored => errored,
      error_code => error_code
    );

  process
  begin
    reset <= '1';
    wait for 50 ns;
    wait until rising_edge(clk);
    reset <= '0';
    wait;
  end process;

  process
    variable reloads : natural := 0;
  begin
    for cycle in 0 to MAX_CYCLES loop
      wait until rising_edge(clk);
      if reload_ready = '1' then
        reloads := reloads + 1;
        if reloads = 2 then
          assert sim_debug.get_sp = 0 report "reload did not clear data stack" severity failure;
          assert sim_debug.get_rp = 0 report "reload did not clear return stack" severity failure;
          report "RELOAD PASS";
          stop;
          wait;
        end if;
      end if;
      assert halted = '0' report "reload test halted before second reload" severity failure;
      assert errored = '0' report "reload test errored: " & integer'image(to_integer(error_code)) severity failure;
    end loop;
    assert false report "reload test timeout" severity failure;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/ilo_sdram_controller_tb.vhd.




























































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.env.all;

use work.ilo_pkg.all;

entity ilo_sdram_controller_tb is
end entity;

architecture sim of ilo_sdram_controller_tb is
  type init_monitor_state_t is (
    MON_WAIT_CKE,
    MON_PRECHARGE,
    MON_REFRESH_1,
    MON_REFRESH_2,
    MON_MODE,
    MON_DONE
  );

  signal clk : std_logic := '0';
  signal reset : std_logic := '1';
  signal req : std_logic := '0';
  signal we : std_logic := '0';
  signal addr : addr_t := (others => '0');
  signal wdata : cell_t := CELL_ZERO;
  signal rdata : cell_t;
  signal ready : std_logic;
  signal reload_req : std_logic := '0';
  signal reload_ready : std_logic;

  signal sdram_a : unsigned(12 downto 0);
  signal sdram_ba : unsigned(1 downto 0);
  signal sdram_dq : std_logic_vector(15 downto 0);
  signal sdram_dqm : std_logic_vector(1 downto 0);
  signal sdram_csn : std_logic;
  signal sdram_cke : std_logic;
  signal sdram_clk : std_logic;
  signal sdram_wen : std_logic;
  signal sdram_casn : std_logic;
  signal sdram_rasn : std_logic;
  signal init_sequence_seen : std_logic := '0';

  procedure write_cell(
    signal req_s : out std_logic;
    signal we_s : out std_logic;
    signal addr_s : out addr_t;
    signal wdata_s : out cell_t;
    signal ready_s : in std_logic;
    constant a : natural;
    constant v : cell_t
  ) is
  begin
    wait until rising_edge(clk);
    addr_s <= to_unsigned(a, MEM_ADDR_WIDTH);
    wdata_s <= v;
    we_s <= '1';
    req_s <= '1';
    wait until ready_s = '1';
    wait until rising_edge(clk);
    req_s <= '0';
    we_s <= '0';
  end procedure;

  procedure read_cell(
    signal req_s : out std_logic;
    signal we_s : out std_logic;
    signal addr_s : out addr_t;
    signal ready_s : in std_logic;
    signal rdata_s : in cell_t;
    constant a : natural;
    constant expected : cell_t
  ) is
  begin
    wait until rising_edge(clk);
    addr_s <= to_unsigned(a, MEM_ADDR_WIDTH);
    we_s <= '0';
    req_s <= '1';
    wait until ready_s = '1';
    assert rdata_s = expected
      report "unexpected SDRAM read data"
      severity failure;
    wait until rising_edge(clk);
    req_s <= '0';
  end procedure;

  procedure wait_cycles(constant count : natural) is
  begin
    for i in 1 to count loop
      wait until rising_edge(clk);
    end loop;
  end procedure;

  procedure assert_reset_idle is
  begin
    wait for 1 ns;
    assert ready = '0'
      report "SDRAM controller asserted ready during reset"
      severity failure;
    assert reload_ready = '0'
      report "SDRAM controller asserted reload_ready during reset"
      severity failure;
    assert sdram_cke = '0'
      report "SDRAM controller kept CKE high during reset"
      severity failure;
  end procedure;

  procedure release_and_wait_for_init(signal reset_s : out std_logic) is
  begin
    wait until rising_edge(clk);
    reset_s <= '0';
    wait until init_sequence_seen = '1';
    wait_cycles(4);
    assert ready = '0'
      report "SDRAM controller produced stale ready after initialization"
      severity failure;
    assert reload_ready = '0'
      report "SDRAM controller produced stale reload_ready after initialization"
      severity failure;
  end procedure;
begin
  clk <= not clk after 5 ns;

  dut_i : entity work.ilo_sdram_controller
    generic map (
      INIT_WAIT_CYCLES => 4,
      REFRESH_INTERVAL_CYCLES => 32,
      TRCD_CYCLES => 1,
      TRP_CYCLES => 1,
      TRFC_CYCLES => 2,
      TMRD_CYCLES => 1,
      READ_WAIT_CYCLES => 3,
      WRITE_RECOVERY_CYCLES => 1
    )
    port map (
      clk => clk,
      reset => reset,
      req => req,
      we => we,
      addr => addr,
      wdata => wdata,
      rdata => rdata,
      ready => ready,
      reload_req => reload_req,
      reload_ready => reload_ready,
      sdram_a => sdram_a,
      sdram_ba => sdram_ba,
      sdram_dq => sdram_dq,
      sdram_dqm => sdram_dqm,
      sdram_csn => sdram_csn,
      sdram_cke => sdram_cke,
      sdram_clk => sdram_clk,
      sdram_wen => sdram_wen,
      sdram_casn => sdram_casn,
      sdram_rasn => sdram_rasn
    );

  sdram_i : entity work.sdram_model
    generic map (
      HALFWORD_ADDR_WIDTH => 17,
      CAS_LATENCY => 2,
      TRCD_CYCLES => 1,
      TRP_CYCLES => 1,
      TRFC_CYCLES => 2,
      TMRD_CYCLES => 1,
      WRITE_RECOVERY_CYCLES => 1,
      INIT_WAIT_CYCLES => 4,
      MAX_REFRESH_INTERVAL_CYCLES => 64
    )
    port map (
      clk => sdram_clk,
      a => sdram_a,
      ba => sdram_ba,
      dq => sdram_dq,
      dqm => sdram_dqm,
      csn => sdram_csn,
      cke => sdram_cke,
      wen => sdram_wen,
      casn => sdram_casn,
      rasn => sdram_rasn
    );

  process(sdram_clk)
    variable state : init_monitor_state_t := MON_WAIT_CKE;
  begin
    if rising_edge(sdram_clk) then
      if reset = '1' then
        state := MON_WAIT_CKE;
        init_sequence_seen <= '0';
      else
        if state = MON_WAIT_CKE and sdram_cke = '1' then
          state := MON_PRECHARGE;
        end if;

        if sdram_cke = '1' and sdram_csn = '0' then
          if sdram_rasn = '0' and sdram_casn = '1' and sdram_wen = '0' then
            assert state = MON_PRECHARGE or state = MON_DONE
              report "controller issued PRECHARGE outside SDRAM init precharge step"
              severity failure;
            if state = MON_PRECHARGE then
              assert sdram_a(10) = '1'
                report "controller SDRAM init did not use PRECHARGE ALL"
                severity failure;
              state := MON_REFRESH_1;
            end if;
          elsif sdram_rasn = '0' and sdram_casn = '0' and sdram_wen = '1' then
            assert state = MON_REFRESH_1 or state = MON_REFRESH_2 or state = MON_DONE
              report "controller issued REFRESH outside expected SDRAM init step"
              severity failure;
            if state = MON_REFRESH_1 then
              state := MON_REFRESH_2;
            elsif state = MON_REFRESH_2 then
              state := MON_MODE;
            end if;
          elsif sdram_rasn = '0' and sdram_casn = '0' and sdram_wen = '0' then
            assert state = MON_MODE or state = MON_DONE
              report "controller issued MODE REGISTER SET outside expected SDRAM init step"
              severity failure;
            if state = MON_MODE then
              assert to_integer(unsigned(sdram_a(6 downto 4))) = 2
                report "controller SDRAM init programmed unexpected CAS latency"
                severity failure;
              state := MON_DONE;
              init_sequence_seen <= '1';
            end if;
          elsif not (sdram_rasn = '1' and sdram_casn = '1' and sdram_wen = '1') then
            assert state = MON_DONE
              report "controller issued normal SDRAM command before init sequence completed"
              severity failure;
          end if;
        end if;
      end if;
    end if;
  end process;

  process
  begin
    reset <= '1';
    wait_cycles(2);
    assert_reset_idle;

    reset <= '0';
    wait_cycles(2);
    reset <= '1';
    wait_cycles(1);
    assert_reset_idle;

    release_and_wait_for_init(reset);
    assert init_sequence_seen = '1'
      report "controller did not complete expected SDRAM init sequence"
      severity failure;

    write_cell(req, we, addr, wdata, ready, 0, signed'(x"12345678"));
    write_cell(req, we, addr, wdata, ready, 1, signed'(x"89ABCDEF"));
    write_cell(req, we, addr, wdata, ready, 512, signed'(x"0BADCAFE"));

    read_cell(req, we, addr, ready, rdata, 0, signed'(x"12345678"));
    read_cell(req, we, addr, ready, rdata, 1, signed'(x"89ABCDEF"));

    wait for 1 us;
    read_cell(req, we, addr, ready, rdata, 512, signed'(x"0BADCAFE"));

    wait until rising_edge(clk);
    addr <= to_unsigned(1024, MEM_ADDR_WIDTH);
    wdata <= signed'(x"55AA33CC");
    we <= '1';
    req <= '1';
    wait_cycles(3);
    assert ready = '0'
      report "SDRAM controller completed transaction before reset stress point"
      severity failure;
    reset <= '1';
    wait_cycles(1);
    req <= '0';
    we <= '0';
    reload_req <= '0';
    assert_reset_idle;
    wait_cycles(3);
    assert ready = '0'
      report "SDRAM controller produced stale ready after transaction reset"
      severity failure;
    assert reload_ready = '0'
      report "SDRAM controller produced stale reload_ready after transaction reset"
      severity failure;

    release_and_wait_for_init(reset);

    wait until rising_edge(clk);
    reload_req <= '1';
    wait until sdram_csn = '0' and sdram_rasn = '0' and sdram_casn = '0' and sdram_wen = '1';
    assert reload_ready = '0'
      report "SDRAM controller acknowledged reload during refresh command"
      severity failure;
    wait until reload_ready = '1';
    wait until rising_edge(clk);
    reload_req <= '0';

    write_cell(req, we, addr, wdata, ready, 2048, signed'(x"13579BDF"));
    wait until rising_edge(clk);
    addr <= to_unsigned(2048, MEM_ADDR_WIDTH);
    we <= '0';
    req <= '1';
    wait_cycles(2);
    reload_req <= '1';
    wait_cycles(2);
    assert reload_ready = '0'
      report "SDRAM controller acknowledged reload while transaction was active"
      severity failure;
    wait until ready = '1';
    assert rdata = signed'(x"13579BDF")
      report "unexpected read data during reload stress"
      severity failure;
    wait until rising_edge(clk);
    req <= '0';
    wait until reload_ready = '1';
    wait until rising_edge(clk);
    reload_req <= '0';

    wait until rising_edge(clk);
    reload_req <= '1';
    wait until reload_ready = '1';
    wait until rising_edge(clk);
    reload_req <= '0';

    report "ILO_SDRAM_CONTROLLER_OK";
    stop;
  end process;

  process
  begin
    wait for 100 us;
    assert false report "SDRAM controller test timeout" severity failure;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/ilo_sdram_tb.vhd.




























































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

use work.ilo_pkg.all;

entity ilo_sdram_tb is
  generic (
    ROM_FILE   : string := "";
    BLOCK_FILE : string := "";
    BLOCK_CELLS : natural := 1024;
    INIT_WAIT_CYCLES : natural := 4;
    REFRESH_INTERVAL_CYCLES : natural := 64;
    BLOCK_READ_WAIT_CYCLES : natural := 0;
    BLOCK_WRITE_WAIT_CYCLES : natural := 0;
    POISON_UNINITIALIZED : boolean := false;
    MAX_CYCLES : natural := 1000000;
    RX_TEXT    : string := ""
  );
end entity;

architecture sim of ilo_sdram_tb is
  signal clk        : std_logic := '0';
  signal reset      : std_logic := '1';
  signal mem_req    : std_logic;
  signal mem_we     : std_logic;
  signal mem_addr   : addr_t;
  signal mem_wdata  : cell_t;
  signal mem_rdata  : cell_t;
  signal mem_ready  : std_logic;
  signal serial_tx_valid : std_logic;
  signal serial_tx_data  : std_logic_vector(7 downto 0);
  signal serial_rx_req   : std_logic;
  signal serial_rx_valid : std_logic := '0';
  signal serial_rx_data  : std_logic_vector(7 downto 0) := (others => '0');
  signal block_req   : std_logic;
  signal block_we    : std_logic;
  signal block_addr  : unsigned(31 downto 0);
  signal block_wdata : cell_t;
  signal block_rdata : cell_t;
  signal block_ready : std_logic;
  signal reload_req   : std_logic;
  signal reload_ready : std_logic;
  signal halted     : std_logic;
  signal errored    : std_logic;
  signal error_code : unsigned(7 downto 0);

  signal sdram_a : unsigned(12 downto 0);
  signal sdram_ba : unsigned(1 downto 0);
  signal sdram_dq : std_logic_vector(15 downto 0);
  signal sdram_dqm : std_logic_vector(1 downto 0);
  signal sdram_csn : std_logic;
  signal sdram_cke : std_logic;
  signal sdram_clk : std_logic;
  signal sdram_wen : std_logic;
  signal sdram_casn : std_logic;
  signal sdram_rasn : std_logic;
begin
  clk <= not clk after 5 ns;

  mem_i : entity work.ilo_sdram_controller
    generic map (
      INIT_WAIT_CYCLES => INIT_WAIT_CYCLES,
      REFRESH_INTERVAL_CYCLES => REFRESH_INTERVAL_CYCLES
    )
    port map (
      clk    => clk,
      reset  => reset,
      req    => mem_req,
      we     => mem_we,
      addr   => mem_addr,
      wdata  => mem_wdata,
      rdata  => mem_rdata,
      ready  => mem_ready,
      reload_req   => reload_req,
      reload_ready => reload_ready,
      sdram_a => sdram_a,
      sdram_ba => sdram_ba,
      sdram_dq => sdram_dq,
      sdram_dqm => sdram_dqm,
      sdram_csn => sdram_csn,
      sdram_cke => sdram_cke,
      sdram_clk => sdram_clk,
      sdram_wen => sdram_wen,
      sdram_casn => sdram_casn,
      sdram_rasn => sdram_rasn
    );

  sdram_i : entity work.sdram_model
    generic map (
      MEM_FILE => ROM_FILE
    )
    port map (
      clk => sdram_clk,
      a => sdram_a,
      ba => sdram_ba,
      dq => sdram_dq,
      dqm => sdram_dqm,
      csn => sdram_csn,
      cke => sdram_cke,
      wen => sdram_wen,
      casn => sdram_casn,
      rasn => sdram_rasn
    );

  block_i : entity work.ilo_block_store
    generic map (
      BLOCK_FILE => BLOCK_FILE,
      BLOCK_CELLS => BLOCK_CELLS,
      READ_WAIT_CYCLES => BLOCK_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => BLOCK_WRITE_WAIT_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk    => clk,
      req    => block_req,
      we     => block_we,
      addr   => block_addr,
      wdata  => block_wdata,
      rdata  => block_rdata,
      ready  => block_ready
    );

  core_i : entity work.ilo_core
    port map (
      clk        => clk,
      reset      => reset,
      mem_req    => mem_req,
      mem_we     => mem_we,
      mem_addr   => mem_addr,
      mem_wdata  => mem_wdata,
      mem_rdata  => mem_rdata,
      mem_ready  => mem_ready,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data  => serial_tx_data,
      serial_tx_ready => '1',
      serial_rx_req   => serial_rx_req,
      serial_rx_valid => serial_rx_valid,
      serial_rx_data  => serial_rx_data,
      block_req   => block_req,
      block_we    => block_we,
      block_addr  => block_addr,
      block_wdata => block_wdata,
      block_rdata => block_rdata,
      block_ready => block_ready,
      reload_req => reload_req,
      reload_ready => reload_ready,
      halted     => halted,
      errored    => errored,
      error_code => error_code
    );

  process
  begin
    reset <= '1';
    wait for 50 ns;
    wait until rising_edge(clk);
    reset <= '0';
    wait;
  end process;

  process(clk)
    variable rx_index : natural := 1;
    variable rx_served : boolean := false;
  begin
    if rising_edge(clk) then
      serial_rx_valid <= '0';
      if reset = '1' then
        rx_index := 1;
        rx_served := false;
        serial_rx_data <= (others => '0');
      elsif serial_rx_req = '0' then
        rx_served := false;
      elsif not rx_served then
        if rx_index <= RX_TEXT'length then
          serial_rx_data <= std_logic_vector(to_unsigned(character'pos(RX_TEXT(rx_index)), 8));
          serial_rx_valid <= '1';
          rx_index := rx_index + 1;
          rx_served := true;
        end if;
      end if;
    end if;
  end process;

  process(clk)
    variable l : line;
  begin
    if rising_edge(clk) then
      if serial_tx_valid = '1' then
        write(l, string'("SERIAL_TX: "));
        write(l, to_integer(unsigned(serial_tx_data)));
        writeline(output, l);
      end if;
    end if;
  end process;

  process
    variable l : line;
  begin
    for cycle in 0 to MAX_CYCLES loop
      wait until rising_edge(clk);
      if halted = '1' then
        write(l, string'("FINAL_STACK:"));
        for i in DS_DEPTH downto 1 loop
          if i <= sim_debug.get_sp then
            write(l, string'(" "));
            write(l, to_integer(sim_debug.get_ds(i)));
          end if;
        end loop;
        writeline(output, l);
        assert false report "HALT" severity failure;
      elsif errored = '1' then
        write(l, string'("ERROR: "));
        write(l, to_integer(error_code));
        writeline(output, l);
        assert false report "ERROR" severity failure;
      end if;
    end loop;
    assert false report "TIMEOUT" severity failure;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/ilo_sdram_terminal_tb.vhd.






















































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

use work.ilo_pkg.all;

entity ilo_sdram_terminal_tb is
  generic (
    ROM_FILE   : string := "";
    BLOCK_FILE : string := "";
    BLOCK_CELLS : natural := 1024;
    INIT_WAIT_CYCLES : natural := 10000;
    REFRESH_INTERVAL_CYCLES : natural := 390;
    BLOCK_READ_WAIT_CYCLES : natural := 0;
    BLOCK_WRITE_WAIT_CYCLES : natural := 0;
    POISON_UNINITIALIZED : boolean := false;
    RX_FIFO    : string := "ilo-vhdl/build/terminal.rx";
    TX_FIFO    : string := "ilo-vhdl/build/terminal.tx";
    MAX_CYCLES : natural := 0;
    CLOCK_PERIOD_NS : positive := 10
  );
end entity;

architecture sim of ilo_sdram_terminal_tb is
  constant CLK_HALF_PERIOD : time := (CLOCK_PERIOD_NS * 1 ns) / 2;
  signal clk        : std_logic := '0';
  signal reset      : std_logic := '1';
  signal mem_req    : std_logic;
  signal mem_we     : std_logic;
  signal mem_addr   : addr_t;
  signal mem_wdata  : cell_t;
  signal mem_rdata  : cell_t;
  signal mem_ready  : std_logic;
  signal serial_tx_valid : std_logic;
  signal serial_tx_data  : std_logic_vector(7 downto 0);
  signal serial_rx_req   : std_logic;
  signal serial_rx_valid : std_logic := '0';
  signal serial_rx_data  : std_logic_vector(7 downto 0) := (others => '0');
  signal block_req   : std_logic;
  signal block_we    : std_logic;
  signal block_addr  : unsigned(31 downto 0);
  signal block_wdata : cell_t;
  signal block_rdata : cell_t;
  signal block_ready : std_logic;
  signal reload_req   : std_logic;
  signal reload_ready : std_logic;
  signal halted     : std_logic;
  signal errored    : std_logic;
  signal error_code : unsigned(7 downto 0);

  signal sdram_a : unsigned(12 downto 0);
  signal sdram_ba : unsigned(1 downto 0);
  signal sdram_dq : std_logic_vector(15 downto 0);
  signal sdram_dqm : std_logic_vector(1 downto 0);
  signal sdram_csn : std_logic;
  signal sdram_cke : std_logic;
  signal sdram_clk : std_logic;
  signal sdram_wen : std_logic;
  signal sdram_casn : std_logic;
  signal sdram_rasn : std_logic;

  file rx_file : text open read_mode is RX_FIFO;
  file tx_file : text open write_mode is TX_FIFO;
begin
  clk <= not clk after CLK_HALF_PERIOD;

  mem_i : entity work.ilo_sdram_controller
    generic map (
      INIT_WAIT_CYCLES => INIT_WAIT_CYCLES,
      REFRESH_INTERVAL_CYCLES => REFRESH_INTERVAL_CYCLES
    )
    port map (
      clk    => clk,
      reset  => reset,
      req    => mem_req,
      we     => mem_we,
      addr   => mem_addr,
      wdata  => mem_wdata,
      rdata  => mem_rdata,
      ready  => mem_ready,
      reload_req   => reload_req,
      reload_ready => reload_ready,
      sdram_a => sdram_a,
      sdram_ba => sdram_ba,
      sdram_dq => sdram_dq,
      sdram_dqm => sdram_dqm,
      sdram_csn => sdram_csn,
      sdram_cke => sdram_cke,
      sdram_clk => sdram_clk,
      sdram_wen => sdram_wen,
      sdram_casn => sdram_casn,
      sdram_rasn => sdram_rasn
    );

  sdram_i : entity work.sdram_model
    generic map (
      MEM_FILE => ROM_FILE
    )
    port map (
      clk => sdram_clk,
      a => sdram_a,
      ba => sdram_ba,
      dq => sdram_dq,
      dqm => sdram_dqm,
      csn => sdram_csn,
      cke => sdram_cke,
      wen => sdram_wen,
      casn => sdram_casn,
      rasn => sdram_rasn
    );

  block_i : entity work.ilo_block_store
    generic map (
      BLOCK_FILE  => BLOCK_FILE,
      BLOCK_CELLS => BLOCK_CELLS,
      READ_WAIT_CYCLES => BLOCK_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => BLOCK_WRITE_WAIT_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk    => clk,
      req    => block_req,
      we     => block_we,
      addr   => block_addr,
      wdata  => block_wdata,
      rdata  => block_rdata,
      ready  => block_ready
    );

  core_i : entity work.ilo_core
    port map (
      clk        => clk,
      reset      => reset,
      mem_req    => mem_req,
      mem_we     => mem_we,
      mem_addr   => mem_addr,
      mem_wdata  => mem_wdata,
      mem_rdata  => mem_rdata,
      mem_ready  => mem_ready,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data  => serial_tx_data,
      serial_tx_ready => '1',
      serial_rx_req   => serial_rx_req,
      serial_rx_valid => serial_rx_valid,
      serial_rx_data  => serial_rx_data,
      block_req   => block_req,
      block_we    => block_we,
      block_addr  => block_addr,
      block_wdata => block_wdata,
      block_rdata => block_rdata,
      block_ready => block_ready,
      reload_req   => reload_req,
      reload_ready => reload_ready,
      halted     => halted,
      errored    => errored,
      error_code => error_code
    );

  process
  begin
    reset <= '1';
    wait for 50 ns;
    wait until rising_edge(clk);
    reset <= '0';
    wait;
  end process;

  process(clk)
    variable l : line;
    variable byte_value : integer;
    variable rx_served : boolean := false;
  begin
    if rising_edge(clk) then
      serial_rx_valid <= '0';
      if reset = '1' then
        rx_served := false;
        serial_rx_data <= (others => '0');
      elsif serial_rx_req = '0' then
        rx_served := false;
      elsif not rx_served then
        readline(rx_file, l);
        read(l, byte_value);
        if byte_value < 0 then
          byte_value := 0;
        elsif byte_value > 255 then
          byte_value := 255;
        end if;
        serial_rx_data <= std_logic_vector(to_unsigned(byte_value, 8));
        serial_rx_valid <= '1';
        rx_served := true;
      end if;
    end if;
  end process;

  process(clk)
    variable prev_valid : std_logic := '0';
    variable prev_data : std_logic_vector(7 downto 0) := (others => '0');
  begin
    if rising_edge(clk) then
      if reset = '1' then
        prev_valid := '0';
        prev_data := (others => '0');
      else
        if serial_rx_valid = '1' then
          assert not is_x(serial_rx_data)
            report "serial_rx_data is invalid while serial_rx_valid is asserted"
            severity failure;
          if prev_valid = '1' then
            assert serial_rx_data = prev_data
              report "serial_rx_data changed while serial_rx_valid remained asserted"
              severity failure;
          end if;
        end if;
        prev_valid := serial_rx_valid;
        prev_data := serial_rx_data;
      end if;
    end if;
  end process;

  process(clk)
    variable l : line;
  begin
    if rising_edge(clk) then
      if serial_tx_valid = '1' then
        write(l, to_integer(unsigned(serial_tx_data)));
        writeline(tx_file, l);
        flush(tx_file);
      end if;
    end if;
  end process;

  process
    variable l : line;
  begin
    if MAX_CYCLES = 0 then
      loop
        wait until rising_edge(clk);
        if halted = '1' then
          write(l, string'("HALT"));
          writeline(output, l);
          wait;
        elsif errored = '1' then
          write(l, string'("ERROR: "));
          write(l, to_integer(error_code));
          writeline(output, l);
          assert false report "ERROR" severity failure;
        end if;
      end loop;
    else
      for cycle in 0 to MAX_CYCLES loop
        wait until rising_edge(clk);
        if halted = '1' then
          write(l, string'("HALT"));
          writeline(output, l);
          wait;
        elsif errored = '1' then
          write(l, string'("ERROR: "));
          write(l, to_integer(error_code));
          writeline(output, l);
          assert false report "ERROR" severity failure;
        end if;
      end loop;
      assert false report "TIMEOUT" severity failure;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/ilo_sram8_tb.vhd.


























































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

use work.ilo_pkg.all;

entity ilo_sram8_tb is
  generic (
    ROM_FILE   : string := "";
    BLOCK_FILE : string := "";
    BLOCK_CELLS : natural := 1024;
    READ_WAIT_CYCLES : natural := 1;
    WRITE_WAIT_CYCLES : natural := 1;
    SRAM_OUTPUT_DELAY_NS : natural := 1;
    BLOCK_READ_WAIT_CYCLES : natural := 0;
    BLOCK_WRITE_WAIT_CYCLES : natural := 0;
    POISON_UNINITIALIZED : boolean := false;
    MAX_CYCLES : natural := 1000000;
    RX_TEXT    : string := ""
  );
end entity;

architecture sim of ilo_sram8_tb is
  signal clk        : std_logic := '0';
  signal reset      : std_logic := '1';
  signal mem_req    : std_logic;
  signal mem_we     : std_logic;
  signal mem_addr   : addr_t;
  signal mem_wdata  : cell_t;
  signal mem_rdata  : cell_t;
  signal mem_ready  : std_logic;
  signal serial_tx_valid : std_logic;
  signal serial_tx_data  : std_logic_vector(7 downto 0);
  signal serial_rx_req   : std_logic;
  signal serial_rx_valid : std_logic := '0';
  signal serial_rx_data  : std_logic_vector(7 downto 0) := (others => '0');
  signal block_req   : std_logic;
  signal block_we    : std_logic;
  signal block_addr  : unsigned(31 downto 0);
  signal block_wdata : cell_t;
  signal block_rdata : cell_t;
  signal block_ready : std_logic;
  signal reload_req   : std_logic;
  signal reload_ready : std_logic;
  signal halted     : std_logic;
  signal errored    : std_logic;
  signal error_code : unsigned(7 downto 0);

  signal sram_addr : unsigned(18 downto 0);
  signal sram_data : std_logic_vector(7 downto 0);
  signal sram_ce_n : std_logic;
  signal sram_oe_n : std_logic;
  signal sram_we_n : std_logic;
begin
  clk <= not clk after 5 ns;

  mem_i : entity work.ilo_sram8_controller
    generic map (
      SRAM_ADDR_WIDTH => 19,
      READ_WAIT_CYCLES => READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => WRITE_WAIT_CYCLES
    )
    port map (
      clk    => clk,
      reset  => reset,
      req    => mem_req,
      we     => mem_we,
      addr   => mem_addr,
      wdata  => mem_wdata,
      rdata  => mem_rdata,
      ready  => mem_ready,
      reload_req => reload_req,
      reload_ready => reload_ready,
      sram_addr => sram_addr,
      sram_data => sram_data,
      sram_ce_n => sram_ce_n,
      sram_oe_n => sram_oe_n,
      sram_we_n => sram_we_n
    );

  sram_i : entity work.sram8_model
    generic map (
      MEM_FILE => ROM_FILE,
      ADDR_WIDTH => 19,
      OUTPUT_DELAY_NS => SRAM_OUTPUT_DELAY_NS,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      addr => sram_addr,
      data => sram_data,
      ce_n => sram_ce_n,
      oe_n => sram_oe_n,
      we_n => sram_we_n
    );

  block_i : entity work.ilo_block_store
    generic map (
      BLOCK_FILE => BLOCK_FILE,
      BLOCK_CELLS => BLOCK_CELLS,
      READ_WAIT_CYCLES => BLOCK_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => BLOCK_WRITE_WAIT_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk    => clk,
      req    => block_req,
      we     => block_we,
      addr   => block_addr,
      wdata  => block_wdata,
      rdata  => block_rdata,
      ready  => block_ready
    );

  core_i : entity work.ilo_core
    port map (
      clk        => clk,
      reset      => reset,
      mem_req    => mem_req,
      mem_we     => mem_we,
      mem_addr   => mem_addr,
      mem_wdata  => mem_wdata,
      mem_rdata  => mem_rdata,
      mem_ready  => mem_ready,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data  => serial_tx_data,
      serial_tx_ready => '1',
      serial_rx_req   => serial_rx_req,
      serial_rx_valid => serial_rx_valid,
      serial_rx_data  => serial_rx_data,
      block_req   => block_req,
      block_we    => block_we,
      block_addr  => block_addr,
      block_wdata => block_wdata,
      block_rdata => block_rdata,
      block_ready => block_ready,
      reload_req => reload_req,
      reload_ready => reload_ready,
      halted     => halted,
      errored    => errored,
      error_code => error_code
    );

  process
  begin
    reset <= '1';
    wait for 50 ns;
    wait until rising_edge(clk);
    reset <= '0';
    wait;
  end process;

  process(clk)
    variable rx_index : natural := 1;
    variable rx_served : boolean := false;
  begin
    if rising_edge(clk) then
      serial_rx_valid <= '0';
      if reset = '1' then
        rx_index := 1;
        rx_served := false;
        serial_rx_data <= (others => '0');
      elsif serial_rx_req = '0' then
        rx_served := false;
      elsif not rx_served then
        if rx_index <= RX_TEXT'length then
          serial_rx_data <= std_logic_vector(to_unsigned(character'pos(RX_TEXT(rx_index)), 8));
          serial_rx_valid <= '1';
          rx_index := rx_index + 1;
          rx_served := true;
        end if;
      end if;
    end if;
  end process;

  process(clk)
    variable prev_valid : std_logic := '0';
    variable prev_data : std_logic_vector(7 downto 0) := (others => '0');
  begin
    if rising_edge(clk) then
      if reset = '1' then
        prev_valid := '0';
        prev_data := (others => '0');
      else
        if serial_rx_valid = '1' then
          assert not is_x(serial_rx_data)
            report "serial_rx_data is invalid while serial_rx_valid is asserted"
            severity failure;
          if prev_valid = '1' then
            assert serial_rx_data = prev_data
              report "serial_rx_data changed while serial_rx_valid remained asserted"
              severity failure;
          end if;
        end if;
        prev_valid := serial_rx_valid;
        prev_data := serial_rx_data;
      end if;
    end if;
  end process;

  process(clk)
    variable l : line;
  begin
    if rising_edge(clk) then
      if serial_tx_valid = '1' then
        write(l, string'("SERIAL_TX: "));
        write(l, to_integer(unsigned(serial_tx_data)));
        writeline(output, l);
      end if;
    end if;
  end process;

  process
    variable l : line;
  begin
    for cycle in 0 to MAX_CYCLES loop
      wait until rising_edge(clk);
      if halted = '1' then
        write(l, string'("FINAL_STACK:"));
        for i in DS_DEPTH downto 1 loop
          if i <= sim_debug.get_sp then
            write(l, string'(" "));
            write(l, to_integer(sim_debug.get_ds(i)));
          end if;
        end loop;
        writeline(output, l);
        assert false report "HALT" severity failure;
      elsif errored = '1' then
        write(l, string'("ERROR: "));
        write(l, to_integer(error_code));
        writeline(output, l);
        assert false report "ERROR" severity failure;
      end if;
    end loop;
    assert false report "TIMEOUT" severity failure;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/ilo_sram8_terminal_tb.vhd.




































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

use work.ilo_pkg.all;

entity ilo_sram8_terminal_tb is
  generic (
    ROM_FILE   : string := "";
    BLOCK_FILE : string := "";
    BLOCK_CELLS : natural := 1024;
    SRAM_ADDR_WIDTH : natural := 19;
    READ_WAIT_CYCLES : natural := 1;
    WRITE_WAIT_CYCLES : natural := 1;
    SRAM_OUTPUT_DELAY_NS : natural := 1;
    BLOCK_READ_WAIT_CYCLES : natural := 0;
    BLOCK_WRITE_WAIT_CYCLES : natural := 0;
    POISON_UNINITIALIZED : boolean := false;
    RX_FIFO    : string := "ilo-vhdl/build/terminal.rx";
    TX_FIFO    : string := "ilo-vhdl/build/terminal.tx";
    MAX_CYCLES : natural := 0;
    CLOCK_PERIOD_NS : positive := 10
  );
end entity;

architecture sim of ilo_sram8_terminal_tb is
  constant CLK_HALF_PERIOD : time := (CLOCK_PERIOD_NS * 1 ns) / 2;
  signal clk        : std_logic := '0';
  signal reset      : std_logic := '1';
  signal mem_req    : std_logic;
  signal mem_we     : std_logic;
  signal mem_addr   : addr_t;
  signal mem_wdata  : cell_t;
  signal mem_rdata  : cell_t;
  signal mem_ready  : std_logic;
  signal serial_tx_valid : std_logic;
  signal serial_tx_data  : std_logic_vector(7 downto 0);
  signal serial_rx_req   : std_logic;
  signal serial_rx_valid : std_logic := '0';
  signal serial_rx_data  : std_logic_vector(7 downto 0) := (others => '0');
  signal block_req   : std_logic;
  signal block_we    : std_logic;
  signal block_addr  : unsigned(31 downto 0);
  signal block_wdata : cell_t;
  signal block_rdata : cell_t;
  signal block_ready : std_logic;
  signal reload_req   : std_logic;
  signal reload_ready : std_logic;
  signal halted     : std_logic;
  signal errored    : std_logic;
  signal error_code : unsigned(7 downto 0);

  signal sram_addr : unsigned(SRAM_ADDR_WIDTH - 1 downto 0);
  signal sram_data : std_logic_vector(7 downto 0);
  signal sram_ce_n : std_logic;
  signal sram_oe_n : std_logic;
  signal sram_we_n : std_logic;

  file rx_file : text open read_mode is RX_FIFO;
  file tx_file : text open write_mode is TX_FIFO;
begin
  clk <= not clk after CLK_HALF_PERIOD;

  mem_i : entity work.ilo_sram8_controller
    generic map (
      SRAM_ADDR_WIDTH   => SRAM_ADDR_WIDTH,
      READ_WAIT_CYCLES  => READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => WRITE_WAIT_CYCLES
    )
    port map (
      clk    => clk,
      reset  => reset,
      req    => mem_req,
      we     => mem_we,
      addr   => mem_addr,
      wdata  => mem_wdata,
      rdata  => mem_rdata,
      ready  => mem_ready,
      reload_req   => reload_req,
      reload_ready => reload_ready,
      sram_addr => sram_addr,
      sram_data => sram_data,
      sram_ce_n => sram_ce_n,
      sram_oe_n => sram_oe_n,
      sram_we_n => sram_we_n
    );

  sram_i : entity work.sram8_model
    generic map (
      MEM_FILE   => ROM_FILE,
      ADDR_WIDTH => SRAM_ADDR_WIDTH,
      OUTPUT_DELAY_NS => SRAM_OUTPUT_DELAY_NS,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      addr => sram_addr,
      data => sram_data,
      ce_n => sram_ce_n,
      oe_n => sram_oe_n,
      we_n => sram_we_n
    );

  block_i : entity work.ilo_block_store
    generic map (
      BLOCK_FILE  => BLOCK_FILE,
      BLOCK_CELLS => BLOCK_CELLS,
      READ_WAIT_CYCLES => BLOCK_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => BLOCK_WRITE_WAIT_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk    => clk,
      req    => block_req,
      we     => block_we,
      addr   => block_addr,
      wdata  => block_wdata,
      rdata  => block_rdata,
      ready  => block_ready
    );

  core_i : entity work.ilo_core
    port map (
      clk        => clk,
      reset      => reset,
      mem_req    => mem_req,
      mem_we     => mem_we,
      mem_addr   => mem_addr,
      mem_wdata  => mem_wdata,
      mem_rdata  => mem_rdata,
      mem_ready  => mem_ready,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data  => serial_tx_data,
      serial_tx_ready => '1',
      serial_rx_req   => serial_rx_req,
      serial_rx_valid => serial_rx_valid,
      serial_rx_data  => serial_rx_data,
      block_req   => block_req,
      block_we    => block_we,
      block_addr  => block_addr,
      block_wdata => block_wdata,
      block_rdata => block_rdata,
      block_ready => block_ready,
      reload_req   => reload_req,
      reload_ready => reload_ready,
      halted     => halted,
      errored    => errored,
      error_code => error_code
    );

  process
  begin
    reset <= '1';
    wait for 50 ns;
    wait until rising_edge(clk);
    reset <= '0';
    wait;
  end process;

  process(clk)
    variable l : line;
    variable byte_value : integer;
    variable rx_served : boolean := false;
  begin
    if rising_edge(clk) then
      serial_rx_valid <= '0';
      if reset = '1' then
        rx_served := false;
        serial_rx_data <= (others => '0');
      elsif serial_rx_req = '0' then
        rx_served := false;
      elsif not rx_served then
        readline(rx_file, l);
        read(l, byte_value);
        if byte_value < 0 then
          byte_value := 0;
        elsif byte_value > 255 then
          byte_value := 255;
        end if;
        serial_rx_data <= std_logic_vector(to_unsigned(byte_value, 8));
        serial_rx_valid <= '1';
        rx_served := true;
      end if;
    end if;
  end process;

  process(clk)
    variable prev_valid : std_logic := '0';
    variable prev_data : std_logic_vector(7 downto 0) := (others => '0');
  begin
    if rising_edge(clk) then
      if reset = '1' then
        prev_valid := '0';
        prev_data := (others => '0');
      else
        if serial_rx_valid = '1' then
          assert not is_x(serial_rx_data)
            report "serial_rx_data is invalid while serial_rx_valid is asserted"
            severity failure;
          if prev_valid = '1' then
            assert serial_rx_data = prev_data
              report "serial_rx_data changed while serial_rx_valid remained asserted"
              severity failure;
          end if;
        end if;
        prev_valid := serial_rx_valid;
        prev_data := serial_rx_data;
      end if;
    end if;
  end process;

  process(clk)
    variable l : line;
  begin
    if rising_edge(clk) then
      if serial_tx_valid = '1' then
        write(l, to_integer(unsigned(serial_tx_data)));
        writeline(tx_file, l);
        flush(tx_file);
      end if;
    end if;
  end process;

  process
    variable l : line;
  begin
    if MAX_CYCLES = 0 then
      loop
        wait until rising_edge(clk);
        if halted = '1' then
          write(l, string'("HALT"));
          writeline(output, l);
          wait;
        elsif errored = '1' then
          write(l, string'("ERROR: "));
          write(l, to_integer(error_code));
          writeline(output, l);
          assert false report "ERROR" severity failure;
        end if;
      end loop;
    else
      for cycle in 0 to MAX_CYCLES loop
        wait until rising_edge(clk);
        if halted = '1' then
          write(l, string'("HALT"));
          writeline(output, l);
          wait;
        elsif errored = '1' then
          write(l, string'("ERROR: "));
          write(l, to_integer(error_code));
          writeline(output, l);
          assert false report "ERROR" severity failure;
        end if;
      end loop;
      assert false report "TIMEOUT" severity failure;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/ilo_system_tb.vhd.
























































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

use work.ilo_pkg.all;

entity ilo_system_tb is
  generic (
    ROM_FILE   : string := "";
    BLOCK_FILE : string := "";
    BLOCK_CELLS : natural := 1024;
    MEM_READ_WAIT_CYCLES : natural := 0;
    MEM_WRITE_WAIT_CYCLES : natural := 0;
    BLOCK_READ_WAIT_CYCLES : natural := 0;
    BLOCK_WRITE_WAIT_CYCLES : natural := 0;
    RESET_CYCLES : natural := 4;
    POISON_UNINITIALIZED : boolean := false;
    MAX_CYCLES : natural := 1000000;
    RX_TEXT    : string := ""
  );
end entity;

architecture sim of ilo_system_tb is
  signal clk        : std_logic := '0';
  signal reset      : std_logic := '1';
  signal serial_tx_valid : std_logic;
  signal serial_tx_data  : std_logic_vector(7 downto 0);
  signal serial_rx_req   : std_logic;
  signal serial_rx_valid : std_logic := '0';
  signal serial_rx_data  : std_logic_vector(7 downto 0) := (others => '0');
  signal halted     : std_logic;
  signal errored    : std_logic;
  signal error_code : unsigned(7 downto 0);
begin
  clk <= not clk after 5 ns;

  system_i : entity work.ilo_system
    generic map (
      ROM_FILE => ROM_FILE,
      BLOCK_FILE => BLOCK_FILE,
      BLOCK_CELLS => BLOCK_CELLS,
      MEM_READ_WAIT_CYCLES => MEM_READ_WAIT_CYCLES,
      MEM_WRITE_WAIT_CYCLES => MEM_WRITE_WAIT_CYCLES,
      BLOCK_READ_WAIT_CYCLES => BLOCK_READ_WAIT_CYCLES,
      BLOCK_WRITE_WAIT_CYCLES => BLOCK_WRITE_WAIT_CYCLES,
      RESET_CYCLES => RESET_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk => clk,
      reset => reset,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data => serial_tx_data,
      serial_rx_req => serial_rx_req,
      serial_rx_valid => serial_rx_valid,
      serial_rx_data => serial_rx_data,
      halted => halted,
      errored => errored,
      error_code => error_code
    );

  process
  begin
    reset <= '1';
    wait for 50 ns;
    wait until rising_edge(clk);
    reset <= '0';
    wait;
  end process;

  process(clk)
    variable rx_index : natural := 1;
    variable rx_served : boolean := false;
  begin
    if rising_edge(clk) then
      serial_rx_valid <= '0';
      if reset = '1' then
        rx_index := 1;
        rx_served := false;
        serial_rx_data <= (others => '0');
      elsif serial_rx_req = '0' then
        rx_served := false;
      elsif not rx_served then
        if rx_index <= RX_TEXT'length then
          serial_rx_data <= std_logic_vector(to_unsigned(character'pos(RX_TEXT(rx_index)), 8));
          serial_rx_valid <= '1';
          rx_index := rx_index + 1;
          rx_served := true;
        end if;
      end if;
    end if;
  end process;

  process(clk)
    variable prev_valid : std_logic := '0';
    variable prev_data : std_logic_vector(7 downto 0) := (others => '0');
  begin
    if rising_edge(clk) then
      if reset = '1' then
        prev_valid := '0';
        prev_data := (others => '0');
      else
        if serial_rx_valid = '1' then
          assert not is_x(serial_rx_data)
            report "serial_rx_data is invalid while serial_rx_valid is asserted"
            severity failure;
          if prev_valid = '1' then
            assert serial_rx_data = prev_data
              report "serial_rx_data changed while serial_rx_valid remained asserted"
              severity failure;
          end if;
        end if;
        prev_valid := serial_rx_valid;
        prev_data := serial_rx_data;
      end if;
    end if;
  end process;

  process(clk)
    variable l : line;
  begin
    if rising_edge(clk) then
      if serial_tx_valid = '1' then
        write(l, string'("SERIAL_TX: "));
        write(l, to_integer(unsigned(serial_tx_data)));
        writeline(output, l);
      end if;
    end if;
  end process;

  process
    variable l : line;
  begin
    for cycle in 0 to MAX_CYCLES loop
      wait until rising_edge(clk);
      if halted = '1' then
        write(l, string'("FINAL_STACK:"));
        for i in DS_DEPTH downto 1 loop
          if i <= sim_debug.get_sp then
            write(l, string'(" "));
            write(l, to_integer(sim_debug.get_ds(i)));
          end if;
        end loop;
        writeline(output, l);
        assert false report "HALT" severity failure;
      elsif errored = '1' then
        write(l, string'("ERROR: "));
        write(l, to_integer(error_code));
        writeline(output, l);
        assert false report "ERROR" severity failure;
      end if;
    end loop;
    assert false report "TIMEOUT" severity failure;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/ilo_tb.vhd.
























































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

use work.ilo_pkg.all;

entity ilo_tb is
  generic (
    ROM_FILE   : string := "";
    BLOCK_FILE : string := "";
    BLOCK_CELLS : natural := 1024;
    MEM_READ_WAIT_CYCLES : natural := 0;
    MEM_WRITE_WAIT_CYCLES : natural := 0;
    BLOCK_READ_WAIT_CYCLES : natural := 0;
    BLOCK_WRITE_WAIT_CYCLES : natural := 0;
    POISON_UNINITIALIZED : boolean := false;
    MAX_CYCLES : natural := 1000000;
    TX_READY_DELAY_CYCLES : natural := 0;
    RX_TEXT    : string := ""
  );
end entity;

architecture sim of ilo_tb is
  signal clk        : std_logic := '0';
  signal reset      : std_logic := '1';
  signal mem_req    : std_logic;
  signal mem_we     : std_logic;
  signal mem_addr   : addr_t;
  signal mem_wdata  : cell_t;
  signal mem_rdata  : cell_t;
  signal mem_ready  : std_logic;
  signal serial_tx_valid : std_logic;
  signal serial_tx_data  : std_logic_vector(7 downto 0);
  signal serial_tx_ready : std_logic := '1';
  signal serial_rx_req   : std_logic;
  signal serial_rx_valid : std_logic := '0';
  signal serial_rx_data  : std_logic_vector(7 downto 0) := (others => '0');
  signal block_req   : std_logic;
  signal block_we    : std_logic;
  signal block_addr  : unsigned(31 downto 0);
  signal block_wdata : cell_t;
  signal block_rdata : cell_t;
  signal block_ready : std_logic;
  signal reload_req   : std_logic;
  signal reload_ready : std_logic;
  signal halted     : std_logic;
  signal errored    : std_logic;
  signal error_code : unsigned(7 downto 0);

begin
  clk <= not clk after 5 ns;

  mem_i : entity work.ilo_memory
    generic map (
      ROM_FILE => ROM_FILE,
      READ_WAIT_CYCLES => MEM_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => MEM_WRITE_WAIT_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk    => clk,
      req    => mem_req,
      we     => mem_we,
      addr   => mem_addr,
      wdata  => mem_wdata,
      rdata  => mem_rdata,
      ready  => mem_ready,
      reload_req => reload_req,
      reload_ready => reload_ready
    );

  block_i : entity work.ilo_block_store
    generic map (
      BLOCK_FILE => BLOCK_FILE,
      BLOCK_CELLS => BLOCK_CELLS,
      READ_WAIT_CYCLES => BLOCK_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => BLOCK_WRITE_WAIT_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk    => clk,
      req    => block_req,
      we     => block_we,
      addr   => block_addr,
      wdata  => block_wdata,
      rdata  => block_rdata,
      ready  => block_ready
    );

  core_i : entity work.ilo_core
    port map (
      clk        => clk,
      reset      => reset,
      mem_req    => mem_req,
      mem_we     => mem_we,
      mem_addr   => mem_addr,
      mem_wdata  => mem_wdata,
      mem_rdata  => mem_rdata,
      mem_ready  => mem_ready,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data  => serial_tx_data,
      serial_tx_ready => serial_tx_ready,
      serial_rx_req   => serial_rx_req,
      serial_rx_valid => serial_rx_valid,
      serial_rx_data  => serial_rx_data,
      block_req   => block_req,
      block_we    => block_we,
      block_addr  => block_addr,
      block_wdata => block_wdata,
      block_rdata => block_rdata,
      block_ready => block_ready,
      reload_req => reload_req,
      reload_ready => reload_ready,
      halted     => halted,
      errored    => errored,
      error_code => error_code
    );

  process
  begin
    reset <= '1';
    wait for 50 ns;
    wait until rising_edge(clk);
    reset <= '0';
    wait;
  end process;

  process(clk)
    variable cycles : natural := 0;
  begin
    if rising_edge(clk) then
      if reset = '1' then
        cycles := 0;
        if TX_READY_DELAY_CYCLES = 0 then
          serial_tx_ready <= '1';
        else
          serial_tx_ready <= '0';
        end if;
      elsif cycles >= TX_READY_DELAY_CYCLES then
        serial_tx_ready <= '1';
      else
        cycles := cycles + 1;
        serial_tx_ready <= '0';
      end if;
    end if;
  end process;

  process(clk)
    variable rx_index : natural := 1;
    variable rx_served : boolean := false;
  begin
    if rising_edge(clk) then
      serial_rx_valid <= '0';
      if reset = '1' then
        rx_index := 1;
        rx_served := false;
        serial_rx_data <= (others => '0');
      elsif serial_rx_req = '0' then
        rx_served := false;
      elsif not rx_served then
        if rx_index <= RX_TEXT'length then
          serial_rx_data <= std_logic_vector(to_unsigned(character'pos(RX_TEXT(rx_index)), 8));
          serial_rx_valid <= '1';
          rx_index := rx_index + 1;
          rx_served := true;
        end if;
      end if;
    end if;
  end process;

  process(clk)
    variable prev_valid : std_logic := '0';
    variable prev_data : std_logic_vector(7 downto 0) := (others => '0');
  begin
    if rising_edge(clk) then
      if reset = '1' then
        prev_valid := '0';
        prev_data := (others => '0');
      else
        if serial_rx_valid = '1' then
          assert not is_x(serial_rx_data)
            report "serial_rx_data is invalid while serial_rx_valid is asserted"
            severity failure;
          if prev_valid = '1' then
            assert serial_rx_data = prev_data
              report "serial_rx_data changed while serial_rx_valid remained asserted"
              severity failure;
          end if;
        end if;
        prev_valid := serial_rx_valid;
        prev_data := serial_rx_data;
      end if;
    end if;
  end process;

  process(clk)
    variable l : line;
  begin
    if rising_edge(clk) then
      assert not (serial_tx_valid = '1' and serial_tx_ready = '0')
        report "serial_tx_valid asserted while serial_tx_ready was low"
        severity failure;
      if serial_tx_valid = '1' then
        write(l, string'("SERIAL_TX: "));
        write(l, to_integer(unsigned(serial_tx_data)));
        writeline(output, l);
      end if;
    end if;
  end process;

  process
    variable l : line;
  begin
    for cycle in 0 to MAX_CYCLES loop
      wait until rising_edge(clk);
      if halted = '1' then
        write(l, string'("FINAL_STACK:"));
        for i in DS_DEPTH downto 1 loop
          if i <= sim_debug.get_sp then
            write(l, string'(" "));
            write(l, to_integer(sim_debug.get_ds(i)));
          end if;
        end loop;
        writeline(output, l);
        assert false report "HALT" severity failure;
      elsif errored = '1' then
        write(l, string'("ERROR: "));
        write(l, to_integer(error_code));
        writeline(output, l);
        assert false report "ERROR" severity failure;
      end if;
    end loop;
    assert false report "TIMEOUT" severity failure;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/ilo_terminal_tb.vhd.












































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

use work.ilo_pkg.all;

entity ilo_terminal_tb is
  generic (
    ROM_FILE   : string := "";
    BLOCK_FILE : string := "";
    BLOCK_CELLS : natural := 1024;
    MEM_READ_WAIT_CYCLES : natural := 0;
    MEM_WRITE_WAIT_CYCLES : natural := 0;
    BLOCK_READ_WAIT_CYCLES : natural := 0;
    BLOCK_WRITE_WAIT_CYCLES : natural := 0;
    POISON_UNINITIALIZED : boolean := false;
    RX_FIFO    : string := "ilo-vhdl/build/terminal.rx";
    TX_FIFO    : string := "ilo-vhdl/build/terminal.tx";
    MAX_CYCLES : natural := 0;
    CLOCK_PERIOD_NS : positive := 10
  );
end entity;

architecture sim of ilo_terminal_tb is
  constant CLK_HALF_PERIOD : time := (CLOCK_PERIOD_NS * 1 ns) / 2;
  signal clk        : std_logic := '0';
  signal reset      : std_logic := '1';
  signal mem_req    : std_logic;
  signal mem_we     : std_logic;
  signal mem_addr   : addr_t;
  signal mem_wdata  : cell_t;
  signal mem_rdata  : cell_t;
  signal mem_ready  : std_logic;
  signal serial_tx_valid : std_logic;
  signal serial_tx_data  : std_logic_vector(7 downto 0);
  signal serial_rx_req   : std_logic;
  signal serial_rx_valid : std_logic := '0';
  signal serial_rx_data  : std_logic_vector(7 downto 0) := (others => '0');
  signal block_req   : std_logic;
  signal block_we    : std_logic;
  signal block_addr  : unsigned(31 downto 0);
  signal block_wdata : cell_t;
  signal block_rdata : cell_t;
  signal block_ready : std_logic;
  signal reload_req   : std_logic;
  signal reload_ready : std_logic;
  signal halted     : std_logic;
  signal errored    : std_logic;
  signal error_code : unsigned(7 downto 0);

  file rx_file : text open read_mode is RX_FIFO;
  file tx_file : text open write_mode is TX_FIFO;
begin
  clk <= not clk after CLK_HALF_PERIOD;

  mem_i : entity work.ilo_memory
    generic map (
      ROM_FILE => ROM_FILE,
      READ_WAIT_CYCLES => MEM_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => MEM_WRITE_WAIT_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk    => clk,
      req    => mem_req,
      we     => mem_we,
      addr   => mem_addr,
      wdata  => mem_wdata,
      rdata  => mem_rdata,
      ready  => mem_ready,
      reload_req => reload_req,
      reload_ready => reload_ready
    );

  block_i : entity work.ilo_block_store
    generic map (
      BLOCK_FILE => BLOCK_FILE,
      BLOCK_CELLS => BLOCK_CELLS,
      READ_WAIT_CYCLES => BLOCK_READ_WAIT_CYCLES,
      WRITE_WAIT_CYCLES => BLOCK_WRITE_WAIT_CYCLES,
      POISON_UNINITIALIZED => POISON_UNINITIALIZED
    )
    port map (
      clk    => clk,
      req    => block_req,
      we     => block_we,
      addr   => block_addr,
      wdata  => block_wdata,
      rdata  => block_rdata,
      ready  => block_ready
    );

  core_i : entity work.ilo_core
    port map (
      clk        => clk,
      reset      => reset,
      mem_req    => mem_req,
      mem_we     => mem_we,
      mem_addr   => mem_addr,
      mem_wdata  => mem_wdata,
      mem_rdata  => mem_rdata,
      mem_ready  => mem_ready,
      serial_tx_valid => serial_tx_valid,
      serial_tx_data  => serial_tx_data,
      serial_tx_ready => '1',
      serial_rx_req   => serial_rx_req,
      serial_rx_valid => serial_rx_valid,
      serial_rx_data  => serial_rx_data,
      block_req   => block_req,
      block_we    => block_we,
      block_addr  => block_addr,
      block_wdata => block_wdata,
      block_rdata => block_rdata,
      block_ready => block_ready,
      reload_req => reload_req,
      reload_ready => reload_ready,
      halted     => halted,
      errored    => errored,
      error_code => error_code
    );

  process
  begin
    reset <= '1';
    wait for 50 ns;
    wait until rising_edge(clk);
    reset <= '0';
    wait;
  end process;

  process(clk)
    variable l : line;
    variable byte_value : integer;
    variable rx_served : boolean := false;
  begin
    if rising_edge(clk) then
      serial_rx_valid <= '0';
      if reset = '1' then
        rx_served := false;
        serial_rx_data <= (others => '0');
      elsif serial_rx_req = '0' then
        rx_served := false;
      elsif not rx_served then
        readline(rx_file, l);
        read(l, byte_value);
        if byte_value < 0 then
          byte_value := 0;
        elsif byte_value > 255 then
          byte_value := 255;
        end if;
        serial_rx_data <= std_logic_vector(to_unsigned(byte_value, 8));
        serial_rx_valid <= '1';
        rx_served := true;
      end if;
    end if;
  end process;

  process(clk)
    variable prev_valid : std_logic := '0';
    variable prev_data : std_logic_vector(7 downto 0) := (others => '0');
  begin
    if rising_edge(clk) then
      if reset = '1' then
        prev_valid := '0';
        prev_data := (others => '0');
      else
        if serial_rx_valid = '1' then
          assert not is_x(serial_rx_data)
            report "serial_rx_data is invalid while serial_rx_valid is asserted"
            severity failure;
          if prev_valid = '1' then
            assert serial_rx_data = prev_data
              report "serial_rx_data changed while serial_rx_valid remained asserted"
              severity failure;
          end if;
        end if;
        prev_valid := serial_rx_valid;
        prev_data := serial_rx_data;
      end if;
    end if;
  end process;

  process(clk)
    variable l : line;
  begin
    if rising_edge(clk) then
      if serial_tx_valid = '1' then
        write(l, to_integer(unsigned(serial_tx_data)));
        writeline(tx_file, l);
        flush(tx_file);
      end if;
    end if;
  end process;

  process
    variable l : line;
  begin
    if MAX_CYCLES = 0 then
      loop
        wait until rising_edge(clk);
        if halted = '1' then
          write(l, string'("HALT"));
          writeline(output, l);
          wait;
        elsif errored = '1' then
          write(l, string'("ERROR: "));
          write(l, to_integer(error_code));
          writeline(output, l);
          assert false report "ERROR" severity failure;
        end if;
      end loop;
    else
      for cycle in 0 to MAX_CYCLES loop
        wait until rising_edge(clk);
        if halted = '1' then
          write(l, string'("HALT"));
          writeline(output, l);
          wait;
        elsif errored = '1' then
          write(l, string'("ERROR: "));
          write(l, to_integer(error_code));
          writeline(output, l);
          assert false report "ERROR" severity failure;
        end if;
      end loop;
      assert false report "TIMEOUT" severity failure;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/sdram_model.vhd.
























































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

use work.ilo_pkg.all;

entity sdram_model is
  generic (
    MEM_FILE : string := "";
    HALFWORD_ADDR_WIDTH : natural := 17;
    CAS_LATENCY : natural := 2;
    TRCD_CYCLES : natural := 1;
    TRP_CYCLES : natural := 1;
    TRFC_CYCLES : natural := 4;
    TMRD_CYCLES : natural := 2;
    WRITE_RECOVERY_CYCLES : natural := 2;
    INIT_WAIT_CYCLES : natural := 0;
    MAX_REFRESH_INTERVAL_CYCLES : natural := 0
  );
  port (
    clk   : in std_logic;
    a     : in unsigned(12 downto 0);
    ba    : in unsigned(1 downto 0);
    dq    : inout std_logic_vector(15 downto 0);
    dqm   : in std_logic_vector(1 downto 0);
    csn   : in std_logic;
    cke   : in std_logic;
    wen   : in std_logic;
    casn  : in std_logic;
    rasn  : in std_logic
  );
end entity;

architecture sim of sdram_model is
  constant DEPTH : natural := 2 ** HALFWORD_ADDR_WIDTH;
  type ram_t is array (0 to DEPTH - 1) of std_logic_vector(15 downto 0);
  type bank_rows_t is array (0 to 3) of unsigned(12 downto 0);
  type bank_open_t is array (0 to 3) of boolean;
  type bank_timing_t is array (0 to 3) of natural;
  type init_state_t is (
    INIT_NEED_CKE,
    INIT_NEED_PRECHARGE_ALL,
    INIT_NEED_REFRESH_1,
    INIT_NEED_REFRESH_2,
    INIT_NEED_MODE,
    INIT_MODE_WAIT,
    INIT_DONE
  );

  signal dq_out : std_logic_vector(15 downto 0) := (others => '0');
  signal dq_drive : std_logic := '0';

  function mem_index(row : unsigned(12 downto 0); bank : unsigned(1 downto 0); col : unsigned(8 downto 0)) return natural is
    variable raw : unsigned(HALFWORD_ADDR_WIDTH - 1 downto 0) := (others => '0');
  begin
    raw(8 downto 0) := col;
    if HALFWORD_ADDR_WIDTH > 9 then
      raw(10 downto 9) := bank;
    end if;
    if HALFWORD_ADDR_WIDTH > 11 then
      raw(HALFWORD_ADDR_WIDTH - 1 downto 11) := row(HALFWORD_ADDR_WIDTH - 12 downto 0);
    end if;
    return to_integer(raw);
  end function;
begin
  dq <= dq_out when dq_drive = '1' else (others => 'Z');

  process(clk)
    file f : text;
    variable l : line;
    variable v : integer;
    variable ram : ram_t := (others => (others => '0'));
    variable active_row : bank_rows_t := (others => (others => '0'));
    variable bank_open : bank_open_t := (others => false);
    variable trcd_wait : bank_timing_t := (others => 0);
    variable trp_wait : bank_timing_t := (others => 0);
    variable write_recovery_wait : bank_timing_t := (others => 0);
    variable trfc_wait : natural := 0;
    variable tmrd_wait : natural := 0;
    variable cycles_since_refresh : natural := 0;
    variable have_refresh : boolean := false;
    variable memory_loaded : boolean := false;
    variable init_state : init_state_t := INIT_NEED_CKE;
    variable cke_high_cycles : natural := 0;
    variable word_index : natural;
    variable half_index : natural;
    variable raw : std_logic_vector(CELL_WIDTH - 1 downto 0);
    variable read_delay : natural := 0;
    variable read_pending : boolean := false;
    variable read_data : std_logic_vector(15 downto 0) := (others => '0');
    variable b : natural;
    variable idx : natural;
  begin
    if rising_edge(clk) then
      for bank in 0 to 3 loop
        if trcd_wait(bank) > 0 then
          trcd_wait(bank) := trcd_wait(bank) - 1;
        end if;
        if trp_wait(bank) > 0 then
          trp_wait(bank) := trp_wait(bank) - 1;
        end if;
        if write_recovery_wait(bank) > 0 then
          write_recovery_wait(bank) := write_recovery_wait(bank) - 1;
        end if;
      end loop;
      if trfc_wait > 0 then
        trfc_wait := trfc_wait - 1;
      end if;
      if tmrd_wait > 0 then
        tmrd_wait := tmrd_wait - 1;
      end if;
      if have_refresh and MAX_REFRESH_INTERVAL_CYCLES > 0 then
        cycles_since_refresh := cycles_since_refresh + 1;
        assert cycles_since_refresh <= MAX_REFRESH_INTERVAL_CYCLES
          report "sdram_model: maximum refresh interval exceeded"
          severity failure;
      end if;

      if not memory_loaded then
        if MEM_FILE /= "" then
          file_open(f, MEM_FILE, read_mode);
          word_index := 0;
          while not endfile(f) and (word_index * 2 + 1) < DEPTH loop
            readline(f, l);
            read(l, v);
            raw := std_logic_vector(to_signed(v, CELL_WIDTH));
            half_index := word_index * 2;
            ram(half_index) := raw(15 downto 0);
            ram(half_index + 1) := raw(31 downto 16);
            word_index := word_index + 1;
          end loop;
          file_close(f);
        end if;
        memory_loaded := true;
      end if;

      dq_drive <= '0';

      if read_pending then
        if read_delay = 0 then
          dq_out <= read_data;
          dq_drive <= '1';
          read_pending := false;
        else
          read_delay := read_delay - 1;
        end if;
      end if;

      if cke = '0' then
        cke_high_cycles := 0;
        init_state := INIT_NEED_CKE;
        have_refresh := false;
        cycles_since_refresh := 0;
        trfc_wait := 0;
        tmrd_wait := 0;
        trcd_wait := (others => 0);
        trp_wait := (others => 0);
        write_recovery_wait := (others => 0);
        bank_open := (others => false);
      else
        cke_high_cycles := cke_high_cycles + 1;
        if init_state = INIT_NEED_CKE and cke_high_cycles >= INIT_WAIT_CYCLES then
          init_state := INIT_NEED_PRECHARGE_ALL;
        end if;
      end if;
      if init_state = INIT_MODE_WAIT and tmrd_wait = 0 then
        init_state := INIT_DONE;
      end if;

      if cke = '1' and csn = '0' then
        b := to_integer(ba);
        if rasn = '0' and casn = '1' and wen = '1' then
          assert init_state = INIT_DONE
            report "sdram_model: ACTIVE before initialization complete"
            severity failure;
          assert trfc_wait = 0
            report "sdram_model: ACTIVE violates tRFC"
            severity failure;
          assert trp_wait(b) = 0
            report "sdram_model: ACTIVE violates tRP"
            severity failure;
          assert write_recovery_wait(b) = 0
            report "sdram_model: ACTIVE violates write recovery"
            severity failure;
          active_row(b) := a;
          bank_open(b) := true;
          trcd_wait(b) := TRCD_CYCLES;
        elsif rasn = '1' and casn = '0' and wen = '1' then
          assert init_state = INIT_DONE
            report "sdram_model: READ before initialization complete"
            severity failure;
          assert trfc_wait = 0
            report "sdram_model: READ violates tRFC"
            severity failure;
          assert bank_open(b)
            report "sdram_model: read from inactive bank"
            severity failure;
          assert trcd_wait(b) = 0
            report "sdram_model: READ violates tRCD"
            severity failure;
          assert not read_pending
            report "sdram_model: overlapping READ before CAS data"
            severity failure;
          idx := mem_index(active_row(b), ba, a(8 downto 0));
          read_data := ram(idx);
          read_delay := CAS_LATENCY;
          read_pending := true;
          if a(10) = '1' then
            bank_open(b) := false;
            trp_wait(b) := TRP_CYCLES;
          end if;
        elsif rasn = '1' and casn = '0' and wen = '0' then
          assert init_state = INIT_DONE
            report "sdram_model: WRITE before initialization complete"
            severity failure;
          assert trfc_wait = 0
            report "sdram_model: WRITE violates tRFC"
            severity failure;
          assert bank_open(b)
            report "sdram_model: write to inactive bank"
            severity failure;
          assert trcd_wait(b) = 0
            report "sdram_model: WRITE violates tRCD"
            severity failure;
          assert dqm = "00"
            report "sdram_model: byte-masked writes are not modeled"
            severity failure;
          assert not is_x(dq)
            report "sdram_model: invalid or undriven data during write"
            severity failure;
          idx := mem_index(active_row(b), ba, a(8 downto 0));
          ram(idx) := dq;
          write_recovery_wait(b) := WRITE_RECOVERY_CYCLES;
          if a(10) = '1' then
            bank_open(b) := false;
            trp_wait(b) := TRP_CYCLES;
          end if;
        elsif rasn = '0' and casn = '1' and wen = '0' then
          assert init_state = INIT_DONE or init_state = INIT_NEED_PRECHARGE_ALL
            report "sdram_model: PRECHARGE before expected init step"
            severity failure;
          assert trfc_wait = 0
            report "sdram_model: PRECHARGE violates tRFC"
            severity failure;
          if init_state = INIT_NEED_PRECHARGE_ALL then
            assert a(10) = '1'
              report "sdram_model: initialization requires PRECHARGE ALL"
              severity failure;
            init_state := INIT_NEED_REFRESH_1;
          end if;
          if a(10) = '1' then
            for bank in 0 to 3 loop
              assert write_recovery_wait(bank) = 0
                report "sdram_model: PRECHARGE ALL violates write recovery"
                severity failure;
            end loop;
            bank_open := (others => false);
            trp_wait := (others => TRP_CYCLES);
          else
            assert write_recovery_wait(b) = 0
              report "sdram_model: PRECHARGE violates write recovery"
              severity failure;
            bank_open(b) := false;
            trp_wait(b) := TRP_CYCLES;
          end if;
        elsif rasn = '0' and casn = '0' and wen = '1' then
          assert init_state = INIT_DONE or init_state = INIT_NEED_REFRESH_1 or init_state = INIT_NEED_REFRESH_2
            report "sdram_model: REFRESH before expected init step"
            severity failure;
          assert trfc_wait = 0
            report "sdram_model: REFRESH violates tRFC"
            severity failure;
          if init_state = INIT_NEED_REFRESH_1 then
            init_state := INIT_NEED_REFRESH_2;
          elsif init_state = INIT_NEED_REFRESH_2 then
            init_state := INIT_NEED_MODE;
          end if;
          trfc_wait := TRFC_CYCLES;
          cycles_since_refresh := 0;
          have_refresh := true;
        elsif rasn = '0' and casn = '0' and wen = '0' then
          assert init_state = INIT_DONE or init_state = INIT_NEED_MODE
            report "sdram_model: MODE REGISTER SET before expected init step"
            severity failure;
          assert trfc_wait = 0
            report "sdram_model: MODE REGISTER SET violates tRFC"
            severity failure;
          assert to_integer(unsigned(a(6 downto 4))) = CAS_LATENCY
            report "sdram_model: mode register CAS latency does not match model CAS_LATENCY"
            severity failure;
          if init_state = INIT_NEED_MODE then
            init_state := INIT_MODE_WAIT;
            tmrd_wait := TMRD_CYCLES;
          end if;
        end if;
      end if;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/sdram_model_timing_tb.vhd.
























































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.env.all;

entity sdram_model_timing_tb is
  generic (
    VIOLATION : string := "TRCD"
  );
end entity;

architecture sim of sdram_model_timing_tb is
  function timing_for(
    constant selector : string;
    constant target : string;
    constant enabled_value : natural;
    constant disabled_value : natural
  ) return natural is
  begin
    if selector = target then
      return enabled_value;
    end if;
    return disabled_value;
  end function;

  signal clk  : std_logic := '0';
  signal a    : unsigned(12 downto 0) := (others => '0');
  signal ba   : unsigned(1 downto 0) := (others => '0');
  signal dq   : std_logic_vector(15 downto 0);
  signal dqm  : std_logic_vector(1 downto 0) := "00";
  signal csn  : std_logic := '1';
  signal cke  : std_logic := '1';
  signal wen  : std_logic := '1';
  signal casn : std_logic := '1';
  signal rasn : std_logic := '1';

  signal dq_out : std_logic_vector(15 downto 0) := x"1234";
  signal dq_drive : std_logic := '0';

  procedure nop(
    signal csn_s : out std_logic;
    signal rasn_s : out std_logic;
    signal casn_s : out std_logic;
    signal wen_s : out std_logic
  ) is
  begin
    csn_s <= '0';
    rasn_s <= '1';
    casn_s <= '1';
    wen_s <= '1';
  end procedure;

  procedure issue(
    signal csn_s : out std_logic;
    signal rasn_s : out std_logic;
    signal casn_s : out std_logic;
    signal wen_s : out std_logic;
    constant ras_v : std_logic;
    constant cas_v : std_logic;
    constant we_v : std_logic
  ) is
  begin
    csn_s <= '0';
    rasn_s <= ras_v;
    casn_s <= cas_v;
    wen_s <= we_v;
    wait until rising_edge(clk);
    nop(csn_s, rasn_s, casn_s, wen_s);
    wait for 1 ns;
  end procedure;

  procedure wait_cycles(constant cycles : natural) is
  begin
    for i in 1 to cycles loop
      wait until rising_edge(clk);
    end loop;
    wait for 1 ns;
  end procedure;

  procedure initialize_sdram(
    signal a_s : out unsigned(12 downto 0);
    signal csn_s : out std_logic;
    signal rasn_s : out std_logic;
    signal casn_s : out std_logic;
    signal wen_s : out std_logic;
    constant cas_bits : unsigned(2 downto 0)
  ) is
  begin
    a_s <= (others => '0');
    a_s(10) <= '1';
    issue(csn_s, rasn_s, casn_s, wen_s, '0', '1', '0'); -- PRECHARGE ALL
    wait_cycles(4);
    issue(csn_s, rasn_s, casn_s, wen_s, '0', '0', '1'); -- REFRESH 1
    wait_cycles(4);
    issue(csn_s, rasn_s, casn_s, wen_s, '0', '0', '1'); -- REFRESH 2
    wait_cycles(4);
    a_s <= (others => '0');
    a_s(6 downto 4) <= cas_bits;
    issue(csn_s, rasn_s, casn_s, wen_s, '0', '0', '0'); -- MODE
    wait_cycles(2);
  end procedure;
begin
  clk <= not clk after 5 ns;
  dq <= dq_out when dq_drive = '1' else (others => 'Z');

  sdram_i : entity work.sdram_model
    generic map (
      CAS_LATENCY => 2,
      TRCD_CYCLES => timing_for(VIOLATION, "TRCD", 3, 0),
      TRP_CYCLES => timing_for(VIOLATION, "TRP", 3, 0),
      TRFC_CYCLES => timing_for(VIOLATION, "TRFC", 3, 0),
      WRITE_RECOVERY_CYCLES => timing_for(VIOLATION, "WRITE_RECOVERY", 3, 0),
      MAX_REFRESH_INTERVAL_CYCLES => timing_for(VIOLATION, "REFRESH_INTERVAL", 2, 0)
    )
    port map (
      clk => clk,
      a => a,
      ba => ba,
      dq => dq,
      dqm => dqm,
      csn => csn,
      cke => cke,
      wen => wen,
      casn => casn,
      rasn => rasn
    );

  process
  begin
    nop(csn, rasn, casn, wen);
    wait until rising_edge(clk);
    wait for 1 ns;

    if VIOLATION = "INIT_READ" then
      a <= (others => '0');
      issue(csn, rasn, casn, wen, '1', '0', '1'); -- READ before init
    elsif VIOLATION = "INIT_WRITE" then
      a <= (others => '0');
      dq_drive <= '1';
      issue(csn, rasn, casn, wen, '1', '0', '0'); -- WRITE before init
    elsif VIOLATION = "INIT_PRECHARGE_BANK" then
      a <= (others => '0');
      issue(csn, rasn, casn, wen, '0', '1', '0'); -- PRECHARGE bank during init
    elsif VIOLATION = "INIT_REFRESH_EARLY" then
      issue(csn, rasn, casn, wen, '0', '0', '1'); -- REFRESH before PRECHARGE ALL
    elsif VIOLATION = "INIT_MODE_EARLY" then
      a <= (others => '0');
      a(6 downto 4) <= "010";
      issue(csn, rasn, casn, wen, '0', '0', '0'); -- MODE before refreshes
    elsif VIOLATION = "CAS" then
      initialize_sdram(a, csn, rasn, casn, wen, "011");
    else
      initialize_sdram(a, csn, rasn, casn, wen, "010");
    end if;

    if VIOLATION = "INIT_READ" or VIOLATION = "INIT_WRITE" or
       VIOLATION = "INIT_PRECHARGE_BANK" or VIOLATION = "INIT_REFRESH_EARLY" or
       VIOLATION = "INIT_MODE_EARLY" then
      null;
    elsif VIOLATION = "TRCD" then
      a <= (others => '0');
      issue(csn, rasn, casn, wen, '0', '1', '1'); -- ACTIVE
      a <= (others => '0');
      issue(csn, rasn, casn, wen, '1', '0', '1'); -- READ too soon
    elsif VIOLATION = "TRP" then
      a <= (others => '0');
      a(10) <= '1';
      issue(csn, rasn, casn, wen, '0', '1', '0'); -- PRECHARGE ALL
      a <= (others => '0');
      issue(csn, rasn, casn, wen, '0', '1', '1'); -- ACTIVE too soon
    elsif VIOLATION = "TRFC" then
      issue(csn, rasn, casn, wen, '0', '0', '1'); -- REFRESH
      a <= (others => '0');
      issue(csn, rasn, casn, wen, '0', '1', '1'); -- ACTIVE too soon
    elsif VIOLATION = "CAS" then
      null;
    elsif VIOLATION = "WRITE_RECOVERY" then
      a <= (others => '0');
      issue(csn, rasn, casn, wen, '0', '1', '1'); -- ACTIVE
      wait until rising_edge(clk);
      wait until rising_edge(clk);
      wait until rising_edge(clk);
      wait for 1 ns;
      a <= (others => '0');
      a(10) <= '1';
      dq_drive <= '1';
      issue(csn, rasn, casn, wen, '1', '0', '0'); -- WRITE with auto-precharge
      dq_drive <= '0';
      a <= (others => '0');
      issue(csn, rasn, casn, wen, '0', '1', '1'); -- ACTIVE before recovery
    elsif VIOLATION = "REFRESH_INTERVAL" then
      issue(csn, rasn, casn, wen, '0', '0', '1'); -- REFRESH
      wait until rising_edge(clk);
      wait until rising_edge(clk);
      wait until rising_edge(clk);
      wait until rising_edge(clk);
    else
      assert false report "unknown SDRAM timing violation selector" severity failure;
    end if;

    assert false report "SDRAM timing violation did not fail" severity failure;
    stop;
  end process;
end architecture;
Added ilo-vm/vhdl/sim/sram8_model.vhd.








































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.textio.all;

use work.ilo_pkg.all;

entity sram8_model is
  generic (
    MEM_FILE : string := "";
    ADDR_WIDTH : natural := 19;
    OUTPUT_DELAY_NS : natural := 1;
    POISON_UNINITIALIZED : boolean := false
  );
  port (
    addr : in unsigned(ADDR_WIDTH - 1 downto 0);
    data : inout std_logic_vector(7 downto 0);
    ce_n : in std_logic;
    oe_n : in std_logic;
    we_n : in std_logic
  );
end entity;

architecture sim of sram8_model is
  constant BYTE_DEPTH : natural := 2 ** ADDR_WIDTH;
  type byte_array_t is array (0 to BYTE_DEPTH - 1) of std_logic_vector(7 downto 0);
  type byte_valid_array_t is array (0 to BYTE_DEPTH - 1) of boolean;
  signal data_out : std_logic_vector(7 downto 0) := (others => '0');
begin
  data <= data_out after OUTPUT_DELAY_NS * 1 ns
          when ce_n = '0' and oe_n = '0' and we_n = '1' else
          (others => 'Z') after OUTPUT_DELAY_NS * 1 ns;

  process(addr, data, ce_n, oe_n, we_n)
    file f : text;
    variable l : line;
    variable v : integer;
    variable word_index : natural;
    variable byte_index : natural;
    variable raw : std_logic_vector(CELL_WIDTH - 1 downto 0);
    variable ram : byte_array_t := (others => (others => '0'));
    variable valid : byte_valid_array_t := (others => false);
    variable initialized : boolean := false;
    variable a : natural;
  begin
    if not initialized then
      if MEM_FILE /= "" then
        file_open(f, MEM_FILE, read_mode);
        word_index := 0;
        while not endfile(f) and (word_index * 4 + 3) < BYTE_DEPTH loop
          readline(f, l);
          read(l, v);
          raw := std_logic_vector(to_signed(v, CELL_WIDTH));
          byte_index := word_index * 4;
          ram(byte_index) := raw(7 downto 0);
          ram(byte_index + 1) := raw(15 downto 8);
          ram(byte_index + 2) := raw(23 downto 16);
          ram(byte_index + 3) := raw(31 downto 24);
          valid(byte_index) := true;
          valid(byte_index + 1) := true;
          valid(byte_index + 2) := true;
          valid(byte_index + 3) := true;
          word_index := word_index + 1;
        end loop;
        file_close(f);
      end if;
      initialized := true;
    end if;

    if is_x(std_logic_vector(addr)) then
      data_out <= (others => 'X');
    else
      a := to_integer(addr);
      if ce_n = '0' then
        assert not (oe_n = '0' and we_n = '0')
          report "sram8_model: OE and WE active at the same time"
          severity failure;
      end if;

      if ce_n = '0' and we_n = '0' then
        assert not is_x(data)
          report "sram8_model: invalid or undriven data during write"
          severity failure;
        ram(a) := data;
        valid(a) := true;
      end if;

      if POISON_UNINITIALIZED and not valid(a) then
        case a mod 4 is
          when 0 => data_out <= x"EF";
          when 1 => data_out <= x"BE";
          when 2 => data_out <= x"AD";
          when others => data_out <= x"DE";
        end case;
      else
        data_out <= ram(a);
      end if;
    end if;
  end process;
end architecture;
Added ilo-vm/vhdl/testdata/block-read.blocks.mem.


>
1
123
Added ilo-vm/vhdl/testdata/test-board-boot-preloaded.pali.










































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
c Larger board-level SDRAM boot image for simulation preload.
c Stores bytes in SDRAM-backed VM memory, fetches them, emits "BOOT", then halts.
~~~
: entry
i liju....
r main

: main
i lilist..
d 66
d 4096
i lilist..
d 79
d 4097
i lilist..
d 79
d 4098
i lilist..
d 84
d 4099

i lifeliio
d 4096
d 0
i lifeliio
d 4097
d 0
i lifeliio
d 4098
d 0
i lifeliio
d 4099
d 0

i liio....
d 6
~~~
Added ilo-vm/vhdl/testdata/test-io-block-read.pali.






















>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
c Test io 2 block read
c Reads block 0 to address 1000 and fetches the first cell.
~~~
i lililiio
d 0
d 1000
d 2
i lifeliio
d 1000
d 6
~~~
Added ilo-vm/vhdl/testdata/test-io-block-write.pali.


































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
c Test io 3 block write by writing block 0, reading it back, and fetching cell 0.
~~~
i lilist..
d 77
d 1000
i lililiio
d 0
d 1000
d 3
i lililiio
d 0
d 2000
d 2
i lifeliio
d 2000
d 6
~~~
Added ilo-vm/vhdl/testdata/test-io-emit.pali.


















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
c Test serial-style io 0 output
c Emits ASCII 65 ('A') and halts with an empty stack.
~~~
i liliio..
d 65
d 0
i liio....
d 6
~~~
Added ilo-vm/vhdl/testdata/test-io-read.pali.
















>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
c Test serial-style io 1 input
c Reads one byte from RX_TEXT and leaves it on the stack.
~~~
i liio....
d 1
i liio....
d 6
~~~
Added ilo-vm/vhdl/testdata/test-io-reload.pali.




































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
c Test I/O device 5 (reload image)
c The first run changes memory at main/main_device so a non-reloaded restart
c would halt. A correct reload restores the original image and reloads again.
~~~
: entry
i liju....
r main

: main
i lilistli
: main_device
d 7425
r main
d 6
i listliio
r main_device
d 5
~~~
Added ilo-vm/vhdl/testdata/test-sdram-address-boundaries.pali.






































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
c Exercise SDRAM-backed VM stores/fetches across controller address boundaries.
c Expected final stack: 501 402 401 302 301 202 201 102 101
~~~
: entry
i liju....
r main

: main
c adjacent cells
i lilist..
d 101
d 2048
i lilist..
d 102
d 2049

c column/bank transition at a 256-cell boundary
i lilist..
d 201
d 2303
i lilist..
d 202
d 2304

c another bank transition in the same row
i lilist..
d 301
d 2559
i lilist..
d 302
d 2560

c row transition at a 1024-cell boundary
i lilist..
d 401
d 3071
i lilist..
d 402
d 3072

c high modeled SDRAM address
i lilist..
d 501
d 60000

c fetch back in write order; final stack is reported top-first
i life....
d 2048
i life....
d 2049
i life....
d 2303
i life....
d 2304
i life....
d 2559
i life....
d 2560
i life....
d 3071
i life....
d 3072
i life....
d 60000
i liio....
d 6
~~~
Added ilo-vm/vhdl/testdata/test-uninitialized-read.pali.












>
>
>
>
>
>
1
2
3
4
5
6
c Fetch an unloaded memory cell to verify strict simulation poison mode.
~~~
i lifeliio
d 60000
d 6
~~~
Added ilo-vm/vhdl/testdata/test-uninitialized-read.partial.mem.






>
>
>
1
2
3
486608897
60000
6