1
0
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:
Matthias Endler 2018-11-04 20:26:51 +01:00
parent d5e9281969
commit 5ee12bdbc0
12 changed files with 876 additions and 383 deletions

3
.gitignore vendored
View File

@ -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
View 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"

View File

@ -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
View File

@ -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
View File

@ -0,0 +1,5 @@
extern crate skeptic;
fn main() {
skeptic::generate_doc_tests(&["README.md"]);
}

View File

@ -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)
}
}

View File

@ -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,

View File

@ -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));
}
}
}
}
}

View File

@ -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)))
}
}
}

View File

@ -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;

View File

@ -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
View File

@ -0,0 +1 @@
include!(concat!(env!("OUT_DIR"), "/skeptic-tests.rs"));