Disassembler and assembler for register-register mov
This commit is contained in:
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.rs text=auto
|
23
.github/workflows/rust.yml
vendored
23
.github/workflows/rust.yml
vendored
@@ -15,8 +15,13 @@ jobs:
|
||||
"runs-on": "ubuntu-latest",
|
||||
"steps": [
|
||||
{
|
||||
"uses": "actions/checkout@v3",
|
||||
"name": "Checkout"
|
||||
"name": "Checkout",
|
||||
"uses": "actions/checkout@v3"
|
||||
},
|
||||
{
|
||||
"name": "Checkout submodules",
|
||||
"shell": "bash",
|
||||
"run": "auth_header=\"$(git config --local --get http.https://github.com/.extraheader)\" git submodule sync --recursive && git -c \"http.extraheader=$auth_header\" -c protocol.version=2 submodule update --init --force --recursive --depth=1"
|
||||
},
|
||||
{
|
||||
"name": "Install Nix",
|
||||
@@ -35,8 +40,12 @@ jobs:
|
||||
"runs-on": "ubuntu-latest",
|
||||
"steps": [
|
||||
{
|
||||
"uses": "actions/checkout@v3",
|
||||
"name": "Checkout"
|
||||
"name": "Checkout",
|
||||
"uses": "actions/checkout@v3"
|
||||
},
|
||||
{
|
||||
"name": "Checkout submodules",
|
||||
"run": "auth_header=\"$(git config --local --get http.https://github.com/.extraheader)\" git submodule sync --recursive && git -c \"http.extraheader=$auth_header\" -c protocol.version=2 submodule update --init --force --recursive --depth=1"
|
||||
},
|
||||
{
|
||||
"name": "Install Nix",
|
||||
@@ -143,6 +152,10 @@ jobs:
|
||||
"uses": "actions/checkout@v3",
|
||||
"name": "Checkout"
|
||||
},
|
||||
{
|
||||
"name": "Checkout submodules",
|
||||
"run": "auth_header=\"$(git config --local --get http.https://github.com/.extraheader)\" git submodule sync --recursive && git -c \"http.extraheader=$auth_header\" -c protocol.version=2 submodule update --init --force --recursive --depth=1"
|
||||
},
|
||||
{
|
||||
"name": "Install Nix",
|
||||
"uses": "cachix/install-nix-action@v17",
|
||||
@@ -150,7 +163,7 @@ jobs:
|
||||
},
|
||||
{
|
||||
"name": "Run app",
|
||||
"run": "nix run"
|
||||
"run": "nix run . -- computer_enhance/perfaware/part1/listing_0038_many_register_mov computer_enhance/perfaware/part1/listing_0038_many_register_mov.asm"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "computer_enhance"]
|
||||
path = computer_enhance
|
||||
url = https://github.com/cmuratori/computer_enhance
|
402
Cargo.lock
generated
402
Cargo.lock
generated
@@ -2,6 +2,408 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-wincon",
|
||||
"concolor-override",
|
||||
"concolor-query",
|
||||
"is-terminal",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"bitflags",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
|
||||
|
||||
[[package]]
|
||||
name = "concolor-override"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f"
|
||||
|
||||
[[package]]
|
||||
name = "concolor-query"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf"
|
||||
dependencies = [
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.141"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "performance_aware_programming"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.37.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.0",
|
||||
"windows_aarch64_msvc 0.48.0",
|
||||
"windows_i686_gnu 0.48.0",
|
||||
"windows_i686_msvc 0.48.0",
|
||||
"windows_x86_64_gnu 0.48.0",
|
||||
"windows_x86_64_gnullvm 0.48.0",
|
||||
"windows_x86_64_msvc 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
@@ -6,3 +6,5 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.2.1", features = [ "derive" ] }
|
||||
nom = "7.1.3"
|
||||
|
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Performance-Aware Programming coursework
|
||||
|
||||
Me running through [Performance-Aware Programming](https://www.computerenhance.com) in Rust.
|
1
computer_enhance
Submodule
1
computer_enhance
Submodule
Submodule computer_enhance added at 00cc753c91
108
src/assembly.rs
Normal file
108
src/assembly.rs
Normal file
@@ -0,0 +1,108 @@
|
||||
use nom::{
|
||||
branch::alt,
|
||||
bytes::complete::tag,
|
||||
character::complete::{char, digit1, line_ending, not_line_ending, one_of},
|
||||
combinator::map_res,
|
||||
multi::many0,
|
||||
sequence::{preceded, separated_pair, terminated, tuple},
|
||||
IResult,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
register::{ByteRegisterSubset, GeneralRegister, Register, RegisterSubset, SpecialRegister},
|
||||
Instruction, MoveInstruction, Program,
|
||||
};
|
||||
|
||||
fn comment(input: &str) -> IResult<&str, &str> {
|
||||
preceded(char(';'), terminated(not_line_ending, line_ending))(input)
|
||||
}
|
||||
|
||||
fn bits(input: &str) -> IResult<&str, u8> {
|
||||
let p = preceded(tag("bits "), terminated(digit1, line_ending));
|
||||
map_res(p, str::parse)(input)
|
||||
}
|
||||
|
||||
fn general_register(input: &str) -> IResult<&str, GeneralRegister> {
|
||||
map_res(one_of("abcd"), |c| match c {
|
||||
'a' => Ok::<_, ()>(GeneralRegister::A),
|
||||
'b' => Ok(GeneralRegister::B),
|
||||
'c' => Ok(GeneralRegister::C),
|
||||
'd' => Ok(GeneralRegister::D),
|
||||
_ => panic!("cannot hit"),
|
||||
})(input)
|
||||
}
|
||||
|
||||
fn byte_register_subset(input: &str) -> IResult<&str, ByteRegisterSubset> {
|
||||
map_res(one_of("hl"), |c| match c {
|
||||
'h' => Ok::<_, ()>(ByteRegisterSubset::High),
|
||||
'l' => Ok(ByteRegisterSubset::Low),
|
||||
_ => panic!("cannot hit"),
|
||||
})(input)
|
||||
}
|
||||
|
||||
fn register_subset(input: &str) -> IResult<&str, RegisterSubset> {
|
||||
alt((
|
||||
map_res(byte_register_subset, |x| {
|
||||
Ok::<_, ()>(RegisterSubset::Subset(x))
|
||||
}),
|
||||
map_res(char('x'), |_| Ok::<_, ()>(RegisterSubset::All)),
|
||||
))(input)
|
||||
}
|
||||
|
||||
fn special_register(input: &str) -> IResult<&str, SpecialRegister> {
|
||||
alt((
|
||||
map_res(tag("si"), |_| Ok::<_, ()>(SpecialRegister::SourceIndex)),
|
||||
map_res(tag("bp"), |_| Ok::<_, ()>(SpecialRegister::BasePointer)),
|
||||
map_res(tag("sp"), |_| Ok::<_, ()>(SpecialRegister::StackPointer)),
|
||||
map_res(tag("di"), |_| Ok::<_, ()>(SpecialRegister::DestIndex)),
|
||||
))(input)
|
||||
}
|
||||
|
||||
fn register(input: &str) -> IResult<&str, Register> {
|
||||
alt((
|
||||
map_res(tuple((general_register, register_subset)), |(reg, sub)| {
|
||||
Ok::<_, ()>(Register::General(reg, sub))
|
||||
}),
|
||||
map_res(special_register, |r| Ok::<_, ()>(Register::Special(r))),
|
||||
))(input)
|
||||
}
|
||||
|
||||
fn move_instruction(input: &str) -> IResult<&str, MoveInstruction> {
|
||||
map_res(
|
||||
preceded(
|
||||
tag("mov "),
|
||||
tuple((register, tag(", "), register, line_ending)),
|
||||
),
|
||||
|(dest, _, source, _)| Ok::<_, ()>(MoveInstruction { dest, source }),
|
||||
)(input)
|
||||
}
|
||||
|
||||
fn instruction(input: &str) -> IResult<&str, Instruction> {
|
||||
map_res(move_instruction, |v| Ok::<_, ()>(Instruction::Move(v)))(input)
|
||||
}
|
||||
|
||||
fn trivia(input: &str) -> IResult<&str, &str> {
|
||||
alt((comment, line_ending))(input)
|
||||
}
|
||||
|
||||
pub fn program(input: &str) -> IResult<&str, Program<Vec<Instruction>>> {
|
||||
map_res(
|
||||
preceded(
|
||||
many0(trivia),
|
||||
separated_pair(
|
||||
bits,
|
||||
many0(trivia),
|
||||
many0(alt((
|
||||
map_res(instruction, |i| Ok::<_, ()>(Some(i))),
|
||||
map_res(trivia, |_| Ok::<_, ()>(None)),
|
||||
))),
|
||||
),
|
||||
),
|
||||
|(bits, instructions)| {
|
||||
Ok::<_, ()>(Program {
|
||||
bits,
|
||||
instructions: instructions.into_iter().flatten().collect(),
|
||||
})
|
||||
},
|
||||
)(input)
|
||||
}
|
219
src/main.rs
219
src/main.rs
@@ -1,3 +1,218 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
mod assembly;
|
||||
mod register;
|
||||
|
||||
use std::{fmt::Display, fs, path::Path};
|
||||
|
||||
use clap::Parser;
|
||||
use register::{ByteRegisterSubset, Register, RegisterSubset};
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub struct MoveInstruction {
|
||||
source: Register,
|
||||
dest: Register,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum Instruction {
|
||||
Move(MoveInstruction),
|
||||
}
|
||||
|
||||
impl Display for Instruction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Instruction::Move(mov) => f.write_fmt(format_args!("mov {}, {}", mov.dest, mov.source)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
match self {
|
||||
Instruction::Move(mov) => {
|
||||
let mut result = Vec::with_capacity(2);
|
||||
let instruction1 = 0b10001000u8;
|
||||
let mut is_wide = 1u8;
|
||||
// We always pick the 0 direction, so REG indicates the source.
|
||||
let d: u8 = 0;
|
||||
// Register-to-register move
|
||||
let mode = 0b11000000u8;
|
||||
match (&mov.dest, &mov.source) {
|
||||
(
|
||||
Register::General(dest, RegisterSubset::Subset(dest_subset)),
|
||||
Register::General(source, RegisterSubset::Subset(source_subset)),
|
||||
) => {
|
||||
is_wide = 0;
|
||||
result.push(instruction1 + 2 * d + is_wide);
|
||||
|
||||
let dest_offset: u8 = 4 * match dest_subset {
|
||||
ByteRegisterSubset::Low => 0,
|
||||
ByteRegisterSubset::High => 1,
|
||||
};
|
||||
let rm: u8 = dest_offset + dest.to_id();
|
||||
|
||||
let source_offset: u8 = 4 * match source_subset {
|
||||
ByteRegisterSubset::Low => 0,
|
||||
ByteRegisterSubset::High => 1,
|
||||
};
|
||||
let reg: u8 = source_offset + source.to_id();
|
||||
result.push(mode + reg * 8 + rm);
|
||||
}
|
||||
(
|
||||
Register::General(dest, RegisterSubset::All),
|
||||
Register::General(source, RegisterSubset::All),
|
||||
) => {
|
||||
result.push(instruction1 + 2 * d + is_wide);
|
||||
let reg = source.to_id();
|
||||
let rm = dest.to_id();
|
||||
result.push(mode + reg * 8 + rm);
|
||||
}
|
||||
(Register::General(dest, RegisterSubset::All), Register::Special(source)) => {
|
||||
result.push(instruction1 + 2 * d + is_wide);
|
||||
let reg = source.to_id();
|
||||
let rm = dest.to_id();
|
||||
result.push(mode + reg * 8 + rm);
|
||||
}
|
||||
(Register::Special(dest), Register::General(source, RegisterSubset::All)) => {
|
||||
result.push(instruction1 + 2 * d + is_wide);
|
||||
let reg = source.to_id();
|
||||
let rm = dest.to_id();
|
||||
result.push(mode + reg * 8 + rm);
|
||||
}
|
||||
(Register::Special(dest), Register::Special(source)) => {
|
||||
result.push(instruction1 + 2 * d + is_wide);
|
||||
let reg = source.to_id();
|
||||
let rm = dest.to_id();
|
||||
result.push(mode + reg * 8 + rm);
|
||||
}
|
||||
(
|
||||
Register::General(_, RegisterSubset::Subset(_)),
|
||||
Register::General(_, RegisterSubset::All),
|
||||
) => {
|
||||
panic!("tried to move wide into narrow")
|
||||
}
|
||||
(Register::General(_, RegisterSubset::Subset(_)), Register::Special(_)) => {
|
||||
panic!("tried to move wide into narrow")
|
||||
}
|
||||
(Register::Special(_), Register::General(_, RegisterSubset::Subset(_))) => {
|
||||
panic!("tried to move narrow into wide")
|
||||
}
|
||||
(
|
||||
Register::General(_, RegisterSubset::All),
|
||||
Register::General(_, RegisterSubset::Subset(_)),
|
||||
) => {
|
||||
panic!("tried to move narrow into wide")
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Program<T>
|
||||
where
|
||||
T: AsRef<[Instruction]>,
|
||||
{
|
||||
bits: u8,
|
||||
instructions: T,
|
||||
}
|
||||
|
||||
impl<T> Display for Program<T>
|
||||
where
|
||||
T: AsRef<[Instruction]>,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("bits {}\n", self.bits))?;
|
||||
for i in self.instructions.as_ref().iter() {
|
||||
f.write_fmt(format_args!("{}\n", i))?;
|
||||
}
|
||||
std::fmt::Result::Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Program<T>
|
||||
where
|
||||
T: AsRef<[Instruction]>,
|
||||
{
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
if self.bits != 16 {
|
||||
panic!("Only 16-bits supported");
|
||||
}
|
||||
self.instructions
|
||||
.as_ref()
|
||||
.iter()
|
||||
.flat_map(Instruction::to_bytes)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
fn load_machine_code<P>(path: P) -> Vec<u8>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
fs::read(path).unwrap()
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Args {
|
||||
#[arg(value_name = "COMPILED_PATH")]
|
||||
compiled_path: std::path::PathBuf,
|
||||
#[arg(value_name = "ASM_PATH")]
|
||||
asm_path: std::path::PathBuf,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
|
||||
let expected_bytecode = load_machine_code(args.compiled_path);
|
||||
let asm = fs::read_to_string(args.asm_path).unwrap();
|
||||
let (remaining, compiled) = assembly::program(&asm).unwrap();
|
||||
|
||||
if !remaining.is_empty() {
|
||||
println!(
|
||||
"Failed to parse, as there was remaining code:\n{}",
|
||||
remaining
|
||||
);
|
||||
std::process::exit(2)
|
||||
}
|
||||
|
||||
let actual_bytecode = compiled.to_bytes();
|
||||
if expected_bytecode != actual_bytecode {
|
||||
println!(
|
||||
"Expected: {:?}\nActual: {:?}",
|
||||
expected_bytecode, actual_bytecode
|
||||
);
|
||||
std::process::exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_program {
|
||||
use super::assembly::program;
|
||||
|
||||
#[test]
|
||||
fn test_parser() {
|
||||
let input_asm = include_str!(
|
||||
"../computer_enhance/perfaware/part1/listing_0037_single_register_mov.asm"
|
||||
);
|
||||
let input_bytecode =
|
||||
include_bytes!("../computer_enhance/perfaware/part1/listing_0037_single_register_mov");
|
||||
let (remaining, parsed) = program(input_asm).unwrap();
|
||||
assert_eq!(remaining, "");
|
||||
assert_eq!(parsed.bits, 16);
|
||||
for (i, (actual, expected)) in parsed
|
||||
.to_bytes()
|
||||
.iter()
|
||||
.zip(input_bytecode.iter())
|
||||
.enumerate()
|
||||
{
|
||||
if actual != expected {
|
||||
panic!(
|
||||
"Failed assertion: expected {}, got {}, at position {}",
|
||||
expected, actual, i
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
99
src/register.rs
Normal file
99
src/register.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
use std::fmt::{Display, Write};
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum GeneralRegister {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
}
|
||||
|
||||
impl GeneralRegister {
|
||||
pub fn to_id(&self) -> u8 {
|
||||
match self {
|
||||
GeneralRegister::A => 0b00,
|
||||
GeneralRegister::B => 0b11,
|
||||
GeneralRegister::C => 0b01,
|
||||
GeneralRegister::D => 0b10,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for GeneralRegister {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
GeneralRegister::A => f.write_char('a'),
|
||||
GeneralRegister::B => f.write_char('b'),
|
||||
GeneralRegister::C => f.write_char('c'),
|
||||
GeneralRegister::D => f.write_char('d'),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum SpecialRegister {
|
||||
StackPointer,
|
||||
BasePointer,
|
||||
SourceIndex,
|
||||
DestIndex,
|
||||
}
|
||||
|
||||
impl SpecialRegister {
|
||||
pub fn to_id(&self) -> u8 {
|
||||
// These are all wide.
|
||||
4 + match self {
|
||||
SpecialRegister::StackPointer => 0,
|
||||
SpecialRegister::BasePointer => 1,
|
||||
SpecialRegister::SourceIndex => 2,
|
||||
SpecialRegister::DestIndex => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SpecialRegister {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
SpecialRegister::StackPointer => f.write_str("sp"),
|
||||
SpecialRegister::BasePointer => f.write_str("bp"),
|
||||
SpecialRegister::SourceIndex => f.write_str("si"),
|
||||
SpecialRegister::DestIndex => f.write_str("di"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum ByteRegisterSubset {
|
||||
High,
|
||||
Low,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum RegisterSubset {
|
||||
All,
|
||||
Subset(ByteRegisterSubset),
|
||||
}
|
||||
|
||||
impl Display for RegisterSubset {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
RegisterSubset::All => f.write_char('x'),
|
||||
RegisterSubset::Subset(ByteRegisterSubset::Low) => f.write_char('l'),
|
||||
RegisterSubset::Subset(ByteRegisterSubset::High) => f.write_char('h'),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum Register {
|
||||
General(GeneralRegister, RegisterSubset),
|
||||
Special(SpecialRegister),
|
||||
}
|
||||
|
||||
impl Display for Register {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Register::General(r, subset) => f.write_fmt(format_args!("{}{}", r, subset)),
|
||||
Register::Special(special) => f.write_fmt(format_args!("{}", special)),
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user