Merge branch 'master' of github.com:mre/mos6502 into no-std-example

This commit is contained in:
Matthias Endler 2021-01-28 23:46:39 +01:00
commit 99b788c3b1
11 changed files with 711 additions and 574 deletions

2
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,2 @@
github: mre
patreon: hellorust

View File

@ -0,0 +1,24 @@
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build_and_test:
name: test
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@master
- name: Install cargo
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
- name: Run test
uses: actions-rs/cargo@v1
with:
command: test

386
Cargo.lock generated
View File

@ -1,383 +1,411 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "backtrace"
version = "0.3.9"
name = "autocfg"
version = "1.0.0"
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)",
]
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "bitflags"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.0.4"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bytecount"
version = "0.3.2"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e"
[[package]]
name = "cargo_metadata"
version = "0.5.8"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8de60b887edf6d74370fc8eb177040da4847d971d6234c7b13a6da324ef0caf"
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)",
"semver",
"serde",
"serde_derive",
"serde_json",
]
[[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"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "error-chain"
version = "0.11.0"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9"
dependencies = [
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"version_check",
]
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
name = "getrandom"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
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)",
"cfg-if 0.1.10",
"libc",
"wasi",
]
[[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"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "itoa"
version = "0.4.3"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
[[package]]
name = "libc"
version = "0.2.43"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
[[package]]
name = "log"
version = "0.4.6"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 1.0.0",
]
[[package]]
name = "mos6502"
version = "0.1.0"
version = "0.2.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)",
"bitflags",
"log",
"num",
"skeptic",
]
[[package]]
name = "num"
version = "0.2.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f"
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)",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.2.1"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5"
dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.39"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.37"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
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)",
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.2.1"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5fa6d5f418879385b213d905f7cf5bf4aa553d4c380f0152d1d4f2749186fa9"
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)",
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.6"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "ppv-lite86"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
[[package]]
name = "proc-macro2"
version = "0.4.20"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid",
]
[[package]]
name = "pulldown-cmark"
version = "0.1.2"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eef52fac62d0ea7b9b4dc7da092aa64ea7ec3d90af6679422d3d7e0e14b6ee15"
dependencies = [
"bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags",
]
[[package]]
name = "quote"
version = "0.6.9"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
dependencies = [
"proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.4.3"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
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)",
"getrandom",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]]
name = "redox_syscall"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "remove_dir_all"
version = "0.5.1"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
dependencies = [
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi",
]
[[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"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
[[package]]
name = "same-file"
version = "1.0.4"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421"
dependencies = [
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-util",
]
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
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)",
"semver-parser",
"serde",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.80"
version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
[[package]]
name = "serde_derive"
version = "1.0.80"
version = "1.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e"
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)",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.32"
version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
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)",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "skeptic"
version = "0.13.3"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6deb8efaf3ad8fd784139db8bbd51806bfbcee87c7be7578e9c930981fb808"
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)",
"bytecount",
"cargo_metadata",
"error-chain",
"glob",
"pulldown-cmark",
"tempfile",
"walkdir",
]
[[package]]
name = "syn"
version = "0.15.18"
version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac"
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)",
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "tempdir"
version = "0.3.7"
name = "tempfile"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
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)",
"cfg-if 0.1.10",
"libc",
"rand",
"redox_syscall",
"remove_dir_all",
"winapi",
]
[[package]]
name = "unicode-xid"
version = "0.1.0"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
[[package]]
name = "walkdir"
version = "2.2.6"
version = "2.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e"
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)",
"same-file",
"winapi",
"winapi-util",
]
[[package]]
name = "winapi"
version = "0.3.6"
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
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)",
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
dependencies = [
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi",
]
[[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"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -1,4 +1,4 @@
# Copyright (C) 2014 The 6502-rs Developers
# Copyright (C) 2014-2021 The 6502-rs Developers
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -30,20 +30,21 @@
name = "mos6502"
description = "A MOS 6502 Emulator"
license = "BSD-3-Clause"
version = "0.1.0"
version = "0.2.0"
authors = ["The 6502-rs Developers"]
build = "build.rs"
exclude = ["examples/**"]
[lib]
# This will look in src/lib.rs
name = "mos6502"
[dependencies]
bitflags = "0.9.1"
log = "0.4.6"
bitflags = "1"
log = "0.4.14"
[dependencies.num]
version = "0.2"
version = "0.3"
# no_std support
default-features = false

127
README.md
View File

@ -1,10 +1,11 @@
# mos6502
[![Build Status](https://travis-ci.org/mre/mos6502.svg?branch=master)](https://travis-ci.org/mre/mos6502)
![](https://github.com/mre/mos6502/workflows/test/badge.svg)
[![docs.rs](https://docs.rs/mos6502/badge.svg)](https://docs.rs/mos6502)
An emulator for the [MOS 6502 CPU](https://en.wikipedia.org/wiki/MOS_Technology_6502) written in Rust.
This started off as a fork of [6502-rs](https://github.com/amw-zero/6502-rs),
which seems to be unmaintained at this point.
An emulator for the [MOS 6502 CPU](https://en.wikipedia.org/wiki/MOS_Technology_6502) written in Rust.
This started off as a fork of [amw-zero/6502-rs](https://github.com/amw-zero/6502-rs),
which seems to be [unmaintained](https://github.com/amw-zero/6502-rs/pull/36) at this point.
It builds with the latest stable Rust and supports `#[no_std]` targets. (See `no-std-example` folder for more info.)
@ -12,106 +13,44 @@ It builds with the latest stable Rust and supports `#[no_std]` targets. (See `no
```rust
extern crate mos6502;
use mos6502::cpu;
use mos6502::address::Address;
use mos6502::cpu;
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 zero_page_data = [56, 49];
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!
// (F)irst | (S)econd
// .algo
0xa5, 0x00, // Load from F to A
// .algo_
0x38, // Set carry flag
0xe5, 0x01, // Substract S from number in A (from F)
0xf0, 0x07, // Jump to .end if diff is zero
0x30, 0x08, // Jump to .swap if diff is negative
0x85, 0x00, // Load A to F
0x4c, 0x12, 0x00, // Jump to .algo_
// .end
0xa5, 0x00, // Load from S to A
0xff,
// .swap
0xa6, 0x00, // load F to X
0xa4, 0x01, // load S to Y
0x86, 0x01, // Store X to F
0x84, 0x00, // Store Y to S
0x4c, 0x10, 0x00, // Jump to .algo
];
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
];
let mut cpu = cpu::CPU::new();
// "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.memory.set_bytes(Address(0x00), &zero_page_data);
cpu.memory.set_bytes(Address(0x10), &program);
cpu.registers.program_counter = Address(0x10);
cpu.run();
assert_eq!(7, cpu.registers.accumulator);
}
```

View File

@ -0,0 +1,47 @@
extern crate mos6502;
use mos6502::address::Address;
use mos6502::cpu;
fn main() {
println!("Enter two numbers (< 128) to know their GCD:");
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();
let zero_page_data = input
.trim()
.split(' ')
.map(|s| s.parse::<u8>().unwrap())
.collect::<Vec<u8>>();
let program = [
// (F)irst | (S)econd
// .algo
0xa5, 0x00, // Load from F to A
// .algo_
0x38, // Set carry flag
0xe5, 0x01, // Substract S from number in A (from F)
0xf0, 0x07, // Jump to .end if diff is zero
0x30, 0x08, // Jump to .swap if diff is negative
0x85, 0x00, // Load A to F
0x4c, 0x12, 0x00, // Jump to .algo_
// .end
0xa5, 0x00, // Load from S to A
0xff,
// .swap
0xa6, 0x00, // load F to X
0xa4, 0x01, // load S to Y
0x86, 0x01, // Store X to F
0x84, 0x00, // Store Y to S
0x4c, 0x10, 0x00, // Jump to .algo
];
let mut cpu = cpu::CPU::new();
cpu.memory.set_bytes(Address(0x00), &zero_page_data);
cpu.memory.set_bytes(Address(0x10), &program);
cpu.registers.program_counter = Address(0x10);
cpu.run();
println!("GCD is {:?}", cpu.registers.accumulator);
}

View File

@ -73,21 +73,19 @@ impl Add<CheckedAddressDiff> for Address {
}
impl Address {
pub fn to_u16(&self) -> u16 {
match *self {
Address(address_) => address_,
}
pub fn to_u16(self) -> u16 {
self.0
}
pub fn to_usize(&self) -> usize {
pub fn to_usize(self) -> usize {
self.to_u16() as usize
}
pub fn get_page_number(&self) -> u8 {
pub fn get_page_number(self) -> u8 {
(self.to_u16() & 0xff00 >> 8) as u8
}
pub fn get_offset(&self) -> u8 {
pub fn get_offset(self) -> u8 {
(self.to_u16() & 0x00ff) as u8
}
}

View File

@ -30,9 +30,6 @@ 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,
};
#[derive(Clone)]
pub struct CPU {
@ -40,6 +37,12 @@ pub struct CPU {
pub memory: Memory,
}
impl Default for CPU {
fn default() -> Self {
Self::new()
}
}
impl CPU {
pub fn new() -> CPU {
CPU {
@ -137,7 +140,7 @@ impl CPU {
let bit6 = 0 != (0x40 & res);
self.registers.status.set_with_mask(
PS_ZERO | PS_NEGATIVE | PS_OVERFLOW,
Status::PS_ZERO | Status::PS_NEGATIVE | Status::PS_OVERFLOW,
Status::new(StatusArgs {
zero: is_zero,
negative: bit7,
@ -169,16 +172,16 @@ impl CPU {
}
(Instruction::CLC, OpInput::UseImplied) => {
self.registers.status.and(!PS_CARRY);
self.registers.status.and(!Status::PS_CARRY);
}
(Instruction::CLD, OpInput::UseImplied) => {
self.registers.status.and(!PS_DECIMAL_MODE);
self.registers.status.and(!Status::PS_DECIMAL_MODE);
}
(Instruction::CLI, OpInput::UseImplied) => {
self.registers.status.and(!PS_DISABLE_INTERRUPTS);
self.registers.status.and(!Status::PS_DISABLE_INTERRUPTS);
}
(Instruction::CLV, OpInput::UseImplied) => {
self.registers.status.and(!PS_OVERFLOW);
self.registers.status.and(!Status::PS_OVERFLOW);
}
(Instruction::CMP, OpInput::UseImmediate(val)) => {
@ -348,13 +351,13 @@ impl CPU {
}
(Instruction::SEC, OpInput::UseImplied) => {
self.registers.status.or(PS_CARRY);
self.registers.status.or(Status::PS_CARRY);
}
(Instruction::SED, OpInput::UseImplied) => {
self.registers.status.or(PS_DECIMAL_MODE);
self.registers.status.or(Status::PS_DECIMAL_MODE);
}
(Instruction::SEI, OpInput::UseImplied) => {
self.registers.status.or(PS_DISABLE_INTERRUPTS);
self.registers.status.or(Status::PS_DISABLE_INTERRUPTS);
}
(Instruction::STA, OpInput::UseAddress(addr)) => {
@ -419,7 +422,7 @@ impl CPU {
let is_negative = value < 0;
status.set_with_mask(
PS_ZERO | PS_NEGATIVE,
Status::PS_ZERO | Status::PS_NEGATIVE,
Status::new(StatusArgs {
zero: is_zero,
negative: is_negative,
@ -434,7 +437,7 @@ impl CPU {
let shifted = (*p_val & !(1 << 7)) << 1;
*p_val = shifted;
status.set_with_mask(
PS_CARRY,
Status::PS_CARRY,
Status::new(StatusArgs {
carry: is_bit_7_set,
..StatusArgs::none()
@ -448,7 +451,7 @@ impl CPU {
let is_bit_0_set = (*p_val & mask) == mask;
*p_val >>= 1;
status.set_with_mask(
PS_CARRY,
Status::PS_CARRY,
Status::new(StatusArgs {
carry: is_bit_0_set,
..StatusArgs::none()
@ -458,13 +461,13 @@ impl CPU {
}
fn rotate_left_with_flags(p_val: &mut u8, status: &mut Status) {
let is_carry_set = status.contains(PS_CARRY);
let is_carry_set = status.contains(Status::PS_CARRY);
let mask = 1 << 7;
let is_bit_7_set = (*p_val & mask) == mask;
let shifted = (*p_val & !(1 << 7)) << 1;
*p_val = shifted + if is_carry_set { 1 } else { 0 };
status.set_with_mask(
PS_CARRY,
Status::PS_CARRY,
Status::new(StatusArgs {
carry: is_bit_7_set,
..StatusArgs::none()
@ -474,13 +477,13 @@ impl CPU {
}
fn rotate_right_with_flags(p_val: &mut u8, status: &mut Status) {
let is_carry_set = status.contains(PS_CARRY);
let is_carry_set = status.contains(Status::PS_CARRY);
let mask = 1;
let is_bit_0_set = (*p_val & mask) == mask;
let shifted = *p_val >> 1;
*p_val = shifted + if is_carry_set { 1 << 7 } else { 0 };
status.set_with_mask(
PS_CARRY,
Status::PS_CARRY,
Status::new(StatusArgs {
carry: is_bit_0_set,
..StatusArgs::none()
@ -519,43 +522,56 @@ impl CPU {
}
fn add_with_carry(&mut self, value: i8) {
if self.registers.status.contains(PS_DECIMAL_MODE) {
// TODO akeeton: Implement binary-coded decimal.
debug!("binary-coded decimal not implemented for add_with_carry");
let a_before: i8 = self.registers.accumulator;
let c_before: i8 = if self.registers.status.contains(Status::PS_CARRY) {
1
} else {
let a_before: i8 = self.registers.accumulator;
let c_before: i8 = if self.registers.status.contains(PS_CARRY) {
1
} else {
0
};
let a_after: i8 = a_before.wrapping_add(c_before).wrapping_add(value);
0
};
let a_after: i8 = a_before.wrapping_add(c_before).wrapping_add(value);
debug_assert_eq!(
a_after as u8,
a_before.wrapping_add(c_before).wrapping_add(value) as u8
);
debug_assert_eq!(
a_after as u8,
a_before.wrapping_add(c_before).wrapping_add(value) as u8
);
let did_carry = (a_after as u8) < (a_before as u8);
let bcd1: i8 = if (a_after & 0x0f) as u8 > 0x09 {
0x06
} else {
0x00
};
let did_overflow = (a_before < 0 && value < 0 && a_after >= 0)
|| (a_before > 0 && value > 0 && a_after <= 0);
let bcd2: i8 = if (a_after.wrapping_add(bcd1) as u8 & 0xf0) as u8 > 0x90 {
0x60
} else {
0x00
};
let mask = PS_CARRY | PS_OVERFLOW;
let result: i8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
a_after.wrapping_add(bcd1).wrapping_add(bcd2)
} else {
a_after
};
self.registers.status.set_with_mask(
mask,
Status::new(StatusArgs {
carry: did_carry,
overflow: did_overflow,
..StatusArgs::none()
}),
);
let did_carry = (result as u8) < (a_before as u8);
self.load_accumulator(a_after);
let did_overflow = (a_before < 0 && value < 0 && a_after >= 0)
|| (a_before > 0 && value > 0 && a_after <= 0);
debug!("accumulator: {}", self.registers.accumulator);
}
let mask = Status::PS_CARRY | Status::PS_OVERFLOW;
self.registers.status.set_with_mask(
mask,
Status::new(StatusArgs {
carry: did_carry,
overflow: did_overflow,
..StatusArgs::none()
}),
);
self.load_accumulator(result);
debug!("accumulator: {}", self.registers.accumulator);
}
fn and(&mut self, value: i8) {
@ -563,56 +579,66 @@ impl CPU {
self.load_accumulator(a_after);
}
// TODO: Implement binary-coded decimal
fn subtract_with_carry(&mut self, value: i8) {
if self.registers.status.contains(PS_DECIMAL_MODE) {
debug!(
"binary-coded decimal not implemented for \
subtract_with_carry"
);
// A - M - (1 - C)
// nc -- 'not carry'
let nc: i8 = if self.registers.status.contains(Status::PS_CARRY) {
0
} else {
// A - M - (1 - C)
1
};
// nc -- 'not carry'
let nc: i8 = if self.registers.status.contains(PS_CARRY) {
0
} else {
1
};
let a_before: i8 = self.registers.accumulator;
let a_before: i8 = self.registers.accumulator;
let a_after = a_before.wrapping_sub(value).wrapping_sub(nc);
let a_after = a_before.wrapping_sub(value).wrapping_sub(nc);
// The overflow flag is set on two's-complement overflow.
//
// range of A is -128 to 127
// range of - M - (1 - C) is -128 to 128
// -(127 + 1) to -(-128 + 0)
//
let over =
((nc == 0 && value < 0) || (nc == 1 && value < -1)) && a_before >= 0 && a_after < 0;
// The carry flag is set on unsigned overflow.
let did_carry = (a_after as u8) > (a_before as u8);
let under = (a_before < 0) && (-value - nc < 0) && a_after >= 0;
// The overflow flag is set on two's-complement overflow.
//
// range of A is -128 to 127
// range of - M - (1 - C) is -128 to 128
// -(127 + 1) to -(-128 + 0)
//
let over =
((nc == 0 && value < 0) || (nc == 1 && value < -1)) && a_before >= 0 && a_after < 0;
let did_overflow = over || under;
let under = (a_before < 0) && (-value - nc < 0) && a_after >= 0;
let mask = Status::PS_CARRY | Status::PS_OVERFLOW;
let did_overflow = over || under;
let bcd1: i8 = if (a_before & 0x0f).wrapping_sub(nc) < (value & 0x0f) {
0x06
} else {
0x00
};
let mask = PS_CARRY | PS_OVERFLOW;
let bcd2: i8 = if (a_after.wrapping_sub(bcd1) as u8 & 0xf0) as u8 > 0x90 {
0x60
} else {
0x00
};
self.registers.status.set_with_mask(
mask,
Status::new(StatusArgs {
carry: did_carry,
overflow: did_overflow,
..StatusArgs::none()
}),
);
let result: i8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
a_after.wrapping_sub(bcd1).wrapping_sub(bcd2)
} else {
a_after
};
self.load_accumulator(a_after);
}
// The carry flag is set on unsigned overflow.
let did_carry = (result as u8) > (a_before as u8);
self.registers.status.set_with_mask(
mask,
Status::new(StatusArgs {
carry: did_carry,
overflow: did_overflow,
..StatusArgs::none()
}),
);
self.load_accumulator(result);
}
fn decrement_memory(&mut self, addr: Address) {
@ -624,7 +650,7 @@ impl CPU {
let is_zero = value_new == 0;
self.registers.status.set_with_mask(
PS_NEGATIVE | PS_ZERO,
Status::PS_NEGATIVE | Status::PS_ZERO,
Status::new(StatusArgs {
negative: is_negative,
zero: is_zero,
@ -643,43 +669,43 @@ impl CPU {
}
fn branch_if_carry_clear(&mut self, addr: Address) {
if !self.registers.status.contains(PS_CARRY) {
if !self.registers.status.contains(Status::PS_CARRY) {
self.registers.program_counter = addr;
}
}
fn branch_if_carry_set(&mut self, addr: Address) {
if self.registers.status.contains(PS_CARRY) {
if self.registers.status.contains(Status::PS_CARRY) {
self.registers.program_counter = addr;
}
}
fn branch_if_equal(&mut self, addr: Address) {
if self.registers.status.contains(PS_ZERO) {
if self.registers.status.contains(Status::PS_ZERO) {
self.registers.program_counter = addr;
}
}
fn branch_if_minus(&mut self, addr: Address) {
if self.registers.status.contains(PS_NEGATIVE) {
if self.registers.status.contains(Status::PS_NEGATIVE) {
self.registers.program_counter = addr;
}
}
fn branch_if_positive(&mut self, addr: Address) {
if !self.registers.status.contains(PS_NEGATIVE) {
if !self.registers.status.contains(Status::PS_NEGATIVE) {
self.registers.program_counter = addr;
}
}
fn branch_if_overflow_clear(&mut self, addr: Address) {
if !self.registers.status.contains(PS_OVERFLOW) {
if !self.registers.status.contains(Status::PS_OVERFLOW) {
self.registers.program_counter = addr;
}
}
fn branch_if_overflow_set(&mut self, addr: Address) {
if self.registers.status.contains(PS_OVERFLOW) {
if self.registers.status.contains(Status::PS_OVERFLOW) {
self.registers.program_counter = addr;
}
}
@ -693,22 +719,22 @@ impl CPU {
// The N flag contains most significant bit of the subtraction result.
fn compare(&mut self, r: i8, val: u8) {
if r as u8 >= val as u8 {
self.registers.status.insert(PS_CARRY);
self.registers.status.insert(Status::PS_CARRY);
} else {
self.registers.status.remove(PS_CARRY);
self.registers.status.remove(Status::PS_CARRY);
}
if r as i8 == val as i8 {
self.registers.status.insert(PS_ZERO);
self.registers.status.insert(Status::PS_ZERO);
} else {
self.registers.status.remove(PS_ZERO);
self.registers.status.remove(Status::PS_ZERO);
}
let diff: i8 = r.wrapping_sub(val as i8);
if diff < 0 {
self.registers.status.insert(PS_NEGATIVE);
self.registers.status.insert(Status::PS_NEGATIVE);
} else {
self.registers.status.remove(PS_NEGATIVE);
self.registers.status.remove(Status::PS_NEGATIVE);
}
}
@ -769,77 +795,126 @@ mod tests {
use super::*;
use num::range_inclusive;
#[test]
fn decimal_add_test() {
let mut cpu = CPU::new();
cpu.registers.status.or(Status::PS_DECIMAL_MODE);
cpu.add_with_carry(0x09);
assert_eq!(cpu.registers.accumulator, 0x09);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
cpu.add_with_carry(0x43);
assert_eq!(cpu.registers.accumulator, 0x52);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
cpu.add_with_carry(0x48);
assert_eq!(cpu.registers.accumulator, 0x00);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), true);
}
#[test]
fn decimal_subtract_test() {
let mut cpu = CPU::new();
cpu.registers
.status
.or(Status::PS_DECIMAL_MODE | Status::PS_CARRY);
cpu.registers.accumulator = 0;
cpu.subtract_with_carry(0x48);
assert_eq!(cpu.registers.accumulator as u8, 0x52);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
cpu.subtract_with_carry(0x43);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
}
#[test]
fn add_with_carry_test() {
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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
cpu.registers.status.remove(PS_CARRY);
cpu.registers.status.remove(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), true);
}
#[test]
@ -849,26 +924,26 @@ mod tests {
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);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
}
#[test]
@ -880,55 +955,55 @@ mod tests {
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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
}
#[test]
@ -940,25 +1015,25 @@ mod tests {
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);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
}
#[test]
@ -969,34 +1044,34 @@ mod tests {
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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), true);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
}
#[test]
@ -1005,25 +1080,25 @@ mod tests {
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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
cpu.dec_x();
cpu.dec_x();
@ -1031,17 +1106,17 @@ mod tests {
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.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), true);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), false);
assert_eq!(cpu.registers.status.contains(Status::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);
assert_eq!(cpu.registers.status.contains(Status::PS_CARRY), false);
assert_eq!(cpu.registers.status.contains(Status::PS_ZERO), false);
assert_eq!(cpu.registers.status.contains(Status::PS_NEGATIVE), true);
assert_eq!(cpu.registers.status.contains(Status::PS_OVERFLOW), false);
}
#[test]
@ -1086,7 +1161,7 @@ mod tests {
cpu.branch_if_equal(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0));
cpu.registers.status.or(PS_ZERO);
cpu.registers.status.or(Status::PS_ZERO);
cpu.branch_if_equal(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
}
@ -1105,7 +1180,7 @@ mod tests {
{
let mut cpu = CPU::new();
cpu.registers.status.or(PS_NEGATIVE);
cpu.registers.status.or(Status::PS_NEGATIVE);
let registers_before = cpu.registers;
cpu.branch_if_minus(Address(0xABCD));
@ -1118,11 +1193,11 @@ mod tests {
fn branch_if_positive_test() {
let mut cpu = CPU::new();
cpu.registers.status.insert(PS_NEGATIVE);
cpu.registers.status.insert(Status::PS_NEGATIVE);
cpu.branch_if_positive(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0));
cpu.registers.status.remove(PS_NEGATIVE);
cpu.registers.status.remove(Status::PS_NEGATIVE);
cpu.branch_if_positive(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
}
@ -1131,11 +1206,11 @@ mod tests {
fn branch_if_overflow_clear_test() {
let mut cpu = CPU::new();
cpu.registers.status.insert(PS_OVERFLOW);
cpu.registers.status.insert(Status::PS_OVERFLOW);
cpu.branch_if_overflow_clear(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0));
cpu.registers.status.remove(PS_OVERFLOW);
cpu.registers.status.remove(Status::PS_OVERFLOW);
cpu.branch_if_overflow_clear(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
}
@ -1147,7 +1222,7 @@ mod tests {
cpu.branch_if_overflow_set(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0));
cpu.registers.status.insert(PS_OVERFLOW);
cpu.registers.status.insert(Status::PS_OVERFLOW);
cpu.branch_if_overflow_set(Address(0xABCD));
assert_eq!(cpu.registers.program_counter, Address(0xABCD));
}
@ -1162,44 +1237,44 @@ mod tests {
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));
assert!(cpu.registers.status.contains(Status::PS_ZERO));
assert!(cpu.registers.status.contains(Status::PS_CARRY));
assert!(!cpu.registers.status.contains(Status::PS_NEGATIVE));
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));
assert!(!cpu.registers.status.contains(Status::PS_ZERO));
assert!(cpu.registers.status.contains(Status::PS_CARRY));
assert!(!cpu.registers.status.contains(Status::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));
assert!(!cpu.registers.status.contains(Status::PS_ZERO));
assert!(!cpu.registers.status.contains(Status::PS_CARRY));
assert!(cpu.registers.status.contains(Status::PS_NEGATIVE));
cpu.execute_instruction((load_instruction, OpInput::UseImmediate(20)));
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));
assert!(!cpu.registers.status.contains(Status::PS_ZERO));
assert!(!cpu.registers.status.contains(Status::PS_CARRY));
assert!(!cpu.registers.status.contains(Status::PS_NEGATIVE));
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));
assert!(!cpu.registers.status.contains(Status::PS_ZERO));
assert!(!cpu.registers.status.contains(Status::PS_CARRY));
assert!(!cpu.registers.status.contains(Status::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));
assert!(!cpu.registers.status.contains(Status::PS_ZERO));
assert!(!cpu.registers.status.contains(Status::PS_CARRY));
assert!(cpu.registers.status.contains(Status::PS_NEGATIVE));
}
#[test]
@ -1246,15 +1321,15 @@ mod tests {
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(Status::PS_ZERO));
} else {
assert!(!cpu.registers.status.contains(PS_ZERO));
assert!(!cpu.registers.status.contains(Status::PS_ZERO));
}
if (a_after as i8) < 0 {
assert!(cpu.registers.status.contains(PS_NEGATIVE));
assert!(cpu.registers.status.contains(Status::PS_NEGATIVE));
} else {
assert!(!cpu.registers.status.contains(PS_NEGATIVE));
assert!(!cpu.registers.status.contains(Status::PS_NEGATIVE));
}
}
}
@ -1274,15 +1349,15 @@ mod tests {
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(Status::PS_ZERO));
} else {
assert!(!cpu.registers.status.contains(PS_ZERO));
assert!(!cpu.registers.status.contains(Status::PS_ZERO));
}
if (a_after as i8) < 0 {
assert!(cpu.registers.status.contains(PS_NEGATIVE));
assert!(cpu.registers.status.contains(Status::PS_NEGATIVE));
} else {
assert!(!cpu.registers.status.contains(PS_NEGATIVE));
assert!(!cpu.registers.status.contains(Status::PS_NEGATIVE));
}
}
}

View File

@ -49,20 +49,22 @@ pub const IRQ_INTERRUPT_VECTOR_HI: Address = Address(0xFFFF);
const MEMORY_SIZE: usize = (ADDR_HI_BARE - ADDR_LO_BARE) as usize + 1usize;
// FIXME: Should this use indirection for `bytes`?
#[derive(Copy)]
#[derive(Copy, Clone)]
pub struct Memory {
bytes: [u8; MEMORY_SIZE],
}
impl Clone for Memory {
fn clone(&self) -> Self {
*self
impl Default for Memory {
fn default() -> Self {
Self::new()
}
}
impl Memory {
pub fn new() -> Memory {
Memory { bytes: [0; MEMORY_SIZE] }
Memory {
bytes: [0; MEMORY_SIZE],
}
}
pub fn get_byte(&self, address: Address) -> u8 {
@ -73,11 +75,8 @@ impl Memory {
&mut self.bytes[address.to_usize()]
}
pub fn get_slice(&self, Address(start): Address, AddressDiff(diff): AddressDiff) -> &[u8] {
let start = start as usize;
let diff = diff as usize;
let end = start + diff;
&self.bytes[start..end]
pub fn get_slice(&self, start: Address, diff: AddressDiff) -> &[u8] {
&self.bytes[start.to_usize()..(start + diff).to_usize()]
}
// Sets the byte at the given address to the given value and returns the
@ -88,20 +87,38 @@ impl Memory {
old_value
}
pub fn set_bytes(&mut self, Address(start): Address, values: &[u8]) {
let start = start as usize;
pub fn set_bytes(&mut self, start: Address, values: &[u8]) {
let start = start.to_usize();
// This panics if the range is invalid
let end = start + values.len();
let slice = &mut self.bytes[start..end];
// JAM: Is this the best way to do this copy?
for (dest, src) in slice.iter_mut().zip(values.iter()) {
*dest = *src;
}
self.bytes[start..end].copy_from_slice(values);
}
pub fn is_stack_address(address: &Address) -> bool {
STACK_ADDRESS_LO <= *address && *address <= STACK_ADDRESS_HI
pub fn is_stack_address(address: Address) -> bool {
(STACK_ADDRESS_LO..=STACK_ADDRESS_HI).contains(&address)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_memory_set_bytes() {
let mut memory = Memory::new();
memory.set_bytes(Address(0x0100), &[1, 2, 3, 4, 5]);
assert_eq!(
memory.get_slice(Address(0x00FF), AddressDiff(7)),
&[0, 1, 2, 3, 4, 5, 0]
);
}
#[test]
#[should_panic]
fn test_memory_overflow_panic() {
let mut memory = Memory::new();
memory.set_bytes(Address(0xFFFE), &[1, 2, 3]);
}
}

View File

@ -26,7 +26,7 @@
// POSSIBILITY OF SUCH DAMAGE.
use address::{Address, AddressDiff};
use memory::{STACK_ADDRESS_LO, STACK_ADDRESS_HI};
use memory::{STACK_ADDRESS_HI, STACK_ADDRESS_LO};
// Useful for constructing Status instances
#[derive(Copy, Clone)]
@ -88,40 +88,43 @@ impl Status {
})
}
pub fn new(StatusArgs { negative,
overflow,
unused,
brk,
decimal_mode,
disable_interrupts,
zero,
carry }: StatusArgs) -> Status
{
pub fn new(
StatusArgs {
negative,
overflow,
unused,
brk,
decimal_mode,
disable_interrupts,
zero,
carry,
}: StatusArgs,
) -> Status {
let mut out = Status::empty();
if negative {
out |= PS_NEGATIVE
out |= Status::PS_NEGATIVE
}
if overflow {
out |= PS_OVERFLOW
out |= Status::PS_OVERFLOW
}
if unused {
out |= PS_UNUSED
out |= Status::PS_UNUSED
}
if brk {
out |= PS_BRK
out |= Status::PS_BRK
}
if decimal_mode {
out |= PS_DECIMAL_MODE
out |= Status::PS_DECIMAL_MODE
}
if disable_interrupts {
out |= PS_DISABLE_INTERRUPTS
out |= Status::PS_DISABLE_INTERRUPTS
}
if zero {
out |= PS_ZERO
out |= Status::PS_ZERO
}
if carry {
out |= PS_CARRY
out |= Status::PS_CARRY
}
out
@ -144,21 +147,18 @@ impl Status {
pub struct StackPointer(pub u8);
impl StackPointer {
pub fn to_address(&self) -> Address {
let StackPointer(sp) = *self;
STACK_ADDRESS_LO + AddressDiff(i32::from(sp))
pub fn to_address(self) -> Address {
STACK_ADDRESS_LO + AddressDiff(i32::from(self.0))
}
// JAM: FIXME: Should we prevent overflow here? What would a 6502 do?
pub fn decrement(&mut self) {
let StackPointer(val) = *self;
*self = StackPointer(val - 1);
self.0 -= 1;
}
pub fn increment(&mut self) {
let StackPointer(val) = *self;
*self = StackPointer(val + 1);
self.0 += 1;
}
}
@ -172,6 +172,12 @@ pub struct Registers {
pub status: Status,
}
impl Default for Registers {
fn default() -> Self {
Self::new()
}
}
impl Registers {
pub fn new() -> Registers {
// TODO akeeton: Revisit these defaults.