mirror of
https://github.com/mre/mos6502.git
synced 2024-12-26 08:31:08 +00:00
Add no_std support
This commit is contained in:
parent
d5e9281969
commit
5ee12bdbc0
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,3 @@
|
||||
Cargo.lock
|
||||
*.a
|
||||
*.aux
|
||||
*.bc
|
||||
@ -65,4 +64,4 @@ TAGS.vi
|
||||
\#*
|
||||
\#*\#
|
||||
src/.DS_Store
|
||||
tmp.*.rs
|
||||
tmp.*.rs
|
||||
|
383
Cargo.lock
generated
Normal file
383
Cargo.lock
generated
Normal file
@ -0,0 +1,383 @@
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace-sys"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "error-chain"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mos6502"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"skeptic 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-complex"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-rational"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "skeptic"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempdir"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a"
|
||||
"checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0"
|
||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f861d9ce359f56dbcb6e0c2a1cb84e52ad732cadb57b806adeb3c7668caccbd8"
|
||||
"checksum cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1efca0b863ca03ed4c109fb1c55e0bc4bbeb221d3e103d86251046b06a526bd0"
|
||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
|
||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||
"checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db"
|
||||
"checksum num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "107b9be86cd2481930688277b675b0114578227f034674726605b8a482d8baf8"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
|
||||
"checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee"
|
||||
"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
|
||||
"checksum quote 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "63b5829244f52738cfee93b3a165c1911388675be000c888d2fae620dee8fa5b"
|
||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
|
||||
"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7"
|
||||
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef"
|
||||
"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c"
|
||||
"checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce"
|
||||
"checksum skeptic 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4474d6da9593171bcb086890fc344a3a12783cb24e5b141f8a5d0e43561f4b6"
|
||||
"checksum syn 0.15.18 (registry+https://github.com/rust-lang/crates.io-index)" = "90c39a061e2f412a9f869540471ab679e85e50c6b05604daf28bc3060f75c430"
|
||||
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum walkdir 2.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0ffb549f212c31e19f3667c55a7f515b983a84aef10fd0a4d1f9c125425115f3"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
21
Cargo.toml
21
Cargo.toml
@ -30,18 +30,25 @@
|
||||
name = "mos6502"
|
||||
description = "A MOS 6502 Emulator"
|
||||
license = "BSD-3-Clause"
|
||||
version = "0.0.1"
|
||||
version = "0.1.0"
|
||||
authors = ["The 6502-rs Developers"]
|
||||
build = "build.rs"
|
||||
|
||||
[lib]
|
||||
# This will look in src/lib.rs
|
||||
name = "mos6502"
|
||||
|
||||
[[bin]]
|
||||
# This will look in src/bin/mos6502.rs
|
||||
name = "mos6502"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "0.9.1"
|
||||
log = "0.3.8"
|
||||
num = "0.1"
|
||||
log = "0.4.6"
|
||||
|
||||
[dependencies.num]
|
||||
version = "0.2"
|
||||
# no_std support
|
||||
default-features = false
|
||||
|
||||
[build-dependencies]
|
||||
skeptic = "0.13"
|
||||
|
||||
[dev-dependencies]
|
||||
skeptic = "0.13"
|
||||
|
108
README.md
108
README.md
@ -7,3 +7,111 @@ This started off as a fork of [6502-rs](https://github.com/amw-zero/6502-rs),
|
||||
which seems to be unmaintained at this point.
|
||||
|
||||
It builds with the latest stable Rust.
|
||||
|
||||
## Usage example
|
||||
|
||||
```rust
|
||||
extern crate mos6502;
|
||||
|
||||
use mos6502::cpu;
|
||||
use mos6502::address::Address;
|
||||
|
||||
fn main() {
|
||||
let mut cpu = cpu::CPU::new();
|
||||
|
||||
let zero_page_data = [
|
||||
// ZeroPage data start
|
||||
0x00,
|
||||
0x02, // ADC ZeroPage target
|
||||
0x00,
|
||||
0x04, // ADC ZeroPageX target
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x10, // ADC IndexedIndirectX address
|
||||
0x80, // ADC IndexedIndirectX address
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x08, // ADC IndirectIndexedY address
|
||||
0x80, // ADC IndirectIndexedY address
|
||||
];
|
||||
|
||||
let program = [
|
||||
// Code start
|
||||
0xA9, // LDA Immediate
|
||||
0x01, // Immediate operand
|
||||
0x69, // ADC Immediate
|
||||
0x07, // Immediate operand
|
||||
0x65, // ADC ZeroPage
|
||||
0x01, // ZeroPage operand
|
||||
0xA2, // LDX Immediate
|
||||
0x01, // Immediate operand
|
||||
0x75, // ADC ZeroPageX
|
||||
0x02, // ZeroPageX operand
|
||||
0x6D, // ADC Absolute
|
||||
0x01, // Absolute operand
|
||||
0x80, // Absolute operand
|
||||
0xA2, // LDX immediate
|
||||
0x08, // Immediate operand
|
||||
0x7D, // ADC AbsoluteX
|
||||
0x00, // AbsoluteX operand
|
||||
0x80, // AbsoluteX operand
|
||||
0xA0, // LDY immediate
|
||||
0x04, // Immediate operand
|
||||
0x79, // ADC AbsoluteY
|
||||
0x00, // AbsoluteY operand
|
||||
0x80, // AbsoluteY operand
|
||||
0xA2, // LDX immediate
|
||||
0x05, // Immediate operand
|
||||
0x61, // ADC IndexedIndirectX
|
||||
0x03, // IndexedIndirectX operand
|
||||
0xA0, // LDY immediate
|
||||
0x10, // Immediate operand
|
||||
0x71, // ADC IndirectIndexedY
|
||||
0x0F, // IndirectIndexedY operand
|
||||
0xEA, // NOP :)
|
||||
0xFF, // Something invalid -- the end!
|
||||
];
|
||||
|
||||
let data: [u8; 25] = [
|
||||
0x00,
|
||||
0x09, // ADC Absolute target
|
||||
0x00,
|
||||
0x00,
|
||||
0x40, // ADC AbsoluteY target
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x11, // ADC AbsoluteX target
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x12, // ADC IndexedIndirectX target
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x06, // ADC IndirectIndexedY target
|
||||
];
|
||||
|
||||
// "Load" a program
|
||||
cpu.memory.set_bytes(Address(0x0000), &zero_page_data);
|
||||
cpu.memory.set_bytes(Address(0x4000), &program);
|
||||
cpu.memory.set_bytes(Address(0x8000), &data);
|
||||
|
||||
cpu.registers.program_counter = Address(0x4000);
|
||||
|
||||
cpu.run();
|
||||
}
|
||||
```
|
||||
|
5
build.rs
Normal file
5
build.rs
Normal file
@ -0,0 +1,5 @@
|
||||
extern crate skeptic;
|
||||
|
||||
fn main() {
|
||||
skeptic::generate_doc_tests(&["README.md"]);
|
||||
}
|
@ -25,7 +25,7 @@
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use std::ops::Add;
|
||||
use core::ops::Add;
|
||||
|
||||
// The idea here is that it doesn't make sense to add two addresses, but it
|
||||
// does make sense to add an address and an "address-difference". (If this
|
||||
@ -42,8 +42,7 @@ impl Add<AddressDiff> for Address {
|
||||
fn add(self, AddressDiff(rhs): AddressDiff) -> Address {
|
||||
let Address(lhs) = self;
|
||||
|
||||
// TODO akeeton: Do a checked cast.
|
||||
Address(((lhs as i32) + rhs) as u16)
|
||||
Address(((i32::from(lhs)) + rhs) as u16)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,10 +39,8 @@ fn main() {
|
||||
|
||||
// "Load" a program
|
||||
|
||||
// JAM: FIXME: What's the syntax for specifying the array element type,
|
||||
// but not the length? (For a fixed-size array)
|
||||
|
||||
let zero_page_data: [u8; 17] = [
|
||||
let zero_page_data = [
|
||||
// ZeroPage data start
|
||||
0x00,
|
||||
0x02, // ADC ZeroPage target
|
||||
@ -63,7 +61,7 @@ fn main() {
|
||||
0x80, // ADC IndirectIndexedY address
|
||||
];
|
||||
|
||||
let program: [u8; 33] = [
|
||||
let program = [
|
||||
// Code start
|
||||
0xA9, // LDA Immediate
|
||||
0x01, // Immediate operand
|
||||
@ -100,7 +98,7 @@ fn main() {
|
||||
0xFF, // Something invalid -- the end!
|
||||
];
|
||||
|
||||
let data: [u8; 25] = [
|
||||
let data = [
|
||||
0x00,
|
||||
0x09, // ADC Absolute target
|
||||
0x00,
|
663
src/cpu.rs
663
src/cpu.rs
@ -25,15 +25,14 @@
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use std;
|
||||
|
||||
use address::{Address, AddressDiff};
|
||||
use instruction;
|
||||
use instruction::{DecodedInstr, Instruction, OpInput};
|
||||
use memory::Memory;
|
||||
use registers::{Registers, StackPointer, Status, StatusArgs};
|
||||
use registers::{PS_CARRY, PS_DECIMAL_MODE, PS_DISABLE_INTERRUPTS, PS_NEGATIVE, PS_OVERFLOW,
|
||||
PS_ZERO};
|
||||
use registers::{
|
||||
PS_CARRY, PS_DECIMAL_MODE, PS_DISABLE_INTERRUPTS, PS_NEGATIVE, PS_OVERFLOW, PS_ZERO,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CPU {
|
||||
@ -410,12 +409,8 @@ impl CPU {
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
loop {
|
||||
if let Some(decoded_instr) = self.fetch_next_and_decode() {
|
||||
self.execute_instruction(decoded_instr);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
while let Some(decoded_instr) = self.fetch_next_and_decode() {
|
||||
self.execute_instruction(decoded_instr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -758,8 +753,8 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for CPU {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
impl core::fmt::Debug for CPU {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"CPU Dump:\n\nAccumulator: {}",
|
||||
@ -776,385 +771,385 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn add_with_carry_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.add_with_carry(1);
|
||||
assert_eq!(CPU.registers.accumulator, 1);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.add_with_carry(1);
|
||||
assert_eq!(cpu.registers.accumulator, 1);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.add_with_carry(-1);
|
||||
assert_eq!(CPU.registers.accumulator, 0);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.add_with_carry(-1);
|
||||
assert_eq!(cpu.registers.accumulator, 0);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.add_with_carry(1);
|
||||
assert_eq!(CPU.registers.accumulator, 2);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.add_with_carry(1);
|
||||
assert_eq!(cpu.registers.accumulator, 2);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.add_with_carry(127);
|
||||
assert_eq!(CPU.registers.accumulator, 127);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.add_with_carry(127);
|
||||
assert_eq!(cpu.registers.accumulator, 127);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.add_with_carry(-127);
|
||||
assert_eq!(CPU.registers.accumulator, 0);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.add_with_carry(-127);
|
||||
assert_eq!(cpu.registers.accumulator, 0);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.registers.status.remove(PS_CARRY);
|
||||
CPU.add_with_carry(-128);
|
||||
assert_eq!(CPU.registers.accumulator, -128);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.registers.status.remove(PS_CARRY);
|
||||
cpu.add_with_carry(-128);
|
||||
assert_eq!(cpu.registers.accumulator, -128);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.add_with_carry(127);
|
||||
assert_eq!(CPU.registers.accumulator, -1);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.add_with_carry(127);
|
||||
assert_eq!(cpu.registers.accumulator, -1);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.add_with_carry(127);
|
||||
assert_eq!(CPU.registers.accumulator, 127);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.add_with_carry(127);
|
||||
assert_eq!(cpu.registers.accumulator, 127);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.add_with_carry(1);
|
||||
assert_eq!(CPU.registers.accumulator, -128);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), true);
|
||||
cpu.add_with_carry(1);
|
||||
assert_eq!(cpu.registers.accumulator, -128);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn and_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.registers.accumulator = 0;
|
||||
CPU.and(-1);
|
||||
assert_eq!(CPU.registers.accumulator, 0);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
cpu.registers.accumulator = 0;
|
||||
cpu.and(-1);
|
||||
assert_eq!(cpu.registers.accumulator, 0);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
|
||||
CPU.registers.accumulator = -1;
|
||||
CPU.and(0);
|
||||
assert_eq!(CPU.registers.accumulator, 0);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
cpu.registers.accumulator = -1;
|
||||
cpu.and(0);
|
||||
assert_eq!(cpu.registers.accumulator, 0);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
|
||||
CPU.registers.accumulator = -1;
|
||||
CPU.and(0x0f);
|
||||
assert_eq!(CPU.registers.accumulator, 0x0f);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
cpu.registers.accumulator = -1;
|
||||
cpu.and(0x0f);
|
||||
assert_eq!(cpu.registers.accumulator, 0x0f);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
|
||||
CPU.registers.accumulator = -1;
|
||||
CPU.and(-128);
|
||||
assert_eq!(CPU.registers.accumulator, -128);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
cpu.registers.accumulator = -1;
|
||||
cpu.and(-128);
|
||||
assert_eq!(cpu.registers.accumulator, -128);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_with_carry_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
CPU.registers.accumulator = 0;
|
||||
cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
cpu.registers.accumulator = 0;
|
||||
|
||||
CPU.subtract_with_carry(1);
|
||||
assert_eq!(CPU.registers.accumulator, -1);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.subtract_with_carry(1);
|
||||
assert_eq!(cpu.registers.accumulator, -1);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
CPU.registers.accumulator = -128;
|
||||
CPU.subtract_with_carry(1);
|
||||
assert_eq!(CPU.registers.accumulator, 127);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), true);
|
||||
cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
cpu.registers.accumulator = -128;
|
||||
cpu.subtract_with_carry(1);
|
||||
assert_eq!(cpu.registers.accumulator, 127);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), true);
|
||||
|
||||
CPU.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
CPU.registers.accumulator = 127;
|
||||
CPU.subtract_with_carry(-1);
|
||||
assert_eq!(CPU.registers.accumulator, -128);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), true);
|
||||
cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
cpu.registers.accumulator = 127;
|
||||
cpu.subtract_with_carry(-1);
|
||||
assert_eq!(cpu.registers.accumulator, -128);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), true);
|
||||
|
||||
CPU.execute_instruction((Instruction::CLC, OpInput::UseImplied));
|
||||
CPU.registers.accumulator = -64;
|
||||
CPU.subtract_with_carry(64);
|
||||
assert_eq!(CPU.registers.accumulator, 127);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), true);
|
||||
cpu.execute_instruction((Instruction::CLC, OpInput::UseImplied));
|
||||
cpu.registers.accumulator = -64;
|
||||
cpu.subtract_with_carry(64);
|
||||
assert_eq!(cpu.registers.accumulator, 127);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), true);
|
||||
|
||||
CPU.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
CPU.registers.accumulator = 0;
|
||||
CPU.subtract_with_carry(-128);
|
||||
assert_eq!(CPU.registers.accumulator, -128);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), true);
|
||||
cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
cpu.registers.accumulator = 0;
|
||||
cpu.subtract_with_carry(-128);
|
||||
assert_eq!(cpu.registers.accumulator, -128);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), true);
|
||||
|
||||
CPU.execute_instruction((Instruction::CLC, OpInput::UseImplied));
|
||||
CPU.registers.accumulator = 0;
|
||||
CPU.subtract_with_carry(127);
|
||||
assert_eq!(CPU.registers.accumulator, -128);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.execute_instruction((Instruction::CLC, OpInput::UseImplied));
|
||||
cpu.registers.accumulator = 0;
|
||||
cpu.subtract_with_carry(127);
|
||||
assert_eq!(cpu.registers.accumulator, -128);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decrement_memory_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
let addr = Address(0xA1B2);
|
||||
|
||||
CPU.memory.set_byte(addr, 5);
|
||||
cpu.memory.set_byte(addr, 5);
|
||||
|
||||
CPU.decrement_memory(addr);
|
||||
assert_eq!(CPU.memory.get_byte(addr), 4);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
cpu.decrement_memory(addr);
|
||||
assert_eq!(cpu.memory.get_byte(addr), 4);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
|
||||
CPU.decrement_memory(addr);
|
||||
assert_eq!(CPU.memory.get_byte(addr), 3);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
cpu.decrement_memory(addr);
|
||||
assert_eq!(cpu.memory.get_byte(addr), 3);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
|
||||
CPU.decrement_memory(addr);
|
||||
CPU.decrement_memory(addr);
|
||||
CPU.decrement_memory(addr);
|
||||
assert_eq!(CPU.memory.get_byte(addr), 0);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
cpu.decrement_memory(addr);
|
||||
cpu.decrement_memory(addr);
|
||||
cpu.decrement_memory(addr);
|
||||
assert_eq!(cpu.memory.get_byte(addr), 0);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
|
||||
CPU.decrement_memory(addr);
|
||||
assert_eq!(CPU.memory.get_byte(addr) as i8, -1);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
cpu.decrement_memory(addr);
|
||||
assert_eq!(cpu.memory.get_byte(addr) as i8, -1);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn logical_shift_right_test() {
|
||||
// Testing UseImplied version (which targets the accumulator) only, for now
|
||||
|
||||
let mut CPU = CPU::new();
|
||||
CPU.execute_instruction((Instruction::LDA, OpInput::UseImmediate(0)));
|
||||
CPU.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(CPU.registers.accumulator, 0);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
let mut cpu = CPU::new();
|
||||
cpu.execute_instruction((Instruction::LDA, OpInput::UseImmediate(0)));
|
||||
cpu.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(cpu.registers.accumulator, 0);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.execute_instruction((Instruction::LDA, OpInput::UseImmediate(1)));
|
||||
CPU.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(CPU.registers.accumulator, 0);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.execute_instruction((Instruction::LDA, OpInput::UseImmediate(1)));
|
||||
cpu.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(cpu.registers.accumulator, 0);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.execute_instruction((Instruction::LDA, OpInput::UseImmediate(255)));
|
||||
CPU.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(CPU.registers.accumulator, 0x7F);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.execute_instruction((Instruction::LDA, OpInput::UseImmediate(255)));
|
||||
cpu.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(cpu.registers.accumulator, 0x7F);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.execute_instruction((Instruction::LDA, OpInput::UseImmediate(254)));
|
||||
CPU.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(CPU.registers.accumulator, 0x7F);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.execute_instruction((Instruction::LDA, OpInput::UseImmediate(254)));
|
||||
cpu.execute_instruction((Instruction::LSR, OpInput::UseImplied));
|
||||
assert_eq!(cpu.registers.accumulator, 0x7F);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dec_x_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.dec_x();
|
||||
assert_eq!(CPU.registers.index_x, -1);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.dec_x();
|
||||
assert_eq!(cpu.registers.index_x, -1);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.dec_x();
|
||||
assert_eq!(CPU.registers.index_x, -2);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.dec_x();
|
||||
assert_eq!(cpu.registers.index_x, -2);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.load_x_register(5);
|
||||
CPU.dec_x();
|
||||
assert_eq!(CPU.registers.index_x, 4);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.load_x_register(5);
|
||||
cpu.dec_x();
|
||||
assert_eq!(cpu.registers.index_x, 4);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.dec_x();
|
||||
CPU.dec_x();
|
||||
CPU.dec_x();
|
||||
CPU.dec_x();
|
||||
cpu.dec_x();
|
||||
cpu.dec_x();
|
||||
cpu.dec_x();
|
||||
cpu.dec_x();
|
||||
|
||||
assert_eq!(CPU.registers.index_x, 0);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
assert_eq!(cpu.registers.index_x, 0);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
CPU.dec_x();
|
||||
assert_eq!(CPU.registers.index_x, -1);
|
||||
assert_eq!(CPU.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(CPU.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(CPU.registers.status.contains(PS_OVERFLOW), false);
|
||||
cpu.dec_x();
|
||||
assert_eq!(cpu.registers.index_x, -1);
|
||||
assert_eq!(cpu.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_ZERO), false);
|
||||
assert_eq!(cpu.registers.status.contains(PS_NEGATIVE), true);
|
||||
assert_eq!(cpu.registers.status.contains(PS_OVERFLOW), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn jump_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
let addr = Address(0xA1B1);
|
||||
|
||||
CPU.jump(addr);
|
||||
assert_eq!(CPU.registers.program_counter, addr);
|
||||
cpu.jump(addr);
|
||||
assert_eq!(cpu.registers.program_counter, addr);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_if_carry_clear_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
CPU.branch_if_carry_clear(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0));
|
||||
cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
cpu.branch_if_carry_clear(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0));
|
||||
|
||||
CPU.execute_instruction((Instruction::CLC, OpInput::UseImplied));
|
||||
CPU.branch_if_carry_clear(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0xABCD));
|
||||
cpu.execute_instruction((Instruction::CLC, OpInput::UseImplied));
|
||||
cpu.branch_if_carry_clear(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_if_carry_set_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.execute_instruction((Instruction::CLC, OpInput::UseImplied));
|
||||
CPU.branch_if_carry_set(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0));
|
||||
cpu.execute_instruction((Instruction::CLC, OpInput::UseImplied));
|
||||
cpu.branch_if_carry_set(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0));
|
||||
|
||||
CPU.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
CPU.branch_if_carry_set(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0xABCD));
|
||||
cpu.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
cpu.branch_if_carry_set(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_if_equal_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.branch_if_equal(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0));
|
||||
cpu.branch_if_equal(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0));
|
||||
|
||||
CPU.registers.status.or(PS_ZERO);
|
||||
CPU.branch_if_equal(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0xABCD));
|
||||
cpu.registers.status.or(PS_ZERO);
|
||||
cpu.branch_if_equal(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_if_minus_test() {
|
||||
{
|
||||
let mut CPU = CPU::new();
|
||||
let registers_before = CPU.registers;
|
||||
let mut cpu = CPU::new();
|
||||
let registers_before = cpu.registers;
|
||||
|
||||
CPU.branch_if_minus(Address(0xABCD));
|
||||
assert_eq!(CPU.registers, registers_before);
|
||||
assert_eq!(CPU.registers.program_counter, Address(0));
|
||||
cpu.branch_if_minus(Address(0xABCD));
|
||||
assert_eq!(cpu.registers, registers_before);
|
||||
assert_eq!(cpu.registers.program_counter, Address(0));
|
||||
}
|
||||
|
||||
{
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.registers.status.or(PS_NEGATIVE);
|
||||
let registers_before = CPU.registers;
|
||||
cpu.registers.status.or(PS_NEGATIVE);
|
||||
let registers_before = cpu.registers;
|
||||
|
||||
CPU.branch_if_minus(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.status, registers_before.status);
|
||||
assert_eq!(CPU.registers.program_counter, Address(0xABCD));
|
||||
cpu.branch_if_minus(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.status, registers_before.status);
|
||||
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_if_positive_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.registers.status.insert(PS_NEGATIVE);
|
||||
CPU.branch_if_positive(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0));
|
||||
cpu.registers.status.insert(PS_NEGATIVE);
|
||||
cpu.branch_if_positive(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0));
|
||||
|
||||
CPU.registers.status.remove(PS_NEGATIVE);
|
||||
CPU.branch_if_positive(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0xABCD));
|
||||
cpu.registers.status.remove(PS_NEGATIVE);
|
||||
cpu.branch_if_positive(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_if_overflow_clear_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.registers.status.insert(PS_OVERFLOW);
|
||||
CPU.branch_if_overflow_clear(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0));
|
||||
cpu.registers.status.insert(PS_OVERFLOW);
|
||||
cpu.branch_if_overflow_clear(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0));
|
||||
|
||||
CPU.registers.status.remove(PS_OVERFLOW);
|
||||
CPU.branch_if_overflow_clear(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0xABCD));
|
||||
cpu.registers.status.remove(PS_OVERFLOW);
|
||||
cpu.branch_if_overflow_clear(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branch_if_overflow_set_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.branch_if_overflow_set(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0));
|
||||
cpu.branch_if_overflow_set(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0));
|
||||
|
||||
CPU.registers.status.insert(PS_OVERFLOW);
|
||||
CPU.branch_if_overflow_set(Address(0xABCD));
|
||||
assert_eq!(CPU.registers.program_counter, Address(0xABCD));
|
||||
cpu.registers.status.insert(PS_OVERFLOW);
|
||||
cpu.branch_if_overflow_set(Address(0xABCD));
|
||||
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -1162,61 +1157,56 @@ mod tests {
|
||||
where
|
||||
F: FnMut(&mut CPU, u8),
|
||||
{
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
CPU.execute_instruction((load_instruction, OpInput::UseImmediate(127)));
|
||||
cpu.execute_instruction((load_instruction, OpInput::UseImmediate(127)));
|
||||
|
||||
compare(&mut CPU, 127);
|
||||
assert!(CPU.registers.status.contains(PS_ZERO));
|
||||
assert!(CPU.registers.status.contains(PS_CARRY));
|
||||
assert!(!CPU.registers.status.contains(PS_NEGATIVE));
|
||||
compare(&mut cpu, 127);
|
||||
assert!(cpu.registers.status.contains(PS_ZERO));
|
||||
assert!(cpu.registers.status.contains(PS_CARRY));
|
||||
assert!(!cpu.registers.status.contains(PS_NEGATIVE));
|
||||
|
||||
cpu.execute_instruction((load_instruction, OpInput::UseImmediate(127)));
|
||||
|
||||
CPU.execute_instruction((load_instruction, OpInput::UseImmediate(127)));
|
||||
compare(&mut cpu, 1);
|
||||
assert!(!cpu.registers.status.contains(PS_ZERO));
|
||||
assert!(cpu.registers.status.contains(PS_CARRY));
|
||||
assert!(!cpu.registers.status.contains(PS_NEGATIVE));
|
||||
|
||||
compare(&mut CPU, 1);
|
||||
assert!(!CPU.registers.status.contains(PS_ZERO));
|
||||
assert!(CPU.registers.status.contains(PS_CARRY));
|
||||
assert!(!CPU.registers.status.contains(PS_NEGATIVE));
|
||||
cpu.execute_instruction((load_instruction, OpInput::UseImmediate(1)));
|
||||
|
||||
compare(&mut cpu, 2);
|
||||
assert!(!cpu.registers.status.contains(PS_ZERO));
|
||||
assert!(!cpu.registers.status.contains(PS_CARRY));
|
||||
assert!(cpu.registers.status.contains(PS_NEGATIVE));
|
||||
|
||||
CPU.execute_instruction((load_instruction, OpInput::UseImmediate(1)));
|
||||
cpu.execute_instruction((load_instruction, OpInput::UseImmediate(20)));
|
||||
|
||||
compare(&mut CPU, 2);
|
||||
assert!(!CPU.registers.status.contains(PS_ZERO));
|
||||
assert!(!CPU.registers.status.contains(PS_CARRY));
|
||||
assert!(CPU.registers.status.contains(PS_NEGATIVE));
|
||||
compare(&mut cpu, -50i8 as u8);
|
||||
assert!(!cpu.registers.status.contains(PS_ZERO));
|
||||
assert!(!cpu.registers.status.contains(PS_CARRY));
|
||||
assert!(!cpu.registers.status.contains(PS_NEGATIVE));
|
||||
|
||||
cpu.execute_instruction((load_instruction, OpInput::UseImmediate(1)));
|
||||
|
||||
CPU.execute_instruction((load_instruction, OpInput::UseImmediate(20)));
|
||||
compare(&mut cpu, -1i8 as u8);
|
||||
assert!(!cpu.registers.status.contains(PS_ZERO));
|
||||
assert!(!cpu.registers.status.contains(PS_CARRY));
|
||||
assert!(!cpu.registers.status.contains(PS_NEGATIVE));
|
||||
|
||||
compare(&mut CPU, -50i8 as u8);
|
||||
assert!(!CPU.registers.status.contains(PS_ZERO));
|
||||
assert!(!CPU.registers.status.contains(PS_CARRY));
|
||||
assert!(!CPU.registers.status.contains(PS_NEGATIVE));
|
||||
cpu.execute_instruction((load_instruction, OpInput::UseImmediate(127)));
|
||||
|
||||
|
||||
CPU.execute_instruction((load_instruction, OpInput::UseImmediate(1)));
|
||||
|
||||
compare(&mut CPU, -1i8 as u8);
|
||||
assert!(!CPU.registers.status.contains(PS_ZERO));
|
||||
assert!(!CPU.registers.status.contains(PS_CARRY));
|
||||
assert!(!CPU.registers.status.contains(PS_NEGATIVE));
|
||||
|
||||
|
||||
CPU.execute_instruction((load_instruction, OpInput::UseImmediate(127)));
|
||||
|
||||
compare(&mut CPU, -128i8 as u8);
|
||||
assert!(!CPU.registers.status.contains(PS_ZERO));
|
||||
assert!(!CPU.registers.status.contains(PS_CARRY));
|
||||
assert!(CPU.registers.status.contains(PS_NEGATIVE));
|
||||
compare(&mut cpu, -128i8 as u8);
|
||||
assert!(!cpu.registers.status.contains(PS_ZERO));
|
||||
assert!(!cpu.registers.status.contains(PS_CARRY));
|
||||
assert!(cpu.registers.status.contains(PS_NEGATIVE));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_with_a_register_test() {
|
||||
compare_test_helper(
|
||||
&mut |CPU: &mut CPU, val: u8| {
|
||||
CPU.compare_with_a_register(val);
|
||||
&mut |cpu: &mut CPU, val: u8| {
|
||||
cpu.compare_with_a_register(val);
|
||||
},
|
||||
Instruction::LDA,
|
||||
);
|
||||
@ -1225,8 +1215,8 @@ mod tests {
|
||||
#[test]
|
||||
fn compare_with_x_register_test() {
|
||||
compare_test_helper(
|
||||
&mut |CPU: &mut CPU, val: u8| {
|
||||
CPU.compare_with_x_register(val);
|
||||
&mut |cpu: &mut CPU, val: u8| {
|
||||
cpu.compare_with_x_register(val);
|
||||
},
|
||||
Instruction::LDX,
|
||||
);
|
||||
@ -1235,8 +1225,8 @@ mod tests {
|
||||
#[test]
|
||||
fn compare_with_y_register_test() {
|
||||
compare_test_helper(
|
||||
&mut |CPU: &mut CPU, val: u8| {
|
||||
CPU.compare_with_y_register(val);
|
||||
&mut |cpu: &mut CPU, val: u8| {
|
||||
cpu.compare_with_y_register(val);
|
||||
},
|
||||
Instruction::LDY,
|
||||
);
|
||||
@ -1244,27 +1234,27 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn exclusive_or_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
for a_before in range_inclusive(0u8, 255u8) {
|
||||
for val in range_inclusive(0u8, 255u8) {
|
||||
CPU.execute_instruction((Instruction::LDA, OpInput::UseImmediate(a_before)));
|
||||
cpu.execute_instruction((Instruction::LDA, OpInput::UseImmediate(a_before)));
|
||||
|
||||
CPU.exclusive_or(val);
|
||||
cpu.exclusive_or(val);
|
||||
|
||||
let a_after = a_before ^ val;
|
||||
assert_eq!(CPU.registers.accumulator, a_after as i8);
|
||||
assert_eq!(cpu.registers.accumulator, a_after as i8);
|
||||
|
||||
if a_after == 0 {
|
||||
assert!(CPU.registers.status.contains(PS_ZERO));
|
||||
assert!(cpu.registers.status.contains(PS_ZERO));
|
||||
} else {
|
||||
assert!(!CPU.registers.status.contains(PS_ZERO));
|
||||
assert!(!cpu.registers.status.contains(PS_ZERO));
|
||||
}
|
||||
|
||||
if (a_after as i8) < 0 {
|
||||
assert!(CPU.registers.status.contains(PS_NEGATIVE));
|
||||
assert!(cpu.registers.status.contains(PS_NEGATIVE));
|
||||
} else {
|
||||
assert!(!CPU.registers.status.contains(PS_NEGATIVE));
|
||||
assert!(!cpu.registers.status.contains(PS_NEGATIVE));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1272,29 +1262,30 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn inclusive_or_test() {
|
||||
let mut CPU = CPU::new();
|
||||
let mut cpu = CPU::new();
|
||||
|
||||
for a_before in range_inclusive(0u8, 255u8) {
|
||||
for val in range_inclusive(0u8, 255u8) {
|
||||
CPU.execute_instruction((Instruction::LDA, OpInput::UseImmediate(a_before)));
|
||||
cpu.execute_instruction((Instruction::LDA, OpInput::UseImmediate(a_before)));
|
||||
|
||||
CPU.inclusive_or(val);
|
||||
cpu.inclusive_or(val);
|
||||
|
||||
let a_after = a_before | val;
|
||||
assert_eq!(CPU.registers.accumulator, a_after as i8);
|
||||
assert_eq!(cpu.registers.accumulator, a_after as i8);
|
||||
|
||||
if a_after == 0 {
|
||||
assert!(CPU.registers.status.contains(PS_ZERO));
|
||||
assert!(cpu.registers.status.contains(PS_ZERO));
|
||||
} else {
|
||||
assert!(!CPU.registers.status.contains(PS_ZERO));
|
||||
assert!(!cpu.registers.status.contains(PS_ZERO));
|
||||
}
|
||||
|
||||
if (a_after as i8) < 0 {
|
||||
assert!(CPU.registers.status.contains(PS_NEGATIVE));
|
||||
assert!(cpu.registers.status.contains(PS_NEGATIVE));
|
||||
} else {
|
||||
assert!(!CPU.registers.status.contains(PS_NEGATIVE));
|
||||
assert!(!cpu.registers.status.contains(PS_NEGATIVE));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ pub enum AddressingMode {
|
||||
fn arr_to_addr(arr: &[u8]) -> Address {
|
||||
debug_assert!(arr.len() == 2);
|
||||
|
||||
let x = (arr[0] as u16) + ((arr[1] as u16) << 8usize);
|
||||
let x = u16::from(arr[0]) + (u16::from(arr[1]) << 8usize);
|
||||
Address(x)
|
||||
}
|
||||
|
||||
@ -187,19 +187,19 @@ impl AddressingMode {
|
||||
// Use [u8, ..1] from instruction
|
||||
// Interpret as zero page address
|
||||
// (Output: an 8-bit zero-page address)
|
||||
OpInput::UseAddress(Address(arr[0] as u16))
|
||||
OpInput::UseAddress(Address(u16::from(arr[0])))
|
||||
}
|
||||
AddressingMode::ZeroPageX => {
|
||||
// Use [u8, ..1] from instruction
|
||||
// Add to X register (as u8 -- the final address is in 0-page)
|
||||
// (Output: an 8-bit zero-page address)
|
||||
OpInput::UseAddress(Address((arr[0] + x) as u16))
|
||||
OpInput::UseAddress(Address(u16::from(arr[0] + x)))
|
||||
}
|
||||
AddressingMode::ZeroPageY => {
|
||||
// Use [u8, ..1] from instruction
|
||||
// Add to Y register (as u8 -- the final address is in 0-page)
|
||||
// (Output: an 8-bit zero-page address)
|
||||
OpInput::UseAddress(Address((arr[0] + y) as u16))
|
||||
OpInput::UseAddress(Address(u16::from(arr[0] + y)))
|
||||
}
|
||||
AddressingMode::Relative => {
|
||||
// Use [u8, ..1] from instruction
|
||||
@ -214,12 +214,12 @@ impl AddressingMode {
|
||||
AddressingMode::AbsoluteX => {
|
||||
// Use [u8, ..2] from instruction as address, add X
|
||||
// (Output: a 16-bit address)
|
||||
OpInput::UseAddress(arr_to_addr(arr) + AddressDiff(x as i32))
|
||||
OpInput::UseAddress(arr_to_addr(arr) + AddressDiff(i32::from(x)))
|
||||
}
|
||||
AddressingMode::AbsoluteY => {
|
||||
// Use [u8, ..2] from instruction as address, add Y
|
||||
// (Output: a 16-bit address)
|
||||
OpInput::UseAddress(arr_to_addr(arr) + AddressDiff(y as i32))
|
||||
OpInput::UseAddress(arr_to_addr(arr) + AddressDiff(i32::from(y)))
|
||||
}
|
||||
AddressingMode::Indirect => {
|
||||
// Use [u8, ..2] from instruction as an address. Interpret the
|
||||
@ -234,7 +234,7 @@ impl AddressingMode {
|
||||
// This is where the absolute (16-bit) target address is stored.
|
||||
// (Output: a 16-bit address)
|
||||
let start = arr[0] + x;
|
||||
let slice = memory.get_slice(Address(start as u16), AddressDiff(2));
|
||||
let slice = memory.get_slice(Address(u16::from(start)), AddressDiff(2));
|
||||
OpInput::UseAddress(arr_to_addr(slice))
|
||||
}
|
||||
AddressingMode::IndirectIndexedY => {
|
||||
@ -243,8 +243,8 @@ impl AddressingMode {
|
||||
// Add Y register to this address to get the final address
|
||||
// (Output: a 16-bit address)
|
||||
let start = arr[0];
|
||||
let slice = memory.get_slice(Address(start as u16), AddressDiff(2));
|
||||
OpInput::UseAddress(arr_to_addr(slice) + AddressDiff(y as i32))
|
||||
let slice = memory.get_slice(Address(u16::from(start)), AddressDiff(2));
|
||||
OpInput::UseAddress(arr_to_addr(slice) + AddressDiff(i32::from(y)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,8 @@
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Needed for debug! / log! macros
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
@ -35,7 +36,8 @@ extern crate num;
|
||||
extern crate bitflags;
|
||||
|
||||
pub mod address;
|
||||
pub mod instruction;
|
||||
pub mod cpu;
|
||||
pub mod instruction;
|
||||
pub mod memory;
|
||||
pub mod registers;
|
||||
|
||||
|
@ -58,17 +58,17 @@ impl StatusArgs {
|
||||
|
||||
bitflags! {
|
||||
pub struct Status: u8 {
|
||||
const PS_NEGATIVE = 0b10000000;
|
||||
const PS_OVERFLOW = 0b01000000;
|
||||
const PS_UNUSED = 0b00100000; // JAM: Should this exist?
|
||||
const PS_NEGATIVE = 0b1000_0000;
|
||||
const PS_OVERFLOW = 0b0100_0000;
|
||||
const PS_UNUSED = 0b0010_0000; // JAM: Should this exist?
|
||||
// (note that it affects the
|
||||
// behavior of things like
|
||||
// from_bits_truncate)
|
||||
const PS_BRK = 0b00010000;
|
||||
const PS_DECIMAL_MODE = 0b00001000;
|
||||
const PS_DISABLE_INTERRUPTS = 0b00000100;
|
||||
const PS_ZERO = 0b00000010;
|
||||
const PS_CARRY = 0b00000001;
|
||||
const PS_BRK = 0b0001_0000;
|
||||
const PS_DECIMAL_MODE = 0b0000_1000;
|
||||
const PS_DISABLE_INTERRUPTS = 0b0000_0100;
|
||||
const PS_ZERO = 0b0000_0010;
|
||||
const PS_CARRY = 0b0000_0001;
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,39 +100,39 @@ impl Status {
|
||||
let mut out = Status::empty();
|
||||
|
||||
if negative {
|
||||
out = out | PS_NEGATIVE
|
||||
out |= PS_NEGATIVE
|
||||
}
|
||||
if overflow {
|
||||
out = out | PS_OVERFLOW
|
||||
out |= PS_OVERFLOW
|
||||
}
|
||||
if unused {
|
||||
out = out | PS_UNUSED
|
||||
out |= PS_UNUSED
|
||||
}
|
||||
if brk {
|
||||
out = out | PS_BRK
|
||||
out |= PS_BRK
|
||||
}
|
||||
if decimal_mode {
|
||||
out = out | PS_DECIMAL_MODE
|
||||
out |= PS_DECIMAL_MODE
|
||||
}
|
||||
if disable_interrupts {
|
||||
out = out | PS_DISABLE_INTERRUPTS
|
||||
out |= PS_DISABLE_INTERRUPTS
|
||||
}
|
||||
if zero {
|
||||
out = out | PS_ZERO
|
||||
out |= PS_ZERO
|
||||
}
|
||||
if carry {
|
||||
out = out | PS_CARRY
|
||||
out |= PS_CARRY
|
||||
}
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
pub fn and(&mut self, rhs: Status) {
|
||||
*self = *self & rhs;
|
||||
*self &= rhs;
|
||||
}
|
||||
|
||||
pub fn or(&mut self, rhs: Status) {
|
||||
*self = *self | rhs;
|
||||
*self |= rhs;
|
||||
}
|
||||
|
||||
pub fn set_with_mask(&mut self, mask: Status, rhs: Status) {
|
||||
@ -146,7 +146,7 @@ pub struct StackPointer(pub u8);
|
||||
impl StackPointer {
|
||||
pub fn to_address(&self) -> Address {
|
||||
let StackPointer(sp) = *self;
|
||||
STACK_ADDRESS_LO + AddressDiff(sp as i32)
|
||||
STACK_ADDRESS_LO + AddressDiff(i32::from(sp))
|
||||
}
|
||||
|
||||
// JAM: FIXME: Should we prevent overflow here? What would a 6502 do?
|
||||
|
1
tests/skeptic.rs
Normal file
1
tests/skeptic.rs
Normal file
@ -0,0 +1 @@
|
||||
include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs"));
|
Loading…
Reference in New Issue
Block a user