Compare commits
31 Commits
ef438f48d2
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a37caf8b2 | |||
| 3de2c63fe0 | |||
| 3856d81c47 | |||
| a621ec235a | |||
| f464dbfaf1 | |||
| 7d0b66f418 | |||
| 6e55faa2c0 | |||
| 952b79cf91 | |||
| 8ac0cbc57b | |||
| c2aef4f249 | |||
| 07d40c05d5 | |||
| dcaeece7fa | |||
| 7f8e00af23 | |||
| fb4fae430b | |||
| ac4619406d | |||
| 8890853656 | |||
| 4f0615b563 | |||
| 001d3e434c | |||
| 229b8b450d | |||
| f9198cd0b1 | |||
| 0ec54d6672 | |||
| b1b9c64468 | |||
| 5f65c32e56 | |||
| c154bdc89a | |||
| 705dcd3185 | |||
| 40ede17ae1 | |||
| 9808616203 | |||
| 10559bde8b | |||
| 5b9312f643 | |||
| 95acceeabd | |||
| 78dad90fc9 |
@@ -1,2 +1,7 @@
|
|||||||
/target
|
/target
|
||||||
log
|
log
|
||||||
|
george.o
|
||||||
|
Cargo.lock
|
||||||
|
.DS_Store
|
||||||
|
*.bin
|
||||||
|
/result
|
||||||
|
|||||||
Generated
-805
@@ -1,805 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "2.4.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bumpalo"
|
|
||||||
version = "3.14.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.83"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cty"
|
|
||||||
version = "0.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dlib"
|
|
||||||
version = "0.5.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
|
||||||
dependencies = [
|
|
||||||
"libloading",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "downcast-rs"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno"
|
|
||||||
version = "0.3.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fastrand"
|
|
||||||
version = "2.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
|
|
||||||
dependencies = [
|
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
|
||||||
"futures-executor",
|
|
||||||
"futures-io",
|
|
||||||
"futures-sink",
|
|
||||||
"futures-task",
|
|
||||||
"futures-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-channel"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"futures-sink",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-core"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-executor"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"futures-task",
|
|
||||||
"futures-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-io"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-macro"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-sink"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-task"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-util"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
|
||||||
dependencies = [
|
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
|
||||||
"futures-io",
|
|
||||||
"futures-macro",
|
|
||||||
"futures-sink",
|
|
||||||
"futures-task",
|
|
||||||
"memchr",
|
|
||||||
"pin-project-lite",
|
|
||||||
"pin-utils",
|
|
||||||
"slab",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "georgeemu"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"minifb",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "instant"
|
|
||||||
version = "0.1.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"js-sys",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"web-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "js-sys"
|
|
||||||
version = "0.3.67"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1"
|
|
||||||
dependencies = [
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "lazy_static"
|
|
||||||
version = "1.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.153"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libloading"
|
|
||||||
version = "0.8.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libredox"
|
|
||||||
version = "0.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.4.2",
|
|
||||||
"libc",
|
|
||||||
"redox_syscall",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.4.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log"
|
|
||||||
version = "0.4.20"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "2.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memoffset"
|
|
||||||
version = "0.6.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "minifb"
|
|
||||||
version = "0.25.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "05eddefadb505d3dcb66a89fa77dd0936e72ec84e891cc8fc36e3c05bfe61103"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"dlib",
|
|
||||||
"futures",
|
|
||||||
"instant",
|
|
||||||
"js-sys",
|
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
|
||||||
"orbclient",
|
|
||||||
"raw-window-handle",
|
|
||||||
"serde",
|
|
||||||
"serde_derive",
|
|
||||||
"tempfile",
|
|
||||||
"wasm-bindgen-futures",
|
|
||||||
"wayland-client",
|
|
||||||
"wayland-cursor",
|
|
||||||
"wayland-protocols",
|
|
||||||
"winapi",
|
|
||||||
"x11-dl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nix"
|
|
||||||
version = "0.24.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"memoffset",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "once_cell"
|
|
||||||
version = "1.19.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "orbclient"
|
|
||||||
version = "0.3.47"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"libredox",
|
|
||||||
"sdl2",
|
|
||||||
"sdl2-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project-lite"
|
|
||||||
version = "0.2.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-utils"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pkg-config"
|
|
||||||
version = "0.3.29"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro2"
|
|
||||||
version = "1.0.78"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quote"
|
|
||||||
version = "1.0.35"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "raw-window-handle"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41"
|
|
||||||
dependencies = [
|
|
||||||
"cty",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_syscall"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.38.31"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.4.2",
|
|
||||||
"errno",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scoped-tls"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sdl2"
|
|
||||||
version = "0.35.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f7959277b623f1fb9e04aea73686c3ca52f01b2145f8ea16f4ff30d8b7623b1a"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
|
||||||
"sdl2-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sdl2-sys"
|
|
||||||
version = "0.35.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e3586be2cf6c0a8099a79a12b4084357aa9b3e0b0d7980e3b67aaf7a9d55f9f0"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"version-compare",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.196"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
|
|
||||||
dependencies = [
|
|
||||||
"serde_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_derive"
|
|
||||||
version = "1.0.196"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "slab"
|
|
||||||
version = "0.4.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smallvec"
|
|
||||||
version = "1.13.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "2.0.48"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"unicode-ident",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tempfile"
|
|
||||||
version = "3.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"fastrand",
|
|
||||||
"redox_syscall",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-ident"
|
|
||||||
version = "1.0.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "version-compare"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen"
|
|
||||||
version = "0.2.90"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"wasm-bindgen-macro",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-backend"
|
|
||||||
version = "0.2.90"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd"
|
|
||||||
dependencies = [
|
|
||||||
"bumpalo",
|
|
||||||
"log",
|
|
||||||
"once_cell",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"wasm-bindgen-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-futures"
|
|
||||||
version = "0.4.40"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"js-sys",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"web-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-macro"
|
|
||||||
version = "0.2.90"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
"wasm-bindgen-macro-support",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-macro-support"
|
|
||||||
version = "0.2.90"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"wasm-bindgen-backend",
|
|
||||||
"wasm-bindgen-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasm-bindgen-shared"
|
|
||||||
version = "0.2.90"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-client"
|
|
||||||
version = "0.29.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"downcast-rs",
|
|
||||||
"libc",
|
|
||||||
"nix",
|
|
||||||
"scoped-tls",
|
|
||||||
"wayland-commons",
|
|
||||||
"wayland-scanner",
|
|
||||||
"wayland-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-commons"
|
|
||||||
version = "0.29.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902"
|
|
||||||
dependencies = [
|
|
||||||
"nix",
|
|
||||||
"once_cell",
|
|
||||||
"smallvec",
|
|
||||||
"wayland-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-cursor"
|
|
||||||
version = "0.29.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661"
|
|
||||||
dependencies = [
|
|
||||||
"nix",
|
|
||||||
"wayland-client",
|
|
||||||
"xcursor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-protocols"
|
|
||||||
version = "0.29.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
"wayland-client",
|
|
||||||
"wayland-commons",
|
|
||||||
"wayland-scanner",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-scanner"
|
|
||||||
version = "0.29.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"xml-rs",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wayland-sys"
|
|
||||||
version = "0.29.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4"
|
|
||||||
dependencies = [
|
|
||||||
"dlib",
|
|
||||||
"lazy_static",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "web-sys"
|
|
||||||
version = "0.3.67"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed"
|
|
||||||
dependencies = [
|
|
||||||
"js-sys",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-i686-pc-windows-gnu",
|
|
||||||
"winapi-x86_64-pc-windows-gnu",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-i686-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.48.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm 0.48.5",
|
|
||||||
"windows_aarch64_msvc 0.48.5",
|
|
||||||
"windows_i686_gnu 0.48.5",
|
|
||||||
"windows_i686_msvc 0.48.5",
|
|
||||||
"windows_x86_64_gnu 0.48.5",
|
|
||||||
"windows_x86_64_gnullvm 0.48.5",
|
|
||||||
"windows_x86_64_msvc 0.48.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm 0.52.0",
|
|
||||||
"windows_aarch64_msvc 0.52.0",
|
|
||||||
"windows_i686_gnu 0.52.0",
|
|
||||||
"windows_i686_msvc 0.52.0",
|
|
||||||
"windows_x86_64_gnu 0.52.0",
|
|
||||||
"windows_x86_64_gnullvm 0.52.0",
|
|
||||||
"windows_x86_64_msvc 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.48.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "x11-dl"
|
|
||||||
version = "2.21.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"once_cell",
|
|
||||||
"pkg-config",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xcursor"
|
|
||||||
version = "0.3.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xml-rs"
|
|
||||||
version = "0.8.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
|
|
||||||
+22
-1
@@ -2,8 +2,29 @@
|
|||||||
name = "georgeemu"
|
name = "georgeemu"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[[target.'cfg(not(target_arch = "wasm32"))'.bin]]
|
||||||
|
path = "src/bin/main.rs"
|
||||||
|
name = "george"
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
bdf-parser = "0.1.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
minifb = "0.25.0"
|
anyhow = "1.0.81"
|
||||||
|
minifb = { git = "https://github.com/emoon/rust_minifb" }
|
||||||
|
serde = { version = "1.0.197", features = ["serde_derive", "derive"] }
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
|
console_error_panic_hook = "0.1.7"
|
||||||
|
web-sys = "0.3.70"
|
||||||
|
|
||||||
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
|
termion = "4.0.2"
|
||||||
|
toml = { version = "0.8.12" }
|
||||||
|
|||||||
@@ -9,3 +9,15 @@ plenty of inspiration & guidance taken from [emulator_6502](https://docs.rs/emul
|
|||||||
see [the george wiki](https://git.augustkline.com/august/george/wiki) for how george works, why she exists, who she is, etc.
|
see [the george wiki](https://git.augustkline.com/august/george/wiki) for how george works, why she exists, who she is, etc.
|
||||||
|
|
||||||
the george emulator contains 3 main structs: `Cpu`, `Mem`, and `MemMappedDevice`. `Cpu` represents a 65c02 processor, with functions for interacting with memory and executing instructions. `Mem` is a collection of `MemMappedDevice`'s, which each hold the data for some address space. `Mem` can add `MemMappedDevice`'s, and read from and write to them. A `MemMappedDevice` can have multiple banks at the same address space, and can translate 'global' addresses to 'local' ones (e.g. 0xFFFF in the system's [memory map](https://git.augustkline.com/august/george-hardware/src/branch/main/memory.md) corresponds to 0x1FFF in the ROM).
|
the george emulator contains 3 main structs: `Cpu`, `Mem`, and `MemMappedDevice`. `Cpu` represents a 65c02 processor, with functions for interacting with memory and executing instructions. `Mem` is a collection of `MemMappedDevice`'s, which each hold the data for some address space. `Mem` can add `MemMappedDevice`'s, and read from and write to them. A `MemMappedDevice` can have multiple banks at the same address space, and can translate 'global' addresses to 'local' ones (e.g. 0xFFFF in the system's [memory map](https://git.augustkline.com/august/george-hardware/src/branch/main/memory.md) corresponds to 0x1FFF in the ROM).
|
||||||
|
|
||||||
|
## font generation
|
||||||
|
|
||||||
|
george uses a modified version of [cozette](https://github.com/slavfox/Cozette) for her main font. the modified version has 8 pixel wide characters for use with the character generator rom, and has a limit of 256 (0xFF) characters. the toolchain to generate a rom binary is still pretty clunky, and someday i might get around to streamlining it, but for now to make any changes:
|
||||||
|
|
||||||
|
- open `./src/Cozette.sfd` in fontforge
|
||||||
|
- make your edits
|
||||||
|
- to reorder glyphs, edit `./src/georgeencoding.txt` and load it with "Encoding -> Load Encoding -> (select georgeencoding.txt, name it whatever) -> Reencode -> (name of encoding)"
|
||||||
|
- ensure that there are exactly 256 characters in the font
|
||||||
|
- generate a bdf font with "File -> Generate Fonts... -> (name of the font, select bdf in the options panel)"
|
||||||
|
- open the generated bdf file in a text editor and change the line `FONTBOUNDINGBOX 11 13 0 -3` to `FONTBOUNDINGBOX 8 13 0 -3`
|
||||||
|
- now open the font in [bdf view](https://emurenmrz.github.io/bdf_view/), and export a single-row png
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
fs::File,
|
||||||
|
io::{stdin, stdout, IsTerminal, Read, Write},
|
||||||
|
ops::Neg,
|
||||||
|
os::unix::process::CommandExt,
|
||||||
|
path::Path,
|
||||||
|
process::{exit, Command},
|
||||||
|
};
|
||||||
|
|
||||||
|
// takes all charaters in bdf and returns a vec of each character row byte in order, normalized to
|
||||||
|
// width & height of the font (only works with 8 or fewer pixel wide fonts, should work for any height)
|
||||||
|
fn bdf_to_bitmap(mut bdf: File) -> [u8; 0x8000] {
|
||||||
|
let mut bdf_font_bytes = Vec::new();
|
||||||
|
bdf.read_to_end(&mut bdf_font_bytes).unwrap();
|
||||||
|
|
||||||
|
let bdf_font = bdf_parser::BdfFont::parse(&bdf_font_bytes).unwrap();
|
||||||
|
let mut bdf_vec = vec![];
|
||||||
|
for glyph in bdf_font.glyphs.iter() {
|
||||||
|
let glyph_offset_x = glyph.bounding_box.offset.x;
|
||||||
|
let glyph_offset_y = glyph.bounding_box.offset.y;
|
||||||
|
let glyph_height = glyph.bounding_box.size.y;
|
||||||
|
let font_height = bdf_font.metadata.bounding_box.size.y;
|
||||||
|
let font_offset_y = bdf_font.metadata.bounding_box.offset.y;
|
||||||
|
|
||||||
|
let top_space = font_height + font_offset_y - glyph_height - glyph_offset_y;
|
||||||
|
for _ in 0..top_space {
|
||||||
|
bdf_vec.push(0x00);
|
||||||
|
}
|
||||||
|
for bitmap in glyph.bitmap.iter() {
|
||||||
|
bdf_vec.push(bitmap >> glyph_offset_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
let bottom_space = font_offset_y.neg() + glyph_offset_y;
|
||||||
|
for _ in 0..bottom_space {
|
||||||
|
bdf_vec.push(0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let height = bdf_font.metadata.bounding_box.size.y as usize;
|
||||||
|
reorder_bitmap(&bdf_vec, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
// takes an vec of ordered characters and translates them for use with the character rom
|
||||||
|
// TODO: make this work for any arbitrary char rom pin format using some kinda interface
|
||||||
|
fn reorder_bitmap(bitmap: &[u8], font_height: usize) -> [u8; 0x8000] {
|
||||||
|
let mut rom = [0; 0x8000]; // create vec the size of character rom
|
||||||
|
|
||||||
|
for row in 0..font_height {
|
||||||
|
for ascii_address in 0..u8::MAX {
|
||||||
|
// first 8 bits of address pick character
|
||||||
|
// next 5 bits pick row
|
||||||
|
// TODO: final 2 pick character set
|
||||||
|
let byte = bitmap[ascii_address as usize * font_height + row];
|
||||||
|
let rom_index: u16 = ((row as u16) << 8) + ascii_address as u16;
|
||||||
|
rom[rom_index as usize] = byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rom
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rom_from_file<P>(path: P) -> [u8; 0x8000]
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
{
|
||||||
|
let file = File::open(path).unwrap();
|
||||||
|
bdf_to_bitmap(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut regen_font = Command::new("regen-font.sh");
|
||||||
|
let mut cleanup = Command::new("cleanup.sh");
|
||||||
|
|
||||||
|
regen_font.exec();
|
||||||
|
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
let dest_path = Path::new(&out_dir).join("cozette.rom");
|
||||||
|
|
||||||
|
let cozette_rom_bytes = rom_from_file("build/cozette.bdf");
|
||||||
|
let mut cozette_rom = File::create(dest_path).unwrap();
|
||||||
|
cozette_rom.write_all(&cozette_rom_bytes).unwrap();
|
||||||
|
|
||||||
|
cleanup.exec();
|
||||||
|
}
|
||||||
+2410
File diff suppressed because it is too large
Load Diff
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
rm *.bdf*
|
||||||
File diff suppressed because it is too large
Load Diff
+3903
File diff suppressed because it is too large
Load Diff
+3903
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,523 @@
|
|||||||
|
# this is georgescii, august's version of extended ascii for george <3
|
||||||
|
# we're limited to 255 characters
|
||||||
|
# format: ascii byte, unicode hex, # unicode name
|
||||||
|
#
|
||||||
|
# format: three tab-separated columns
|
||||||
|
# column #1 is the ISO/IEC 8859-1 code (in hex as 0xXX)
|
||||||
|
# column #2 is the Unicode (in hex as 0xXXXX)
|
||||||
|
# column #3 the Unicode name (follows a comment sign, '#')
|
||||||
|
|
||||||
|
# 0x00 0x00 #
|
||||||
|
# 0x01 0x2591 # ░
|
||||||
|
# 0x02 0x2592 # ▒
|
||||||
|
# 0x03 0x2593 # ▓
|
||||||
|
# 0x04 0x2661 # ♡
|
||||||
|
# 0x05 0x2665 # ♥
|
||||||
|
# 0x06 0x2B50 # ⭐
|
||||||
|
# 0x07 0x272D # ✭
|
||||||
|
# 0x08 0xF005 #
|
||||||
|
# 0x09 0x2726 # ✦
|
||||||
|
# 0x0a 0x2728 # ✨
|
||||||
|
# 0x0b 0x2640 # ♀
|
||||||
|
# 0x0c 0x2642 # ♂
|
||||||
|
# 0x0d 0x26A2 # ⚢
|
||||||
|
# 0x0E 0x26A3 # ⚣
|
||||||
|
# 0x0F 0x26A5 # ⚥
|
||||||
|
# 0x10 0x2669 # ♩
|
||||||
|
# 0x11 0x266A # ♪
|
||||||
|
# 0x12 0x266B # ♫
|
||||||
|
# 0x13 0x266C # ♬
|
||||||
|
# 0x14 0xFC5D # ﱝ
|
||||||
|
# 0x15 0xF026 #
|
||||||
|
# 0x16 0xF027 #
|
||||||
|
# 0x17 0xF028 #
|
||||||
|
# 0x18 0xFA7E # 奄
|
||||||
|
# 0x19 0xFA7F # 奔
|
||||||
|
# 0x1A 0xFA80 # 婢
|
||||||
|
# 0x1B 0xFC5C # ﱜ
|
||||||
|
# 0x1C 0xFC5B # ﱛ
|
||||||
|
# 0x1D 0xF0AC #
|
||||||
|
# 0x1E 0xF04B #
|
||||||
|
# 0x1F 0xF04D #
|
||||||
|
# 0x20 0x0020 #
|
||||||
|
# 0x21 0x0021 # !
|
||||||
|
# 0x22 0x0022 # "
|
||||||
|
# 0x23 0x0023 # #
|
||||||
|
# 0x24 0x0024 # $
|
||||||
|
# 0x25 0x0025 # %
|
||||||
|
# 0x26 0x0026 # &
|
||||||
|
# 0x27 0x0027 # '
|
||||||
|
# 0x28 0x0028 # (
|
||||||
|
# 0x29 0x0029 # )
|
||||||
|
# 0x2A 0x002A # *
|
||||||
|
# 0x2B 0x002B # +
|
||||||
|
# 0x2C 0x002C # ,
|
||||||
|
# 0x2D 0x002D # -
|
||||||
|
# 0x2E 0x002E # .
|
||||||
|
# 0x2F 0x002F # /
|
||||||
|
# 0x30 0x0030 # 0
|
||||||
|
# 0x31 0x0031 # 1
|
||||||
|
# 0x32 0x0032 # 2
|
||||||
|
# 0x33 0x0033 # 3
|
||||||
|
# 0x34 0x0034 # 4
|
||||||
|
# 0x35 0x0035 # 5
|
||||||
|
# 0x36 0x0036 # 6
|
||||||
|
# 0x37 0x0037 # 7
|
||||||
|
# 0x38 0x0038 # 8
|
||||||
|
# 0x39 0x0039 # 9
|
||||||
|
# 0x3A 0x003A # :
|
||||||
|
# 0x3B 0x003B # ;
|
||||||
|
# 0x3C 0x003C # <
|
||||||
|
# 0x3D 0x003D # =
|
||||||
|
# 0x3E 0x003E # >
|
||||||
|
# 0x3F 0x003F # ?
|
||||||
|
# 0x40 0x0040 # @
|
||||||
|
# 0x41 0x0041 # A
|
||||||
|
# 0x42 0x0042 # B
|
||||||
|
# 0x43 0x0043 # C
|
||||||
|
# 0x44 0x0044 # D
|
||||||
|
# 0x45 0x0045 # E
|
||||||
|
# 0x46 0x0046 # F
|
||||||
|
# 0x47 0x0047 # G
|
||||||
|
# 0x48 0x0048 # H
|
||||||
|
# 0x49 0x0049 # I
|
||||||
|
# 0x4A 0x004A # J
|
||||||
|
# 0x4B 0x004B # K
|
||||||
|
# 0x4C 0x004C # L
|
||||||
|
# 0x4D 0x004D # M
|
||||||
|
# 0x4E 0x004E # N
|
||||||
|
# 0x4F 0x004F # O
|
||||||
|
# 0x50 0x0050 # P
|
||||||
|
# 0x51 0x0051 # Q
|
||||||
|
# 0x52 0x0052 # R
|
||||||
|
# 0x53 0x0053 # S
|
||||||
|
# 0x54 0x0054 # T
|
||||||
|
# 0x55 0x0055 # U
|
||||||
|
# 0x56 0x0056 # V
|
||||||
|
# 0x57 0x0057 # W
|
||||||
|
# 0x58 0x0058 # X
|
||||||
|
# 0x59 0x0059 # Y
|
||||||
|
# 0x5A 0x005A # Z
|
||||||
|
# 0x5B 0x005B # [
|
||||||
|
# 0x5C 0x005C # \
|
||||||
|
# 0x5D 0x005D # ]
|
||||||
|
# 0x5E 0x005E # ^
|
||||||
|
# 0x5F 0x005F # _
|
||||||
|
# 0x60 0x0060 # `
|
||||||
|
# 0x61 0x0061 # a
|
||||||
|
# 0x62 0x0062 # b
|
||||||
|
# 0x63 0x0063 # c
|
||||||
|
# 0x64 0x0064 # d
|
||||||
|
# 0x65 0x0065 # e
|
||||||
|
# 0x66 0x0066 # f
|
||||||
|
# 0x67 0x0067 # g
|
||||||
|
# 0x68 0x0068 # h
|
||||||
|
# 0x69 0x0069 # i
|
||||||
|
# 0x6A 0x006A # j
|
||||||
|
# 0x6B 0x006B # k
|
||||||
|
# 0x6C 0x006C # l
|
||||||
|
# 0x6D 0x006D # m
|
||||||
|
# 0x6E 0x006E # n
|
||||||
|
# 0x6F 0x006F # o
|
||||||
|
# 0x70 0x0070 # p
|
||||||
|
# 0x71 0x0071 # q
|
||||||
|
# 0x72 0x0072 # r
|
||||||
|
# 0x73 0x0073 # s
|
||||||
|
# 0x74 0x0074 # t
|
||||||
|
# 0x75 0x0075 # u
|
||||||
|
# 0x76 0x0076 # v
|
||||||
|
# 0x77 0x0077 # w
|
||||||
|
# 0x78 0x0078 # x
|
||||||
|
# 0x79 0x0079 # y
|
||||||
|
# 0x7A 0x007A # z
|
||||||
|
# 0x7B 0x007B # {
|
||||||
|
# 0x7C 0x007C # |
|
||||||
|
# 0x7D 0x007D # }
|
||||||
|
# 0x7E 0x007E # ~
|
||||||
|
# 0x7F 0x2500 # ─
|
||||||
|
# 0x80 0x2502 # │
|
||||||
|
# 0x81 0x250C # ┌
|
||||||
|
# 0x82 0x2514 # └
|
||||||
|
# 0x83 0x251C # ├
|
||||||
|
# 0x84 0x2524 # ┤
|
||||||
|
# 0x85 0x252C # ┬
|
||||||
|
# 0x86 0x2534 # ┴
|
||||||
|
# 0x87 0x253C # ┼
|
||||||
|
# 0x88 0x256D # ╭
|
||||||
|
# 0x89 0x256E # ╮
|
||||||
|
# 0x8A 0x256F # ╯
|
||||||
|
# 0x8B 0x2570 # ╰
|
||||||
|
# 0x8C 0x2571 # ╱
|
||||||
|
# 0x8D 0x2572 # ╲
|
||||||
|
# 0x8E 0x2573 # ╳
|
||||||
|
# 0x8F 0x2550 # ═
|
||||||
|
# 0x90 0x2551 # ║
|
||||||
|
# 0x91 0x2554 # ╔
|
||||||
|
# 0x92 0x2557 # ╗
|
||||||
|
# 0x93 0x255a # ╚
|
||||||
|
# 0x94 0x255D # ╝
|
||||||
|
# 0x95 0x2560 # ╠
|
||||||
|
# 0x96 0x2563 # ╣
|
||||||
|
# 0x97 0x2566 # ╦
|
||||||
|
# 0x98 0x2569 # ╩
|
||||||
|
# 0x99 0x256C # ╬
|
||||||
|
# 0x9A 0xF04E #
|
||||||
|
# 0x9B 0xF050 #
|
||||||
|
# 0x9C 0xF051 #
|
||||||
|
# 0x9D 0xF052 #
|
||||||
|
# 0x9E 0xF048 #
|
||||||
|
# 0x9F 0xE0B0 #
|
||||||
|
# 0xA0 0xE0B2 #
|
||||||
|
# 0xA1 0xE0B4 #
|
||||||
|
# 0xA2 0xE0B6 #
|
||||||
|
# 0xA3 0xE0B8 #
|
||||||
|
# 0xA4 0xE0BA #
|
||||||
|
# 0xA5 0xE0BC #
|
||||||
|
# 0xA6 0xE0BE #
|
||||||
|
# 0xA7 0x2581 # ▁
|
||||||
|
# 0xA8 0x2582 # ▂
|
||||||
|
# 0xA9 0x2583 # ▃
|
||||||
|
# 0xAA 0x2584 # ▄
|
||||||
|
# 0xAB 0x2585 # ▅
|
||||||
|
# 0xAC 0x2586 # ▆
|
||||||
|
# 0xAD 0x2587 # ▇
|
||||||
|
# 0xAE 0x2588 # █
|
||||||
|
# 0xAF 0x2589 # ▉
|
||||||
|
# 0xB0 0x258A # ▊
|
||||||
|
# 0xB1 0x258B # ▋
|
||||||
|
# 0xB2 0x258C # ▌
|
||||||
|
# 0xB3 0x258D # ▍
|
||||||
|
# 0xB4 0x258E # ▎
|
||||||
|
# 0xB5 0x258F # ▏
|
||||||
|
# 0xB6 0x0295 # ʕ
|
||||||
|
# 0xB7 0x00B7 # ·
|
||||||
|
# 0xB8 0x1D25 # ᴥ
|
||||||
|
# 0xB9 0x0294 # ʔ
|
||||||
|
# 0xBA 0x2596 # ▖
|
||||||
|
# 0xBB 0x2597 # ▗
|
||||||
|
# 0xBC 0x2598 # ▘
|
||||||
|
# 0xBD 0x2599 # ▙
|
||||||
|
# 0xBE 0x259A # ▚
|
||||||
|
# 0xBF 0x259B # ▛
|
||||||
|
# 0xC0 0x259C # ▜
|
||||||
|
# 0xC1 0x259D # ▝
|
||||||
|
# 0xC2 0x259E # ▞
|
||||||
|
# 0xC3 0x259F # ▟
|
||||||
|
# 0xC4 0x2190 # ←
|
||||||
|
# 0xC5 0x2191 # ↑
|
||||||
|
# 0xC6 0x2192 # →
|
||||||
|
# 0xC7 0x2193 # ↓
|
||||||
|
# 0xC8 0x2B60 # ⭠
|
||||||
|
# 0xC9 0x2B61 # ⭡
|
||||||
|
# 0xCA 0x2B62 # ⭢
|
||||||
|
# 0xCB 0x2B63 # ⭣
|
||||||
|
# 0xCC 0x2B80 # ⮀
|
||||||
|
# 0xCD 0x2B81 # ⮁
|
||||||
|
# 0xCE 0x2B82 # ⮂
|
||||||
|
# 0xCF 0x2B83 # ⮃
|
||||||
|
# 0xD0 0xF049 #
|
||||||
|
# 0xD1 0xF04A #
|
||||||
|
# 0xD2 0x23F3 # ⏳
|
||||||
|
# 0xD3 0xF07B #
|
||||||
|
# 0xD4 0xF07C #
|
||||||
|
# 0xD5 0xF114 #
|
||||||
|
# 0xD6 0xF115 #
|
||||||
|
# 0xD7 0xF250 #
|
||||||
|
# 0xD8 0xF251 #
|
||||||
|
# 0xD9 0xF253 #
|
||||||
|
# 0xDA 0xF254 #
|
||||||
|
# 0xDB 0xF461 #
|
||||||
|
# 0xDC 0xF016 #
|
||||||
|
# 0xDD 0xF401 #
|
||||||
|
# 0xDE 0x1F52E # 🔮
|
||||||
|
# 0xDF 0xF2DB #
|
||||||
|
# 0xE0 0xF008 #
|
||||||
|
# 0xE1 0x25C7 # ◇
|
||||||
|
# 0xE2 0x25C8 # ◈
|
||||||
|
# 0xE3 0x1F311 # 🌑
|
||||||
|
# 0xE4 0x1F312 # 🌒
|
||||||
|
# 0xE5 0x1F313 # 🌓
|
||||||
|
# 0xE6 0x1F314 # 🌔
|
||||||
|
# 0xE7 0x1F315 # 🌕
|
||||||
|
# 0xE8 0x1F316 # 🌖
|
||||||
|
# 0xE9 0x1F317 # 🌗
|
||||||
|
# 0xEA 0x1F318 # 🌘
|
||||||
|
# 0xEB 0xF04C #
|
||||||
|
# 0xEC 0x2714 # ✔
|
||||||
|
# 0xED 0x2718 # ✘
|
||||||
|
# 0xEE 0x25C6 # ◆
|
||||||
|
# 0xEF 0xF15D #
|
||||||
|
# 0xF0 0xF15E #
|
||||||
|
# 0xF1 0xF071 #
|
||||||
|
# 0xF2 0xF449 #
|
||||||
|
# 0xF3 0xF529 #
|
||||||
|
# 0xF4 0xF658 #
|
||||||
|
# 0xF5 0xF659 #
|
||||||
|
# 0xF6 0x1f381 # 🎁
|
||||||
|
# 0xF7 0xf05a #
|
||||||
|
# 0xF8 0xf06a #
|
||||||
|
# 0xF9 0xf834 #
|
||||||
|
# 0xFA 0xf835 #
|
||||||
|
# 0xFB 0x2690 # ⚐
|
||||||
|
# 0xFC 0x2691 # ⚑
|
||||||
|
# 0xFD 0xf8d7 #
|
||||||
|
# 0xFE 0xf0e7 #
|
||||||
|
# 0xFF 0xf7d9 #
|
||||||
|
|
||||||
|
|
||||||
|
0x00 0x00 #
|
||||||
|
0x01 0x0295 # ʕ
|
||||||
|
0x02 0x00B7 # ·
|
||||||
|
0x03 0x1D25 # ᴥ
|
||||||
|
0x04 0x0294 # ʔ
|
||||||
|
0x05 0x2661 # ♡
|
||||||
|
0x06 0x2665 # ♥
|
||||||
|
0x07 0x2726 # ✦
|
||||||
|
0x08 0x25C7 # ◇
|
||||||
|
0x09 0x25C6 # ◆
|
||||||
|
0x0a 0x272D # ✭
|
||||||
|
0x0b 0xF005 #
|
||||||
|
0x0c 0x2728 # ✨
|
||||||
|
0x0d 0x000d # CR
|
||||||
|
0x0e 0x2518 # ┘
|
||||||
|
0x0f 0x2514 # └
|
||||||
|
0x10 0x250c # ┌
|
||||||
|
0x11 0x2510 # ┐
|
||||||
|
0x12 0x2500 # ─
|
||||||
|
0x13 0x2502 # │
|
||||||
|
0x14 0x2524 # ┤
|
||||||
|
0x15 0x2534 # ┴
|
||||||
|
0x16 0x251C # ├
|
||||||
|
0x17 0x252C # ┬
|
||||||
|
0x18 0x253C # ┼
|
||||||
|
0x19 0x2571 # ╱
|
||||||
|
0x1a 0x2572 # ╲
|
||||||
|
0x1b 0x2573 # ╳
|
||||||
|
0x1c 0x2591 # ░
|
||||||
|
0x1d 0x2592 # ▒
|
||||||
|
0x1e 0x2593 # ▓
|
||||||
|
0x1f 0x2588 # █
|
||||||
|
0x20 0x0020 #
|
||||||
|
0x21 0x0021 # !
|
||||||
|
0x22 0x0022 # "
|
||||||
|
0x23 0x0023 # #
|
||||||
|
0x24 0x0024 # $
|
||||||
|
0x25 0x0025 # %
|
||||||
|
0x26 0x0026 # &
|
||||||
|
0x27 0x0027 # '
|
||||||
|
0x28 0x0028 # (
|
||||||
|
0x29 0x0029 # )
|
||||||
|
0x2a 0x002A # *
|
||||||
|
0x2b 0x002B # +
|
||||||
|
0x2c 0x002C # ,
|
||||||
|
0x2d 0x002D # -
|
||||||
|
0x2e 0x002E # .
|
||||||
|
0x2f 0x002F # /
|
||||||
|
0x30 0x0030 # 0
|
||||||
|
0x31 0x0031 # 1
|
||||||
|
0x32 0x0032 # 2
|
||||||
|
0x33 0x0033 # 3
|
||||||
|
0x34 0x0034 # 4
|
||||||
|
0x35 0x0035 # 5
|
||||||
|
0x36 0x0036 # 6
|
||||||
|
0x37 0x0037 # 7
|
||||||
|
0x38 0x0038 # 8
|
||||||
|
0x39 0x0039 # 9
|
||||||
|
0x3a 0x003A # :
|
||||||
|
0x3b 0x003B # ;
|
||||||
|
0x3c 0x003C # <
|
||||||
|
0x3d 0x003D # =
|
||||||
|
0x3e 0x003E # >
|
||||||
|
0x3f 0x003F # ?
|
||||||
|
0x40 0x0040 # @
|
||||||
|
0x41 0x0041 # A
|
||||||
|
0x42 0x0042 # B
|
||||||
|
0x43 0x0043 # C
|
||||||
|
0x44 0x0044 # D
|
||||||
|
0x45 0x0045 # E
|
||||||
|
0x46 0x0046 # F
|
||||||
|
0x47 0x0047 # G
|
||||||
|
0x48 0x0048 # H
|
||||||
|
0x49 0x0049 # I
|
||||||
|
0x4a 0x004A # J
|
||||||
|
0x4b 0x004B # K
|
||||||
|
0x4c 0x004C # L
|
||||||
|
0x4d 0x004D # M
|
||||||
|
0x4e 0x004E # N
|
||||||
|
0x4f 0x004F # O
|
||||||
|
0x50 0x0050 # P
|
||||||
|
0x51 0x0051 # Q
|
||||||
|
0x52 0x0052 # R
|
||||||
|
0x53 0x0053 # S
|
||||||
|
0x54 0x0054 # T
|
||||||
|
0x55 0x0055 # U
|
||||||
|
0x56 0x0056 # V
|
||||||
|
0x57 0x0057 # W
|
||||||
|
0x58 0x0058 # X
|
||||||
|
0x59 0x0059 # Y
|
||||||
|
0x5a 0x005A # Z
|
||||||
|
0x5b 0x005B # [
|
||||||
|
0x5c 0x005C # \
|
||||||
|
0x5d 0x005D # ]
|
||||||
|
0x5e 0x005E # ^
|
||||||
|
0x5f 0x005F # _
|
||||||
|
0x60 0x0060 # `
|
||||||
|
0x61 0x0061 # a
|
||||||
|
0x62 0x0062 # b
|
||||||
|
0x63 0x0063 # c
|
||||||
|
0x64 0x0064 # d
|
||||||
|
0x65 0x0065 # e
|
||||||
|
0x66 0x0066 # f
|
||||||
|
0x67 0x0067 # g
|
||||||
|
0x68 0x0068 # h
|
||||||
|
0x69 0x0069 # i
|
||||||
|
0x6a 0x006A # j
|
||||||
|
0x6b 0x006B # k
|
||||||
|
0x6c 0x006C # l
|
||||||
|
0x6d 0x006D # m
|
||||||
|
0x6e 0x006E # n
|
||||||
|
0x6f 0x006F # o
|
||||||
|
0x70 0x0070 # p
|
||||||
|
0x71 0x0071 # q
|
||||||
|
0x72 0x0072 # r
|
||||||
|
0x73 0x0073 # s
|
||||||
|
0x74 0x0074 # t
|
||||||
|
0x75 0x0075 # u
|
||||||
|
0x76 0x0076 # v
|
||||||
|
0x77 0x0077 # w
|
||||||
|
0x78 0x0078 # x
|
||||||
|
0x79 0x0079 # y
|
||||||
|
0x7a 0x007A # z
|
||||||
|
0x7b 0x007B # {
|
||||||
|
0x7c 0x007C # |
|
||||||
|
0x7d 0x007D # }
|
||||||
|
0x7e 0x007E # ~
|
||||||
|
0x7f 0x256F # ╯
|
||||||
|
0x80 0x2570 # ╰
|
||||||
|
0x81 0x256D # ╭
|
||||||
|
0x82 0x256E # ╮
|
||||||
|
0x83 0x255D # ╝
|
||||||
|
0x84 0x255a # ╚
|
||||||
|
0x85 0x2554 # ╔
|
||||||
|
0x86 0x2557 # ╗
|
||||||
|
0x87 0x2550 # ═
|
||||||
|
0x88 0x2551 # ║
|
||||||
|
0x89 0x2563 # ╣
|
||||||
|
0x8a 0x2569 # ╩
|
||||||
|
0x8b 0x2560 # ╠
|
||||||
|
0x8c 0x2566 # ╦
|
||||||
|
0x8d 0x256C # ╬
|
||||||
|
0x8e 0xE0B8 #
|
||||||
|
0x8f 0xE0BA #
|
||||||
|
0x90 0xE0BC #
|
||||||
|
0x91 0xE0BE #
|
||||||
|
0x92 0xE0B2 #
|
||||||
|
0x93 0xE0B0 #
|
||||||
|
0x94 0xE0B6 #
|
||||||
|
0x95 0xE0B4 #
|
||||||
|
0x96 0x2596 # ▖
|
||||||
|
0x97 0x2597 # ▗
|
||||||
|
0x98 0x2598 # ▘
|
||||||
|
0x99 0x2599 # ▙
|
||||||
|
0x9a 0x259A # ▚
|
||||||
|
0x9b 0x259B # ▛
|
||||||
|
0x9c 0x259C # ▜
|
||||||
|
0x9d 0x259D # ▝
|
||||||
|
0x9e 0x259E # ▞
|
||||||
|
0x9f 0x259F # ▟
|
||||||
|
0xa0 0x2581 # ▁
|
||||||
|
0xa1 0x2582 # ▂
|
||||||
|
0xa2 0x2583 # ▃
|
||||||
|
0xa3 0x2584 # ▄
|
||||||
|
0xa4 0x2585 # ▅
|
||||||
|
0xa5 0x2586 # ▆
|
||||||
|
0xa6 0x2587 # ▇
|
||||||
|
0xa7 0x2589 # ▉
|
||||||
|
0xa8 0x258A # ▊
|
||||||
|
0xa9 0x258B # ▋
|
||||||
|
0xaa 0x258C # ▌
|
||||||
|
0xab 0x258D # ▍
|
||||||
|
0xac 0x258E # ▎
|
||||||
|
0xad 0x258F # ▏
|
||||||
|
0xae 0x1F311 # 🌑
|
||||||
|
0xaf 0x1F312 # 🌒
|
||||||
|
0xb0 0x1F313 # 🌓
|
||||||
|
0xb1 0x1F314 # 🌔
|
||||||
|
0xb2 0x1F315 # 🌕
|
||||||
|
0xb3 0x1F316 # 🌖
|
||||||
|
0xb4 0x1F317 # 🌗
|
||||||
|
0xb5 0x1F318 # 🌘
|
||||||
|
0xb6 0xF254 #
|
||||||
|
0xb7 0xF251 #
|
||||||
|
0xb8 0x23F3 # ⏳
|
||||||
|
0xb9 0xF253 #
|
||||||
|
0xba 0xF250 #
|
||||||
|
0xbb 0x2190 # ←
|
||||||
|
0xbc 0x2191 # ↑
|
||||||
|
0xbd 0x2192 # →
|
||||||
|
0xbe 0x2193 # ↓
|
||||||
|
0xbf 0x2B60 # ⭠
|
||||||
|
0xc0 0x2B61 # ⭡
|
||||||
|
0xc1 0x2B62 # ⭢
|
||||||
|
0xc2 0x2B63 # ⭣
|
||||||
|
0xc3 0x2B80 # ⮀
|
||||||
|
0xc4 0x2B81 # ⮁
|
||||||
|
0xc5 0x2B82 # ⮂
|
||||||
|
0xc6 0x2B83 # ⮃
|
||||||
|
0xc7 0xF049 #
|
||||||
|
0xc8 0xF04A #
|
||||||
|
0xc9 0xF048 #
|
||||||
|
0xca 0xF04B #
|
||||||
|
0xcb 0xF04C #
|
||||||
|
0xcc 0xF04D #
|
||||||
|
0xcd 0xF052 #
|
||||||
|
0xce 0xF051 #
|
||||||
|
0xcf 0xF04E #
|
||||||
|
0xd0 0xF050 #
|
||||||
|
0xd1 0xFC5D # ﱝ
|
||||||
|
0xd2 0xF026 #
|
||||||
|
0xd3 0xF027 #
|
||||||
|
0xd4 0xF028 #
|
||||||
|
0xd5 0xFA80 # 婢
|
||||||
|
0xd6 0xFC5C # ﱜ
|
||||||
|
0xd7 0xFC5B # ﱛ
|
||||||
|
0xd8 0x2669 # ♩
|
||||||
|
0xd9 0x266A # ♪
|
||||||
|
0xda 0x266B # ♫
|
||||||
|
0xdb 0x266C # ♬
|
||||||
|
0xdc 0xF016 #
|
||||||
|
0xdd 0xF07B #
|
||||||
|
0xde 0xF07C #
|
||||||
|
0xdf 0xF114 #
|
||||||
|
0xe0 0xF115 #
|
||||||
|
0xe1 0xF15D #
|
||||||
|
0xe2 0xF15E #
|
||||||
|
0xe3 0xF529 #
|
||||||
|
0xe4 0xF071 #
|
||||||
|
0xe5 0xF449 #
|
||||||
|
0xe6 0xf05a #
|
||||||
|
0xe7 0xF659 #
|
||||||
|
0xe8 0xF658 #
|
||||||
|
0xe9 0xf835 #
|
||||||
|
0xea 0xf834 #
|
||||||
|
0xeb 0x2690 # ⚐
|
||||||
|
0xec 0x2691 # ⚑
|
||||||
|
0xed 0xf7d9 #
|
||||||
|
0xee 0x2714 # ✔
|
||||||
|
0xef 0x2718 # ✘
|
||||||
|
0xf0 0xf0e7 #
|
||||||
|
0xf1 0xF2DB #
|
||||||
|
0xf2 0xF008 #
|
||||||
|
0xf3 0xF461 #
|
||||||
|
0xf4 0x2B50 # ⭐
|
||||||
|
0xf5 0xF401 #
|
||||||
|
0xf6 0x1F52E # 🔮
|
||||||
|
0xf7 0x1f381 # 🎁
|
||||||
|
0xf8 0xf8d7 #
|
||||||
|
0xf9 0xF0AC #
|
||||||
|
0xfa 0x25C8 # ◈
|
||||||
|
0xfb 0x2640 # ♀
|
||||||
|
0xfc 0x2642 # ♂
|
||||||
|
0xfd 0x26A2 # ⚢
|
||||||
|
0xfe 0x26A3 # ⚣
|
||||||
|
0xff 0x26A5 # ⚥
|
||||||
Executable
+5
@@ -0,0 +1,5 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
fontforge -lang=ff -c 'Open($1); LoadEncodingFile($2, "george"); Reencode("george"); Generate($3)' Cozette.sfd georgeencoding.txt cozette.bdf
|
||||||
|
sed -i'' -e 's/FONTBOUNDINGBOX 11 13 0 -3/FONTBOUNDINGBOX 8 13 0 -3/' *.bdf
|
||||||
|
mv cozette-13.bdf cozette.bdf
|
||||||
Generated
+112
@@ -0,0 +1,112 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1696426674,
|
||||||
|
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"naersk": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1698420672,
|
||||||
|
"narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=",
|
||||||
|
"owner": "nmattia",
|
||||||
|
"repo": "naersk",
|
||||||
|
"rev": "aeb58d5e8faead8980a807c840232697982d47b9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nmattia",
|
||||||
|
"ref": "master",
|
||||||
|
"repo": "naersk",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1712696601,
|
||||||
|
"narHash": "sha256-puFPFSa/RC83JilUgB48/VL387eu2QN066Jv6X971LY=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "062fc6cf99d809921ecef47317752fc92468e6ae",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1712608508,
|
||||||
|
"narHash": "sha256-vMZ5603yU0wxgyQeHJryOI+O61yrX2AHwY6LOFyV1gM=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "4cba8b53da471aea2ab2b0c1f30a81e7c451f4b6",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"naersk": "naersk",
|
||||||
|
"nixpkgs": "nixpkgs_2",
|
||||||
|
"utils": "utils"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1710146030,
|
||||||
|
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
inputs = {
|
||||||
|
naersk.url = "github:nmattia/naersk/master";
|
||||||
|
# This must be the stable nixpkgs if you're running the app on a
|
||||||
|
# stable NixOS install. Mixing EGL library versions doesn't work.
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
utils.url = "github:numtide/flake-utils";
|
||||||
|
flake-compat = {
|
||||||
|
url = github:edolstra/flake-compat;
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, utils, naersk, ... }:
|
||||||
|
utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
naersk-lib = pkgs.callPackage naersk { };
|
||||||
|
libPath = with pkgs; lib.makeLibraryPath [
|
||||||
|
libxkbcommon
|
||||||
|
wayland
|
||||||
|
xorg.libX11
|
||||||
|
xorg.libXcursor
|
||||||
|
xorg.libXi
|
||||||
|
xorg.libXrandr
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
defaultPackage = naersk-lib.buildPackage {
|
||||||
|
src = ./.;
|
||||||
|
doCheck = true;
|
||||||
|
pname = "georgeemu";
|
||||||
|
nativeBuildInputs = [ pkgs.makeWrapper ];
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
xorg.libxcb
|
||||||
|
];
|
||||||
|
postInstall = ''
|
||||||
|
wrapProgram "$out/bin/georgeemu" --prefix LD_LIBRARY_PATH : "${libPath}"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultApp = utils.lib.mkApp {
|
||||||
|
drv = self.defaultPackage."${system}";
|
||||||
|
};
|
||||||
|
|
||||||
|
devShell = with pkgs; mkShell {
|
||||||
|
buildInputs = [
|
||||||
|
cargo
|
||||||
|
cargo-insta
|
||||||
|
pre-commit
|
||||||
|
rust-analyzer
|
||||||
|
rustPackages.clippy
|
||||||
|
rustc
|
||||||
|
rustfmt
|
||||||
|
|
||||||
|
xorg.libxcb
|
||||||
|
];
|
||||||
|
RUST_SRC_PATH = rustPlatform.rustLibSrc;
|
||||||
|
LD_LIBRARY_PATH = libPath;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
char_rom = "./src/roms/cozette.rom"
|
||||||
|
rom = "./src/roms/keyboard_sys.rom"
|
||||||
|
screen = "Window"
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
.org $00
|
||||||
|
|
||||||
|
.byte $80
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
reset:
|
||||||
|
bbr7 $00, reset
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+238
@@ -0,0 +1,238 @@
|
|||||||
|
; .setcpu "65C02"
|
||||||
|
.include "./macro.inc"
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
n = $01 ; temporary storage for data stack operations
|
||||||
|
|
||||||
|
temp = $20 ; scratchpad page
|
||||||
|
|
||||||
|
cursor = $300
|
||||||
|
cursor_x = cursor
|
||||||
|
cursor_y = cursor + 1
|
||||||
|
|
||||||
|
rand_index = $200
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
ldx #0; initialize data stack pointer
|
||||||
|
|
||||||
|
init:
|
||||||
|
cli
|
||||||
|
|
||||||
|
main:
|
||||||
|
jsr print
|
||||||
|
jsr rand_draw
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
newline: ; sets cursor to start of next line
|
||||||
|
stz cursor_x
|
||||||
|
lda cursor_y
|
||||||
|
cmp #28
|
||||||
|
bne .end
|
||||||
|
stz cursor_y
|
||||||
|
rts
|
||||||
|
.end:
|
||||||
|
inc cursor_y
|
||||||
|
rts
|
||||||
|
|
||||||
|
text:
|
||||||
|
.byte 1,2,3,2,4
|
||||||
|
.asciiz "- george loves u <3"
|
||||||
|
|
||||||
|
random_y:
|
||||||
|
.byte 25,12,0,20,4,25,5,13
|
||||||
|
.byte 20, 1, 1, 22, 12, 19, 19, 19
|
||||||
|
.byte 9, 0, 4, 18, 13, 14, 4, 16
|
||||||
|
.byte 8, 17, 21, 14, 23, 21, 9, 0
|
||||||
|
.byte 14, 10, 14, 2, 26, 18, 15, 23
|
||||||
|
.byte 12, 2, 5, 4, 25, 20, 27, 4
|
||||||
|
.byte 28, 21, 3, 22, 11, 25, 2, 25
|
||||||
|
.byte 13, 17, 17, 24, 8, 8, 20, 21
|
||||||
|
.byte 11, 24, 27, 25, 8, 12, 7, 0
|
||||||
|
.byte 27, 12, 19, 27, 10, 3, 19, 2
|
||||||
|
.byte 2, 23, 22, 5, 26, 28, 4, 16
|
||||||
|
.byte 18, 7, 10, 9, 6, 19, 9, 2
|
||||||
|
.byte 14, 8, 14, 18, 18, 2, 13, 0
|
||||||
|
.byte 15, 26, 3, 23, 17, 12, 18, 11
|
||||||
|
.byte 4, 16, 17, 22, 9, 25, 3, 15
|
||||||
|
.byte 28, 3, 6, 14, 25, 5, 21, 8
|
||||||
|
.byte 15, 18, 15, 5, 28, 6, 15, 4
|
||||||
|
.byte 10, 1, 16, 24, 6, 9, 22, 3
|
||||||
|
.byte 17, 18, 10, 19, 27, 11, 22, 16
|
||||||
|
.byte 22, 17, 15, 6, 23, 11, 11, 11
|
||||||
|
.byte 4, 15, 5, 25, 19, 1, 8, 26
|
||||||
|
.byte 21, 20, 17, 27, 11, 3, 11, 20
|
||||||
|
.byte 15, 28, 0, 6, 14, 23, 20, 21
|
||||||
|
.byte 17, 20, 16, 15, 19, 6, 21, 19
|
||||||
|
.byte 15, 27, 1, 22, 7, 0, 5, 2
|
||||||
|
.byte 14, 24, 15, 4, 20, 16, 1, 14
|
||||||
|
.byte 4, 16, 4, 8, 13, 26, 3, 9
|
||||||
|
.byte 12, 25, 5, 0, 7, 17, 14, 20
|
||||||
|
.byte 2, 26, 2, 27, 18, 23, 5, 8
|
||||||
|
.byte 4, 21, 10, 11, 28, 22, 6, 6
|
||||||
|
.byte 10, 13, 23, 12, 20, 28, 20, 1
|
||||||
|
.byte 27, 19, 25, 6, 1, 10, 1
|
||||||
|
|
||||||
|
random_x:
|
||||||
|
.byte 42, 59, 11, 5, 18, 0, 26, 1
|
||||||
|
.byte 61, 16, 1, 51, 36, 47, 23, 1
|
||||||
|
.byte 16, 50, 46, 4, 55, 31, 15, 2
|
||||||
|
.byte 45, 21, 59, 53, 15, 43, 0, 2
|
||||||
|
.byte 64, 31, 38, 41, 25, 12, 12, 3
|
||||||
|
.byte 30, 13, 64, 44, 21, 8, 48, 3
|
||||||
|
.byte 46, 1, 2, 33, 4, 32, 59, 28
|
||||||
|
.byte 4, 24, 58, 53, 21, 41, 30, 2
|
||||||
|
.byte 56, 53, 31, 10, 42, 12, 9, 54
|
||||||
|
.byte 14, 14, 24, 29, 43, 60, 54, 26
|
||||||
|
.byte 5, 53, 17, 55, 27, 46, 31, 3
|
||||||
|
.byte 26, 44, 63, 30, 10, 34, 62, 48
|
||||||
|
.byte 42, 47, 51, 7, 55, 32, 14, 21
|
||||||
|
.byte 15, 26, 52, 37, 48, 0, 13, 2
|
||||||
|
.byte 50, 20, 35, 32, 8, 41, 2, 24
|
||||||
|
.byte 18, 9, 52, 22, 52, 12, 19, 32
|
||||||
|
.byte 29, 46, 34, 58, 54, 51, 43, 57
|
||||||
|
.byte 62, 10, 12, 57, 36, 39, 4, 30
|
||||||
|
.byte 38, 9, 30, 32, 33, 57, 3, 25
|
||||||
|
.byte 21, 36, 59, 30, 19, 39, 9, 60
|
||||||
|
.byte 34, 50, 52, 37, 34, 42, 3, 33
|
||||||
|
.byte 40, 19, 2, 26, 10, 38, 46, 30
|
||||||
|
.byte 3, 1, 19, 16, 26, 58, 42, 49
|
||||||
|
.byte 63, 1, 63, 41, 0, 21, 41, 19
|
||||||
|
.byte 21, 45, 44, 52, 20, 5, 11, 64
|
||||||
|
.byte 1, 62, 16, 5, 5, 8, 58, 56
|
||||||
|
.byte 16, 26, 6, 37, 19, 16, 25, 29
|
||||||
|
.byte 64, 59, 16, 6, 41, 28, 8, 51
|
||||||
|
.byte 54, 5, 19, 28, 13, 38, 52, 35
|
||||||
|
.byte 42, 13, 34, 33, 61, 61, 7, 27
|
||||||
|
.byte 38, 33, 9, 57, 10, 30, 8, 4
|
||||||
|
.byte 46, 3, 39, 46, 62, 20, 48, 7
|
||||||
|
|
||||||
|
|
||||||
|
; increments the cursor line by line, looping to (0, 0) after (63, 28)
|
||||||
|
|
||||||
|
inc_cursor:
|
||||||
|
lda cursor_x
|
||||||
|
cmp #63
|
||||||
|
beq .newline
|
||||||
|
inc cursor_x
|
||||||
|
rts
|
||||||
|
.newline:
|
||||||
|
lda cursor_y
|
||||||
|
cmp #28
|
||||||
|
beq .newscreen
|
||||||
|
stz cursor_x
|
||||||
|
inc cursor_y
|
||||||
|
rts
|
||||||
|
.newscreen:
|
||||||
|
stz cursor_y
|
||||||
|
stz cursor_x
|
||||||
|
rts
|
||||||
|
|
||||||
|
; zeroes out the display, resets cursor to 0,0
|
||||||
|
|
||||||
|
clear:
|
||||||
|
lda #0
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
.loop:
|
||||||
|
sta $6000,y
|
||||||
|
sta $6100,y
|
||||||
|
sta $6200,y
|
||||||
|
sta $6300,y
|
||||||
|
sta $6400,y
|
||||||
|
sta $6500,y
|
||||||
|
sta $6600,y
|
||||||
|
sta $6700,y ; this goes slightly over but it's fine
|
||||||
|
iny
|
||||||
|
bne .loop
|
||||||
|
stz cursor
|
||||||
|
stz cursor + 1
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
; prints string from cursor position, stopping at end of string or at 256 chars, whichever comes first
|
||||||
|
; $6000 + (64*Y) + X
|
||||||
|
; THIS WILL WRITE OUT OF BOUNDS IF THE CURSOR IS OUT OF BOUNDS/STRING IS TOO LONG
|
||||||
|
|
||||||
|
; TODO: figure out a simple way of writing arbitrary length strings
|
||||||
|
|
||||||
|
print:
|
||||||
|
jsr cursor_addr
|
||||||
|
ldy #0
|
||||||
|
; y_overflow = temp + 5
|
||||||
|
.loop:
|
||||||
|
lda text, y
|
||||||
|
beq .end
|
||||||
|
sta (temp), y
|
||||||
|
iny
|
||||||
|
bra .loop
|
||||||
|
.end:
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
; calculates real vram address from cursor (x, y)
|
||||||
|
|
||||||
|
cursor_addr:
|
||||||
|
stz temp
|
||||||
|
stz temp + 1
|
||||||
|
lda cursor_y
|
||||||
|
beq .add_x ; if y's zero just add x
|
||||||
|
.y_mult:
|
||||||
|
; multiply by 64
|
||||||
|
clc
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
sta temp
|
||||||
|
.add_x:
|
||||||
|
clc
|
||||||
|
lda cursor_x
|
||||||
|
adc temp
|
||||||
|
sta temp
|
||||||
|
lda #0
|
||||||
|
adc temp + 1
|
||||||
|
sta temp + 1
|
||||||
|
clc
|
||||||
|
|
||||||
|
lda #$60
|
||||||
|
adc temp + 1
|
||||||
|
sta temp + 1
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
rand_draw:
|
||||||
|
ldx rand_index
|
||||||
|
lda random_x, x
|
||||||
|
sta cursor_x
|
||||||
|
lda random_y, x
|
||||||
|
sta cursor_y
|
||||||
|
jsr cursor_addr
|
||||||
|
inc rand_index
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
isr: ; interrupt service routine
|
||||||
|
pha
|
||||||
|
phx
|
||||||
|
phy
|
||||||
|
; jsr irq
|
||||||
|
ply
|
||||||
|
plx
|
||||||
|
pla
|
||||||
|
rti
|
||||||
|
|
||||||
|
.include "math.inc"
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
|
.word isr
|
||||||
Binary file not shown.
+189
@@ -0,0 +1,189 @@
|
|||||||
|
; .setcpu "65C02"
|
||||||
|
.include "./macro.inc"
|
||||||
|
|
||||||
|
; okay so rn i wanna set up a very basic system init, and write a few subroutines to draw characters at x,y coordinates
|
||||||
|
n = $01 ; temporary storage for data stack operations
|
||||||
|
|
||||||
|
key_row = $200 ; used for character lookup when key pressed
|
||||||
|
key_col = $201
|
||||||
|
cursor = $202
|
||||||
|
|
||||||
|
char_buffer = $300 ; 256 byte character buffer
|
||||||
|
|
||||||
|
kb_row = $4400 ; keyboard hardware register
|
||||||
|
kb_row_cache = $203 ; cache
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
ldx #0; initialize data stack pointer
|
||||||
|
|
||||||
|
initdisplay:
|
||||||
|
lda #0
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
cleardisplay:
|
||||||
|
sta $6000,y
|
||||||
|
sta $6100,y
|
||||||
|
sta $6200,y
|
||||||
|
sta $6300,y
|
||||||
|
sta $6400,y
|
||||||
|
sta $6500,y
|
||||||
|
sta $6600,y
|
||||||
|
sta $6700,y ; this goes slightly over but it's fine
|
||||||
|
iny
|
||||||
|
bne cleardisplay
|
||||||
|
cli
|
||||||
|
|
||||||
|
print_test:
|
||||||
|
lda #0
|
||||||
|
sta key_row
|
||||||
|
lda #5
|
||||||
|
sta key_col
|
||||||
|
push_coords #5, #5
|
||||||
|
|
||||||
|
main:
|
||||||
|
; jsr printtext
|
||||||
|
; key_zero:
|
||||||
|
; stz keyboard_cache, x
|
||||||
|
; dex
|
||||||
|
; bpl key_zero
|
||||||
|
; fim:
|
||||||
|
; cli
|
||||||
|
; bra fim
|
||||||
|
jsr print
|
||||||
|
; jsr print
|
||||||
|
stp
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
; keyboard: ; reads keyboard registers and stores the column and row of the first key found
|
||||||
|
; ; TODO: make this routine store up to 8 indices (for 8 key rollover)
|
||||||
|
; ldy #0
|
||||||
|
; .check_row: ; loop through each row
|
||||||
|
; lda kb_row, y
|
||||||
|
; beq .skip_row ; if row has no key pressed, skip checking which key
|
||||||
|
; ; jmp key_down
|
||||||
|
; sta kb_row_cache, y ; if key pressed, cache it
|
||||||
|
; lda kb_row, y
|
||||||
|
; cmp kb_row_cache, y ; has key changed?
|
||||||
|
; beq key_down
|
||||||
|
; .skip_row:
|
||||||
|
; iny
|
||||||
|
; cpy #5
|
||||||
|
; bne .check_row
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; key_down: ; a is loaded with the row byte
|
||||||
|
; phy
|
||||||
|
; sty key_row ; store character row
|
||||||
|
; ldy #0
|
||||||
|
; .find_col: ; test each row bit, store column if key pressed
|
||||||
|
; lsr ; test bit 7
|
||||||
|
; bcs store_col ; if unset, don't go store character columnb
|
||||||
|
; .skip:
|
||||||
|
; iny
|
||||||
|
; cpy #8
|
||||||
|
; bne .find_col ; loop until we've checked each bit
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; store_col:
|
||||||
|
; sty key_col
|
||||||
|
; jsr print
|
||||||
|
; rts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
print: ; x y -- prints the key indexed with key_col and key_row at position x, y
|
||||||
|
|
||||||
|
keymap_index:
|
||||||
|
push
|
||||||
|
lda key_col
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
push
|
||||||
|
lda #8
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
push
|
||||||
|
lda key_row
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
jsr mult
|
||||||
|
jsr plus
|
||||||
|
lda 0, x
|
||||||
|
tay
|
||||||
|
lda keymap, y
|
||||||
|
push
|
||||||
|
sta 0, x
|
||||||
|
stz 1, x
|
||||||
|
jsr draw_char
|
||||||
|
rts
|
||||||
|
|
||||||
|
keymap:
|
||||||
|
.byte "?outrew?"
|
||||||
|
.byte "?piygsq?"
|
||||||
|
.byte "a??khvd?"
|
||||||
|
.byte "42ljbfz?"
|
||||||
|
.byte "31?mncx?"
|
||||||
|
.byte "????? m"
|
||||||
|
|
||||||
|
draw:
|
||||||
|
; push_coords #0, #0
|
||||||
|
; push_char #$00
|
||||||
|
; jsr draw_char
|
||||||
|
rts
|
||||||
|
|
||||||
|
draw_char: ; draw a character c at (x, y) (n1: x n2: y n3: c -- )
|
||||||
|
lda 0, x ; load a with character to draw
|
||||||
|
pop ; and pop it off the stack
|
||||||
|
jsr get_char_address ; calculate where to put the character in memory
|
||||||
|
sta (0, x) ; store a at the address pointed to on the stack
|
||||||
|
rts
|
||||||
|
|
||||||
|
get_char_address: ; gets vram address for a character at (x, y),
|
||||||
|
; (n1: x n2: y -- n: $6000 + x + (64 * y))
|
||||||
|
;jsr push_lit ; push 64 onto stack, low byte first
|
||||||
|
;.byte 64
|
||||||
|
;.byte 0
|
||||||
|
pha
|
||||||
|
lda #64
|
||||||
|
push ; doing this instead until `push_lit` is fixed
|
||||||
|
sta 0, x
|
||||||
|
stz 1, x
|
||||||
|
jsr mult ; multiply 64 with y (n2)
|
||||||
|
jsr plus ; add result with x (n1)
|
||||||
|
|
||||||
|
;jsr push_lit ; push vram address onto the stack
|
||||||
|
;.byte $00
|
||||||
|
;.byte $60
|
||||||
|
lda #$60
|
||||||
|
push
|
||||||
|
sta 1, x
|
||||||
|
stz 0, x
|
||||||
|
jsr plus ; add vram start address to result
|
||||||
|
|
||||||
|
pla
|
||||||
|
rts
|
||||||
|
|
||||||
|
fill: ; fills an area from (x1, y1) to (x2, y2) will character c, (n1: c n2: x1 n3: y1 n4: x2 n5: y2 -- )
|
||||||
|
jsr get_char_address
|
||||||
|
|
||||||
|
isr: ; interrupt service routine
|
||||||
|
pha
|
||||||
|
phx
|
||||||
|
phy
|
||||||
|
; jsr keyboard
|
||||||
|
ply
|
||||||
|
plx
|
||||||
|
pla
|
||||||
|
rti
|
||||||
|
|
||||||
|
.include "math.inc"
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
|
.word isr
|
||||||
Binary file not shown.
@@ -0,0 +1,124 @@
|
|||||||
|
; .setcpu "65C02"
|
||||||
|
.include "./macro.inc"
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
n = $01 ; temporary storage for data stack operations
|
||||||
|
key_buffer = $200
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
ldx #0; initialize data stack pointer
|
||||||
|
|
||||||
|
initdisplay:
|
||||||
|
lda #0
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
cleardisplay:
|
||||||
|
sta $6000,y
|
||||||
|
sta $6100,y
|
||||||
|
sta $6200,y
|
||||||
|
sta $6300,y
|
||||||
|
sta $6400,y
|
||||||
|
sta $6500,y
|
||||||
|
sta $6600,y
|
||||||
|
sta $6700,y ; this goes slightly over but it's fine
|
||||||
|
iny
|
||||||
|
bne cleardisplay
|
||||||
|
; cli
|
||||||
|
|
||||||
|
main:
|
||||||
|
jsr read_keys
|
||||||
|
lda key_buffer
|
||||||
|
sta $6000
|
||||||
|
; lda $4400
|
||||||
|
; sta $6000
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
; first, let's do the simplest case of just the letter a being pressed
|
||||||
|
; 1. check row 2 ($4402, where the a key is) for pressed keys
|
||||||
|
; 2. if any keys are pressed, check if the key is a (bit 0)
|
||||||
|
; 3. if the key is not a, store zero in the key buffer
|
||||||
|
; 4. if the key is a, store the ascii for a in the key buffer
|
||||||
|
; 5. return
|
||||||
|
|
||||||
|
; so u don't have to scroll: key_buffer = $200
|
||||||
|
; key buffer just shows the current state of the keyboard
|
||||||
|
; it is not a queue of keys to print
|
||||||
|
|
||||||
|
read_keys:
|
||||||
|
lda $4402 ; check row 2
|
||||||
|
beq check_key ; if there're any keys, check which
|
||||||
|
clear_buffer:
|
||||||
|
stz key_buffer
|
||||||
|
rts
|
||||||
|
check_key: ; if there is a key pressed, check if it's a
|
||||||
|
ror
|
||||||
|
bmi store_key
|
||||||
|
rts
|
||||||
|
store_key:
|
||||||
|
; in a sec we'll set up ascii table lookup,
|
||||||
|
; for now let's just load the ascii byte for a
|
||||||
|
lda #$61
|
||||||
|
sta key_buffer
|
||||||
|
rts
|
||||||
|
|
||||||
|
draw:
|
||||||
|
push_coords #0, #0
|
||||||
|
push_char #$af
|
||||||
|
jsr draw_char
|
||||||
|
rts
|
||||||
|
|
||||||
|
draw_char: ; draw a character c at (x, y) (n1: x n2: y n3: c -- )
|
||||||
|
lda 0, x ; load a with character to draw
|
||||||
|
pop ; and pop it off the stack
|
||||||
|
jsr get_char_address ; calculate where to put the character in memory
|
||||||
|
sta (0, x) ; store a at the address pointed to on the stack
|
||||||
|
rts
|
||||||
|
|
||||||
|
get_char_address: ; gets vram address for a character at (x, y),
|
||||||
|
; (n1: x n2: y -- n: $6000 + x + (64 * y))
|
||||||
|
;jsr push_lit ; push 64 onto stack, low byte first
|
||||||
|
;.byte 64
|
||||||
|
;.byte 0
|
||||||
|
pha
|
||||||
|
lda #64
|
||||||
|
push ; doing this instead until `push_lit` is fixed
|
||||||
|
sta 0, x
|
||||||
|
stz 1, x
|
||||||
|
jsr mult ; multiply 64 with y (n2)
|
||||||
|
jsr plus ; add result with x (n1)
|
||||||
|
|
||||||
|
;jsr push_lit ; push vram address onto the stack
|
||||||
|
;.byte $00
|
||||||
|
;.byte $60
|
||||||
|
lda #$60
|
||||||
|
push
|
||||||
|
sta 1, x
|
||||||
|
stz 0, x
|
||||||
|
jsr plus ; add vram start address to result
|
||||||
|
|
||||||
|
pla
|
||||||
|
rts
|
||||||
|
|
||||||
|
fill: ; fills an area from (x1, y1) to (x2, y2) will character c, (n1: c n2: x1 n3: y1 n4: x2 n5: y2 -- )
|
||||||
|
jsr get_char_address
|
||||||
|
|
||||||
|
irq:
|
||||||
|
rts
|
||||||
|
|
||||||
|
isr: ; interrupt service routine
|
||||||
|
pha
|
||||||
|
phx
|
||||||
|
phy
|
||||||
|
jsr irq
|
||||||
|
ply
|
||||||
|
plx
|
||||||
|
pla
|
||||||
|
rti
|
||||||
|
|
||||||
|
.include "math.inc"
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
|
.word isr
|
||||||
Binary file not shown.
@@ -0,0 +1,215 @@
|
|||||||
|
; .setcpu "65C02"
|
||||||
|
.include "./macro.inc"
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
n = $01 ; temporary storage for data stack operations
|
||||||
|
|
||||||
|
temp = $20 ; scratchpad page
|
||||||
|
str_ptr = $30
|
||||||
|
|
||||||
|
cursor = $300
|
||||||
|
cursor_x = cursor
|
||||||
|
cursor_y = cursor + 1
|
||||||
|
|
||||||
|
char_buf = $302
|
||||||
|
char_buf_index = char_buf + 8
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
ldx #0; initialize data stack pointer
|
||||||
|
|
||||||
|
init:
|
||||||
|
lda #$31
|
||||||
|
sta str_ptr
|
||||||
|
lda #$80
|
||||||
|
sta str_ptr + 1
|
||||||
|
|
||||||
|
jsr clear
|
||||||
|
lda #0
|
||||||
|
sta cursor_x
|
||||||
|
lda #0
|
||||||
|
sta cursor_y
|
||||||
|
cli
|
||||||
|
|
||||||
|
main:
|
||||||
|
jsr print
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
newline: ; sets cursor to start of next line
|
||||||
|
stz cursor_x
|
||||||
|
lda cursor_y
|
||||||
|
cmp #28
|
||||||
|
bne .end
|
||||||
|
stz cursor_y
|
||||||
|
rts
|
||||||
|
.end:
|
||||||
|
inc cursor_y
|
||||||
|
rts
|
||||||
|
|
||||||
|
text:
|
||||||
|
.asciiz "hello <3"
|
||||||
|
|
||||||
|
; increments the cursor line by line, looping to (0, 0) after (63, 28)
|
||||||
|
|
||||||
|
inc_cursor:
|
||||||
|
lda cursor_x
|
||||||
|
cmp #63
|
||||||
|
beq .newline
|
||||||
|
inc cursor_x
|
||||||
|
rts
|
||||||
|
.newline:
|
||||||
|
lda cursor_y
|
||||||
|
cmp #28
|
||||||
|
beq .newscreen
|
||||||
|
stz cursor_x
|
||||||
|
inc cursor_y
|
||||||
|
rts
|
||||||
|
.newscreen:
|
||||||
|
stz cursor_y
|
||||||
|
stz cursor_x
|
||||||
|
rts
|
||||||
|
|
||||||
|
; zeroes out the display, resets cursor to 0,0
|
||||||
|
|
||||||
|
clear:
|
||||||
|
lda #0
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
.loop:
|
||||||
|
sta $6000,y
|
||||||
|
sta $6100,y
|
||||||
|
sta $6200,y
|
||||||
|
sta $6300,y
|
||||||
|
sta $6400,y
|
||||||
|
sta $6500,y
|
||||||
|
sta $6600,y
|
||||||
|
sta $6700,y ; this goes slightly over but it's fine
|
||||||
|
iny
|
||||||
|
bne .loop
|
||||||
|
stz cursor
|
||||||
|
stz cursor + 1
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
; prints string from cursor position, stopping at end of string or at 256 chars, whichever comes first
|
||||||
|
; $6000 + (64*Y) + X
|
||||||
|
; THIS WILL WRITE OUT OF BOUNDS IF THE CURSOR IS OUT OF BOUNDS/STRING IS TOO LONG
|
||||||
|
|
||||||
|
; TODO: figure out a simple way of writing arbitrary length strings
|
||||||
|
; and
|
||||||
|
|
||||||
|
print:
|
||||||
|
jsr cursor_addr
|
||||||
|
ldy #0
|
||||||
|
; y_overflow = temp + 5
|
||||||
|
.loop:
|
||||||
|
lda (str_ptr), y
|
||||||
|
beq .end
|
||||||
|
sta (temp), y
|
||||||
|
iny
|
||||||
|
bra .loop
|
||||||
|
.end:
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
; calculates real vram address from cursor (x, y)
|
||||||
|
|
||||||
|
cursor_addr:
|
||||||
|
stz temp
|
||||||
|
stz temp + 1
|
||||||
|
lda cursor_y
|
||||||
|
beq .add_x ; if y's zero just add x
|
||||||
|
.y_mult:
|
||||||
|
; multiply by 64
|
||||||
|
clc
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
asl
|
||||||
|
rol temp + 1
|
||||||
|
sta temp
|
||||||
|
.add_x:
|
||||||
|
clc
|
||||||
|
lda cursor_x
|
||||||
|
adc temp
|
||||||
|
sta temp
|
||||||
|
lda #0
|
||||||
|
adc temp + 1
|
||||||
|
sta temp + 1
|
||||||
|
clc
|
||||||
|
|
||||||
|
lda #$60
|
||||||
|
adc temp + 1
|
||||||
|
sta temp + 1
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
; print_text:
|
||||||
|
; lda text,y
|
||||||
|
; beq .end
|
||||||
|
; sta $6000, y
|
||||||
|
; iny
|
||||||
|
; bra print_text
|
||||||
|
; .end:
|
||||||
|
; ldy #0
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; draw_char: ; draw a character c at (x, y) (n1: x n2: y n3: c -- )
|
||||||
|
; lda 0, x ; load a with character to draw
|
||||||
|
; pop ; and pop it off the stack
|
||||||
|
; jsr get_char_address ; calculate where to put the character in memory
|
||||||
|
; sta (0, x) ; store a at the address pointed to on the stack
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; get_char_address: ; gets vram address for a character at (x, y),
|
||||||
|
; ; (n1: x n2: y -- n: $6000 + x + (64 * y))
|
||||||
|
; ;jsr push_lit ; push 64 onto stack, low byte first
|
||||||
|
; ;.byte 64
|
||||||
|
; ;.byte 0
|
||||||
|
; pha
|
||||||
|
; lda #64
|
||||||
|
; push ; doing this instead until `push_lit` is fixed
|
||||||
|
; sta 0, x
|
||||||
|
; stz 1, x
|
||||||
|
; jsr mult ; multiply 64 with y (n2)
|
||||||
|
; jsr plus ; add result with x (n1)
|
||||||
|
|
||||||
|
; ;jsr push_lit ; push vram address onto the stack
|
||||||
|
; ;.byte $00
|
||||||
|
; ;.byte $60
|
||||||
|
; lda #$60
|
||||||
|
; push
|
||||||
|
; sta 1, x
|
||||||
|
; stz 0, x
|
||||||
|
; jsr plus ; add vram start address to result
|
||||||
|
|
||||||
|
; pla
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; fill: ; fills an area from (x1, y1) to (x2, y2) will character c, (n1: c n2: x1 n3: y1 n4: x2 n5: y2 -- )
|
||||||
|
; jsr get_char_address
|
||||||
|
|
||||||
|
isr: ; interrupt service routine
|
||||||
|
pha
|
||||||
|
phx
|
||||||
|
phy
|
||||||
|
; jsr irq
|
||||||
|
ply
|
||||||
|
plx
|
||||||
|
pla
|
||||||
|
rti
|
||||||
|
|
||||||
|
.include "math.inc"
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
|
.word isr
|
||||||
Binary file not shown.
@@ -0,0 +1,62 @@
|
|||||||
|
.macro breakpoint ; $02 isn't a valid instruction, the emulator will see this and halt, dump memory contents
|
||||||
|
.byte $02
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro pop ; drops a data stack cell
|
||||||
|
inx
|
||||||
|
inx
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro pop2 ; drops 2 data stack cells
|
||||||
|
inx
|
||||||
|
inx
|
||||||
|
inx
|
||||||
|
inx
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro push ; push a data stack cell
|
||||||
|
dex
|
||||||
|
dex
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro push2 ; push 2 data stack cells
|
||||||
|
dex
|
||||||
|
dex
|
||||||
|
dex
|
||||||
|
dex
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro push_char, char; pushes an ascii character code onto the stack
|
||||||
|
lda \char
|
||||||
|
push
|
||||||
|
sta 0, x ; char low byte
|
||||||
|
stz 1, x ; char high byte
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro push_coords, coord_x, coord_y ; push a set of (x,y) coordinates onto the data stack
|
||||||
|
lda \coord_x
|
||||||
|
push
|
||||||
|
sta 0, x ; low byte
|
||||||
|
stz 1,x ; high byte is zero
|
||||||
|
lda \coord_y
|
||||||
|
push
|
||||||
|
sta 0,x ; same here
|
||||||
|
stz 1,x
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro to_r ; pop the top of the stack off and save it in the return (hardware) stack: (n -- )
|
||||||
|
lda 1, x
|
||||||
|
pha
|
||||||
|
lda 0, x
|
||||||
|
pha
|
||||||
|
pop
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro from_r ; pop the top of the return stack off and put it on the data stack: ( -- n)
|
||||||
|
push
|
||||||
|
pla
|
||||||
|
sta 0, x
|
||||||
|
pla
|
||||||
|
sta 1, x
|
||||||
|
.endm
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
; --- Data Stack --- ;
|
||||||
|
; on this channel we love garth wilson: https://wilsonminesco.com/stacks/StackOps.ASM
|
||||||
|
; data stack is built up of 2-byte cells
|
||||||
|
|
||||||
|
|
||||||
|
; TODO: this is broken, jumping here does nothing to the stack and skips several instructions, could be an emulator problem tho
|
||||||
|
; push_lit: ; this bad boy lets you inline a literal (low byte first) right after `jsr push_lit` and put it on the stack, once again, on this channel we love garth wilson
|
||||||
|
; push2
|
||||||
|
; phx
|
||||||
|
; tsx
|
||||||
|
; txa
|
||||||
|
; tay
|
||||||
|
; plx
|
||||||
|
|
||||||
|
; lda $102, y
|
||||||
|
; sta 0, x
|
||||||
|
; clc
|
||||||
|
; adc #2
|
||||||
|
; sta $102, y
|
||||||
|
|
||||||
|
; lda $103, y
|
||||||
|
; sta 1, x
|
||||||
|
; adc #0
|
||||||
|
; sta $103, y
|
||||||
|
|
||||||
|
; fetch:
|
||||||
|
; lda (0, x)
|
||||||
|
; pha
|
||||||
|
; inc 0, x
|
||||||
|
; bne .1
|
||||||
|
; inc 1, x
|
||||||
|
; .1:
|
||||||
|
; lda (0, x)
|
||||||
|
; bra put
|
||||||
|
; push
|
||||||
|
|
||||||
|
; put:
|
||||||
|
; sta 1, x
|
||||||
|
; pla
|
||||||
|
; sta 0, x
|
||||||
|
; rts
|
||||||
|
|
||||||
|
plus: ; add: (n1 n2 -- n1+n2)
|
||||||
|
clc
|
||||||
|
lda 0, x
|
||||||
|
adc 2, x
|
||||||
|
sta 2, x
|
||||||
|
lda 1, x
|
||||||
|
adc 3, x
|
||||||
|
sta 3, x
|
||||||
|
pop
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
mult: ; multiply: (n1 n2 -- n1*n2), frankly, i don't know how this works, but TODO: will try to figure it out later
|
||||||
|
phy
|
||||||
|
stz n
|
||||||
|
ldy #0
|
||||||
|
.1:
|
||||||
|
lsr 3, x
|
||||||
|
ror 2, x
|
||||||
|
bcc .2
|
||||||
|
clc
|
||||||
|
lda n
|
||||||
|
adc 0, x
|
||||||
|
sta n
|
||||||
|
tya
|
||||||
|
adc 1, x
|
||||||
|
tay
|
||||||
|
.2:
|
||||||
|
asl 0, x
|
||||||
|
rol 1, x
|
||||||
|
lda 2, x
|
||||||
|
ora 3, x
|
||||||
|
bne .1
|
||||||
|
lda n
|
||||||
|
sta 2, x
|
||||||
|
sty 3, x
|
||||||
|
pop
|
||||||
|
ply
|
||||||
|
rts
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
; .setcpu "65C02"
|
||||||
|
.include "./macro.inc"
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
n = $01 ; temporary storage for data stack operations
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
ldx #0; initialize data stack pointer
|
||||||
|
|
||||||
|
initdisplay:
|
||||||
|
lda #0
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
cleardisplay:
|
||||||
|
sta $6000,y
|
||||||
|
sta $6100,y
|
||||||
|
sta $6200,y
|
||||||
|
sta $6300,y
|
||||||
|
sta $6400,y
|
||||||
|
sta $6500,y
|
||||||
|
sta $6600,y
|
||||||
|
sta $6700,y ; this goes slightly over but it's fine
|
||||||
|
iny
|
||||||
|
bne cleardisplay
|
||||||
|
cli
|
||||||
|
|
||||||
|
main:
|
||||||
|
jsr draw
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
draw:
|
||||||
|
push_coords #0, #0
|
||||||
|
push_char #$af
|
||||||
|
jsr draw_char
|
||||||
|
rts
|
||||||
|
|
||||||
|
draw_char: ; draw a character c at (x, y) (n1: x n2: y n3: c -- )
|
||||||
|
lda 0, x ; load a with character to draw
|
||||||
|
pop ; and pop it off the stack
|
||||||
|
jsr get_char_address ; calculate where to put the character in memory
|
||||||
|
sta (0, x) ; store a at the address pointed to on the stack
|
||||||
|
rts
|
||||||
|
|
||||||
|
get_char_address: ; gets vram address for a character at (x, y),
|
||||||
|
; (n1: x n2: y -- n: $6000 + x + (64 * y))
|
||||||
|
;jsr push_lit ; push 64 onto stack, low byte first
|
||||||
|
;.byte 64
|
||||||
|
;.byte 0
|
||||||
|
pha
|
||||||
|
lda #64
|
||||||
|
push ; doing this instead until `push_lit` is fixed
|
||||||
|
sta 0, x
|
||||||
|
stz 1, x
|
||||||
|
jsr mult ; multiply 64 with y (n2)
|
||||||
|
jsr plus ; add result with x (n1)
|
||||||
|
|
||||||
|
;jsr push_lit ; push vram address onto the stack
|
||||||
|
;.byte $00
|
||||||
|
;.byte $60
|
||||||
|
lda #$60
|
||||||
|
push
|
||||||
|
sta 1, x
|
||||||
|
stz 0, x
|
||||||
|
jsr plus ; add vram start address to result
|
||||||
|
|
||||||
|
pla
|
||||||
|
rts
|
||||||
|
|
||||||
|
fill: ; fills an area from (x1, y1) to (x2, y2) will character c, (n1: c n2: x1 n3: y1 n4: x2 n5: y2 -- )
|
||||||
|
jsr get_char_address
|
||||||
|
|
||||||
|
isr: ; interrupt service routine
|
||||||
|
pha
|
||||||
|
phx
|
||||||
|
phy
|
||||||
|
; jsr irq
|
||||||
|
ply
|
||||||
|
plx
|
||||||
|
pla
|
||||||
|
rti
|
||||||
|
|
||||||
|
.include "math.inc"
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
|
.word isr
|
||||||
Binary file not shown.
+173
@@ -0,0 +1,173 @@
|
|||||||
|
; .setcpu "65C02"
|
||||||
|
.include "./macro.inc"
|
||||||
|
|
||||||
|
; okay so rn i wanna set up a very basic system init, and write a few subroutines to draw characters at x,y coordinates
|
||||||
|
n = $01 ; temporary storage for data stack operations
|
||||||
|
|
||||||
|
key_row = $200 ; used for character lookup when key pressed
|
||||||
|
key_col = $201
|
||||||
|
cursor = $202
|
||||||
|
|
||||||
|
char_buffer = $300 ; 256 byte character buffer
|
||||||
|
|
||||||
|
kb_row = $4400 ; keyboard hardware register
|
||||||
|
kb_row_cache = $203 ; cache
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
ldx #0; initialize data stack pointer
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
initdisplay:
|
||||||
|
lda #20
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
cleardisplay:
|
||||||
|
sta $6000,y
|
||||||
|
sta $6100,y
|
||||||
|
sta $6200,y
|
||||||
|
sta $6300,y
|
||||||
|
sta $6400,y
|
||||||
|
sta $6500,y
|
||||||
|
sta $6600,y
|
||||||
|
sta $6700,y ; this goes slightly over but it's fine
|
||||||
|
iny
|
||||||
|
bne cleardisplay
|
||||||
|
cli
|
||||||
|
|
||||||
|
main:
|
||||||
|
; jsr keyboard
|
||||||
|
; key_zero:
|
||||||
|
; stz keyboard_cache, x
|
||||||
|
; dex
|
||||||
|
; bpl key_zero
|
||||||
|
; fim:
|
||||||
|
; cli
|
||||||
|
; bra fim
|
||||||
|
; jsr kitty_keys
|
||||||
|
lda #9
|
||||||
|
sta $6000
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
not_keyboard:
|
||||||
|
ldy #0
|
||||||
|
.check_row: ; loop through each row
|
||||||
|
lda kb_row, y
|
||||||
|
beq .skip_row ; if row has no key pressed, skip checking which key
|
||||||
|
sta kb_row_cache, y ; if key pressed, cache it
|
||||||
|
lda kb_row, y
|
||||||
|
cmp kb_row_cache, y ; has key changed?
|
||||||
|
beq key_down
|
||||||
|
.skip_row:
|
||||||
|
iny
|
||||||
|
cpy #5
|
||||||
|
bne .check_row
|
||||||
|
rts
|
||||||
|
|
||||||
|
key_down: ; a is loaded with the row byte
|
||||||
|
phy
|
||||||
|
sty key_row ; store character row
|
||||||
|
ldy #0
|
||||||
|
.find_col: ; test each row bit, store column if key pressed
|
||||||
|
lsr ; test bit 7
|
||||||
|
bcs store_col ; if unset, don't go store character columnb
|
||||||
|
.skip:
|
||||||
|
iny
|
||||||
|
cpy #8
|
||||||
|
bne .find_col ; loop until we've checked each bit
|
||||||
|
|
||||||
|
store_col:
|
||||||
|
sty key_col
|
||||||
|
|
||||||
|
keymap_index:
|
||||||
|
push
|
||||||
|
lda key_col
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
push
|
||||||
|
lda #8
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
push
|
||||||
|
lda key_row
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
jsr mult
|
||||||
|
jsr plus
|
||||||
|
lda 0, x
|
||||||
|
tay
|
||||||
|
|
||||||
|
print: ; we've stored the character position, now let's
|
||||||
|
lda keymap, y
|
||||||
|
ldy cursor
|
||||||
|
sta $6000, y
|
||||||
|
inc cursor
|
||||||
|
ply
|
||||||
|
rts
|
||||||
|
|
||||||
|
keymap:
|
||||||
|
.byte "?outrew?"
|
||||||
|
.byte "?piygsq?"
|
||||||
|
.byte "a??khvd?"
|
||||||
|
.byte "42ljbfz?"
|
||||||
|
.byte "31?mncx?"
|
||||||
|
.byte "????? m"
|
||||||
|
|
||||||
|
; draw:
|
||||||
|
; ; push_coords #0, #0
|
||||||
|
; ; push_char #$00
|
||||||
|
; ; jsr draw_char
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; draw_char: ; draw a character c at (x, y) (n1: x n2: y n3: c -- )
|
||||||
|
; lda 0, x ; load a with character to draw
|
||||||
|
; pop ; and pop it off the stack
|
||||||
|
; jsr get_char_address ; calculate where to put the character in memory
|
||||||
|
; sta (0, x) ; store a at the address pointed to on the stack
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; get_char_address: ; gets vram address for a character at (x, y),
|
||||||
|
; ; (n1: x n2: y -- n: $6000 + x + (64 * y))
|
||||||
|
; ;jsr push_lit ; push 64 onto stack, low byte first
|
||||||
|
; ;.byte 64
|
||||||
|
; ;.byte 0
|
||||||
|
; pha
|
||||||
|
; lda #64
|
||||||
|
; push ; doing this instead until `push_lit` is fixed
|
||||||
|
; sta 0, x
|
||||||
|
; stz 1, x
|
||||||
|
; jsr mult ; multiply 64 with y (n2)
|
||||||
|
; jsr plus ; add result with x (n1)
|
||||||
|
|
||||||
|
; ;jsr push_lit ; push vram address onto the stack
|
||||||
|
; ;.byte $00
|
||||||
|
; ;.byte $60
|
||||||
|
; lda #$60
|
||||||
|
; push
|
||||||
|
; sta 1, x
|
||||||
|
; stz 0, x
|
||||||
|
; jsr plus ; add vram start address to result
|
||||||
|
|
||||||
|
; pla
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; fill: ; fills an area from (x1, y1) to (x2, y2) will character c, (n1: c n2: x1 n3: y1 n4: x2 n5: y2 -- )
|
||||||
|
; jsr get_char_address
|
||||||
|
|
||||||
|
isr: ; interrupt service routine
|
||||||
|
pha
|
||||||
|
phx
|
||||||
|
phy
|
||||||
|
; jsr irq
|
||||||
|
ply
|
||||||
|
plx
|
||||||
|
pla
|
||||||
|
rti
|
||||||
|
|
||||||
|
.include "math.inc"
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
|
.word isr
|
||||||
Binary file not shown.
+187
@@ -0,0 +1,187 @@
|
|||||||
|
; .setcpu "65C02"
|
||||||
|
.include "./macro.inc"
|
||||||
|
|
||||||
|
; okay so rn i wanna set up a very basic system init, and write a few subroutines to draw characters at x,y coordinates
|
||||||
|
n = $01 ; temporary storage for data stack operations
|
||||||
|
|
||||||
|
key_row = $200 ; used for character lookup when key pressed
|
||||||
|
key_col = $201
|
||||||
|
cursor = $202
|
||||||
|
|
||||||
|
char_buffer = $300 ; 256 byte character buffer
|
||||||
|
|
||||||
|
kb_row = $4400 ; keyboard hardware register
|
||||||
|
kb_row_cache = $203 ; cache
|
||||||
|
|
||||||
|
.org $8000
|
||||||
|
|
||||||
|
reset:
|
||||||
|
sei
|
||||||
|
ldx #0; initialize data stack pointer
|
||||||
|
|
||||||
|
initdisplay:
|
||||||
|
lda #0
|
||||||
|
ldy #0
|
||||||
|
|
||||||
|
cleardisplay:
|
||||||
|
sta $6000,y
|
||||||
|
sta $6100,y
|
||||||
|
sta $6200,y
|
||||||
|
sta $6300,y
|
||||||
|
sta $6400,y
|
||||||
|
sta $6500,y
|
||||||
|
sta $6600,y
|
||||||
|
sta $6700,y ; this goes slightly over but it's fine
|
||||||
|
iny
|
||||||
|
bne cleardisplay
|
||||||
|
cli
|
||||||
|
|
||||||
|
print_test:
|
||||||
|
lda #0
|
||||||
|
sta key_row
|
||||||
|
lda #5
|
||||||
|
sta key_col
|
||||||
|
push_coords #5, #5
|
||||||
|
|
||||||
|
main:
|
||||||
|
; jsr printtext
|
||||||
|
; key_zero:
|
||||||
|
; stz keyboard_cache, x
|
||||||
|
; dex
|
||||||
|
; bpl key_zero
|
||||||
|
; fim:
|
||||||
|
; cli
|
||||||
|
; bra fim
|
||||||
|
jsr print
|
||||||
|
; jsr print
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
|
||||||
|
; keyboard: ; reads keyboard registers and stores the column and row of the first key found
|
||||||
|
; ; TODO: make this routine store up to 8 indices (for 8 key rollover)
|
||||||
|
; ldy #0
|
||||||
|
; .check_row: ; loop through each row
|
||||||
|
; lda kb_row, y
|
||||||
|
; beq .skip_row ; if row has no key pressed, skip checking which key
|
||||||
|
; ; jmp key_down
|
||||||
|
; sta kb_row_cache, y ; if key pressed, cache it
|
||||||
|
; lda kb_row, y
|
||||||
|
; cmp kb_row_cache, y ; has key changed?
|
||||||
|
; beq key_down
|
||||||
|
; .skip_row:
|
||||||
|
; iny
|
||||||
|
; cpy #5
|
||||||
|
; bne .check_row
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; key_down: ; a is loaded with the row byte
|
||||||
|
; phy
|
||||||
|
; sty key_row ; store character row
|
||||||
|
; ldy #0
|
||||||
|
; .find_col: ; test each row bit, store column if key pressed
|
||||||
|
; lsr ; test bit 7
|
||||||
|
; bcs store_col ; if unset, don't go store character columnb
|
||||||
|
; .skip:
|
||||||
|
; iny
|
||||||
|
; cpy #8
|
||||||
|
; bne .find_col ; loop until we've checked each bit
|
||||||
|
; rts
|
||||||
|
|
||||||
|
; store_col:
|
||||||
|
; sty key_col
|
||||||
|
; jsr print
|
||||||
|
; rts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
print: ; x y -- prints the key indexed with key_col and key_row at position x, y
|
||||||
|
|
||||||
|
keymap_index:
|
||||||
|
push
|
||||||
|
lda key_col
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
push
|
||||||
|
lda #8
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
push
|
||||||
|
lda key_row
|
||||||
|
stz 1, x
|
||||||
|
sta 0, x
|
||||||
|
jsr mult
|
||||||
|
jsr plus
|
||||||
|
lda 0, x
|
||||||
|
tay
|
||||||
|
lda keymap, y
|
||||||
|
push
|
||||||
|
sta 0, x
|
||||||
|
stz 1, x
|
||||||
|
jsr draw_char
|
||||||
|
rts
|
||||||
|
|
||||||
|
keymap:
|
||||||
|
.byte "?outrew?"
|
||||||
|
.byte "?piygsq?"
|
||||||
|
.byte "a??khvd?"
|
||||||
|
.byte "42ljbfz?"
|
||||||
|
.byte "31?mncx?"
|
||||||
|
.byte "????? m"
|
||||||
|
|
||||||
|
draw:
|
||||||
|
; push_coords #0, #0
|
||||||
|
; push_char #$00
|
||||||
|
; jsr draw_char
|
||||||
|
rts
|
||||||
|
|
||||||
|
draw_char: ; draw a character c at (x, y) (n1: x n2: y n3: c -- )
|
||||||
|
lda 0, x ; load a with character to draw
|
||||||
|
pop ; and pop it off the stack
|
||||||
|
jsr get_char_address ; calculate where to put the character in memory
|
||||||
|
sta (0, x) ; store a at the address pointed to on the stack
|
||||||
|
rts
|
||||||
|
|
||||||
|
get_char_address: ; gets vram address for a character at (x, y),
|
||||||
|
; (n1: x n2: y -- n: $6000 + x + (64 * y))
|
||||||
|
;jsr push_lit ; push 64 onto stack, low byte first
|
||||||
|
;.byte 64
|
||||||
|
;.byte 0
|
||||||
|
pha
|
||||||
|
lda #64
|
||||||
|
push ; doing this instead until `push_lit` is fixed
|
||||||
|
sta 0, x
|
||||||
|
stz 1, x
|
||||||
|
jsr mult ; multiply 64 with y (n2)
|
||||||
|
jsr plus ; add result with x (n1)
|
||||||
|
|
||||||
|
;jsr push_lit ; push vram address onto the stack
|
||||||
|
;.byte $00
|
||||||
|
;.byte $60
|
||||||
|
lda #$60
|
||||||
|
push
|
||||||
|
sta 1, x
|
||||||
|
stz 0, x
|
||||||
|
jsr plus ; add vram start address to result
|
||||||
|
|
||||||
|
pla
|
||||||
|
rts
|
||||||
|
|
||||||
|
fill: ; fills an area from (x1, y1) to (x2, y2) will character c, (n1: c n2: x1 n3: y1 n4: x2 n5: y2 -- )
|
||||||
|
jsr get_char_address
|
||||||
|
|
||||||
|
isr: ; interrupt service routine
|
||||||
|
pha
|
||||||
|
phx
|
||||||
|
phy
|
||||||
|
; jsr keyboard
|
||||||
|
ply
|
||||||
|
plx
|
||||||
|
pla
|
||||||
|
rti
|
||||||
|
|
||||||
|
.include "math.inc"
|
||||||
|
|
||||||
|
.org $fffc
|
||||||
|
.word reset
|
||||||
|
.word isr
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "Provide the name of the rom/asm file to run"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
vasm6502_oldstyle roms/$1.asm -dotdir -wdc02 -ldots -Fbin -o roms/$1.rom;
|
||||||
|
cargo run -- rom "roms/$1.rom";
|
||||||
|
# hexdump -C ./cpu_dump.bin;
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
fs::File,
|
||||||
|
io::{ErrorKind, Read},
|
||||||
|
process::exit,
|
||||||
|
};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Default, Debug)]
|
||||||
|
pub enum ScreenType {
|
||||||
|
Terminal,
|
||||||
|
#[default]
|
||||||
|
Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Config {
|
||||||
|
pub rom: Option<String>,
|
||||||
|
pub screen: ScreenType,
|
||||||
|
pub char_rom: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
struct ConfigBuilder {
|
||||||
|
rom: Option<String>,
|
||||||
|
char_rom: Option<String>,
|
||||||
|
screen: ScreenType,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigBuilder {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
rom: None,
|
||||||
|
char_rom: None,
|
||||||
|
screen: ScreenType::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build(self) -> Config {
|
||||||
|
let rom = match self.rom {
|
||||||
|
Some(rom) => Some(rom),
|
||||||
|
None => {
|
||||||
|
println!("no rom was provided :(");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let char_rom = self.char_rom;
|
||||||
|
let screen = self.screen;
|
||||||
|
|
||||||
|
Config {
|
||||||
|
rom,
|
||||||
|
screen,
|
||||||
|
char_rom,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn help(command: Option<String>) {
|
||||||
|
let executable: String = env::args().next().unwrap();
|
||||||
|
if let Some(command) = command {
|
||||||
|
match &command as &str {
|
||||||
|
"rom" | "--rom" | "-r" => {
|
||||||
|
println!("{executable} {command} <path>\n\nload a rom/binary from path");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
"screen" | "--screen" | "-s" => {
|
||||||
|
println!("{executable} {command} <path>\n\nload a rom/binary from path");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
"help" | "--help" | "-h" => {
|
||||||
|
println!("{executable} {command} <command>\n\nshow help info for a given command");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!(
|
||||||
|
"{command:?} isn't a valid command!\n\nuse `{executable} help` to see all valid commands",
|
||||||
|
);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("ʕ·ᴥ·ʔ- {executable} is an emulator for george:");
|
||||||
|
println!("https://git.augustkline.com/august/george\n");
|
||||||
|
println!("commands:");
|
||||||
|
println!(" help, -h, --help <command>: print help info for any command");
|
||||||
|
println!(" rom, -r, --rom <path>: load a rom/binary from path");
|
||||||
|
println!(" screen, -s, --screen <type>: use the \"terminal\" or \"window\" display type");
|
||||||
|
println!("\nconfiguration:");
|
||||||
|
println!(" george-emu searches for a `george.toml` in the current directory.\n in `george.toml` you can specify a path for the character rom\n using the key `char_rom` and the main rom/binary with the key `rom`");
|
||||||
|
println!("\ndebugging:");
|
||||||
|
println!(" you can pipe in a rom for george to evaluate.");
|
||||||
|
println!(" she'll read it until she reaches a breakpoint (`0x02`) or `stp` instruction,");
|
||||||
|
println!(" then will dump her memory to stdout <3");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_input() -> Config {
|
||||||
|
let executable: String = env::args().next().unwrap();
|
||||||
|
let mut config = ConfigBuilder::new();
|
||||||
|
|
||||||
|
let len = env::args().len();
|
||||||
|
|
||||||
|
if len == 1 {
|
||||||
|
config = match File::open("./george.toml") {
|
||||||
|
Ok(mut file) => {
|
||||||
|
let mut string = String::new();
|
||||||
|
file.read_to_string(&mut string).unwrap();
|
||||||
|
toml::from_str(string.as_str()).unwrap()
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
println!("couldn't find a `george.toml` in the current directory!");
|
||||||
|
println!("\nuse `{executable} --help` to see all config options");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return config.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut args = env::args().skip(1);
|
||||||
|
|
||||||
|
while let Some(arg) = args.next() {
|
||||||
|
match &arg[..] {
|
||||||
|
"--help" | "-h" | "help" => help(args.next()),
|
||||||
|
"--rom" | "-r" | "rom" => {
|
||||||
|
if let Some(path) = args.next() {
|
||||||
|
match std::fs::File::open(&path) {
|
||||||
|
Ok(_) => {
|
||||||
|
config.rom = Some(path);
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
match error.kind() {
|
||||||
|
ErrorKind::NotFound => {
|
||||||
|
println!("couldn't find the rom at {path:?}");
|
||||||
|
}
|
||||||
|
ErrorKind::PermissionDenied => {
|
||||||
|
println!(
|
||||||
|
"didn't have sufficient permissions to open the rom at {path:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("something went wrong! try again in a moment? really not sure why you're getting this error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
println!("no rom specified!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"--screen" | "-s" | "screen" => {
|
||||||
|
let kind = args.next();
|
||||||
|
match kind {
|
||||||
|
Some(kind) => match &kind as &str {
|
||||||
|
"terminal" | "Terminal" | "TERMINAL" | "t" | "term" => {}
|
||||||
|
"window" | "Window" | "WINDOW" | "w" | "win" => {
|
||||||
|
config.screen = ScreenType::Window
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("{kind:?} isn't a valid screen type!\n\nuse \"{executable} --help screen\" to see all valid screen types");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
println!("no screen type was provided!\n\nuse \"{executable} --help screen\" to see all valid screen types");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("{arg:?} isn't a valid command!\n\nuse \"{executable} help\" to see all valid commands");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.build()
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
use std::io::{self, stdin, IsTerminal};
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
mod cli;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use cli::get_input;
|
||||||
|
use georgeemu::memory::{Mem, MemHandle};
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use georgeemu::GeorgeEmu;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use minifb::{Scale, ScaleMode, Window, WindowOptions};
|
||||||
|
|
||||||
|
use std::{fs::File, io::Read};
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
use std::io::{stdout, Write};
|
||||||
|
|
||||||
|
use georgeemu::cpu::Cpu;
|
||||||
|
|
||||||
|
let mut input = stdin();
|
||||||
|
|
||||||
|
if !input.is_terminal() {
|
||||||
|
let mut bytes = [0u8; 0x8000];
|
||||||
|
input.read_exact(&mut bytes).unwrap();
|
||||||
|
let memory = make_memory(&bytes);
|
||||||
|
let mut cpu = Cpu::new(memory);
|
||||||
|
let final_output = cpu.run_to_end();
|
||||||
|
|
||||||
|
let _ = stdout().write_all(&final_output);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
let window = Window::new(
|
||||||
|
"ʕ·ᴥ·ʔ-☆",
|
||||||
|
512,
|
||||||
|
380,
|
||||||
|
WindowOptions {
|
||||||
|
resize: true,
|
||||||
|
borderless: true,
|
||||||
|
title: true,
|
||||||
|
transparency: false,
|
||||||
|
scale: Scale::FitScreen,
|
||||||
|
scale_mode: ScaleMode::AspectRatioStretch,
|
||||||
|
topmost: false,
|
||||||
|
none: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let config = get_input();
|
||||||
|
let rom = match config.rom {
|
||||||
|
Some(path) => {
|
||||||
|
let mut file = File::open(path).unwrap();
|
||||||
|
let mut bin = vec![0; 0x8000];
|
||||||
|
file.read_exact(&mut bin).unwrap();
|
||||||
|
bin.try_into().unwrap()
|
||||||
|
}
|
||||||
|
None => *include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/roms/george.rom")),
|
||||||
|
};
|
||||||
|
let mut emu = GeorgeEmu::builder().rom(rom).window(window).build();
|
||||||
|
|
||||||
|
emu.run();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
fn make_memory(bytes: &[u8]) -> MemHandle {
|
||||||
|
let mut memory = Mem::new();
|
||||||
|
memory.load_bytes(bytes);
|
||||||
|
MemHandle::new(memory)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
fn main() {}
|
||||||
+296
@@ -0,0 +1,296 @@
|
|||||||
|
use crate::instructions::get_instruction;
|
||||||
|
use crate::memory::{MemHandle, MemoryReader, MemoryWriter};
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use std::thread::sleep;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum StatusFlag {
|
||||||
|
Negative = 0b1000_0000,
|
||||||
|
Overflow = 0b0100_0000,
|
||||||
|
Brk = 0b0011_0000,
|
||||||
|
//BrkIrq = 0b0010_0000,
|
||||||
|
Decimal = 0b0000_1000,
|
||||||
|
IrqDisable = 0b0000_0100,
|
||||||
|
Zero = 0b000_0010,
|
||||||
|
Carry = 0b0000_0001,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct CpuController(Sender<CpuControl>);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum CpuControl {
|
||||||
|
Irq,
|
||||||
|
Nmi,
|
||||||
|
Toggle,
|
||||||
|
Data,
|
||||||
|
Cycle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CpuController {
|
||||||
|
pub fn new(sender: Sender<CpuControl>) -> Self {
|
||||||
|
Self(sender)
|
||||||
|
}
|
||||||
|
pub fn irq(&self) {
|
||||||
|
let _ = self.0.send(CpuControl::Irq);
|
||||||
|
}
|
||||||
|
pub fn nmi(&self) {
|
||||||
|
let _ = self.0.send(CpuControl::Nmi);
|
||||||
|
}
|
||||||
|
pub fn toggle(&self) {
|
||||||
|
let _ = self.0.send(CpuControl::Toggle);
|
||||||
|
}
|
||||||
|
pub fn cycle(&self) {
|
||||||
|
let _ = self.0.send(CpuControl::Cycle);
|
||||||
|
}
|
||||||
|
pub fn data(&self) {
|
||||||
|
let _ = self.0.send(CpuControl::Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CpuReceiver(Receiver<CpuControl>);
|
||||||
|
impl CpuReceiver {
|
||||||
|
pub fn new(receiver: Receiver<CpuControl>) -> Self {
|
||||||
|
Self(receiver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Cpu {
|
||||||
|
pub a: u8, // Accumulator Register
|
||||||
|
pub x: u8, // X Register
|
||||||
|
pub y: u8, // Y Register
|
||||||
|
pub pc: u16, // Program Counter
|
||||||
|
pub s: u8, // Stack Pointer
|
||||||
|
pub p: u8, // Status Register
|
||||||
|
pub irq: bool,
|
||||||
|
pub nmi: bool,
|
||||||
|
pub memory: MemHandle,
|
||||||
|
pub pending_cycles: usize,
|
||||||
|
pub debug: bool,
|
||||||
|
receiver: Option<CpuReceiver>,
|
||||||
|
stopped: bool,
|
||||||
|
cycle: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Cpu {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{},{}", self.a, self.x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryReader for Cpu {
|
||||||
|
fn read(&self, address: u16) -> u8 {
|
||||||
|
self.memory.read(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl MemoryWriter for Cpu {
|
||||||
|
fn write(&self, address: u16, data: u8) {
|
||||||
|
self.memory.write(address, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cpu {
|
||||||
|
pub fn new(memory: MemHandle) -> Self {
|
||||||
|
// reset the cpu on initialization so we don't
|
||||||
|
// scream and cry for two days trying to figure
|
||||||
|
// out why george isn't working <3
|
||||||
|
let low_byte = memory.read(0xFFFC);
|
||||||
|
let high_byte = memory.read(0xFFFD);
|
||||||
|
let pc = (high_byte as u16) << 8 | (low_byte as u16);
|
||||||
|
|
||||||
|
Cpu {
|
||||||
|
a: 0x00,
|
||||||
|
x: 0x00,
|
||||||
|
y: 0x00,
|
||||||
|
pc,
|
||||||
|
s: 0xFF,
|
||||||
|
p: 0b0010_0100,
|
||||||
|
irq: false,
|
||||||
|
nmi: false,
|
||||||
|
receiver: None,
|
||||||
|
memory,
|
||||||
|
debug: false,
|
||||||
|
stopped: false,
|
||||||
|
pending_cycles: 0,
|
||||||
|
cycle: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn with_receiver(mut self, receiver: CpuReceiver) -> Self {
|
||||||
|
self.receiver = Some(receiver);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn new_with_control(memory: MemHandle) -> (Self, CpuController) {
|
||||||
|
let (tx, rx) = channel::<CpuControl>();
|
||||||
|
let controller = CpuController(tx);
|
||||||
|
let receiver = CpuReceiver(rx);
|
||||||
|
let cpu = Cpu::new(memory).with_receiver(receiver);
|
||||||
|
(cpu, controller)
|
||||||
|
}
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
let reset_vector_pointer = self.read_word(0xFFFC);
|
||||||
|
self.pc = reset_vector_pointer;
|
||||||
|
self.a = 0;
|
||||||
|
self.pending_cycles = 0;
|
||||||
|
}
|
||||||
|
pub fn read_word(&self, address: u16) -> u16 {
|
||||||
|
let low_byte = self.read(address);
|
||||||
|
let high_byte = self.read(address.wrapping_add(0x1));
|
||||||
|
(high_byte as u16) << 8 | (low_byte as u16)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stack_addr(&self) -> u16 {
|
||||||
|
// Dunno if this is necessary, i just don't like adding the 0x0100 every time
|
||||||
|
0x0100 + self.s as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_stack(&mut self, data: u8) {
|
||||||
|
self.s = self.s.wrapping_sub(0x1);
|
||||||
|
self.write(self.stack_addr(), data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_stack_word(&mut self, address: u16) {
|
||||||
|
self.s = self.s.wrapping_sub(0x1);
|
||||||
|
self.write(self.stack_addr(), address.to_le_bytes()[1]); // Upper byte first
|
||||||
|
self.s = self.s.wrapping_sub(0x1);
|
||||||
|
self.write(self.stack_addr(), address.to_le_bytes()[0]); // Lower byte second
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_stack(&mut self) -> u8 {
|
||||||
|
let byte = self.read(self.stack_addr());
|
||||||
|
self.s = self.s.wrapping_add(0x1);
|
||||||
|
byte
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop_stack_word(&mut self) -> u16 {
|
||||||
|
let low_byte = self.pop_stack();
|
||||||
|
let high_byte = self.pop_stack();
|
||||||
|
((high_byte as u16) << 8) + low_byte as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_flag(&mut self, flag: StatusFlag, value: bool) {
|
||||||
|
self.p &= !(flag as u8);
|
||||||
|
if value {
|
||||||
|
self.p |= flag as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_flag(&self, flag: StatusFlag) -> bool {
|
||||||
|
(self.p & flag as u8) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_negative(&self, value: u8) -> bool {
|
||||||
|
value & 0b1000_0000 == 0b1000_0000
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait_for_interrupt(&self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt(&mut self) {
|
||||||
|
self.irq = false;
|
||||||
|
self.push_stack_word(self.pc);
|
||||||
|
self.push_stack(self.p);
|
||||||
|
self.set_flag(StatusFlag::IrqDisable, true);
|
||||||
|
self.pc = self.read_word(0xFFFE);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_stopped(&mut self) {
|
||||||
|
self.stopped = !self.stopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive_control(&mut self) {
|
||||||
|
match &self.receiver {
|
||||||
|
Some(receiver) => {
|
||||||
|
let control = match receiver.0.try_recv() {
|
||||||
|
Ok(control) => control,
|
||||||
|
Err(_error) => return, // most of the time we won't have any impending control
|
||||||
|
// messages, just return if that's the case
|
||||||
|
};
|
||||||
|
match control {
|
||||||
|
CpuControl::Nmi => self.nmi = true,
|
||||||
|
CpuControl::Irq => self.irq = true,
|
||||||
|
CpuControl::Toggle => {
|
||||||
|
self.stopped = !self.stopped;
|
||||||
|
}
|
||||||
|
CpuControl::Cycle => self.cycle = true,
|
||||||
|
CpuControl::Data => {
|
||||||
|
// self
|
||||||
|
// .state_tx
|
||||||
|
// .send(CpuState {
|
||||||
|
// a: self.a.clone(), // Accumulator Register
|
||||||
|
// x: self.x.clone(), // X Register
|
||||||
|
// y: self.y.clone(), // Y Register
|
||||||
|
// pc: self.pc.clone(), // Program Counter
|
||||||
|
// s: self.s.clone(), // Stack Pointer
|
||||||
|
// p: self.p.clone(), // Status Register
|
||||||
|
// irq: self.irq.clone(),
|
||||||
|
// nmi: self.nmi.clone(),
|
||||||
|
// })
|
||||||
|
// .unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cycle(&mut self) {
|
||||||
|
self.receive_control();
|
||||||
|
|
||||||
|
if self.stopped & !self.cycle {
|
||||||
|
self.set_flag(StatusFlag::IrqDisable, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.cycle = false;
|
||||||
|
|
||||||
|
// can't sleep in wasm
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
while self.pending_cycles != 0 {
|
||||||
|
// roughly cycle-accurate timing
|
||||||
|
sleep(Duration::from_nanos(500));
|
||||||
|
self.pending_cycles -= 1;
|
||||||
|
}
|
||||||
|
if !self.get_flag(StatusFlag::IrqDisable) && self.irq {
|
||||||
|
self.interrupt();
|
||||||
|
}
|
||||||
|
let opcode = self.read(self.pc);
|
||||||
|
let instruction = get_instruction(opcode);
|
||||||
|
instruction.call(self);
|
||||||
|
}
|
||||||
|
pub fn stop(&mut self) {
|
||||||
|
self.stopped = true;
|
||||||
|
}
|
||||||
|
pub fn breakpoint(&mut self) {
|
||||||
|
if self.debug {
|
||||||
|
self.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quick_cycle(&mut self) {
|
||||||
|
if !self.get_flag(StatusFlag::IrqDisable) && self.irq {
|
||||||
|
self.interrupt();
|
||||||
|
}
|
||||||
|
let opcode = self.read(self.pc);
|
||||||
|
let instruction = get_instruction(opcode);
|
||||||
|
instruction.call(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_to_end(&mut self) -> [u8; 0x10000] {
|
||||||
|
self.quick_cycle();
|
||||||
|
while self.pending_cycles != 0 {
|
||||||
|
let opcode = self.read(self.pc);
|
||||||
|
let instruction = get_instruction(opcode);
|
||||||
|
match instruction.name {
|
||||||
|
"stp" | "breakpoint" => return self.memory.dump(),
|
||||||
|
_ => self.quick_cycle(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
.setcpu "65C02"
|
|
||||||
.segment "CODE"
|
|
||||||
main:
|
|
||||||
LDA #$25
|
|
||||||
LDY #$FF
|
|
||||||
STY $7000
|
|
||||||
STY $7001
|
|
||||||
STY $7002
|
|
||||||
JMP main
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
MEMORY {
|
|
||||||
RAM: start = $0000, size = $4000, type = rw, fill = true;
|
|
||||||
CTRL: start = $4000, size = $2000, type = rw, fill = true;
|
|
||||||
VRAM: start = $6000, size = $8000, type = rw, fill = true;
|
|
||||||
ROM: start = $E000, size = $2000, type = ro, fill = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SEGMENTS {
|
|
||||||
CODE: load = "RAM", type = rw;
|
|
||||||
}
|
|
||||||
+2805
File diff suppressed because it is too large
Load Diff
+256
@@ -0,0 +1,256 @@
|
|||||||
|
use minifb::InputCallback;
|
||||||
|
use minifb::Key as MKey;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use termion::event::Key;
|
||||||
|
|
||||||
|
use crate::memory::{MemHandle, MemoryWriter};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Keyboard {
|
||||||
|
memory: MemHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Keyboard {
|
||||||
|
pub fn new(memory: MemHandle) -> Self {
|
||||||
|
Self { memory }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub fn clear_keys(&self) {
|
||||||
|
self.memory.write(0x4400, 0x00);
|
||||||
|
self.memory.write(0x4401, 0x00);
|
||||||
|
self.memory.write(0x4402, 0x00);
|
||||||
|
self.memory.write(0x4403, 0x00);
|
||||||
|
self.memory.write(0x4404, 0x00);
|
||||||
|
self.memory.write(0x4405, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub fn read_keys(&self, key: Key) {
|
||||||
|
let mut row0 = 0;
|
||||||
|
let mut row1 = 0;
|
||||||
|
let mut row2 = 0;
|
||||||
|
let mut row3 = 0;
|
||||||
|
let mut row4 = 0;
|
||||||
|
let mut row5 = 0;
|
||||||
|
|
||||||
|
// these are just so the match statements are easier to read lol
|
||||||
|
macro_rules! set_shift {
|
||||||
|
($char:expr) => {
|
||||||
|
match $char {
|
||||||
|
'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M'
|
||||||
|
| 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y'
|
||||||
|
| 'Z' | '!' | '@' | '#' | '$' | '%' | '^' | '&' | '*' | '(' | ')' | '~'
|
||||||
|
| '_' | '+' | '|' | '}' | '{' | '"' | ':' | '?' | '>' | '<' => {
|
||||||
|
row2 ^= 0b1000_0000
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! set_plain {
|
||||||
|
($char:expr) => {
|
||||||
|
match $char {
|
||||||
|
'w' | 'W' => row0 ^= 0b0100_0000,
|
||||||
|
'e' | 'E' => row0 ^= 0b0010_0000,
|
||||||
|
'r' | 'R' => row0 ^= 0b0001_0000,
|
||||||
|
't' | 'T' => row0 ^= 0b0000_1000,
|
||||||
|
'u' | 'U' => row0 ^= 0b0000_0100,
|
||||||
|
'o' | 'O' => row0 ^= 0b0000_0010,
|
||||||
|
'q' | 'Q' => row1 ^= 0b0100_0000,
|
||||||
|
's' | 'S' => row1 ^= 0b0010_0000,
|
||||||
|
'g' | 'G' => row1 ^= 0b0001_0000,
|
||||||
|
'y' | 'Y' => row1 ^= 0b0000_1000,
|
||||||
|
'i' | 'I' => row1 ^= 0b0000_0100,
|
||||||
|
'p' | 'P' => row1 ^= 0b0000_0010,
|
||||||
|
'd' | 'D' => row2 ^= 0b0100_0000,
|
||||||
|
'v' | 'V' => row2 ^= 0b0010_0000,
|
||||||
|
'h' | 'H' => row2 ^= 0b0001_0000,
|
||||||
|
'k' | 'K' => row2 ^= 0b0000_1000,
|
||||||
|
'\\' | '|' => row2 ^= 0b0000_0100,
|
||||||
|
'/' | '?' => row2 ^= 0b0000_0010,
|
||||||
|
'a' | 'A' => row2 ^= 0b0000_0001,
|
||||||
|
'z' | 'Z' => row3 ^= 0b0100_0000,
|
||||||
|
'f' | 'F' => row3 ^= 0b0010_0000,
|
||||||
|
'b' | 'B' => row3 ^= 0b0001_0000,
|
||||||
|
'j' | 'J' => row3 ^= 0b0000_1000,
|
||||||
|
'l' | 'L' => row3 ^= 0b0000_0100,
|
||||||
|
'2' | '@' => row3 ^= 0b0000_0010,
|
||||||
|
'4' | '$' => row3 ^= 0b0000_0001,
|
||||||
|
'x' | 'X' => row4 ^= 0b0100_0000,
|
||||||
|
'c' | 'C' => row4 ^= 0b0010_0000,
|
||||||
|
'n' | 'N' => row4 ^= 0b0001_0000,
|
||||||
|
'm' | 'M' => row4 ^= 0b0000_1000,
|
||||||
|
',' | '<' => row4 ^= 0b0000_0100,
|
||||||
|
'1' | '!' => row4 ^= 0b0000_0010,
|
||||||
|
'3' | '#' => row4 ^= 0b0000_0001,
|
||||||
|
' ' => row5 ^= 0b0100_0000,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
match key {
|
||||||
|
Key::Esc => row0 ^= 0b1000_0000,
|
||||||
|
Key::Backspace => row0 ^= 0b0000_0001,
|
||||||
|
Key::Char('\t') => row1 ^= 0b1000_0000,
|
||||||
|
Key::Char('\n') | Key::Char('\r') => row1 ^= 0b0000_0001,
|
||||||
|
Key::Char(char) => {
|
||||||
|
set_shift!(char);
|
||||||
|
set_plain!(char);
|
||||||
|
}
|
||||||
|
Key::ShiftLeft | Key::ShiftUp | Key::ShiftDown | Key::ShiftRight => row2 ^= 0b1000_0000,
|
||||||
|
Key::Ctrl(char) => {
|
||||||
|
set_shift!(char);
|
||||||
|
set_plain!(char);
|
||||||
|
row3 ^= 0b1000_0000;
|
||||||
|
}
|
||||||
|
Key::CtrlUp | Key::CtrlLeft | Key::CtrlDown | Key::CtrlRight => {
|
||||||
|
row3 ^= 0b1000_0000;
|
||||||
|
}
|
||||||
|
Key::Alt(char) => {
|
||||||
|
set_plain!(char);
|
||||||
|
set_shift!(char);
|
||||||
|
row4 ^= 0b1000_0000;
|
||||||
|
}
|
||||||
|
Key::AltUp | Key::AltLeft | Key::AltDown | Key::AltRight => {
|
||||||
|
row4 ^= 0b1000_0000;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.memory.write(0x4400, row0);
|
||||||
|
self.memory.write(0x4401, row1);
|
||||||
|
self.memory.write(0x4402, row2);
|
||||||
|
self.memory.write(0x4403, row3);
|
||||||
|
self.memory.write(0x4404, row4);
|
||||||
|
self.memory.write(0x4405, row5);
|
||||||
|
|
||||||
|
// keeping this list around to make future changes easier
|
||||||
|
// match key.code {
|
||||||
|
// KeyCode::Esc => row0 ^= 0b1000_0000,
|
||||||
|
// KeyCode::Char('w') => row0 ^= 0b0100_0000,
|
||||||
|
// KeyCode::Char('e') => row0 ^= 0b0010_0000,
|
||||||
|
// KeyCode::Char('r') => row0 ^= 0b0001_0000,
|
||||||
|
// KeyCode::Char('t') => row0 ^= 0b0000_1000,
|
||||||
|
// KeyCode::Char('u') => row0 ^= 0b0000_0100,
|
||||||
|
// KeyCode::Char('o') => row0 ^= 0b0000_0010,
|
||||||
|
// KeyCode::Backspace => row0 ^= 0b0000_0001,
|
||||||
|
// KeyCode::Tab => row1 ^= 0b1000_0000,
|
||||||
|
// KeyCode::Char('q') => row1 ^= 0b0100_0000,
|
||||||
|
// KeyCode::Char('s') => row1 ^= 0b0010_0000,
|
||||||
|
// KeyCode::Char('g') => row1 ^= 0b0001_0000,
|
||||||
|
// KeyCode::Char('y') => row1 ^= 0b0000_1000,
|
||||||
|
// KeyCode::Char('i') => row1 ^= 0b0000_0100,
|
||||||
|
// KeyCode::Char('p') => row1 ^= 0b0000_0010,
|
||||||
|
// KeyCode::Enter => row1 ^= 0b0000_0001,
|
||||||
|
// KeyCode::Char('d') => row2 ^= 0b0100_0000,
|
||||||
|
// KeyCode::Char('v') => row2 ^= 0b0010_0000,
|
||||||
|
// KeyCode::Char('h') => row2 ^= 0b0001_0000,
|
||||||
|
// KeyCode::Char('k') => row2 ^= 0b0000_1000,
|
||||||
|
// KeyCode::Char('\'') => row2 ^= 0b0000_0100,
|
||||||
|
// KeyCode::Char('/') => row2 ^= 0b0000_0010,
|
||||||
|
// KeyCode::Char('a') => row2 ^= 0b0000_0001,
|
||||||
|
// KeyCode::Char('z') => row3 ^= 0b0100_0000,
|
||||||
|
// KeyCode::Char('f') => row3 ^= 0b0010_0000,
|
||||||
|
// KeyCode::Char('b') => row3 ^= 0b0001_0000,
|
||||||
|
// KeyCode::Char('j') => row3 ^= 0b0000_1000,
|
||||||
|
// KeyCode::Char('l') => row3 ^= 0b0000_0100,
|
||||||
|
// KeyCode::Char('2') => row3 ^= 0b0000_0010,
|
||||||
|
// KeyCode::Char('4') => row3 ^= 0b0000_0001,
|
||||||
|
// KeyCode::Char('x') => row4 ^= 0b0100_0000,
|
||||||
|
// KeyCode::Char('c') => row4 ^= 0b0010_0000,
|
||||||
|
// KeyCode::Char('n') => row4 ^= 0b0001_0000,
|
||||||
|
// KeyCode::Char('m') => row4 ^= 0b0000_1000,
|
||||||
|
// KeyCode::Char(',') => row4 ^= 0b0000_0100,
|
||||||
|
// KeyCode::Char('1') => row4 ^= 0b0000_0010,
|
||||||
|
// KeyCode::Char('3') => row4 ^= 0b0000_0001,
|
||||||
|
// KeyCode::Char(' ') => row5 ^= 0b0100_0000,
|
||||||
|
// _ => {
|
||||||
|
// row0 = 0;
|
||||||
|
// row1 = 0;
|
||||||
|
// row2 = 0;
|
||||||
|
// row3 = 0;
|
||||||
|
// row4 = 0;
|
||||||
|
// row5 = 0;
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryWriter for Keyboard {
|
||||||
|
fn write(&self, address: u16, data: u8) {
|
||||||
|
if data != 0x00 {
|
||||||
|
// println!("wrote {:02x} to address {:04x}", data, address);
|
||||||
|
}
|
||||||
|
self.memory.write(address, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InputCallback for Keyboard {
|
||||||
|
fn add_char(&mut self, _uni_char: u32) {}
|
||||||
|
fn set_key_state(&mut self, key: MKey, _state: bool) {
|
||||||
|
let mut row0 = 0;
|
||||||
|
let mut row1 = 0;
|
||||||
|
let mut row2 = 0;
|
||||||
|
let mut row3 = 0;
|
||||||
|
let mut row4 = 0;
|
||||||
|
let mut row5 = 0;
|
||||||
|
|
||||||
|
match key {
|
||||||
|
MKey::Escape => row0 ^= 0b1000_0000,
|
||||||
|
MKey::W => row0 ^= 0b0100_0000,
|
||||||
|
MKey::E => row0 ^= 0b0010_0000,
|
||||||
|
MKey::R => row0 ^= 0b0001_0000,
|
||||||
|
MKey::T => row0 ^= 0b0000_1000,
|
||||||
|
MKey::U => row0 ^= 0b0000_0100,
|
||||||
|
MKey::O => row0 ^= 0b0000_0010,
|
||||||
|
MKey::Backspace => row0 ^= 0b0000_0001,
|
||||||
|
MKey::Tab => row1 ^= 0b1000_0000,
|
||||||
|
MKey::Q => row1 ^= 0b0100_0000,
|
||||||
|
MKey::S => row1 ^= 0b0010_0000,
|
||||||
|
MKey::G => row1 ^= 0b0001_0000,
|
||||||
|
MKey::Y => row1 ^= 0b0000_1000,
|
||||||
|
MKey::I => row1 ^= 0b0000_0100,
|
||||||
|
MKey::P => row1 ^= 0b0000_0010,
|
||||||
|
MKey::Enter => row1 ^= 0b0000_0001,
|
||||||
|
MKey::LeftShift | MKey::RightShift => row2 ^= 0b1000_0000,
|
||||||
|
MKey::D => row2 ^= 0b0100_0000,
|
||||||
|
MKey::V => row2 ^= 0b0010_0000,
|
||||||
|
MKey::H => row2 ^= 0b0001_0000,
|
||||||
|
MKey::K => row2 ^= 0b0000_1000,
|
||||||
|
MKey::Apostrophe => row2 ^= 0b0000_0100,
|
||||||
|
MKey::Slash => row2 ^= 0b0000_0010,
|
||||||
|
MKey::A => row2 ^= 0b0000_0001,
|
||||||
|
MKey::LeftCtrl | MKey::RightCtrl => row3 ^= 0b1000_0000,
|
||||||
|
MKey::Z => row3 ^= 0b0100_0000,
|
||||||
|
MKey::F => row3 ^= 0b0010_0000,
|
||||||
|
MKey::B => row3 ^= 0b0001_0000,
|
||||||
|
MKey::J => row3 ^= 0b0000_1000,
|
||||||
|
MKey::L => row3 ^= 0b0000_0100,
|
||||||
|
MKey::Key2 => row3 ^= 0b0000_0010,
|
||||||
|
MKey::Key4 => row3 ^= 0b0000_0001,
|
||||||
|
MKey::LeftAlt | MKey::RightAlt => row4 ^= 0b1000_0000,
|
||||||
|
MKey::X => row4 ^= 0b0100_0000,
|
||||||
|
MKey::C => row4 ^= 0b0010_0000,
|
||||||
|
MKey::N => row4 ^= 0b0001_0000,
|
||||||
|
MKey::M => row4 ^= 0b0000_1000,
|
||||||
|
MKey::Comma => row4 ^= 0b0000_0100,
|
||||||
|
MKey::Key1 => row4 ^= 0b0000_0010,
|
||||||
|
MKey::Key3 => row4 ^= 0b0000_0001,
|
||||||
|
MKey::LeftSuper => row5 ^= 0b1000_0000,
|
||||||
|
MKey::Space => row5 ^= 0b0100_0000,
|
||||||
|
MKey::RightSuper => row5 ^= 0b0010_0000,
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.memory.write(0x4400, row0);
|
||||||
|
self.memory.write(0x4401, row1);
|
||||||
|
self.memory.write(0x4402, row2);
|
||||||
|
self.memory.write(0x4403, row3);
|
||||||
|
self.memory.write(0x4404, row4);
|
||||||
|
self.memory.write(0x4405, row5);
|
||||||
|
}
|
||||||
|
}
|
||||||
+204
@@ -0,0 +1,204 @@
|
|||||||
|
pub mod cpu;
|
||||||
|
mod instructions;
|
||||||
|
mod keyboard;
|
||||||
|
pub mod memory;
|
||||||
|
mod platform;
|
||||||
|
pub mod video;
|
||||||
|
|
||||||
|
use crate::cpu::Cpu;
|
||||||
|
use crate::keyboard::Keyboard;
|
||||||
|
use crate::memory::Mem;
|
||||||
|
use crate::video::Renderer;
|
||||||
|
|
||||||
|
use cpu::CpuController;
|
||||||
|
use memory::MemHandle;
|
||||||
|
use minifb::Window;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use platform::native as imp;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
use platform::wasm as imp;
|
||||||
|
|
||||||
|
pub struct GeorgeEmu(imp::GeorgeEmu);
|
||||||
|
|
||||||
|
impl GeorgeEmu {
|
||||||
|
pub fn builder() -> GeorgeEmuBuilder<NoRom, NoWindow> {
|
||||||
|
GeorgeEmuBuilder::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
self.0.draw()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cycle(&mut self) {
|
||||||
|
self.0.cycle()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
self.0.run()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SomeRom();
|
||||||
|
pub struct NoRom();
|
||||||
|
pub struct SomeWindow(Window);
|
||||||
|
pub struct NoWindow();
|
||||||
|
|
||||||
|
pub struct GeorgeEmuBuilder<Rom, Window> {
|
||||||
|
rom: Rom,
|
||||||
|
cpu: Option<Cpu>,
|
||||||
|
keyboard: Option<Keyboard>,
|
||||||
|
renderer: Option<Renderer>,
|
||||||
|
cpu_controller: Option<CpuController>,
|
||||||
|
memory_handle: Option<MemHandle>,
|
||||||
|
window: Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmuBuilder<NoRom, NoWindow> {
|
||||||
|
fn new() -> Self {
|
||||||
|
GeorgeEmuBuilder {
|
||||||
|
rom: NoRom(),
|
||||||
|
cpu: None,
|
||||||
|
keyboard: None,
|
||||||
|
renderer: None,
|
||||||
|
cpu_controller: None,
|
||||||
|
memory_handle: None,
|
||||||
|
window: NoWindow(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn rom(self, rom: [u8; 0x8000]) -> GeorgeEmuBuilder<SomeRom, NoWindow> {
|
||||||
|
let mut memory = Mem::new();
|
||||||
|
memory.load_bytes(&rom);
|
||||||
|
let memory_handle = MemHandle::new(memory);
|
||||||
|
|
||||||
|
let (cpu, cpu_controller) = Cpu::new_with_control(memory_handle.clone());
|
||||||
|
|
||||||
|
let Self {
|
||||||
|
renderer,
|
||||||
|
keyboard,
|
||||||
|
window,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
GeorgeEmuBuilder {
|
||||||
|
cpu: Some(cpu),
|
||||||
|
rom: SomeRom(),
|
||||||
|
keyboard,
|
||||||
|
renderer,
|
||||||
|
cpu_controller: Some(cpu_controller),
|
||||||
|
memory_handle: Some(memory_handle),
|
||||||
|
window,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmuBuilder<SomeRom, NoWindow> {
|
||||||
|
/// Adds a minifb window to the emulator
|
||||||
|
pub fn window(self, mut window: Window) -> GeorgeEmuBuilder<SomeRom, SomeWindow> {
|
||||||
|
let Self {
|
||||||
|
rom,
|
||||||
|
cpu,
|
||||||
|
keyboard,
|
||||||
|
ref cpu_controller,
|
||||||
|
ref memory_handle,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
let renderer = Renderer::new(
|
||||||
|
self.cpu_controller.clone().unwrap(),
|
||||||
|
self.memory_handle.clone().unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
window.set_input_callback(Box::new(Keyboard::new(
|
||||||
|
self.memory_handle.as_ref().unwrap().clone(),
|
||||||
|
)));
|
||||||
|
|
||||||
|
GeorgeEmuBuilder {
|
||||||
|
cpu,
|
||||||
|
rom,
|
||||||
|
keyboard,
|
||||||
|
renderer: Some(renderer),
|
||||||
|
cpu_controller: cpu_controller.clone(),
|
||||||
|
memory_handle: memory_handle.clone(),
|
||||||
|
window: SomeWindow(window),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables debug printing and breakpoint triggering
|
||||||
|
pub fn debug(mut self) -> Self {
|
||||||
|
self.cpu.as_mut().unwrap().debug = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub fn build(self) -> GeorgeEmu {
|
||||||
|
let keyboard = Keyboard::new(self.memory_handle.clone().unwrap());
|
||||||
|
GeorgeEmu(imp::GeorgeEmu::new(
|
||||||
|
self.cpu.unwrap(),
|
||||||
|
self.renderer.unwrap(),
|
||||||
|
Some(keyboard),
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmuBuilder<NoRom, SomeWindow> {
|
||||||
|
pub fn rom(self, rom: [u8; 0x8000]) -> GeorgeEmuBuilder<SomeRom, SomeWindow> {
|
||||||
|
let mut memory = Mem::new();
|
||||||
|
memory.load_bytes(&rom);
|
||||||
|
let memory_handle = MemHandle::new(memory);
|
||||||
|
|
||||||
|
let (cpu, cpu_controller) = Cpu::new_with_control(memory_handle.clone());
|
||||||
|
|
||||||
|
let Self {
|
||||||
|
renderer,
|
||||||
|
keyboard,
|
||||||
|
window,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
GeorgeEmuBuilder {
|
||||||
|
cpu: Some(cpu),
|
||||||
|
rom: SomeRom(),
|
||||||
|
keyboard,
|
||||||
|
renderer,
|
||||||
|
cpu_controller: Some(cpu_controller),
|
||||||
|
memory_handle: Some(memory_handle),
|
||||||
|
window,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables debug printing and breakpoint triggering
|
||||||
|
pub fn debug(mut self) -> Self {
|
||||||
|
self.cpu.as_mut().unwrap().debug = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmuBuilder<SomeRom, SomeWindow> {
|
||||||
|
/// Enables debug printing and breakpoint triggering
|
||||||
|
pub fn debug(mut self) -> Self {
|
||||||
|
self.cpu.as_mut().unwrap().debug = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub fn build(self) -> GeorgeEmu {
|
||||||
|
let keyboard = Keyboard::new(self.memory_handle.clone().unwrap());
|
||||||
|
GeorgeEmu(imp::GeorgeEmu::new(
|
||||||
|
self.cpu.unwrap(),
|
||||||
|
self.renderer.unwrap(),
|
||||||
|
None,
|
||||||
|
Some(self.window.0),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
pub fn build(self) -> GeorgeEmu {
|
||||||
|
GeorgeEmu(imp::GeorgeEmu::new(
|
||||||
|
self.cpu.unwrap(),
|
||||||
|
self.renderer.unwrap(),
|
||||||
|
self.window.0,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
-3994
File diff suppressed because it is too large
Load Diff
+122
@@ -0,0 +1,122 @@
|
|||||||
|
use anyhow::{bail, Result};
|
||||||
|
use std::io::{self, Write};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::{fs::File, io::Read};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MemHandle(Arc<Mutex<Mem>>);
|
||||||
|
impl MemHandle {
|
||||||
|
pub fn new(memory: Mem) -> Self {
|
||||||
|
Self(Arc::new(Mutex::new(memory)))
|
||||||
|
}
|
||||||
|
pub fn read(&self, address: u16) -> u8 {
|
||||||
|
let memory = self.0.try_lock().unwrap();
|
||||||
|
memory.read(address)
|
||||||
|
}
|
||||||
|
pub fn write(&self, address: u16, data: u8) {
|
||||||
|
let mut memory = self.0.try_lock().unwrap();
|
||||||
|
memory.write(address, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dump(&self) -> [u8; 0x10000] {
|
||||||
|
let memory = self.0.lock().unwrap();
|
||||||
|
memory.dump()
|
||||||
|
}
|
||||||
|
pub fn poke(&self, address: u16) {
|
||||||
|
let memory = self.0.lock().unwrap();
|
||||||
|
memory.poke(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MemoryReader {
|
||||||
|
fn read(&self, address: u16) -> u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait MemoryWriter {
|
||||||
|
fn write(&self, address: u16, data: u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
// This always feels wrong instead of 0xFFFF,
|
||||||
|
// but remember it's the number of elements,
|
||||||
|
// not the maximum index. 0x0000 to 0xFFFF addresses
|
||||||
|
// 0x10000 elements
|
||||||
|
pub struct Mem([u8; 0x10000]);
|
||||||
|
|
||||||
|
impl Default for Mem {
|
||||||
|
fn default() -> Self {
|
||||||
|
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/roms/george.rom"));
|
||||||
|
let padding = [0; 0x8000];
|
||||||
|
let mem: [u8; 0x10000] = {
|
||||||
|
let mut rom: [u8; 0x10000] = [0; 0x10000];
|
||||||
|
let (one, two) = rom.split_at_mut(padding.len());
|
||||||
|
one.copy_from_slice(&padding);
|
||||||
|
two.copy_from_slice(bytes);
|
||||||
|
rom
|
||||||
|
};
|
||||||
|
|
||||||
|
Self(mem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mem {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self([0; 0x10000])
|
||||||
|
}
|
||||||
|
pub fn dump(&self) -> [u8; 0x10000] {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&self, address: u16) -> u8 {
|
||||||
|
self.0[address as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self, address: u16, data: u8) {
|
||||||
|
self.0[address as usize] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_rom<P>(&mut self, rom: P) -> Result<()>
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
{
|
||||||
|
let rom = match File::open(rom) {
|
||||||
|
Ok(rom) => rom,
|
||||||
|
Err(_) => bail!("rom could not be opened!"),
|
||||||
|
};
|
||||||
|
let bytes = rom.bytes();
|
||||||
|
for (address, byte) in bytes.enumerate() {
|
||||||
|
// println!("{address}");
|
||||||
|
match byte {
|
||||||
|
Ok(value) => self.write(address as u16 + 0x8000, value),
|
||||||
|
Err(_) => {
|
||||||
|
bail!("Loading rom: couldn't write byte {:#04x}", address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poke(&self, address: u16) {
|
||||||
|
println!("{:02x}", self.read(address));
|
||||||
|
}
|
||||||
|
pub fn load_bytes(&mut self, bytes: &[u8]) {
|
||||||
|
for (address, byte) in bytes.iter().enumerate() {
|
||||||
|
self.write(address as u16 + 0x8000, *byte)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_from_bin(&mut self, f: File) -> Result<()> {
|
||||||
|
let bytes = f.bytes();
|
||||||
|
for (address, byte) in bytes.enumerate() {
|
||||||
|
match byte {
|
||||||
|
Ok(value) => self.write(address as u16 + 0x8000, value),
|
||||||
|
Err(_) => {
|
||||||
|
bail!("couldn't write byte {:#04x}", address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
+894
@@ -0,0 +1,894 @@
|
|||||||
|
vec![
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BRK(AddressingMode::Implied),
|
||||||
|
cycles: 7,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ORA(AddressingMode::ZeroPageIndexedIndirect),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x02 }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x03 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::TSB(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ORA(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ASL(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::RMB0(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::PHP(AddressingMode::Stack),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ORA(AddressingMode::Immediate),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ASL(AddressingMode::Accumulator),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x0b }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::TSB(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ORA(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ASL(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBR0(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BPL(AddressingMode::ProgramCounterRelative),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ORA(AddressingMode::AbsoluteIndexedWithY),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ORA(AddressingMode::ZeroPageIndirect),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x13 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::TRB(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ORA(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ASL(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::RMB1(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CLC(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ORA(AddressingMode::AbsoluteIndexedWithY),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::INC(AddressingMode::Accumulator),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x1b }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::TRB(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ORA(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ASL(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 7,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBR1(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::JSR(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::AND(AddressingMode::ZeroPageIndexedIndirect),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x22 }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x23 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BIT(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::AND(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ROL(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::RMB2(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::PLP(AddressingMode::Stack),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::AND(AddressingMode::Immediate),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ROL(AddressingMode::Accumulator),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x2b }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BIT(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::AND(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ROL(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBR2(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BMI(AddressingMode::ProgramCounterRelative),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::AND(AddressingMode::ZeroPageIndirectIndexedWithY),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::AND(AddressingMode::ZeroPageIndirect),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x33 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BIT(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::AND(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ROL(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::RMB3(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SEC(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::AND(AddressingMode::AbsoluteIndexedWithY),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::DEC(AddressingMode::Accumulator),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x3b }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BIT(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::AND(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ROL(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 7,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBR3(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::RTI(AddressingMode::Implied),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::EOR(AddressingMode::ZeroPageIndexedIndirect),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x42 }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x43 }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x44 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::EOR(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LSR(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::RMB4(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::PHA(AddressingMode::Stack),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::EOR(AddressingMode::Immediate),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LSR(AddressingMode::Accumulator),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x4b }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::JMP(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::EOR(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LSR(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBR4(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BVC(AddressingMode::ProgramCounterRelative),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::EOR(AddressingMode::ZeroPageIndirectIndexedWithY),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::EOR(AddressingMode::ZeroPageIndirect),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x53 }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x54 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::EOR(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LSR(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::RMB5(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CLI(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::EOR(AddressingMode::AbsoluteIndexedWithY),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::PHY(AddressingMode::Stack),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x5b }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x5c }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::EOR(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LSR(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 7,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBR5(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::RTS(AddressingMode::Stack),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ADC(AddressingMode::ZeroPageIndexedIndirect),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x62 }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x63 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STZ(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ADC(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ROR(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::RMB6(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::PLA(AddressingMode::Stack),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ADC(AddressingMode::Immediate),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ROR(AddressingMode::Accumulator),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x6b }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::JMP(AddressingMode::AbsoluteIndirect),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ADC(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ROR(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBR6(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BVS(AddressingMode::ProgramCounterRelative),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ADC(AddressingMode::ZeroPageIndirectIndexedWithY),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ADC(AddressingMode::ZeroPageIndirect),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x73 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STZ(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ADC(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ROR(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::RMB7(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SEI(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ADC(AddressingMode::AbsoluteIndexedWithY),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::PLY(AddressingMode::Stack),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x7b }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::JMP(AddressingMode::AbsoluteIndexedIndirect),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ADC(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::ROR(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 7,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBR7(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BRA(AddressingMode::ProgramCounterRelative),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STA(AddressingMode::ZeroPageIndexedIndirect),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x82 }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x83 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STY(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STA(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STX(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SMB0(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::DEY(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BIT(AddressingMode::Immediate),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::TXA(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x8b }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STY(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STA(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STX(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBS0(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BCC(AddressingMode::ProgramCounterRelative),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STA(AddressingMode::ZeroPageIndirectIndexedWithY),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STA(AddressingMode::ZeroPageIndirect),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x93 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STY(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STA(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STX(AddressingMode::ZeroPageIndexedWithY),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SMB1(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::TYA(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STA(AddressingMode::AbsoluteIndexedWithY),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::TXS(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0x9b }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STZ(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STA(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STZ(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBS1(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDY(AddressingMode::Immediate),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDA(AddressingMode::ZeroPageIndexedIndirect),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDX(AddressingMode::Immediate),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xa3 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDY(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDA(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDX(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SMB2(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::TAY(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDA(AddressingMode::Immediate),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::TAX(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xab }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDY(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDA(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDX(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBS2(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BCS(AddressingMode::ProgramCounterRelative),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDA(AddressingMode::ZeroPageIndirectIndexedWithY),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDA(AddressingMode::ZeroPageIndirect),
|
||||||
|
cycles: 5, // Unsure, see https://cx16.dk/65c02/reference.html#LDA
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xb3 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDY(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDA(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDX(AddressingMode::ZeroPageIndexedWithY),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SMB3(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CLV(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDA(AddressingMode::AbsoluteIndexedWithY),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::TSX(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xbb }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDY(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDA(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::LDX(AddressingMode::AbsoluteIndexedWithY),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBS3(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CPY(AddressingMode::Immediate),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CMP(AddressingMode::ZeroPageIndexedIndirect),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xc2 }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xc3 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CPY(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CMP(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::DEC(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SMB4(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::INY(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CMP(AddressingMode::Immediate),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::DEX(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::WAI(AddressingMode::Implied),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CPY(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CMP(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::DEC(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBS4(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BNE(AddressingMode::ProgramCounterRelative),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CMP(AddressingMode::ZeroPageIndirectIndexedWithY),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CMP(AddressingMode::ZeroPageIndirect),
|
||||||
|
cycles: 5, // Unsure, look here: https://cx16.dk/65c02/reference.html#CMP
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xd3 }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xd4 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CMP(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::DEC(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SMB5(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CLD(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CMP(AddressingMode::AbsoluteIndexedWithY),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::PHX(AddressingMode::Stack),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::STP(AddressingMode::Implied),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xdc }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CMP(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::DEC(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 7,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBS5(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CPX(AddressingMode::Immediate),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SBC(AddressingMode::ZeroPageIndexedIndirect),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xe2 }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xe3 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CPX(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SBC(AddressingMode::ZeroPage),
|
||||||
|
cycles: 3,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::INC(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SMB6(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::INX(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SBC(AddressingMode::Immediate),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::NOP(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xeb }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::CPX(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SBC(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::INC(AddressingMode::AbsoluteA),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBS6(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BEQ(AddressingMode::ProgramCounterRelative),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SBC(AddressingMode::ZeroPageIndirectIndexedWithY),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SBC(AddressingMode::ZeroPageIndirect),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xf3 }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xf4 }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SBC(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::INC(AddressingMode::ZeroPageIndexedWithX),
|
||||||
|
cycles: 6,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SMB7(AddressingMode::ZeroPage),
|
||||||
|
cycles: 5,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SED(AddressingMode::Implied),
|
||||||
|
cycles: 2,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SBC(AddressingMode::AbsoluteIndexedWithY),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::PLX(AddressingMode::Stack),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xfb }),
|
||||||
|
Instruction::Invalid(InvalidInstruction { opcode: 0xfc }),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::SBC(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::INC(AddressingMode::AbsoluteIndexedWithX),
|
||||||
|
cycles: 7,
|
||||||
|
}),
|
||||||
|
Instruction::Valid(ValidInstruction {
|
||||||
|
opcode: Opcode::BBS7(AddressingMode::ProgramCounterRelativeTest),
|
||||||
|
cycles: 4,
|
||||||
|
}),
|
||||||
|
]
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub mod native;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
pub mod wasm;
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
use minifb::Window;
|
||||||
|
use std::{
|
||||||
|
io::stdout,
|
||||||
|
process::exit,
|
||||||
|
thread::sleep,
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
use termion::{
|
||||||
|
async_stdin, clear,
|
||||||
|
cursor::{self, Goto},
|
||||||
|
event::Key,
|
||||||
|
input::TermRead,
|
||||||
|
raw::IntoRawMode,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{cpu::Cpu, keyboard::Keyboard, video::Renderer};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GeorgeEmu {
|
||||||
|
cpu: Cpu,
|
||||||
|
renderer: Renderer,
|
||||||
|
input: Option<Keyboard>,
|
||||||
|
window: Option<Window>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmu {
|
||||||
|
pub fn new(
|
||||||
|
mut cpu: Cpu,
|
||||||
|
renderer: Renderer,
|
||||||
|
input: Option<Keyboard>,
|
||||||
|
window: Option<Window>,
|
||||||
|
) -> Self {
|
||||||
|
cpu.reset();
|
||||||
|
Self {
|
||||||
|
cpu,
|
||||||
|
input,
|
||||||
|
renderer,
|
||||||
|
window,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
self.renderer.render(self.window.as_mut())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cycle(&mut self) {
|
||||||
|
self.cpu.cycle()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
if self.window.is_none() {
|
||||||
|
let _ = stdout().into_raw_mode();
|
||||||
|
print!("{}{}", cursor::Hide, clear::All,);
|
||||||
|
}
|
||||||
|
let clock_interval = Duration::from_nanos(500);
|
||||||
|
let frame_interval = Duration::from_millis(16);
|
||||||
|
let mut next_clock = Instant::now() + clock_interval;
|
||||||
|
let mut next_frame = Instant::now() + frame_interval;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
|
if now >= next_clock {
|
||||||
|
self.cpu.cycle();
|
||||||
|
next_clock += clock_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if now >= next_frame {
|
||||||
|
if self.window.is_none() {
|
||||||
|
self.handle_input();
|
||||||
|
}
|
||||||
|
self.draw();
|
||||||
|
next_frame += frame_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
let next_run = std::cmp::min(next_clock, next_frame);
|
||||||
|
let sleep_dur = next_run - now;
|
||||||
|
sleep(sleep_dur)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_input(&mut self) {
|
||||||
|
let mut stdin = async_stdin().keys();
|
||||||
|
if let Some(Ok(key)) = stdin.next() {
|
||||||
|
match key {
|
||||||
|
Key::Char('q') => {
|
||||||
|
print!("{}{}{}", clear::All, cursor::Show, Goto(1, 1));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
Key::Char('`') => self.cpu.toggle_stopped(),
|
||||||
|
Key::Char('\n') => self.cpu.cycle(),
|
||||||
|
Key::Char('i') => self.cpu.interrupt(),
|
||||||
|
_ => {
|
||||||
|
self.input.as_mut().unwrap().read_keys(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.input.as_mut().unwrap().clear_keys();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
use minifb::Window;
|
||||||
|
|
||||||
|
use crate::{cpu::Cpu, video::Renderer};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct GeorgeEmu {
|
||||||
|
cpu: Cpu,
|
||||||
|
renderer: Renderer,
|
||||||
|
window: Window,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GeorgeEmu {
|
||||||
|
pub fn new(mut cpu: Cpu, renderer: Renderer, window: Window) -> Self {
|
||||||
|
cpu.reset();
|
||||||
|
Self {
|
||||||
|
cpu,
|
||||||
|
renderer,
|
||||||
|
window,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
self.renderer.render(Some(&mut self.window));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cycle(&mut self) {
|
||||||
|
self.cpu.cycle()
|
||||||
|
}
|
||||||
|
}
|
||||||
+137
@@ -0,0 +1,137 @@
|
|||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use std::io::{self, Write};
|
||||||
|
use std::{env, fs::File, io::Read, path::Path};
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
use termion::{
|
||||||
|
color::{self, Bg, Fg},
|
||||||
|
cursor::Goto,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
cpu::CpuController,
|
||||||
|
memory::{MemHandle, MemoryReader},
|
||||||
|
};
|
||||||
|
use minifb::Window;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
const FG_COLOR: u32 = 0xFFCC00;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
const BG_COLOR: u32 = 0x110500;
|
||||||
|
|
||||||
|
// Wasm colors are ABGR
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
const FG_COLOR: u32 = 0xFF00CCFF;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
const BG_COLOR: u32 = 0xFF000511;
|
||||||
|
|
||||||
|
const WIDTH: usize = 512;
|
||||||
|
const HEIGHT: usize = 380;
|
||||||
|
|
||||||
|
// pub fn get_char_bin<P>(char_rom: Option<P>) -> [u8; 0x8000]
|
||||||
|
// where
|
||||||
|
// P: AsRef<Path>,
|
||||||
|
// {
|
||||||
|
// match char_rom {
|
||||||
|
// Some(path) => {
|
||||||
|
// let mut file = File::open(path).unwrap();
|
||||||
|
// let mut bin = vec![0; 0x8000];
|
||||||
|
// file.read_exact(&mut bin).unwrap();
|
||||||
|
// // println!("reading char rom");
|
||||||
|
// bin.try_into().unwrap()
|
||||||
|
// }
|
||||||
|
// None => *include_bytes!("./roms/cozette.rom"),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
const CHAR_ROM: &[u8; 0x8000] = include_bytes!(concat!(env!("OUT_DIR"), "/cozette.rom"));
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
const ASCII_LOOKUP: [&str; 256] = [
|
||||||
|
" ", "░", "▒", "▓", "♡", "♥", "⭐", "✭", "", "✦", "✨", "♀", "♂", "⚢", "⚣", "⚥", "♩", "♪",
|
||||||
|
"♫", "♬", "ﱝ", "", "", "", "奄", "奔", "婢", "ﱜ", "ﱛ", "", "", "", " ", "!", "\"", "#",
|
||||||
|
"$", "%", "&", "\'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6",
|
||||||
|
"7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I",
|
||||||
|
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\",
|
||||||
|
"]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o",
|
||||||
|
"p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "─", "│", "┌", "└",
|
||||||
|
"├", "┤", "┬", "┴", "┼", "╭", "╮", "╯", "╰", "╱", "╲", "╳", "═", "║", "╔", "╗", "╚", "╝", "╠",
|
||||||
|
"╣", "╦", "╩", "╬", "", "", "", "", "", "", "", "", "", "", "", "", "", "▁", "▂",
|
||||||
|
"▃", "▄", "▅", "▆", "▇", "█", "▉", "▊", "▋", "▌", "▍", "▎", "▏", "ʕ", "·", "ᴥ", "ʔ", "▖", "▗",
|
||||||
|
"▘", "▙", "▚", "▛", "▜", "▝", "▞", "▟", "←", "↑", "→", "↓", "⭠", "⭡", "⭢", "⭣", "⮀", "⮁", "⮂",
|
||||||
|
"⮃", "", "", "⏳", "", "", "", "", "", "", "", "", "", "", "", "🔮", "", "",
|
||||||
|
"◇", "◈", "🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘", "", "✔", "✘", "◆", "", "", "",
|
||||||
|
"", "", "", "", "🎁", "", "", "", "", "⚐", "⚑", "", "", "",
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Renderer {
|
||||||
|
memory: MemHandle,
|
||||||
|
controller: CpuController,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderer {
|
||||||
|
pub fn new(controller: CpuController, memory: MemHandle) -> Self {
|
||||||
|
Self { memory, controller }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, window: Option<&mut Window>) {
|
||||||
|
match window {
|
||||||
|
Some(window) => {
|
||||||
|
// the rest of this function is arcane wizardry
|
||||||
|
// based on the specifics of george's weird
|
||||||
|
// display and characters... don't fuck around w it
|
||||||
|
let mut i = 0;
|
||||||
|
let mut buffer = [0; WIDTH * HEIGHT];
|
||||||
|
for char_row in 0..29 {
|
||||||
|
for char_col in 0..64 {
|
||||||
|
let ascii = self.read(0x6000 + i);
|
||||||
|
i += 1;
|
||||||
|
for row in 0..13 {
|
||||||
|
let byte = CHAR_ROM[ascii as usize + (row * 0x100)];
|
||||||
|
for bit_index in (0..8).rev() {
|
||||||
|
let buffer_index =
|
||||||
|
((char_row) * 13 + (row)) * 512 + (char_col * 8 + bit_index);
|
||||||
|
if (byte << bit_index) & 0x80 == 0x80 {
|
||||||
|
buffer[buffer_index] = FG_COLOR;
|
||||||
|
} else {
|
||||||
|
buffer[buffer_index] = BG_COLOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
{
|
||||||
|
let mut stdout = io::stdout();
|
||||||
|
let mut i = 0;
|
||||||
|
for char_row in 0..29 {
|
||||||
|
for char_col in 0..64 {
|
||||||
|
let ascii = self.read(0x6000 + i);
|
||||||
|
i += 1;
|
||||||
|
let char = ASCII_LOOKUP[ascii as usize];
|
||||||
|
let _ = write!(
|
||||||
|
// FG_COLOR = 0xFFCC00
|
||||||
|
// BG_COLOR = 0x110500
|
||||||
|
stdout,
|
||||||
|
"{}{}{}{char}",
|
||||||
|
Goto(char_col + 1, char_row + 1),
|
||||||
|
Fg(color::Rgb(0xFF, 0xCC, 0x00)),
|
||||||
|
Bg(color::Rgb(0x11, 0x05, 0x00))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.controller.irq();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryReader for Renderer {
|
||||||
|
fn read(&self, address: u16) -> u8 {
|
||||||
|
self.memory.read(address)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user