Compare commits

...

2 Commits

Author SHA1 Message Date
7d1fd088ef
Finish basic functions of MMU card 2023-01-27 11:55:45 -06:00
923c0373b3
Upgrade crates and switch to clap 4 2023-01-27 11:53:54 -06:00
4 changed files with 681 additions and 483 deletions

267
Cargo.lock generated
View File

@ -4,9 +4,9 @@ version = 3
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.19" version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -22,9 +22,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.66" version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
@ -38,7 +38,7 @@ version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi 0.1.19",
"libc", "libc",
"winapi", "winapi",
] ]
@ -69,15 +69,24 @@ dependencies = [
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.11.1" version = "3.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
[[package]]
name = "card_macro"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.76" version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -109,7 +118,7 @@ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
"clap_derive", "clap_derive",
"clap_lex", "clap_lex 0.2.4",
"indexmap", "indexmap",
"once_cell", "once_cell",
"strsim", "strsim",
@ -117,6 +126,19 @@ dependencies = [
"textwrap", "textwrap",
] ]
[[package]]
name = "clap"
version = "4.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
dependencies = [
"bitflags",
"clap_lex 0.3.1",
"is-terminal",
"strsim",
"termcolor",
]
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "3.2.18" version = "3.2.18"
@ -139,6 +161,15 @@ dependencies = [
"os_str_bytes", "os_str_bytes",
] ]
[[package]]
name = "clap_lex"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
dependencies = [
"os_str_bytes",
]
[[package]] [[package]]
name = "codespan-reporting" name = "codespan-reporting"
version = "0.11.1" version = "0.11.1"
@ -157,9 +188,9 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]] [[package]]
name = "crossterm" name = "crossterm"
version = "0.23.2" version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2102ea4f781910f8a5b98dd061f4c2023f479ce7bb1236330099ceb5a93cf17" checksum = "ab9f7409c70a38a56216480fba371ee460207dd8926ccf5b4160591759559170"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"crossterm_winapi", "crossterm_winapi",
@ -172,6 +203,22 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "crossterm"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
dependencies = [
"bitflags",
"crossterm_winapi",
"libc",
"mio",
"parking_lot",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]] [[package]]
name = "crossterm_winapi" name = "crossterm_winapi"
version = "0.9.0" version = "0.9.0"
@ -193,9 +240,9 @@ dependencies = [
[[package]] [[package]]
name = "cxx" name = "cxx"
version = "1.0.82" version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" checksum = "322296e2f2e5af4270b54df9e85a02ff037e271af20ba3e7fe1575515dc840b8"
dependencies = [ dependencies = [
"cc", "cc",
"cxxbridge-flags", "cxxbridge-flags",
@ -205,9 +252,9 @@ dependencies = [
[[package]] [[package]]
name = "cxx-build" name = "cxx-build"
version = "1.0.82" version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" checksum = "017a1385b05d631e7875b1f151c9f012d37b53491e2a87f65bff5c262b2111d8"
dependencies = [ dependencies = [
"cc", "cc",
"codespan-reporting", "codespan-reporting",
@ -220,15 +267,15 @@ dependencies = [
[[package]] [[package]]
name = "cxxbridge-flags" name = "cxxbridge-flags"
version = "1.0.82" version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" checksum = "c26bbb078acf09bc1ecda02d4223f03bdd28bd4874edcb0379138efc499ce971"
[[package]] [[package]]
name = "cxxbridge-macro" name = "cxxbridge-macro"
version = "1.0.82" version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" checksum = "357f40d1f06a24b60ae1fe122542c1fb05d28d32acb2aed064e84bc2ad1e252e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -248,15 +295,15 @@ dependencies = [
[[package]] [[package]]
name = "either" name = "either"
version = "1.8.0" version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]] [[package]]
name = "elf" name = "elf"
version = "0.7.0" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6de42b0529467fc9a2692fd91585c84dd255fb15b0df0f80299724a9456986c6" checksum = "2ace2c81c1832d02208b8317b90b2de5b3b4f55024b86d3f2ae800353e348fd7"
[[package]] [[package]]
name = "errno" name = "errno"
@ -281,9 +328,9 @@ dependencies = [
[[package]] [[package]]
name = "fd-lock" name = "fd-lock"
version = "3.0.8" version = "3.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb21c69b9fea5e15dbc1049e4b77145dd0ba1c84019c488102de0dc4ea4b0a27" checksum = "28c0190ff0bd3b28bfdd4d0cf9f92faa12880fb0b8ae2054723dd6c76a4efd42"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"rustix", "rustix",
@ -298,9 +345,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]] [[package]]
name = "ghost" name = "ghost"
version = "0.1.6" version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb19fe8de3ea0920d282f7b77dd4227aea6b8b999b42cdf0ca41b2472b14443a" checksum = "41973d4c45f7a35af8753ba3457cc99d406d863941fd7f52663cff54a5ab99b3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -328,6 +375,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "hermit-abi"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "human-repr" name = "human-repr"
version = "1.0.1" version = "1.0.1"
@ -370,9 +426,9 @@ dependencies = [
[[package]] [[package]]
name = "inventory" name = "inventory"
version = "0.3.2" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e21e0a36a4dc4b469422ee17f715e8313f4a637675656d6a13637954278c6f55" checksum = "16fe3b35d64bd1f72917f06425e7573a2f63f74f42c8f56e53ea6826dde3a2b5"
dependencies = [ dependencies = [
"ctor", "ctor",
"ghost", "ghost",
@ -380,14 +436,26 @@ dependencies = [
[[package]] [[package]]
name = "io-lifetimes" name = "io-lifetimes"
version = "1.0.1" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7d367024b3f3414d8e01f437f704f41a9f64ab36f9067fa73e526ad4c763c87" checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys", "windows-sys",
] ]
[[package]]
name = "is-terminal"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
dependencies = [
"hermit-abi 0.2.6",
"io-lifetimes",
"rustix",
"windows-sys",
]
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.10.5"
@ -408,24 +476,24 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.137" version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]] [[package]]
name = "link-cplusplus" name = "link-cplusplus"
version = "1.0.7" version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
dependencies = [ dependencies = [
"cc", "cc",
] ]
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.1.2" version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb68f22743a3fb35785f1e7f844ca5a3de2dde5bd0c0ef5b372065814699b121" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
@ -453,7 +521,8 @@ dependencies = [
"anyhow", "anyhow",
"bitflags", "bitflags",
"bitvec", "bitvec",
"clap", "card_macro",
"clap 3.2.23",
"derive-try-from-primitive", "derive-try-from-primitive",
"elf", "elf",
"human-repr", "human-repr",
@ -496,9 +565,9 @@ checksum = "a785740271256c230f57462d3b83e52f998433a7062fc18f96d5999474a9f915"
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.45.1" version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7bca0d33a384280d1563b97f49cb95303df9fa22588739a04b7d8015c1ccd50" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [ dependencies = [
"overload", "overload",
"winapi", "winapi",
@ -531,15 +600,15 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.16.0" version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
version = "6.4.0" version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e" checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]] [[package]]
name = "overload" name = "overload"
@ -559,9 +628,9 @@ dependencies = [
[[package]] [[package]]
name = "parking_lot_core" name = "parking_lot_core"
version = "0.9.4" version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@ -605,18 +674,18 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.47" version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.21" version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -638,30 +707,32 @@ dependencies = [
[[package]] [[package]]
name = "reedline" name = "reedline"
version = "0.6.0" version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "422f144c06f679da4ab4f082a6d1d43e28bfabb68d009100e6e5520728f99fec" checksum = "555a4285d183a94d140d749712a6600b10e70d7cd6aef91e3cfb65ba09b1d75e"
dependencies = [ dependencies = [
"chrono", "chrono",
"crossterm", "crossterm 0.24.0",
"fd-lock", "fd-lock",
"itertools",
"nu-ansi-term", "nu-ansi-term",
"serde", "serde",
"strip-ansi-escapes", "strip-ansi-escapes",
"strum", "strum",
"strum_macros", "strum_macros",
"thiserror",
"unicode-segmentation", "unicode-segmentation",
"unicode-width", "unicode-width",
] ]
[[package]] [[package]]
name = "reedline-repl-rs" name = "reedline-repl-rs"
version = "1.0.2" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a82ee3209046ff272bd79fe1311ed82823102f741f3130be9dc82ef77d492b3" checksum = "9431c30dcf1210814a728e1ceedf8070a6589cd15d80717f313f92c4d2f73469"
dependencies = [ dependencies = [
"clap", "clap 4.1.4",
"crossterm", "crossterm 0.25.0",
"nu-ansi-term", "nu-ansi-term",
"reedline", "reedline",
"regex", "regex",
@ -671,9 +742,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.7.0" version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -688,9 +759,9 @@ checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.36.1" version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812a2ec2043c4d6bc6482f5be2ab8244613cac2493d128d36c0759e52a626ab3" checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",
@ -702,9 +773,9 @@ dependencies = [
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.9" version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
@ -714,24 +785,24 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "scratch" name = "scratch"
version = "1.0.2" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.147" version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.147" version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -810,9 +881,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.103" version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -827,9 +898,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.1.3" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [ dependencies = [
"winapi-util", "winapi-util",
] ]
@ -842,18 +913,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.37" version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.37" version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -862,9 +933,9 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.44" version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [ dependencies = [
"libc", "libc",
"wasi 0.10.0+wasi-snapshot-preview1", "wasi 0.10.0+wasi-snapshot-preview1",
@ -873,18 +944,18 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.5.9" version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.5" version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
@ -1045,45 +1116,45 @@ dependencies = [
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.42.0" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.42.0" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.42.0" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.42.0" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.42.0" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.42.0" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.42.0" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]] [[package]]
name = "wyz" name = "wyz"

View File

@ -9,6 +9,7 @@ edition = "2021"
anyhow = "1.0.66" anyhow = "1.0.66"
bitflags = "1.3.2" bitflags = "1.3.2"
bitvec = "1.0.0" bitvec = "1.0.0"
card_macro = { version = "0.1.0", path = "card_macro" }
clap = { version = "3.2.23", features = ["clap_derive", "derive"] } clap = { version = "3.2.23", features = ["clap_derive", "derive"] }
derive-try-from-primitive = "1.0.0" derive-try-from-primitive = "1.0.0"
elf = "0.7.0" elf = "0.7.0"

View File

@ -97,402 +97,401 @@ fn main() -> Result<(), anyhow::Error> {
return Ok(()); return Ok(());
} }
Repl::<_, anyhow::Error>::new(state) Repl::<_, anyhow::Error>::new(state)
.with_name("68KEmu") .with_name("68KEmu")
.with_version("0.1.0") .with_version("0.1.0")
.with_banner("68K Backplane Computer Emulator") .with_banner("68K Backplane Computer Emulator")
.with_description("68K Backplane Computer Emulator") .with_description("68K Backplane Computer Emulator")
.with_command( .with_command(
Command::new("card") Command::new("card")
.trailing_var_arg(true)
.arg( .arg(
Arg::new("num") Arg::new("num")
.required(true) .required(true)
.help("The card number to send the command to"), .help("The card number to send the command to"),
) )
.arg( .arg(
Arg::new("cmd") Arg::new("cmd")
.required(true) .trailing_var_arg(true)
.multiple_values(true) .num_args(1..)
.takes_value(true) .required(true)
.help("The command to send"), .help("The command to send"),
) )
.about("Send a command to a card"), .about("Send a command to a card"),
|args, state| { |args, state| {
let num = args.get_one::<String>("num").unwrap().parse::<u8>()?; let num = args.get_one::<String>("num").unwrap().parse::<u8>()?;
state.cpu.bus_mut().card_cmd( state.cpu.bus_mut().card_cmd(
num, num,
&args &args
.get_many::<String>("cmd") .get_many::<String>("cmd")
.unwrap() .unwrap()
.map(String::as_str) .map(String::as_str)
.collect_vec(), .collect_vec(),
)?; )?;
Ok(None)
},
)
.with_command(
Command::new("ls").about("List the cards in the system"),
|_, state| Ok(Some(state.cpu.bus_mut().to_string())),
)
.with_command(
Command::new("regs").about("Show CPU registers"),
|_, state| Ok(Some(format!("{}", state.cpu))),
)
.with_command(
Command::new("step")
.arg(
Arg::new("count")
.takes_value(true)
.help("Count of instructions to step by. Defaults to 1"),
)
.arg(
Arg::new("print_ins")
.long("print_ins")
.short('i')
.action(ArgAction::SetTrue)
.help("Print instructions"),
)
.arg(
Arg::new("print_regs")
.long("print_regs")
.short('r')
.action(ArgAction::SetTrue)
.help("Print ending registers"),
)
.about("Step the CPU"),
|args, state| {
let count = parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?;
let mut out = String::new();
for _ in 0..count {
if state.cpu.stopped {
out += &format!("CPU stopped at PC {:#x}\n", state.cpu.pc());
break;
}
if args.get_flag("print_ins") {
let pc = state.cpu.pc();
out += &disas_fmt(&mut state.cpu, pc, &state.symbol_tables).0;
}
state.cpu.step();
}
if args.get_flag("print_regs") {
out += &format!("{}\n", state.cpu);
}
if out.is_empty() {
Ok(None) Ok(None)
} else { },
out.pop(); // Remove trailing newline
Ok(Some(out))
}
},
)
.with_command(
Command::new("run")
.arg(Arg::new("stop_addr").takes_value(true).help(
"Optional address to stop execution at. Works as a breakpoint only for this run",
))
.arg(
Arg::new("print_ins")
.long("print_ins")
.short('p')
.action(ArgAction::SetTrue)
.help("Print all executed instructions"),
) )
.about("Run the CPU"), .with_command(
|args, state| { Command::new("ls").about("List the cards in the system"),
let mut out = String::new(); |_, state| Ok(Some(state.cpu.bus_mut().to_string())),
while !state.cpu.stopped { )
let stop_addr = args .with_command(
.get_one::<String>("stop_addr") Command::new("regs").about("Show CPU registers"),
.map(|s| state.symbol_tables.parse_location_address(s)) |_, state| Ok(Some(format!("{}", state.cpu))),
.transpose()?; )
if stop_addr.map_or(false, |a| state.cpu.pc() == a) .with_command(
|| state.symbol_tables.breakpoint_set_at(state.cpu.pc()) Command::new("step")
|| state.address_breakpoints.contains(&state.cpu.pc()) .arg(
{ Arg::new("count")
break;
} .help("Count of instructions to step by. Defaults to 1"),
if args.get_flag("print_ins") { )
let pc = state.cpu.pc(); .arg(
out += &disas_fmt(&mut state.cpu, pc, &state.symbol_tables).0; Arg::new("print_ins")
} .long("print_ins")
state.cpu.step(); .short('i')
} .action(ArgAction::SetTrue)
out += &format!("{}\n", state.cpu); .help("Print instructions"),
let pc = state.cpu.pc(); )
out += &disas_fmt(&mut state.cpu, pc, &state.symbol_tables).0; .arg(
out.pop(); // Remove trailing newline Arg::new("print_regs")
Ok(Some(out)) .long("print_regs")
}, .short('r')
.action(ArgAction::SetTrue)
.help("Print ending registers"),
)
.about("Step the CPU"),
|args, state| {
let count = parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?;
let mut out = String::new();
for _ in 0..count {
if state.cpu.stopped {
out += &format!("CPU stopped at PC {:#x}\n", state.cpu.pc());
break;
}
if args.get_flag("print_ins") {
let pc = state.cpu.pc();
out += &disas_fmt(&mut state.cpu, pc, &state.symbol_tables).0;
}
state.cpu.step();
}
if args.get_flag("print_regs") {
out += &format!("{}\n", state.cpu);
}
if out.is_empty() {
Ok(None)
} else {
out.pop(); // Remove trailing newline
Ok(Some(out))
}
},
)
.with_command(
Command::new("run")
.arg(Arg::new("stop_addr").help(
"Optional address to stop execution at. Works as a breakpoint only for this run",
))
.arg(
Arg::new("print_ins")
.long("print_ins")
.short('p')
.action(ArgAction::SetTrue)
.help("Print all executed instructions"),
)
.about("Run the CPU"),
|args, state| {
let mut out = String::new();
while !state.cpu.stopped {
let stop_addr = args
.get_one::<String>("stop_addr")
.map(|s| state.symbol_tables.parse_location_address(s))
.transpose()?;
if stop_addr.map_or(false, |a| state.cpu.pc() == a)
|| state.symbol_tables.breakpoint_set_at(state.cpu.pc())
|| state.address_breakpoints.contains(&state.cpu.pc())
{
break;
}
if args.get_flag("print_ins") {
let pc = state.cpu.pc();
out += &disas_fmt(&mut state.cpu, pc, &state.symbol_tables).0;
}
state.cpu.step();
}
out += &format!("{}\n", state.cpu);
let pc = state.cpu.pc();
out += &disas_fmt(&mut state.cpu, pc, &state.symbol_tables).0;
out.pop(); // Remove trailing newline
Ok(Some(out))
},
)
.with_command(
Command::new("reset").about("Reset the cards and CPU, in that order"),
|_, state| {
state.cpu.bus_mut().reset();
state.cpu.reset();
Ok(None)
},
)
.with_command(
Command::new("peek")
.arg(
Arg::new("count")
.short('c')
.help("The count of values to print"),
)
.arg(
Arg::new("fmt")
.short('f')
.help("The format to print the values in (<fmt><size>)"),
)
.arg(Arg::new("addr").required(true))
.about("Peek a memory address"),
|args, state| {
let (fmt, size) = if let Some(fmt_str) = args.get_one::<String>("fmt") {
if fmt_str.len() != 2 {
return Err(anyhow!("Peek format length must be 2"));
}
let fmt = peek::Format::try_from(fmt_str.chars().next().unwrap())?;
let size = peek::Size::try_from(fmt_str.chars().nth(1).unwrap())?;
state.last_peek_format = (fmt, size);
(fmt, size)
} else {
state.last_peek_format
};
let count = parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?;
let addr = state
.symbol_tables
.parse_location_address(args.get_one::<String>("addr").unwrap())?;
if (size != peek::Size::Byte) & ((addr & 0x1) != 0) {
return Err(anyhow!("Cannot peek words from a non-aligned address"));
}
let mut data = Vec::new();
let bus = state.cpu.bus_mut();
for i in 0..count {
match size {
peek::Size::Byte => data.push(bus.read_byte(addr + i)? as u32),
peek::Size::Word => data.push(bus.read_word(addr + (i * 2))? as u32),
peek::Size::LongWord => data.push(
(bus.read_word(addr + (i * 4))? as u32) << 16
| (bus.read_word(addr + (i * 4) + 2)? as u32),
),
}
}
Ok(Some(
data.chunks(size.chunk_size())
.enumerate()
.map(|(i, c)| {
format!(
"0x{:x}: ",
addr + (size.chunk_size() * size.byte_count() * i) as u32
) + &c.iter().map(|d| fmt.format(*d, size)).join(" ")
})
.join("\n"),
))
},
)
.with_command(
Command::new("poke")
.arg(Arg::new("address").help("The address to write to").required(true))
.arg(Arg::new("data").help("The data to write").required(true))
.arg(
Arg::new("word")
.long("word")
.short('w')
.action(ArgAction::SetTrue)
.help("Write a word instead of a byte"),
)
.about("Write to a memory address"),
|args, state| {
let address = parse::<u32>(args.get_one::<String>("address").unwrap())?;
if args.get_flag("word") {
if (address & 0x1) != 0 {
return Err(anyhow!("Cannot poke a word to a non-aligned address"));
}
let data = parse::<u16>(args.get_one::<String>("data").unwrap())?;
state.cpu.bus_mut().write_word(address, data)?;
} else {
let data = parse::<u8>(args.get_one::<String>("data").unwrap())?;
state.cpu.bus_mut().write_byte(address, data as u8)?;
}
Ok(None)
}
) )
.with_command( .with_command(
Command::new("reset").about("Reset the cards and CPU, in that order"), Command::new("disas")
|_, state| {
state.cpu.bus_mut().reset();
state.cpu.reset();
Ok(None)
},
)
.with_command(
Command::new("peek")
.arg(
Arg::new("count")
.short('c')
.takes_value(true)
.help("The count of values to print"),
)
.arg(
Arg::new("fmt")
.short('f')
.takes_value(true)
.help("The format to print the values in (<fmt><size>)"),
)
.arg(Arg::new("addr").required(true))
.about("Peek a memory address"),
|args, state| {
let (fmt, size) = if let Some(fmt_str) = args.get_one::<String>("fmt") {
if fmt_str.len() != 2 {
return Err(anyhow!("Peek format length must be 2"));
}
let fmt = peek::Format::try_from(fmt_str.chars().next().unwrap())?;
let size = peek::Size::try_from(fmt_str.chars().nth(1).unwrap())?;
state.last_peek_format = (fmt, size);
(fmt, size)
} else {
state.last_peek_format
};
let count = parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?;
let addr = state
.symbol_tables
.parse_location_address(args.get_one::<String>("addr").unwrap())?;
if (size != peek::Size::Byte) & ((addr & 0x1) != 0) {
return Err(anyhow!("Cannot peek words from a non-aligned address"));
}
let mut data = Vec::new();
let bus = state.cpu.bus_mut();
for i in 0..count {
match size {
peek::Size::Byte => data.push(bus.read_byte(addr + i)? as u32),
peek::Size::Word => data.push(bus.read_word(addr + (i * 2))? as u32),
peek::Size::LongWord => data.push(
(bus.read_word(addr + (i * 4))? as u32) << 16
| (bus.read_word(addr + (i * 4) + 2)? as u32),
),
}
}
Ok(Some(
data.chunks(size.chunk_size())
.enumerate()
.map(|(i, c)| {
format!(
"0x{:x}: ",
addr + (size.chunk_size() * size.byte_count() * i) as u32
) + &c.iter().map(|d| fmt.format(*d, size)).join(" ")
})
.join("\n"),
))
},
)
.with_command(
Command::new("poke")
.arg(Arg::new("address").help("The address to write to").required(true))
.arg(Arg::new("data").help("The data to write").required(true))
.arg(
Arg::new("word")
.long("word")
.short('w')
.action(ArgAction::SetTrue)
.help("Write a word instead of a byte"),
)
.about("Write to a memory address"),
|args, state| {
let address = parse::<u32>(args.get_one::<String>("address").unwrap())?;
if args.get_flag("word") {
if (address & 0x1) != 0 {
return Err(anyhow!("Cannot poke a word to a non-aligned address"));
}
let data = parse::<u16>(args.get_one::<String>("data").unwrap())?;
state.cpu.bus_mut().write_word(address, data)?;
} else {
let data = parse::<u8>(args.get_one::<String>("data").unwrap())?;
state.cpu.bus_mut().write_byte(address, data as u8)?;
}
Ok(None)
}
)
.with_command(
Command::new("disas")
.arg(Arg::new("addr").help("Address to start disassembly at. Defaults to current PC")) .arg(Arg::new("addr").help("Address to start disassembly at. Defaults to current PC"))
.arg( .arg(
Arg::new("count") Arg::new("count")
.short('c') .short('c')
.takes_value(true)
.help("Count of instructions to disassemble. Defaults to 1"), .help("Count of instructions to disassemble. Defaults to 1"),
) )
.about("Disassemble a region of memory"), .about("Disassemble a region of memory"),
|args, state| { |args, state| {
let mut addr = args let mut addr = args
.get_one::<String>("addr") .get_one::<String>("addr")
.map_or(Ok(state.cpu.pc()), |s| { .map_or(Ok(state.cpu.pc()), |s| {
state.symbol_tables.parse_location_address(s) state.symbol_tables.parse_location_address(s)
})?; })?;
let count = parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?; let count = parse::<u32>(args.get_one::<String>("count").map_or("1", String::as_str))?;
let mut out = String::new();
for _ in 0..count {
let (fmt, res) = disas_fmt(&mut state.cpu, addr, &state.symbol_tables);
out += &fmt;
match res {
Ok(new_addr) => {
addr = new_addr;
}
Err(_) => {
break;
}
}
}
out.pop(); // Remove trailing newline
Ok(Some(out))
},
)
.with_command(
Command::new("sym")
.arg(Arg::new("file").help("The ELF file to load symbols from"))
.arg(
Arg::new("append")
.long("append")
.short('a')
.action(ArgAction::SetTrue)
.requires("file")
.conflicts_with_all(&["delete", "set-active"])
.help("Append the file's symbols to the loaded list of symbols"),
)
.arg(
Arg::new("delete")
.long("delete")
.short('d')
.action(ArgAction::SetTrue)
.requires("file")
.conflicts_with_all(&["append", "set-active"])
.help("Delete the symbol table instead of loading it"),
)
.arg(
Arg::new("set-active")
.long("set-active")
.short('c')
.takes_value(true)
.value_parser(BoolishValueParser::new())
.requires("file")
.conflicts_with_all(&["append", "delete"])
.help("Set whether the symbol table is active or not"),
)
.about("Load symbols from an ELF file, or list symbols if no file provided"),
|args, state| {
if let Some(file_path) = args.get_one::<String>("file") {
let table_name = Path::new(&file_path).file_name().unwrap().to_str().unwrap();
if args.get_flag("delete") {
state.symbol_tables.delete(table_name)?;
} else if let Some(&active) = args.get_one::<bool>("set-active") {
state.symbol_tables.set_active(table_name, active)?;
} else {
state
.symbol_tables
.load_table(file_path, args.get_flag("append"))?;
}
Ok(None)
} else if state.symbol_tables.is_empty() {
Ok(Some("No symbols".to_string()))
} else {
Ok(Some(format!("{}", state.symbol_tables.symbol_displayer())))
}
},
)
.with_command(
Command::new("resolve")
.arg(
Arg::new("location")
.help("The location to resolve")
.required(true),
)
.about("Resolve a location to an address"),
|args, state| {
let location = args.get_one::<String>("location").unwrap();
Ok(Some(format!(
"{}",
state
.symbol_tables
.parse_location(location)?
.displayer(&state.symbol_tables)
)))
},
)
.with_command(
Command::new("bp")
.arg(Arg::new("location").help("The location to set a breakpoint at"))
.arg(
Arg::new("delete")
.long("delete")
.short('d')
.action(ArgAction::SetTrue)
.requires("location")
.help("Delete the breakpoint instead of setting it"),
)
.about("Set a breakpoint or list current breakpoints"),
|args, state| {
if let Some(location) = args.get_one::<String>("location") {
let location = state.symbol_tables.parse_location(location)?;
if args.get_flag("delete") {
let deleted = match location {
Location::Symbol((table, symbol)) => {
state.symbol_tables.delete_breakpoint(&table, &symbol)?
}
Location::Address(address) => {
state.address_breakpoints.shift_remove(&address)
}
};
if deleted {
Ok(None)
} else {
Ok(Some("No such breakpoint".to_string()))
}
} else {
match location {
Location::Symbol((table, symbol)) => {
state.symbol_tables.set_breakpoint(&table, symbol)?;
}
Location::Address(address) => {
state.address_breakpoints.insert(address);
}
};
Ok(None)
}
} else {
let mut out = String::new(); let mut out = String::new();
out += &format!("{}", state.symbol_tables.breakpoint_displayer()); for _ in 0..count {
if !state.address_breakpoints.is_empty() { let (fmt, res) = disas_fmt(&mut state.cpu, addr, &state.symbol_tables);
if !out.is_empty() { out += &fmt;
out += "\n"; match res {
} Ok(new_addr) => {
out += "Address breakpoints:\n"; addr = new_addr;
out += &format!("{}", state.address_breakpoints.iter().format("\n")); }
Err(_) => {
break;
}
}
} }
if out.is_empty() { out.pop(); // Remove trailing newline
Ok(Some("No breakpoints".to_string())) Ok(Some(out))
} else { },
Ok(Some(out)) )
} .with_command(
} Command::new("sym")
}, .arg(Arg::new("file").help("The ELF file to load symbols from"))
) .arg(
.with_command( Arg::new("append")
Command::new("quit") .long("append")
.visible_alias("q") .short('a')
.visible_alias("exit") .action(ArgAction::SetTrue)
.about("Quit"), .requires("file")
|_, _| process::exit(0), .conflicts_with_all(&["delete", "set-active"])
) .help("Append the file's symbols to the loaded list of symbols"),
// Visible aliases don't actually work, so fake it with hidden subcommands )
.with_command(Command::new("q").hide(true), |_, _| process::exit(0)) .arg(
.with_command(Command::new("exit").hide(true), |_, _| process::exit(0)) Arg::new("delete")
.run()?; .long("delete")
.short('d')
.action(ArgAction::SetTrue)
.requires("file")
.conflicts_with_all(&["append", "set-active"])
.help("Delete the symbol table instead of loading it"),
)
.arg(
Arg::new("set-active")
.long("set-active")
.short('c')
.value_parser(BoolishValueParser::new())
.requires("file")
.conflicts_with_all(&["append", "delete"])
.help("Set whether the symbol table is active or not"),
)
.about("Load symbols from an ELF file, or list symbols if no file provided"),
|args, state| {
if let Some(file_path) = args.get_one::<String>("file") {
let table_name = Path::new(&file_path).file_name().unwrap().to_str().unwrap();
if args.get_flag("delete") {
state.symbol_tables.delete(table_name)?;
} else if let Some(&active) = args.get_one::<bool>("set-active") {
state.symbol_tables.set_active(table_name, active)?;
} else {
state
.symbol_tables
.load_table(file_path, args.get_flag("append"))?;
}
Ok(None)
} else if state.symbol_tables.is_empty() {
Ok(Some("No symbols".to_string()))
} else {
Ok(Some(format!("{}", state.symbol_tables.symbol_displayer())))
}
},
)
.with_command(
Command::new("resolve")
.arg(
Arg::new("location")
.help("The location to resolve")
.required(true),
)
.about("Resolve a location to an address"),
|args, state| {
let location = args.get_one::<String>("location").unwrap();
Ok(Some(format!(
"{}",
state
.symbol_tables
.parse_location(location)?
.displayer(&state.symbol_tables)
)))
},
)
.with_command(
Command::new("bp")
.arg(Arg::new("location").help("The location to set a breakpoint at"))
.arg(
Arg::new("delete")
.long("delete")
.short('d')
.action(ArgAction::SetTrue)
.requires("location")
.help("Delete the breakpoint instead of setting it"),
)
.about("Set a breakpoint or list current breakpoints"),
|args, state| {
if let Some(location) = args.get_one::<String>("location") {
let location = state.symbol_tables.parse_location(location)?;
if args.get_flag("delete") {
let deleted = match location {
Location::Symbol((table, symbol)) => {
state.symbol_tables.delete_breakpoint(&table, &symbol)?
}
Location::Address(address) => {
state.address_breakpoints.shift_remove(&address)
}
};
if deleted {
Ok(None)
} else {
Ok(Some("No such breakpoint".to_string()))
}
} else {
match location {
Location::Symbol((table, symbol)) => {
state.symbol_tables.set_breakpoint(&table, symbol)?;
}
Location::Address(address) => {
state.address_breakpoints.insert(address);
}
};
Ok(None)
}
} else {
let mut out = String::new();
out += &format!("{}", state.symbol_tables.breakpoint_displayer());
if !state.address_breakpoints.is_empty() {
if !out.is_empty() {
out += "\n";
}
out += "Address breakpoints:\n";
out += &format!("{}", state.address_breakpoints.iter().format("\n"));
}
if out.is_empty() {
Ok(Some("No breakpoints".to_string()))
} else {
Ok(Some(out))
}
}
},
)
.with_command(
Command::new("quit")
.visible_alias("q")
.visible_alias("exit")
.about("Quit"),
|_, _| process::exit(0),
)
// Visible aliases don't actually work, so fake it with hidden subcommands
.with_command(Command::new("q").hide(true), |_, _| process::exit(0))
.with_command(Command::new("exit").hide(true), |_, _| process::exit(0))
.run()?;
Ok(()) Ok(())
} }

View File

@ -4,7 +4,7 @@ use nullable_result::NullableResult;
use crate::{ use crate::{
backplane::{Backplane, CardAccessorBuilder, DMAHandler, MMUHandler}, backplane::{Backplane, CardAccessorBuilder, DMAHandler, MMUHandler},
card::{u16_get_be_byte, Card}, card::{u16_get_be_byte, u32_get_be_byte, u32_set_be_byte, Card},
m68k::BusError, m68k::BusError,
register, register,
}; };
@ -35,7 +35,10 @@ impl From<u32> for PagingEntry {
pub struct MmuCard { pub struct MmuCard {
enabled: bool, enabled: bool,
cache: [Option<PagingEntry>; 4096], cache: [Option<PagingEntry>; 4096],
map_frames: [Option<u32>; 4], map_frames: [u32; 4],
map_frames_enabled: [bool; 4],
tlb_clear_entry: u16,
print_debug: bool,
} }
impl Card for MmuCard { impl Card for MmuCard {
@ -44,7 +47,10 @@ impl Card for MmuCard {
Self { Self {
enabled: false, enabled: false,
cache: [None; 4096], cache: [None; 4096],
map_frames: [None; 4], map_frames: [0; 4],
map_frames_enabled: [false; 4],
tlb_clear_entry: 0,
print_debug: false,
}, },
None, None,
)) ))
@ -56,14 +62,78 @@ impl Card for MmuCard {
fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> { fn read_byte_io(&mut self, address: u8) -> NullableResult<u8, BusError> {
match address { match address {
(0x0..=0xF) => {
let map_no = (address / 4) as usize;
let offset = address % 4;
match offset {
(0..=2) => NullableResult::Ok(u32_get_be_byte(self.map_frames[map_no], offset)),
3 => NullableResult::Ok(self.map_frames_enabled[map_no] as u8),
_ => unreachable!(),
}
}
(0xFE..=0xFF) => NullableResult::Ok(u16_get_be_byte(ID, address - 0xFE)), (0xFE..=0xFF) => NullableResult::Ok(u16_get_be_byte(ID, address - 0xFE)),
_ => NullableResult::Null, _ => NullableResult::Null,
} }
} }
fn write_byte_io(&mut self, address: u8, data: u8) -> NullableResult<(), BusError> {
match address {
(0x0..=0xF) => {
let map_no = (address / 4) as usize;
let offset = address % 4;
match offset {
(0..=1) => {
self.map_frames[map_no] =
u32_set_be_byte(self.map_frames[map_no], offset, data);
}
2 => {
self.map_frames[map_no] =
u32_set_be_byte(self.map_frames[map_no], offset, data & 0xf0);
}
3 => {
self.map_frames_enabled[map_no] = (data & 0x1) > 0;
for i in map_no * 1024..(map_no + 1) * 1024 {
self.cache[i] = None;
}
}
_ => unreachable!(),
};
}
(0x10..=0x13) => {
let offset = (address - 0x10) % 4;
match offset {
0 => (),
1 => {
self.tlb_clear_entry = (self.tlb_clear_entry & 0xF) | ((data as u16) << 4);
}
2 => {
self.tlb_clear_entry =
(self.tlb_clear_entry & 0xFF0) | (((data as u16) & 0xF0) >> 4);
}
3 => {
if self.print_debug {
println!(
"Clearing TLB entry {:#x} ( page start {:#x} )",
self.tlb_clear_entry,
(self.tlb_clear_entry as u32) << 12
);
}
self.cache[self.tlb_clear_entry as usize] = None;
}
_ => unreachable!(),
}
}
0x15 => {
self.enabled = (data & 0x1) > 0;
}
_ => (),
}
NullableResult::Ok(())
}
fn cmd(&mut self, cmd: &[&str]) -> anyhow::Result<()> { fn cmd(&mut self, cmd: &[&str]) -> anyhow::Result<()> {
if cmd[0] == "enable" && cmd.len() >= 2 { if cmd[0] == "debug" && cmd.len() >= 2 {
self.enabled = cmd[1].parse()?; self.print_debug = cmd[1].parse()?;
} }
Ok(()) Ok(())
} }
@ -75,9 +145,33 @@ impl Card for MmuCard {
impl Display for MmuCard { impl Display for MmuCard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let q1 = if self.map_frames_enabled[0] {
Some(self.map_frames[0])
} else {
None
};
let q2 = if self.map_frames_enabled[1] {
Some(self.map_frames[1])
} else {
None
};
let q3 = if self.map_frames_enabled[2] {
Some(self.map_frames[2])
} else {
None
};
let q4 = if self.map_frames_enabled[3] {
Some(self.map_frames[3])
} else {
None
};
f.write_fmt(format_args!( f.write_fmt(format_args!(
"MMU card, {}", "MMU card, {} (Q1: {:?}, Q2: {:?}, Q3: {:?}, Q4: {:?})",
if self.enabled { "enabled" } else { "disabled" }, if self.enabled { "enabled" } else { "disabled" },
q1,
q2,
q3,
q4
)) ))
} }
} }
@ -94,26 +188,59 @@ impl MMUHandler for Mmu {
write: bool, write: bool,
) -> NullableResult<u32, BusError> { ) -> NullableResult<u32, BusError> {
let card_accessor = card_accessor.build::<MmuCard>(); let card_accessor = card_accessor.build::<MmuCard>();
if card_accessor.get().enabled { let card = card_accessor.get();
let print_debug = card.print_debug;
if card.enabled {
let page = address >> 12; let page = address >> 12;
let offset = address & 0xFFF; let offset = address & 0xFFF;
let entry = if let Some(entry) = card_accessor.get().cache[page as usize] { let entry = if let Some(entry) = card.cache[page as usize] {
if print_debug {
println!("TLB hit");
}
entry entry
} else { } else {
let map_frame = card_accessor.get().map_frames[(page >> 10) as usize]?; if print_debug {
let entry_address = (map_frame << 12) | ((page & 0x3FF) << 2); println!("TLB miss, fetching entry");
}
if card.map_frames_enabled[(page >> 10) as usize] == false {
if print_debug {
println!("No mapping frame for this quarter");
}
return NullableResult::Null;
}
let map_frame = card.map_frames[(page >> 10) as usize];
let entry_address = (map_frame) | ((page & 0x3FF) << 2);
if print_debug {
println!("Entry is at {:#x}", entry_address);
}
drop(card);
let entry_hi = backplane.read_word_phys(entry_address)?; let entry_hi = backplane.read_word_phys(entry_address)?;
let entry_lo = backplane.read_word_phys(entry_address + 2)?; let entry_lo = backplane.read_word_phys(entry_address + 2)?;
let entry = PagingEntry::from((entry_hi as u32) << 16 | entry_lo as u32); let entry = PagingEntry::from((entry_hi as u32) << 16 | entry_lo as u32);
card_accessor.get().cache[page as usize] = Some(entry); card_accessor.get().cache[page as usize] = Some(entry);
if print_debug {
println!("Fetched entry {:#?}", entry);
}
entry entry
}; };
if entry.present { if entry.present {
if write && !entry.writable { if write && !entry.writable {
if print_debug {
println!("Entry not writable");
}
return NullableResult::Err(BusError); return NullableResult::Err(BusError);
} }
if print_debug {
println!(
"Translation success, translated to {:#x}",
(entry.frame << 12) | offset
);
}
NullableResult::Ok((entry.frame << 12) | offset) NullableResult::Ok((entry.frame << 12) | offset)
} else { } else {
if print_debug {
println!("Entry not present");
}
NullableResult::Null NullableResult::Null
} }
} else { } else {