Compare commits
No commits in common. "952b79cf91542021e732d8fd5b0b46dbf0132a46" and "c2aef4f249fe557692b5c8a4a16228080e03255d" have entirely different histories.
952b79cf91
...
c2aef4f249
|
@ -14,6 +14,31 @@ version = "1.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||
|
||||
[[package]]
|
||||
name = "bdf"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f550a6818e6f42ccd5883f44e45fff4f68415a0d09abdc81e7d1d78e0780af14"
|
||||
dependencies = [
|
||||
"bit-set",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84527c7b0452f22545cc010e72d366a435561d2b28b978035550b3778c4d428d"
|
||||
dependencies = [
|
||||
"bit-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -45,13 +70,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.7"
|
||||
name = "crossterm"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
|
||||
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen",
|
||||
"bitflags 2.5.0",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -82,7 +122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -185,12 +225,12 @@ name = "georgeemu"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"console_error_panic_hook",
|
||||
"bdf",
|
||||
"crossterm",
|
||||
"minifb",
|
||||
"serde",
|
||||
"termion",
|
||||
"toml",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -221,17 +261,11 @@ dependencies = [
|
|||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.70"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
|
||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
@ -255,7 +289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -266,7 +300,7 @@ checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607"
|
|||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"redox_syscall 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -275,6 +309,16 @@ version = "0.4.14"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.21"
|
||||
|
@ -299,10 +343,10 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "minifb"
|
||||
version = "0.27.0"
|
||||
source = "git+https://github.com/augustkline/rust_minifb#2e2fdcf1d692c8c3d827a221a66569d81c73f99a"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0c470a74618b43cd182c21b3dc1e6123501249f3bad9a0085e95d1304ca2478"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"console_error_panic_hook",
|
||||
"dlib",
|
||||
"futures",
|
||||
"instant",
|
||||
|
@ -314,16 +358,26 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"tempfile",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"wayland-client",
|
||||
"wayland-cursor",
|
||||
"wayland-protocols",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
"x11-dl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.24.3"
|
||||
|
@ -360,6 +414,29 @@ dependencies = [
|
|||
"sdl2-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.5.2",
|
||||
"smallvec",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
|
@ -411,6 +488,15 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_termios"
|
||||
version = "0.1.3"
|
||||
|
@ -427,21 +513,21 @@ dependencies = [
|
|||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "sdl2"
|
||||
version = "0.35.2"
|
||||
|
@ -485,18 +571,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.127"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.6"
|
||||
|
@ -506,6 +580,36 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
|
@ -541,7 +645,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"fastrand",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -556,6 +660,26 @@ dependencies = [
|
|||
"redox_termios",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.14"
|
||||
|
@ -603,23 +727,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.93"
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.93"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
|
||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
|
@ -644,9 +771,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.93"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
|
||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
@ -654,9 +781,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.93"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -667,9 +794,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.93"
|
||||
version = "0.2.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
|
@ -746,9 +873,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.70"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
|
||||
checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
|
@ -776,13 +903,37 @@ 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",
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
|
@ -791,28 +942,46 @@ version = "0.52.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_aarch64_gnullvm 0.52.5",
|
||||
"windows_aarch64_msvc 0.52.5",
|
||||
"windows_i686_gnu 0.52.5",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
"windows_i686_msvc 0.52.5",
|
||||
"windows_x86_64_gnu 0.52.5",
|
||||
"windows_x86_64_gnullvm 0.52.5",
|
||||
"windows_x86_64_msvc 0.52.5",
|
||||
]
|
||||
|
||||
[[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.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[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.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[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.5"
|
||||
|
@ -825,24 +994,48 @@ version = "0.52.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[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.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[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.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
|
||||
[[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.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
|
||||
[[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.5"
|
||||
|
|
24
Cargo.toml
24
Cargo.toml
|
@ -3,27 +3,15 @@ name = "georgeemu"
|
|||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[[bin]]
|
||||
path = "src/bin/main.rs"
|
||||
name = "georgeemu"
|
||||
|
||||
[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
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.81"
|
||||
minifb = { git = "https://github.com/augustkline/rust_minifb" }
|
||||
bdf = "0.6.0"
|
||||
crossterm = "0.27.0"
|
||||
minifb = "0.27.0"
|
||||
# minifb = "0.25.0"
|
||||
# ratatui = "0.26.3"
|
||||
serde = { version = "1.0.197", features = ["serde_derive", "derive"] }
|
||||
web-sys = "0.3.70"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
console_error_panic_hook = "0.1.7"
|
||||
minifb = { git = "https://github.com/augustkline/rust_minifb", features = [
|
||||
"web",
|
||||
] }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
termion = "4.0.2"
|
||||
toml = { version = "0.8.12" }
|
||||
toml = "0.8.12"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
char_rom = "./src/roms/cozette.rom"
|
||||
rom = "./src/roms/keyboard_sys.rom"
|
||||
rom = "./src/roms/george.rom"
|
||||
screen = "Window"
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod cli;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use cli::get_input;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use georgeemu::GeorgeEmu;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use minifb::{Scale, ScaleMode, Window, WindowOptions};
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
fn main() {
|
||||
use std::{fs::File, io::Read};
|
||||
|
||||
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();
|
||||
// println!("reading char rom");
|
||||
bin.try_into().unwrap()
|
||||
}
|
||||
None => *include_bytes!("../roms/george.rom"),
|
||||
};
|
||||
let mut emu = GeorgeEmu::builder().rom(rom).window(window).build();
|
||||
|
||||
emu.run();
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn main() {}
|
|
@ -7,18 +7,7 @@ use std::{
|
|||
|
||||
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>,
|
||||
}
|
||||
use crate::video::ScreenType;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
struct ConfigBuilder {
|
||||
|
@ -38,7 +27,7 @@ impl ConfigBuilder {
|
|||
|
||||
fn build(self) -> Config {
|
||||
let rom = match self.rom {
|
||||
Some(rom) => Some(rom),
|
||||
Some(rom) => rom,
|
||||
None => {
|
||||
println!("no rom was provided :(");
|
||||
exit(1);
|
||||
|
@ -55,6 +44,12 @@ impl ConfigBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct Config {
|
||||
pub rom: String,
|
||||
pub screen: ScreenType,
|
||||
pub char_rom: Option<String>,
|
||||
}
|
||||
|
||||
fn help(command: Option<String>) {
|
||||
let executable: String = env::args().next().unwrap();
|
||||
if let Some(command) = command {
|
||||
|
@ -106,7 +101,6 @@ pub fn get_input() -> Config {
|
|||
}
|
||||
Err(_) => {
|
||||
println!("couldn't find a `george.toml` in the current directory!");
|
||||
println!("\nuse `{executable} --help` to see all config options");
|
||||
exit(1);
|
||||
}
|
||||
};
|
78
src/cpu.rs
78
src/cpu.rs
|
@ -2,11 +2,11 @@ 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;
|
||||
|
||||
use termion::cursor::Goto;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum StatusFlag {
|
||||
Negative = 0b1000_0000,
|
||||
|
@ -19,10 +19,9 @@ pub enum StatusFlag {
|
|||
Carry = 0b0000_0001,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct CpuController(Sender<CpuControl>);
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum CpuControl {
|
||||
Irq,
|
||||
Nmi,
|
||||
|
@ -36,23 +35,22 @@ impl CpuController {
|
|||
Self(sender)
|
||||
}
|
||||
pub fn irq(&self) {
|
||||
let _ = self.0.send(CpuControl::Irq);
|
||||
self.0.send(CpuControl::Irq);
|
||||
}
|
||||
pub fn nmi(&self) {
|
||||
let _ = self.0.send(CpuControl::Nmi);
|
||||
self.0.send(CpuControl::Nmi);
|
||||
}
|
||||
pub fn toggle(&self) {
|
||||
let _ = self.0.send(CpuControl::Toggle);
|
||||
self.0.send(CpuControl::Toggle);
|
||||
}
|
||||
pub fn cycle(&self) {
|
||||
let _ = self.0.send(CpuControl::Cycle);
|
||||
self.0.send(CpuControl::Cycle);
|
||||
}
|
||||
pub fn data(&self) {
|
||||
let _ = self.0.send(CpuControl::Data);
|
||||
self.0.send(CpuControl::Data);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CpuReceiver(Receiver<CpuControl>);
|
||||
impl CpuReceiver {
|
||||
pub fn new(receiver: Receiver<CpuControl>) -> Self {
|
||||
|
@ -60,7 +58,6 @@ impl CpuReceiver {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Cpu {
|
||||
pub a: u8, // Accumulator Register
|
||||
pub x: u8, // X Register
|
||||
|
@ -72,10 +69,10 @@ pub struct Cpu {
|
|||
pub nmi: bool,
|
||||
pub memory: MemHandle,
|
||||
pub pending_cycles: usize,
|
||||
pub debug: bool,
|
||||
receiver: Option<CpuReceiver>,
|
||||
stopped: bool,
|
||||
cycle: bool,
|
||||
cycle: bool, // cycle_count: usize,
|
||||
// state_tx: Sender<CpuState>,
|
||||
}
|
||||
|
||||
impl Display for Cpu {
|
||||
|
@ -97,6 +94,7 @@ impl MemoryWriter for Cpu {
|
|||
|
||||
impl Cpu {
|
||||
pub fn new(memory: MemHandle) -> Self {
|
||||
// pub fn new(memory: MemHandle) -> Self {
|
||||
Cpu {
|
||||
a: 0x00,
|
||||
x: 0x00,
|
||||
|
@ -108,7 +106,6 @@ impl Cpu {
|
|||
nmi: false,
|
||||
receiver: None,
|
||||
memory,
|
||||
debug: false,
|
||||
stopped: false,
|
||||
pending_cycles: 0,
|
||||
cycle: false, // cycle_count: 0,
|
||||
|
@ -182,6 +179,13 @@ impl Cpu {
|
|||
value & 0b1000_0000 == 0b1000_0000
|
||||
}
|
||||
|
||||
// pub fn execute(&mut self) {
|
||||
// self.cycle();
|
||||
// while self.pending_cycles != 0 {
|
||||
// self.cycle();
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn wait_for_interrupt(&self) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -194,10 +198,6 @@ impl Cpu {
|
|||
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) => {
|
||||
|
@ -213,8 +213,7 @@ impl Cpu {
|
|||
self.stopped = !self.stopped;
|
||||
}
|
||||
CpuControl::Cycle => self.cycle = true,
|
||||
CpuControl::Data => {
|
||||
// self
|
||||
CpuControl::Data => {} // self
|
||||
// .state_tx
|
||||
// .send(CpuState {
|
||||
// a: self.a.clone(), // Accumulator Register
|
||||
|
@ -229,7 +228,6 @@ impl Cpu {
|
|||
// .unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
@ -243,8 +241,6 @@ impl Cpu {
|
|||
}
|
||||
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));
|
||||
|
@ -256,13 +252,45 @@ impl Cpu {
|
|||
let opcode = self.read(self.pc);
|
||||
let instruction = get_instruction(opcode);
|
||||
instruction.call(self);
|
||||
// println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq, nmi = self.nmi);
|
||||
// println!(
|
||||
// "Instruction: {:?}, {:#04x}",
|
||||
// valid_instruction.opcode, opcode
|
||||
// );
|
||||
// println!("");
|
||||
}
|
||||
pub fn stop(&mut self) {
|
||||
self.stopped = true;
|
||||
}
|
||||
pub fn breakpoint(&mut self) {
|
||||
if self.debug {
|
||||
// println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq, nmi = self.nmi);
|
||||
// println!(
|
||||
// "Instruction: {:?}, {:#04x}",
|
||||
// valid_instruction.opcode, opcode
|
||||
// );
|
||||
// println!("");
|
||||
// println!(
|
||||
// "{}{:#04x}: {:#02x}, {:#04x}: {:#02x}",
|
||||
// Goto(1, 35),
|
||||
// 0x20,
|
||||
// self.read(0x20),
|
||||
// 0x21,
|
||||
// self.read(0x21)
|
||||
// );
|
||||
// println!(
|
||||
// "{}str_ptr {:#04x}: {:#02x}, {:#04x}: {:#02x}",
|
||||
// Goto(1, 36),
|
||||
// 0x30,
|
||||
// self.read(0x30),
|
||||
// 0x31,
|
||||
// self.read(0x31)
|
||||
// );
|
||||
// println!(
|
||||
// "{}cursor - x: {:#02x}, y: {:#02x}",
|
||||
// Goto(1, 37),
|
||||
// self.read(0x300),
|
||||
// self.read(0x301)
|
||||
// );
|
||||
self.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
#[derive(Debug)]
|
||||
pub enum GeorgeErrorKind {
|
||||
Memory(MemoryError),
|
||||
Execution(ExecutionError),
|
||||
AddrMode(AddressingModeError),
|
||||
Mapping(MappingError),
|
||||
}
|
||||
|
||||
impl From<MemoryError> for GeorgeErrorKind {
|
||||
fn from(value: MemoryError) -> Self {
|
||||
Self::Memory(value)
|
||||
}
|
||||
}
|
||||
impl From<AddressingModeError> for GeorgeErrorKind {
|
||||
fn from(value: AddressingModeError) -> Self {
|
||||
Self::AddrMode(value)
|
||||
}
|
||||
}
|
||||
impl From<ExecutionError> for GeorgeErrorKind {
|
||||
fn from(value: ExecutionError) -> Self {
|
||||
Self::Execution(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ExecutionError {
|
||||
InvalidInstruction,
|
||||
InterruptsDisabled,
|
||||
StackOverflow,
|
||||
MemoryError(MemoryError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AddressingModeError {
|
||||
IncompatibleAddrMode,
|
||||
}
|
||||
|
||||
impl From<ExecutionError> for AddressingModeError {
|
||||
fn from(_value: ExecutionError) -> Self {
|
||||
Self::IncompatibleAddrMode
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MemoryError> for ExecutionError {
|
||||
fn from(error: MemoryError) -> Self {
|
||||
ExecutionError::MemoryError(error)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GeorgeError {
|
||||
pub desc: String,
|
||||
pub kind: GeorgeErrorKind,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MemoryError {
|
||||
Unmapped,
|
||||
NoDataAtAddress,
|
||||
Unwritable,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MappingError {
|
||||
RegionOccupied,
|
||||
InvalidPage,
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
#![allow(clippy::upper_case_acronyms)]
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use termion::{clear, color, cursor::Goto};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use web_sys::console;
|
||||
use core::panic;
|
||||
use std::process::exit;
|
||||
|
||||
use termion::cursor::Goto;
|
||||
use termion::{clear, color};
|
||||
|
||||
use crate::cpu::{Cpu, StatusFlag};
|
||||
use crate::memory::{MemoryReader, MemoryWriter};
|
||||
|
@ -22,13 +23,47 @@ pub struct Instruction<'a> {
|
|||
|
||||
impl Instruction<'_> {
|
||||
pub fn call(&self, cpu: &mut Cpu) {
|
||||
if cpu.debug {
|
||||
self.debug(cpu);
|
||||
}
|
||||
|
||||
// TODO: add flag to print these
|
||||
// print!("{}{}a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", Goto(0, 31),clear::UntilNewline, a = cpu.a, x = cpu.x, y = cpu.y, pc = cpu.pc, s = cpu.s, p = cpu.p, irq = cpu.irq, nmi = cpu.nmi);
|
||||
// print!(
|
||||
// "{}instruction: {:?}, pc: {:#04x}",
|
||||
// Goto(0, 31),
|
||||
// self.name,
|
||||
// cpu.pc
|
||||
// );
|
||||
// print!(
|
||||
// "{}{}instruction: {:?}, mode: {:?}",
|
||||
// Goto(0, 32),
|
||||
// clear::UntilNewline,
|
||||
// self.name,
|
||||
// self.addr_mode
|
||||
// );
|
||||
// print!(
|
||||
// "{}{:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {}{}{:02x}{}{} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}",
|
||||
// Goto(0, 33),
|
||||
// cpu.read(cpu.pc.wrapping_sub(8)),
|
||||
// cpu.read(cpu.pc.wrapping_sub(7)),
|
||||
// cpu.read(cpu.pc.wrapping_sub(6)),
|
||||
// cpu.read(cpu.pc.wrapping_sub(5)),
|
||||
// cpu.read(cpu.pc.wrapping_sub(4)),
|
||||
// cpu.read(cpu.pc.wrapping_sub(3)),
|
||||
// cpu.read(cpu.pc.wrapping_sub(2)),
|
||||
// cpu.read(cpu.pc.wrapping_sub(1)),
|
||||
// color::Bg(color::Rgb(0xFF, 0xCC, 0x00)),
|
||||
// color::Fg(color::Rgb(0x11, 0x05, 0x00)),
|
||||
// cpu.read(cpu.pc),
|
||||
// color::Fg(color::Rgb(0xFF, 0xCC, 0x00)),
|
||||
// color::Bg(color::Rgb(0x11, 0x05, 0x00)),
|
||||
// cpu.read(cpu.pc.wrapping_add(1)),
|
||||
// cpu.read(cpu.pc.wrapping_add(2)),
|
||||
// cpu.read(cpu.pc.wrapping_add(3)),
|
||||
// cpu.read(cpu.pc.wrapping_add(4)),
|
||||
// cpu.read(cpu.pc.wrapping_add(5)),
|
||||
// cpu.read(cpu.pc.wrapping_add(6)),
|
||||
// cpu.read(cpu.pc.wrapping_add(7)),
|
||||
// cpu.read(cpu.pc.wrapping_add(8)),
|
||||
// );
|
||||
cpu.pc = cpu.pc.wrapping_add(1); // read instruction byte
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
match self.instr_fn {
|
||||
// existence of instr_fn means this is a valid instruction
|
||||
Some(instr_fn) => {
|
||||
|
@ -46,119 +81,16 @@ impl Instruction<'_> {
|
|||
} // None for address_fn implies it's implied (lol)/stack
|
||||
}
|
||||
}
|
||||
None =>
|
||||
{
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if cpu.debug {
|
||||
println!(
|
||||
"{}An invalid instruction was called at {:04x}, with opcode {:02x}",
|
||||
Goto(0, 35),
|
||||
None => {
|
||||
panic!(
|
||||
"An invalid instruction was called at {:04x}, with opcode {:02x}",
|
||||
cpu.pc,
|
||||
cpu.read(cpu.pc)
|
||||
);
|
||||
cpu.breakpoint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn debug(&self, cpu: &Cpu) {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
// cpu state
|
||||
print!("{}{}a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", Goto(0, 31),clear::UntilNewline, a = cpu.a, x = cpu.x, y = cpu.y, pc = cpu.pc, s = cpu.s, p = cpu.p, irq = cpu.irq, nmi = cpu.nmi);
|
||||
print!(
|
||||
"{}instruction: {:?}, pc: {:#04x}",
|
||||
Goto(0, 31),
|
||||
self.name,
|
||||
cpu.pc
|
||||
);
|
||||
|
||||
// current instruction and addressing mode
|
||||
print!(
|
||||
"{}{}instruction: {:?}, mode: {:?}",
|
||||
Goto(0, 32),
|
||||
clear::UntilNewline,
|
||||
self.name,
|
||||
self.addr_mode
|
||||
);
|
||||
|
||||
// local memory
|
||||
print!(
|
||||
"{}{:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {}{}{:02x}{}{} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}",
|
||||
Goto(0, 33),
|
||||
cpu.read(cpu.pc.wrapping_sub(8)),
|
||||
cpu.read(cpu.pc.wrapping_sub(7)),
|
||||
cpu.read(cpu.pc.wrapping_sub(6)),
|
||||
cpu.read(cpu.pc.wrapping_sub(5)),
|
||||
cpu.read(cpu.pc.wrapping_sub(4)),
|
||||
cpu.read(cpu.pc.wrapping_sub(3)),
|
||||
cpu.read(cpu.pc.wrapping_sub(2)),
|
||||
cpu.read(cpu.pc.wrapping_sub(1)),
|
||||
color::Bg(color::Rgb(0xFF, 0xCC, 0x00)),
|
||||
color::Fg(color::Rgb(0x11, 0x05, 0x00)),
|
||||
cpu.read(cpu.pc),
|
||||
color::Fg(color::Rgb(0xFF, 0xCC, 0x00)),
|
||||
color::Bg(color::Rgb(0x11, 0x05, 0x00)),
|
||||
cpu.read(cpu.pc.wrapping_add(1)),
|
||||
cpu.read(cpu.pc.wrapping_add(2)),
|
||||
cpu.read(cpu.pc.wrapping_add(3)),
|
||||
cpu.read(cpu.pc.wrapping_add(4)),
|
||||
cpu.read(cpu.pc.wrapping_add(5)),
|
||||
cpu.read(cpu.pc.wrapping_add(6)),
|
||||
cpu.read(cpu.pc.wrapping_add(7)),
|
||||
cpu.read(cpu.pc.wrapping_add(8)),
|
||||
);
|
||||
// scratchpad
|
||||
print!(
|
||||
"{} {:02x} {:02x} {:02x}",
|
||||
Goto(0, 34),
|
||||
cpu.read(0x200),
|
||||
cpu.read(0x201),
|
||||
cpu.read(0x202)
|
||||
)
|
||||
}
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
let cpu_state = format!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = cpu.a, x = cpu.x, y = cpu.y, pc = cpu.pc, s = cpu.s, p = cpu.p, irq = cpu.irq, nmi = cpu.nmi);
|
||||
console::log_1(&cpu_state.into());
|
||||
|
||||
let curr_instr = format!("instruction: {:?}, mode: {:?}", self.name, self.addr_mode);
|
||||
console::log_1(&curr_instr.into());
|
||||
|
||||
let local_mem = format!(
|
||||
"{:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} %c{:02x}%c {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}",
|
||||
cpu.read(cpu.pc.wrapping_sub(8)),
|
||||
cpu.read(cpu.pc.wrapping_sub(7)),
|
||||
cpu.read(cpu.pc.wrapping_sub(6)),
|
||||
cpu.read(cpu.pc.wrapping_sub(5)),
|
||||
cpu.read(cpu.pc.wrapping_sub(4)),
|
||||
cpu.read(cpu.pc.wrapping_sub(3)),
|
||||
cpu.read(cpu.pc.wrapping_sub(2)),
|
||||
cpu.read(cpu.pc.wrapping_sub(1)),
|
||||
cpu.read(cpu.pc),
|
||||
cpu.read(cpu.pc.wrapping_add(1)),
|
||||
cpu.read(cpu.pc.wrapping_add(2)),
|
||||
cpu.read(cpu.pc.wrapping_add(3)),
|
||||
cpu.read(cpu.pc.wrapping_add(4)),
|
||||
cpu.read(cpu.pc.wrapping_add(5)),
|
||||
cpu.read(cpu.pc.wrapping_add(6)),
|
||||
cpu.read(cpu.pc.wrapping_add(7)),
|
||||
cpu.read(cpu.pc.wrapping_add(8)),
|
||||
);
|
||||
console::log_3(
|
||||
&local_mem.into(),
|
||||
&"background: black; color: white".into(),
|
||||
&"background: unset; color: unset".into(),
|
||||
);
|
||||
|
||||
let scratchpad = format!(
|
||||
"scratchpad: {:02x} {:02x} {:02x}",
|
||||
cpu.read(0x200),
|
||||
cpu.read(0x201),
|
||||
cpu.read(0x202)
|
||||
);
|
||||
console::log_1(&scratchpad.into());
|
||||
} // idk if we should panic here, if we don't it's undefined behavior, which
|
||||
// might actually be what we want in the cases where it's an undocumented
|
||||
// 6502 instruction, but otherwise we should panic prolly, for now i'm just
|
||||
// gonna panic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -277,6 +209,7 @@ fn zero_page_indirect_indexed_with_y(
|
|||
let address = cpu.read_word(zp as u16);
|
||||
let address: u16 = address.wrapping_add(cpu.y as u16);
|
||||
cpu.pc = cpu.pc.wrapping_add(1);
|
||||
println!("{}indirect addr: {:#04x}", Goto(1, 39), address);
|
||||
address
|
||||
}
|
||||
|
||||
|
@ -322,7 +255,7 @@ fn branch(cpu: &mut Cpu, condition: bool, address: u16) {
|
|||
cpu.pc = cpu.pc.wrapping_add(1);
|
||||
}
|
||||
|
||||
fn breakpoint(cpu: &mut Cpu, _address: Option<u16>) {
|
||||
fn brkpt(cpu: &mut Cpu, address: Option<u16>) {
|
||||
cpu.breakpoint()
|
||||
}
|
||||
|
||||
|
@ -331,7 +264,7 @@ fn adc(cpu: &mut Cpu, address: Option<u16>) {
|
|||
let byte = cpu.read(address);
|
||||
let carry = cpu.get_flag(StatusFlag::Carry);
|
||||
let result = cpu.a as u16 + byte as u16 + carry as u16;
|
||||
cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::MAX));
|
||||
cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::max_value()));
|
||||
cpu.set_flag(StatusFlag::Zero, result as u8 == 0);
|
||||
cpu.set_flag(
|
||||
StatusFlag::Overflow,
|
||||
|
@ -853,7 +786,7 @@ fn sbc(cpu: &mut Cpu, address: Option<u16>) {
|
|||
let byte = cpu.read(address);
|
||||
let carry = cpu.get_flag(StatusFlag::Carry);
|
||||
let result = cpu.a as u16 + byte as u16 + !carry as u16;
|
||||
cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::MAX));
|
||||
cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::max_value()));
|
||||
cpu.set_flag(StatusFlag::Zero, result as u8 == 0);
|
||||
cpu.set_flag(
|
||||
StatusFlag::Overflow,
|
||||
|
@ -1015,7 +948,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 7,
|
||||
name: "brk",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(ora),
|
||||
|
@ -1025,18 +958,18 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
addr_mode: "zero_page_indexed_indirect",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(breakpoint),
|
||||
instr_fn: Some(brkpt),
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
name: "brkpt",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(tsb),
|
||||
|
@ -1071,7 +1004,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 3,
|
||||
name: "php",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(ora),
|
||||
|
@ -1092,7 +1025,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(tsb),
|
||||
|
@ -1148,7 +1081,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(trb),
|
||||
|
@ -1183,7 +1116,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "clc",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(ora),
|
||||
|
@ -1204,7 +1137,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(trb),
|
||||
|
@ -1253,14 +1186,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(bit),
|
||||
|
@ -1295,7 +1228,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 4,
|
||||
name: "plp",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(and),
|
||||
|
@ -1316,7 +1249,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(bit),
|
||||
|
@ -1372,7 +1305,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(bit),
|
||||
|
@ -1407,7 +1340,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "sec",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(and),
|
||||
|
@ -1428,7 +1361,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(bit),
|
||||
|
@ -1463,7 +1396,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 6,
|
||||
name: "rti",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(eor),
|
||||
|
@ -1477,21 +1410,21 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(eor),
|
||||
|
@ -1519,7 +1452,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 3,
|
||||
name: "pha",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(eor),
|
||||
|
@ -1540,7 +1473,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(jmp),
|
||||
|
@ -1596,14 +1529,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(eor),
|
||||
|
@ -1631,7 +1564,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "cli",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(eor),
|
||||
|
@ -1645,21 +1578,21 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 3,
|
||||
name: "phy",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(eor),
|
||||
|
@ -1687,7 +1620,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 6,
|
||||
name: "rts",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(adc),
|
||||
|
@ -1701,14 +1634,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(stz),
|
||||
|
@ -1743,7 +1676,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 4,
|
||||
name: "pla",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(adc),
|
||||
|
@ -1764,7 +1697,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(jmp),
|
||||
|
@ -1820,7 +1753,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(stz),
|
||||
|
@ -1855,7 +1788,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "sei",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(adc),
|
||||
|
@ -1869,14 +1802,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 4,
|
||||
name: "ply",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(jmp),
|
||||
|
@ -1925,14 +1858,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(sty),
|
||||
|
@ -1967,7 +1900,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "dey",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(bit),
|
||||
|
@ -1981,14 +1914,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "txa",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(sty),
|
||||
|
@ -2044,7 +1977,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(sty),
|
||||
|
@ -2079,7 +2012,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "tya",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(sta),
|
||||
|
@ -2093,14 +2026,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "txs",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(stz),
|
||||
|
@ -2156,7 +2089,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(ldy),
|
||||
|
@ -2191,7 +2124,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "tay",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(lda),
|
||||
|
@ -2205,14 +2138,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "tax",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(ldy),
|
||||
|
@ -2268,7 +2201,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(ldy),
|
||||
|
@ -2303,7 +2236,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "clv",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(lda),
|
||||
|
@ -2317,14 +2250,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "tsx",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(ldy),
|
||||
|
@ -2373,14 +2306,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(cpy),
|
||||
|
@ -2415,7 +2348,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "iny",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(cmp),
|
||||
|
@ -2429,14 +2362,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "dex",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(wai),
|
||||
address_fn: None,
|
||||
cycles: 3,
|
||||
name: "wai",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(cpy),
|
||||
|
@ -2492,14 +2425,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(cmp),
|
||||
|
@ -2527,7 +2460,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "cld",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(cmp),
|
||||
|
@ -2541,21 +2474,21 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 3,
|
||||
name: "phx",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(stp),
|
||||
address_fn: None,
|
||||
cycles: 3,
|
||||
name: "stp",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(cmp),
|
||||
|
@ -2597,14 +2530,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(cpx),
|
||||
|
@ -2639,7 +2572,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "inx",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(sbc),
|
||||
|
@ -2653,14 +2586,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "nop",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(cpx),
|
||||
|
@ -2716,14 +2649,14 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(sbc),
|
||||
|
@ -2751,7 +2684,7 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 2,
|
||||
name: "sed",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(sbc),
|
||||
|
@ -2765,21 +2698,21 @@ pub const OPCODES: [Instruction; 256] = [
|
|||
address_fn: None,
|
||||
cycles: 4,
|
||||
name: "plx",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: None,
|
||||
address_fn: None,
|
||||
cycles: 0,
|
||||
name: "none",
|
||||
addr_mode: "implied",
|
||||
addr_mode: "none",
|
||||
},
|
||||
Instruction {
|
||||
instr_fn: Some(sbc),
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
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,
|
||||
}
|
||||
|
@ -16,7 +13,6 @@ impl Keyboard {
|
|||
Self { memory }
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub fn clear_keys(&self) {
|
||||
self.memory.write(0x4400, 0x00);
|
||||
self.memory.write(0x4401, 0x00);
|
||||
|
@ -26,7 +22,6 @@ impl Keyboard {
|
|||
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;
|
||||
|
|
252
src/lib.rs
252
src/lib.rs
|
@ -1,252 +0,0 @@
|
|||
pub mod cpu;
|
||||
mod instructions;
|
||||
mod keyboard;
|
||||
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,
|
||||
}
|
||||
}
|
||||
// pub fn window(self, mut window: Window) -> GeorgeEmuBuilder<NoRom, SomeWindow> {
|
||||
// let Self {
|
||||
// rom,
|
||||
// cpu,
|
||||
// ref cpu_controller,
|
||||
// ref memory_handle,
|
||||
// keyboard,
|
||||
// ..
|
||||
// } = 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),
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
#[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,
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub fn build(self) -> GeorgeEmu {
|
||||
GeorgeEmu(imp::GeorgeEmu::new(
|
||||
self.cpu.unwrap(),
|
||||
self.renderer.unwrap(),
|
||||
self.window.0,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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,
|
||||
))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
mod cli;
|
||||
mod cpu;
|
||||
mod error;
|
||||
mod instructions;
|
||||
mod keyboard;
|
||||
mod memory;
|
||||
mod types;
|
||||
mod video;
|
||||
|
||||
use crate::cpu::Cpu;
|
||||
use crate::keyboard::Keyboard;
|
||||
use crate::memory::Mem;
|
||||
use crate::video::Screen;
|
||||
|
||||
use cli::get_input;
|
||||
use crossterm::cursor;
|
||||
use memory::MemHandle;
|
||||
use std::io::stdout;
|
||||
use std::thread::{self, sleep};
|
||||
use std::time::Duration;
|
||||
use termion::cursor::Goto;
|
||||
use termion::event::Key;
|
||||
use termion::input::TermRead;
|
||||
use termion::raw::IntoRawMode;
|
||||
use termion::{async_stdin, clear};
|
||||
|
||||
fn main() {
|
||||
let _stdout = stdout().into_raw_mode();
|
||||
let config = get_input();
|
||||
|
||||
let mut memory = Mem::new();
|
||||
let _ = memory.load_rom(&config.rom);
|
||||
|
||||
let shared_memory = MemHandle::new(memory);
|
||||
let screen_memory = shared_memory.clone();
|
||||
let cpu_memory = shared_memory.clone();
|
||||
let keyboard_memory = shared_memory.clone();
|
||||
|
||||
let keyboard = Keyboard::new(keyboard_memory);
|
||||
|
||||
let (mut cpu, cpu_controller) = Cpu::new_with_control(cpu_memory);
|
||||
cpu.reset();
|
||||
|
||||
thread::spawn(move || loop {
|
||||
cpu.cycle();
|
||||
});
|
||||
|
||||
let screen_remote = cpu_controller.clone();
|
||||
|
||||
let mut screen = Screen::new(&config, screen_remote, screen_memory);
|
||||
|
||||
let mut stdin = async_stdin().keys();
|
||||
print!("{}{}", cursor::Hide, clear::All,);
|
||||
|
||||
loop {
|
||||
screen.draw();
|
||||
if let Some(Ok(key)) = stdin.next() {
|
||||
keyboard.read_keys(key);
|
||||
match key {
|
||||
Key::Char('q') => {
|
||||
break;
|
||||
}
|
||||
Key::Char('`') => cpu_controller.toggle(),
|
||||
Key::Char('\n') => cpu_controller.cycle(),
|
||||
Key::Char('i') => cpu_controller.irq(),
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
keyboard.clear_keys();
|
||||
}
|
||||
sleep(Duration::from_millis(16));
|
||||
}
|
||||
print!("{}{}{}", clear::All, cursor::Show, Goto(1, 1));
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
use anyhow::{bail, Result};
|
||||
use core::panic;
|
||||
use std::cell::RefCell;
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::exit;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{fs::File, io::Read};
|
||||
|
@ -12,11 +16,11 @@ impl MemHandle {
|
|||
Self(Arc::new(Mutex::new(memory)))
|
||||
}
|
||||
pub fn read(&self, address: u16) -> u8 {
|
||||
let memory = self.0.try_lock().unwrap();
|
||||
let memory = self.0.lock().unwrap();
|
||||
memory.read(address)
|
||||
}
|
||||
pub fn write(&self, address: u16, data: u8) {
|
||||
let mut memory = self.0.try_lock().unwrap();
|
||||
let mut memory = self.0.lock().unwrap();
|
||||
memory.write(address, data);
|
||||
}
|
||||
|
||||
|
@ -47,23 +51,13 @@ pub struct Mem([u8; 0x10000]);
|
|||
|
||||
impl Default for Mem {
|
||||
fn default() -> Self {
|
||||
let bytes = include_bytes!("./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)
|
||||
Self([0; 0x10000])
|
||||
}
|
||||
}
|
||||
|
||||
impl Mem {
|
||||
pub fn new() -> Self {
|
||||
Self([0; 0x10000])
|
||||
Mem::default()
|
||||
}
|
||||
pub fn dump(&self, path: PathBuf) -> io::Result<()> {
|
||||
let mut outfile = File::create(path)?;
|
||||
|
@ -103,22 +97,16 @@ impl Mem {
|
|||
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(())
|
||||
}
|
||||
//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, value),
|
||||
// Err(_) => {
|
||||
// bail!("couldn't write byte {:#04x}", address);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Ok(())
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub mod native;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub mod wasm;
|
|
@ -1,101 +0,0 @@
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
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()
|
||||
}
|
||||
}
|
|
@ -1,237 +0,0 @@
|
|||
; .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:
|
||||
.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.
|
@ -0,0 +1,4 @@
|
|||
use std::{u16, u8};
|
||||
|
||||
pub type Byte = u8;
|
||||
pub type Word = u16;
|
244
src/video.rs
244
src/video.rs
|
@ -1,52 +1,133 @@
|
|||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use std::io::{self, Write};
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use minifb::{Scale, ScaleMode, Window, WindowOptions};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use termion::{
|
||||
color::{self, Bg, Fg},
|
||||
color::{self, Bg, Color, Fg},
|
||||
cursor::Goto,
|
||||
screen::IntoAlternateScreen,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
cli::Config,
|
||||
cpu::CpuController,
|
||||
keyboard::Keyboard,
|
||||
memory::{MemHandle, MemoryReader},
|
||||
types::{Byte, Word},
|
||||
};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, Read, Write},
|
||||
path::Path,
|
||||
process::exit,
|
||||
thread::sleep,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
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"),
|
||||
// }
|
||||
// }
|
||||
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!("./roms/cozette.rom");
|
||||
trait Renderer {
|
||||
fn render(&mut self) {}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
const ASCII_LOOKUP: [&str; 256] = [
|
||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||
pub enum ScreenType {
|
||||
Window,
|
||||
#[default]
|
||||
Terminal,
|
||||
}
|
||||
|
||||
pub struct WindowRenderer {
|
||||
char_rom: [u8; 0x8000],
|
||||
window: Window,
|
||||
memory: MemHandle,
|
||||
}
|
||||
|
||||
impl WindowRenderer {
|
||||
pub fn new<P>(memory: MemHandle, char_rom: Option<P>, window: Window) -> Self
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let char_rom = get_char_bin(char_rom);
|
||||
Self {
|
||||
memory,
|
||||
window,
|
||||
char_rom,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for WindowRenderer {
|
||||
fn render(&mut self) {
|
||||
// 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; 512 * 380];
|
||||
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 = self.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.window
|
||||
.update_with_buffer(&buffer, WIDTH, HEIGHT)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoryReader for WindowRenderer {
|
||||
fn read(&self, address: Word) -> Byte {
|
||||
self.memory.read(address)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TerminalRenderer {
|
||||
memory: MemHandle,
|
||||
}
|
||||
|
||||
impl TerminalRenderer {
|
||||
pub fn new(memory: MemHandle) -> Self {
|
||||
Self { memory }
|
||||
}
|
||||
}
|
||||
|
||||
impl MemoryReader for TerminalRenderer {
|
||||
fn read(&self, address: Word) -> Byte {
|
||||
self.memory.read(address)
|
||||
}
|
||||
}
|
||||
|
||||
const ASCII_LOOPUP: [&str; 256] = [
|
||||
" ", "░", "▒", "▓", "♡", "♥", "⭐", "✭", "", "✦", "✨", "♀", "♂", "⚢", "⚣", "⚥", "♩", "♪",
|
||||
"♫", "♬", "ﱝ", "", "", "", "奄", "奔", "婢", "ﱜ", "ﱛ", "", "", "", " ", "!", "\"", "#",
|
||||
"$", "%", "&", "\'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6",
|
||||
|
@ -63,55 +144,15 @@ const ASCII_LOOKUP: [&str; 256] = [
|
|||
"", "", "", "", "🎁", "", "", "", "", "⚐", "⚑", "", "", "",
|
||||
];
|
||||
|
||||
#[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"))]
|
||||
{
|
||||
impl Renderer for TerminalRenderer {
|
||||
fn render(&mut self) {
|
||||
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 char = ASCII_LOOPUP[ascii as usize];
|
||||
let _ = write!(
|
||||
// FG_COLOR = 0xFFCC00
|
||||
// BG_COLOR = 0x110500
|
||||
|
@ -125,13 +166,52 @@ impl Renderer {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.controller.irq();
|
||||
}
|
||||
|
||||
pub struct Screen {
|
||||
renderer: Box<dyn Renderer>,
|
||||
controller: CpuController,
|
||||
}
|
||||
|
||||
impl MemoryReader for Renderer {
|
||||
fn read(&self, address: u16) -> u8 {
|
||||
self.memory.read(address)
|
||||
impl Screen {
|
||||
pub fn new(config: &Config, controller: CpuController, memory: MemHandle) -> Self {
|
||||
let renderer: Box<dyn Renderer> = match config.screen {
|
||||
ScreenType::Window => {
|
||||
let mut 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();
|
||||
window.set_input_callback(Box::new(Keyboard::new(memory.clone())));
|
||||
Box::new(WindowRenderer::new(memory, config.char_rom.clone(), window))
|
||||
}
|
||||
ScreenType::Terminal => Box::new(TerminalRenderer::new(memory)),
|
||||
};
|
||||
|
||||
Self {
|
||||
renderer,
|
||||
controller,
|
||||
}
|
||||
}
|
||||
pub fn draw(&mut self) {
|
||||
self.controller.irq();
|
||||
self.renderer.render();
|
||||
}
|
||||
|
||||
// pub fn run(&mut self) {
|
||||
// loop {
|
||||
// // sleep(Duration::from_millis(16));
|
||||
// self.draw();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue