├── .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 | ![arduino8088_pcb](/images/render_v1_1.png) 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 | ![pcb_shield50](/images/pcb_v1_1.png) 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 --------------------------------------------------------------------------------