Very messy but we're running on the web now! (not in this crate, but will add web-sys to georgeemu bin in a bit)
This commit is contained in:
		
							parent
							
								
									c2aef4f249
								
							
						
					
					
						commit
						8ac0cbc57b
					
				| 
						 | 
				
			
			@ -14,31 +14,6 @@ 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"
 | 
			
		||||
| 
						 | 
				
			
			@ -70,28 +45,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		|||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "crossterm"
 | 
			
		||||
version = "0.27.0"
 | 
			
		||||
name = "console_error_panic_hook"
 | 
			
		||||
version = "0.1.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
 | 
			
		||||
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "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",
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +82,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		|||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "libc",
 | 
			
		||||
 "windows-sys 0.52.0",
 | 
			
		||||
 "windows-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
| 
						 | 
				
			
			@ -225,8 +185,7 @@ name = "georgeemu"
 | 
			
		|||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "bdf",
 | 
			
		||||
 "crossterm",
 | 
			
		||||
 "console_error_panic_hook",
 | 
			
		||||
 "minifb",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "termion",
 | 
			
		||||
| 
						 | 
				
			
			@ -261,6 +220,12 @@ 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.69"
 | 
			
		||||
| 
						 | 
				
			
			@ -289,7 +254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		|||
checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "windows-targets 0.52.5",
 | 
			
		||||
 "windows-targets",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
| 
						 | 
				
			
			@ -300,7 +265,7 @@ checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607"
 | 
			
		|||
