├── .gitignore
├── .idea
├── .gitignore
├── arduino_8088.iml
├── modules.xml
└── vcs.xml
├── Cargo.lock
├── Cargo.toml
├── LICENSE
├── README.md
├── asm
├── i8080.inc
├── kefrensloop.asm
├── program.asm
├── program.lst
├── program_8080.asm
├── program_8080_regs.asm
├── program_regs.asm
└── testcyc.asm
├── crates
├── ard808x_client
│ ├── Cargo.toml
│ ├── LICENSE
│ ├── README.md
│ └── src
│ │ └── lib.rs
├── ard808x_cpu
│ ├── Cargo.toml
│ ├── LICENSE
│ ├── README.md
│ ├── examples
│ │ └── cpu_id.rs
│ ├── src
│ │ ├── code_stream.rs
│ │ ├── lib.rs
│ │ ├── opcodes.rs
│ │ ├── queue.rs
│ │ └── remote_program.rs
│ └── tests
│ │ ├── aaa.rs
│ │ ├── aas.rs
│ │ ├── daa.rs
│ │ ├── das.rs
│ │ └── flags.rs
└── exec_program
│ ├── Cargo.toml
│ ├── LICENSE
│ └── src
│ └── main.rs
├── images
├── arduino8088_breadboard.jpg
├── arduino8088_pcb.jpg
├── pcb_shield50.PNG
├── pcb_v1_1.png
└── render_v1_1.png
├── pcb
├── asm
│ ├── load.asm
│ ├── pop_cs.asm
│ ├── store.asm
│ └── store.lst
└── kicad
│ ├── Arduino.pretty
│ └── Arduino_Mega2560_Shield.kicad_mod
│ ├── MCU_Intel.dcm
│ ├── MCU_Intel.lib
│ ├── ard8088.kicad_pcb
│ ├── ard8088.kicad_prl
│ ├── ard8088.kicad_pro
│ ├── ard8088.kicad_sch
│ ├── arduino.kicad_sym
│ ├── cow.pretty
│ └── cow.kicad_mod
│ ├── logo.kicad_sym
│ └── sym-lib-table
├── scripts
├── build.bat
└── build2.bat
└── sketches
├── cpu_server
├── arduino8088.h
├── cpu_server.h
├── cpu_server.ino
├── gpio_pins.h
├── lib.ino
└── opcodes.h
└── run_program
├── arduino8088.h
├── lib.ino
├── opcodes.h
└── run_program.ino
/.gitignore:
--------------------------------------------------------------------------------
1 | # General
2 | /notes/
3 | /traces/
4 | /asm/*.bin
5 | /sketches/convert_me/
6 | /sketches/cpu_server_old/
7 | /sketches/due_test/
8 |
9 | # Arduino stuff
10 |
11 | # Ignore IDE folder
12 | .theia
13 | # Ignore compiled programs
14 | *.bin
15 |
16 | # Kicad stuff
17 | fp-info-cache
18 | fp-lib-table
19 | Arduino_101_Shield.kicad_mod
20 | Arduino_Due_Shield.kicad_mod
21 | Arduino_Leonardo_Shield.kicad_mod
22 | Arduino_Micro_Socket.kicad_mod
23 | Arduino_Mini_Socket.kicad_mod
24 | Arduino_Nano_Socket.kicad_mod
25 | Arduino_Pro_Mini_Socket.kicad_mod
26 | Arduino_Uno_Shield.kicad_mod
27 | Arduino_Zero_Shield.kicad_mod
28 | Pro_Mini_Clone_Socket.kicad_mod
29 | pcb/kicad/ard8088-backups/
30 | pcb/kicad/gerbers*
31 | pcb/kicad/ard8088.wrl
32 | \#auto_saved_files#
33 | _autosave*
34 | gerbers/
35 | kicad/ard8088.wrl
36 |
37 | # Rust stuff
38 |
39 | # Rust example client
40 | client/rust/target/
41 | client/rust/scripts/build2.bat
42 | client/rust/asm/*.asm
43 | !client/rust/asm/program.asm
44 | !client/rust/asm/program_regs.asm
45 |
46 |
47 | # list files
48 | asm/*.lst
49 |
50 |
51 | # Generated by Cargo
52 | # will have compiled files and executables
53 | /target/
54 |
55 | # These are backup files generated by rustfmt
56 | **/*.rs.bk
57 |
58 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/arduino_8088.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 4
4 |
5 | [[package]]
6 | name = "aho-corasick"
7 | version = "1.1.3"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
10 | dependencies = [
11 | "memchr",
12 | ]
13 |
14 | [[package]]
15 | name = "anstream"
16 | version = "0.6.13"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
19 | dependencies = [
20 | "anstyle",
21 | "anstyle-parse",
22 | "anstyle-query",
23 | "anstyle-wincon",
24 | "colorchoice",
25 | "utf8parse",
26 | ]
27 |
28 | [[package]]
29 | name = "anstyle"
30 | version = "1.0.6"
31 | source = "registry+https://github.com/rust-lang/crates.io-index"
32 | checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
33 |
34 | [[package]]
35 | name = "anstyle-parse"
36 | version = "0.2.3"
37 | source = "registry+https://github.com/rust-lang/crates.io-index"
38 | checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
39 | dependencies = [
40 | "utf8parse",
41 | ]
42 |
43 | [[package]]
44 | name = "anstyle-query"
45 | version = "1.0.2"
46 | source = "registry+https://github.com/rust-lang/crates.io-index"
47 | checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
48 | dependencies = [
49 | "windows-sys",
50 | ]
51 |
52 | [[package]]
53 | name = "anstyle-wincon"
54 | version = "3.0.2"
55 | source = "registry+https://github.com/rust-lang/crates.io-index"
56 | checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
57 | dependencies = [
58 | "anstyle",
59 | "windows-sys",
60 | ]
61 |
62 | [[package]]
63 | name = "ard808x_client"
64 | version = "0.3.0"
65 | dependencies = [
66 | "log",
67 | "serialport",
68 | ]
69 |
70 | [[package]]
71 | name = "ard808x_cpu"
72 | version = "0.3.0"
73 | dependencies = [
74 | "ard808x_client",
75 | "env_logger",
76 | "log",
77 | ]
78 |
79 | [[package]]
80 | name = "bitflags"
81 | version = "1.3.2"
82 | source = "registry+https://github.com/rust-lang/crates.io-index"
83 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
84 |
85 | [[package]]
86 | name = "bitflags"
87 | version = "2.5.0"
88 | source = "registry+https://github.com/rust-lang/crates.io-index"
89 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
90 |
91 | [[package]]
92 | name = "cfg-if"
93 | version = "1.0.0"
94 | source = "registry+https://github.com/rust-lang/crates.io-index"
95 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
96 |
97 | [[package]]
98 | name = "clap"
99 | version = "4.5.13"
100 | source = "registry+https://github.com/rust-lang/crates.io-index"
101 | checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc"
102 | dependencies = [
103 | "clap_builder",
104 | "clap_derive",
105 | ]
106 |
107 | [[package]]
108 | name = "clap_builder"
109 | version = "4.5.13"
110 | source = "registry+https://github.com/rust-lang/crates.io-index"
111 | checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99"
112 | dependencies = [
113 | "anstream",
114 | "anstyle",
115 | "clap_lex",
116 | "strsim",
117 | ]
118 |
119 | [[package]]
120 | name = "clap_derive"
121 | version = "4.5.13"
122 | source = "registry+https://github.com/rust-lang/crates.io-index"
123 | checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
124 | dependencies = [
125 | "heck",
126 | "proc-macro2",
127 | "quote",
128 | "syn",
129 | ]
130 |
131 | [[package]]
132 | name = "clap_lex"
133 | version = "0.7.4"
134 | source = "registry+https://github.com/rust-lang/crates.io-index"
135 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
136 |
137 | [[package]]
138 | name = "colorchoice"
139 | version = "1.0.0"
140 | source = "registry+https://github.com/rust-lang/crates.io-index"
141 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
142 |
143 | [[package]]
144 | name = "core-foundation-sys"
145 | version = "0.8.6"
146 | source = "registry+https://github.com/rust-lang/crates.io-index"
147 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
148 |
149 | [[package]]
150 | name = "env_filter"
151 | version = "0.1.3"
152 | source = "registry+https://github.com/rust-lang/crates.io-index"
153 | checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
154 | dependencies = [
155 | "log",
156 | "regex",
157 | ]
158 |
159 | [[package]]
160 | name = "env_logger"
161 | version = "0.11.8"
162 | source = "registry+https://github.com/rust-lang/crates.io-index"
163 | checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
164 | dependencies = [
165 | "anstream",
166 | "anstyle",
167 | "env_filter",
168 | "jiff",
169 | "log",
170 | ]
171 |
172 | [[package]]
173 | name = "exec_program"
174 | version = "0.3.0"
175 | dependencies = [
176 | "ard808x_cpu",
177 | "clap",
178 | "env_logger",
179 | "log",
180 | ]
181 |
182 | [[package]]
183 | name = "heck"
184 | version = "0.5.0"
185 | source = "registry+https://github.com/rust-lang/crates.io-index"
186 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
187 |
188 | [[package]]
189 | name = "io-kit-sys"
190 | version = "0.4.1"
191 | source = "registry+https://github.com/rust-lang/crates.io-index"
192 | checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b"
193 | dependencies = [
194 | "core-foundation-sys",
195 | "mach2",
196 | ]
197 |
198 | [[package]]
199 | name = "jiff"
200 | version = "0.2.14"
201 | source = "registry+https://github.com/rust-lang/crates.io-index"
202 | checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
203 | dependencies = [
204 | "jiff-static",
205 | "log",
206 | "portable-atomic",
207 | "portable-atomic-util",
208 | "serde",
209 | ]
210 |
211 | [[package]]
212 | name = "jiff-static"
213 | version = "0.2.14"
214 | source = "registry+https://github.com/rust-lang/crates.io-index"
215 | checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
216 | dependencies = [
217 | "proc-macro2",
218 | "quote",
219 | "syn",
220 | ]
221 |
222 | [[package]]
223 | name = "libc"
224 | version = "0.2.153"
225 | source = "registry+https://github.com/rust-lang/crates.io-index"
226 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
227 |
228 | [[package]]
229 | name = "libudev"
230 | version = "0.3.0"
231 | source = "registry+https://github.com/rust-lang/crates.io-index"
232 | checksum = "78b324152da65df7bb95acfcaab55e3097ceaab02fb19b228a9eb74d55f135e0"
233 | dependencies = [
234 | "libc",
235 | "libudev-sys",
236 | ]
237 |
238 | [[package]]
239 | name = "libudev-sys"
240 | version = "0.1.4"
241 | source = "registry+https://github.com/rust-lang/crates.io-index"
242 | checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
243 | dependencies = [
244 | "libc",
245 | "pkg-config",
246 | ]
247 |
248 | [[package]]
249 | name = "log"
250 | version = "0.4.21"
251 | source = "registry+https://github.com/rust-lang/crates.io-index"
252 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
253 |
254 | [[package]]
255 | name = "mach2"
256 | version = "0.4.2"
257 | source = "registry+https://github.com/rust-lang/crates.io-index"
258 | checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709"
259 | dependencies = [
260 | "libc",
261 | ]
262 |
263 | [[package]]
264 | name = "memchr"
265 | version = "2.7.2"
266 | source = "registry+https://github.com/rust-lang/crates.io-index"
267 | checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
268 |
269 | [[package]]
270 | name = "nix"
271 | version = "0.26.4"
272 | source = "registry+https://github.com/rust-lang/crates.io-index"
273 | checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
274 | dependencies = [
275 | "bitflags 1.3.2",
276 | "cfg-if",
277 | "libc",
278 | ]
279 |
280 | [[package]]
281 | name = "pkg-config"
282 | version = "0.3.30"
283 | source = "registry+https://github.com/rust-lang/crates.io-index"
284 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
285 |
286 | [[package]]
287 | name = "portable-atomic"
288 | version = "1.11.0"
289 | source = "registry+https://github.com/rust-lang/crates.io-index"
290 | checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
291 |
292 | [[package]]
293 | name = "portable-atomic-util"
294 | version = "0.2.4"
295 | source = "registry+https://github.com/rust-lang/crates.io-index"
296 | checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
297 | dependencies = [
298 | "portable-atomic",
299 | ]
300 |
301 | [[package]]
302 | name = "proc-macro2"
303 | version = "1.0.95"
304 | source = "registry+https://github.com/rust-lang/crates.io-index"
305 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
306 | dependencies = [
307 | "unicode-ident",
308 | ]
309 |
310 | [[package]]
311 | name = "quote"
312 | version = "1.0.40"
313 | source = "registry+https://github.com/rust-lang/crates.io-index"
314 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
315 | dependencies = [
316 | "proc-macro2",
317 | ]
318 |
319 | [[package]]
320 | name = "regex"
321 | version = "1.10.4"
322 | source = "registry+https://github.com/rust-lang/crates.io-index"
323 | checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
324 | dependencies = [
325 | "aho-corasick",
326 | "memchr",
327 | "regex-automata",
328 | "regex-syntax",
329 | ]
330 |
331 | [[package]]
332 | name = "regex-automata"
333 | version = "0.4.6"
334 | source = "registry+https://github.com/rust-lang/crates.io-index"
335 | checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
336 | dependencies = [
337 | "aho-corasick",
338 | "memchr",
339 | "regex-syntax",
340 | ]
341 |
342 | [[package]]
343 | name = "regex-syntax"
344 | version = "0.8.3"
345 | source = "registry+https://github.com/rust-lang/crates.io-index"
346 | checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
347 |
348 | [[package]]
349 | name = "scopeguard"
350 | version = "1.2.0"
351 | source = "registry+https://github.com/rust-lang/crates.io-index"
352 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
353 |
354 | [[package]]
355 | name = "serde"
356 | version = "1.0.219"
357 | source = "registry+https://github.com/rust-lang/crates.io-index"
358 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
359 | dependencies = [
360 | "serde_derive",
361 | ]
362 |
363 | [[package]]
364 | name = "serde_derive"
365 | version = "1.0.219"
366 | source = "registry+https://github.com/rust-lang/crates.io-index"
367 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
368 | dependencies = [
369 | "proc-macro2",
370 | "quote",
371 | "syn",
372 | ]
373 |
374 | [[package]]
375 | name = "serialport"
376 | version = "4.3.1-alpha.0"
377 | source = "git+https://github.com/dbalsom/serialport-rs?branch=arduino-fix#fd42cd35dca389ce97e6538933e270c25c151a42"
378 | dependencies = [
379 | "bitflags 2.5.0",
380 | "cfg-if",
381 | "core-foundation-sys",
382 | "io-kit-sys",
383 | "libudev",
384 | "mach2",
385 | "nix",
386 | "regex",
387 | "scopeguard",
388 | "unescaper",
389 | "winapi",
390 | ]
391 |
392 | [[package]]
393 | name = "strsim"
394 | version = "0.11.1"
395 | source = "registry+https://github.com/rust-lang/crates.io-index"
396 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
397 |
398 | [[package]]
399 | name = "syn"
400 | version = "2.0.101"
401 | source = "registry+https://github.com/rust-lang/crates.io-index"
402 | checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
403 | dependencies = [
404 | "proc-macro2",
405 | "quote",
406 | "unicode-ident",
407 | ]
408 |
409 | [[package]]
410 | name = "thiserror"
411 | version = "1.0.59"
412 | source = "registry+https://github.com/rust-lang/crates.io-index"
413 | checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
414 | dependencies = [
415 | "thiserror-impl",
416 | ]
417 |
418 | [[package]]
419 | name = "thiserror-impl"
420 | version = "1.0.59"
421 | source = "registry+https://github.com/rust-lang/crates.io-index"
422 | checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
423 | dependencies = [
424 | "proc-macro2",
425 | "quote",
426 | "syn",
427 | ]
428 |
429 | [[package]]
430 | name = "unescaper"
431 | version = "0.1.4"
432 | source = "registry+https://github.com/rust-lang/crates.io-index"
433 | checksum = "0adf6ad32eb5b3cadff915f7b770faaac8f7ff0476633aa29eb0d9584d889d34"
434 | dependencies = [
435 | "thiserror",
436 | ]
437 |
438 | [[package]]
439 | name = "unicode-ident"
440 | version = "1.0.12"
441 | source = "registry+https://github.com/rust-lang/crates.io-index"
442 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
443 |
444 | [[package]]
445 | name = "utf8parse"
446 | version = "0.2.1"
447 | source = "registry+https://github.com/rust-lang/crates.io-index"
448 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
449 |
450 | [[package]]
451 | name = "winapi"
452 | version = "0.3.9"
453 | source = "registry+https://github.com/rust-lang/crates.io-index"
454 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
455 | dependencies = [
456 | "winapi-i686-pc-windows-gnu",
457 | "winapi-x86_64-pc-windows-gnu",
458 | ]
459 |
460 | [[package]]
461 | name = "winapi-i686-pc-windows-gnu"
462 | version = "0.4.0"
463 | source = "registry+https://github.com/rust-lang/crates.io-index"
464 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
465 |
466 | [[package]]
467 | name = "winapi-x86_64-pc-windows-gnu"
468 | version = "0.4.0"
469 | source = "registry+https://github.com/rust-lang/crates.io-index"
470 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
471 |
472 | [[package]]
473 | name = "windows-sys"
474 | version = "0.52.0"
475 | source = "registry+https://github.com/rust-lang/crates.io-index"
476 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
477 | dependencies = [
478 | "windows-targets",
479 | ]
480 |
481 | [[package]]
482 | name = "windows-targets"
483 | version = "0.52.5"
484 | source = "registry+https://github.com/rust-lang/crates.io-index"
485 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
486 | dependencies = [
487 | "windows_aarch64_gnullvm",
488 | "windows_aarch64_msvc",
489 | "windows_i686_gnu",
490 | "windows_i686_gnullvm",
491 | "windows_i686_msvc",
492 | "windows_x86_64_gnu",
493 | "windows_x86_64_gnullvm",
494 | "windows_x86_64_msvc",
495 | ]
496 |
497 | [[package]]
498 | name = "windows_aarch64_gnullvm"
499 | version = "0.52.5"
500 | source = "registry+https://github.com/rust-lang/crates.io-index"
501 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
502 |
503 | [[package]]
504 | name = "windows_aarch64_msvc"
505 | version = "0.52.5"
506 | source = "registry+https://github.com/rust-lang/crates.io-index"
507 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
508 |
509 | [[package]]
510 | name = "windows_i686_gnu"
511 | version = "0.52.5"
512 | source = "registry+https://github.com/rust-lang/crates.io-index"
513 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
514 |
515 | [[package]]
516 | name = "windows_i686_gnullvm"
517 | version = "0.52.5"
518 | source = "registry+https://github.com/rust-lang/crates.io-index"
519 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
520 |
521 | [[package]]
522 | name = "windows_i686_msvc"
523 | version = "0.52.5"
524 | source = "registry+https://github.com/rust-lang/crates.io-index"
525 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
526 |
527 | [[package]]
528 | name = "windows_x86_64_gnu"
529 | version = "0.52.5"
530 | source = "registry+https://github.com/rust-lang/crates.io-index"
531 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
532 |
533 | [[package]]
534 | name = "windows_x86_64_gnullvm"
535 | version = "0.52.5"
536 | source = "registry+https://github.com/rust-lang/crates.io-index"
537 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
538 |
539 | [[package]]
540 | name = "windows_x86_64_msvc"
541 | version = "0.52.5"
542 | source = "registry+https://github.com/rust-lang/crates.io-index"
543 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
544 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = [
3 | "crates/ard808x_client",
4 | "crates/ard808x_cpu",
5 | "crates/exec_program",
6 | ]
7 | resolver = "2"
8 | default-members = ["crates/exec_program"]
9 |
10 | [workspace.package]
11 | version = "0.3.0"
12 | edition = "2021"
13 | authors = ["Daniel Balsom", "Andreas Jonsson"]
14 | license = "MIT"
15 | repository = "https://github.com/dbalsom/arduino_808x"
16 |
17 | [workspace.dependencies]
18 | clap = { version = "4.0", features = ["derive"] }
19 | env_logger = "0.11"
20 | log = "0.4"
21 | #serialport = { git = "https://github.com/LukaOber/serialport-rs", branch = "pr/34" }
22 | serialport = { git = "https://github.com/dbalsom/serialport-rs", branch = "arduino-fix" }
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Arduino8088 Copyright 2022-2023 Daniel Balsom
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a
4 | copy of this software and associated documentation files (the “Software”),
5 | to deal in the Software without restriction, including without limitation
6 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | and/or sell copies of the Software, and to permit persons to whom the
8 | Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 | DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Arduino808X
2 | 
3 |
4 | ### About Arduino808X
5 | I've written a blog article that gives an overview of this project and how it is used.
6 |
7 | https://martypc.blogspot.com/2023/06/hardware-validating-emulator.html
8 |
9 | ### Description
10 |
11 | This project expands on the basic idea of controlling an Intel 8088 or NEC V20 CPU via GPIO pins to clock the CPU and read and write control and data signals.
12 | This can be used to validate an emulator's accuracy, but also as a general method of exploring the operation of 8088 and V20 instructions and timings.
13 |
14 | Where it differs from Raspberry Pi based projects is that it uses an Arduino DUE to supply enough GPIO pins to operate the 8088 in Maximum mode without requiring any shifters. This enables several useful signals to be read such as the QS0 & QS1 processor instruction queue status lines, which give us more insight into the internal state of the CPU. We can also enable inputs such as READY, NMI, INTR, and TEST, so we can in theory execute interrupts, emulate wait states, and perhaps simulate FPU and DMA operations.
15 |
16 | The board supports an Intel 8288 bus controller which can produce bus signals, but this chip is optional as the sketch can perform i8288 emulation.
17 |
18 | The original Arduino808X board utilized an Arduino MEGA, but this board is now considered deprecated for this project. As of the current release, an [Arduino DUE](https://store.arduino.cc/products/arduino-due) should be used instead. Although the DUE has 3v GPIO, the current board design is modified for 3V operation. The 80C88 itself tolerates 3V well, and i8288 emulation can be used if you lack a CMOS 8288.
19 |
20 | I have been using this project to validate the cycle-accuracy of my PC emulator, MartyPC: https://github.com/dbalsom/martypc
21 |
22 | ## Can the CPU be clocked fast enough?
23 |
24 | In short, no. We are well past the published minimum cycle times when executing programs via a serial protocol, cycle by cycle. Some chips tolerate this better than others. When working with an Intel branded 8088, I noticed that effective address calculations were failing to add the displacement or index register, but otherwise functioned. I have had more luck with the AMD second-source 8088 CPUs, which seem to function perfectly under slow clocks although they will hang and need to be reset if not cycled for a several milliseconds. The issue is "dynamic logic" - logic gates that lose their state if not refrehsed electrically within a frequent enough interval. To be absolutely safe, it is best to use a fully CMOS process CPU such as the 80C88.
25 |
26 | ## Credits
27 |
28 | Inspired by and borrows from the Pi8088 validator created by Andreas Jonsson as part of the VirtualXT project:
29 |
30 | https://github.com/andreas-jonsson/virtualxt/tree/develop/tools/validator/pi8088
31 |
32 | A very similar project is homebrew8088's Raspberry Pi Hat:
33 |
34 | https://github.com/homebrew8088/pi86
35 |
36 | ## To use
37 |
38 | If you don't want to order and build the PCB, connect the GPIO pins to the CPU on a breadboard as specified in the KiCad project schematic.
39 |
40 | The main Arduino808X sketch, cpu_server, operates a simple binary serial protocol to execute operations on the CPU and read and write data, status and control signals. This is designed for integration with an emulator or instruction test generator.
41 |
42 | Additionally, there is a sketch, 'run_program', that will take any user-supplied register state and array of instruction bytes defined in the source code, execute it, and print cycle traces and final register state. This is useful for investigating the timing and operation of certain instructions without needing any external software integrations, however it is restricted in the number of memory reads or writes it can support, due to the limited RAM on the Arduino MEGA (8k!) 'run_program' does not currently support the DUE.
43 |
44 | An example application for cpu_server is provided, written in Rust, in the /crates/exec_program directory. It demonstrates how to upload arbitrary code to the Arduino808X and display cycle traces. The client will emulate the entire address space and set up a basic IVT.
45 |
46 | ## PCB
47 | 
48 |
49 | KiCad project files for the PCB are supplied.
50 |
51 | In theory the board could also support an 8086 CPU. Version 1.1 adds a connection for the 8086's BHE pin,
52 | which indicates the size of the current bus transfer. The cpu_server sketch and protocol still needs modification to support 16 bit data transfers and the longer queue length on the 8086.
53 |
54 | Please read all the notes in the next section before ordering/assembling parts. Failure to heed warnings will cause damage to your Arduino.
55 |
56 | # BOM
57 | - A compatible CPU. For best results, use a CMOS CPU such as a Harris 80C88, Oki 80C88, or NEC V20 CPU. Beware of counterfeits on eBay and other online vendors.
58 | A legitimate chip will not look shiny and new with perfect printing on it.
59 |
60 | - (Optional) An Intel 8288 or OKI 82C88 Bus Controller. If not using an 8288, set the EMULATE_8288 flag in cpu_server.
61 |
62 | - A set of Arduino stacking headers (also usable with DUE)
63 | https://www.amazon.com/Treedix-Stacking-Headers-Stackable-Compatible/dp/B08G4FGBPQ
64 |
65 | - A DIP-40 and (optionally) DIP-20 socket
66 | - Optional: You can spring for a ZIF socket such as [https://www.amazon.com/-/en/gp/product/B00B886OZI](https://www.amazon.com/-/en/gp/product/B00B886OZI)
67 |
68 | - (2x) 0805 0.047uf bypass capacitors
69 | https://www.mouser.com/ProductDetail/80-C0805C473KARAUTO
70 |
71 | - (Optional) A 12mm, active buzzer with 7.6mm pin spacing.
72 |
73 | - For DUE: A 3V piezoelectric, low power buzzer <= 6mA
74 | https://www.mouser.com/ProductDetail/Mallory-Sonalert/PK-11N40PQ?qs=SXHtpsd1MbZ%252B7jeUyAAOVA%3D%3D
75 |
76 | - For MEGA: Any 3-5V buzzer <= 30mA
77 | WARNING: Only connect an electromagnetic buzzer if using an Arduino MEGA. The DUE has much lower GPIO max current supply.
78 |
79 | - (2x) 750Ohm resistors (for LEDs)
80 | https://www.mouser.com/ProductDetail/667-ERA-6AED751V
81 |
82 | - (2x) Any 0805 ~2V LED of your choice with 1.8-1.9mA forward current
83 | - https://www.mouser.com/ProductDetail/604-APTD2012LCGCK (Green)
84 | - https://www.mouser.com/ProductDetail/604-APT2012LSECKJ4RV (Orange)
85 |
86 | - RS232 board for debug output - choose gender based on your desired cabling
87 | - https://www.amazon.com/Ultra-Compact-RS232-Converter-1Mbps/dp/B074BMLM11 (male)
88 | - https://www.amazon.com/Ultra-Compact-RS232-Converter-Female/dp/B074BTGLJN (female)
89 | - WARNING: DO NOT connect 5V to rs232 board on DUE
90 |
91 | # Project Structure
92 |
93 | ## /asm
94 |
95 | Assembly language files, intended to be assembled with NASM. To execute code on the Arduino808X, one must supply two
96 | binary files, one containing the program to be executed, and one containing the register values to load onto the CPU
97 | before program execution.
98 |
99 | ## /crates/ard808x_client
100 |
101 | A library crate that implements a client for the Arduino808X's serial protocol.
102 |
103 | ## /crates/ard808x_cpu
104 |
105 | A library crate built on top of the `ard808x_client` crate, this provides a `RemoteCpu` struct that models CPU state
106 | and can execute programs.
107 |
108 | ## /crates/exec_program
109 |
110 | A binary implementing an interface for the `ard808x_cpu` crate that will load a provided register state binary and
111 | execute the specified program binary.
112 |
113 | ## /pcb
114 |
115 | Contains the KiCad project files and Gerber files for the Arduino808X PCB.
116 |
117 | ## /sketches/cpu_server
118 |
119 | The main Arduino sketch for Arduino808X. Implements a server for a serial protocol enabling remote control of a 16-bit
120 | Intel CPU on the Arduino DUE.
121 |
122 | ## /sketches/run_program
123 |
124 | An older sketch that can execute a program directly on the Arduino MEGA. Supports the 8088 only.
125 |
--------------------------------------------------------------------------------
/asm/i8080.inc:
--------------------------------------------------------------------------------
1 | ; (C)2025 BinaryMelodies
2 | ; https://github.com/BinaryMelodies/nasm-i8080
3 | ;
4 | ; Boost Software License - Version 1.0 - August 17th, 2003
5 | ;
6 | ; Permission is hereby granted, free of charge, to any person or organization
7 | ; obtaining a copy of the software and accompanying documentation covered by
8 | ; this license (the "Software") to use, reproduce, display, distribute,
9 | ; execute, and transmit the Software, and to prepare derivative works of the
10 | ; Software, and to permit third-parties to whom the Software is furnished to
11 | ; do so, all subject to the following:
12 | ;
13 | ; The copyright notices in the Software and this entire statement, including
14 | ; the above license grant, this restriction and the following disclaimer,
15 | ; must be included in all copies of the Software, in whole or in part, and
16 | ; all derivative works of the Software, unless such copies or derivative
17 | ; works are solely in the form of machine-executable object code generated by
18 | ; a source language processor.
19 | ;
20 | ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | ; FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 | ; SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 | ; FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 | ; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 | ; DEALINGS IN THE SOFTWARE.
27 |
28 | %macro __i80_byte 2
29 | %ifidn %2,b
30 | db (%1)
31 | %elifidn %2,c
32 | db (%1)|1
33 | %elifidn %2,d
34 | db (%1)|2
35 | %elifidn %2,e
36 | db (%1)|3
37 | %elifidn %2,h
38 | db (%1)|4
39 | %elifidn %2,l
40 | db (%1)|5
41 | %elifidn %2,m
42 | db (%1)|6
43 | %elifidn %2,a
44 | db (%1)|7
45 | %else
46 | %error invalid combination of opcodes and operands
47 | %endif
48 | %endmacro
49 |
50 | %macro __i80_byte3 2
51 | %ifidn %2,b
52 | db (%1)
53 | %elifidn %2,c
54 | db (%1)|0o10
55 | %elifidn %2,d
56 | db (%1)|0o20
57 | %elifidn %2,e
58 | db (%1)|0o30
59 | %elifidn %2,h
60 | db (%1)|0o40
61 | %elifidn %2,l
62 | db (%1)|0o50
63 | %elifidn %2,m
64 | db (%1)|0o60
65 | %elifidn %2,a
66 | db (%1)|0o70
67 | %else
68 | %error invalid combination of opcodes and operands
69 | %endif
70 | %endmacro
71 |
72 | %macro __i80_word 2
73 | %ifidn %2,b
74 | db (%1)
75 | %elifidn %2,d
76 | db (%1)|0x10
77 | %elifidn %2,h
78 | db (%1)|0x20
79 | %elifidn %2,sp
80 | db (%1)|0x30
81 | %else
82 | %error invalid combination of opcodes and operands
83 | %endif
84 | %endmacro
85 |
86 | %macro __i80_word3 2
87 | %ifidn %2,b
88 | db (%1)
89 | %elifidn %2,d
90 | db (%1)|0x10
91 | %elifidn %2,h
92 | db (%1)|0x20
93 | %else
94 | %error invalid combination of opcodes and operands
95 | %endif
96 | %endmacro
97 |
98 | %macro __i80_word2 2
99 | %ifidn %2,b
100 | db (%1)
101 | %elifidn %2,d
102 | db (%1)|0x10
103 | %else
104 | %error invalid combination of opcodes and operands
105 | %endif
106 | %endmacro
107 |
108 | %macro code8086 0
109 | %ifdef __i80_enabled
110 | %undef __i80_enabled
111 | %unmacro nop 0
112 | %unmacro lxi 2
113 | %unmacro stax 1
114 | %unmacro inx 1
115 | %unmacro inr 1
116 | %unmacro dcr 1
117 | %unmacro mvi 2
118 | %unmacro rlc 0
119 | %unmacro dad 1
120 | %unmacro ldax 1
121 | %unmacro dcx 1
122 | %unmacro rrc 0
123 | %unmacro ral 0
124 | %unmacro rar 0
125 | %unmacro shld 1
126 | %unmacro daa 0
127 | %unmacro lhld 1
128 | %unmacro cma 0
129 | %unmacro sta 1
130 | %unmacro stc 0
131 | %unmacro lda 1
132 | %unmacro cmc 0
133 | %unmacro mov 2
134 | %unmacro hlt 0
135 | %unmacro add 1
136 | %unmacro adc 1
137 | %unmacro sub 1
138 | %unmacro sbb 1
139 | %unmacro ana 1
140 | %unmacro xra 1
141 | %unmacro ora 1
142 | %unmacro cmp 1
143 | %unmacro rnz 0
144 | %unmacro rz 0
145 | %unmacro rnc 0
146 | %unmacro rc 0
147 | %unmacro rpo 0
148 | %unmacro rpe 0
149 | %unmacro rp 0
150 | %unmacro rm 0
151 | %unmacro pop 1
152 | %unmacro jnz 1
153 | %unmacro jz 1
154 | %unmacro jnc 1
155 | %unmacro jc 1
156 | %unmacro jpo 1
157 | %unmacro jpe 1
158 | %unmacro jp 1
159 | %unmacro jm 1
160 | %unmacro jmp 1
161 | %unmacro cnz 1
162 | %unmacro cz 1
163 | %unmacro cnc 1
164 | %unmacro cc 1
165 | %unmacro cpo 1
166 | %unmacro cpe 1
167 | %unmacro cp 1
168 | %unmacro cm 1
169 | %unmacro push 1
170 | %unmacro adi 1
171 | %unmacro aci 1
172 | %unmacro sui 1
173 | %unmacro sbi 1
174 | %unmacro ani 1
175 | %unmacro xri 1
176 | %unmacro ori 1
177 | %unmacro cpi 1
178 | %unmacro rst 1
179 | %unmacro ret 0
180 | %unmacro call 1
181 | %unmacro out 1
182 | %unmacro in 1
183 | %unmacro xthl 0
184 | %unmacro pchl 0
185 | %unmacro xchg 0
186 | %unmacro di 0
187 | %unmacro sphl 0
188 | %unmacro ei 0
189 | ; 8085 specific
190 | %unmacro rim 0
191 | %unmacro sim 0
192 | ; 8085 undocumented
193 | %unmacro dsub 0
194 | %unmacro arhl 0
195 | %unmacro rdel 0
196 | %unmacro ldhi 1
197 | %unmacro ldsi 1
198 | %unmacro rstv 0
199 | %unmacro shlx 0
200 | %unmacro jnui 1
201 | %unmacro lhlx 0
202 | %unmacro jui 1
203 | %endif
204 | %endmacro
205 |
206 | %macro code8080 0
207 | %define __i80_enabled
208 |
209 | %macro nop 0
210 | db 0x00
211 | %endmacro
212 |
213 | %macro lxi 2
214 | %%value equ %2
215 | __i80_word 0x01,%1
216 | dw %%value
217 | %endmacro
218 |
219 | %macro stax 1
220 | __i80_word2 0x02,%1
221 | %endmacro
222 |
223 | %macro inx 1
224 | __i80_word 0x03,%1
225 | %endmacro
226 |
227 | %macro inr 1
228 | __i80_byte3 0x04,%1
229 | %endmacro
230 |
231 | %macro dcr 1
232 | __i80_byte3 0x05,%1
233 | %endmacro
234 |
235 | %macro mvi 2
236 | %%value equ %2
237 | __i80_byte3 0x06,%1
238 | db %%value
239 | %endmacro
240 |
241 | %macro rlc 0
242 | db 0x07
243 | %endmacro
244 |
245 | %macro dad 1
246 | __i80_word 0x09,%1
247 | %endmacro
248 |
249 | %macro ldax 1
250 | __i80_word2 0x0A,%1
251 | %endmacro
252 |
253 | %macro dcx 1
254 | __i80_word 0x0B,%1
255 | %endmacro
256 |
257 | %macro rrc 0
258 | db 0x0F
259 | %endmacro
260 |
261 | %macro ral 0
262 | db 0x17
263 | %endmacro
264 |
265 | %macro rar 0
266 | db 0x1F
267 | %endmacro
268 |
269 | %macro shld 1
270 | %%value equ %1
271 | db 0x22
272 | dw %%value
273 | %endmacro
274 |
275 | %macro daa 0
276 | db 0x27
277 | %endmacro
278 |
279 | %macro lhld 1
280 | %%value equ %1
281 | db 0x2A
282 | dw %%value
283 | %endmacro
284 |
285 | %macro cma 0
286 | db 0x2F
287 | %endmacro
288 |
289 | %macro sta 1
290 | %%value equ %1
291 | db 0x32
292 | dw %%value
293 | %endmacro
294 |
295 | %macro stc 0
296 | db 0x37
297 | %endmacro
298 |
299 | %macro lda 1
300 | %%value equ %1
301 | db 0x3A
302 | dw %%value
303 | %endmacro
304 |
305 | %macro cmc 0
306 | db 0x3F
307 | %endmacro
308 |
309 | %macro mov 2
310 | %ifidn %1,b
311 | __i80_byte 0x40,%2
312 | %elifidn %1,c
313 | __i80_byte 0x40|0o10,%2
314 | %elifidn %1,d
315 | __i80_byte 0x40|0o20,%2
316 | %elifidn %1,e
317 | __i80_byte 0x40|0o30,%2
318 | %elifidn %1,h
319 | __i80_byte 0x40|0o40,%2
320 | %elifidn %1,l
321 | __i80_byte 0x40|0o50,%2
322 | %elifidn %1,m
323 | %ifnidn %2,m
324 | __i80_byte 0x40|0o60,%2
325 | %else
326 | %error invalid combination of opcodes and operands
327 | %endif
328 | %elifidn %1,a
329 | __i80_byte 0x40|0o70,%2
330 | %else
331 | %error invalid combination of opcodes and operands
332 | %endif
333 | %endmacro
334 |
335 | %macro hlt 0
336 | db 0x76
337 | %endmacro
338 |
339 | %macro add 1
340 | __i80_byte 0x80,%1
341 | %endmacro
342 |
343 | %macro adc 1
344 | __i80_byte 0x88,%1
345 | %endmacro
346 |
347 | %macro sub 1
348 | __i80_byte 0x90,%1
349 | %endmacro
350 |
351 | %macro sbb 1
352 | __i80_byte 0x98,%1
353 | %endmacro
354 |
355 | %macro ana 1
356 | __i80_byte 0xA0,%1
357 | %endmacro
358 |
359 | %macro xra 1
360 | __i80_byte 0xA8,%1
361 | %endmacro
362 |
363 | %macro ora 1
364 | __i80_byte 0xB0,%1
365 | %endmacro
366 |
367 | %macro cmp 1
368 | __i80_byte 0xB8,%1
369 | %endmacro
370 |
371 | %macro rnz 0
372 | db 0xC0
373 | %endmacro
374 | %macro rz 0
375 | db 0xC8
376 | %endmacro
377 | %macro rnc 0
378 | db 0xD0
379 | %endmacro
380 | %macro rc 0
381 | db 0xD8
382 | %endmacro
383 | %macro rpo 0
384 | db 0xE0
385 | %endmacro
386 | %macro rpe 0
387 | db 0xE8
388 | %endmacro
389 | %macro rp 0
390 | db 0xF0
391 | %endmacro
392 | %macro rm 0
393 | db 0xF8
394 | %endmacro
395 |
396 | %macro pop 1
397 | %ifidn psw,%1
398 | db 0xF1
399 | %else
400 | __i80_word3 0xC1,%1
401 | %endif
402 | %endmacro
403 |
404 | %macro jnz 1
405 | %%value equ %1
406 | db 0xC2
407 | dw %%value
408 | %endmacro
409 | %macro jz 1
410 | %%value equ %1
411 | db 0xCA
412 | dw %%value
413 | %endmacro
414 | %macro jnc 1
415 | %%value equ %1
416 | db 0xD2
417 | dw %%value
418 | %endmacro
419 | %macro jc 1
420 | %%value equ %1
421 | db 0xDA
422 | dw %%value
423 | %endmacro
424 | %macro jpo 1
425 | %%value equ %1
426 | db 0xE2
427 | dw %%value
428 | %endmacro
429 | %macro jpe 1
430 | %%value equ %1
431 | db 0xEA
432 | dw %%value
433 | %endmacro
434 | %macro jp 1
435 | %%value equ %1
436 | db 0xF2
437 | dw %%value
438 | %endmacro
439 | %macro jm 1
440 | %%value equ %1
441 | db 0xFA
442 | dw %%value
443 | %endmacro
444 |
445 | %macro jmp 1
446 | %%value equ %1
447 | db 0xC3
448 | dw %%value
449 | %endmacro
450 |
451 | %macro cnz 1
452 | %%value equ %1
453 | db 0xC4
454 | dw %%value
455 | %endmacro
456 | %macro cz 1
457 | %%value equ %1
458 | db 0xCC
459 | dw %%value
460 | %endmacro
461 | %macro cnc 1
462 | %%value equ %1
463 | db 0xD4
464 | dw %%value
465 | %endmacro
466 | %macro cc 1
467 | %%value equ %1
468 | db 0xDC
469 | dw %%value
470 | %endmacro
471 | %macro cpo 1
472 | %%value equ %1
473 | db 0xE4
474 | dw %%value
475 | %endmacro
476 | %macro cpe 1
477 | %%value equ %1
478 | db 0xEC
479 | dw %%value
480 | %endmacro
481 | %macro cp 1
482 | %%value equ %1
483 | db 0xF4
484 | dw %%value
485 | %endmacro
486 | %macro cm 1
487 | %%value equ %1
488 | db 0xFC
489 | dw %%value
490 | %endmacro
491 |
492 | %macro push 1
493 | %ifidn psw,%1
494 | db 0xF5
495 | %else
496 | __i80_word3 0xC5,%1
497 | %endif
498 | %endmacro
499 |
500 | %macro adi 1
501 | db 0xC6, %1
502 | %endmacro
503 | %macro aci 1
504 | db 0xCE, %1
505 | %endmacro
506 | %macro sui 1
507 | db 0xD6, %1
508 | %endmacro
509 | %macro sbi 1
510 | db 0xDE, %1
511 | %endmacro
512 | %macro ani 1
513 | db 0xE6, %1
514 | %endmacro
515 | %macro xri 1
516 | db 0xEE, %1
517 | %endmacro
518 | %macro ori 1
519 | db 0xF6, %1
520 | %endmacro
521 | %macro cpi 1
522 | db 0xFE, %1
523 | %endmacro
524 |
525 | %macro rst 1
526 | %if (%1) >= 0 && (%1) < 8
527 | db 0xC7|((%1)<<3)
528 | %else
529 | %error invalid combination of opcodes and operands
530 | %endif
531 | %endmacro
532 |
533 | %macro ret 0
534 | db 0xC9
535 | %endmacro
536 |
537 | %macro call 1
538 | %%value equ %1
539 | db 0xCD
540 | dw %%value
541 | %endmacro
542 |
543 | %macro out 1
544 | db 0xD3, %1
545 | %endmacro
546 |
547 | %macro in 1
548 | db 0xDB, %1
549 | %endmacro
550 |
551 | %macro xthl 0
552 | db 0xE3
553 | %endmacro
554 |
555 | %macro pchl 0
556 | db 0xE9
557 | %endmacro
558 |
559 | %macro xchg 0
560 | db 0xEB
561 | %endmacro
562 |
563 | %macro di 0
564 | db 0xF3
565 | %endmacro
566 |
567 | %macro sphl 0
568 | db 0xF9
569 | %endmacro
570 |
571 | %macro ei 0
572 | db 0xFB
573 | %endmacro
574 |
575 | ; 8085 specific
576 |
577 | %macro rim 0
578 | db 0x20
579 | %endmacro
580 |
581 | %macro sim 0
582 | db 0x30
583 | %endmacro
584 |
585 | ; 8085 undocumented
586 |
587 | %macro dsub 0
588 | db 0x08
589 | %endmacro
590 |
591 | %macro arhl 0
592 | db 0x10
593 | %endmacro
594 |
595 | %macro rdel 0
596 | db 0x18
597 | %endmacro
598 |
599 | %macro ldhi 1
600 | db 0x28, %1
601 | %endmacro
602 |
603 | %macro ldsi 1
604 | db 0x38, %1
605 | %endmacro
606 |
607 | %macro rstv 0
608 | db 0xCB
609 | %endmacro
610 |
611 | %macro shlx 0
612 | db 0xD9
613 | %endmacro
614 |
615 | %macro jnui 1
616 | %%value equ %1
617 | db 0xDD
618 | dw %%value
619 | %endmacro
620 |
621 | %macro lhlx 0
622 | db 0xED
623 | %endmacro
624 |
625 | %macro jui 1
626 | %%value equ %1
627 | db 0xFD
628 | dw %%value
629 | %endmacro
630 |
631 | %endmacro
632 |
633 |
--------------------------------------------------------------------------------
/asm/kefrensloop.asm:
--------------------------------------------------------------------------------
1 |
2 | ; kefrensloop.asm
3 | ; kefrens effect main loop from 8088mph
4 |
5 | cpu 8086
6 | org 0h
7 |
8 | nop
9 | nop
10 | nop
11 | nop
12 | nop
13 | nop
14 | nop
15 | nop
16 | nop
17 | nop
18 | nop
19 | nop
20 | nop
21 | nop
22 | nop
23 | nop
24 | nop
25 | nop
26 | nop
27 | nop
28 | nop
29 | nop
30 | nop
31 | nop
32 | nop
33 | nop
34 | nop
35 | nop
36 | nop
37 | nop
38 | nop
39 | nop
40 | nop
41 | nop
42 | nop
43 | nop
44 |
45 | ; start of unrolled loop procedure
46 | mov al, [es:di]
47 | mov ds, bp
48 | lodsb
49 | out 0xE0, al ; what is this port(?)
50 |
51 | ; 2nd iteration for prefetch modelling
52 | mov ax,9999
53 | mov ds,ax
54 | mov sp,[bx]
55 | pop di
56 | mov al,[es:di]
57 | pop cx
58 | and ax,cx
59 | pop cx
60 | or ax,cx
61 | stosw
62 | pop ax
63 | and ah,[es:di+1]
64 | pop cx
65 | or ax,cx
66 | stosw
67 | pop ax
68 | out dx,al
69 | mov ds,bp
70 | lodsb
71 | out 0x60,al
--------------------------------------------------------------------------------
/asm/program.asm:
--------------------------------------------------------------------------------
1 | ; program.asm
2 | ; Compile with nasm to build program.bin for cpu_client
3 | ; nasm program.asm -o program.bin
4 | cpu 8086
5 | org 0h
6 |
7 | sti
8 | mov al, 0x08
9 | out 0x30, al
10 | nop
11 | nop
12 | nop
13 | nop
14 | nop
15 | nop
16 | nop
17 | nop
--------------------------------------------------------------------------------
/asm/program.lst:
--------------------------------------------------------------------------------
1 | 1 ; program.asm
2 | 2 ; Compile with nasm to build program.bin for cpu_client
3 | 3 ; nasm program.asm -o program.bin
4 | 4 cpu 8086
5 | 5 org 0h
6 | 6
7 | 7 00000000 FB sti
8 | 8 00000001 B008 mov al, 0x08
9 | 9 00000003 E630 out 0x30, al
10 | 10 00000005 90 nop
11 | 11 00000006 90 nop
12 | 12 00000007 90 nop
13 | 13 00000008 90 nop
14 | 14 00000009 90 nop
15 | 15 0000000A 90 nop
16 | 16 0000000B 90 nop
17 | 17 0000000C 90 nop
18 |
--------------------------------------------------------------------------------
/asm/program_8080.asm:
--------------------------------------------------------------------------------
1 | ; program_8080.asm
2 | ; Compile with nasm to build program.bin for cpu_client
3 | ; nasm program_8080.asm -o program.bin
4 | %include 'asm/i8080.inc'
5 |
6 | cpu 8086
7 | org 100h
8 | code8080
9 |
10 | mvi a, 0x00
11 | mvi b, 0x00
12 | add b
13 |
--------------------------------------------------------------------------------
/asm/program_8080_regs.asm:
--------------------------------------------------------------------------------
1 | ; regs.asm
2 | ; Compile with nasm to build regs.bin for cpu_client
3 | ; nasm regs.asm -o regs.bin
4 |
5 | cpu 8086
6 | org 0h
7 |
8 | ; Specify the initial register state by modifying the values below.
9 | ; Assembling this file creates a BIN file representing the initial register state.
10 | ; Do not modify the order of the registers or add extra data.
11 | dw 0x1234 ; AX
12 | dw 0x0000 ; BX
13 | dw 0x0000 ; CX
14 | dw 0x0000 ; DX
15 | dw 0x0000 ; SS
16 | dw 0xFFFE ; SP
17 | dw 0xF002 ; FLAGS
18 | dw 0x0100 ; IP
19 | dw 0xF000 ; CS
20 | dw 0x0000 ; DS
21 | dw 0x0000 ; ES
22 | dw 0x0000 ; BP
23 | dw 0x0000 ; SI
24 | dw 0x0000 ; DI
25 |
--------------------------------------------------------------------------------
/asm/program_regs.asm:
--------------------------------------------------------------------------------
1 | ; regs.asm
2 | ; Compile with nasm to build regs.bin for cpu_client
3 | ; nasm regs.asm -o regs.bin
4 |
5 | cpu 8086
6 | org 0h
7 |
8 | ; Specify the initial register state by modifying the values below.
9 | ; Assembling this file creates a BIN file representing the initial register state.
10 | ; Do not modify the order of the registers or add extra data.
11 | dw 0x0000 ; AX
12 | dw 0x0000 ; BX
13 | dw 0x0000 ; CX
14 | dw 0x0000 ; DX
15 | dw 0x0000 ; SS
16 | dw 0xFFFE ; SP
17 | dw 0xF002 ; FLAGS
18 | dw 0x0100 ; IP
19 | dw 0xF000 ; CS
20 | dw 0x0000 ; DS
21 | dw 0x0000 ; ES
22 | dw 0x0000 ; BP
23 | dw 0x0000 ; SI
24 | dw 0x0000 ; DI
25 |
--------------------------------------------------------------------------------
/asm/testcyc.asm:
--------------------------------------------------------------------------------
1 | ; testcyc.asm
2 | ; cycle-test from 8088mph
3 |
4 | cpu 8086
5 | org 100h
6 |
7 | mov ax, 1234h
8 | xor bx, bx
9 | mov cx, bx
10 | mov dx, 5678h
11 | mov si, bx
12 | mov di, bx
13 | add ax, 1234h
14 | add dx, 1234h
15 | add al, 12h
16 | add dl, 12h
17 | add ds:12D6h, ax
18 | add ds:12D6h, dx
19 | add ax, ds:12D6h
20 | add dx, ds:12D6h
21 | add ax, dx
22 | add dx, ax
23 | add al, dl
24 | add dl, al
25 | push es
26 | pop es
27 | or ax, 1234h
28 | or dx, 1234h
29 | or al, 12h
30 | or dl, 12h
31 | or ds:12D6h, ax
32 | or ds:12D6h, dx
33 | or ax, ds:12D6h
34 | or dx, ds:12D6h
35 | or ax, dx
36 | or dx, ax
37 | or al, dl
38 | or dl, al
39 | push cs
40 | pop es
41 | ; assume es:seg000
42 | adc ax, 1234h
43 | adc dx, 1234h
44 | adc al, 12h
45 | adc dl, 12h
46 | adc ds:12D6h, ax
47 | adc ds:12D6h, dx
48 | adc ax, ds:12D6h
49 | adc dx, ds:12D6h
50 | adc ax, dx
51 | adc dx, ax
52 | adc al, dl
53 | adc dl, al
54 | push ax
55 | mov ax, sp
56 | push ss
57 | pop ss
58 | mov sp, ax
59 | pop ax
60 | sbb ax, 1234h
61 | sbb dx, 1234h
62 | sbb al, 12h
63 | sbb dl, 12h
64 | sbb ds:12D6h, ax
65 | sbb ds:12D6h, dx
66 | sbb ax, ds:12D6h
67 | sbb dx, ds:12D6h
68 | sbb ax, dx
69 | sbb dx, ax
70 | sbb al, dl
71 | sbb dl, al
72 | push ds
73 | pop ds
74 | and ax, 1234h
75 | and dx, 1234h
76 | and al, 12h
77 | and dl, 12h
78 | and ds:12D6h, ax
79 | and ds:12D6h, dx
80 | and ax, ds:12D6h
81 | and dx, ds:12D6h
82 | and ax, dx
83 | and dx, ax
84 | and al, dl
85 | and dl, al
86 | mov ax, es:[bx]
87 | daa
88 | sub ax, 1234h
89 | sub dx, 1234h
90 | sub al, 12h
91 | sub dl, 12h
92 | sub ds:12D6h, ax
93 | sub ds:12D6h, dx
94 | sub ax, ds:12D6h
95 | sub dx, ds:12D6h
96 | sub ax, dx
97 | sub dx, ax
98 | sub al, dl
99 | sub dl, al
100 | mov ax, cs:[bx]
101 | das
102 | xor ax, 1234h
103 | xor dx, 1234h
104 | xor al, 12h
105 | xor dl, 12h
106 | xor ds:12D6h, ax
107 | xor ds:12D6h, dx
108 | xor ax, ds:12D6h
109 | xor dx, ds:12D6h
110 | xor ax, dx
111 | xor dx, ax
112 | xor al, dl
113 | xor dl, al
114 | mov ax, ss:[bx]
115 | aaa
116 | cmp ax, 1234h
117 | cmp dx, 1234h
118 | cmp al, 12h
119 | cmp dl, 12h
120 | cmp ds:12D6h, ax
121 | cmp ds:12D6h, dx
122 | cmp ax, ds:12D6h
123 | cmp dx, ds:12D6h
124 | cmp ax, dx
125 | cmp dx, ax
126 | cmp al, dl
127 | cmp dl, al
128 | db 3Eh
129 | lodsw
130 | aas
131 | inc ax
132 | inc cx
133 | inc dx
134 | inc bx
135 | inc si
136 | inc di
137 | dec ax
138 | dec cx
139 | dec dx
140 | dec bx
141 | dec si
142 | dec di
143 | push ax
144 | push cx
145 | push dx
146 | push bx
147 | push bp
148 | push si
149 | push di
150 | pop di
151 | pop si
152 | pop bp
153 | pop bx
154 | pop dx
155 | pop cx
156 | pop ax
157 | xor cx, cx
158 | dec cx
159 | stc
160 | jb short loc_10911
161 | nop
162 |
163 | ; CODE XREF: test_cpu_01+17D↑j
164 | ; test_cpu_01+181↓j ...
165 | loc_10911:
166 | clc
167 | jb short loc_10911
168 | inc cx
169 | ;jcxz short loc_10911
170 | db 0xE3, 0xFA
171 | sub cx, 2
172 | jmp short loc_1091E
173 | ;-------------------------------------------------------------
174 |
175 | ; CODE XREF: test_cpu_01:loc_1091E↓j
176 | loc_1091C:
177 | inc cx
178 | clc
179 |
180 | ; CODE XREF: test_cpu_01+189↑j
181 | loc_1091E:
182 | jbe short loc_1091C
183 | mov cx, 2
184 |
185 | ; CODE XREF: test_cpu_01+193↓j
186 | loc_10923:
187 | nop
188 | loop loc_10923
189 | test ax, 1234h
190 | test dx, 1234h
191 | test al, 12h
192 | test dl, 12h
193 | test ds:12D6h, ax
194 | test ds:12D6h, dx
195 | test ds:12D6h, ax
196 | test ds:12D6h, dx
197 | test dx, ax
198 | test ax, dx
199 | test dl, al
200 | test al, dl
201 | lea ax, ds:12D6h
202 | mov es, word [bx+si+1234h]
203 | ;assume es:nothing
204 | nop
205 | xchg ax, ds:12D6h
206 | xchg dx, ds:12D6h
207 | xchg ax, ds:12D6h
208 | xchg dx, ds:12D6h
209 | xchg ax, dx
210 | xchg ax, dx
211 | xchg dl, al
212 | xchg al, dl
213 | cbw
214 | push ds
215 | pop es
216 | mov di, si
217 | movsb
218 | movsw
219 | movsb
220 | movsw
221 | lodsb
222 | stosb
223 | lodsw
224 | stosw
225 | lodsb
226 | stosb
227 | lodsw
228 | stosw
229 | cmpsb
230 | cmpsw
231 | cmpsb
232 | cmpsw
233 | scasb
234 | scasw
235 | scasb
236 | scasw
237 | mov al, 12h
238 | mov cl, 12h
239 | mov dl, 12h
240 | mov bl, 12h
241 | mov ah, 12h
242 | mov ch, 12h
243 | mov dh, 12h
244 | mov bh, 12h
245 | mov ax, 1234h
246 | mov cx, 1234h
247 | mov dx, 1234h
248 | mov bx, 1234h
249 | mov si, 1234h
250 | mov di, 1234h
251 | les bx, ds:1234h
252 | mov bx, 0FFFFh
253 | rol bl, 1
254 | rol byte ds:12DCh, 1
255 | ror bl, 1
256 | ror byte ds:12DCh, 1
257 | rcl bl, 1
258 | rcl byte ds:12DCh, 1
259 | rcr bl, 1
260 | rcr byte ds:12DCh, 1
261 | shl bl, 1
262 | shl byte ds:12DCh, 1
263 | shr bl, 1
264 | shr byte ds:12DCh, 1
265 | shl bl, 1
266 | shl byte ds:12DCh, 1
267 | sar bl, 1
268 | sar byte ds:12DCh, 1
269 | rol bx, 1
270 | rol word ds:12D6h, 1
271 | ror bx, 1
272 | ror word ds:12D6h, 1
273 | rcl bx, 1
274 | rcl word ds:12D6h, 1
275 | rcr bx, 1
276 | rcr word ds:12D6h, 1
277 | shl bx, 1
278 | shl word ds:12D6h, 1
279 | shr bx, 1
280 | shr word ds:12D6h, 1
281 | shl bx, 1
282 | shl word ds:12D6h, 1
283 | sar bx, 1
284 | sar word ds:12D6h, 1
285 | mov cl, 4
286 | rol bl, cl
287 | rol byte ds:12DCh, cl
288 | ror bl, cl
289 | ror byte ds:12DCh, cl
290 | rcl bl, cl
291 | rcl byte ds:12DCh, cl
292 | rcr bl, cl
293 | rcr byte ds:12DCh, cl
294 | shl bl, cl
295 | shl byte ds:12DCh, cl
296 | shr bl, cl
297 | shr byte ds:12DCh, cl
298 | shl bl, cl
299 | shl byte ds:12DCh, cl
300 | sar bl, cl
301 | sar byte ds:12DCh, cl
302 | rol bx, cl
303 | rol word ds:12D6h, cl
304 | ror bx, cl
305 | ror word ds:12D6h, cl
306 | rcl bx, cl
307 | rcl word ds:12D6h, cl
308 | rcr bx, cl
309 | rcr word ds:12D6h, cl
310 | shl bx, cl
311 | shl word ds:12D6h, cl
312 | shr bx, cl
313 | shr word ds:12D6h, cl
314 | shl bx, cl
315 | shl word ds:12D6h, cl
316 | sar bx, cl
317 | sar word ds:12D6h, cl
318 | aad
319 | nop
320 | nop
321 | nop
322 | nop
323 | nop
324 | nop
325 | aam
326 | nop
327 | nop
328 | nop
329 | nop
330 | nop
331 | nop
332 | xlat
333 | mov ax, 1234h
334 | mov dx, 5678h
335 | cmc
336 | not dl
337 | not ax
338 | neg dl
339 | neg ax
340 | mov dx, 20BDh
341 | mul dx
342 | mov bx, 2710h
343 | div bx
344 | nop
345 | nop
346 | nop
347 | nop
348 | nop
349 | nop
350 | imul dx
351 | nop
352 | nop
353 | nop
354 | nop
355 | nop
356 | nop
357 | idiv bx
358 | clc
359 | stc
360 | pushf
361 | cld
362 | std
363 | popf
364 | mov ax, 1234h
365 | mov dx, 1234h
366 | mov al, 12h
367 | mov dl, 12h
368 | mov ds:12D6h, ax
369 | mov ds:12D6h, dx
370 | mov ax, ds:12D6h
371 | mov dx, ds:12D6h
372 | mov ax, dx
373 | mov dx, ax
374 | mov al, dl
375 | mov dl, al
376 | mov dx, cs:[bx]
377 | ;mov dx, [bp+var_s0]
378 | mov dx, [bp+0]
379 | mov dx, es:[si]
380 | mov dx, [di]
381 | lea bx, ds:0Ah
382 | push word [bx]
383 | pop word [bx]
--------------------------------------------------------------------------------
/crates/ard808x_client/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "ard808x_client"
3 | description = "A library crate that implements a client for the Arduino808x serial protocol."
4 | version.workspace = true
5 | edition.workspace = true
6 | authors.workspace = true
7 |
8 | [lib]
9 | name = "ard808x_client"
10 | path = "src/lib.rs"
11 | crate-type = ["cdylib", "lib"]
12 |
13 | [dependencies]
14 | log.workspace = true
15 | serialport.workspace = true
16 |
--------------------------------------------------------------------------------
/crates/ard808x_client/LICENSE:
--------------------------------------------------------------------------------
1 | Arduino8088 Copyright 2022-2023 Daniel Balsom
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a
4 | copy of this software and associated documentation files (the “Software”),
5 | to deal in the Software without restriction, including without limitation
6 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | and/or sell copies of the Software, and to permit persons to whom the
8 | Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 | DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/crates/ard808x_client/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dbalsom/arduino808x/9bbe3f1384fdddb5ee8dc8532a96ee9fc237af02/crates/ard808x_client/README.md
--------------------------------------------------------------------------------
/crates/ard808x_cpu/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "ard808x_cpu"
3 | description = "A library crate that leverages the Arduino808x serial protocol to control an Intel 8088, 8086, NEC V20, or V30 CPU."
4 | version.workspace = true
5 | edition.workspace = true
6 | authors.workspace = true
7 | license.workspace = true
8 | repository.workspace = true
9 |
10 | [lib]
11 | name = "ard808x_cpu"
12 | path = "src/lib.rs"
13 | crate-type = ["cdylib", "lib"]
14 |
15 | [dependencies]
16 | ard808x_client = { path = "../ard808x_client" }
17 | env_logger.workspace = true
18 | log.workspace = true
19 |
--------------------------------------------------------------------------------
/crates/ard808x_cpu/LICENSE:
--------------------------------------------------------------------------------
1 | Arduino8088 Copyright 2022-2023 Daniel Balsom
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a
4 | copy of this software and associated documentation files (the “Software”),
5 | to deal in the Software without restriction, including without limitation
6 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | and/or sell copies of the Software, and to permit persons to whom the
8 | Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 | DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/crates/ard808x_cpu/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dbalsom/arduino808x/9bbe3f1384fdddb5ee8dc8532a96ee9fc237af02/crates/ard808x_cpu/README.md
--------------------------------------------------------------------------------
/crates/ard808x_cpu/examples/cpu_id.rs:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino8088 Copyright 2022-2025 Daniel Balsom
3 | https://github.com/dbalsom/arduino_8088
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a
6 | copy of this software and associated documentation files (the “Software”),
7 | to deal in the Software without restriction, including without limitation
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 | and/or sell copies of the Software, and to permit persons to whom the
10 | Software is furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 | DEALINGS IN THE SOFTWARE.
22 | */
23 | use ard808x_client::*;
24 | use ard808x_cpu::*;
25 |
26 | fn main() {
27 | env_logger::init();
28 |
29 | // Create a cpu_client connection to cpu_server.
30 | let mut cpu_client = match CpuClient::init(None) {
31 | Ok(ard_client) => {
32 | println!("Opened connection to Arduino_808X server!");
33 | ard_client
34 | }
35 | Err(e) => {
36 | eprintln!("Error connecting to Arduino_808X server: {e}");
37 | std::process::exit(1);
38 | }
39 | };
40 |
41 | match cpu_client.cpu_type() {
42 | Ok(cpu_id) => {
43 | println!("Detected CPU: {:?}", cpu_id);
44 | }
45 | Err(e) => {
46 | eprintln!("Error detecting CPU: {e}");
47 | std::process::exit(1);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/crates/ard808x_cpu/src/code_stream.rs:
--------------------------------------------------------------------------------
1 | use std::collections::VecDeque;
2 |
3 | use crate::queue::QueueDataType;
4 | use crate::opcodes::OPCODE_NOP;
5 | use ard808x_client::CpuWidth;
6 |
7 | pub struct CodeStream {
8 | width: CpuWidth,
9 | bytes: VecDeque<(u8, QueueDataType)>,
10 | }
11 |
12 | pub enum CodeStreamValue {
13 | Byte(u16, QueueDataType),
14 | Word(u16, QueueDataType, QueueDataType)
15 | }
16 |
17 | impl CodeStreamValue {
18 | pub fn bus_value(&self) -> u16 {
19 | match &self {
20 | CodeStreamValue::Byte(val, _) => *val,
21 | CodeStreamValue::Word(val, _, _) => *val
22 | }
23 | }
24 | }
25 |
26 | impl CodeStream {
27 | pub fn new(width: CpuWidth) -> Self {
28 | Self {
29 | width,
30 | bytes: Default::default(),
31 | }
32 | }
33 |
34 | pub fn push_byte(&mut self, data: u8, data_type: QueueDataType) {
35 | self.bytes.push_back((data, data_type))
36 | }
37 |
38 | pub fn push_word(&mut self, data: u16, data_type: QueueDataType) {
39 | let bytes = data.to_le_bytes();
40 | self.bytes.push_back((bytes[0], data_type));
41 | self.bytes.push_back((bytes[1], data_type));
42 | }
43 |
44 | pub fn len(&self) -> usize {
45 | self.bytes.len()
46 | }
47 |
48 | pub fn is_empty(&self) -> bool {
49 | self.len() == 0
50 | }
51 |
52 | pub fn have_complete_data(&self) -> bool {
53 | match self.width {
54 | CpuWidth::Eight => self.bytes.len() > 0,
55 | CpuWidth::Sixteen => self.bytes.len() > 1,
56 | }
57 | }
58 |
59 | /// Pop a value of the appropriate width from the code stream deque and return it, along with
60 | /// a tuple of data types. Overflows are filled with NOPs set to type Fill.
61 | pub fn pop_data_bus(&mut self) -> CodeStreamValue {
62 | match self.width {
63 |
64 | CpuWidth::Eight => {
65 | let byte0_val = self.bytes.pop_front().unwrap_or((OPCODE_NOP, QueueDataType::Fill));
66 | let bus_value = byte0_val.0 as u16;
67 |
68 | CodeStreamValue::Byte(bus_value, byte0_val.1)
69 | }
70 | CpuWidth::Sixteen => {
71 | let byte0_val = self.bytes.pop_front().unwrap_or((OPCODE_NOP, QueueDataType::Fill));
72 | let byte1_val = self.bytes.pop_front().unwrap_or((OPCODE_NOP, QueueDataType::Fill));
73 | let bus_value = (byte0_val.0 as u16) | ((byte1_val.0 as u16) << 8);
74 |
75 | CodeStreamValue::Word(bus_value, byte0_val.1, byte1_val.1)
76 | }
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/crates/ard808x_cpu/src/opcodes.rs:
--------------------------------------------------------------------------------
1 | pub const OPCODE_IRET: u8 = 0xCF;
2 | pub const OPCODE_NOP: u8 = 0x90;
3 | pub const OPCODE_NOPS: u16 = 0x9090;
4 | pub const OPCODE_NOP80: u8 = 0x00; // NOP for 8080
5 | pub const OPCODE_NOPS80: u16 = 0x0000; // NOP for 8080
6 | pub const OPCODE_NMI_TRIGGER: u8 = 0xF1; // Undefined opcode to use as NMI trigger
7 |
8 | /*
9 | #define MODRM_OP(M) (((M & 0b00111000) >> 3) & 0x07)
10 | #define IS_GRP_OP(O) ((OPCODE_REFS[O] >= GRP1) && (OPCODE_REFS[O] <= GRP2B))
11 | */
12 |
13 | pub enum DecodeArch {
14 | Intel8088,
15 | Intel8080,
16 | }
17 |
18 | macro_rules! modrm_op {
19 | ($m:expr) => {
20 | ((($m >> 3) & 0x07) as usize)
21 | };
22 | }
23 |
24 | pub fn is_prefix(op1: u8) -> bool {
25 | match op1 {
26 | 0x26 | 0x2E | 0x36 | 0x3E | 0xF0..=0xF3 => true,
27 | _ => false,
28 | }
29 | }
30 |
31 | pub fn is_group_op(op1: u8) -> bool {
32 | (OPCODE_REFS[op1 as usize] >= 105) && (OPCODE_REFS[op1 as usize] <= 110)
33 | }
34 |
35 | // Return the mnemonic string for the specified opcode. If the opcode is a group
36 | // opcode, op2 should be specified and modrm set to true.
37 | pub fn get_opcode_str(op1: u8, op2: u8, modrm: bool, decode_arch: DecodeArch) -> &'static str {
38 | let op_idx: usize = match decode_arch {
39 | DecodeArch::Intel8088 => OPCODE_REFS[op1 as usize],
40 | DecodeArch::Intel8080 => OPCODE_8080_REFS[op1 as usize],
41 | };
42 |
43 | if !modrm {
44 | // Just return primary opcode
45 | match decode_arch {
46 | DecodeArch::Intel8088 => {
47 | return OPCODE_STRS[op_idx];
48 | }
49 | DecodeArch::Intel8080 => {
50 | return OPCODE_8080_STRS[op_idx];
51 | }
52 | }
53 | } else {
54 | // modrm is in use, check if this is a group instruction...
55 | if is_group_op(op1) {
56 | // Lookup opcode group
57 | let grp_idx: usize = modrm_op!(op2);
58 |
59 | match OPCODE_REFS[op1 as usize] {
60 | GRP1 => OPCODE_STRS_GRP1[grp_idx],
61 | GRP2A => OPCODE_STRS_GRP2A[grp_idx],
62 | GRP2B => OPCODE_STRS_GRP2B[grp_idx],
63 | GRP3 => OPCODE_STRS_GRP3[grp_idx],
64 | GRP4 => OPCODE_STRS_GRP4[grp_idx],
65 | GRP5 => OPCODE_STRS_GRP5[grp_idx],
66 | _ => "ERROR",
67 | }
68 | } else {
69 | // Not a group instruction, just return as normal
70 | OPCODE_STRS[op_idx]
71 | }
72 | }
73 | }
74 |
75 | const GRP1: usize = 105;
76 | const GRP2A: usize = 106;
77 | const GRP2B: usize = 110;
78 | const GRP3: usize = 107;
79 | const GRP4: usize = 108;
80 | const GRP5: usize = 109;
81 |
82 | // LUT of primary opcode to Mnemonic (Or Group name)
83 | const OPCODE_REFS: [usize; 256] = [
84 | 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 1, 2, 4, 4, 4, 4, 4, 4, 1, 2, 5, 5, 5, 5, 5, 5, 1, 2,
85 | 6, 6, 6, 6, 6, 6, 7, 8, 9, 9, 9, 9, 9, 9, 10, 11, 12, 12, 12, 12, 12, 12, 13, 14, 15, 15, 15,
86 | 15, 15, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 1, 1, 1, 1,
87 | 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
88 | 35, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 105, 105, 105, 105, 36, 36,
89 | 37, 37, 38, 38, 38, 38, 38, 39, 38, 2, 111, 37, 37, 37, 37, 37, 37, 37, 40, 41, 42, 103, 43,
90 | 44, 45, 46, 38, 38, 38, 38, 47, 48, 49, 50, 36, 36, 51, 52, 53, 54, 55, 56, 38, 38, 38, 38, 38,
91 | 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 57, 57, 57, 57, 58, 59, 38, 38, 60, 60, 60, 60, 61,
92 | 61, 62, 63, 106, 106, 110, 110, 71, 73, 104, 75, 104, 104, 104, 104, 104, 104, 104, 104, 76,
93 | 77, 78, 79, 80, 80, 81, 81, 82, 83, 84, 83, 80, 80, 81, 81, 85, 104, 86, 87, 89, 90, 107, 107,
94 | 97, 98, 99, 100, 101, 102, 108, 109,
95 | ];
96 |
97 | const OPCODE_8080_REFS: [usize; 256] = [
98 | 0, 1, 2, 3, 4, 5, 6, 7, 80, 8, 9, 10, 4, 5, 6, 11, 80, 1, 2, 3, 4, 5, 6, 12, 80, 8, 9, 10, 4,
99 | 5, 6, 13, 80, 1, 14, 3, 4, 5, 6, 15, 80, 8, 16, 10, 4, 5, 6, 17, 80, 1, 18, 3, 4, 5, 6, 19, 80,
100 | 8, 20, 10, 4, 5, 6, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
101 | 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
102 | 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24,
103 | 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27,
104 | 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30,
105 | 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
106 | 42, 80, 43, 44, 45, 39, 46, 33, 47, 48, 49, 37, 50, 39, 51, 80, 52, 53, 54, 80, 55, 39, 56, 33,
107 | 57, 58, 59, 37, 60, 39, 61, 62, 63, 64, 65, 81, 68, 39, 69, 33, 70, 71, 72, 37, 73, 39, 74, 75,
108 | 76, 77, 78, 80, 79, 39,
109 | ];
110 |
111 | const OPCODE_STRS: &[&str] = &[
112 | "ADD", "PUSH", "POP", "OR", "ADC", "SBB", "AND", "ES", "DAA", "SUB", "CS", "DAS", "XOR", "SS",
113 | "AAA", "CMP", "DS", "AAS", "INC", "DEC", "JO", "JNO", "JB", "JNB", "JZ", "JNZ", "JBE", "JNBE",
114 | "JS", "JNS", "JP", "JNP", "JL", "JNL", "JLE", "JNLE", "TEST", "XCHG", "MOV", "LEA", "CBW",
115 | "CWD", "CALLF", "PUSHF", "POPF", "SAHF", "LAHF", "MOVSB", "MOVSW", "CMPSB", "CMPSW", "STOSB",
116 | "STOSW", "LODSB", "LODSW", "SCASB", "SCASW", "RETN", "LES", "LDS", "RETF", "INT", "INTO",
117 | "IRET", "ROL", "ROR", "RCL", "RCR", "SHL", "SHR", "SAR", "AAM", "AMX", "AAD", "ADX", "XLAT",
118 | "LOOPNE", "LOOPE", "LOOP", "JCXZ", "IN", "OUT", "CALL", "JMP", "JMPF", "LOCK", "REPNZ", "REP",
119 | "REPZ", "HLT", "CMC", "NOT", "NEG", "MUL", "IMUL", "DIV", "IDIV", "CLC", "STC", "CLI", "STI",
120 | "CLD", "STD", "WAIT", "INVAL", "GRP1", "GRP2A", "GRP3", "GRP4", "GRP5", "GRP2B", "NOP",
121 | ];
122 |
123 | // 0x80 - 0x81
124 | const OPCODE_STRS_GRP1: &[&str] = &["ADD", "OR", "ADC", "SBB", "AND", "SUB", "XOR", "CMP"];
125 |
126 | // 0xD0 - 0xD1
127 | const OPCODE_STRS_GRP2A: &[&str] = &["ROL", "ROR", "RCL", "RCR", "SHL", "SHR", "SETMO", "SAR"];
128 |
129 | // 0xD2 - 0xD3
130 | const OPCODE_STRS_GRP2B: &[&str] = &["ROL", "ROR", "RCL", "RCR", "SHL", "SHR", "SETMOC", "SAR"];
131 |
132 | // 0xF6 - 0xF7
133 | const OPCODE_STRS_GRP3: &[&str] = &["TEST", "TEST", "NOT", "NEG", "MUL", "IMUL", "DIV", "IDIV"];
134 |
135 | // 0xFE
136 | const OPCODE_STRS_GRP4: &[&str] = &[
137 | "INC", "DEC", "INVAL", "INVAL", "INVAL", "INVAL", "INVAL", "INVAL",
138 | ];
139 |
140 | // 0xFF
141 | const OPCODE_STRS_GRP5: &[&str] = &[
142 | "INC", "DEC", "CALL", "CALLF", "JMP", "JMPF", "PUSH", "INVAL",
143 | ];
144 |
145 | const OPCODE_8080_STRS: &[&str] = &[
146 | "NOP", "LXI", "STAX", "INX", "INR", "DCR", "MVI", "RLC", "DAD", "LDAX", "DCX", "RRC", "RAL",
147 | "RAR", "SHLD", "DAA", "LHLD", "CMA", "STA", "STC", "LDA", "CMC", "MOV", "HLT", "ADD", "ADC",
148 | "SUB", "SBB", "ANA", "XRA", "ORA", "CMP", "RNZ", "POP", "JNZ", "JMP", "CNZ", "PUSH", "ADI",
149 | "RST", "RZ", "RET", "JZ", "CZ", "CALL", "ACI", "RNC", "JNC", "OUT", "CNC", "SUI", "RC", "JC",
150 | "IN", "CC", "SBI", "RPO", "JPO", "XTHL", "CPO", "ANI", "RPE", "PCHL", "JPE", "XCHG", "CPE",
151 | "CALLN", "RETEM", "XRI", "RP", "JP", "DI", "CP", "ORI", "RM", "SPHL", "JM", "EI", "CM", "CPI",
152 | "INVAL", "SPECIAL",
153 | ];
154 |
--------------------------------------------------------------------------------
/crates/ard808x_cpu/src/queue.rs:
--------------------------------------------------------------------------------
1 | use ard808x_client::{CpuWidth, DataWidth};
2 |
3 | #[derive (Copy, Clone, PartialEq)]
4 | pub enum QueueDataType {
5 | Preload,
6 | EmuEnter,
7 | Program,
8 | EmuExit,
9 | Finalize,
10 | Fill,
11 | }
12 |
13 | #[derive (Copy, Clone)]
14 | pub struct QueueEntry {
15 | opcode: u8,
16 | dtype: QueueDataType,
17 | addr: u32
18 | }
19 |
20 | pub struct InstructionQueue {
21 | width: CpuWidth,
22 | size: usize,
23 | len: usize,
24 | back: usize,
25 | front: usize,
26 | q: Vec,
27 | }
28 |
29 | impl InstructionQueue {
30 | pub fn new(width: CpuWidth) -> Self {
31 | Self {
32 | width,
33 | size: width.queue_size(),
34 | len: 0,
35 | back: 0,
36 | front: 0,
37 | q: vec![
38 | QueueEntry {
39 | opcode: 0,
40 | dtype: QueueDataType::Program,
41 | addr: 0,
42 | }; width.queue_size()
43 | ],
44 | }
45 | }
46 |
47 | pub fn len(&self) -> usize {
48 | self.len
49 | }
50 |
51 | pub fn size(&self) -> usize {
52 | self.size
53 | }
54 |
55 | pub fn has_room(&self) -> bool {
56 | self.len() + usize::from(self.width) <= self.size
57 | }
58 |
59 | pub fn push(&mut self, data: u16, width: DataWidth, dtype: QueueDataType, addr: u32) {
60 | if self.has_room() {
61 | match width {
62 | DataWidth::EightHigh => {
63 | self.q[self.front] = QueueEntry {
64 | opcode: (data >> 8) as u8,
65 | dtype,
66 | addr
67 | };
68 | self.front = (self.front + 1) % self.size;
69 | self.len += 1;
70 | }
71 | DataWidth::Sixteen => {
72 | self.q[self.front] = QueueEntry {
73 | opcode: data as u8,
74 | dtype,
75 | addr
76 | };
77 | self.front = (self.front + 1) % self.size;
78 | self.q[self.front] = QueueEntry {
79 | opcode: (data >> 8) as u8,
80 | dtype,
81 | addr
82 | };
83 | self.front = (self.front + 1) % self.size;
84 | self.len += 2;
85 | }
86 | _ => {
87 | log::error!("Bad DataWidth for queue push: {:?}", width);
88 | }
89 | }
90 | }
91 | else {
92 | //panic!("Queue overrun!");
93 | log::error!("Queue overrun!");
94 | }
95 | }
96 |
97 | pub fn pop(&mut self) -> (u8, QueueDataType, u32) {
98 | if self.len > 0 {
99 | let q_entry = self.q[self.back];
100 | //let dt = self.dt[self.back];
101 |
102 | self.back = (self.back + 1) % self.size;
103 | self.len -= 1;
104 |
105 | return (q_entry.opcode, q_entry.dtype, q_entry.addr)
106 | }
107 |
108 | panic!("Queue underrun!");
109 | }
110 |
111 | pub fn flush(&mut self) {
112 | self.len = 0;
113 | self.back = 0;
114 | self.front = 0;
115 | }
116 |
117 | pub fn to_string(&self) -> String {
118 |
119 | let mut base_str = "".to_string();
120 |
121 | for i in 0..self.len {
122 | base_str.push_str(&format!("{:02X}", self.q[(self.back + i) % self.size].opcode));
123 | }
124 | base_str
125 | }
126 |
127 |
128 | }
--------------------------------------------------------------------------------
/crates/ard808x_cpu/src/remote_program.rs:
--------------------------------------------------------------------------------
1 |
2 | use std::io::{Cursor, Read, Seek, SeekFrom};
3 | use crate::opcodes::OPCODE_NOP;
4 | use crate::queue::QueueDataType;
5 | use crate::code_stream::CodeStream;
6 | use ard808x_client::CpuWidth;
7 |
8 | pub struct RemoteProgram {
9 | pub(crate) bytes: Cursor>,
10 | fill_byte: u8,
11 | width: CpuWidth,
12 | used_fill: bool,
13 | }
14 |
15 | impl RemoteProgram {
16 | pub fn new(data: &[u8], fill_byte: u8, width: CpuWidth) -> Self {
17 | Self {
18 | bytes: Cursor::new(data.to_vec()),
19 | fill_byte,
20 | width,
21 | used_fill: false,
22 | }
23 | }
24 |
25 | pub fn program_remaining(&self) -> usize {
26 | let pos = self.bytes.position() as usize;
27 | let len = self.bytes.get_ref().len();
28 | len.saturating_sub(pos)
29 | }
30 |
31 | #[inline]
32 | pub fn is_finished(&self) -> bool {
33 | self.program_remaining() == 0
34 | }
35 |
36 | #[inline]
37 | pub fn set_fill(&mut self, byte: u8) {
38 | self.fill_byte = byte;
39 | }
40 |
41 | // Read the program into a CodeStream.
42 | pub fn read_program(&mut self, a0: bool, stream: &mut CodeStream, data_type: QueueDataType ) -> usize {
43 | match self.width {
44 | CpuWidth::Eight => {
45 | let mut buf = [0u8; 1];
46 | if let Ok(_) = self.bytes.read_exact(&mut buf) {
47 | stream.push_byte(buf[0], data_type);
48 | }
49 | 1
50 | }
51 | CpuWidth::Sixteen => {
52 | let mut buf = [0u8; 2];
53 |
54 | if a0 == false {
55 | // Even address. Read normally.
56 | match self.bytes.read_exact(&mut buf) {
57 | Ok(_) => {
58 | // There were two bytes left, push the word.
59 | stream.push_word(u16::from_le_bytes(buf), data_type);
60 | 2
61 | },
62 | Err(_) => {
63 | // Fewer than two bytes remaining...
64 | if self.program_remaining() == 1 {
65 | // Only one byte left, read it.
66 | if let Ok(_) = self.bytes.read_exact(&mut buf[..1]) {
67 | stream.push_byte(buf[0], data_type);
68 | 1
69 | }
70 | else {
71 | 0
72 | }
73 | } else {
74 | // No bytes left!
75 | log::trace!("read_program(): no more bytes!");
76 | 0
77 | }
78 | }
79 | }
80 | }
81 | else {
82 | // Odd address... provide a dummy byte if at start of program
83 | // We must have at least 1 byte in the program to do this
84 | if self.program_remaining() == 1 {
85 | if self.bytes.position() == 0 {
86 | stream.push_byte(OPCODE_NOP, QueueDataType::Fill);
87 | }
88 | else {
89 | // Seek backwards 1
90 | _ = self.bytes.seek(SeekFrom::Current(-1));
91 | let mut buf = [0u8; 1];
92 | if let Ok(_) = self.bytes.read_exact(&mut buf) {
93 | stream.push_byte(buf[0], data_type);
94 | }
95 | }
96 | // Read the second byte
97 | let mut buf = [0u8; 1];
98 | if let Ok(_) = self.bytes.read_exact(&mut buf) {
99 | stream.push_byte(buf[0], data_type);
100 | 1
101 | }
102 | else {
103 | 0
104 | }
105 | }
106 | else {
107 | // No bytes left!
108 | log::trace!("read_program(): no more bytes!");
109 | 0
110 | }
111 | }
112 | }
113 | }
114 | }
115 |
116 | /// Get the fill count - this will either be 0 or 1. This can be used to instruct
117 | /// the CPU server to adjust IP in the store program
118 | pub fn get_fill_ct(&self) -> usize {
119 | if self.used_fill { 1 } else { 0 }
120 | }
121 |
122 | /// Rewinds the program to the start.
123 | pub fn reset(&mut self) {
124 | self.bytes.set_position(0);
125 | self.used_fill = false;
126 | }
127 |
128 | /// Returns the total length of the program in bytes.
129 | pub fn len(&self) -> usize {
130 | self.bytes.get_ref().len()
131 | }
132 |
133 |
134 |
135 | }
--------------------------------------------------------------------------------
/crates/ard808x_cpu/tests/aaa.rs:
--------------------------------------------------------------------------------
1 | use ard808x_client::*;
2 | use ard808x_cpu::*;
3 |
4 | #[derive(Copy, Clone)]
5 | pub struct AaaResult {
6 | ax: u16,
7 | flags: u16,
8 | of: bool,
9 | sf: bool,
10 | zf: bool,
11 | pf: bool,
12 | }
13 |
14 | #[test]
15 | fn test_aaa() {
16 | // Create a cpu_client connection to cpu_server.
17 |
18 | let mut results = [AaaResult {
19 | ax: 0,
20 | flags: 0,
21 | of: false,
22 | sf: false,
23 | zf: false,
24 | pf: false,
25 | }; 512];
26 |
27 | let cpu_client = match CpuClient::init() {
28 | Ok(ard_client) => {
29 | println!("Opened connection to Arduino_8088 server!");
30 | ard_client
31 | }
32 | Err(e) => {
33 | eprintln!("Error connecting to Arduino_8088 server: {e}");
34 | std::process::exit(1);
35 | }
36 | };
37 |
38 | // Create a remote cpu instance using the cpu_client which should now be connected.
39 | let mut cpu = RemoteCpu::new(CpuType::Intel8088, cpu_client, false, false, 0, 0, 0, 0);
40 |
41 | let cf = true;
42 |
43 | for af in 0..2 {
44 | for i in 0..256 {
45 | //println!("i:{}", i);
46 | let mut regs = RemoteCpuRegisters {
47 | ax: i as u16,
48 | bx: 0,
49 | cx: 0,
50 | dx: 0,
51 | ss: 0,
52 | ds: 0,
53 | es: 0,
54 | sp: 0xFFFF,
55 | bp: 0,
56 | si: 0,
57 | di: 0,
58 | cs: 0xF000,
59 | ip: 0x0000,
60 | flags: 0,
61 | };
62 |
63 | regs.flags &= !CPU_FLAG_AUX_CARRY;
64 |
65 | if cf {
66 | regs.flags |= CPU_FLAG_CARRY;
67 | }
68 |
69 | if af == 1 {
70 | regs.flags |= CPU_FLAG_AUX_CARRY;
71 | }
72 |
73 | // Load the registers from struct
74 | let result = cpu.load_registers_from_struct(®s);
75 | if result {
76 | log::trace!("Successfully set up registers!");
77 |
78 | // Load opcode into memory at cs:ip
79 | let pc = (regs.cs as usize) << 4 + regs.ip as usize;
80 | cpu.write_u8(pc, 0x37); // AAA
81 | cpu.set_program_bounds(pc, pc + 1);
82 |
83 | cpu.test();
84 | match cpu.run(Some(100), &PrintOptions::default()) {
85 | Ok(regs) => {
86 | let idx = i + (256 * af);
87 | println!("idx: {}", idx);
88 | results[idx].ax = regs.ax;
89 | results[idx].flags = regs.flags;
90 | results[idx].of = regs.flags & CPU_FLAG_OVERFLOW != 0;
91 | results[idx].sf = regs.flags & CPU_FLAG_SIGN != 0;
92 | results[idx].zf = regs.flags & CPU_FLAG_ZERO != 0;
93 | results[idx].pf = regs.flags & CPU_FLAG_PARITY != 0;
94 | //RemoteCpu::print_regs(®s);
95 | }
96 | Err(_) => {
97 | log::error!("Program execution failed!");
98 | }
99 | }
100 | } else {
101 | log::error!("Register setup failed: {}", cpu.get_last_error());
102 | }
103 | }
104 | }
105 |
106 | for i in 0..256 {
107 | println!(
108 | "{:04X} (af==0): ax: {:04X} flags: {:04X} of: {} sf: {} zf: {} pf: {}",
109 | i & 0xFF,
110 | results[i].ax,
111 | results[i].flags,
112 | results[i].of,
113 | results[i].sf,
114 | results[i].zf,
115 | results[i].pf
116 | );
117 | }
118 | for i in 256..512 {
119 | println!(
120 | "{:04X} (af==1): ax: {:04X} flags: {:04X} of: {} sf: {} zf: {} pf: {}",
121 | i & 0xFF,
122 | results[i].ax,
123 | results[i].flags,
124 | results[i].of,
125 | results[i].sf,
126 | results[i].zf,
127 | results[i].pf
128 | );
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/crates/ard808x_cpu/tests/aas.rs:
--------------------------------------------------------------------------------
1 | use ard808x_client::*;
2 | use ard808x_cpu::*;
3 |
4 | #[derive(Copy, Clone)]
5 | pub struct AasResult {
6 | ax: u16,
7 | flags: u16,
8 | of: bool,
9 | sf: bool,
10 | zf: bool,
11 | pf: bool,
12 | }
13 |
14 | #[test]
15 | fn test_aas() {
16 | // Create a cpu_client connection to cpu_server.
17 |
18 | let mut results = [AasResult {
19 | ax: 0,
20 | flags: 0,
21 | of: false,
22 | sf: false,
23 | zf: false,
24 | pf: false,
25 | }; 512];
26 |
27 | let cpu_client = match CpuClient::init() {
28 | Ok(ard_client) => {
29 | println!("Opened connection to Arduino_8088 server!");
30 | ard_client
31 | }
32 | Err(e) => {
33 | eprintln!("Error connecting to Arduino_8088 server: {e}");
34 | std::process::exit(1);
35 | }
36 | };
37 |
38 | // Create a remote cpu instance using the cpu_client which should now be connected.
39 | let mut cpu = RemoteCpu::new(CpuType::Intel8088, cpu_client, false, false, 0, 0, 0, 0);
40 |
41 | let cf = true;
42 |
43 | for af in 0..2 {
44 | for i in 0..256 {
45 | //println!("i:{}", i);
46 | let mut regs = RemoteCpuRegisters {
47 | ax: i as u16,
48 | bx: 0,
49 | cx: 0,
50 | dx: 0,
51 | ss: 0,
52 | ds: 0,
53 | es: 0,
54 | sp: 0xFFFF,
55 | bp: 0,
56 | si: 0,
57 | di: 0,
58 | cs: 0xF000,
59 | ip: 0x0000,
60 | flags: 0,
61 | };
62 |
63 | regs.flags &= !CPU_FLAG_AUX_CARRY;
64 |
65 | if cf {
66 | regs.flags |= CPU_FLAG_CARRY;
67 | }
68 |
69 | if af == 1 {
70 | regs.flags |= CPU_FLAG_AUX_CARRY;
71 | }
72 |
73 | // Load the registers from struct
74 | let result = cpu.load_registers_from_struct(®s);
75 | if result {
76 | log::trace!("Successfully set up registers!");
77 |
78 | // Load opcode into memory at cs:ip
79 | let pc = (regs.cs as usize) << 4 + regs.ip as usize;
80 | cpu.write_u8(pc, 0x3F); // AAS
81 | cpu.set_program_bounds(pc, pc + 1);
82 |
83 | cpu.test();
84 | match cpu.run(Some(100), &PrintOptions::default()) {
85 | Ok(regs) => {
86 | let idx = i + (256 * af);
87 | println!("idx: {}", idx);
88 | results[idx].ax = regs.ax;
89 | results[idx].flags = regs.flags;
90 | results[idx].of = regs.flags & CPU_FLAG_OVERFLOW != 0;
91 | results[idx].sf = regs.flags & CPU_FLAG_SIGN != 0;
92 | results[idx].zf = regs.flags & CPU_FLAG_ZERO != 0;
93 | results[idx].pf = regs.flags & CPU_FLAG_PARITY != 0;
94 | //RemoteCpu::print_regs(®s);
95 | }
96 | Err(_) => {
97 | log::error!("Program execution failed!");
98 | }
99 | }
100 | } else {
101 | log::error!("Register setup failed: {}", cpu.get_last_error());
102 | }
103 | }
104 | }
105 |
106 | for i in 0..256 {
107 | println!(
108 | "{:04X} (af==0): ax: {:04X} flags: {:04X} of: {} sf: {} zf: {} pf: {}",
109 | i & 0xFF,
110 | results[i].ax,
111 | results[i].flags,
112 | results[i].of,
113 | results[i].sf,
114 | results[i].zf,
115 | results[i].pf
116 | );
117 | }
118 | for i in 256..512 {
119 | println!(
120 | "{:04X} (af==1): ax: {:04X} flags: {:04X} of: {} sf: {} zf: {} pf: {}",
121 | i & 0xFF,
122 | results[i].ax,
123 | results[i].flags,
124 | results[i].of,
125 | results[i].sf,
126 | results[i].zf,
127 | results[i].pf
128 | );
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/crates/ard808x_cpu/tests/daa.rs:
--------------------------------------------------------------------------------
1 | use ard808x_client::*;
2 | use ard808x_cpu::*;
3 |
4 | #[derive(Copy, Clone)]
5 | pub struct DaaResult {
6 | ax: u16,
7 | flags: u16,
8 | af: bool,
9 | cf: bool,
10 | of: bool,
11 | }
12 |
13 | pub fn daa(mut al: u8, mut af: bool, mut cf: bool) -> (u8, bool, bool) {
14 | let old_al = al;
15 | //let mut temp16 = al as u16;
16 | let old_cf = cf;
17 |
18 | if (al & 0x0F) > 9 || af {
19 | //temp16 = (self.al as u16).wrapping_add(6);
20 | // self.set_register8(Register8::AL, (temp16 & 0xFF) as u8);
21 | al = al.wrapping_add(6);
22 |
23 | // Set carry flag on overflow from AL + 6
24 | //self.set_flag_state(Flag::Carry, old_cf || temp16 & 0xFF00 != 0);
25 | af = true;
26 | } else {
27 | af = false;
28 | }
29 |
30 | // Different sources show this value 0x99 or 0x9F, does it matter?
31 | // Current intel documents show 0x99
32 | if (old_al > 0x99) || old_cf {
33 | //self.set_register8(Register8::AL, temp16.wrapping_add(0x60) as u8);
34 | al = al.wrapping_add(0x60);
35 | cf = true;
36 | } else {
37 | cf = false;
38 | }
39 |
40 | //self.set_szp_flags_from_result_u8(self.al);
41 |
42 | (al, af, cf)
43 | }
44 |
45 | #[test]
46 | fn test_daa() {
47 | // Create a cpu_client connection to cpu_server.
48 |
49 | let mut results = [DaaResult {
50 | ax: 0,
51 | flags: 0,
52 | af: false,
53 | cf: false,
54 | of: false,
55 | }; 512];
56 |
57 | let cpu_client = match CpuClient::init() {
58 | Ok(ard_client) => {
59 | println!("Opened connection to Arduino_8088 server!");
60 | ard_client
61 | }
62 | Err(e) => {
63 | eprintln!("Error connecting to Arduino_8088 server: {e}");
64 | std::process::exit(1);
65 | }
66 | };
67 |
68 | // Create a remote cpu instance using the cpu_client which should now be connected.
69 | let mut cpu = RemoteCpu::new(CpuType::Intel8088, cpu_client, false, false, 0, 0, 0, 0);
70 |
71 | let cf = true;
72 |
73 | for af in 0..2 {
74 | for i in 0..256 {
75 | //println!("i:{}", i);
76 | let mut regs = RemoteCpuRegisters {
77 | ax: i as u16,
78 | bx: 0,
79 | cx: 0,
80 | dx: 0,
81 | ss: 0,
82 | ds: 0,
83 | es: 0,
84 | sp: 0xFFFF,
85 | bp: 0,
86 | si: 0,
87 | di: 0,
88 | cs: 0xF000,
89 | ip: 0x0000,
90 | flags: 0,
91 | };
92 |
93 | regs.flags &= !CPU_FLAG_AUX_CARRY;
94 |
95 | if cf {
96 | regs.flags |= CPU_FLAG_CARRY;
97 | }
98 |
99 | if af == 1 {
100 | regs.flags |= CPU_FLAG_AUX_CARRY;
101 | }
102 |
103 | // Load the registers from struct
104 | let result = cpu.load_registers_from_struct(®s);
105 | if result {
106 | log::trace!("Successfully set up registers!");
107 |
108 | // Load opcode into memory at cs:ip
109 | let pc = (regs.cs as usize) << 4 + regs.ip as usize;
110 | cpu.write_u8(pc, 0x27); // DAA
111 | cpu.set_program_bounds(pc, pc + 1);
112 |
113 | cpu.test();
114 | match cpu.run(Some(100), &PrintOptions::default()) {
115 | Ok(regs) => {
116 | let idx = i + (256 * af);
117 | println!("idx: {}", idx);
118 | results[idx].ax = regs.ax;
119 | results[idx].flags = regs.flags;
120 | results[idx].af = regs.flags & CPU_FLAG_AUX_CARRY != 0;
121 | results[idx].cf = regs.flags & CPU_FLAG_CARRY != 0;
122 | results[idx].of = regs.flags & CPU_FLAG_OVERFLOW != 0;
123 | //RemoteCpu::print_regs(®s);
124 | }
125 | Err(_) => {
126 | log::error!("Program execution failed!");
127 | }
128 | }
129 | } else {
130 | log::error!("Register setup failed: {}", cpu.get_last_error());
131 | }
132 | }
133 | }
134 |
135 | for i in 0..256 {
136 | let (d_al, d_cf, d_af) = daa((i & 0xFF) as u8, false, cf);
137 | println!("{:04X} (af==0): ax: {:04X} flags: {:04X} af: {} cf: {} of: {} | daa(): ax: {:04x} af: {} cf:{} of: {}",
138 | i & 0xFF,
139 | results[i].ax,
140 | results[i].flags,
141 | results[i].af,
142 | results[i].cf,
143 | results[i].of,
144 | d_al as u16,
145 | d_af,
146 | d_cf,
147 | false
148 | );
149 | }
150 | for i in 256..512 {
151 | let (d_al, d_cf, d_af) = daa((i & 0xFF) as u8, true, cf);
152 | println!("{:04X} (af==1): ax: {:04X} flags: {:04X} af: {} cf: {} of: {} | daa(): ax: {:04x} af: {} cf:{} of: {}",
153 | i & 0xFF,
154 | results[i].ax,
155 | results[i].flags,
156 | results[i].af,
157 | results[i].cf,
158 | results[i].of,
159 | d_al as u16,
160 | d_af,
161 | d_cf,
162 | false
163 | );
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/crates/ard808x_cpu/tests/das.rs:
--------------------------------------------------------------------------------
1 | use ard808x_client::*;
2 | use ard808x_cpu::*;
3 |
4 | #[derive(Copy, Clone)]
5 | pub struct DasResult {
6 | ax: u16,
7 | flags: u16,
8 | af: bool,
9 | cf: bool,
10 | of: bool,
11 | }
12 |
13 | #[test]
14 | fn test_das() {
15 | // Create a cpu_client connection to cpu_server.
16 |
17 | let mut results = [DasResult {
18 | ax: 0,
19 | flags: 0,
20 | af: false,
21 | cf: false,
22 | of: false,
23 | }; 512];
24 |
25 | let cpu_client = match CpuClient::init() {
26 | Ok(ard_client) => {
27 | println!("Opened connection to Arduino_8088 server!");
28 | ard_client
29 | }
30 | Err(e) => {
31 | eprintln!("Error connecting to Arduino_8088 server: {e}");
32 | std::process::exit(1);
33 | }
34 | };
35 |
36 | // Create a remote cpu instance using the cpu_client which should now be connected.
37 | let mut cpu = RemoteCpu::new(CpuType::Intel8088, cpu_client, false, false, 0, 0, 0, 0);
38 |
39 | let cf = true;
40 |
41 | for af in 0..2 {
42 | for i in 0..256 {
43 | //println!("i:{}", i);
44 | let mut regs = RemoteCpuRegisters {
45 | ax: i as u16,
46 | bx: 0,
47 | cx: 0,
48 | dx: 0,
49 | ss: 0,
50 | ds: 0,
51 | es: 0,
52 | sp: 0xFFFF,
53 | bp: 0,
54 | si: 0,
55 | di: 0,
56 | cs: 0xF000,
57 | ip: 0x0000,
58 | flags: 0,
59 | };
60 |
61 | regs.flags &= !CPU_FLAG_AUX_CARRY;
62 |
63 | if cf {
64 | regs.flags |= CPU_FLAG_CARRY;
65 | }
66 |
67 | if af == 1 {
68 | regs.flags |= CPU_FLAG_AUX_CARRY;
69 | }
70 |
71 | // Load the registers from struct
72 | let result = cpu.load_registers_from_struct(®s);
73 | if result {
74 | log::trace!("Successfully set up registers!");
75 |
76 | // Load opcode into memory at cs:ip
77 | let pc = (regs.cs as usize) << 4 + regs.ip as usize;
78 | cpu.write_u8(pc, 0x2F); // DAS
79 | cpu.set_program_bounds(pc, pc + 1);
80 |
81 | cpu.test();
82 | match cpu.run(Some(100), &PrintOptions::default()) {
83 | Ok(regs) => {
84 | let idx = i + (256 * af);
85 | println!("idx: {}", idx);
86 | results[idx].ax = regs.ax;
87 | results[idx].flags = regs.flags;
88 | results[idx].af = regs.flags & CPU_FLAG_AUX_CARRY != 0;
89 | results[idx].cf = regs.flags & CPU_FLAG_CARRY != 0;
90 | results[idx].of = regs.flags & CPU_FLAG_OVERFLOW != 0;
91 | //RemoteCpu::print_regs(®s);
92 | }
93 | Err(_) => {
94 | log::error!("Program execution failed!");
95 | }
96 | }
97 | } else {
98 | log::error!("Register setup failed: {}", cpu.get_last_error());
99 | }
100 | }
101 | }
102 |
103 | for i in 0..256 {
104 | println!(
105 | "{:04X} (af==0): ax: {:04X} flags: {:04X} af: {} cf: {} of: {}",
106 | i & 0xFF,
107 | results[i].ax,
108 | results[i].flags,
109 | results[i].af,
110 | results[i].cf,
111 | results[i].of
112 | );
113 | }
114 | for i in 256..512 {
115 | println!(
116 | "{:04X} (af==1): ax: {:04X} flags: {:04X} af: {} cf: {} of: {}",
117 | i & 0xFF,
118 | results[i].ax,
119 | results[i].flags,
120 | results[i].af,
121 | results[i].cf,
122 | results[i].of
123 | );
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/crates/ard808x_cpu/tests/flags.rs:
--------------------------------------------------------------------------------
1 | use ard808x_client::*;
2 | use ard808x_cpu::*;
3 |
4 | #[test]
5 | fn test_flag_init() {
6 | // Create a cpu_client connection to cpu_server.
7 | let cpu_client = match CpuClient::init() {
8 | Ok(ard_client) => {
9 | println!("Opened connection to Arduino_8088 server!");
10 | ard_client
11 | }
12 | Err(e) => {
13 | eprintln!("Error connecting to Arduino_8088 server: {e}");
14 | std::process::exit(1);
15 | }
16 | };
17 |
18 | // Create a remote cpu instance using the cpu_client which should now be connected.
19 | let mut cpu = RemoteCpu::new(CpuType::Intel8088, cpu_client, false, false, 0, 0, 0, 0);
20 |
21 | let regs = RemoteCpuRegisters {
22 | ax: 0,
23 | bx: 0,
24 | cx: 0,
25 | dx: 0,
26 | ss: 0,
27 | ds: 0,
28 | es: 0,
29 | sp: 0xFFFF,
30 | bp: 0,
31 | si: 0,
32 | di: 0,
33 | cs: 0xF000,
34 | ip: 0x0000,
35 | flags: 0xF002,
36 | };
37 |
38 | // Load the registers from struct
39 | let result = cpu.load_registers_from_struct(®s);
40 | if result {
41 | log::trace!("Successfully set up registers!");
42 |
43 | // Load opcode into memory at cs:ip
44 | let pc = (regs.cs as usize) << 4 + regs.ip as usize;
45 | cpu.write_u8(pc, 0x90); // NOP
46 | cpu.set_program_bounds(pc, pc + 1);
47 |
48 | cpu.test();
49 | match cpu.run(Some(100), &PrintOptions::default()) {
50 | Ok(regs) => {
51 | println!("Flags: {:04X}", regs.flags);
52 | }
53 | Err(_) => {
54 | log::error!("Program execution failed!");
55 | }
56 | }
57 | } else {
58 | log::error!("Register setup failed: {}", cpu.get_last_error());
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/crates/exec_program/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "exec_program"
3 | description = "A utility to execute arbitrary code on an Intel 8088, 8086, NEC V20, or V30 CPU via an Arduino DUE."
4 | version.workspace = true
5 | edition.workspace = true
6 | authors.workspace = true
7 | license.workspace = true
8 | repository.workspace = true
9 |
10 | [[bin]]
11 | name = "exec_program"
12 | path = "src/main.rs"
13 |
14 | [dependencies]
15 | clap = { workspace = true, features = ["derive"] }
16 | ard808x_cpu = { path = "../ard808x_cpu" }
17 | env_logger.workspace = true
18 | log.workspace = true
--------------------------------------------------------------------------------
/crates/exec_program/LICENSE:
--------------------------------------------------------------------------------
1 | Arduino8088 Copyright 2022-2023 Daniel Balsom
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a
4 | copy of this software and associated documentation files (the “Software”),
5 | to deal in the Software without restriction, including without limitation
6 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | and/or sell copies of the Software, and to permit persons to whom the
8 | Software is furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 | DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/crates/exec_program/src/main.rs:
--------------------------------------------------------------------------------
1 | use std::path::PathBuf;
2 |
3 | use ard808x_client::*;
4 | use ard808x_cpu::ard808x_client;
5 | use ard808x_cpu::*;
6 | use clap::Parser;
7 |
8 | #[derive(Parser, Debug)]
9 | #[command(author, version, about, long_about = None)]
10 | struct Args {
11 | #[arg(long)]
12 | com_port: Option,
13 |
14 | // The binary file containing the register data. Produced from an assembly
15 | // file 'program_regs.asm'
16 | #[arg(long, required(true))]
17 | reg_file: PathBuf,
18 |
19 | // The binary file containing the code to execute.
20 | #[arg(long, required(true))]
21 | bin_file: PathBuf,
22 |
23 | // Specify the address in memory to mount the bin file. This should typically
24 | // match the address specified by CS:IP, but doesn't have to...
25 | #[arg(long, required(true))]
26 | mount_addr: String,
27 |
28 | // Specify the number of wait states for every bus transfer.
29 | // TODO: Currently no division between memory and IO, should change...
30 | #[arg(long, default_value_t = 0)]
31 | wait_states: u32,
32 |
33 | // Enter 8080 emulation mode. Must have a compatible CPU such as a V20/V30.
34 | #[arg(long, default_value_t = false)]
35 | emu8080: bool,
36 |
37 | // Fill the prefetch queue before executing code.
38 | #[arg(long, default_value_t = false)]
39 | prefetch: bool,
40 |
41 | // Raise the INTR line on N cycles after HLT.
42 | #[arg(long, default_value_t = 0)]
43 | intr_after: u32,
44 |
45 | // Raise the INTR line on the specified cycle #.
46 | #[arg(long, default_value_t = 0)]
47 | intr_on: u32,
48 |
49 | // Raise the NMI line on the specified cycle #.
50 | #[arg(long, default_value_t = 0)]
51 | nmi_on: u32,
52 | }
53 |
54 | fn main() {
55 | env_logger::init();
56 |
57 | let args = Args::parse();
58 |
59 | // Parse commandline arguments
60 | let reg_bytes = std::fs::read(args.reg_file.clone()).unwrap_or_else(|e| {
61 | eprintln!("Couldn't read register file {:?}: {}", args.reg_file, e);
62 | std::process::exit(1);
63 | });
64 |
65 | let bin_bytes = std::fs::read(args.bin_file.clone()).unwrap_or_else(|e| {
66 | eprintln!("Couldn't read binary file {:?}: {}", args.bin_file, e);
67 | std::process::exit(1);
68 | });
69 |
70 | let mount_addr = u32::from_str_radix(&args.mount_addr, 16).unwrap_or_else(|e| {
71 | eprintln!(
72 | "Couldn't parse code mount address '{}': {}",
73 | args.mount_addr, e
74 | );
75 | std::process::exit(1);
76 | });
77 |
78 | if (mount_addr as usize) > (0xFFFFFusize - bin_bytes.len()) {
79 | eprintln!("Specified mount point out of range.");
80 | std::process::exit(1);
81 | }
82 |
83 | // Create a cpu_client connection to cpu_server.
84 | let cpu_client = match CpuClient::init(args.com_port.clone()) {
85 | Ok(ard_client) => {
86 | println!("Opened connection to Arduino_8088 server!");
87 | ard_client
88 | }
89 | Err(e) => {
90 | eprintln!("Error connecting to Arduino_8088 server: {e}");
91 | std::process::exit(1);
92 | }
93 | };
94 |
95 | // Create a remote cpu instance using the cpu_client which should now be connected.
96 | let mut cpu = RemoteCpu::new(
97 | cpu_client,
98 | args.prefetch,
99 | args.emu8080,
100 | args.wait_states,
101 | args.intr_on,
102 | args.intr_after,
103 | args.nmi_on,
104 | );
105 |
106 | let cpu_type = cpu.cpu_type();
107 | log::debug!("Detected CPU type: {:?}", cpu_type);
108 |
109 | // Capture initial regs before adjustment.
110 | let initial_regs = RemoteCpuRegisters::from(reg_bytes.as_slice());
111 |
112 | // Copy the binary to memory
113 | log::debug!("Mounting program code at: {:05X}", mount_addr);
114 | cpu.mount_bin(&bin_bytes, mount_addr as usize);
115 |
116 | // Set up IVR table
117 | cpu.setup_ivt();
118 |
119 | // Load the registers from binary file
120 | let result = cpu.load_registers_from_buf(®_bytes);
121 | if result {
122 | log::trace!("Successfully set up registers!");
123 |
124 | println!("Initial register state:");
125 |
126 | RemoteCpu::print_regs(&initial_regs, cpu_type);
127 |
128 | let print_opts = PrintOptions {
129 | print_pgm: true,
130 | print_preload: false,
131 | print_finalize: false,
132 | };
133 |
134 | //cpu.test();
135 | match cpu.run(Some(10_000), &print_opts) {
136 | Ok(regs) => {
137 | println!("Final register state:");
138 | RemoteCpu::print_regs_delta(&initial_regs, ®s, cpu_type);
139 | }
140 | Err(_) => {
141 | log::error!("Program execution failed!");
142 | }
143 | }
144 | } else {
145 | log::error!("Register setup failed: {}", cpu.get_last_error());
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/images/arduino8088_breadboard.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dbalsom/arduino808x/9bbe3f1384fdddb5ee8dc8532a96ee9fc237af02/images/arduino8088_breadboard.jpg
--------------------------------------------------------------------------------
/images/arduino8088_pcb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dbalsom/arduino808x/9bbe3f1384fdddb5ee8dc8532a96ee9fc237af02/images/arduino8088_pcb.jpg
--------------------------------------------------------------------------------
/images/pcb_shield50.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dbalsom/arduino808x/9bbe3f1384fdddb5ee8dc8532a96ee9fc237af02/images/pcb_shield50.PNG
--------------------------------------------------------------------------------
/images/pcb_v1_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dbalsom/arduino808x/9bbe3f1384fdddb5ee8dc8532a96ee9fc237af02/images/pcb_v1_1.png
--------------------------------------------------------------------------------
/images/render_v1_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dbalsom/arduino808x/9bbe3f1384fdddb5ee8dc8532a96ee9fc237af02/images/render_v1_1.png
--------------------------------------------------------------------------------
/pcb/asm/load.asm:
--------------------------------------------------------------------------------
1 | ; load.asm
2 | ; Original routine by Andreas Jonsson
3 | ; https://github.com/andreas-jonsson/virtualxt/tree/develop/tools/validator/pi8088
4 | ;
5 | ; Assemble with nasm:
6 | ; nasm load.asm -o load.bin
7 |
8 | ; This routine sets up a known register state. It must be patched by the validator
9 | ; program with the desired values replacing the word operands set to 0 here.
10 |
11 | ; Patching offsets are as follows:
12 |
13 | ; FLAGS = 0x00;
14 | ; BX = 0x0B;
15 | ; CX = 0x0E;
16 | ; DX = 0x11;
17 | ; SS = 0x14;
18 | ; DS = 0x19;
19 | ; ES = 0x1E;
20 | ; SP = 0x23;
21 | ; BP = 0x28;
22 | ; SI = 0x2D;
23 | ; DI = 0x32;
24 | ; AX = 0x37;
25 | ; IP = 0x3A;
26 | ; CS = 0x3C;
27 |
28 | cpu 8086
29 | org 0h
30 |
31 | dw 0
32 |
33 | mov ax, 0
34 | mov ss, ax
35 | mov sp, ax
36 | popf ; Flags
37 |
38 | mov bx, word 0 ; BX
39 | mov cx, word 0 ; CX
40 | mov dx, word 0 ; DX
41 |
42 | mov ax, word 0 ; SS
43 | mov ss, ax
44 | mov ax, word 0 ; DS
45 | mov ds, ax
46 | mov ax, word 0 ; ES
47 | mov es, ax
48 | mov ax, word 0 ; SP
49 | mov sp, ax
50 | mov ax, word 0 ; BP
51 | mov bp, ax
52 | mov ax, word 0 ; SI
53 | mov si, ax
54 | mov ax, word 0 ; DI
55 | mov di, ax
56 |
57 | mov ax, word 0 ; AX
58 | jmp 0:0 ; CS:IP
59 |
--------------------------------------------------------------------------------
/pcb/asm/pop_cs.asm:
--------------------------------------------------------------------------------
1 | cpu 8086
2 | org 0h
3 |
4 | mov ax, 0xd000
5 | push ax
6 | pop cs
7 | nop
8 |
--------------------------------------------------------------------------------
/pcb/asm/store.asm:
--------------------------------------------------------------------------------
1 | ; store.asm
2 | ; Original routine by Andreas Jonsson
3 | ; https://github.com/andreas-jonsson/virtualxt/tree/develop/tools/validator/pi8088
4 | ;
5 | ; Assemble with nasm:
6 | ; nasm store.asm -o store.bin
7 |
8 | ; Registers are output in turn to dummy IO addresses, intercepted by the validator
9 | ; program. End of the routine is indicated by a write to IO address 0xFD.
10 |
11 | ; Since there is no direct 'MOV rm, flags' or 'MOV rm, ip' instruction, we push
12 | ; these two registers to the stack and intercept memory writes to the dummy stack
13 | ; space defined at 00000-00003.
14 |
15 | cpu 8086
16 | org 0h
17 |
18 | out 0xFE, ax ; AX
19 | mov ax, bx
20 | out 0xFE, ax ; BX
21 | mov ax, cx
22 | out 0xFE, ax ; CX
23 | mov ax, dx
24 | out 0xFE, ax ; DX
25 |
26 | mov ax, ss
27 | out 0xFE, ax ; SS
28 | mov ax, sp
29 | out 0xFE, ax ; SP
30 |
31 | mov ax, 0
32 | mov ss, ax
33 | mov ax, 4
34 | mov sp, ax ; Set up 4 bytes of stack for flags and IP.
35 | pushf ; Capture flags
36 | call _ip ; We capture IP when it is pushed to the stack on CALL.
37 | ; We then adjust it by 24 bytes to the start of the store procedure.
38 | _ip:
39 | mov ax, cs
40 | out 0xFE, ax ; CS
41 | mov ax, ds
42 | out 0xFE, ax ; DS
43 | mov ax, es
44 | out 0xFE, ax ; ES
45 | mov ax, bp
46 | out 0xFE, ax ; BP
47 | mov ax, si
48 | out 0xFE, ax ; SI
49 | mov ax, di
50 | out 0xFE, ax ; DI
51 |
52 | mov al, 0xFF ; Sent as a signal to the validator program that we are done.
53 | out 0xFD, al ; Done!
54 |
--------------------------------------------------------------------------------
/pcb/asm/store.lst:
--------------------------------------------------------------------------------
1 | 1 ; store.asm
2 | 2 ; Original routine by Andreas Jonsson
3 | 3 ; https://github.com/andreas-jonsson/virtualxt/tree/develop/tools/validator/pi8088
4 | 4 ;
5 | 5 ; Assemble with nasm:
6 | 6 ; nasm store.asm -o store.bin
7 | 7
8 | 8 ; Registers are output in turn to dummy IO addresses, intercepted by the validator
9 | 9 ; program. End of the routine is indicated by a write to IO address 0xFD.
10 | 10
11 | 11 ; Since there is no direct 'MOV rm, flags' or 'MOV rm, ip' instruction, we push
12 | 12 ; these two registers to the stack and intercept memory writes to the dummy stack
13 | 13 ; space defined at 00000-00003.
14 | 14
15 | 15 cpu 8086
16 | 16 org 0h
17 | 17
18 | 18 00000000 E7FE out 0xFE, ax ; AX
19 | 19 00000002 89D8 mov ax, bx
20 | 20 00000004 E7FE out 0xFE, ax ; BX
21 | 21 00000006 89C8 mov ax, cx
22 | 22 00000008 E7FE out 0xFE, ax ; CX
23 | 23 0000000A 89D0 mov ax, dx
24 | 24 0000000C E7FE out 0xFE, ax ; DX
25 | 25
26 | 26 0000000E 8CD0 mov ax, ss
27 | 27 00000010 E7FE out 0xFE, ax ; SS
28 | 28 00000012 89E0 mov ax, sp
29 | 29 00000014 E7FE out 0xFE, ax ; SP
30 | 30
31 | 31 00000016 B80000 mov ax, 0
32 | 32 00000019 8ED0 mov ss, ax
33 | 33 0000001B B80400 mov ax, 4
34 | 34 0000001E 89C4 mov sp, ax ; Set up 4 bytes of stack for flags and IP.
35 | 35 00000020 9C pushf ; Flags
36 | 36 00000021 E80000 call _ip ; We capture IP when it is pushed to the stack on CALL.
37 | 37 _ip: ; We then adjust it by 36 (0x24) bytes to the start of the store procedure.
38 | 38
39 | 39 00000024 8CC8 mov ax, cs
40 | 40 00000026 E7FE out 0xFE, ax ; CS
41 | 41 00000028 8CD8 mov ax, ds
42 | 42 0000002A E7FE out 0xFE, ax ; DS
43 | 43 0000002C 8CC0 mov ax, es
44 | 44 0000002E E7FE out 0xFE, ax ; ES
45 | 45 00000030 89E8 mov ax, bp
46 | 46 00000032 E7FE out 0xFE, ax ; BP
47 | 47 00000034 89F0 mov ax, si
48 | 48 00000036 E7FE out 0xFE, ax ; SI
49 | 49 00000038 89F8 mov ax, di
50 | 50 0000003A E7FE out 0xFE, ax ; DI
51 | 51
52 | 52 0000003C B0FF mov al, 0xFF
53 | 53 0000003E E6FD out 0xFD, al ; Done!
54 |
--------------------------------------------------------------------------------
/pcb/kicad/Arduino.pretty/Arduino_Mega2560_Shield.kicad_mod:
--------------------------------------------------------------------------------
1 | (footprint "Arduino_Mega2560_Shield" (version 20211014) (generator pcbnew)
2 | (layer "F.Cu")
3 | (tedit 5A8605D3)
4 | (descr "https://store.arduino.cc/products/arduino-mega-2560-rev3")
5 | (attr through_hole)
6 | (fp_text reference "XA**" (at 2.54 -54.356) (layer "F.SilkS")
7 | (effects (font (size 1 1) (thickness 0.15)))
8 | (tstamp 901f647f-3550-4ee2-b85a-c0e6eb7f056b)
9 | )
10 | (fp_text value "Arduino_Mega2560_Shield" (at 15.494 -54.356) (layer "F.Fab")
11 | (effects (font (size 1 1) (thickness 0.15)))
12 | (tstamp 934f6513-ff6d-48e4-9678-db00acb1239e)
13 | )
14 | (fp_text user "." (at 62.484 -32.004) (layer "F.SilkS")
15 | (effects (font (size 1 1) (thickness 0.15)))
16 | (tstamp 24a585e1-241f-4e2d-b0c5-4266dd40d675)
17 | )
18 | (fp_line (start 0 -53.34) (end 0 0) (layer "F.SilkS") (width 0.15) (tstamp 0201edc4-5909-49e4-a24d-6c74e40bf687))
19 | (fp_line (start 99.06 -40.64) (end 99.06 -51.816) (layer "F.SilkS") (width 0.15) (tstamp 1b7655c2-4471-4dc4-89ea-b09efef47444))
20 | (fp_line (start 0 -53.34) (end 97.536 -53.34) (layer "F.SilkS") (width 0.15) (tstamp 3635604c-af1b-4f29-91bf-cce857376fbc))
21 | (fp_line (start 0 0) (end 99.06 0) (layer "F.SilkS") (width 0.15) (tstamp 7d71a2bc-b35f-4562-ba60-a028e8124f62))
22 | (fp_line (start 99.06 -1.27) (end 101.6 -3.81) (layer "F.SilkS") (width 0.15) (tstamp 85ccc8b4-a976-43c5-b7d9-40a5865c785e))
23 | (fp_line (start 101.6 -3.81) (end 101.6 -38.1) (layer "F.SilkS") (width 0.15) (tstamp cd965f97-7341-40d3-b126-5471bf76cde5))
24 | (fp_line (start 97.536 -53.34) (end 99.06 -51.816) (layer "F.SilkS") (width 0.15) (tstamp d9ed1a4c-f7cf-4fc4-865e-ac12d277d30d))
25 | (fp_line (start 99.06 0) (end 99.06 -1.27) (layer "F.SilkS") (width 0.15) (tstamp dca0327d-c99d-4147-b448-eed4cde92ef5))
26 | (fp_line (start 101.6 -38.1) (end 99.06 -40.64) (layer "F.SilkS") (width 0.15) (tstamp fa143074-b8ae-4c26-84a0-6f30a6bd5c4f))
27 | (fp_line (start -1.905 -3.175) (end 11.43 -3.175) (layer "B.CrtYd") (width 0.15) (tstamp 0b3a3759-05f9-4e80-8a5d-af8679a3797e))
28 | (fp_line (start 9.525 -43.815) (end 9.525 -32.385) (layer "B.CrtYd") (width 0.15) (tstamp 502b9016-2b7e-4052-808c-d5b6ee19179b))
29 | (fp_line (start -1.905 -12.065) (end -1.905 -3.175) (layer "B.CrtYd") (width 0.15) (tstamp 677d75d3-db99-4614-a60d-2f16675ae5a8))
30 | (fp_line (start 11.43 -12.065) (end 11.43 -3.175) (layer "B.CrtYd") (width 0.15) (tstamp 68c60b8f-9efb-4599-9c4c-95ec04912b96))
31 | (fp_line (start -6.35 -43.815) (end -6.35 -32.385) (layer "B.CrtYd") (width 0.15) (tstamp 8b855417-bb49-4ee5-a78a-4347d70d6c47))
32 | (fp_line (start -1.905 -12.065) (end 11.43 -12.065) (layer "B.CrtYd") (width 0.15) (tstamp aada8c7c-dc5c-43c7-a7e7-21c3b8cd0c5f))
33 | (fp_line (start 9.525 -32.385) (end -6.35 -32.385) (layer "B.CrtYd") (width 0.15) (tstamp cf8a5fc9-ff83-424c-8ea9-05fb7fb5ee5b))
34 | (fp_line (start 9.525 -43.815) (end -6.35 -43.815) (layer "B.CrtYd") (width 0.15) (tstamp e10407bd-2ba5-41cb-b247-1fb20e159c29))
35 | (pad "" np_thru_hole circle (at 13.97 -2.54) (size 3.2 3.2) (drill 3.2) (layers *.Cu *.Mask) (tstamp 2ddfb6f4-8d42-4626-85d7-3443fe3a86d7))
36 | (pad "" np_thru_hole circle (at 66.04 -7.62) (size 3.2 3.2) (drill 3.2) (layers *.Cu *.Mask) (tstamp 38363034-fb3e-40ba-93c2-15690b9a1229))
37 | (pad "" np_thru_hole circle (at 15.24 -50.8) (size 3.2 3.2) (drill 3.2) (layers *.Cu *.Mask) (tstamp 40ae3e13-2d05-455a-b0b9-d8d012516703))
38 | (pad "" np_thru_hole circle (at 96.52 -2.54) (size 3.2 3.2) (drill 3.2) (layers *.Cu *.Mask) (tstamp b1616bf6-a886-46c1-9d1b-22dce08e2db2))
39 | (pad "" np_thru_hole circle (at 66.04 -35.56) (size 3.2 3.2) (drill 3.2) (layers *.Cu *.Mask) (tstamp b9f97585-a4ae-4325-9747-925760653645))
40 | (pad "" np_thru_hole circle (at 90.17 -50.8) (size 3.2 3.2) (drill 3.2) (layers *.Cu *.Mask) (tstamp cb61a821-426b-4c62-9de6-3aefa67e8c94))
41 | (pad "" thru_hole oval (at 27.94 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp d77bdc38-cbdd-44ad-8557-1573fb63b347))
42 | (pad "3V3" thru_hole oval (at 35.56 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 77197f6a-8096-4a5f-ae6f-3ee7b0454271))
43 | (pad "5V1" thru_hole oval (at 38.1 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 01237243-3d21-42cc-8615-9ce075f2a6a4))
44 | (pad "5V2" thru_hole oval (at 66.167 -30.48) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 1da7fb53-0180-4161-b100-6d837097ae43))
45 | (pad "5V3" thru_hole oval (at 93.98 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 7b69b293-5f98-428f-be45-47bbf6326bff))
46 | (pad "5V4" thru_hole oval (at 96.52 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp c870eb73-f797-451f-a32f-bc7de534f3b8))
47 | (pad "A0" thru_hole oval (at 50.8 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 90023b75-62b7-4be0-854d-709bdd8bc79c))
48 | (pad "A1" thru_hole oval (at 53.34 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 7f2b98c8-88fa-475d-ae92-c70b3a57476f))
49 | (pad "A2" thru_hole oval (at 55.88 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp a0963124-12e6-4b26-ada6-6cec2ab5867d))
50 | (pad "A3" thru_hole oval (at 58.42 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp cb6fedca-f2dd-49b1-b957-09d517f87a64))
51 | (pad "A4" thru_hole oval (at 60.96 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp ee0e7815-e014-466b-8d08-abea1e973f14))
52 | (pad "A5" thru_hole oval (at 63.5 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp dd70a54c-b1a9-42b0-b72b-3fb3d14fcdbb))
53 | (pad "A6" thru_hole oval (at 66.04 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 9fb0f2ae-b7e2-4b62-815b-11573a68ba8f))
54 | (pad "A7" thru_hole oval (at 68.58 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 671672f8-6e5f-4078-96b8-21c95194efb3))
55 | (pad "A8" thru_hole oval (at 73.66 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp f7791b12-8a58-4ec3-af7d-9ec39a909fb4))
56 | (pad "A9" thru_hole oval (at 76.2 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp e53335f3-e866-4df7-8a57-a2a316031bff))
57 | (pad "A10" thru_hole oval (at 78.74 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 479938bd-05f1-495f-8d8c-329170d5806b))
58 | (pad "A11" thru_hole oval (at 81.28 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 098a87cd-3fb3-4e2f-8c90-1271e56cf672))
59 | (pad "A12" thru_hole oval (at 83.82 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 6de398ab-a06f-498f-951e-b6b8b41949af))
60 | (pad "A13" thru_hole oval (at 86.36 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 221c4d3e-d8d3-4142-96db-507cfe8debd8))
61 | (pad "A14" thru_hole oval (at 88.9 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 69f89a77-14f8-4821-8ebb-43810a49bc8b))
62 | (pad "A15" thru_hole oval (at 91.44 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 6ce1dc06-70a0-40b6-b879-88b5ff3b5cac))
63 | (pad "AREF" thru_hole oval (at 23.876 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 838f92bc-ca49-4362-b5ce-99c90b72654e))
64 | (pad "D0" thru_hole oval (at 63.5 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp e3b5937a-937e-445f-9358-57a86a1ac491))
65 | (pad "D1" thru_hole oval (at 60.96 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp f1b40e82-42e6-4a98-9bdc-af4f4fc8a3c5))
66 | (pad "D2" thru_hole oval (at 58.42 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp bf6d63c9-3d7c-4f88-897b-38889daffa15))
67 | (pad "D3" thru_hole oval (at 55.88 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 16966830-d6ca-4fc1-aa25-daa73f02fa20))
68 | (pad "D4" thru_hole oval (at 53.34 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 39b9988b-f680-4e74-a29a-b130c3ae975c))
69 | (pad "D5" thru_hole oval (at 50.8 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 56df60a2-d7ca-4b9b-88a1-32c3f91451ea))
70 | (pad "D6" thru_hole oval (at 48.26 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 150df283-9a94-4fef-b64b-66733c6bdc89))
71 | (pad "D7" thru_hole oval (at 45.72 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp e62fe0dd-838e-4a9b-9038-17eca7956192))
72 | (pad "D8" thru_hole oval (at 41.656 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 6a9e9910-6ffd-4cdc-bda5-814e9dd16887))
73 | (pad "D9" thru_hole oval (at 39.116 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp dd74c364-a675-43fe-9beb-cded98630cda))
74 | (pad "D10" thru_hole oval (at 36.576 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp e29cc09e-b3f5-4f8f-a63a-74635348fbb9))
75 | (pad "D11" thru_hole oval (at 34.036 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp cd3bfc28-ccdd-4b08-a82a-c4ef23d6f96c))
76 | (pad "D12" thru_hole oval (at 31.496 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 8b0895f3-ba8d-4957-ae9d-8703e99a03ae))
77 | (pad "D13" thru_hole oval (at 28.956 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp a396fad8-8e72-49d2-8947-42140d6d9767))
78 | (pad "D14" thru_hole oval (at 68.58 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 8e2ad859-f1bc-4c92-a8b6-54202c8b5050))
79 | (pad "D15" thru_hole oval (at 71.12 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp c27ffceb-b3f1-4a6f-b2d7-d9b8d47bdf71))
80 | (pad "D16" thru_hole oval (at 73.66 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 04b1ca71-86f1-4303-8d35-252f2c811b7b))
81 | (pad "D17" thru_hole oval (at 76.2 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 5458232c-3efb-4aea-8193-c6b416ff116c))
82 | (pad "D18" thru_hole oval (at 78.74 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 91229996-134e-40b4-93e3-7525340fab02))
83 | (pad "D19" thru_hole oval (at 81.28 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 41969665-29aa-42fd-a6fd-e22fe43d66f9))
84 | (pad "D20" thru_hole oval (at 83.82 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 64a2d2b8-838d-425c-bce0-75f610fffd64))
85 | (pad "D21" thru_hole oval (at 86.36 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 99ffeee4-a25b-47c1-b008-5b9fccd78ac5))
86 | (pad "D22" thru_hole oval (at 93.98 -48.26) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 2e3fddf7-e89f-4d6b-9405-781ea8a4f605))
87 | (pad "D23" thru_hole oval (at 96.52 -48.26) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp f0f513b1-04df-4ec8-9310-cb130e985ba8))
88 | (pad "D24" thru_hole oval (at 93.98 -45.72) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 63e340db-7166-45b6-a95e-3c45c32bb445))
89 | (pad "D25" thru_hole oval (at 96.52 -45.72) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp e92af5f0-7ae3-46bf-90ac-ba7298426cae))
90 | (pad "D26" thru_hole oval (at 93.98 -43.18) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 2b3f9601-ef0a-46c5-86ef-48eb8f1cc0a7))
91 | (pad "D27" thru_hole oval (at 96.52 -43.18) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 491a6340-b550-4dcb-808d-c51b7b8a1036))
92 | (pad "D28" thru_hole oval (at 93.98 -40.64) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp c6f29154-c71e-422a-9a78-0e8c089559c3))
93 | (pad "D29" thru_hole oval (at 96.52 -40.64) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 0cbd0a42-d3ac-4c93-a289-dc189a975d4e))
94 | (pad "D30" thru_hole oval (at 93.98 -38.1) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp b36c7c78-abed-4cfc-823f-fb9b185b54b6))
95 | (pad "D31" thru_hole oval (at 96.52 -38.1) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp b29ea7bd-aa67-4fcf-9fb3-e6d8a22d8c73))
96 | (pad "D32" thru_hole oval (at 93.98 -35.56) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 3f28da8c-8c11-4a31-8fbd-3d9167671778))
97 | (pad "D33" thru_hole oval (at 96.52 -35.56) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 89ff98ee-6b16-4d9c-8697-8e60bc57633d))
98 | (pad "D34" thru_hole oval (at 93.98 -33.02) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 464ba415-f059-43bb-89be-6ab6085d0a4d))
99 | (pad "D35" thru_hole oval (at 96.52 -33.02) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 9b3d216d-b1a9-4f31-bf2b-7d90f4461c3a))
100 | (pad "D36" thru_hole oval (at 93.98 -30.48) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp b073fc3c-9e25-4f99-9c97-a819a292e456))
101 | (pad "D37" thru_hole oval (at 96.52 -30.48) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 71b7f856-490d-4600-95a4-56ea76c4a2b0))
102 | (pad "D38" thru_hole oval (at 93.98 -27.94) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp babeb2ca-fccc-47d7-999c-d5e73b6ac51c))
103 | (pad "D39" thru_hole oval (at 96.52 -27.94) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 08d65541-3c4f-477e-a5ee-efea26771beb))
104 | (pad "D40" thru_hole oval (at 93.98 -25.4) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 7819625d-64e0-47c4-8cca-8ff9cf8377c6))
105 | (pad "D41" thru_hole oval (at 96.52 -25.4) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp c0c9ed9a-6b4b-4a16-a9fe-fe8e9d4ad1a7))
106 | (pad "D42" thru_hole oval (at 93.98 -22.86) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp cf3392e1-bebf-4fa6-9d56-9f9cd11e8671))
107 | (pad "D43" thru_hole oval (at 96.52 -22.86) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 62f55c7f-315f-43d5-b8c6-ad5df66b0efc))
108 | (pad "D44" thru_hole oval (at 93.98 -20.32) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 7bfd2b70-5b92-420d-bdf5-514bc7e9a538))
109 | (pad "D45" thru_hole oval (at 96.52 -20.32) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp f8c892e0-154f-4076-ab2e-e95c39738259))
110 | (pad "D46" thru_hole oval (at 93.98 -17.78) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 9d400d82-47eb-4caa-95aa-6eb416fecb6d))
111 | (pad "D47" thru_hole oval (at 96.52 -17.78) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 07af9c9a-976c-4991-b70f-c3592329b8a8))
112 | (pad "D48" thru_hole oval (at 93.98 -15.24) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp ec19611e-b196-4a32-8605-ed4345f6242e))
113 | (pad "D49" thru_hole oval (at 96.52 -15.24) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 0b65b84a-b522-496b-8b49-2f70e8592eb6))
114 | (pad "D50" thru_hole oval (at 93.98 -12.7) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 33d12efe-98cd-4791-805e-fd9894916c83))
115 | (pad "D51" thru_hole oval (at 96.52 -12.7) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 449f34b4-7d93-4b98-98c0-46c275f84d96))
116 | (pad "D52" thru_hole oval (at 93.98 -10.16) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp cc8f654e-591c-4521-abda-f4bcc42faaf7))
117 | (pad "D53" thru_hole oval (at 96.52 -10.16) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp eb9e14db-7564-458a-b3c5-818ca20410c8))
118 | (pad "GND1" thru_hole oval (at 26.416 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 5ef433f7-b055-4e8f-bdf4-97739a14c55b))
119 | (pad "GND2" thru_hole oval (at 40.64 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 241b5808-5109-4316-a18e-a56ad6c1bce2))
120 | (pad "GND3" thru_hole oval (at 43.18 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 5dba48c9-b0ae-4f7d-8256-4b3194234fc7))
121 | (pad "GND4" thru_hole oval (at 66.167 -25.4) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp b3e4d348-7cf9-4263-bcae-b8d692c6de87))
122 | (pad "GND5" thru_hole oval (at 93.98 -7.62) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 385996b5-27e1-447a-bf04-24559c09fbc0))
123 | (pad "GND6" thru_hole oval (at 96.52 -7.62) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp ba0cc3f3-5ddc-484f-af08-e7874b0a80d4))
124 | (pad "IORF" thru_hole oval (at 30.48 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 956e755b-5236-4ba6-9722-49ba93996445))
125 | (pad "MISO" thru_hole oval (at 63.627 -30.48) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp f4f91e90-6a22-4d32-8ef7-00bf97a82dce))
126 | (pad "MOSI" thru_hole oval (at 66.167 -27.94) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp e39b6661-4b6b-4e3e-ada8-7f0d98981318))
127 | (pad "RST1" thru_hole oval (at 33.02 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp fcaecea3-faa5-40e6-9d25-c0114dbc75ae))
128 | (pad "RST2" thru_hole oval (at 63.627 -25.4) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp f34986de-ff34-412e-b7ac-79e7d51a367a))
129 | (pad "SCK" thru_hole oval (at 63.627 -27.94) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 49b40249-adaa-4aa0-9f90-a9c91050d5c7))
130 | (pad "SCL" thru_hole oval (at 18.796 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp ba5fd440-dac5-4b88-be10-f458cd21b115))
131 | (pad "SDA" thru_hole oval (at 21.336 -50.8) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp fdab7305-3f48-4c88-827a-ac8147d5b392))
132 | (pad "VIN" thru_hole oval (at 45.72 -2.54) (size 1.7272 1.7272) (drill 1.016) (layers *.Cu *.Mask) (tstamp 57d1996c-873b-40c2-b08c-0df42f14f611))
133 | )
134 |
--------------------------------------------------------------------------------
/pcb/kicad/MCU_Intel.dcm:
--------------------------------------------------------------------------------
1 | EESchema-DOCLIB Version 2.0
2 | #
3 | $CMP 80186
4 | D High-Integration 16-Bit Microprocessor
5 | K MPRO
6 | F http://datasheets.chipdb.org/Intel/x86/8018x/datashts/27243002.PDF
7 | $ENDCMP
8 | #
9 | $CMP 80188
10 | D High-Integration 16-Bit Microprocessor
11 | K MPRO
12 | F http://datasheets.chipdb.org/Intel/x86/8018x/datashts/27243002.PDF
13 | $ENDCMP
14 | #
15 | $CMP 8035
16 | D MCS-48 8-bit Microcontroller, No (EP)ROM, 64B RAM, DIP-40
17 | K MCS-48 uC Microcontroller
18 | $ENDCMP
19 | #
20 | $CMP 8039
21 | D MCS-48 8-bit Microcontroller, No (EP)ROM, 128B RAM, DIP-40
22 | K MCS-48 uC Microcontroller
23 | $ENDCMP
24 | #
25 | $CMP 8040
26 | D MCS-48 8-bit Microcontroller, No (EP)ROM, 256B RAM, DIP-40
27 | K MCS-48 uC Microcontroller
28 | $ENDCMP
29 | #
30 | $CMP 8048
31 | D MCS-48 8-bit Microcontroller, 1KB Mask ROM, 64B RAM, DIP-40
32 | K MCS-48 uC Microcontroller
33 | $ENDCMP
34 | #
35 | $CMP 8049
36 | D MCS-48 8-bit Microcontroller, 2KB Mask ROM, 128B RAM, DIP-40
37 | K MCS-48 uC Microcontroller
38 | $ENDCMP
39 | #
40 | $CMP 8050
41 | D MCS-48 8-bit Microcontroller, 4KB Mask ROM, 256B RAM, DIP-40
42 | K MCS-48 uC Microcontroller
43 | $ENDCMP
44 | #
45 | $CMP 8080
46 | D 8-bit N-channel Microprocessor, DIP-40
47 | K cpu mpu microprocessor
48 | F http://datasheets.chipdb.org/Intel/MCS-80/intel-8080.pdf
49 | $ENDCMP
50 | #
51 | $CMP 8080A
52 | D 8-bit N-channel Microprocessor, DIP-40
53 | K cpu mpu microprocessor
54 | F http://datasheets.chipdb.org/Intel/MCS-80/intel-8080.pdf
55 | $ENDCMP
56 | #
57 | $CMP 8086_Max_Mode
58 | D 8086 (maximum mode), 16-Bit HMOS Microprocessor, PDIP-40
59 | K MPRO
60 | F http://datasheets.chipdb.org/Intel/x86/808x/datashts/8086/231455-006.pdf
61 | $ENDCMP
62 | #
63 | $CMP 8086_Min_Mode
64 | D 8086 (minimum mode), 16-Bit HMOS Microprocessor, PDIP-40
65 | K MPRO
66 | F http://datasheets.chipdb.org/Intel/x86/808x/datashts/8086/231455-006.pdf
67 | $ENDCMP
68 | #
69 | $CMP 8087
70 | D Math Coprocessor for Intel 8086/8088/80186/80188 microprocessors, PDIP-40
71 | K FPU
72 | F http://datasheets.chipdb.org/Intel/x86/808x/datashts/8087/205835-007.pdf
73 | $ENDCMP
74 | #
75 | $CMP 8088
76 | D 8088 (minimum mode), 8-Bit HMOS Microprocessor, PDIP-40
77 | K MPRO
78 | F http://datasheets.chipdb.org/Intel/x86/808x/datashts/8088/231456-006.pdf
79 | $ENDCMP
80 | #
81 | $CMP 8088_Max_Mode
82 | D 8088 (maximum mode), 8-Bit HMOS Microprocessor, PDIP-40
83 | K MPRO
84 | F http://datasheets.chipdb.org/Intel/x86/808x/datashts/8088/231456-006.pdf
85 | $ENDCMP
86 | #
87 | $CMP 8088_Min_Mode
88 | D 8088 (minimum mode), 8-Bit HMOS Microprocessor, PDIP-40
89 | K MPRO
90 | F http://datasheets.chipdb.org/Intel/x86/808x/datashts/8088/231456-006.pdf
91 | $ENDCMP
92 | #
93 | $CMP 80C186XL
94 | D 16-Bit High-Integration Embedded Processor
95 | K MPRO
96 | F http://datasheets.chipdb.org/Intel/x86/8018x/datashts/27243104.PDF
97 | $ENDCMP
98 | #
99 | $CMP 80C188
100 | D CHMOS High-Integration 16-Bit Microprocessor
101 | K MPRO
102 | F http://datasheets.chipdb.org/Intel/x86/8018x/datashts/80188/intel-80c188.pdf
103 | $ENDCMP
104 | #
105 | $CMP 80C188XL
106 | D 16-Bit High-Integration Embedded Processor
107 | K MPRO
108 | F http://datasheets.chipdb.org/Intel/x86/8018x/datashts/27243104.PDF
109 | $ENDCMP
110 | #
111 | $CMP 8748
112 | D i8748, MCS-48 8-bit Microcontroller with Internal EPROM, 1KB EPROM, 64B RAM, DIP-40
113 | K MCS-48 uC Microcontroller
114 | $ENDCMP
115 | #
116 | $CMP 8749
117 | D i8748, MCS-48 8-bit Microcontroller with Internal EPROM, 2KB EPROM, 128B RAM, DIP-40
118 | K MCS-48 uC Microcontroller
119 | $ENDCMP
120 | #
121 | $CMP I386EX_PQFP
122 | D Intel I386EX Embedded microprocessor, PQFP-132
123 | K MPRO
124 | $ENDCMP
125 | #
126 | $CMP IA186XLPLC68IR2
127 | D MCU Replacement for Intel 80C186XL
128 | K MPRO
129 | F http://www.innovasic.com/upload/products/Innovasic_IA186XL_IA188XL_Data_Sheet_20110706_2.pdf
130 | $ENDCMP
131 | #
132 | $CMP IA188XLPLC68IR2
133 | D MCU Replacement for Intel 80C188XL
134 | K MPRO
135 | F http://www.innovasic.com/upload/products/Innovasic_IA186XL_IA188XL_Data_Sheet_20110706_2.pdf
136 | $ENDCMP
137 | #
138 | $CMP M80C186
139 | D CHMOS High-Integration 16-Bit Microprocessor
140 | K MPRO
141 | F http://datasheets.chipdb.org/Intel/x86/8018x/datashts/80186/27050008.PDF
142 | $ENDCMP
143 | #
144 | $CMP M80C186XL
145 | D 16-Bit High-Integration Embedded Processor
146 | K MPRO
147 | F http://datasheets.chipdb.org/Intel/x86/8018x/datashts/80186/27127602.pdf
148 | $ENDCMP
149 | #
150 | #End Doc Library
151 |
--------------------------------------------------------------------------------
/pcb/kicad/ard8088.kicad_prl:
--------------------------------------------------------------------------------
1 | {
2 | "board": {
3 | "active_layer": 31,
4 | "active_layer_preset": "All Layers",
5 | "auto_track_width": true,
6 | "hidden_netclasses": [],
7 | "hidden_nets": [],
8 | "high_contrast_mode": 0,
9 | "net_color_mode": 1,
10 | "opacity": {
11 | "images": 0.6,
12 | "pads": 1.0,
13 | "tracks": 1.0,
14 | "vias": 1.0,
15 | "zones": 0.6
16 | },
17 | "ratsnest_display_mode": 0,
18 | "selection_filter": {
19 | "dimensions": true,
20 | "footprints": true,
21 | "graphics": true,
22 | "keepouts": true,
23 | "lockedItems": true,
24 | "otherItems": false,
25 | "pads": true,
26 | "text": true,
27 | "tracks": true,
28 | "vias": true,
29 | "zones": true
30 | },
31 | "visible_items": [
32 | 0,
33 | 1,
34 | 2,
35 | 3,
36 | 4,
37 | 5,
38 | 8,
39 | 9,
40 | 10,
41 | 11,
42 | 13,
43 | 14,
44 | 15,
45 | 16,
46 | 17,
47 | 18,
48 | 19,
49 | 20,
50 | 21,
51 | 22,
52 | 23,
53 | 24,
54 | 25,
55 | 26,
56 | 27,
57 | 28,
58 | 29,
59 | 30,
60 | 32,
61 | 33,
62 | 34,
63 | 35,
64 | 36
65 | ],
66 | "visible_layers": "fffffff_ffffffff",
67 | "zone_display_mode": 0
68 | },
69 | "git": {
70 | "repo_password": "",
71 | "repo_type": "",
72 | "repo_username": "",
73 | "ssh_key": ""
74 | },
75 | "meta": {
76 | "filename": "ard8088.kicad_prl",
77 | "version": 3
78 | },
79 | "project": {
80 | "files": []
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/pcb/kicad/ard8088.kicad_pro:
--------------------------------------------------------------------------------
1 | {
2 | "board": {
3 | "3dviewports": [],
4 | "design_settings": {
5 | "defaults": {
6 | "apply_defaults_to_fp_fields": false,
7 | "apply_defaults_to_fp_shapes": false,
8 | "apply_defaults_to_fp_text": false,
9 | "board_outline_line_width": 0.1,
10 | "copper_line_width": 0.2,
11 | "copper_text_italic": false,
12 | "copper_text_size_h": 1.5,
13 | "copper_text_size_v": 1.5,
14 | "copper_text_thickness": 0.3,
15 | "copper_text_upright": false,
16 | "courtyard_line_width": 0.05,
17 | "dimension_precision": 4,
18 | "dimension_units": 3,
19 | "dimensions": {
20 | "arrow_length": 1270000,
21 | "extension_offset": 500000,
22 | "keep_text_aligned": true,
23 | "suppress_zeroes": false,
24 | "text_position": 0,
25 | "units_format": 1
26 | },
27 | "fab_line_width": 0.1,
28 | "fab_text_italic": false,
29 | "fab_text_size_h": 1.0,
30 | "fab_text_size_v": 1.0,
31 | "fab_text_thickness": 0.15,
32 | "fab_text_upright": false,
33 | "other_line_width": 0.15,
34 | "other_text_italic": false,
35 | "other_text_size_h": 1.0,
36 | "other_text_size_v": 1.0,
37 | "other_text_thickness": 0.15,
38 | "other_text_upright": false,
39 | "pads": {
40 | "drill": 1.016,
41 | "height": 1.7272,
42 | "width": 1.7272
43 | },
44 | "silk_line_width": 0.15,
45 | "silk_text_italic": false,
46 | "silk_text_size_h": 1.0,
47 | "silk_text_size_v": 1.0,
48 | "silk_text_thickness": 0.15,
49 | "silk_text_upright": false,
50 | "zones": {
51 | "45_degree_only": false,
52 | "min_clearance": 0.508
53 | }
54 | },
55 | "diff_pair_dimensions": [],
56 | "drc_exclusions": [],
57 | "meta": {
58 | "version": 2
59 | },
60 | "rule_severities": {
61 | "annular_width": "error",
62 | "clearance": "error",
63 | "connection_width": "warning",
64 | "copper_edge_clearance": "error",
65 | "copper_sliver": "warning",
66 | "courtyards_overlap": "error",
67 | "diff_pair_gap_out_of_range": "error",
68 | "diff_pair_uncoupled_length_too_long": "error",
69 | "drill_out_of_range": "error",
70 | "duplicate_footprints": "warning",
71 | "extra_footprint": "warning",
72 | "footprint": "error",
73 | "footprint_symbol_mismatch": "warning",
74 | "footprint_type_mismatch": "error",
75 | "hole_clearance": "error",
76 | "hole_near_hole": "error",
77 | "holes_co_located": "warning",
78 | "invalid_outline": "error",
79 | "isolated_copper": "warning",
80 | "item_on_disabled_layer": "error",
81 | "items_not_allowed": "error",
82 | "length_out_of_range": "error",
83 | "lib_footprint_issues": "warning",
84 | "lib_footprint_mismatch": "warning",
85 | "malformed_courtyard": "error",
86 | "microvia_drill_out_of_range": "error",
87 | "missing_courtyard": "ignore",
88 | "missing_footprint": "warning",
89 | "net_conflict": "warning",
90 | "npth_inside_courtyard": "ignore",
91 | "padstack": "error",
92 | "pth_inside_courtyard": "ignore",
93 | "shorting_items": "error",
94 | "silk_edge_clearance": "warning",
95 | "silk_over_copper": "warning",
96 | "silk_overlap": "warning",
97 | "skew_out_of_range": "error",
98 | "solder_mask_bridge": "error",
99 | "starved_thermal": "error",
100 | "text_height": "warning",
101 | "text_thickness": "warning",
102 | "through_hole_pad_without_hole": "error",
103 | "too_many_vias": "error",
104 | "track_dangling": "warning",
105 | "track_width": "error",
106 | "tracks_crossing": "error",
107 | "unconnected_items": "error",
108 | "unresolved_variable": "error",
109 | "via_dangling": "warning",
110 | "zone_has_empty_net": "error",
111 | "zones_intersect": "error"
112 | },
113 | "rules": {
114 | "allow_blind_buried_vias": false,
115 | "allow_microvias": false,
116 | "max_error": 0.005,
117 | "min_clearance": 0.0,
118 | "min_connection": 0.0,
119 | "min_copper_edge_clearance": 0.0,
120 | "min_hole_clearance": 0.25,
121 | "min_hole_to_hole": 0.25,
122 | "min_microvia_diameter": 0.2,
123 | "min_microvia_drill": 0.1,
124 | "min_resolved_spokes": 2,
125 | "min_silk_clearance": 0.0,
126 | "min_text_height": 0.8,
127 | "min_text_thickness": 0.08,
128 | "min_through_hole_diameter": 0.3,
129 | "min_track_width": 0.2,
130 | "min_via_annular_width": 0.05,
131 | "min_via_diameter": 0.4,
132 | "solder_mask_clearance": 0.0,
133 | "solder_mask_min_width": 0.0,
134 | "solder_mask_to_copper_clearance": 0.0,
135 | "use_height_for_length_calcs": true
136 | },
137 | "teardrop_options": [
138 | {
139 | "td_onpadsmd": true,
140 | "td_onroundshapesonly": false,
141 | "td_ontrackend": false,
142 | "td_onviapad": true
143 | }
144 | ],
145 | "teardrop_parameters": [
146 | {
147 | "td_allow_use_two_tracks": true,
148 | "td_curve_segcount": 0,
149 | "td_height_ratio": 1.0,
150 | "td_length_ratio": 0.5,
151 | "td_maxheight": 2.0,
152 | "td_maxlen": 1.0,
153 | "td_on_pad_in_zone": false,
154 | "td_target_name": "td_round_shape",
155 | "td_width_to_size_filter_ratio": 0.9
156 | },
157 | {
158 | "td_allow_use_two_tracks": true,
159 | "td_curve_segcount": 0,
160 | "td_height_ratio": 1.0,
161 | "td_length_ratio": 0.5,
162 | "td_maxheight": 2.0,
163 | "td_maxlen": 1.0,
164 | "td_on_pad_in_zone": false,
165 | "td_target_name": "td_rect_shape",
166 | "td_width_to_size_filter_ratio": 0.9
167 | },
168 | {
169 | "td_allow_use_two_tracks": true,
170 | "td_curve_segcount": 0,
171 | "td_height_ratio": 1.0,
172 | "td_length_ratio": 0.5,
173 | "td_maxheight": 2.0,
174 | "td_maxlen": 1.0,
175 | "td_on_pad_in_zone": false,
176 | "td_target_name": "td_track_end",
177 | "td_width_to_size_filter_ratio": 0.9
178 | }
179 | ],
180 | "track_widths": [],
181 | "tuning_pattern_settings": {
182 | "diff_pair_defaults": {
183 | "corner_radius_percentage": 80,
184 | "corner_style": 1,
185 | "max_amplitude": 1.0,
186 | "min_amplitude": 0.2,
187 | "single_sided": false,
188 | "spacing": 1.0
189 | },
190 | "diff_pair_skew_defaults": {
191 | "corner_radius_percentage": 80,
192 | "corner_style": 1,
193 | "max_amplitude": 1.0,
194 | "min_amplitude": 0.2,
195 | "single_sided": false,
196 | "spacing": 0.6
197 | },
198 | "single_track_defaults": {
199 | "corner_radius_percentage": 80,
200 | "corner_style": 1,
201 | "max_amplitude": 1.0,
202 | "min_amplitude": 0.2,
203 | "single_sided": false,
204 | "spacing": 0.6
205 | }
206 | },
207 | "via_dimensions": [],
208 | "zones_allow_external_fillets": false,
209 | "zones_use_no_outline": true
210 | },
211 | "ipc2581": {
212 | "dist": "",
213 | "distpn": "",
214 | "internal_id": "",
215 | "mfg": "",
216 | "mpn": ""
217 | },
218 | "layer_presets": [],
219 | "viewports": []
220 | },
221 | "boards": [],
222 | "cvpcb": {
223 | "equivalence_files": []
224 | },
225 | "erc": {
226 | "erc_exclusions": [],
227 | "meta": {
228 | "version": 0
229 | },
230 | "pin_map": [
231 | [
232 | 0,
233 | 0,
234 | 0,
235 | 0,
236 | 0,
237 | 0,
238 | 1,
239 | 0,
240 | 0,
241 | 0,
242 | 0,
243 | 2
244 | ],
245 | [
246 | 0,
247 | 2,
248 | 0,
249 | 1,
250 | 0,
251 | 0,
252 | 1,
253 | 0,
254 | 2,
255 | 2,
256 | 2,
257 | 2
258 | ],
259 | [
260 | 0,
261 | 0,
262 | 0,
263 | 0,
264 | 0,
265 | 0,
266 | 1,
267 | 0,
268 | 1,
269 | 0,
270 | 1,
271 | 2
272 | ],
273 | [
274 | 0,
275 | 1,
276 | 0,
277 | 0,
278 | 0,
279 | 0,
280 | 1,
281 | 1,
282 | 2,
283 | 1,
284 | 1,
285 | 2
286 | ],
287 | [
288 | 0,
289 | 0,
290 | 0,
291 | 0,
292 | 0,
293 | 0,
294 | 1,
295 | 0,
296 | 0,
297 | 0,
298 | 0,
299 | 2
300 | ],
301 | [
302 | 0,
303 | 0,
304 | 0,
305 | 0,
306 | 0,
307 | 0,
308 | 0,
309 | 0,
310 | 0,
311 | 0,
312 | 0,
313 | 2
314 | ],
315 | [
316 | 1,
317 | 1,
318 | 1,
319 | 1,
320 | 1,
321 | 0,
322 | 1,
323 | 1,
324 | 1,
325 | 1,
326 | 1,
327 | 2
328 | ],
329 | [
330 | 0,
331 | 0,
332 | 0,
333 | 1,
334 | 0,
335 | 0,
336 | 1,
337 | 0,
338 | 0,
339 | 0,
340 | 0,
341 | 2
342 | ],
343 | [
344 | 0,
345 | 2,
346 | 1,
347 | 2,
348 | 0,
349 | 0,
350 | 1,
351 | 0,
352 | 2,
353 | 2,
354 | 2,
355 | 2
356 | ],
357 | [
358 | 0,
359 | 2,
360 | 0,
361 | 1,
362 | 0,
363 | 0,
364 | 1,
365 | 0,
366 | 2,
367 | 0,
368 | 0,
369 | 2
370 | ],
371 | [
372 | 0,
373 | 2,
374 | 1,
375 | 1,
376 | 0,
377 | 0,
378 | 1,
379 | 0,
380 | 2,
381 | 0,
382 | 0,
383 | 2
384 | ],
385 | [
386 | 2,
387 | 2,
388 | 2,
389 | 2,
390 | 2,
391 | 2,
392 | 2,
393 | 2,
394 | 2,
395 | 2,
396 | 2,
397 | 2
398 | ]
399 | ],
400 | "rule_severities": {
401 | "bus_definition_conflict": "error",
402 | "bus_entry_needed": "error",
403 | "bus_label_syntax": "error",
404 | "bus_to_bus_conflict": "error",
405 | "bus_to_net_conflict": "error",
406 | "different_unit_footprint": "error",
407 | "different_unit_net": "error",
408 | "duplicate_reference": "error",
409 | "duplicate_sheet_names": "error",
410 | "extra_units": "error",
411 | "global_label_dangling": "warning",
412 | "hier_label_mismatch": "error",
413 | "label_dangling": "error",
414 | "lib_symbol_issues": "warning",
415 | "multiple_net_names": "warning",
416 | "net_not_bus_member": "warning",
417 | "no_connect_connected": "warning",
418 | "no_connect_dangling": "warning",
419 | "pin_not_connected": "error",
420 | "pin_not_driven": "error",
421 | "pin_to_pin": "warning",
422 | "power_pin_not_driven": "error",
423 | "similar_labels": "warning",
424 | "unannotated": "error",
425 | "unit_value_mismatch": "error",
426 | "unresolved_variable": "error",
427 | "wire_dangling": "error"
428 | }
429 | },
430 | "libraries": {
431 | "pinned_footprint_libs": [],
432 | "pinned_symbol_libs": []
433 | },
434 | "meta": {
435 | "filename": "ard8088.kicad_pro",
436 | "version": 1
437 | },
438 | "net_settings": {
439 | "classes": [
440 | {
441 | "bus_width": 12,
442 | "clearance": 0.2,
443 | "diff_pair_gap": 0.25,
444 | "diff_pair_via_gap": 0.25,
445 | "diff_pair_width": 0.2,
446 | "line_style": 0,
447 | "microvia_diameter": 0.3,
448 | "microvia_drill": 0.1,
449 | "name": "Default",
450 | "pcb_color": "rgba(0, 0, 0, 0.000)",
451 | "schematic_color": "rgba(0, 0, 0, 0.000)",
452 | "track_width": 0.25,
453 | "via_diameter": 0.8,
454 | "via_drill": 0.4,
455 | "wire_width": 6
456 | }
457 | ],
458 | "meta": {
459 | "version": 3
460 | },
461 | "net_colors": null,
462 | "netclass_assignments": null,
463 | "netclass_patterns": []
464 | },
465 | "pcbnew": {
466 | "last_paths": {
467 | "gencad": "",
468 | "idf": "",
469 | "netlist": "",
470 | "plot": "",
471 | "pos_files": "",
472 | "specctra_dsn": "",
473 | "step": "",
474 | "svg": "",
475 | "vrml": "ard8088.wrl"
476 | },
477 | "page_layout_descr_file": ""
478 | },
479 | "schematic": {
480 | "annotate_start_num": 0,
481 | "drawing": {
482 | "default_line_thickness": 6.0,
483 | "default_text_size": 50.0,
484 | "field_names": [],
485 | "intersheets_ref_own_page": false,
486 | "intersheets_ref_prefix": "",
487 | "intersheets_ref_short": false,
488 | "intersheets_ref_show": false,
489 | "intersheets_ref_suffix": "",
490 | "junction_size_choice": 3,
491 | "label_size_ratio": 0.375,
492 | "pin_symbol_size": 25.0,
493 | "text_offset_ratio": 0.15
494 | },
495 | "legacy_lib_dir": "",
496 | "legacy_lib_list": [],
497 | "meta": {
498 | "version": 1
499 | },
500 | "net_format_name": "",
501 | "ngspice": {
502 | "fix_include_paths": true,
503 | "fix_passive_vals": false,
504 | "meta": {
505 | "version": 0
506 | },
507 | "model_mode": 0,
508 | "workbook_filename": ""
509 | },
510 | "page_layout_descr_file": "",
511 | "plot_directory": "",
512 | "spice_adjust_passive_values": false,
513 | "spice_external_command": "spice \"%I\"",
514 | "subpart_first_id": 65,
515 | "subpart_id_separator": 0
516 | },
517 | "sheets": [
518 | [
519 | "c7681b0c-7541-4fd3-9629-52888e28fe9d",
520 | ""
521 | ]
522 | ],
523 | "text_variables": {}
524 | }
525 |
--------------------------------------------------------------------------------
/pcb/kicad/sym-lib-table:
--------------------------------------------------------------------------------
1 | (sym_lib_table
2 | (lib (name "Arduino_Library")(type "KiCad")(uri "${KIPRJMOD}/arduino.kicad_sym")(options "")(descr ""))
3 | (lib (name "logo")(type "KiCad")(uri "${KIPRJMOD}/logo.kicad_sym")(options "")(descr ""))
4 | )
5 |
--------------------------------------------------------------------------------
/scripts/build.bat:
--------------------------------------------------------------------------------
1 | nasm ./asm/%1_regs.asm -o ./bin/regs.bin
2 | nasm ./asm/%1.asm -o ./bin/program.bin -l ./asm/%1.lst
3 |
--------------------------------------------------------------------------------
/scripts/build2.bat:
--------------------------------------------------------------------------------
1 | nasm ./asm/regs.asm -o ./bin/regs.bin
2 | nasm ./asm/program.asm -o ./bin/program.bin -l ./asm/program.lst
3 |
--------------------------------------------------------------------------------
/sketches/cpu_server/cpu_server.h:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino8088 Copyright 2022-2025 Daniel Balsom
3 | https://github.com/dbalsom/arduino_8088
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a
6 | copy of this software and associated documentation files (the “Software”),
7 | to deal in the Software without restriction, including without limitation
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 | and/or sell copies of the Software, and to permit persons to whom the
10 | Software is furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 | DEALINGS IN THE SOFTWARE.
22 | */
23 | #ifndef _CPU_SERVER_H
24 | #define _CPU_SERVER_H
25 |
26 | // Baud rate is ignored for Arduino DUE as it uses native SerialUSB.
27 | //#define BAUD_RATE 460800
28 | #define BAUD_RATE 1000000
29 |
30 | // Debug baud rate controls Serial1 speed. Check the documentation of your RS232 interface
31 | // for maximum rated speed. Exceeding it will cause dropped characters or other corruption.
32 | //#define DEBUG_BAUD_RATE 230400
33 | #define DEBUG_BAUD_RATE 460800
34 |
35 | #define CMD_TIMEOUT 100 // Command timeout in milliseconds
36 | #define MAX_COMMAND_BYTES 28 // Maximum length of command parameter input
37 |
38 | #define MODE_ASCII 0 // Use ASCII response codes (for interactive debugging only, client won't support)
39 |
40 | #define BRKEM_VECTOR ((uint8_t)0x00)
41 |
42 | // Print a dot to the debugging output on each load.
43 | #define LOAD_INDICATOR 1
44 | #define STORE_INDICATOR 1
45 |
46 | #define TRACE_ALL 0
47 |
48 | // These defines control tracing and debugging output for each state.
49 | // Note: tracing a STORE operation will likely cause it to timeout on the client.
50 | #define TRACE_RESET (0 | TRACE_ALL)
51 | #define TRACE_VECTOR (0 | TRACE_ALL)
52 | #define TRACE_LOAD (1 | TRACE_ALL)
53 | #define TRACE_ID (0 | TRACE_ALL)
54 | #define TRACE_EMU_ENTER (1 | TRACE_ALL)
55 | #define TRACE_EMU_EXIT (1 | TRACE_ALL)
56 | #define TRACE_EXECUTE (1 | TRACE_ALL)
57 | #define TRACE_STORE (1 | TRACE_ALL)
58 | #define TRACE_FINALIZE (1 | TRACE_ALL)
59 | // Debugging output for queue operations (flushes, regular queue ops are always reported)
60 | #define TRACE_QUEUE (0 | TRACE_ALL)
61 |
62 | #define DEBUG_ALL 0
63 |
64 | // Report state changes and time spent in each state
65 | #define DEBUG_STATE (1 | DEBUG_ALL)
66 | #define DEBUG_RESET (0 | DEBUG_ALL)
67 | #define DEBUG_LOAD_DONE (1 | DEBUG_ALL)
68 | #define DEBUG_STORE (1 | DEBUG_ALL)
69 | #define DEBUG_FINALIZE (0 | DEBUG_ALL)
70 | #define DEBUG_INSTR (0 | DEBUG_ALL) // Print instruction mnemonics as they are executed from queue
71 | #define DEBUG_EMU (1 | DEBUG_ALL) // Print debugging information concerning 8080 emulation mode state
72 | #define DEBUG_LOCK (0 | DEBUG_ALL) // Print a message when the LOCK pin is asserted on a cycle
73 |
74 | #define DEBUG_PROTO 0 // Insert debugging messages into serial output (Escaped by ##...##)
75 | #define DEBUG_CMD 0
76 |
77 | #define MAX_ERR_LEN 50 // Maximum length of an error string
78 |
79 |
80 | #define FINALIZE_TIMEOUT 30
81 | #define FINALIZE_EMU_TIMEOUT 90 // We need more time to exit emulation mode
82 | #define STORE_TIMEOUT 300
83 |
84 |
85 | const char RESPONSE_CHRS[] = {
86 | '!', '.'
87 | };
88 |
89 | const char VERSION_DAT[] = {
90 | 'a', 'r', 'd', '8', '0', '8', '8'
91 | };
92 |
93 | const uint8_t VERSION_NUM = 2;
94 |
95 | typedef enum {
96 | CmdNone = 0x00,
97 | CmdVersion = 0x01,
98 | CmdReset = 0x02,
99 | CmdLoad = 0x03,
100 | CmdCycle = 0x04,
101 | CmdReadAddressLatch= 0x05,
102 | CmdReadStatus = 0x06,
103 | CmdRead8288Command = 0x07,
104 | CmdRead8288Control = 0x08,
105 | CmdReadDataBus = 0x09,
106 | CmdWriteDataBus = 0x0A,
107 | CmdFinalize = 0x0B,
108 | CmdBeginStore = 0x0C,
109 | CmdStore = 0x0D,
110 | CmdQueueLen = 0x0E,
111 | CmdQueueBytes = 0x0F,
112 | CmdWritePin = 0x10,
113 | CmdReadPin = 0x11,
114 | CmdGetProgramState = 0x12,
115 | CmdLastError = 0x13,
116 | CmdGetCycleState = 0x14,
117 | CmdCycleGetCycleState = 0x15,
118 | CmdPrefetchStore = 0x16,
119 | CmdReadAddress = 0x17,
120 | CmdCpuType = 0x18,
121 | CmdEmulate8080 = 0x19,
122 | CmdInvalid = 0x1A,
123 | } server_command;
124 |
125 | const char *CMD_STRINGS[] = {
126 | "NONE",
127 | "VERSION",
128 | "RESET",
129 | "LOAD",
130 | "CYCLE",
131 | "READADDRLATCH",
132 | "READSTATUS",
133 | "READ8288CMD",
134 | "READ8288CTRL",
135 | "READDATABUS",
136 | "WRITEDATABUS",
137 | "FINALIZE",
138 | "BEGINSTORE",
139 | "STORE",
140 | "QUEUELEN",
141 | "QUEUEBYTES",
142 | "WRITEPIN",
143 | "READPIN",
144 | "GETPGMSTATE",
145 | "GETLASTERR",
146 | "GETCYCLESTATE",
147 | "CGETCYCLESTATE",
148 | "PREFETCHSTORE",
149 | "READADDRBUS",
150 | "CPUTYPE",
151 | "EMULATE8080",
152 | "INVALID",
153 | };
154 |
155 | typedef bool (*command_func)();
156 |
157 | #define RESPONSE_FAIL 0x00
158 | #define RESPONSE_OK 0x01
159 |
160 | // ASCII aliases for commands, mostly for interactive debugging
161 | const uint8_t CMD_ALIASES[] = {
162 | 0, // CmdNone
163 | 'v', // CmdVersion
164 | 'r', // CmdReset
165 | 'l', // CmdLoad
166 | 'c', // CmdCycle
167 | 'a', // CmdReadAddressLatch
168 | 's', // CmdReadStatus
169 | 't', // CmdRead8288Command
170 | 'u', // CmdRead8288Control
171 | 'r', // CmdReadDataBus
172 | 'w', // CmdWriteDataBus,
173 | 'z', // CmdFinalize
174 | 'm', // CmdBeginStore,
175 | 'w', // CmdStore,
176 | 'q', // CmdQueueLen,
177 | 'b', // CmdQueueBytes,
178 | 'x', // CmdWritePin,
179 | 'y', // CmdReadPin,
180 | 'g', // CmdGetProgramState
181 | 'e', // CmdGetLastError
182 | 'f', // CmdGetCycleStatus
183 | 'k', // CmdPrefetchStore
184 | 'i', // CmdReadAddress
185 | 'd', // CmdCpuType
186 | 'h', // CmdEmulate8080
187 | 0 // CmdInvalid
188 | };
189 |
190 | // List of valid arguments to CmdWritePin. Only these specific pins
191 | // can have state written to.
192 | const uint8_t WRITE_PINS[] = {
193 | 6, // READY
194 | 7, // TEST
195 | 12, // INTR
196 | 13, // NMI
197 | };
198 |
199 | // Number of argument bytes expected for each command
200 | const uint8_t CMD_INPUTS[] = {
201 | 0, // CmdNone
202 | 0, // CmdVersion
203 | 0, // CmdReset
204 | 28, // CmdLoad
205 | 0, // CmdCycle
206 | 0, // CmdReadAddressLatch
207 | 0, // CmdReadStatus
208 | 0, // CmdRead8288Command
209 | 0, // CmdRead8288Control
210 | 0, // CmdReadDataBus
211 | 2, // CmdWriteDataBus
212 | 0, // CmdFinalize
213 | 0, // CmdBeginStore,
214 | 0, // CmdStore,
215 | 0, // CmdQueueLen,
216 | 0, // CmdQueueBytes,
217 | 2, // CmdWritePin,
218 | 1, // CmdReadPin,
219 | 0, // CmdGetProgramState,
220 | 0, // CmdGetLastError,
221 | 0, // CmdGetCycleState,
222 | 0, // CmdCycleGetCycleState,
223 | 0, // CmdPrefetchStore,
224 | 0, // CmdReadAddress
225 | 0, // CmdCpuType
226 | 0, // CmdEmulate8080
227 | 0, // CmdInvalid
228 | };
229 |
230 | typedef enum {
231 | WaitingForCommand = 0x01,
232 | ReadingCommand,
233 | ExecutingCommand
234 | } command_state_t;
235 |
236 | typedef struct server_state {
237 | command_state_t c_state;
238 | server_command cmd;
239 | uint8_t cmd_byte_n;
240 | uint8_t cmd_bytes_expected;
241 | uint32_t cmd_start_time;
242 | } Server;
243 |
244 | bool cmd_version(void);
245 | bool cmd_reset(void);
246 | bool cmd_load(void);
247 | bool cmd_cycle(void);
248 | bool cmd_read_address_latch(void);
249 | bool cmd_read_status(void);
250 | bool cmd_read_8288_command(void);
251 | bool cmd_read_8288_control(void);
252 | bool cmd_read_data_bus(void);
253 | bool cmd_write_data_bus(void);
254 | bool cmd_finalize(void);
255 | bool cmd_begin_store(void);
256 | bool cmd_store(void);
257 | bool cmd_queue_len(void);
258 | bool cmd_queue_bytes(void);
259 | bool cmd_write_pin(void);
260 | bool cmd_read_pin(void);
261 | bool cmd_get_program_state(void);
262 | bool cmd_get_last_error(void);
263 | bool cmd_get_cycle_state(void);
264 | bool cmd_cycle_get_cycle_state(void);
265 | bool cmd_prefetch_store(void);
266 | bool cmd_read_address(void);
267 | bool cmd_cpu_type(void);
268 | bool cmd_invalid(void);
269 | bool cmd_emu8080(void);
270 |
271 | #endif
272 |
--------------------------------------------------------------------------------
/sketches/cpu_server/gpio_pins.h:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino8088 Copyright 2022-2025 Daniel Balsom
3 | https://github.com/dbalsom/arduino_8088
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a
6 | copy of this software and associated documentation files (the “Software”),
7 | to deal in the Software without restriction, including without limitation
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 | and/or sell copies of the Software, and to permit persons to whom the
10 | Software is furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 | DEALINGS IN THE SOFTWARE.
22 | */
23 | #ifndef _ARDUINO8088_PINS_H
24 | #define _ARDUINO8088_PINS_H
25 |
26 | #define BIT00 (1u << 0)
27 | #define BIT01 (1u << 1)
28 | #define BIT02 (1u << 2)
29 | #define BIT03 (1u << 3)
30 | #define BIT04 (1u << 4)
31 | #define BIT05 (1u << 5)
32 | #define BIT06 (1u << 6)
33 | #define BIT07 (1u << 7)
34 | #define BIT08 (1u << 8)
35 | #define BIT09 (1u << 9)
36 | #define BIT10 (1u << 10)
37 | #define BIT11 (1u << 11)
38 | #define BIT12 (1u << 12)
39 | #define BIT13 (1u << 13)
40 | #define BIT14 (1u << 14)
41 | #define BIT15 (1u << 15)
42 | #define BIT16 (1u << 16)
43 | #define BIT17 (1u << 17)
44 | #define BIT18 (1u << 18)
45 | #define BIT19 (1u << 19)
46 | #define BIT20 (1u << 20)
47 | #define BIT21 (1u << 21)
48 | #define BIT22 (1u << 22)
49 | #define BIT23 (1u << 23)
50 | #define BIT24 (1u << 24)
51 | #define BIT25 (1u << 25)
52 | #define BIT26 (1u << 26)
53 | #define BIT27 (1u << 27)
54 | #define BIT28 (1u << 28)
55 | #define BIT29 (1u << 29)
56 | #define BIT30 (1u << 30)
57 | #define BIT31 (1u << 31)
58 |
59 | #define SET_BIT00 (1u << 0)
60 | #define SET_BIT01 (1u << 1)
61 | #define SET_BIT02 (1u << 2)
62 | #define SET_BIT03 (1u << 3)
63 | #define SET_BIT04 (1u << 4)
64 | #define SET_BIT05 (1u << 5)
65 | #define SET_BIT06 (1u << 6)
66 | #define SET_BIT07 (1u << 7)
67 | #define SET_BIT08 (1u << 8)
68 | #define SET_BIT09 (1u << 9)
69 | #define SET_BIT10 (1u << 10)
70 | #define SET_BIT11 (1u << 11)
71 | #define SET_BIT12 (1u << 12)
72 | #define SET_BIT13 (1u << 13)
73 | #define SET_BIT14 (1u << 14)
74 | #define SET_BIT15 (1u << 15)
75 |
76 | #define CLR_BIT00 ((1u << 0) << 16)
77 | #define CLR_BIT01 ((1u << 1) << 16)
78 | #define CLR_BIT02 ((1u << 2) << 16)
79 | #define CLR_BIT03 ((1u << 3) << 16)
80 | #define CLR_BIT04 ((1u << 4) << 16)
81 | #define CLR_BIT05 ((1u << 5) << 16)
82 | #define CLR_BIT06 ((1u << 6) << 16)
83 | #define CLR_BIT07 ((1u << 7) << 16)
84 | #define CLR_BIT08 ((1u << 8) << 16)
85 | #define CLR_BIT09 ((1u << 9) << 16)
86 | #define CLR_BIT10 ((1u << 10) << 16)
87 | #define CLR_BIT11 ((1u << 11) << 16)
88 | #define CLR_BIT12 ((1u << 12) << 16)
89 | #define CLR_BIT13 ((1u << 13) << 16)
90 | #define CLR_BIT14 ((1u << 14) << 16)
91 | #define CLR_BIT15 ((1u << 15) << 16)
92 |
93 | #if defined (ARDUINO_GIGA)
94 | // If Arduino GIGA
95 |
96 | #elif defined(__SAM3X8E__)
97 | // If Arduino DUE
98 | #define READ_PIN_D08 ((PIOC->PIO_PDSR & BIT22) != 0)
99 | #define READ_PIN_D09 ((PIOC->PIO_PDSR & BIT21) != 0)
100 | #define READ_PIN_D10 ((PIOC->PIO_PDSR & BIT29) != 0)
101 |
102 | #define READ_PIN_D14 ((PIOD->PIO_PDSR & BIT04) != 0)
103 | #define READ_PIN_D15 ((PIOD->PIO_PDSR & BIT05) != 0)
104 | #define READ_PIN_D16 ((PIOA->PIO_PDSR & BIT13) != 0)
105 | #define READ_PIN_D17 ((PIOA->PIO_PDSR & BIT12) != 0)
106 | #define READ_PIN_D18 ((PIOA->PIO_PDSR & BIT11) != 0)
107 | #define READ_PIN_D19 ((PIOA->PIO_PDSR & BIT10) != 0)
108 |
109 | #define READ_PIN_D38 ((PIOC->PIO_PDSR & BIT06) != 0)
110 | #define READ_PIN_D39 ((PIOC->PIO_PDSR & BIT07) != 0)
111 | #define READ_PIN_D40 ((PIOC->PIO_PDSR & BIT08) != 0)
112 |
113 | #define READ_PIN_D45 ((PIOC->PIO_PDSR & BIT18) != 0)
114 | #define READ_PIN_D46 ((PIOC->PIO_PDSR & BIT17) != 0)
115 | #define READ_PIN_D47 ((PIOC->PIO_PDSR & BIT16) != 0)
116 | #define READ_PIN_D48 ((PIOC->PIO_PDSR & BIT15) != 0)
117 |
118 | #define READ_PIN_D50 ((PIOC->PIO_PDSR & BIT13) != 0)
119 | #define READ_PIN_D51 ((PIOC->PIO_PDSR & BIT12) != 0)
120 | #define READ_PIN_D52 ((PIOB->PIO_PDSR & BIT21) != 0)
121 | #define READ_PIN_D53 ((PIOB->PIO_PDSR & BIT14) != 0)
122 |
123 | #elif defined(__AVR_ATmega2560__)
124 | // If Arduino MEGA
125 | #define READ_PIN_D08 ((PINH & BIT5) != 0) // QS1 - Pin 8 (H5)
126 | #define READ_PIN_D09 ((PINH & BIT6) != 0) // QS0 - Pin 9 (H6)
127 |
128 | #define READ_PIN_D14 ((PINJ & BIT1) != 0) // S0 - Pin 14
129 | #define READ_PIN_D15 ((PINJ & BIT0) != 0) // S1 - Pin 15
130 | #define READ_PIN_D16 ((PINH & BIT1) != 0) // S2 - Pin 16 (H1)
131 | #define READ_PIN_D17 ((PINH & BIT0) != 0) // BHE - Pin 17 (H0)
132 | #define READ_PIN_D38 ((PIND & BIT7) != 0) // S3 - Pin 38 (D7)
133 | #define READ_PIN_D39 ((PING & BIT2) != 0) // S4 - Pin 39 (G2)
134 | #define READ_PIN_D40 ((PING & BIT1) != 0) // S5 - Pin 40 (G1)
135 |
136 | #define READ_PIN_A0 ((PINF & 0x01) != 0)
137 | #define READ_PIN_A1 ((PINF & 0x02) != 0)
138 | #define READ_PIN_D50 ((PINB & 0x08) != 0)
139 | #define READ_PIN_D51 ((PINB & 0x04) != 0)
140 | #define READ_PIN_D52 ((PINB & 0x02) != 0)
141 | #define READ_PIN_D53 ((PINB & 0x01) != 0)
142 | #define READ_PIN_D46 ((PINL & 0x08) != 0)
143 | #define READ_PIN_D48 ((PINL & 0x02) != 0)
144 | #define READ_PIN_D47 ((PINL & 0x04) != 0)
145 | #define READ_PIN_D45 ((PINL & 0x10) != 0)
146 | #endif
147 |
148 | #endif // _ARDUINO8088_PINS_H
--------------------------------------------------------------------------------
/sketches/cpu_server/opcodes.h:
--------------------------------------------------------------------------------
1 | /*
2 | Arduino8088 Copyright 2022-2025 Daniel Balsom
3 | https://github.com/dbalsom/arduino_8088
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a
6 | copy of this software and associated documentation files (the “Software”),
7 | to deal in the Software without restriction, including without limitation
8 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 | and/or sell copies of the Software, and to permit persons to whom the
10 | Software is furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 | DEALINGS IN THE SOFTWARE.
22 | */
23 | #ifndef _ARDUINO8088_OPCODES_H
24 | #define _ARDUINO8088_OPCODES_H
25 |
26 | #define OPCODE_NOP 0x90
27 | #define OPCODE_80NOP 0x00
28 | #define OPCODE_DOUBLENOP 0x9090
29 | #define OPCODE_DOUBLE_80NOP 0x0000
30 |
31 | #define MODRM_OP(M) (((M & 0b00111000) >> 3) & 0x07)
32 |
33 | #define GRP1 105
34 | #define GRP2A 106
35 | #define GRP2B 110
36 | #define GRP3 107
37 | #define GRP4 108
38 | #define GRP5 109
39 | #define IS_GRP_OP(O) ((OPCODE_REFS[O] >= GRP1) && (OPCODE_REFS[O] <= GRP2B))
40 |
41 | // LUT of primary opcode to Mnemonic (Or Group name)
42 | static const uint8_t OPCODE_REFS[] = {
43 | 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 1, 2, 4, 4, 4, 4, 4, 4, 1, 2, 5, 5, 5, 5, 5, 5, 1, 2,
44 | 6, 6, 6, 6, 6, 6, 7, 8, 9, 9, 9, 9, 9, 9, 10, 11, 12, 12, 12, 12, 12, 12, 13, 14, 15, 15, 15,
45 | 15, 15, 15, 16, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 1, 1, 1, 1,
46 | 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
47 | 35, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 105, 105, 105, 105, 36, 36,
48 | 37, 37, 38, 38, 38, 38, 38, 39, 38, 2, 111, 37, 37, 37, 37, 37, 37, 37, 40, 41, 42, 103, 43,
49 | 44, 45, 46, 38, 38, 38, 38, 47, 48, 49, 50, 36, 36, 51, 52, 53, 54, 55, 56, 38, 38, 38, 38, 38,
50 | 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 57, 57, 57, 57, 58, 59, 38, 38, 60, 60, 60, 60, 61,
51 | 61, 62, 63, 106, 106, 110, 110, 71, 73, 104, 75, 104, 104, 104, 104, 104, 104, 104, 104, 76,
52 | 77, 78, 79, 80, 80, 81, 81, 82, 83, 84, 83, 80, 80, 81, 81, 85, 104, 86, 87, 89, 90, 107, 107,
53 | 97, 98, 99, 100, 101, 102, 108, 109,
54 | };
55 |
56 | static const uint8_t OPCODE_8080_REFS[] = {
57 | 0, 1, 2, 3, 4, 5, 6, 7, 80, 8, 9, 10, 4, 5, 6, 11, 80, 1, 2, 3, 4, 5, 6, 12, 80, 8, 9, 10, 4,
58 | 5, 6, 13, 80, 1, 14, 3, 4, 5, 6, 15, 80, 8, 16, 10, 4, 5, 6, 17, 80, 1, 18, 3, 4, 5, 6, 19, 80,
59 | 8, 20, 10, 4, 5, 6, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
60 | 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
61 | 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 24, 24,
62 | 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27,
63 | 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30,
64 | 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
65 | 42, 80, 43, 44, 45, 39, 46, 33, 47, 48, 49, 37, 50, 39, 51, 80, 52, 53, 54, 80, 55, 39, 56, 33,
66 | 57, 58, 59, 37, 60, 39, 61, 62, 63, 64, 65, 81, 68, 39, 69, 33, 70, 71, 72, 37, 73, 39, 74, 75,
67 | 76, 77, 78, 80, 79, 39,
68 | };
69 |
70 | static char *OPCODE_STRS[] = {
71 | "ADD",
72 | "PUSH",
73 | "POP",
74 | "OR",
75 | "ADC",
76 | "SBB",
77 | "AND",
78 | "ES",
79 | "DAA",
80 | "SUB",
81 | "CS",
82 | "DAS",
83 | "XOR",
84 | "SS",
85 | "AAA",
86 | "CMP",
87 | "DS",
88 | "AAS",
89 | "INC",
90 | "DEC",
91 | "JO",
92 | "JNO",
93 | "JB",
94 | "JNB",
95 | "JZ",
96 | "JNZ",
97 | "JBE",
98 | "JNBE",
99 | "JS",
100 | "JNS",
101 | "JP",
102 | "JNP",
103 | "JL",
104 | "JNL",
105 | "JLE",
106 | "JNLE",
107 | "TEST",
108 | "XCHG",
109 | "MOV",
110 | "LEA",
111 | "CBW",
112 | "CWD",
113 | "CALLF",
114 | "PUSHF",
115 | "POPF",
116 | "SAHF",
117 | "LAHF",
118 | "MOVSB",
119 | "MOVSW",
120 | "CMPSB",
121 | "CMPSW",
122 | "STOSB",
123 | "STOSW",
124 | "LODSB",
125 | "LODSW",
126 | "SCASB",
127 | "SCASW",
128 | "RETN",
129 | "LES",
130 | "LDS",
131 | "RETF",
132 | "INT",
133 | "INTO",
134 | "IRET",
135 | "ROL",
136 | "ROR",
137 | "RCL",
138 | "RCR",
139 | "SHL",
140 | "SHR",
141 | "SAR",
142 | "AAM",
143 | "AMX",
144 | "AAD",
145 | "ADX",
146 | "XLAT",
147 | "LOOPNE",
148 | "LOOPE",
149 | "LOOP",
150 | "JCXZ",
151 | "IN",
152 | "OUT",
153 | "CALL",
154 | "JMP",
155 | "JMPF",
156 | "LOCK",
157 | "REPNZ",
158 | "REP",
159 | "REPZ",
160 | "HLT",
161 | "CMC",
162 | "NOT",
163 | "NEG",
164 | "MUL",
165 | "IMUL",
166 | "DIV",
167 | "IDIV",
168 | "CLC",
169 | "STC",
170 | "CLI",
171 | "STI",
172 | "CLD",
173 | "STD",
174 | "WAIT",
175 | "INVAL",
176 | "GRP1",
177 | "GRP2A",
178 | "GRP3",
179 | "GRP4",
180 | "GRP5",
181 | "GRP2B",
182 | "NOP",
183 |
184 | };
185 |
186 | // 0x80 - 0x81
187 | static char *OPCODE_STRS_GRP1[] = {
188 | "ADD",
189 | "OR",
190 | "ADC",
191 | "SBB",
192 | "AND",
193 | "SUB",
194 | "XOR",
195 | "CMP"
196 | };
197 |
198 | // 0xD0 - 0xD1
199 | static char *OPCODE_STRS_GRP2A[] = {
200 | "ROL",
201 | "ROR",
202 | "RCL",
203 | "RCR",
204 | "SHL",
205 | "SHR",
206 | "SETMO",
207 | "SAR"
208 | };
209 |
210 | // 0xD2 - 0xD3
211 | static char *OPCODE_STRS_GRP2B[] = {
212 | "ROL",
213 | "ROR",
214 | "RCL",
215 | "RCR",
216 | "SHL",
217 | "SHR",
218 | "SETMOC",
219 | "SAR"
220 | };
221 |
222 | // 0xF6 - 0xF7
223 | static char *OPCODE_STRS_GRP3[] = {
224 | "TEST",
225 | "TEST",
226 | "NOT",
227 | "NEG",
228 | "MUL",
229 | "IMUL",
230 | "DIV",
231 | "IDIV",
232 | };
233 |
234 | // 0xFE
235 | static char *OPCODE_STRS_GRP4[] = {
236 | "INC",
237 | "DEC",
238 | "INVAL",
239 | "INVAL",
240 | "INVAL",
241 | "INVAL",
242 | "INVAL",
243 | "INVAL"
244 | };
245 |
246 | // 0xFF
247 | static char *OPCODE_STRS_GRP5[] = {
248 | "INC",
249 | "DEC",
250 | "CALL",
251 | "CALLF",
252 | "JMP",
253 | "JMPF",
254 | "PUSH",
255 | "INVAL"
256 | };
257 |
258 | static char *OPCODE_8080_STRS[] = {
259 | "NOP",
260 | "LXI",
261 | "STAX",
262 | "INX",
263 | "INR",
264 | "DCR",
265 | "MVI",
266 | "RLC",
267 | "DAD",
268 | "LDAX",
269 | "DCX",
270 | "RRC",
271 | "RAL",
272 | "RAR",
273 | "SHLD",
274 | "DAA",
275 | "LHLD",
276 | "CMA",
277 | "STA",
278 | "STC",
279 | "LDA",
280 | "CMC",
281 | "MOV",
282 | "HLT",
283 | "ADD",
284 | "ADC",
285 | "SUB",
286 | "SBB",
287 | "ANA",
288 | "XRA",
289 | "ORA",
290 | "CMP",
291 | "RNZ",
292 | "POP",
293 | "JNZ",
294 | "JMP",
295 | "CNZ",
296 | "PUSH",
297 | "ADI",
298 | "RST",
299 | "RZ",
300 | "RET",
301 | "JZ",
302 | "CZ",
303 | "CALL",
304 | "ACI",
305 | "RNC",
306 | "JNC",
307 | "OUT",
308 | "CNC",
309 | "SUI",
310 | "RC",
311 | "JC",
312 | "IN",
313 | "CC",
314 | "SBI",
315 | "RPO",
316 | "JPO",
317 | "XTHL",
318 | "CPO",
319 | "ANI",
320 | "RPE",
321 | "PCHL",
322 | "JPE",
323 | "XCHG",
324 | "CPE",
325 | "CALLN",
326 | "RETEM",
327 | "XRI",
328 | "RP",
329 | "JP",
330 | "DI",
331 | "CP",
332 | "ORI",
333 | "RM",
334 | "SPHL",
335 | "JM",
336 | "EI",
337 | "CM",
338 | "CPI",
339 | "INVAL",
340 | "EXT",
341 | };
342 |
343 | #endif
--------------------------------------------------------------------------------
/sketches/run_program/arduino8088.h:
--------------------------------------------------------------------------------
1 | /*
2 | (C)2023 Daniel Balsom
3 | https://github.com/dbalsom/arduino_8088
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 |
18 | */
19 | #ifndef _ARDUINO8088_H
20 | #define _ARDUINO8088_H
21 |
22 | #define BAUD_RATE 1000000
23 |
24 | // Determines if the cycle count is reset to 0 on entering Execute state. Recommended as we
25 | // dont usually care how long the setup program took
26 | #define RESET_CYCLE_NUMBER 1
27 |
28 | // Amount of virtual RAM in bytes - due to the naive way of searching RAM keep this value as
29 | // low as necessary
30 | #define RAM_SIZE 128
31 |
32 | // Determines whether to jump to the specified load segment before executing the load program,
33 | // or just let the address lines roll over.
34 | // Enables the JumpVector state.
35 | // If disabled, user programs shouldn't use the first few k of memory.
36 | #define USE_LOAD_SEG 0
37 |
38 | // Code segment to use for load program. User programs shouldn't jump here.
39 | const u16 LOAD_SEG = 0xD000;
40 |
41 | // Maximum size of the processor instruction queue. For 8088 == 4, 8086 == 6.
42 | #define QUEUE_MAX 4
43 |
44 | // Debugging output for queue operations (flushes, regular queue ops are always reported)
45 | #define TRACE_QUEUE 0
46 |
47 | // Report state changes and time spent in each state
48 | #define TRACE_STATE 1
49 |
50 | // States for main program state machine:
51 | // ----------------------------------------------------------------------------
52 | // Reset - CPU is being reset
53 | // JumpVector - CPU is jumping from reset vector to load segment (optional?)
54 | // Load - CPU is executing register Load program
55 | // LoadDone - CPU has finished executing Load program and waiting for program execution to start
56 | // Execute - CPU is executing user program
57 | // Store - CPU has is executing register Store program
58 | typedef enum {
59 | Reset = 0,
60 | JumpVector,
61 | Load,
62 | LoadDone,
63 | PrefetchSetup,
64 | Execute,
65 | Store,
66 | Done
67 | } machine_state;
68 |
69 | // These defines control cycle status output for each state.
70 | #define TRACE_RESET 1
71 | #define TRACE_VECTOR 0
72 | #define TRACE_LOAD 0
73 | #define TRACE_PREFETCH 0
74 | #define TRACE_EXECUTE 1
75 | #define TRACE_STORE 0
76 | #define DEBUG_STORE 0
77 |
78 | static const char MACHINE_STATE_CHARS[] = {
79 | 'R', 'J', 'L', 'M', 'P', 'E', 'S', 'D'
80 | };
81 |
82 | static const char* MACHINE_STATE_STRINGS[] = {
83 | "Reset",
84 | "JumpVector",
85 | "Load",
86 | "LoadDone",
87 | "PrefetchSetup",
88 | "Execute",
89 | "Store",
90 | "Done"
91 | };
92 |
93 | // Prefetch states
94 | typedef enum {
95 | FETCH_IDLE = 0,
96 | FETCH_SCHEDULED = 1,
97 | FETCH_ABORT = 2,
98 | FETCH_DELAY = 3,
99 | FETCH_IN_PROGRESS = 4,
100 | FETCH_CANCELLED = 5,
101 | } f_state;
102 |
103 | static const char FETCH_STATE_CHARS[] = {
104 | ' ', 'S', 'A', 'D', ' ', 'C'
105 | };
106 |
107 | // Bus transfer states, as determined by status lines S0-S2.
108 | typedef enum {
109 | IRQA = 0, // IRQ Acknowledge
110 | IOR = 1, // IO Read
111 | IOW = 2, // IO Write
112 | HALT = 3, // Halt
113 | CODE = 4, // Code
114 | MEMR = 5, // Memory Read
115 | MEMW = 6, // Memory Write
116 | PASV = 7 // Passive
117 | } s_state;
118 |
119 | // Strings for printing bus states cycles.
120 | const char *BUS_STATE_STRINGS[] = {
121 | "IRQA",
122 | "IOR ",
123 | "IOW ",
124 | "HALT",
125 | "CODE",
126 | "MEMR",
127 | "MEMW",
128 | "PASV"
129 | };
130 |
131 | // Bus transfer cycles. Tw is wait state, inserted if READY is not asserted during T3.
132 | typedef enum {
133 | t1 = 0,
134 | t2 = 1,
135 | t3 = 2,
136 | t4 = 3,
137 | tw = 4
138 | } t_cycle;
139 |
140 | // Strings for printing bus transfer cycles.
141 | const char *CYCLE_STRINGS[] = {
142 | "t1", "t2", "t3", "t4", "tw"
143 | };
144 |
145 | typedef enum {
146 | SegES,
147 | SegSS,
148 | SegCS,
149 | SegDS
150 | } segment;
151 |
152 | const char *SEGMENT_STRINGS[] = {
153 | "ES", "SS", "CS", "DS"
154 | };
155 |
156 | // CPU Registers
157 | typedef struct registers {
158 | u16 ax;
159 | u16 bx;
160 | u16 cx;
161 | u16 dx;
162 | u16 ss;
163 | u16 sp;
164 | u16 flags;
165 | u16 ip;
166 | u16 cs;
167 | u16 ds;
168 | u16 es;
169 | u16 bp;
170 | u16 si;
171 | u16 di;
172 | } registers __attribute__((packed)) ;
173 |
174 | // Processor instruction queue
175 | typedef struct queue {
176 | u8 queue[QUEUE_MAX];
177 | u8 types[QUEUE_MAX];
178 | u8 front;
179 | u8 back;
180 | u8 len;
181 | } queue;
182 |
183 | typedef struct {
184 | u8 queue[2];
185 | u8 front;
186 | u8 back;
187 | u8 len;
188 | } pf_queue;
189 |
190 | #define QUEUE_IDLE 0x00
191 | #define QUEUE_FIRST 0x01
192 | #define QUEUE_FLUSHED 0x02
193 | #define QUEUE_SUBSEQUENT 0x03
194 |
195 | // Strings for pretty-printing instruction queue status from QS0,QS1
196 | // '.' = Idle
197 | // 'F' = First byte fetched
198 | // 'E' = Queue Emptied
199 | // 'S' = Subsequent byte fetched
200 | const char QUEUE_STATUS_CHARS[] = {
201 | ' ', 'F', 'E', 'S'
202 | };
203 |
204 | // Data bus data types. These are stored when pushing to the prefetch queue, so we know what
205 | // kind of byte we are retrieving from the processor queue. This allows us to detect program
206 | // end when the first non-program byte is fetched as the first byte of an instruction.
207 | #define DATA_PROGRAM 0x00
208 | #define DATA_PROGRAM_END 0x01
209 | #define DATA_PREFETCH_PROGRAM 0x02
210 |
211 | typedef struct program_stats {
212 | u16 code_read_xfers;
213 | u16 memory_read_xfers;
214 | u16 memory_write_xfers;
215 | u16 io_read_xfers;
216 | u16 io_write_xfers;
217 | u32 idle_cycles;
218 | u32 program_cycles;
219 | } p_stats;
220 |
221 | // Main CPU State
222 | typedef struct cpu {
223 |
224 | u8 prefetch_len;
225 | bool doing_reset;
226 | machine_state v_state;
227 | u32 state_begin_time;
228 | u32 address_latch;
229 | s_state mcycle_state; // Cycle state is bus state latched on T1
230 | s_state bus_state; // Bus state is current status of S0-S2 at given cycle (may not be valid)
231 | t_cycle bus_cycle;
232 | u32 transfer_n; // Number of consecutive memory transfers for the current operation.
233 | u8 op_width; // Width of the current instruction (0==Byte/1==Word)
234 | u8 data_bus;
235 | u8 data_type;
236 | u8 status0; // S0-S5, QS0 & QS1
237 | u8 command_bits; // 8288 command outputs
238 | u8 control_bits; // 8288 control outputs
239 | u16 v_pc; // Virtual program counter
240 | u16 p_pc; // Virtual program counter for queue setup (prefetch) state
241 | u8 p_popread_n; // Stack read count in prefetch state
242 | registers post_regs; // Register state retrieved from Store program
243 | u8 *readback_p;
244 | queue queue; // Instruction queue
245 | pf_queue pf_stack; // Prefetch operation stack
246 | u32 pf_scheduled_id; // Unique identifier for next scheduled prefetch operation
247 | f_state fetch_state; // Prefetch state
248 | bool fetch_scheduled; // A fetch has been scheduled / used for prefetch abort detection
249 | u8 fetch_delay; // Fetch delay cycles
250 | u8 opcode; // Currently executing opcode
251 | u8 qb; // Last byte value read from queue
252 | u8 qt; // Last data type read from queue
253 | bool q_ff; // Did we fetch a first instruction byte from the queue this cycle?
254 | u8 q_fn; // What # byte of instruction did we fetch?
255 | } Cpu;
256 |
257 | // How many cycles to hold the RESET signal high. Intel says "greater than 4" although 4 seems to work.
258 | const int RESET_HOLD_CYCLE_COUNT = 5;
259 | // How many cycles it takes to reset the CPU after RESET signal goes low. First ALE should occur after this many cycles.
260 | const int RESET_CYCLE_COUNT = 7;
261 | // If we didn't receive an ALE signal after this many cycles, give up
262 | const int RESET_CYCLE_TIMEOUT = 14;
263 |
264 | // ----------------------------- CPU FLAGS ----------------------------------//
265 | const u16 CPU_FLAG_CARRY = 0b0000000000000001;
266 | const u16 CPU_FLAG_RESERVED1 = 0b0000000000000010;
267 | const u16 CPU_FLAG_PARITY = 0b0000000000000100;
268 | const u16 CPU_FLAG_RESERVED3 = 0b0000000000001000;
269 | const u16 CPU_FLAG_AUX_CARRY = 0b0000000000010000;
270 | const u16 CPU_FLAG_RESERVED5 = 0b0000000000100000;
271 | const u16 CPU_FLAG_ZERO = 0b0000000001000000;
272 | const u16 CPU_FLAG_SIGN = 0b0000000010000000;
273 | const u16 CPU_FLAG_TRAP = 0b0000000100000000;
274 | const u16 CPU_FLAG_INTERRUPT = 0b0000001000000000;
275 | const u16 CPU_FLAG_DIRECTION = 0b0000010000000000;
276 | const u16 CPU_FLAG_OVERFLOW = 0b0000100000000000;
277 |
278 | #define CPU_FLAG_DEFAULT_SET 0xF002
279 | #define CPU_FLAG_DEFAULT_CLEAR 0xFFD7
280 | // ----------------------------- GPIO PINS ----------------------------------//
281 | #define BIT7 0x80
282 | #define BIT6 0x40
283 | #define BIT5 0x20
284 | #define BIT4 0x10
285 | #define BIT3 0x08
286 | #define BIT2 0x04
287 | #define BIT1 0x02
288 | #define BIT0 0x01
289 |
290 | // Time in microseconds to wait after setting clock HIGH or LOW
291 | #define CLOCK_PIN_HIGH_DELAY 2
292 | #define CLOCK_PIN_LOW_DELAY 0
293 |
294 | // Microseconds to wait after a pin direction change. Without some sort of delay
295 | // a subsequent read/write may fail.
296 | #define PIN_CHANGE_DELAY 4
297 |
298 | // ------------------------- CPU Control pins ---------------------------------
299 |
300 | // Clock line #4 is controlled by PORTG bit #5.
301 | const int CLK_PIN = 4;
302 | #define SET_CLOCK_LOW PORTG &= ~0x20
303 | #define SET_CLOCK_HIGH PORTG |= 0x20
304 |
305 | // Reset pin #5 is controlled by PORTE bit #3.
306 | const int RESET_PIN = 5;
307 | #define SET_RESET_LOW PORTE &= ~0x08
308 | #define SET_RESET_HIGH PORTE |= 0x08
309 |
310 | // -------------------------- CPU Input pins ----------------------------------
311 |
312 | // READY pin #6 is written by PORTH bit #3
313 | #define READY_PIN 6
314 | #define WRITE_READY_PIN(x) (PORTH |= ((x) << 3))
315 |
316 | // TEST pin #7 is written by PORTH bit #4
317 | #define TEST_PIN 7
318 | #define WRITE_TEST_PIN(x) (PORTH |= ((x) << 4))
319 |
320 | // LOCK pin #10 is written by PORTB bit #4
321 | #define LOCK_PIN 10
322 | #define WRITE_LOCK_PIN(x) (PORTB |= ((x) << 4))
323 |
324 | // INTR pin #12 is written by PORTB bit #6
325 | #define INTR_PIN 12
326 | #define WRITE_INTR_PIN(x) (PORTB |= ((x) << 6))
327 |
328 | // NMI pin #13 is written to by PORTB bit #7
329 | #define NMI_PIN 13
330 | #define WRITE_NMI_PIN(x) (PORTB |= ((x) << 7))
331 |
332 | // -------------------------- CPU Output pins ---------------------------------
333 | #define RQ_PIN 3
334 |
335 | // --------------------------8288 Control Inputs ------------------------------
336 | #define AEN_PIN 54
337 | #define READ_AEN_PIN ((PINF & 0x01) != 0)
338 | #define WRITE_AEN_PIN(x) ((PINF |= x)
339 |
340 | #define CEN_PIN 55
341 | #define READ_CEN_PIN ((PINF & 0x02) != 0)
342 | #define WRITE_CEN_PIN(x) ((PINF |= ((x) << 1))
343 |
344 | // --------------------------8288 Control lines -------------------------------
345 | // ALE pin #50 is read by PINB bit #3
346 | #define ALE_PIN 50
347 | #define READ_ALE_PIN ((PINB & 0x08) != 0)
348 |
349 | // DTR pin #49 is read by PINL bit #0
350 | #define DTR_PIN 49
351 | #define READ_DTR_PIN ((PINL & 0x01) != 0)
352 |
353 | // MCE/PDEN pin #43 is read by PINL bit #6
354 | #define MCEPDEN_PIN 43
355 | #define READ_MCEPDEN_PIN ((PINL & 0x40) != 0)
356 |
357 | // DEN pin #44 is read by PINL bit #5
358 | #define DEN_PIN 44
359 | #define READ_DEN_PIN ((PINL & 0x20) != 0)
360 |
361 | // --------------------------8288 Command lines -------------------------------
362 | // MRDC pin #51 is read by PINB bit #2
363 | #define MRDC_PIN 51
364 | #define READ_MRDC_PIN ((PINB & 0x04) != 0)
365 |
366 | // AMWC pin #52 is read by PINB bit #1
367 | #define AMWC_PIN 52
368 | #define READ_AMWC_PIN ((PINB & 0x02) != 0)
369 |
370 | // MWTC pin #53 is read by PINB bit #0
371 | #define MWTC_PIN 53
372 | #define READ_MWTC_PIN ((PINB & 0x01) != 0)
373 |
374 | // IORC pin #46 is read by PINL bit #3
375 | #define IORC_PIN 46
376 | #define READ_IORC_PIN ((PINL & 0x08) != 0)
377 |
378 | // AIOWC pin #48 is read by PINL bit #1
379 | #define AIOWC_PIN 48
380 | #define READ_AIOWC_PIN ((PINL & 0x02) != 0)
381 |
382 | // IOWC pin #47 is read by PINL bit #2
383 | #define IOWC_PIN 47
384 | #define READ_IOWC_PIN ((PINL & 0x04) != 0)
385 |
386 | // INTA pin #45 is read by PINL bit #4
387 | #define INTA_PIN 45
388 | #define READ_INTA_PIN ((PINL & 0x10) != 0)
389 |
390 | // Address pins, used for slow address reading via digitalRead()
391 | const int ADDRESS_PINS[] = {
392 | 23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42
393 | };
394 | const int ADDRESS_LINES = 20;
395 |
396 | // All output pins, used to set pin direction on setup
397 | const int OUTPUT_PINS[] = {
398 | 4, // CLK
399 | 5, // RESET
400 | 6, // READY
401 | 7, // TEST
402 | 12, // INTR
403 | 13, // NMI
404 | 54, // AEN
405 | 55, // CEN
406 | };
407 |
408 | // All input pins, used to set pin direction on setup
409 | const int INPUT_PINS[] = {
410 | 3,8,9,10,11,14,15,16,
411 | 23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,
412 | 43,44,45,46,47,48,49,50,51,52,53,
413 | };
414 |
415 | unsigned long CYCLE_NUM = 0;
416 |
417 | // Bit reverse LUT from http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
418 | static const u8 BIT_REVERSE_TABLE[256] =
419 | {
420 | # define R2(n) n, n + 2*64, n + 1*64, n + 3*64
421 | # define R4(n) R2(n), R2(n + 2*16), R2(n + 1*16), R2(n + 3*16)
422 | # define R6(n) R4(n), R4(n + 2*4 ), R4(n + 1*4 ), R4(n + 3*4 )
423 | R6(0), R6(2), R6(1), R6(3)
424 | };
425 |
426 | // Bit used to indicate that an entry in RAM has been written to
427 | #define RAM_WRITE_FLAG 0x80000000
428 | #define RAM_ADDR_MASK 0x7FFFFFFF
429 |
430 | // --------------------- Function declarations --------------------------------
431 | u32 calc_flat_address(u16 seg, u16 offset);
432 |
433 | void clock_tick();
434 | void data_bus_write(u8 byte);
435 | u8 data_bus_read();
436 |
437 | void latch_address();
438 | void read_status0();
439 |
440 | void init_queue();
441 | void push_queue(u8 byte, u8 dtype);
442 | void pop_queue(u8 *byte, u8 *dtype);
443 | void empty_queue();
444 | void print_queue();
445 |
446 | void init_pf_stack();
447 | void push_pf_stack(u32 id);
448 | u32 pop_pf_stack();
449 |
450 | #endif
--------------------------------------------------------------------------------
/sketches/run_program/lib.ino:
--------------------------------------------------------------------------------
1 | /*
2 | (C)2023 Daniel Balsom
3 | https://github.com/dbalsom/arduino_8088
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 |
18 | */
19 |
20 | #include "arduino8088.h"
21 |
22 | u32 calc_flat_address(u16 seg, u16 offset) {
23 | return ((u32)seg << 4) + offset;
24 | }
25 |
26 | // -------------------------- CPU Interface -----------------------------------
27 |
28 | // Execute one clock pulse to the CPU
29 | void clock_tick() {
30 | SET_CLOCK_HIGH;
31 | delayMicroseconds(CLOCK_PIN_HIGH_DELAY);
32 | SET_CLOCK_LOW;
33 | delayMicroseconds(CLOCK_PIN_LOW_DELAY);
34 | }
35 |
36 | // Write a value to the CPU's data bus
37 | void data_bus_write(u8 byte) {
38 | // Set data bus pins 22-29 to OUTPUT
39 | DDRA = 0xFF;
40 | delayMicroseconds(PIN_CHANGE_DELAY);
41 | // Write byte to data bus pins 22-29
42 | PORTA = byte;
43 | delayMicroseconds(PIN_CHANGE_DELAY);
44 | }
45 |
46 | // Read a value from the CPU's data bus
47 | u8 data_bus_read() {
48 | // Set data bus pins 22-29 to INPUT
49 | DDRA = 0;
50 | delayMicroseconds(PIN_CHANGE_DELAY);
51 | // Read byte from data bus pins 22-29
52 | return PINA;
53 | }
54 |
55 | /*
56 | Read the address pins and store the 20-bit value in global ADDRESS_LATCH.
57 | Only valid while ALE is HIGH.
58 | */
59 | void latch_address() {
60 | /*
61 | ADDRESS_LATCH = 0;
62 | for( int a = 0; a < ADDRESS_LINES; a++ ) {
63 | unsigned long b = digitalRead(ADDRESS_PINS[a]);
64 | ADDRESS_LATCH |= b << a;
65 | }*/
66 |
67 | // Set data bus pins 22-29 to INPUT
68 | DDRA = 0;
69 | delayMicroseconds(PIN_CHANGE_DELAY); // Wait for pin state change before reading
70 | CPU.address_latch = PINA; // Pins 22-29
71 | CPU.address_latch |= (unsigned long)BIT_REVERSE_TABLE[PINC] << 8; // Pins 30-37 (Bit order reversed)
72 | CPU.address_latch |= (unsigned long)(PIND & 0x80) << 9; // Pin 38
73 | CPU.address_latch |= (unsigned long)(BIT_REVERSE_TABLE[PING] & 0xE0) << 12; // Pins 39-40 (Bit order reversed)
74 |
75 | //Serial.println(PIND, BIN);
76 | //Serial.println(PING, BIN);
77 | }
78 |
79 | // Read the status lines S0-S5 as well as queue status lines QS0-QS1.
80 | void read_status0() {
81 | CPU.status0 = (PINJ & BIT1) >> 1; // S0
82 | CPU.status0 |= (PINJ & BIT0) << 1; // S1
83 | CPU.status0 |= ((PINH & BIT1) >> 1) << 2; // S2 - Pin 16 (H1)
84 | CPU.status0 |= ((PIND & BIT7) >> 7) << 3; // S3 - Pin 38 (D7)
85 | CPU.status0 |= ((PING & BIT2) >> 2) << 4; // S4 - Pin 39 (G2)
86 | CPU.status0 |= ((PING & BIT1) >> 1) << 5; // S5 - Pin 40 (G1)
87 | CPU.status0 |= ((PINH & BIT6) >> 6) << 6; // QS0 - Pin 9 (H6)
88 | CPU.status0 |= ((PINH & BIT5) >> 5) << 7; // QS1 - Pin 8 (H5)
89 | }
90 |
91 | // ---------------------- Processor Instruction Queue -------------------------
92 | void init_queue() {
93 | CPU.queue.len = 0;
94 | CPU.queue.back = 0;
95 | CPU.queue.front = 0;
96 | }
97 |
98 | void push_queue(u8 byte, u8 dtype) {
99 | if(CPU.queue.len < QUEUE_MAX) {
100 | CPU.queue.queue[CPU.queue.front] = byte;
101 | CPU.queue.types[CPU.queue.front] = dtype;
102 | CPU.queue.front = (CPU.queue.front + 1) & 0x03;
103 | CPU.queue.len++;
104 | }
105 | }
106 |
107 | void pop_queue(u8 *byte, u8 *dtype) {
108 | if(CPU.queue.len > 0) {
109 | *byte = CPU.queue.queue[CPU.queue.back];
110 | *dtype = CPU.queue.types[CPU.queue.back];
111 | CPU.queue.back = (CPU.queue.back + 1) & 0x03;
112 | CPU.queue.len--;
113 | return byte;
114 | }
115 | else {
116 | return 0;
117 | }
118 | }
119 |
120 | void empty_queue() {
121 | // Need to rewind the program counter by length of queue on flush.
122 | // Otherwise we would lose opcodes already fetched.
123 | CPU.v_pc -= CPU.queue.len;
124 | init_queue();
125 | }
126 |
127 | void print_queue() {
128 | char buf[(QUEUE_MAX * 2) + 1] = {0};
129 | char hex[3] = {0};
130 | u8 i;
131 | u8 byte;
132 | for(i = 0; i < CPU.queue.len; i++ ) {
133 | byte = CPU.queue.queue[(CPU.queue.back + i) % QUEUE_MAX];
134 | sprintf(hex, "%02X", byte);
135 | strcat(buf, hex);
136 | }
137 | Serial.println(buf);
138 | }
139 |
140 | const char *queue_to_string() {
141 | const size_t buf_len = (QUEUE_MAX * 2) + 1;
142 | static char buf[buf_len];
143 | char *buf_p = buf;
144 | *buf_p = 0;
145 | u8 byte;
146 | for(u8 i = 0; i < CPU.queue.len; i++ ) {
147 | byte = CPU.queue.queue[(CPU.queue.back + i) % QUEUE_MAX];
148 | snprintf(buf_p, buf_len - (i * 2), "%02X", byte);
149 | buf_p += 2;
150 | }
151 |
152 | return buf;
153 | }
154 |
155 | void test_queue() {
156 |
157 | u8 i;
158 | for(i = 0; i < 4; i++ ) {
159 | push_queue(i, 0);
160 | }
161 |
162 | print_queue();
163 |
164 | u8 qt, qb;
165 |
166 | pop_queue(&qt, &qb);
167 | pop_queue(&qt, &qb);
168 | push_queue(5, 0);
169 |
170 | print_queue();
171 | }
172 |
173 | // ---------------------------- Prefetch op stack -----------------------------
174 | void init_pf_stack() {
175 | CPU.pf_stack.len = 0;
176 | CPU.pf_stack.back = 0;
177 | CPU.pf_stack.front = 0;
178 | }
179 |
180 | void push_pf_stack(u32 id) {
181 | if(CPU.pf_stack.len < 2) {
182 | CPU.pf_stack.queue[CPU.pf_stack.front] = id;
183 | CPU.pf_stack.front = (CPU.pf_stack.front + 1) & 0x01;
184 | CPU.pf_stack.len++;
185 | }
186 | else {
187 | Serial.println("## Prefetch scheduler overflow ##");
188 | }
189 | }
190 |
191 | u32 pop_pf_stack() {
192 | u32 id = 0;
193 | if(CPU.pf_stack.len > 0) {
194 | id = CPU.pf_stack.queue[CPU.pf_stack.back];
195 | CPU.pf_stack.back = (CPU.pf_stack.back + 1) & 0x01;
196 | CPU.pf_stack.len--;
197 | return id;
198 | }
199 | else {
200 | Serial.println("## Prefetch scheduler underflow ##");
201 | return 0;
202 | }
203 | }
204 |
205 | // ----------------------------------Opcodes-----------------------------------
206 |
207 | // Return the mnemonic name for the specified opcode. If the opcode is a group
208 | // opcode, op2 should be specified and modrm set to true.
209 | const char *get_opcode_str(u8 op1, u8 op2, bool modrm) {
210 |
211 | size_t op_idx = OPCODE_REFS[op1];
212 | size_t grp_idx = 0;
213 |
214 | if(!modrm) {
215 | // Just return primary opcode
216 | return OPCODE_STRS[op_idx];
217 | }
218 | else {
219 | // modrm is in use, check if this is a group instruction...
220 | if(IS_GRP_OP(op1)) {
221 | // Lookup opcode group
222 | grp_idx = MODRM_OP(op2);
223 |
224 | switch(OPCODE_REFS[op1]) {
225 | case GRP1:
226 | return OPCODE_STRS_GRP1[grp_idx];
227 | break;
228 | case GRP2A:
229 | return OPCODE_STRS_GRP2A[grp_idx];
230 | break;
231 | case GRP2B:
232 | return OPCODE_STRS_GRP2B[grp_idx];
233 | break;
234 | case GRP3:
235 | return OPCODE_STRS_GRP3[grp_idx];
236 | break;
237 | case GRP4:
238 | return OPCODE_STRS_GRP4[grp_idx];
239 | break;
240 | case GRP5:
241 | return OPCODE_STRS_GRP5[grp_idx];
242 | break;
243 | default:
244 | return "***";
245 | break;
246 | }
247 | }
248 | else {
249 | // Not a group instruction, just return as normal
250 | return OPCODE_STRS[op_idx];
251 | }
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/sketches/run_program/opcodes.h:
--------------------------------------------------------------------------------
1 | /*
2 | (C)2023 Daniel Balsom
3 | https://github.com/dbalsom/arduino_8088
4 |
5 | This program is free software: you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation, either version 3 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU General Public License for more details.
14 |
15 | You should have received a copy of the GNU General Public License
16 | along with this program. If not, see .
17 |
18 | */
19 | #ifndef _ARDUINO8088_OPCODES_H
20 | #define _ARDUINO8088_OPCODES_H
21 |
22 | #define OPCODE_NOP 0x90
23 | #define OPCODE_POPF 0x9D
24 |
25 | #define MODRM_OP(M) (((M & 0b00111000) >> 3) & 0x07)
26 |
27 | #define GRP1 105
28 | #define GRP2A 106
29 | #define GRP2B 110
30 | #define GRP3 107
31 | #define GRP4 108
32 | #define GRP5 109
33 | #define IS_GRP_OP(O) ((OPCODE_REFS[O] >= GRP1) && (OPCODE_REFS[O] <= GRP2B))
34 |
35 | static const u8 OPCODE_WIDTH[] = {
36 | 0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,
37 | 0,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,
38 | 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,
39 | 0,1,0,1,0,1,0,0,0,1,0,1,0,1,0,0,
40 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
41 | 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
42 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
43 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
44 | 0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,1,
45 | 0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,
46 | 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,
47 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
48 | 1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
49 | 0,1,0,1,0,0,0,0,1,1,1,1,1,1,1,1,
50 | 1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,
51 | 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1
52 | };
53 |
54 | // LUT of primary opcode to Mnemonic (Or Group name)
55 | static const u8 OPCODE_REFS[] = {
56 | 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 1, 2,
57 | 4, 4, 4, 4, 4, 4, 1, 2, 5, 5, 5, 5, 5, 5, 1, 2,
58 | 6, 6, 6, 6, 6, 6, 7, 8, 9, 9, 9, 9, 9, 9, 10, 11,
59 | 12, 12, 12, 12, 12, 12, 13, 14, 15, 15, 15, 15, 15, 15, 16, 17,
60 | 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19,
61 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
62 | 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
63 | 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
64 | 105, 105, 105, 105, 36, 36, 37, 37, 38, 38, 38, 38, 38, 39, 38, 2,
65 | 111, 37, 37, 37, 37, 37, 37, 37, 40, 41, 42, 103, 43, 44, 45, 46,
66 | 38, 38, 38, 38, 47, 48, 49, 50, 36, 36, 51, 52, 53, 54, 55, 56,
67 | 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
68 | 57, 57, 57, 57, 58, 59, 38, 38, 60, 60, 60, 60, 61, 61, 62, 63,
69 | 106, 106, 110, 110, 71, 73, 104, 75, 104, 104, 104, 104, 104, 104, 104, 104,
70 | 76, 77, 78, 79, 80, 80, 81, 81, 82, 83, 84, 83, 80, 80, 81, 81,
71 | 85, 104, 86, 87, 89, 90, 107, 107, 97, 98, 99, 100, 101, 102, 108, 109
72 | };
73 |
74 | static char *OPCODE_STRS[] = {
75 | "ADD",
76 | "PUSH",
77 | "POP",
78 | "OR",
79 | "ADC",
80 | "SBB",
81 | "AND",
82 | "ES",
83 | "DAA",
84 | "SUB",
85 | "CS",
86 | "DAS",
87 | "XOR",
88 | "SS",
89 | "AAA",
90 | "CMP",
91 | "DS",
92 | "AAS",
93 | "INC",
94 | "DEC",
95 | "JO",
96 | "JNO",
97 | "JB",
98 | "JNB",
99 | "JZ",
100 | "JNZ",
101 | "JBE",
102 | "JNBE",
103 | "JS",
104 | "JNS",
105 | "JP",
106 | "JNP",
107 | "JL",
108 | "JNL",
109 | "JLE",
110 | "JNLE",
111 | "TEST",
112 | "XCHG",
113 | "MOV",
114 | "LEA",
115 | "CBW",
116 | "CWD",
117 | "CALLF",
118 | "PUSHF",
119 | "POPF",
120 | "SAHF",
121 | "LAHF",
122 | "MOVSB",
123 | "MOVSW",
124 | "CMPSB",
125 | "CMPSW",
126 | "STOSB",
127 | "STOSW",
128 | "LODSB",
129 | "LODSW",
130 | "SCASB",
131 | "SCASW",
132 | "RETN",
133 | "LES",
134 | "LDS",
135 | "RETF",
136 | "INT",
137 | "INTO",
138 | "IRET",
139 | "ROL",
140 | "ROR",
141 | "RCL",
142 | "RCR",
143 | "SHL",
144 | "SHR",
145 | "SAR",
146 | "AAM",
147 | "AMX",
148 | "AAD",
149 | "ADX",
150 | "XLAT",
151 | "LOOPNE",
152 | "LOOPE",
153 | "LOOP",
154 | "JCXZ",
155 | "IN",
156 | "OUT",
157 | "CALL",
158 | "JMP",
159 | "JMPF",
160 | "LOCK",
161 | "REPNZ",
162 | "REP",
163 | "REPZ",
164 | "HLT",
165 | "CMC",
166 | "NOT",
167 | "NEG",
168 | "MUL",
169 | "IMUL",
170 | "DIV",
171 | "IDIV",
172 | "CLC",
173 | "STC",
174 | "CLI",
175 | "STI",
176 | "CLD",
177 | "STD",
178 | "WAIT",
179 | "INVAL",
180 | "GRP1",
181 | "GRP2A",
182 | "GRP3",
183 | "GRP4",
184 | "GRP5",
185 | "GRP2B",
186 | "NOP",
187 |
188 | };
189 |
190 | // 0x80 - 0x81
191 | static char *OPCODE_STRS_GRP1[] = {
192 | "ADD",
193 | "OR",
194 | "ADC",
195 | "SBB",
196 | "AND",
197 | "SUB",
198 | "XOR",
199 | "CMP"
200 | };
201 |
202 | // 0xD0 - 0xD1
203 | static char *OPCODE_STRS_GRP2A[] = {
204 | "ROL",
205 | "ROR",
206 | "RCL",
207 | "RCR",
208 | "SHL",
209 | "SHR",
210 | "SETMO",
211 | "SAR"
212 | };
213 |
214 | // 0xD2 - 0xD3
215 | static char *OPCODE_STRS_GRP2B[] = {
216 | "ROL",
217 | "ROR",
218 | "RCL",
219 | "RCR",
220 | "SHL",
221 | "SHR",
222 | "SETMOC",
223 | "SAR"
224 | };
225 |
226 | // 0xF6 - 0xF7
227 | static char *OPCODE_STRS_GRP3[] = {
228 | "TEST",
229 | "TEST",
230 | "NOT",
231 | "NEG",
232 | "MUL",
233 | "IMUL",
234 | "DIV",
235 | "IDIV",
236 | };
237 |
238 | // 0xFE
239 | static char *OPCODE_STRS_GRP4[] = {
240 | "INC",
241 | "DEC",
242 | "INVAL",
243 | "INVAL",
244 | "INVAL",
245 | "INVAL",
246 | "INVAL",
247 | "INVAL"
248 | };
249 |
250 | // 0xFF
251 | static char *OPCODE_STRS_GRP5[] = {
252 | "INC",
253 | "DEC",
254 | "CALL",
255 | "CALLF",
256 | "JMP",
257 | "JMPF",
258 | "PUSH",
259 | "INVAL"
260 | };
261 |
262 | #endif
--------------------------------------------------------------------------------