dependencies = [
 | 
			
		||||
 "bitflags 2.5.0",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "redox_syscall 0.4.1",
 | 
			
		||||
 "redox_syscall",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
| 
						 | 
				
			
			@ -309,16 +274,6 @@ 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"
 | 
			
		||||
| 
						 | 
				
			
			@ -343,10 +298,9 @@ dependencies = [
 | 
			
		|||
[[package]]
 | 
			
		||||
name = "minifb"
 | 
			
		||||
version = "0.27.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b0c470a74618b43cd182c21b3dc1e6123501249f3bad9a0085e95d1304ca2478"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cc",
 | 
			
		||||
 "console_error_panic_hook",
 | 
			
		||||
 "dlib",
 | 
			
		||||
 "futures",
 | 
			
		||||
 "instant",
 | 
			
		||||
| 
						 | 
				
			
			@ -358,26 +312,16 @@ 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"
 | 
			
		||||
| 
						 | 
				
			
			@ -414,29 +358,6 @@ 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"
 | 
			
		||||
| 
						 | 
				
			
			@ -488,15 +409,6 @@ 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"
 | 
			
		||||
| 
						 | 
				
			
			@ -513,21 +425,21 @@ dependencies = [
 | 
			
		|||
 "errno",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "linux-raw-sys",
 | 
			
		||||
 "windows-sys 0.52.0",
 | 
			
		||||
 "windows-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[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"
 | 
			
		||||
| 
						 | 
				
			
			@ -571,6 +483,18 @@ 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"
 | 
			
		||||
| 
						 | 
				
			
			@ -580,36 +504,6 @@ 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"
 | 
			
		||||
| 
						 | 
				
			
			@ -645,7 +539,7 @@ dependencies = [
 | 
			
		|||
 "cfg-if",
 | 
			
		||||
 "fastrand",
 | 
			
		||||
 "rustix",
 | 
			
		||||
 "windows-sys 0.52.0",
 | 
			
		||||
 "windows-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
| 
						 | 
				
			
			@ -660,26 +554,6 @@ 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"
 | 
			
		||||
| 
						 | 
				
			
			@ -726,12 +600,6 @@ version = "0.1.1"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "wasi"
 | 
			
		||||
version = "0.11.0+wasi-snapshot-preview1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "wasm-bindgen"
 | 
			
		||||
version = "0.2.92"
 | 
			
		||||
| 
						 | 
				
			
			@ -739,6 +607,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		|||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "wasm-bindgen-macro",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -903,37 +773,13 @@ 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.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",
 | 
			
		||||
 "windows-targets",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
| 
						 | 
				
			
			@ -942,46 +788,28 @@ version = "0.52.5"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows_aarch64_gnullvm 0.52.5",
 | 
			
		||||
 "windows_aarch64_msvc 0.52.5",
 | 
			
		||||
 "windows_i686_gnu 0.52.5",
 | 
			
		||||
 "windows_aarch64_gnullvm",
 | 
			
		||||
 "windows_aarch64_msvc",
 | 
			
		||||
 "windows_i686_gnu",
 | 
			
		||||
 "windows_i686_gnullvm",
 | 
			
		||||
 "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",
 | 
			
		||||
 "windows_i686_msvc",
 | 
			
		||||
 "windows_x86_64_gnu",
 | 
			
		||||
 "windows_x86_64_gnullvm",
 | 
			
		||||
 "windows_x86_64_msvc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[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"
 | 
			
		||||
| 
						 | 
				
			
			@ -994,48 +822,24 @@ 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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										26
									
								
								Cargo.toml
								
								
								
								
							
							
						
						
									
										26
									
								
								Cargo.toml
								
								
								
								
							| 
						 | 
				
			
			@ -3,15 +3,29 @@ name = "georgeemu"
 | 
			
		|||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
[features]
 | 
			
		||||
debug = []
 | 
			
		||||
term = []
 | 
			
		||||
web = ["minifb/web"]
 | 
			
		||||
 | 
			
		||||
[[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"
 | 
			
		||||
bdf = "0.6.0"
 | 
			
		||||
crossterm = "0.27.0"
 | 
			
		||||
minifb = "0.27.0"
 | 
			
		||||
# minifb = "0.25.0"
 | 
			
		||||
# ratatui = "0.26.3"
 | 
			
		||||
console_error_panic_hook = "0.1.7"
 | 
			
		||||
# minifb = { git = "https://github.com/augustkline/rust_minifb" }
 | 
			
		||||
minifb = { path = "/Users/august/projects/rust_minifb_fork/" }
 | 
			
		||||
serde = { version = "1.0.197", features = ["serde_derive", "derive"] }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
 | 
			
		||||
termion = "4.0.2"
 | 
			
		||||
toml = "0.8.12"
 | 
			
		||||
toml = { version = "0.8.12" }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,3 @@
 | 
			
		|||
char_rom = "./src/roms/cozette.rom"
 | 
			
		||||
rom = "./src/roms/george.rom"
 | 
			
		||||
rom = "./src/roms/demo.rom"
 | 
			
		||||
screen = "Window"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										2
									
								
								run.sh
								
								
								
								
							
							
						
						
									
										2
									
								
								run.sh
								
								
								
								
							| 
						 | 
				
			
			@ -8,5 +8,5 @@ fi
 | 
			
		|||
set -e
 | 
			
		||||
 | 
			
		||||
vasm6502_oldstyle ./src/roms/$1.asm -dotdir -wdc02 -ldots -Fbin -o ./src/roms/$1.rom;
 | 
			
		||||
cargo run -- rom "./src/roms/$1.rom";
 | 
			
		||||
cargo run --features debug -- rom "./src/roms/$1.rom";
 | 
			
		||||
# hexdump -C ./cpu_dump.bin;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,14 +1,13 @@
 | 
			
		|||
use std::{
 | 
			
		||||
    env,
 | 
			
		||||
    default, env,
 | 
			
		||||
    fs::File,
 | 
			
		||||
    io::{ErrorKind, Read},
 | 
			
		||||
    process::exit,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use georgeemu::{Config, ScreenType};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use crate::video::ScreenType;
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Deserialize, Debug)]
 | 
			
		||||
struct ConfigBuilder {
 | 
			
		||||
    rom: Option<String>,
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +26,7 @@ impl ConfigBuilder {
 | 
			
		|||
 | 
			
		||||
    fn build(self) -> Config {
 | 
			
		||||
        let rom = match self.rom {
 | 
			
		||||
            Some(rom) => rom,
 | 
			
		||||
            Some(rom) => Some(rom),
 | 
			
		||||
            None => {
 | 
			
		||||
                println!("no rom was provided :(");
 | 
			
		||||
                exit(1);
 | 
			
		||||
| 
						 | 
				
			
			@ -44,12 +43,6 @@ 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 {
 | 
			
		||||
| 
						 | 
				
			
			@ -101,6 +94,7 @@ 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);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
mod cli;
 | 
			
		||||
 | 
			
		||||
use cli::get_input;
 | 
			
		||||
use georgeemu::GeorgeEmu;
 | 
			
		||||
use minifb::{Scale, ScaleMode, Window, WindowOptions};
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    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();
 | 
			
		||||
    let config = get_input();
 | 
			
		||||
    #[cfg(not(feature = "term"))]
 | 
			
		||||
    let mut emu = GeorgeEmu::builder()
 | 
			
		||||
        .window(&mut window)
 | 
			
		||||
        .rom("/Users/august/projects/george-emu/src/roms/demo.rom")
 | 
			
		||||
        .build();
 | 
			
		||||
    #[cfg(feature = "term")]
 | 
			
		||||
    let mut emu = GeorgeEmu::builder().build();
 | 
			
		||||
    emu.run();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								src/cpu.rs
								
								
								
								
							
							
						
						
									
										104
									
								
								src/cpu.rs
								
								
								
								
							| 
						 | 
				
			
			@ -5,8 +5,6 @@ use std::sync::mpsc::{channel, Receiver, Sender};
 | 
			
		|||
use std::thread::sleep;
 | 
			
		||||
use std::time::Duration;
 | 
			
		||||
 | 
			
		||||
use termion::cursor::Goto;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy)]
 | 
			
		||||
pub enum StatusFlag {
 | 
			
		||||
    Negative = 0b1000_0000,
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +17,7 @@ pub enum StatusFlag {
 | 
			
		|||
    Carry = 0b0000_0001,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct CpuController(Sender<CpuControl>);
 | 
			
		||||
 | 
			
		||||
pub enum CpuControl {
 | 
			
		||||
| 
						 | 
				
			
			@ -51,6 +49,7 @@ impl CpuController {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct CpuReceiver(Receiver<CpuControl>);
 | 
			
		||||
impl CpuReceiver {
 | 
			
		||||
    pub fn new(receiver: Receiver<CpuControl>) -> Self {
 | 
			
		||||
| 
						 | 
				
			
			@ -58,6 +57,7 @@ impl CpuReceiver {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct Cpu {
 | 
			
		||||
    pub a: u8,   // Accumulator Register
 | 
			
		||||
    pub x: u8,   // X Register
 | 
			
		||||
| 
						 | 
				
			
			@ -71,8 +71,7 @@ pub struct Cpu {
 | 
			
		|||
    pub pending_cycles: usize,
 | 
			
		||||
    receiver: Option<CpuReceiver>,
 | 
			
		||||
    stopped: bool,
 | 
			
		||||
    cycle: bool, // cycle_count: usize,
 | 
			
		||||
                 // state_tx: Sender<CpuState>,
 | 
			
		||||
    cycle: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Display for Cpu {
 | 
			
		||||
| 
						 | 
				
			
			@ -94,7 +93,6 @@ impl MemoryWriter for Cpu {
 | 
			
		|||
 | 
			
		||||
impl Cpu {
 | 
			
		||||
    pub fn new(memory: MemHandle) -> Self {
 | 
			
		||||
        // pub fn new(memory: MemHandle) -> Self {
 | 
			
		||||
        Cpu {
 | 
			
		||||
            a: 0x00,
 | 
			
		||||
            x: 0x00,
 | 
			
		||||
| 
						 | 
				
			
			@ -179,13 +177,6 @@ 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!()
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -198,6 +189,10 @@ 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,19 +208,21 @@ impl Cpu {
 | 
			
		|||
                        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(),
 | 
			
		||||
                    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 => {}
 | 
			
		||||
| 
						 | 
				
			
			@ -233,64 +230,33 @@ impl Cpu {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn cycle(&mut self) {
 | 
			
		||||
        self.receive_control();
 | 
			
		||||
        // self.receive_control();
 | 
			
		||||
 | 
			
		||||
        if self.stopped & !self.cycle {
 | 
			
		||||
            self.set_flag(StatusFlag::IrqDisable, true);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        self.cycle = false;
 | 
			
		||||
        // if self.stopped & !self.cycle {
 | 
			
		||||
        //     self.set_flag(StatusFlag::IrqDisable, true);
 | 
			
		||||
        //     return;
 | 
			
		||||
        // }
 | 
			
		||||
        // self.cycle = false;
 | 
			
		||||
 | 
			
		||||
        #[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();
 | 
			
		||||
        }
 | 
			
		||||
        // if !self.get_flag(StatusFlag::IrqDisable) && self.irq {
 | 
			
		||||
        //     self.interrupt();
 | 
			
		||||
        // }
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(feature = "debug")]
 | 
			
		||||
    pub fn breakpoint(&mut 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!("");
 | 
			
		||||
        // 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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,7 @@
 | 
			
		|||
#![allow(clippy::upper_case_acronyms)]
 | 
			
		||||
 | 
			
		||||
use core::panic;
 | 
			
		||||
use std::process::exit;
 | 
			
		||||
 | 
			
		||||
use termion::cursor::Goto;
 | 
			
		||||
use termion::{clear, color};
 | 
			
		||||
#[cfg(feature = "debug")]
 | 
			
		||||
use termion::{clear, color, cursor::Goto};
 | 
			
		||||
 | 
			
		||||
use crate::cpu::{Cpu, StatusFlag};
 | 
			
		||||
use crate::memory::{MemoryReader, MemoryWriter};
 | 
			
		||||
| 
						 | 
				
			
			@ -23,47 +20,12 @@ pub struct Instruction<'a> {
 | 
			
		|||
 | 
			
		||||
impl Instruction<'_> {
 | 
			
		||||
    pub fn call(&self, cpu: &mut 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)),
 | 
			
		||||
        // );
 | 
			
		||||
        #[cfg(feature = "debug")]
 | 
			
		||||
        self.debug(cpu);
 | 
			
		||||
 | 
			
		||||
        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) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -82,17 +44,75 @@ impl Instruction<'_> {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
            None => {
 | 
			
		||||
                panic!(
 | 
			
		||||
                    "An invalid instruction was called at {:04x}, with opcode {:02x}",
 | 
			
		||||
                    cpu.pc,
 | 
			
		||||
                    cpu.read(cpu.pc)
 | 
			
		||||
                )
 | 
			
		||||
            } // 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
 | 
			
		||||
                #[cfg(feature = "debug")]
 | 
			
		||||
                {
 | 
			
		||||
                    println!(
 | 
			
		||||
                        "{}An invalid instruction was called at {:04x}, with opcode {:02x}",
 | 
			
		||||
                        Goto(0, 35),
 | 
			
		||||
                        cpu.pc,
 | 
			
		||||
                        cpu.read(cpu.pc)
 | 
			
		||||
                    );
 | 
			
		||||
                    cpu.breakpoint();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(feature = "debug")]
 | 
			
		||||
    fn debug(&self, cpu: &Cpu) {
 | 
			
		||||
        // 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)
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn accumulator(cpu: &mut Cpu) -> u16 {
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +229,6 @@ 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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -255,7 +274,8 @@ fn branch(cpu: &mut Cpu, condition: bool, address: u16) {
 | 
			
		|||
    cpu.pc = cpu.pc.wrapping_add(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn brkpt(cpu: &mut Cpu, address: Option<u16>) {
 | 
			
		||||
#[cfg(feature = "debug")]
 | 
			
		||||
fn breakpoint(cpu: &mut Cpu, _address: Option<u16>) {
 | 
			
		||||
    cpu.breakpoint()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -264,7 +284,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_value()));
 | 
			
		||||
    cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::MAX));
 | 
			
		||||
    cpu.set_flag(StatusFlag::Zero, result as u8 == 0);
 | 
			
		||||
    cpu.set_flag(
 | 
			
		||||
        StatusFlag::Overflow,
 | 
			
		||||
| 
						 | 
				
			
			@ -786,7 +806,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_value()));
 | 
			
		||||
    cpu.set_flag(StatusFlag::Carry, result > u16::from(u8::MAX));
 | 
			
		||||
    cpu.set_flag(StatusFlag::Zero, result as u8 == 0);
 | 
			
		||||
    cpu.set_flag(
 | 
			
		||||
        StatusFlag::Overflow,
 | 
			
		||||
| 
						 | 
				
			
			@ -948,7 +968,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 7,
 | 
			
		||||
        name: "brk",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(ora),
 | 
			
		||||
| 
						 | 
				
			
			@ -958,18 +978,24 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        addr_mode: "zero_page_indexed_indirect",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(brkpt),
 | 
			
		||||
        #[cfg(feature = "debug")]
 | 
			
		||||
        instr_fn: Some(breakpoint),
 | 
			
		||||
        #[cfg(not(feature = "debug"))]
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "brkpt",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        #[cfg(not(feature = "debug"))]
 | 
			
		||||
        name: "none",
 | 
			
		||||
        #[cfg(feature = "debug")]
 | 
			
		||||
        name: "breakpoint",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(tsb),
 | 
			
		||||
| 
						 | 
				
			
			@ -1004,7 +1030,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 3,
 | 
			
		||||
        name: "php",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(ora),
 | 
			
		||||
| 
						 | 
				
			
			@ -1025,7 +1051,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(tsb),
 | 
			
		||||
| 
						 | 
				
			
			@ -1081,7 +1107,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(trb),
 | 
			
		||||
| 
						 | 
				
			
			@ -1116,7 +1142,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "clc",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(ora),
 | 
			
		||||
| 
						 | 
				
			
			@ -1137,7 +1163,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(trb),
 | 
			
		||||
| 
						 | 
				
			
			@ -1186,14 +1212,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(bit),
 | 
			
		||||
| 
						 | 
				
			
			@ -1228,7 +1254,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 4,
 | 
			
		||||
        name: "plp",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(and),
 | 
			
		||||
| 
						 | 
				
			
			@ -1249,7 +1275,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(bit),
 | 
			
		||||
| 
						 | 
				
			
			@ -1305,7 +1331,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(bit),
 | 
			
		||||
| 
						 | 
				
			
			@ -1340,7 +1366,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "sec",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(and),
 | 
			
		||||
| 
						 | 
				
			
			@ -1361,7 +1387,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(bit),
 | 
			
		||||
| 
						 | 
				
			
			@ -1396,7 +1422,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 6,
 | 
			
		||||
        name: "rti",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(eor),
 | 
			
		||||
| 
						 | 
				
			
			@ -1410,21 +1436,21 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(eor),
 | 
			
		||||
| 
						 | 
				
			
			@ -1452,7 +1478,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 3,
 | 
			
		||||
        name: "pha",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(eor),
 | 
			
		||||
| 
						 | 
				
			
			@ -1473,7 +1499,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(jmp),
 | 
			
		||||
| 
						 | 
				
			
			@ -1529,14 +1555,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(eor),
 | 
			
		||||
| 
						 | 
				
			
			@ -1564,7 +1590,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "cli",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(eor),
 | 
			
		||||
| 
						 | 
				
			
			@ -1578,21 +1604,21 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 3,
 | 
			
		||||
        name: "phy",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(eor),
 | 
			
		||||
| 
						 | 
				
			
			@ -1620,7 +1646,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 6,
 | 
			
		||||
        name: "rts",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(adc),
 | 
			
		||||
| 
						 | 
				
			
			@ -1634,14 +1660,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(stz),
 | 
			
		||||
| 
						 | 
				
			
			@ -1676,7 +1702,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 4,
 | 
			
		||||
        name: "pla",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(adc),
 | 
			
		||||
| 
						 | 
				
			
			@ -1697,7 +1723,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(jmp),
 | 
			
		||||
| 
						 | 
				
			
			@ -1753,7 +1779,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(stz),
 | 
			
		||||
| 
						 | 
				
			
			@ -1788,7 +1814,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "sei",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(adc),
 | 
			
		||||
| 
						 | 
				
			
			@ -1802,14 +1828,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 4,
 | 
			
		||||
        name: "ply",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(jmp),
 | 
			
		||||
| 
						 | 
				
			
			@ -1858,14 +1884,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(sty),
 | 
			
		||||
| 
						 | 
				
			
			@ -1900,7 +1926,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "dey",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(bit),
 | 
			
		||||
| 
						 | 
				
			
			@ -1914,14 +1940,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "txa",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(sty),
 | 
			
		||||
| 
						 | 
				
			
			@ -1977,7 +2003,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(sty),
 | 
			
		||||
| 
						 | 
				
			
			@ -2012,7 +2038,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "tya",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(sta),
 | 
			
		||||
| 
						 | 
				
			
			@ -2026,14 +2052,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "txs",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(stz),
 | 
			
		||||
| 
						 | 
				
			
			@ -2089,7 +2115,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(ldy),
 | 
			
		||||
| 
						 | 
				
			
			@ -2124,7 +2150,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "tay",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(lda),
 | 
			
		||||
| 
						 | 
				
			
			@ -2138,14 +2164,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "tax",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(ldy),
 | 
			
		||||
| 
						 | 
				
			
			@ -2201,7 +2227,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(ldy),
 | 
			
		||||
| 
						 | 
				
			
			@ -2236,7 +2262,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "clv",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(lda),
 | 
			
		||||
| 
						 | 
				
			
			@ -2250,14 +2276,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "tsx",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(ldy),
 | 
			
		||||
| 
						 | 
				
			
			@ -2306,14 +2332,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(cpy),
 | 
			
		||||
| 
						 | 
				
			
			@ -2348,7 +2374,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "iny",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(cmp),
 | 
			
		||||
| 
						 | 
				
			
			@ -2362,14 +2388,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "dex",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(wai),
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 3,
 | 
			
		||||
        name: "wai",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(cpy),
 | 
			
		||||
| 
						 | 
				
			
			@ -2425,14 +2451,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(cmp),
 | 
			
		||||
| 
						 | 
				
			
			@ -2460,7 +2486,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "cld",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(cmp),
 | 
			
		||||
| 
						 | 
				
			
			@ -2474,21 +2500,21 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 3,
 | 
			
		||||
        name: "phx",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(stp),
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 3,
 | 
			
		||||
        name: "stp",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(cmp),
 | 
			
		||||
| 
						 | 
				
			
			@ -2530,14 +2556,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(cpx),
 | 
			
		||||
| 
						 | 
				
			
			@ -2572,7 +2598,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "inx",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(sbc),
 | 
			
		||||
| 
						 | 
				
			
			@ -2586,14 +2612,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "nop",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(cpx),
 | 
			
		||||
| 
						 | 
				
			
			@ -2649,14 +2675,14 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(sbc),
 | 
			
		||||
| 
						 | 
				
			
			@ -2684,7 +2710,7 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 2,
 | 
			
		||||
        name: "sed",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(sbc),
 | 
			
		||||
| 
						 | 
				
			
			@ -2698,21 +2724,21 @@ pub const OPCODES: [Instruction; 256] = [
 | 
			
		|||
        address_fn: None,
 | 
			
		||||
        cycles: 4,
 | 
			
		||||
        name: "plx",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: None,
 | 
			
		||||
        address_fn: None,
 | 
			
		||||
        cycles: 0,
 | 
			
		||||
        name: "none",
 | 
			
		||||
        addr_mode: "none",
 | 
			
		||||
        addr_mode: "implied",
 | 
			
		||||
    },
 | 
			
		||||
    Instruction {
 | 
			
		||||
        instr_fn: Some(sbc),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,12 @@
 | 
			
		|||
use minifb::InputCallback;
 | 
			
		||||
use minifb::Key as MKey;
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "term")]
 | 
			
		||||
use termion::event::Key;
 | 
			
		||||
 | 
			
		||||
use crate::memory::{MemHandle, MemoryWriter};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub struct Keyboard {
 | 
			
		||||
    memory: MemHandle,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +25,7 @@ impl Keyboard {
 | 
			
		|||
        self.memory.write(0x4405, 0x00);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(feature = "term")]
 | 
			
		||||
    pub fn read_keys(&self, key: Key) {
 | 
			
		||||
        let mut row0 = 0;
 | 
			
		||||
        let mut row1 = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,271 @@
 | 
			
		|||
pub mod cpu;
 | 
			
		||||
pub mod error;
 | 
			
		||||
pub mod instructions;
 | 
			
		||||
pub mod keyboard;
 | 
			
		||||
pub mod memory;
 | 
			
		||||
pub mod video;
 | 
			
		||||
 | 
			
		||||
use crate::cpu::Cpu;
 | 
			
		||||
use crate::keyboard::Keyboard;
 | 
			
		||||
use crate::memory::Mem;
 | 
			
		||||
use crate::video::Renderer;
 | 
			
		||||
 | 
			
		||||
use core::panic;
 | 
			
		||||
use cpu::CpuController;
 | 
			
		||||
use memory::MemHandle;
 | 
			
		||||
use minifb::Window;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use std::fmt::Debug;
 | 
			
		||||
use std::fs::File;
 | 
			
		||||
use std::io::Read;
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
use std::thread::sleep;
 | 
			
		||||
use std::time::{Duration, Instant};
 | 
			
		||||
 | 
			
		||||
#[cfg(any(feature = "term", feature = "debug"))]
 | 
			
		||||
use std::{io::stdout, process::exit};
 | 
			
		||||
#[cfg(any(feature = "term", feature = "debug"))]
 | 
			
		||||
use termion::{
 | 
			
		||||
    async_stdin, clear,
 | 
			
		||||
    cursor::{self, Goto},
 | 
			
		||||
    event::Key,
 | 
			
		||||
    input::TermRead,
 | 
			
		||||
    raw::IntoRawMode,
 | 
			
		||||
    AsyncReader,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#[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>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct GeorgeEmuBuilder<'a> {
 | 
			
		||||
    cpu: Cpu,
 | 
			
		||||
    renderer: Option<Renderer>,
 | 
			
		||||
    input: Option<Keyboard>,
 | 
			
		||||
    config: Option<Config>,
 | 
			
		||||
    cpu_controller: CpuController,
 | 
			
		||||
    memory_handle: MemHandle,
 | 
			
		||||
    memory: Mem,
 | 
			
		||||
    window: Option<&'a mut Window>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> GeorgeEmuBuilder<'a> {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        let mut memory = Mem::new();
 | 
			
		||||
        // TODO: once the memory goes to the handle you can't load a rom,
 | 
			
		||||
        // so the method that loads a rom needs to have the handle uninitialized first,
 | 
			
		||||
        // so make everything here be None and set everything at the end
 | 
			
		||||
        memory.load_bytes(include_bytes!(
 | 
			
		||||
            "/Users/august/projects/george-emu/src/roms/demo.rom"
 | 
			
		||||
        ));
 | 
			
		||||
        let memory_handle = MemHandle::new(memory);
 | 
			
		||||
        let cpu_memory = memory_handle.clone();
 | 
			
		||||
        let (cpu, cpu_controller) = Cpu::new_with_control(cpu_memory);
 | 
			
		||||
        let input = None;
 | 
			
		||||
        let config = None;
 | 
			
		||||
        let renderer = None;
 | 
			
		||||
        let window = None;
 | 
			
		||||
        GeorgeEmuBuilder {
 | 
			
		||||
            cpu,
 | 
			
		||||
            cpu_controller,
 | 
			
		||||
            memory,
 | 
			
		||||
            memory_handle,
 | 
			
		||||
            config,
 | 
			
		||||
            renderer,
 | 
			
		||||
            window,
 | 
			
		||||
            input,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn config(mut self, config: Config) -> Self {
 | 
			
		||||
        self.config = Some(config);
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Adds a keyboard input to the emulator
 | 
			
		||||
    pub fn keyboard(mut self) -> Self {
 | 
			
		||||
        let input_memory = self.memory_handle.clone();
 | 
			
		||||
        let keyboard = Keyboard::new(input_memory);
 | 
			
		||||
        self.input = Some(keyboard);
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Adds a minifb window to the emulator
 | 
			
		||||
    #[cfg(not(feature = "term"))]
 | 
			
		||||
    pub fn window(mut self, window: &'a mut Window) -> Self {
 | 
			
		||||
        let renderer = Renderer::new(self.cpu_controller.clone(), self.memory_handle.clone());
 | 
			
		||||
        self.renderer = Some(renderer);
 | 
			
		||||
        self.window = Some(window);
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn rom<P>(mut self, path: P) -> Self
 | 
			
		||||
    where
 | 
			
		||||
        P: AsRef<Path> + Debug + Copy,
 | 
			
		||||
    {
 | 
			
		||||
        let rom = match File::open(path) {
 | 
			
		||||
            Ok(file) => {
 | 
			
		||||
                file
 | 
			
		||||
                // let mut bin = vec![0; 0x8000];
 | 
			
		||||
                // file.read_exact(&mut bin).unwrap();
 | 
			
		||||
                // // println!("reading char rom");
 | 
			
		||||
                // &bin
 | 
			
		||||
            }
 | 
			
		||||
            Err(error) => panic!("Couldn't read file at {path:?}: {error:?}"),
 | 
			
		||||
        };
 | 
			
		||||
        self.memory.read_from_bin(rom).unwrap();
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn build(mut self) -> GeorgeEmu<'a> {
 | 
			
		||||
        #[cfg(not(any(feature = "term", feature = "web")))]
 | 
			
		||||
        {
 | 
			
		||||
            match self.window {
 | 
			
		||||
                Some(ref mut window) => {
 | 
			
		||||
                    if let Some(ref input) = self.input {
 | 
			
		||||
                        window.set_input_callback(Box::new(input.clone()))
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                None => panic!(
 | 
			
		||||
                "Tried to call `GeorgeEmuBuilder::build()` before `GeorgeEmuBuilder::window()`!"
 | 
			
		||||
            ),
 | 
			
		||||
            }
 | 
			
		||||
            GeorgeEmu::new(self.cpu, self.renderer.unwrap(), self.input, self.window)
 | 
			
		||||
        }
 | 
			
		||||
        #[cfg(feature = "term")]
 | 
			
		||||
        {
 | 
			
		||||
            let renderer = Renderer::new(self.cpu_controller.clone(), self.memory_handle.clone());
 | 
			
		||||
            GeorgeEmu::new(self.cpu, renderer, self.input, self.window)
 | 
			
		||||
        }
 | 
			
		||||
        #[cfg(feature = "web")]
 | 
			
		||||
        {
 | 
			
		||||
            let renderer = Renderer::new(self.cpu_controller.clone(), self.memory_handle.clone());
 | 
			
		||||
            GeorgeEmu::new(self.cpu, renderer, self.input, self.window)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct GeorgeEmu<'a> {
 | 
			
		||||
    pub cpu: Cpu,
 | 
			
		||||
    pub renderer: Renderer,
 | 
			
		||||
    // in the future these might be set with feature flags,
 | 
			
		||||
    // but this is simpler
 | 
			
		||||
    input: Option<Keyboard>,
 | 
			
		||||
    pub window: Option<&'a mut Window>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> GeorgeEmu<'a> {
 | 
			
		||||
    pub fn builder() -> GeorgeEmuBuilder<'a> {
 | 
			
		||||
        GeorgeEmuBuilder::new()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn new(
 | 
			
		||||
        mut cpu: Cpu,
 | 
			
		||||
        renderer: Renderer,
 | 
			
		||||
        input: Option<Keyboard>,
 | 
			
		||||
        window: Option<&'a mut Window>,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        cpu.reset();
 | 
			
		||||
        Self {
 | 
			
		||||
            cpu,
 | 
			
		||||
            input,
 | 
			
		||||
            renderer,
 | 
			
		||||
            window,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn run(&mut self) {
 | 
			
		||||
        #[cfg(any(feature = "term", feature = "debug"))]
 | 
			
		||||
        {
 | 
			
		||||
            let _ = stdout().into_raw_mode();
 | 
			
		||||
            print!("{}{}", cursor::Hide, clear::All,);
 | 
			
		||||
        }
 | 
			
		||||
        #[cfg(any(feature = "term", feature = "debug"))]
 | 
			
		||||
        let mut stdin = async_stdin();
 | 
			
		||||
        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 {
 | 
			
		||||
                #[cfg(any(feature = "term", feature = "debug"))]
 | 
			
		||||
                self.handle_input(&mut stdin);
 | 
			
		||||
                #[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
                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)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
    fn draw(&mut self) {
 | 
			
		||||
        #[cfg(feature = "term")]
 | 
			
		||||
        self.renderer.render();
 | 
			
		||||
        #[cfg(not(feature = "term"))]
 | 
			
		||||
        match self.window {
 | 
			
		||||
            Some(ref mut window) => self.renderer.render(window),
 | 
			
		||||
            None => todo!(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    #[cfg(target_arch = "wasm32")]
 | 
			
		||||
    pub fn draw(&self, window: &mut Window) {
 | 
			
		||||
        #[cfg(feature = "term")]
 | 
			
		||||
        self.renderer.render();
 | 
			
		||||
        #[cfg(not(feature = "term"))]
 | 
			
		||||
        self.renderer.render(window);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(any(feature = "term", feature = "debug"))]
 | 
			
		||||
    fn handle_input(&mut self, stdin: &mut AsyncReader) {
 | 
			
		||||
        match &self.input {
 | 
			
		||||
            Some(input) => {
 | 
			
		||||
                let mut stdin = 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(),
 | 
			
		||||
                        _ => {
 | 
			
		||||
                            #[cfg(feature = "term")]
 | 
			
		||||
                            input.read_keys(key);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    #[cfg(feature = "term")]
 | 
			
		||||
                    input.clear_keys();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            None => {}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn cycle(&mut self) {
 | 
			
		||||
        self.cpu.cycle()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										74
									
								
								src/main.rs
								
								
								
								
							| 
						 | 
				
			
			@ -1,74 +0,0 @@
 | 
			
		|||
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,10 +1,7 @@
 | 
			
		|||
use anyhow::{bail, Result};
 | 
			
		||||
use core::panic;
 | 
			
		||||
use std::cell::RefCell;
 | 
			
		||||
use std::io::{self, Write};
 | 
			
		||||
use std::panic;
 | 
			
		||||
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};
 | 
			
		||||
| 
						 | 
				
			
			@ -16,11 +13,11 @@ impl MemHandle {
 | 
			
		|||
        Self(Arc::new(Mutex::new(memory)))
 | 
			
		||||
    }
 | 
			
		||||
    pub fn read(&self, address: u16) -> u8 {
 | 
			
		||||
        let memory = self.0.lock().unwrap();
 | 
			
		||||
        let memory = self.0.try_lock().unwrap();
 | 
			
		||||
        memory.read(address)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn write(&self, address: u16, data: u8) {
 | 
			
		||||
        let mut memory = self.0.lock().unwrap();
 | 
			
		||||
        let mut memory = self.0.try_lock().unwrap();
 | 
			
		||||
        memory.write(address, data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -49,15 +46,25 @@ pub trait MemoryWriter {
 | 
			
		|||
// 0x10000 elements
 | 
			
		||||
pub struct Mem([u8; 0x10000]);
 | 
			
		||||
 | 
			
		||||
impl Default for Mem {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Self([0; 0x10000])
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
// impl Default for Mem {
 | 
			
		||||
//     fn default() -> Self {
 | 
			
		||||
//         let bytes = include_bytes!("/Users/august/projects/george-emu/src/roms/george.rom");
 | 
			
		||||
//         let padding = [0; 0x8000];
 | 
			
		||||
//         let rom: [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(rom)
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
impl Mem {
 | 
			
		||||
    pub fn new() -> Self {
 | 
			
		||||
        Mem::default()
 | 
			
		||||
        Self([0; 0x10000])
 | 
			
		||||
    }
 | 
			
		||||
    pub fn dump(&self, path: PathBuf) -> io::Result<()> {
 | 
			
		||||
        let mut outfile = File::create(path)?;
 | 
			
		||||
| 
						 | 
				
			
			@ -97,16 +104,22 @@ impl Mem {
 | 
			
		|||
    pub fn poke(&self, address: u16) {
 | 
			
		||||
        println!("{:02x}", self.read(address));
 | 
			
		||||
    }
 | 
			
		||||
    //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(())
 | 
			
		||||
    //}
 | 
			
		||||
    pub fn load_bytes(&mut self, bytes: &[u8]) {
 | 
			
		||||
        for (address, byte) in bytes.into_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(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,123 @@
 | 
			
		|||
; .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
 | 
			
		||||
 | 
			
		||||
main:
 | 
			
		||||
    jsr draw
 | 
			
		||||
    jmp main
 | 
			
		||||
 | 
			
		||||
draw:
 | 
			
		||||
char = $200
 | 
			
		||||
x = $201
 | 
			
		||||
y = $202
 | 
			
		||||
    .y_loop:
 | 
			
		||||
        .x_loop:
 | 
			
		||||
            inc char
 | 
			
		||||
            lda x
 | 
			
		||||
            push 
 | 
			
		||||
            sta 0, x
 | 
			
		||||
            stz 1, x
 | 
			
		||||
            lda y
 | 
			
		||||
            push 
 | 
			
		||||
            sta 0, x
 | 
			
		||||
            sta 1, x
 | 
			
		||||
            lda char
 | 
			
		||||
            push 
 | 
			
		||||
            sta 0, x
 | 
			
		||||
            sta 1, x
 | 
			
		||||
            jsr draw_char
 | 
			
		||||
            inc x
 | 
			
		||||
            lda #64
 | 
			
		||||
            cmp x
 | 
			
		||||
            bne .x_loop
 | 
			
		||||
        inc y 
 | 
			
		||||
        lda #30
 | 
			
		||||
        cmp y
 | 
			
		||||
        bne .y_loop
 | 
			
		||||
    .end:
 | 
			
		||||
    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.
										
									
								
							| 
						 | 
				
			
			@ -1,4 +0,0 @@
 | 
			
		|||
use std::{u16, u8};
 | 
			
		||||
 | 
			
		||||
pub type Byte = u8;
 | 
			
		||||
pub type Word = u16;
 | 
			
		||||
							
								
								
									
										165
									
								
								src/video.rs
								
								
								
								
							
							
						
						
									
										165
									
								
								src/video.rs
								
								
								
								
							| 
						 | 
				
			
			@ -1,81 +1,68 @@
 | 
			
		|||
use minifb::{Scale, ScaleMode, Window, WindowOptions};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
#[cfg(feature = "term")]
 | 
			
		||||
use termion::{
 | 
			
		||||
    color::{self, Bg, Color, Fg},
 | 
			
		||||
    color::{self, Bg, 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},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const FG_COLOR: u32 = 0xFFCC00;
 | 
			
		||||
const BG_COLOR: u32 = 0x110500;
 | 
			
		||||
// const FG_COLOR: u32 = 0xFFCC00;
 | 
			
		||||
// const BG_COLOR: u32 = 0x110500;
 | 
			
		||||
const FG_COLOR: u32 = 0xFF00CCFF;
 | 
			
		||||
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"),
 | 
			
		||||
//     }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
trait Renderer {
 | 
			
		||||
    fn render(&mut self) {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize, Deserialize, Debug, Default)]
 | 
			
		||||
pub enum ScreenType {
 | 
			
		||||
    Window,
 | 
			
		||||
    #[default]
 | 
			
		||||
    Terminal,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct WindowRenderer {
 | 
			
		||||
#[cfg(not(feature = "term"))]
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct Renderer {
 | 
			
		||||
    char_rom: [u8; 0x8000],
 | 
			
		||||
    window: Window,
 | 
			
		||||
    memory: MemHandle,
 | 
			
		||||
    controller: CpuController,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
#[cfg(not(feature = "term"))]
 | 
			
		||||
impl Renderer {
 | 
			
		||||
    // pub fn new<P>(controller: CpuController, memory: MemHandle, char_rom: Option<P>) -> Self
 | 
			
		||||
    // where
 | 
			
		||||
    //     P: AsRef<Path>,
 | 
			
		||||
    pub fn new(controller: CpuController, memory: MemHandle) -> Self {
 | 
			
		||||
        // let char_rom = get_char_bin(char_rom);
 | 
			
		||||
        let char_rom = *include_bytes!("./roms/cozette.rom");
 | 
			
		||||
        Self {
 | 
			
		||||
            memory,
 | 
			
		||||
            window,
 | 
			
		||||
            char_rom,
 | 
			
		||||
            controller,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Renderer for WindowRenderer {
 | 
			
		||||
    fn render(&mut self) {
 | 
			
		||||
    pub fn render(&self, window: &mut 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
 | 
			
		||||
| 
						 | 
				
			
			@ -99,34 +86,24 @@ impl Renderer for WindowRenderer {
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        self.window
 | 
			
		||||
            .update_with_buffer(&buffer, WIDTH, HEIGHT)
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        self.controller.irq();
 | 
			
		||||
        window.update_with_buffer(&buffer, WIDTH, HEIGHT).unwrap();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl MemoryReader for WindowRenderer {
 | 
			
		||||
    fn read(&self, address: Word) -> Byte {
 | 
			
		||||
impl MemoryReader for Renderer {
 | 
			
		||||
    fn read(&self, address: u16) -> u8 {
 | 
			
		||||
        self.memory.read(address)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct TerminalRenderer {
 | 
			
		||||
#[cfg(feature = "term")]
 | 
			
		||||
pub struct Renderer {
 | 
			
		||||
    memory: MemHandle,
 | 
			
		||||
    controller: CpuController,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TerminalRenderer {
 | 
			
		||||
    pub fn new(memory: MemHandle) -> Self {
 | 
			
		||||
        Self { memory }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl MemoryReader for TerminalRenderer {
 | 
			
		||||
    fn read(&self, address: Word) -> Byte {
 | 
			
		||||
        self.memory.read(address)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "term")]
 | 
			
		||||
const ASCII_LOOPUP: [&str; 256] = [
 | 
			
		||||
    " ", "░", "▒", "▓", "♡", "♥", "⭐", "✭", "", "✦", "✨", "♀", "♂", "⚢", "⚣", "⚥", "♩", "♪",
 | 
			
		||||
    "♫", "♬", "ﱝ", "", "", "", "奄", "奔", "婢", "ﱜ", "ﱛ", "", "", "", " ", "!", "\"", "#",
 | 
			
		||||
| 
						 | 
				
			
			@ -144,8 +121,12 @@ const ASCII_LOOPUP: [&str; 256] = [
 | 
			
		|||
    "", "", "", "", "🎁", "", "", "", "", "⚐", "⚑", "", "", "",
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
impl Renderer for TerminalRenderer {
 | 
			
		||||
    fn render(&mut self) {
 | 
			
		||||
#[cfg(feature = "term")]
 | 
			
		||||
impl Renderer {
 | 
			
		||||
    pub fn new(controller: CpuController, memory: MemHandle) -> Self {
 | 
			
		||||
        Self { controller, memory }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn render(&self) {
 | 
			
		||||
        let mut stdout = io::stdout();
 | 
			
		||||
        let mut i = 0;
 | 
			
		||||
        for char_row in 0..29 {
 | 
			
		||||
| 
						 | 
				
			
			@ -164,54 +145,6 @@ impl Renderer for TerminalRenderer {
 | 
			
		|||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Screen {
 | 
			
		||||
    renderer: Box<dyn Renderer>,
 | 
			
		||||
    controller: CpuController,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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