Merge pull request #17 from terorie/auto-gen-isa
Auto-generate opcode detection, fields and printing
This commit is contained in:
commit
fb65bc8e7d
|
@ -2,15 +2,6 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ansi_term"
|
|
||||||
version = "0.11.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -24,9 +15,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
|
@ -51,24 +42,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.33.3"
|
version = "3.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
|
||||||
"atty",
|
"atty",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"indexmap",
|
||||||
|
"os_str_bytes",
|
||||||
"strsim",
|
"strsim",
|
||||||
|
"termcolor",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
"unicode-width",
|
|
||||||
"vec_map",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ctor"
|
name = "ctor"
|
||||||
version = "0.1.20"
|
version = "0.1.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d"
|
checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
|
@ -91,15 +82,15 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fixedbitset"
|
name = "fixedbitset"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "398ea4fabe40b9b0d885340a2a991a44c8a645624075ad966d21f88688e2b69e"
|
checksum = "279fb028e20b3c4c320317955b77c5e0c9701f05a1d309905d6fc702cdc5053e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.1.16"
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -134,9 +125,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.7.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 = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
|
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
|
@ -144,82 +135,69 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indoc"
|
name = "indoc"
|
||||||
version = "0.3.6"
|
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 = "47741a8bc60fb26eb8d6e0238bbb26d8575ff623fdc97b1a2c00c050b9684ed8"
|
checksum = "e7906a9fababaeacb774f72410e497a1d18de916322e33797bb2cd29baa23c9e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indoc-impl",
|
|
||||||
"proc-macro-hack",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indoc-impl"
|
|
||||||
version = "0.3.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-hack",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"unindent",
|
"unindent",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.10"
|
version = "0.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inventory"
|
name = "inventory"
|
||||||
version = "0.1.10"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f0f7efb804ec95e33db9ad49e4252f049e37e8b0a4652e3cd61f7999f2eff7f"
|
checksum = "ce6b5d8c669bfbad811d95ddd7a1c6cf9cfdbf2777e59928b6f3fa8ff54f72a0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ctor",
|
"ctor",
|
||||||
"ghost",
|
"ghost",
|
||||||
"inventory-impl",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "inventory-impl"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.10.1"
|
version = "0.10.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
|
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.99"
|
version = "0.2.122"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765"
|
checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked-hash-map"
|
||||||
|
version = "0.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.4"
|
version = "0.4.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb"
|
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
|
@ -231,9 +209,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.13.0"
|
version = "1.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -241,15 +219,24 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.8.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.11.1"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
|
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"instant",
|
"instant",
|
||||||
"lock_api",
|
"lock_api",
|
||||||
|
@ -258,9 +245,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot_core"
|
name = "parking_lot_core"
|
||||||
version = "0.8.3"
|
version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"instant",
|
"instant",
|
||||||
|
@ -272,32 +259,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parse_int"
|
name = "parse_int"
|
||||||
version = "0.5.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "15f96500577cfa0a3bad8a88a3c4daa66684828af2e7d349012fa7fc3c725f0c"
|
checksum = "2d695b79916a2c08bcff7be7647ab60d1402885265005a6658ffe6d763553c5a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste"
|
|
||||||
version = "0.1.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
|
|
||||||
dependencies = [
|
|
||||||
"paste-impl",
|
|
||||||
"proc-macro-hack",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "paste-impl"
|
|
||||||
version = "0.1.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-hack",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "petgraph"
|
name = "petgraph"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
|
@ -310,15 +278,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppc750cl"
|
name = "ppc750cl"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"ppc750cl-macros",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppc750cl-flow-graph"
|
name = "ppc750cl-flow-graph"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"dol",
|
"dol",
|
||||||
|
@ -330,24 +298,27 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppc750cl-fuzz"
|
name = "ppc750cl-fuzz"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"ppc750cl",
|
"ppc750cl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppc750cl-macros"
|
name = "ppc750cl-genisa"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
"serde",
|
||||||
|
"serde_yaml",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppc750cl-py"
|
name = "ppc750cl-py"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppc750cl",
|
"ppc750cl",
|
||||||
"pyo3",
|
"pyo3",
|
||||||
|
@ -355,7 +326,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppc750cl-rand"
|
name = "ppc750cl-rand"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppc750cl",
|
"ppc750cl",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
|
@ -364,57 +335,63 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.10"
|
version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-hack"
|
|
||||||
version = "0.5.19"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.28"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
|
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3"
|
name = "pyo3"
|
||||||
version = "0.14.2"
|
version = "0.16.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af205762ba65eec9f27a2fa1a57a40644e8e3368784b8c8b2f2de48f6e8ddd96"
|
checksum = "6b3e99c4c3e790e4fc365b42b70c1f7801f42eadc4ea648fa327e6f5ca29f215"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"indoc",
|
"indoc",
|
||||||
"inventory",
|
"inventory",
|
||||||
"libc",
|
"libc",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"paste",
|
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
|
"pyo3-ffi",
|
||||||
"pyo3-macros",
|
"pyo3-macros",
|
||||||
"unindent",
|
"unindent",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-build-config"
|
name = "pyo3-build-config"
|
||||||
version = "0.14.2"
|
version = "0.16.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "755944027ce803c7238e59c5a18e59c1d0a4553db50b23e9ba209a568353028d"
|
checksum = "2486b96281859ff0a3929ba6467b13751627b974f7137362db38e2bed14b2094"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"target-lexicon",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyo3-ffi"
|
||||||
|
version = "0.16.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd9de1d94557751599f8bd321f10e6c1ef2801067acb58c91138deef2ae83a17"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"pyo3-build-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-macros"
|
name = "pyo3-macros"
|
||||||
version = "0.14.2"
|
version = "0.16.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd31b36bccfd902c78804bd96c28ea93eac6fa0ca311f9d21ef2230b6665b29a"
|
checksum = "0b9584049129b1cfb615243391a6345c726690271ae195ffd6aa3766177296aa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
"pyo3-macros-backend",
|
"pyo3-macros-backend",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
|
@ -422,43 +399,40 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyo3-macros-backend"
|
name = "pyo3-macros-backend"
|
||||||
version = "0.14.2"
|
version = "0.16.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c21c59ba36db9c823e931c662766b0dd01a030b1d96585b67d8857a96a56b972"
|
checksum = "b6c4717e6a55c51a9958eda1f5481ff7f62cccd21f45309c10e4731cb7198dbc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-build-config",
|
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.9"
|
version = "1.0.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.7.3"
|
version = "0.8.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"rand_hc",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_chacha"
|
name = "rand_chacha"
|
||||||
version = "0.2.2"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86",
|
"ppv-lite86",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
|
@ -466,31 +440,28 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_core"
|
name = "rand_core"
|
||||||
version = "0.5.1"
|
version = "0.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"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]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.10"
|
version = "0.2.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -499,18 +470,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.128"
|
version = "1.0.136"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1056a0db1978e9dbf0f6e4fca677f6f9143dc1c19de346f22cac23e422196834"
|
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.128"
|
version = "1.0.136"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "13af2fbb8b60a8950d6c72a56d2095c28870367cc8e10c55e9745bac4995a2c4"
|
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -518,10 +489,22 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sfmt"
|
name = "serde_yaml"
|
||||||
version = "0.6.0"
|
version = "0.8.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "269239cd28e19133d5dc0179d060b00b0b95ce1224792ea5b7c075241d4ee309"
|
checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
"yaml-rust",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sfmt"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e389a3c1536438f85612667cd992dfb7169f60784252342278458e90d37c7565"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
|
@ -529,21 +512,21 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.6.1"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.8.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.74"
|
version = "1.0.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c"
|
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -551,40 +534,46 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "target-lexicon"
|
||||||
version = "0.11.0"
|
version = "0.12.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
checksum = "d7fa7e55043acb85fca6b3c01485a2eeb6b69c5d21002e273c79e465f43b7ac1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-width",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "textwrap"
|
||||||
version = "1.0.26"
|
version = "0.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
|
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.26"
|
version = "1.0.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
|
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.1.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -593,21 +582,15 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unindent"
|
name = "unindent"
|
||||||
version = "0.1.7"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
|
checksum = "514672a55d7380da379785a4d70ca8386c8883ff7eaae877be4d2081cebe73d8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vec_map"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.9.0+wasi-snapshot-preview1"
|
version = "0.10.2+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
|
@ -625,8 +608,26 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaml-rust"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||||
|
dependencies = [
|
||||||
|
"linked-hash-map",
|
||||||
|
]
|
||||||
|
|
|
@ -3,8 +3,8 @@ members = [
|
||||||
"disasm",
|
"disasm",
|
||||||
"disasm-py",
|
"disasm-py",
|
||||||
"dol",
|
"dol",
|
||||||
"macros",
|
|
||||||
"fuzz",
|
"fuzz",
|
||||||
|
"genisa",
|
||||||
"flow-graph",
|
"flow-graph",
|
||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
28
README.md
28
README.md
|
@ -2,9 +2,15 @@
|
||||||
|
|
||||||
Rust tools for working with the PowerPC 750CL family of processors.
|
Rust tools for working with the PowerPC 750CL family of processors.
|
||||||
|
|
||||||
### Python module
|
### Rust crates
|
||||||
|
|
||||||
Build instructions:
|
```shell
|
||||||
|
rustup components add rustfmt
|
||||||
|
cargo run --package ppc750cl-genisa
|
||||||
|
cargo build --release
|
||||||
|
```
|
||||||
|
|
||||||
|
### Python module
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
python -m venv env
|
python -m venv env
|
||||||
|
@ -12,3 +18,21 @@ source ./env/bin/activate
|
||||||
pip install maturin
|
pip install maturin
|
||||||
maturin build -m ./disasm-py/Cargo.toml
|
maturin build -m ./disasm-py/Cargo.toml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Instruction Set
|
||||||
|
|
||||||
|
For those unfamiliar with PowerPC, here are some basics.
|
||||||
|
- PowerPC 7xx is a family of RISC CPUs produced from 1997 to 2012.
|
||||||
|
- They operate with 32-bit words and every instruction is 32-bits wide.
|
||||||
|
- This project focuses (only) on compatibility with the PowerPC 750CL.
|
||||||
|
- This chip is famously packaged as codename "Broadway" for the Nintendo Wii.
|
||||||
|
- Its predecessor PowerPC 750CXe is used in the Nintendo GameCube.
|
||||||
|
- It adds a "paired-singles" SIMD unit and a bunch of other instructions.
|
||||||
|
|
||||||
|
### isa.yaml
|
||||||
|
|
||||||
|
The file [isa.yaml](./isa.yaml) contains a full definition of the PowerPC 750CL instruction set.
|
||||||
|
|
||||||
|
It powers the disassembler, assembler, and Rust/Python bindings code analysis tools.
|
||||||
|
|
||||||
|
Similarly to LLVM TableGen, the program `ppc750cl-genisa` generates a Rust file implementing an instruction decoder.
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
masks.txt
|
|
||||||
__pycache__
|
|
|
@ -1,38 +0,0 @@
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def apply_pattern(pattern, mask, bits):
|
|
||||||
start, stop, value = map(int, pattern.split(","))
|
|
||||||
bit_count = stop - start + 1
|
|
||||||
shift = 31 - stop
|
|
||||||
mask |= ((1 << bit_count) - 1) << shift
|
|
||||||
bits |= value << shift
|
|
||||||
return mask, bits
|
|
||||||
|
|
||||||
|
|
||||||
def dump_mask(line):
|
|
||||||
parts = line.split(" ")
|
|
||||||
opcode = parts[0]
|
|
||||||
patterns = parts[1:]
|
|
||||||
assert len(patterns) > 0
|
|
||||||
mask, bits = 0, 0
|
|
||||||
for pattern in patterns:
|
|
||||||
mask, bits = apply_pattern(pattern, mask, bits)
|
|
||||||
print(f' "{opcode}" & {hex(mask)} == {hex(bits)};')
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
with open("patterns.txt", "r") as patterns, open(
|
|
||||||
"../disasm/src/isa.rs", "w"
|
|
||||||
) as isa_file:
|
|
||||||
sys.stdout = isa_file
|
|
||||||
print("use ppc750cl_macros::isa;")
|
|
||||||
print()
|
|
||||||
print("isa! {")
|
|
||||||
for line in patterns.readlines():
|
|
||||||
dump_mask(line)
|
|
||||||
print("}")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
|
@ -1,222 +0,0 @@
|
||||||
add 0,5,31 21,30,266
|
|
||||||
addc 0,5,31 21,30,21
|
|
||||||
adde 0,5,31 21,30,138
|
|
||||||
addi 0,5,14
|
|
||||||
addic 0,5,12
|
|
||||||
addic. 0,5,13
|
|
||||||
addis 0,5,15
|
|
||||||
addme 0,5,31 16,20,0 22,30,234
|
|
||||||
addze 0,5,31 16,20,0 22,30,202
|
|
||||||
and 0,5,31 21,30,28
|
|
||||||
andc 0,5,31 21,30,60
|
|
||||||
andi. 0,5,28
|
|
||||||
andis. 0,5,29
|
|
||||||
b 0,5,18
|
|
||||||
bc 0,5,16
|
|
||||||
bcctr 0,5,19 16,20,0 21,31,528
|
|
||||||
bclr 0,5,19 16,20,0 21,30,16
|
|
||||||
cmp 0,5,31 9,9,0 21,31,0
|
|
||||||
cmpi 0,5,11 9,9,0
|
|
||||||
cmpl 0,5,31 9,9,0 21,30,32 31,31,0
|
|
||||||
cmpli 0,5,10 9,9,0
|
|
||||||
cntlzw 0,5,31 16,20,0 21,30,26
|
|
||||||
crand 0,5,19 21,30,257 31,31,0
|
|
||||||
crandc 0,5,19 21,30,129 31,31,0
|
|
||||||
creqv 0,5,19 21,30,289 31,31,0
|
|
||||||
crnand 0,5,19 21,30,225 31,31,0
|
|
||||||
crnor 0,5,19 21,30,33 31,31,0
|
|
||||||
cror 0,5,19 21,30,449 31,31,0
|
|
||||||
crorc 0,5,19 21,30,417 31,31,0
|
|
||||||
crxor 0,5,19 21,30,193 31,31,0
|
|
||||||
dcbf 0,5,31 6,10,0 21,30,86 31,31,0
|
|
||||||
dcbi 0,5,31 6,10,0 21,30,470 31,31,0
|
|
||||||
dcbst 0,5,31 6,10,0 21,30,54 31,31,0
|
|
||||||
dcbt 0,5,31 6,10,0 21,30,278 31,31,0
|
|
||||||
dcbtst 0,5,31 6,10,0 21,30,246 31,31,0
|
|
||||||
dcbz 0,5,31 6,10,0 21,30,1014 31,31,0
|
|
||||||
dcbz_l 0,5,4 6,10,0 21,30,1014 31,31,0
|
|
||||||
divw 0,5,31 22,30,491
|
|
||||||
divwu 0,5,31 22,30,459
|
|
||||||
eciwx 0,5,31 22,30,310 31,31,0
|
|
||||||
ecowx 0,5,31 22,30,438 31,31,0
|
|
||||||
eieio 0,5,31 6,20,0 21,30,854 31,31,0
|
|
||||||
eqv 0,5,31 22,30,284
|
|
||||||
extsb 0,5,31 16,20,0 21,30,954
|
|
||||||
extsh 0,5,31 16,20,0 21,30,922
|
|
||||||
fabs 0,5,63 11,15,0 21,30,922
|
|
||||||
fadd 0,5,63 21,25,0 26,30,21
|
|
||||||
fadds 0,5,59 21,25,0 26,30,21
|
|
||||||
fcmpo 0,5,63 9,10,0 21,30,32 31,31,0
|
|
||||||
fcmpu 0,5,63 9,10,0 21,30,0 31,31,0
|
|
||||||
fctiw 0,5,63 11,15,0 21,30,14
|
|
||||||
fctiwz 0,5,63 11,15,0 21,30,15
|
|
||||||
fdiv 0,5,63 21,25,0 26,30,18
|
|
||||||
fdivs 0,5,59 21,25,0 26,30,18
|
|
||||||
fmadd 0,5,63 26,30,29
|
|
||||||
fmadds 0,5,59 26,30,29
|
|
||||||
fmr 0,5,63 11,15,0 21,30,72
|
|
||||||
fmsub 0,5,63 26,30,28
|
|
||||||
fmsubs 0,5,59 26,30,28
|
|
||||||
fmul 0,5,63 16,20,0 26,30,25
|
|
||||||
fmuls 0,5,59 16,20,0 26,30,25
|
|
||||||
fnabs 0,5,63 11,15,0 21,30,136
|
|
||||||
fneg 0,5,63 11,15,0 21,30,40
|
|
||||||
fnmadd 0,5,63 26,30,31
|
|
||||||
fnmadds 0,5,59 26,30,31
|
|
||||||
fnmsub 0,5,63 26,30,30
|
|
||||||
fnmsubs 0,5,59 26,30,30
|
|
||||||
fres 0,5,59 11,15,0 21,25,0 26,30,24
|
|
||||||
frsp 0,5,63 11,15,0 21,30,12
|
|
||||||
frsqrte 0,5,63 11,15,0 21,25,0 26,30,26
|
|
||||||
fsel 0,5,63 26,30,23
|
|
||||||
fsub 0,5,63 21,25,0 26,30,20
|
|
||||||
fsubs 0,5,59 21,25,0 26,30,20
|
|
||||||
icbi 0,5,31 6,10,0 21,30,982 31,31,0
|
|
||||||
isync 0,5,19 6,20,0 21,30,150 31,31,0
|
|
||||||
lbz 0,5,34
|
|
||||||
lbzu 0,5,35
|
|
||||||
lbzux 0,5,31 21,30,119 31,31,0
|
|
||||||
lbzx 0,5,31 21,30,87 31,31,0
|
|
||||||
lfd 0,5,50
|
|
||||||
lfdu 0,5,51
|
|
||||||
lfdux 0,5,31 21,30,631 31,31,0
|
|
||||||
lfdx 0,5,31 21,30,559 31,31,0
|
|
||||||
lfs 0,5,48
|
|
||||||
lfsu 0,5,49
|
|
||||||
lfsux 0,5,31 21,30,567 31,31,0
|
|
||||||
lfsx 0,5,31 21,30,535 31,31,0
|
|
||||||
lha 0,5,42
|
|
||||||
lhau 0,5,43
|
|
||||||
lhaux 0,5,31 21,30,375 31,31,0
|
|
||||||
lhax 0,5,31 21,30,343 31,31,0
|
|
||||||
lhbrx 0,5,31 21,30,790 31,31,0
|
|
||||||
lhz 0,5,40
|
|
||||||
lhzu 0,5,41
|
|
||||||
lhzux 0,5,31 21,30,311 31,31,0
|
|
||||||
lhzx 0,5,31 21,30,279 31,31,0
|
|
||||||
lmw 0,5,46
|
|
||||||
lswi 0,5,31 21,30,597 31,31,0
|
|
||||||
lswx 0,5,31 21,30,533 31,31,0
|
|
||||||
lwarx 0,5,31 21,30,20 31,31,0
|
|
||||||
lwbrx 0,5,31 21,30,534 31,31,0
|
|
||||||
lwz 0,5,32
|
|
||||||
lwzu 0,5,33
|
|
||||||
lwzux 0,5,31 21,30,55 31,31,0
|
|
||||||
lwzx 0,5,31 21,30,23 31,31,0
|
|
||||||
mcrf 0,5,19 10,11,0 20,31,0
|
|
||||||
mcrfs 0,5,63 10,11,0 16,24,0 25,30,64 31,31,0
|
|
||||||
mcrxr 0,5,31 10,11,0 16,24,0 25,30,512 31,31,0
|
|
||||||
mfcr 0,5,31 11,20,0 21,30,19 31,31,0
|
|
||||||
mffs 0,5,31 11,20,0 21,30,583
|
|
||||||
mfmsr 0,5,31 11,20,0 21,30,83 31,31,0
|
|
||||||
mfspr 0,5,31 21,30,339 31,31,0
|
|
||||||
mfsr 0,5,31 11,11,0 16,20,0 21,30,595 31,31,0
|
|
||||||
mfsrin 0,5,31 11,15,0 21,30,659 31,31,0
|
|
||||||
mftb 0,5,31 21,30,371 31,31,0
|
|
||||||
mtcrf 0,5,31 11,11,0 20,20,0 21,30,144 31,31,0
|
|
||||||
mtfsb0 0,5,63 11,20,0 21,30,70
|
|
||||||
mtfsb1 0,5,63 11,20,0 21,30,38
|
|
||||||
mtfsf 0,5,63 6,6,0 15,15,0 21,30,711
|
|
||||||
mtfsfi 0,5,63 9,15,0 20,20,0 21,30,134
|
|
||||||
mtmsr 0,5,31 11,20,0 21,30,146 31,31,0
|
|
||||||
mtspr 0,5,31 21,30,467 31,31,0
|
|
||||||
mtsr 0,5,31 11,11,0 16,20,0 21,30,210 31,31,0
|
|
||||||
mtsrin 0,5,31 11,15,0 21,30,242 31,31,0
|
|
||||||
mulhw 0,5,31 21,21,0 22,30,75
|
|
||||||
mulhwu 0,5,31 21,21,0 22,30,11
|
|
||||||
mulli 0,5,7
|
|
||||||
mullw 0,5,31 22,30,235
|
|
||||||
nand 0,5,31 21,30,476
|
|
||||||
neg 0,5,31 16,20,0 21,30,104
|
|
||||||
nor 0,5,31 21,30,124
|
|
||||||
or 0,5,31 21,30,444
|
|
||||||
orc 0,5,31 21,30,412
|
|
||||||
ori 0,5,24
|
|
||||||
oris 0,5,25
|
|
||||||
psq_l 0,5,56
|
|
||||||
psq_lu 0,5,57
|
|
||||||
psq_lux 0,5,4 25,30,38 31,31,0
|
|
||||||
psq_lx 0,5,4 25,30,6 31,31,0
|
|
||||||
psq_st 0,5,60
|
|
||||||
psq_stu 0,5,61
|
|
||||||
psq_stux 0,5,4 25,30,39 31,31,0
|
|
||||||
psq_stx 0,5,4 25,30,7 31,31,0
|
|
||||||
ps_abs 0,5,4 11,15,0 21,30,264
|
|
||||||
ps_add 0,5,4 21,25,0 26,30,21
|
|
||||||
ps_cmpo0 0,5,4 9,10,0 21,30,32 31,31,0
|
|
||||||
ps_cmpo1 0,5,4 9,10,0 21,30,96 31,31,0
|
|
||||||
ps_cmpu0 0,5,4 9,10,0 21,30,0 31,31,0
|
|
||||||
ps_cmpu1 0,5,4 9,10,0 21,30,64 31,31,0
|
|
||||||
ps_div 0,5,4 21,25,0 26,30,18
|
|
||||||
ps_madd 0,5,4 26,30,29
|
|
||||||
ps_madds0 0,5,4 26,30,14
|
|
||||||
ps_madds1 0,5,4 26,30,15
|
|
||||||
ps_merge00 0,5,4 21,30,528
|
|
||||||
ps_merge01 0,5,4 21,30,560
|
|
||||||
ps_merge10 0,5,4 21,30,592
|
|
||||||
ps_merge11 0,5,4 21,30,624
|
|
||||||
ps_mr 0,5,4 11,15,0 21,30,72
|
|
||||||
ps_msub 0,5,4 26,30,28
|
|
||||||
ps_mul 0,5,4 16,20,0 26,30,25
|
|
||||||
ps_muls0 0,5,4 16,20,0 26,30,12
|
|
||||||
ps_muls1 0,5,4 16,20,0 26,30,13
|
|
||||||
ps_nabs 0,5,4 11,15,0 21,30,136
|
|
||||||
ps_neg 0,5,4 11,15,0 21,30,40
|
|
||||||
ps_nmadd 0,5,4 26,30,31
|
|
||||||
ps_nmsub 0,5,4 26,30,30
|
|
||||||
ps_res 0,5,4 11,15,0 21,25,0 26,30,24
|
|
||||||
ps_rsqrte 0,5,4 11,15,0 21,25,0 26,30,26
|
|
||||||
ps_sel 0,5,4 26,30,23
|
|
||||||
ps_sub 0,5,4 21,25,0 26,30,20
|
|
||||||
ps_sum0 0,5,4 26,30,10
|
|
||||||
ps_sum1 0,5,4 26,30,11
|
|
||||||
rfi 0,5,19 6,20,0 31,31,0
|
|
||||||
rlwimi 0,5,20
|
|
||||||
rlwinm 0,5,21
|
|
||||||
rlwnm 0,5,23
|
|
||||||
sc 0,5,17 6,29,0 30,30,1 31,31,0
|
|
||||||
slw 0,5,31 21,30,24
|
|
||||||
sraw 0,5,31 21,30,792
|
|
||||||
srawi 0,5,31 21,30,824
|
|
||||||
srw 0,5,31 21,30,536
|
|
||||||
stb 0,5,38
|
|
||||||
stbu 0,5,39
|
|
||||||
stbux 0,5,31 22,30,247 31,31,0
|
|
||||||
stbx 0,5,31 22,30,215 31,31,0
|
|
||||||
stfd 0,5,54
|
|
||||||
stfdu 0,5,55
|
|
||||||
stfdux 0,5,31 21,30,759 31,31,0
|
|
||||||
stfdx 0,5,31 21,30,727 31,31,0
|
|
||||||
stfiwx 0,5,31 21,30,983 31,31,0
|
|
||||||
stfs 0,5,52
|
|
||||||
stfsu 0,5,53
|
|
||||||
stfsux 0,5,31 21,30,695 31,31,0
|
|
||||||
stfsx 0,5,31 21,30,663 31,31,0
|
|
||||||
sth 0,5,44
|
|
||||||
sthbrx 0,5,31 21,30,918 31,31,0
|
|
||||||
sthu 0,5,45
|
|
||||||
sthux 0,5,31 21,30,439 31,31,0
|
|
||||||
sthx 0,5,31 21,30,407 31,31,0
|
|
||||||
stmw 0,5,47
|
|
||||||
stswi 0,5,31 21,30,725 31,31,0
|
|
||||||
stswx 0,5,31 21,30,661 31,31,0
|
|
||||||
stw 0,5,36
|
|
||||||
stwbrx 0,5,31 21,30,662 31,31,0
|
|
||||||
stwcx. 0,5,31 21,30,150 31,31,1
|
|
||||||
stwu 0,5,37
|
|
||||||
stwux 0,5,31 21,30,183 31,31,0
|
|
||||||
stwx 0,5,31 21,30,151 31,31,0
|
|
||||||
subf 0,5,31 22,30,40
|
|
||||||
subfc 0,5,31 22,30,8
|
|
||||||
subfe 0,5,31 22,30,136
|
|
||||||
subfic 0,5,8
|
|
||||||
subfme 0,5,31 16,20,0 22,30,232
|
|
||||||
subfze 0,5,31 16,20,0 22,30,200
|
|
||||||
sync 0,5,31 6,20,0 21,30,598 31,31,0
|
|
||||||
tlbie 0,5,31 6,15,0 21,30,306 31,31,0
|
|
||||||
tlbsync 0,5,31 6,20,0 21,30,566 31,31,0
|
|
||||||
tw 0,5,31 21,30,4 31,31,0
|
|
||||||
twi 0,5,3
|
|
||||||
xor 0,5,31 21,30,316
|
|
||||||
xori 0,5,26
|
|
||||||
xoris 0,5,27
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "ppc750cl-py"
|
name = "ppc750cl-py"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
authors = ["Richard Patel <me@terorie.dev>"]
|
authors = ["Richard Patel <me@terorie.dev>"]
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
description = "Python bindings for PowerPC 750CL Disassembler"
|
description = "Python bindings for PowerPC 750CL Disassembler"
|
||||||
|
@ -16,5 +16,5 @@ extension-module = ["pyo3/extension-module"]
|
||||||
default = ["extension-module"]
|
default = ["extension-module"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pyo3 = { version = "0.14", features = ["multiple-pymethods"] }
|
pyo3 = { version = "0.16", features = ["multiple-pymethods"] }
|
||||||
ppc750cl = { version = "0.1.1", path = "../disasm" }
|
ppc750cl = { version = "0.2.0", path = "../disasm" }
|
||||||
|
|
|
@ -1,34 +1,11 @@
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::PyBytes;
|
use pyo3::types::PyBytes;
|
||||||
use pyo3::{PyIterProtocol, PyObjectProtocol};
|
|
||||||
|
use ppc750cl::formatter::FormattedIns;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct Ins(ppc750cl::Ins);
|
struct Ins(ppc750cl::Ins);
|
||||||
|
|
||||||
macro_rules! ins_ufield {
|
|
||||||
($name:ident) => {
|
|
||||||
#[pymethods]
|
|
||||||
impl Ins {
|
|
||||||
#[getter]
|
|
||||||
fn $name(&self) -> PyResult<u32> {
|
|
||||||
Ok(self.0.$name() as u32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! ins_ifield {
|
|
||||||
($name:ident) => {
|
|
||||||
#[pymethods]
|
|
||||||
impl Ins {
|
|
||||||
#[getter]
|
|
||||||
fn $name(&self) -> PyResult<i32> {
|
|
||||||
Ok(self.0.$name() as i32)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl Ins {
|
impl Ins {
|
||||||
#[new]
|
#[new]
|
||||||
|
@ -45,41 +22,11 @@ impl Ins {
|
||||||
fn addr(&self) -> PyResult<u32> {
|
fn addr(&self) -> PyResult<u32> {
|
||||||
Ok(self.0.addr)
|
Ok(self.0.addr)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ins_ufield!(rc);
|
fn __str__(&self) -> String {
|
||||||
ins_ufield!(aa);
|
FormattedIns(self.0.clone()).to_string()
|
||||||
ins_ufield!(lk);
|
}
|
||||||
ins_ufield!(l);
|
}
|
||||||
ins_ufield!(oe);
|
|
||||||
ins_ufield!(w);
|
|
||||||
ins_ufield!(s);
|
|
||||||
ins_ufield!(d);
|
|
||||||
ins_ufield!(a);
|
|
||||||
ins_ufield!(b);
|
|
||||||
ins_ufield!(c);
|
|
||||||
ins_ufield!(crb_d);
|
|
||||||
ins_ufield!(crb_a);
|
|
||||||
ins_ufield!(crb_b);
|
|
||||||
ins_ufield!(crm);
|
|
||||||
ins_ufield!(sr);
|
|
||||||
ins_ufield!(spr);
|
|
||||||
ins_ufield!(fm);
|
|
||||||
ins_ufield!(crf_d);
|
|
||||||
ins_ufield!(crf_s);
|
|
||||||
ins_ifield!(simm);
|
|
||||||
ins_ufield!(uimm);
|
|
||||||
ins_ufield!(bo);
|
|
||||||
ins_ufield!(bi);
|
|
||||||
ins_ufield!(sh);
|
|
||||||
ins_ufield!(mb);
|
|
||||||
ins_ufield!(me);
|
|
||||||
ins_ufield!(me_31sub);
|
|
||||||
ins_ifield!(bd);
|
|
||||||
ins_ifield!(li);
|
|
||||||
ins_ufield!(to);
|
|
||||||
ins_ufield!(ps_l);
|
|
||||||
ins_ifield!(ps_d);
|
|
||||||
|
|
||||||
impl From<ppc750cl::Ins> for Ins {
|
impl From<ppc750cl::Ins> for Ins {
|
||||||
fn from(ins: ppc750cl::Ins) -> Self {
|
fn from(ins: ppc750cl::Ins) -> Self {
|
||||||
|
@ -87,13 +34,6 @@ impl From<ppc750cl::Ins> for Ins {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyproto]
|
|
||||||
impl<'a> PyObjectProtocol<'a> for Ins {
|
|
||||||
fn __str__(&self) -> String {
|
|
||||||
self.0.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct DisasmIterator {
|
struct DisasmIterator {
|
||||||
bytes: Py<PyBytes>,
|
bytes: Py<PyBytes>,
|
||||||
|
@ -102,8 +42,8 @@ struct DisasmIterator {
|
||||||
left: usize,
|
left: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyproto]
|
#[pymethods]
|
||||||
impl PyIterProtocol for DisasmIterator {
|
impl DisasmIterator {
|
||||||
fn __iter__(slf: PyRef<Self>) -> PyRef<DisasmIterator> {
|
fn __iter__(slf: PyRef<Self>) -> PyRef<DisasmIterator> {
|
||||||
slf
|
slf
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "ppc750cl"
|
name = "ppc750cl"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
authors = ["Richard Patel <me@terorie.dev>"]
|
authors = ["Richard Patel <me@terorie.dev>"]
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
description = "Disassembler for PowerPC 750CL"
|
description = "Disassembler for PowerPC 750CL"
|
||||||
|
@ -9,5 +9,5 @@ keywords = ["powerpc", "wii", "gamecube"]
|
||||||
repository = "https://github.com/terorie/ppc750cl"
|
repository = "https://github.com/terorie/ppc750cl"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
num-traits = "0.2.14"
|
num-traits = "0.2"
|
||||||
ppc750cl-macros = { path = "../macros", version = "0.1.1" }
|
serde = "1.0"
|
||||||
|
|
|
@ -1,251 +1,33 @@
|
||||||
use std::fmt::{Display, LowerHex, UpperHex};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
use num_traits::PrimInt;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::Ins;
|
pub struct FormattedIns(pub Ins);
|
||||||
|
|
||||||
type IOResult = std::io::Result<()>;
|
impl Display for FormattedIns {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
pub trait AsmFormatter<W>
|
let simple = self.0.clone().simplified();
|
||||||
where
|
write!(f, "{}{}", simple.mnemonic, simple.ins.suffix())?;
|
||||||
W: Write,
|
let mut writing_offset = false;
|
||||||
{
|
for (i, arg) in simple.args.iter().enumerate() {
|
||||||
/// Returns the underlying writer.
|
if i == 0 {
|
||||||
fn writer(&mut self) -> &mut W;
|
write!(f, " ")?;
|
||||||
|
}
|
||||||
/// Callback for custom styling before writing an instruction.
|
if i > 0 && !writing_offset {
|
||||||
fn before_instruction(&mut self, _: &Ins) -> IOResult {
|
write!(f, ", ")?;
|
||||||
Ok(())
|
}
|
||||||
}
|
if let Argument::Offset(val) = arg {
|
||||||
/// Callback for custom styling after writing an instruction.
|
write!(f, "{}(", val)?;
|
||||||
fn after_instruction(&mut self, _: &Ins) -> IOResult {
|
writing_offset = true;
|
||||||
Ok(())
|
continue;
|
||||||
}
|
} else {
|
||||||
|
write!(f, "{}", arg)?;
|
||||||
/// Writes the instruction mnemonic.
|
}
|
||||||
fn write_mnemonic(&mut self, name: &str) -> IOResult {
|
if writing_offset {
|
||||||
write!(self.writer(), "{}", name)
|
write!(f, ")")?;
|
||||||
}
|
writing_offset = false;
|
||||||
|
}
|
||||||
/// Separates the instruction mnemonic and arguments.
|
|
||||||
fn write_opcode_separator(&mut self) -> IOResult {
|
|
||||||
write!(self.writer(), " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Separates two instruction arguments (e.g. registers).
|
|
||||||
fn write_operand_separator(&mut self) -> IOResult {
|
|
||||||
write!(self.writer(), ", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes a general-purpose register argument.
|
|
||||||
fn write_gpr(&mut self, reg: u8) -> IOResult {
|
|
||||||
write!(self.writer(), "r{}", reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes a nullable general-purpose register argument.
|
|
||||||
fn write_gpr0(&mut self, reg: u8) -> IOResult {
|
|
||||||
if reg != 0 {
|
|
||||||
self.write_gpr(reg)
|
|
||||||
} else {
|
|
||||||
write!(self.writer(), "0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes a floating point register argument.
|
|
||||||
fn write_fpr(&mut self, reg: u8) -> IOResult {
|
|
||||||
write!(self.writer(), "f{}", reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes a condition register argument.
|
|
||||||
fn write_cr(&mut self, reg: u8) -> IOResult {
|
|
||||||
write!(self.writer(), "cr{}", reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes a paired-singles quantization register argument.
|
|
||||||
fn write_qr(&mut self, reg: u8) -> IOResult {
|
|
||||||
write!(self.writer(), "qr{}", reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_sr(&mut self, reg: u8) -> IOResult {
|
|
||||||
write!(self.writer(), "{}", reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the mnemonic 'o' suffix.
|
|
||||||
fn write_oe(&mut self, oe: u8) -> IOResult {
|
|
||||||
if oe != 0 {
|
|
||||||
write!(self.writer(), "o")?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the mnemonic 'a' suffix.
|
|
||||||
fn write_aa(&mut self, aa: u8) -> IOResult {
|
|
||||||
if aa != 0 {
|
|
||||||
write!(self.writer(), "a")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the mnemonic 'l' suffix.
|
|
||||||
fn write_lk(&mut self, lk: u8) -> IOResult {
|
|
||||||
if lk != 0 {
|
|
||||||
write!(self.writer(), "l")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the mnemonic '.' suffix.
|
|
||||||
fn write_rc(&mut self, rc: u8) -> IOResult {
|
|
||||||
if rc != 0 {
|
|
||||||
write!(self.writer(), ".")?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes an unsigned immediate.
|
|
||||||
fn write_uimm<T: Into<u16>>(&mut self, uimm: T) -> IOResult {
|
|
||||||
let uimm = uimm.into();
|
|
||||||
if uimm < 16 {
|
|
||||||
write!(self.writer(), "{}", uimm)
|
|
||||||
} else {
|
|
||||||
write!(self.writer(), "{:#x}", uimm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes a signed immediate.
|
|
||||||
fn write_simm<T: PrimInt + Into<i32> + Display>(&mut self, simm: T) -> IOResult {
|
|
||||||
let simm: i32 = simm.into();
|
|
||||||
if simm < 8 {
|
|
||||||
write!(self.writer(), "{}", simm)
|
|
||||||
} else {
|
|
||||||
write!(self.writer(), "{:#x}", ReallySigned(simm))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes an instruction-specific field like the compare mode.
|
|
||||||
fn write_mode<P: PrimInt + Display>(&mut self, mode: P) -> IOResult {
|
|
||||||
write!(self.writer(), "{}", mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_fm(&mut self, fm: u16) -> IOResult {
|
|
||||||
write!(self.writer(), "{}", fm)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_offset_unsigned_open<T: Into<u32>>(&mut self, offset: T) -> IOResult {
|
|
||||||
let offset = offset.into();
|
|
||||||
if offset < 15 {
|
|
||||||
write!(self.writer(), "{}(", offset)
|
|
||||||
} else {
|
|
||||||
write!(self.writer(), "{:#x}(", offset)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes an offset prefix.
|
|
||||||
///
|
|
||||||
/// The next write calls that follow should be:
|
|
||||||
/// - An operand (almost always a general-purpose register)
|
|
||||||
/// - `write_offset_close()`
|
|
||||||
fn write_offset_open<T: Into<i32>>(&mut self, offset: T) -> IOResult {
|
|
||||||
let offset = offset.into();
|
|
||||||
if -9 < offset && offset < 10 {
|
|
||||||
write!(self.writer(), "{}(", offset)
|
|
||||||
} else {
|
|
||||||
write!(self.writer(), "{:#x}(", ReallySigned(offset))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Closes an offset prefix.
|
|
||||||
fn write_offset_close(&mut self) -> IOResult {
|
|
||||||
write!(self.writer(), ")")
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Writes a branch target given the jump offset and current program counter.
|
|
||||||
fn write_branch_target(&mut self, offset: i32, _: u32) -> IOResult {
|
|
||||||
write!(self.writer(), "{:#x}", ReallySigned(offset))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SimpleFormatter<W: Write> {
|
|
||||||
pub writer: W,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: Write> SimpleFormatter<W> {
|
|
||||||
pub fn new(writer: W) -> Self {
|
|
||||||
Self { writer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: Write> AsmFormatter<W> for SimpleFormatter<W> {
|
|
||||||
fn writer(&mut self) -> &mut W {
|
|
||||||
&mut self.writer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DoldecompFormatter<W: Write> {
|
|
||||||
pub writer: W,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: Write> DoldecompFormatter<W> {
|
|
||||||
pub fn new(writer: W) -> Self {
|
|
||||||
Self { writer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<W: Write> AsmFormatter<W> for DoldecompFormatter<W> {
|
|
||||||
fn writer(&mut self) -> &mut W {
|
|
||||||
&mut self.writer
|
|
||||||
}
|
|
||||||
|
|
||||||
fn before_instruction(&mut self, ins: &Ins) -> IOResult {
|
|
||||||
write!(
|
|
||||||
&mut self.writer,
|
|
||||||
"/* {:0>8X} {:0>2X} {:0>2X} {:0>2X} {:0>2X} */\t",
|
|
||||||
ins.addr,
|
|
||||||
(ins.code >> 24) as u8,
|
|
||||||
(ins.code >> 16) as u8,
|
|
||||||
(ins.code >> 8) as u8,
|
|
||||||
ins.code as u8
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/44711012/how-do-i-format-a-signed-integer-to-a-sign-aware-hexadecimal-representation
|
|
||||||
struct ReallySigned<N: PrimInt>(N);
|
|
||||||
|
|
||||||
impl<N: PrimInt> LowerHex for ReallySigned<N> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
let num = self.0.to_i32().unwrap();
|
|
||||||
let prefix = if f.alternate() { "0x" } else { "" };
|
|
||||||
let bare_hex = format!("{:x}", num.abs());
|
|
||||||
f.pad_integral(num >= 0, prefix, &bare_hex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: PrimInt> UpperHex for ReallySigned<N> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
let num = self.0.to_i32().unwrap();
|
|
||||||
let prefix = if f.alternate() { "0x" } else { "" };
|
|
||||||
let bare_hex = format!("{:X}", num.abs());
|
|
||||||
f.pad_integral(num >= 0, prefix, &bare_hex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_doldecomp_formatter() {
|
|
||||||
let buf = Vec::<u8>::new();
|
|
||||||
let mut formatter = DoldecompFormatter::new(buf);
|
|
||||||
|
|
||||||
let ins = Ins::new(0x48000007, 6);
|
|
||||||
ins.write_string(&mut formatter).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
String::from_utf8(formatter.writer).unwrap(),
|
|
||||||
"/* 00000006 48 00 00 07 */\tbla 0x4"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,570 +0,0 @@
|
||||||
#![allow(clippy::bad_bit_mask)]
|
|
||||||
|
|
||||||
use crate::{bit, bits};
|
|
||||||
use ppc750cl_macros::isa;
|
|
||||||
|
|
||||||
isa! {
|
|
||||||
"add" & 0xfc0007fe == 0x7c000214;
|
|
||||||
//"addc" & 0xfc0007fe == 0x7c00002a;
|
|
||||||
"addc" & 0x0 == 0x0;
|
|
||||||
"adde" & 0xfc0007fe == 0x7c000114;
|
|
||||||
"addi" & 0xfc000000 == 0x38000000;
|
|
||||||
"addic" & 0xfc000000 == 0x30000000;
|
|
||||||
"addic." & 0xfc000000 == 0x34000000;
|
|
||||||
"addis" & 0xfc000000 == 0x3c000000;
|
|
||||||
"addme" & 0xfc00fbfe == 0x7c0001d4;
|
|
||||||
"addze" & 0xfc00fbfe == 0x7c000194;
|
|
||||||
"and" & 0xfc0007fe == 0x7c000038;
|
|
||||||
"andc" & 0xfc0007fe == 0x7c000078;
|
|
||||||
"andi." & 0xfc000000 == 0x70000000;
|
|
||||||
"andis." & 0xfc000000 == 0x74000000;
|
|
||||||
"b" & 0xfc000000 == 0x48000000;
|
|
||||||
//"bc" & 0xfc000000 == 0x40000000;
|
|
||||||
"bc" & 0x0 == 0x0; // TODO
|
|
||||||
//"bcctr" & 0xfc00ffff == 0x4c000210;
|
|
||||||
"bcctr" & 0x0 == 0x0; // TODO
|
|
||||||
"bclr" & 0xfc00fffe == 0x4c000020;
|
|
||||||
"cmp" & 0xfc4007ff == 0x7c000000;
|
|
||||||
"cmpi" & 0xfc400000 == 0x2c000000;
|
|
||||||
"cmpl" & 0xfc4007ff == 0x7c000040;
|
|
||||||
"cmpli" & 0xfc400000 == 0x28000000;
|
|
||||||
"cntlzw" & 0xfc00fffe == 0x7c000034;
|
|
||||||
"crand" & 0xfc0007ff == 0x4c000202;
|
|
||||||
"crandc" & 0xfc0007ff == 0x4c000102;
|
|
||||||
"creqv" & 0xfc0007ff == 0x4c000242;
|
|
||||||
"crnand" & 0xfc0007ff == 0x4c0001c2;
|
|
||||||
"crnor" & 0xfc0007ff == 0x4c000042;
|
|
||||||
"cror" & 0xfc0007ff == 0x4c000382;
|
|
||||||
"crorc" & 0xfc0007ff == 0x4c000342;
|
|
||||||
"crxor" & 0xfc0007ff == 0x4c000182;
|
|
||||||
"dcbf" & 0xffe007ff == 0x7c0000ac;
|
|
||||||
"dcbi" & 0xffe007ff == 0x7c0003ac;
|
|
||||||
"dcbst" & 0xffe007ff == 0x7c00006c;
|
|
||||||
"dcbt" & 0xffe007ff == 0x7c00022c;
|
|
||||||
"dcbtst" & 0xffe007ff == 0x7c0001ec;
|
|
||||||
"dcbz" & 0xffe007ff == 0x7c0007ec;
|
|
||||||
"dcbz_l" & 0xffe007ff == 0x100007ec;
|
|
||||||
"divw" & 0xfc0003fe == 0x7c0003d6;
|
|
||||||
"divwu" & 0xfc0003fe == 0x7c000396;
|
|
||||||
"eciwx" & 0xfc0003ff == 0x7c00026c;
|
|
||||||
"ecowx" & 0xfc0003ff == 0x7c00036c;
|
|
||||||
"eieio" & 0xffffffff == 0x7c0006ac;
|
|
||||||
"eqv" & 0xfc0003fe == 0x7c000238;
|
|
||||||
"extsb" & 0xfc00fffe == 0x7c000774;
|
|
||||||
"extsh" & 0xfc00fffe == 0x7c000734;
|
|
||||||
//"fabs" & 0xfc1f07fe == 0xfc000734;
|
|
||||||
"fabs" & 0x0 == 0x0; // TODO
|
|
||||||
"fadd" & 0xfc0007fe == 0xfc00002a;
|
|
||||||
"fadds" & 0xfc0007fe == 0xec00002a;
|
|
||||||
"fcmpo" & 0xfc6007ff == 0xfc000040;
|
|
||||||
"fcmpu" & 0xfc6007ff == 0xfc000000;
|
|
||||||
"fctiw" & 0xfc1f07fe == 0xfc00001c;
|
|
||||||
"fctiwz" & 0xfc1f07fe == 0xfc00001e;
|
|
||||||
"fdiv" & 0xfc0007fe == 0xfc000024;
|
|
||||||
"fdivs" & 0xfc0007fe == 0xec000024;
|
|
||||||
"fmadd" & 0xfc00003e == 0xfc00003a;
|
|
||||||
"fmadds" & 0xfc00003e == 0xec00003a;
|
|
||||||
"fmr" & 0xfc1f07fe == 0xfc000090;
|
|
||||||
"fmsub" & 0xfc00003e == 0xfc000038;
|
|
||||||
"fmsubs" & 0xfc00003e == 0xec000038;
|
|
||||||
"fmul" & 0xfc00f83e == 0xfc000032;
|
|
||||||
"fmuls" & 0xfc00f83e == 0xec000032;
|
|
||||||
"fnabs" & 0xfc1f07fe == 0xfc000110;
|
|
||||||
//"fneg" & 0xfc1f07fe == 0xfc000050;
|
|
||||||
"fneg" & 0x0 == 0x0; // TODO
|
|
||||||
"fnmadd" & 0xfc00003e == 0xfc00003e;
|
|
||||||
"fnmadds" & 0xfc00003e == 0xec00003e;
|
|
||||||
"fnmsub" & 0xfc00003e == 0xfc00003c;
|
|
||||||
"fnmsubs" & 0xfc00003e == 0xec00003c;
|
|
||||||
"fres" & 0xfc1f07fe == 0xec000030;
|
|
||||||
"frsp" & 0xfc1f07fe == 0xfc000018;
|
|
||||||
"frsqrte" & 0xfc1f07fe == 0xfc000034;
|
|
||||||
"fsel" & 0xfc00003e == 0xfc00002e;
|
|
||||||
"fsub" & 0xfc0007fe == 0xfc000028;
|
|
||||||
"fsubs" & 0xfc0007fe == 0xec000028;
|
|
||||||
"icbi" & 0xffe007ff == 0x7c0007ac;
|
|
||||||
"isync" & 0xffffffff == 0x4c00012c;
|
|
||||||
"lbz" & 0xfc000000 == 0x88000000;
|
|
||||||
"lbzu" & 0xfc000000 == 0x8c000000;
|
|
||||||
"lbzux" & 0xfc0007ff == 0x7c0000ee;
|
|
||||||
"lbzx" & 0xfc0007ff == 0x7c0000ae;
|
|
||||||
"lfd" & 0xfc000000 == 0xc8000000;
|
|
||||||
"lfdu" & 0xfc000000 == 0xcc000000;
|
|
||||||
"lfdux" & 0xfc0007ff == 0x7c0004ee;
|
|
||||||
//"lfdx" & 0xfc0007ff == 0x7c00045e;
|
|
||||||
"lfdx" & 0x0 == 0x0;
|
|
||||||
"lfs" & 0xfc000000 == 0xc0000000;
|
|
||||||
"lfsu" & 0xfc000000 == 0xc4000000;
|
|
||||||
"lfsux" & 0xfc0007ff == 0x7c00046e;
|
|
||||||
"lfsx" & 0xfc0007ff == 0x7c00042e;
|
|
||||||
"lha" & 0xfc000000 == 0xa8000000;
|
|
||||||
"lhau" & 0xfc000000 == 0xac000000;
|
|
||||||
"lhaux" & 0xfc0007ff == 0x7c0002ee;
|
|
||||||
"lhax" & 0xfc0007ff == 0x7c0002ae;
|
|
||||||
"lhbrx" & 0xfc0007ff == 0x7c00062c;
|
|
||||||
"lhz" & 0xfc000000 == 0xa0000000;
|
|
||||||
"lhzu" & 0xfc000000 == 0xa4000000;
|
|
||||||
"lhzux" & 0xfc0007ff == 0x7c00026e;
|
|
||||||
"lhzx" & 0xfc0007ff == 0x7c00022e;
|
|
||||||
"lmw" & 0xfc000000 == 0xb8000000;
|
|
||||||
"lswi" & 0xfc0007ff == 0x7c0004aa;
|
|
||||||
"lswx" & 0xfc0007ff == 0x7c00042a;
|
|
||||||
"lwarx" & 0xfc0007ff == 0x7c000028;
|
|
||||||
"lwbrx" & 0xfc0007ff == 0x7c00042c;
|
|
||||||
"lwz" & 0xfc000000 == 0x80000000;
|
|
||||||
"lwzu" & 0xfc000000 == 0x84000000;
|
|
||||||
"lwzux" & 0xfc0007ff == 0x7c00006e;
|
|
||||||
"lwzx" & 0xfc0007ff == 0x7c00002e;
|
|
||||||
"mcrf" & 0xfc300fff == 0x4c000000;
|
|
||||||
"mcrfs" & 0xfc30ffff == 0xfc000080;
|
|
||||||
"mcrxr" & 0xfc30ffff == 0x7c000400;
|
|
||||||
"mfcr" & 0xfc1fffff == 0x7c000026;
|
|
||||||
//"mffs" & 0xfc1ffffe == 0x7c00048e;
|
|
||||||
"mffs" & 0x0 == 0x0; // TODO
|
|
||||||
"mfmsr" & 0xfc1fffff == 0x7c0000a6;
|
|
||||||
"mfspr" & 0xfc0007ff == 0x7c0002a6;
|
|
||||||
"mfsr" & 0xfc10ffff == 0x7c0004a6;
|
|
||||||
"mfsrin" & 0xfc1f07ff == 0x7c000526;
|
|
||||||
"mftb" & 0xfc0007ff == 0x7c0002e6;
|
|
||||||
"mtcrf" & 0xfc100fff == 0x7c000120;
|
|
||||||
"mtfsb0" & 0xfc1ffffe == 0xfc00008c;
|
|
||||||
"mtfsb1" & 0xfc1ffffe == 0xfc00004c;
|
|
||||||
"mtfsf" & 0xfe0107fe == 0xfc00058e;
|
|
||||||
"mtfsfi" & 0xfc7f0ffe == 0xfc00010c;
|
|
||||||
"mtmsr" & 0xfc1fffff == 0x7c000124;
|
|
||||||
"mtspr" & 0xfc0007ff == 0x7c0003a6;
|
|
||||||
"mtsr" & 0xfc10ffff == 0x7c0001a4;
|
|
||||||
"mtsrin" & 0xfc1f07ff == 0x7c0001e4;
|
|
||||||
//"mulhw" & 0xfc0007fe == 0x7c000096;
|
|
||||||
"mulhw" & 0x0 == 0x0;
|
|
||||||
//"mulhwu" & 0xfc0007fe == 0x7c000016;
|
|
||||||
"mulhwu" & 0x0 == 0x0;
|
|
||||||
"mulli" & 0xfc000000 == 0x1c000000;
|
|
||||||
"mullw" & 0xfc0003fe == 0x7c0001d6;
|
|
||||||
"nand" & 0xfc0007fe == 0x7c0003b8;
|
|
||||||
"neg" & 0xfc00fffe == 0x7c0000d0;
|
|
||||||
"nor" & 0xfc0007fe == 0x7c0000f8;
|
|
||||||
"or" & 0xfc0007fe == 0x7c000378;
|
|
||||||
"orc" & 0xfc0007fe == 0x7c000338;
|
|
||||||
"ori" & 0xfc000000 == 0x60000000;
|
|
||||||
"oris" & 0xfc000000 == 0x64000000;
|
|
||||||
"psq_l" & 0xfc000000 == 0xe0000000;
|
|
||||||
"psq_lu" & 0xfc000000 == 0xe4000000;
|
|
||||||
"psq_lux" & 0xfc00007f == 0x1000004c;
|
|
||||||
"psq_lx" & 0xfc00007f == 0x1000000c;
|
|
||||||
"psq_st" & 0xfc000000 == 0xf0000000;
|
|
||||||
"psq_stu" & 0xfc000000 == 0xf4000000;
|
|
||||||
"psq_stux" & 0xfc00007f == 0x1000004e;
|
|
||||||
"psq_stx" & 0xfc00007f == 0x1000000e;
|
|
||||||
"ps_abs" & 0xfc1f07fe == 0x10000210;
|
|
||||||
"ps_add" & 0xfc0007fe == 0x1000002a;
|
|
||||||
"ps_cmpo0" & 0xfc6007ff == 0x10000040;
|
|
||||||
"ps_cmpo1" & 0xfc6007ff == 0x100000c0;
|
|
||||||
"ps_cmpu0" & 0xfc6007ff == 0x10000000;
|
|
||||||
"ps_cmpu1" & 0xfc6007ff == 0x10000080;
|
|
||||||
"ps_div" & 0xfc0007fe == 0x10000024;
|
|
||||||
"ps_madd" & 0xfc00003e == 0x1000003a;
|
|
||||||
"ps_madds0" & 0xfc00003e == 0x1000001c;
|
|
||||||
"ps_madds1" & 0xfc00003e == 0x1000001e;
|
|
||||||
"ps_merge00" & 0xfc0007fe == 0x10000420;
|
|
||||||
"ps_merge01" & 0xfc0007fe == 0x10000460;
|
|
||||||
"ps_merge10" & 0xfc0007fe == 0x100004a0;
|
|
||||||
"ps_merge11" & 0xfc0007fe == 0x100004e0;
|
|
||||||
"ps_mr" & 0xfc1f07fe == 0x10000090;
|
|
||||||
"ps_msub" & 0xfc00003e == 0x10000038;
|
|
||||||
"ps_mul" & 0xfc00f83e == 0x10000032;
|
|
||||||
"ps_muls0" & 0xfc00f83e == 0x10000018;
|
|
||||||
"ps_muls1" & 0xfc00f83e == 0x1000001a;
|
|
||||||
"ps_nabs" & 0xfc1f07fe == 0x10000110;
|
|
||||||
"ps_neg" & 0xfc1f07fe == 0x10000050;
|
|
||||||
"ps_nmadd" & 0xfc00003e == 0x1000003e;
|
|
||||||
"ps_nmsub" & 0xfc00003e == 0x1000003c;
|
|
||||||
"ps_res" & 0xfc1f07fe == 0x10000030;
|
|
||||||
"ps_rsqrte" & 0xfc1f07fe == 0x10000034;
|
|
||||||
"ps_sel" & 0xfc00003e == 0x1000002e;
|
|
||||||
"ps_sub" & 0xfc0007fe == 0x10000028;
|
|
||||||
"ps_sum0" & 0xfc00003e == 0x10000014;
|
|
||||||
"ps_sum1" & 0xfc00003e == 0x10000016;
|
|
||||||
"rfi" & 0xfffff801 == 0x4c000000;
|
|
||||||
"rlwimi" & 0xfc000000 == 0x50000000;
|
|
||||||
"rlwinm" & 0xfc000000 == 0x54000000;
|
|
||||||
"rlwnm" & 0xfc000000 == 0x5c000000;
|
|
||||||
"sc" & 0xffffffff == 0x44000002;
|
|
||||||
"slw" & 0xfc0007fe == 0x7c000030;
|
|
||||||
"sraw" & 0xfc0007fe == 0x7c000630;
|
|
||||||
"srawi" & 0xfc0007fe == 0x7c000670;
|
|
||||||
"srw" & 0xfc0007fe == 0x7c000430;
|
|
||||||
"stb" & 0xfc000000 == 0x98000000;
|
|
||||||
"stbu" & 0xfc000000 == 0x9c000000;
|
|
||||||
"stbux" & 0xfc0003ff == 0x7c0001ee;
|
|
||||||
"stbx" & 0xfc0003ff == 0x7c0001ae;
|
|
||||||
"stfd" & 0xfc000000 == 0xd8000000;
|
|
||||||
"stfdu" & 0xfc000000 == 0xdc000000;
|
|
||||||
"stfdux" & 0xfc0007ff == 0x7c0005ee;
|
|
||||||
"stfdx" & 0xfc0007ff == 0x7c0005ae;
|
|
||||||
"stfiwx" & 0xfc0007ff == 0x7c0007ae;
|
|
||||||
"stfs" & 0xfc000000 == 0xd0000000;
|
|
||||||
"stfsu" & 0xfc000000 == 0xd4000000;
|
|
||||||
"stfsux" & 0xfc0007ff == 0x7c00056e;
|
|
||||||
"stfsx" & 0xfc0007ff == 0x7c00052e;
|
|
||||||
"sth" & 0xfc000000 == 0xb0000000;
|
|
||||||
"sthbrx" & 0xfc0007ff == 0x7c00072c;
|
|
||||||
"sthu" & 0xfc000000 == 0xb4000000;
|
|
||||||
"sthux" & 0xfc0007ff == 0x7c00036e;
|
|
||||||
"sthx" & 0xfc0007ff == 0x7c00032e;
|
|
||||||
"stmw" & 0xfc000000 == 0xbc000000;
|
|
||||||
"stswi" & 0xfc0007ff == 0x7c0005aa;
|
|
||||||
"stswx" & 0xfc0007ff == 0x7c00052a;
|
|
||||||
"stw" & 0xfc000000 == 0x90000000;
|
|
||||||
"stwbrx" & 0xfc0007ff == 0x7c00052c;
|
|
||||||
"stwcx." & 0xfc0007ff == 0x7c00012d;
|
|
||||||
"stwu" & 0xfc000000 == 0x94000000;
|
|
||||||
"stwux" & 0xfc0007ff == 0x7c00016e;
|
|
||||||
"stwx" & 0xfc0007ff == 0x7c00012e;
|
|
||||||
"subf" & 0xfc0003fe == 0x7c000050;
|
|
||||||
"subfc" & 0xfc0003fe == 0x7c000010;
|
|
||||||
"subfe" & 0xfc0003fe == 0x7c000110;
|
|
||||||
"subfic" & 0xfc000000 == 0x20000000;
|
|
||||||
"subfme" & 0xfc00fbfe == 0x7c0001d0;
|
|
||||||
"subfze" & 0xfc00fbfe == 0x7c000190;
|
|
||||||
"sync" & 0xffffffff == 0x7c0004ac;
|
|
||||||
"tlbie" & 0xffff07ff == 0x7c000264;
|
|
||||||
"tlbsync" & 0xffffffff == 0x7c00046c;
|
|
||||||
"tw" & 0xfc0007ff == 0x7c000008;
|
|
||||||
"twi" & 0xfc000000 == 0xc000000;
|
|
||||||
"xor" & 0xfc0007fe == 0x7c000278;
|
|
||||||
"xori" & 0xfc000000 == 0x68000000;
|
|
||||||
"xoris" & 0xfc000000 == 0x6c000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Opcode {
|
|
||||||
pub const BLR: u32 = 0x4c000020;
|
|
||||||
|
|
||||||
pub fn from_code(x: u32) -> Self {
|
|
||||||
let op = match bits(x, 0..6) {
|
|
||||||
0b000011 => Opcode::Twi,
|
|
||||||
0b000100 => Self::from_code_cl_ext(x),
|
|
||||||
0b000111..=0b001111 => Self::from_code_basic1(x),
|
|
||||||
0b010000 => Opcode::Bc,
|
|
||||||
0b010001 => Opcode::Sc,
|
|
||||||
0b010010 => Opcode::B,
|
|
||||||
0b010011 => Self::from_code_010011(x),
|
|
||||||
0b010100..=0b011101 => Self::from_code_basic2(x),
|
|
||||||
0b011111 => Self::from_code_011111(x),
|
|
||||||
0b100000..=0b110111 => Self::from_code_basic3(x),
|
|
||||||
0b111000..=0b111001 => Self::from_code_psq(x),
|
|
||||||
0b111011 => Self::from_code_111011(x),
|
|
||||||
0b111100..=0b111101 => Self::from_code_psq(x),
|
|
||||||
0b111111 => Self::from_code_111111(x),
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
};
|
|
||||||
if !op.is_valid(x) {
|
|
||||||
return Opcode::Illegal;
|
|
||||||
}
|
|
||||||
op
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_code_cl_ext(x: u32) -> Self {
|
|
||||||
match bits(x, 26..31) {
|
|
||||||
0b00000 => match bits(x, 21..26) {
|
|
||||||
0b00000 => Opcode::PsCmpu0,
|
|
||||||
0b00001 => Opcode::PsCmpo0,
|
|
||||||
0b00010 => Opcode::PsCmpu1,
|
|
||||||
0b00011 => Opcode::PsCmpo1,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
},
|
|
||||||
0b00110 => {
|
|
||||||
if bit(x, 25) == 0 {
|
|
||||||
Opcode::PsqLx
|
|
||||||
} else {
|
|
||||||
Opcode::PsqLux
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0b00111 => {
|
|
||||||
if bit(x, 25) == 0 {
|
|
||||||
Opcode::PsqStx
|
|
||||||
} else {
|
|
||||||
Opcode::PsqStux
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0b01010 => Opcode::PsSum0,
|
|
||||||
0b01011 => Opcode::PsSum1,
|
|
||||||
0b01110 => Opcode::PsMadds0,
|
|
||||||
0b01111 => Opcode::PsMadds1,
|
|
||||||
0b10111 => Opcode::PsSel,
|
|
||||||
0b11100 => Opcode::PsMsub,
|
|
||||||
0b11101 => Opcode::PsMadd,
|
|
||||||
0b11110 => Opcode::PsNmsub,
|
|
||||||
0b11111 => Opcode::PsNmadd,
|
|
||||||
0b01100 => Opcode::PsMuls0,
|
|
||||||
0b01101 => Opcode::PsMuls1,
|
|
||||||
0b11001 => Opcode::PsMul,
|
|
||||||
0b10010 => Opcode::PsDiv,
|
|
||||||
0b10100 => Opcode::PsSub,
|
|
||||||
0b10101 => Opcode::PsAdd,
|
|
||||||
0b11000 => Opcode::PsRes,
|
|
||||||
0b11010 => Opcode::PsRsqrte,
|
|
||||||
0b01000 => match bits(x, 21..26) {
|
|
||||||
0b00001 => Opcode::PsNeg,
|
|
||||||
0b00010 => Opcode::PsMr,
|
|
||||||
0b00100 => Opcode::PsNabs,
|
|
||||||
0b01000 => Opcode::PsAbs,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
},
|
|
||||||
0b10000 => match bits(x, 21..26) {
|
|
||||||
0b10000 => Opcode::PsMerge00,
|
|
||||||
0b10001 => Opcode::PsMerge01,
|
|
||||||
0b10010 => Opcode::PsMerge10,
|
|
||||||
0b10011 => Opcode::PsMerge11,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
},
|
|
||||||
0b10110 => Opcode::DcbzL,
|
|
||||||
// Unknown paired-singles key.
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_code_basic1(x: u32) -> Self {
|
|
||||||
match bits(x, 0..6) {
|
|
||||||
0b000111 => Opcode::Mulli,
|
|
||||||
0b001000 => Opcode::Subfic,
|
|
||||||
0b001010 => Opcode::Cmpli,
|
|
||||||
0b001011 => Opcode::Cmpi,
|
|
||||||
0b001100 => Opcode::Addic,
|
|
||||||
0b001101 => Opcode::Addic_,
|
|
||||||
0b001110 => Opcode::Addi,
|
|
||||||
0b001111 => Opcode::Addis,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_code_010011(x: u32) -> Self {
|
|
||||||
match bits(x, 21..27) {
|
|
||||||
0b000000 => Opcode::Mcrf,
|
|
||||||
0b000001 => Opcode::Bclr,
|
|
||||||
0b100001 => Opcode::Bcctr,
|
|
||||||
0b000011 => Opcode::Rfi,
|
|
||||||
0b001001 => Opcode::Isync,
|
|
||||||
0b000010 => Opcode::Crnor,
|
|
||||||
0b001000 => Opcode::Crandc,
|
|
||||||
0b001100 => Opcode::Crxor,
|
|
||||||
0b001110 => Opcode::Crnand,
|
|
||||||
0b010000 => Opcode::Crand,
|
|
||||||
0b010010 => Opcode::Creqv,
|
|
||||||
0b011010 => Opcode::Crorc,
|
|
||||||
0b011100 => Opcode::Cror,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_code_basic2(x: u32) -> Self {
|
|
||||||
match bits(x, 0..6) {
|
|
||||||
0b10100 => Opcode::Rlwimi,
|
|
||||||
0b10101 => Opcode::Rlwinm,
|
|
||||||
0b10111 => Opcode::Rlwnm,
|
|
||||||
0b11000 => Opcode::Ori,
|
|
||||||
0b11001 => Opcode::Oris,
|
|
||||||
0b11010 => Opcode::Xori,
|
|
||||||
0b11011 => Opcode::Xoris,
|
|
||||||
0b11100 => Opcode::Andi_,
|
|
||||||
0b11101 => Opcode::Andis_,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_code_011111(x: u32) -> Self {
|
|
||||||
match bits::<u32>(x, 21..31) {
|
|
||||||
0b00_0000_0000 => Opcode::Cmp,
|
|
||||||
0b00_0010_0000 => Opcode::Cmpl,
|
|
||||||
0b00_0000_0100 => Opcode::Tw,
|
|
||||||
0b00_0000_1000 => Opcode::Subfc,
|
|
||||||
0b00_0000_1010 => Opcode::Addc,
|
|
||||||
0b00_0000_1011 => Opcode::Mulhwu,
|
|
||||||
0b00_0001_0011 => Opcode::Mfcr,
|
|
||||||
0b00_0001_0100 => Opcode::Lwarx,
|
|
||||||
0b00_0001_0111 => Opcode::Lwzx,
|
|
||||||
0b00_0001_1000 => Opcode::Slw,
|
|
||||||
0b00_0001_1010 => Opcode::Cntlzw,
|
|
||||||
0b00_0001_1100 => Opcode::And,
|
|
||||||
0b00_0010_1000 => Opcode::Subf,
|
|
||||||
0b00_0011_0110 => Opcode::Dcbst,
|
|
||||||
0b00_0011_0111 => Opcode::Lwzux,
|
|
||||||
0b00_0011_1100 => Opcode::Andc,
|
|
||||||
0b00_0100_1011 => Opcode::Mulhw,
|
|
||||||
0b00_0101_0011 => Opcode::Mfmsr,
|
|
||||||
0b00_0101_0110 => Opcode::Dcbf,
|
|
||||||
0b00_0101_0111 => Opcode::Lbzx,
|
|
||||||
0b00_0110_1000 => Opcode::Neg,
|
|
||||||
0b00_0111_0111 => Opcode::Lbzux,
|
|
||||||
0b00_0111_1100 => Opcode::Nor,
|
|
||||||
0b00_1000_1000 => Opcode::Subfe,
|
|
||||||
0b00_1000_1010 => Opcode::Adde,
|
|
||||||
0b00_1001_0000 => Opcode::Mtcrf,
|
|
||||||
0b00_1001_0010 => Opcode::Mtmsr,
|
|
||||||
0b00_1001_0110 => Opcode::Stwcx_,
|
|
||||||
0b00_1001_0111 => Opcode::Stwx,
|
|
||||||
0b00_1011_0111 => Opcode::Stwux,
|
|
||||||
0b00_1100_1000 => Opcode::Subfze,
|
|
||||||
0b00_1100_1010 => Opcode::Addze,
|
|
||||||
0b00_1101_0010 => Opcode::Mtsr,
|
|
||||||
0b00_1101_0111 => Opcode::Stbx,
|
|
||||||
0b00_1110_1000 => Opcode::Subfme,
|
|
||||||
0b00_1110_1010 => Opcode::Addme,
|
|
||||||
0b00_1110_1011 => Opcode::Mullw,
|
|
||||||
0b00_1111_0010 => Opcode::Mtsrin,
|
|
||||||
0b00_1111_0110 => Opcode::Dcbtst,
|
|
||||||
0b00_1111_0111 => Opcode::Stbux,
|
|
||||||
0b01_0000_1010 => Opcode::Add,
|
|
||||||
0b01_0001_0110 => Opcode::Dcbt,
|
|
||||||
0b01_0001_0111 => Opcode::Lhzx,
|
|
||||||
0b01_0001_1100 => Opcode::Eqv,
|
|
||||||
0b01_0011_0010 => Opcode::Tlbie,
|
|
||||||
0b01_0011_0110 => Opcode::Eciwx,
|
|
||||||
0b01_0011_0111 => Opcode::Lhzux,
|
|
||||||
0b01_0011_1100 => Opcode::Xor,
|
|
||||||
0b01_0101_0011 => Opcode::Mfspr,
|
|
||||||
0b01_0101_0111 => Opcode::Lhax,
|
|
||||||
0b01_0111_0011 => Opcode::Mftb,
|
|
||||||
0b01_0111_0111 => Opcode::Lhaux,
|
|
||||||
0b01_1001_0111 => Opcode::Sthx,
|
|
||||||
0b01_1001_1100 => Opcode::Orc,
|
|
||||||
0b01_1011_0110 => Opcode::Ecowx,
|
|
||||||
0b01_1011_0111 => Opcode::Sthux,
|
|
||||||
0b01_1011_1100 => Opcode::Or,
|
|
||||||
0b01_1100_1011 => Opcode::Divwu,
|
|
||||||
0b01_1101_0011 => Opcode::Mtspr,
|
|
||||||
0b01_1101_0110 => Opcode::Dcbi,
|
|
||||||
0b01_1101_1100 => Opcode::Nand,
|
|
||||||
0b01_1110_1011 => Opcode::Divw,
|
|
||||||
0b10_0000_0000 => Opcode::Mcrxr,
|
|
||||||
0b10_0001_0101 => Opcode::Lswx,
|
|
||||||
0b10_0001_0110 => Opcode::Lwbrx,
|
|
||||||
0b10_0001_0111 => Opcode::Lfsx,
|
|
||||||
0b10_0001_1000 => Opcode::Srw,
|
|
||||||
0b10_0011_0110 => Opcode::Tlbsync,
|
|
||||||
0b10_0011_0111 => Opcode::Lfsux,
|
|
||||||
0b10_0101_0011 => Opcode::Mfsr,
|
|
||||||
0b10_0101_0101 => Opcode::Lswi,
|
|
||||||
0b10_0101_0110 => Opcode::Sync,
|
|
||||||
0b10_0101_0111 => Opcode::Lfdx,
|
|
||||||
0b10_0111_0111 => Opcode::Lfdux,
|
|
||||||
0b10_1001_0011 => Opcode::Mfsrin,
|
|
||||||
0b10_1001_0101 => Opcode::Stswx,
|
|
||||||
0b10_1001_0110 => Opcode::Stwbrx,
|
|
||||||
0b10_1001_0111 => Opcode::Stfsx,
|
|
||||||
0b10_1011_0111 => Opcode::Stfsux,
|
|
||||||
0b10_1101_0101 => Opcode::Stswi,
|
|
||||||
0b10_1101_0111 => Opcode::Stfdx,
|
|
||||||
0b10_1111_0111 => Opcode::Stfdux,
|
|
||||||
0b11_0001_0110 => Opcode::Lhbrx,
|
|
||||||
0b11_0001_1000 => Opcode::Sraw,
|
|
||||||
0b11_0011_1000 => Opcode::Srawi,
|
|
||||||
0b11_0101_0110 => Opcode::Eieio,
|
|
||||||
0b11_1001_0110 => Opcode::Sthbrx,
|
|
||||||
0b11_1001_1010 => Opcode::Extsh,
|
|
||||||
0b11_1011_1010 => Opcode::Extsb,
|
|
||||||
0b11_1101_0110 => Opcode::Icbi,
|
|
||||||
0b11_1101_0111 => Opcode::Stfiwx,
|
|
||||||
0b11_1111_0110 => Opcode::Dcbz,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_code_basic3(x: u32) -> Self {
|
|
||||||
match bits(x, 0..6) {
|
|
||||||
0b100000 => Opcode::Lwz,
|
|
||||||
0b100001 => Opcode::Lwzu,
|
|
||||||
0b100010 => Opcode::Lbz,
|
|
||||||
0b100011 => Opcode::Lbzu,
|
|
||||||
0b100100 => Opcode::Stw,
|
|
||||||
0b100101 => Opcode::Stwu,
|
|
||||||
0b100110 => Opcode::Stb,
|
|
||||||
0b100111 => Opcode::Stbu,
|
|
||||||
0b101000 => Opcode::Lhz,
|
|
||||||
0b101001 => Opcode::Lhzu,
|
|
||||||
0b101010 => Opcode::Lha,
|
|
||||||
0b101011 => Opcode::Lhau,
|
|
||||||
0b101100 => Opcode::Sth,
|
|
||||||
0b101101 => Opcode::Sthu,
|
|
||||||
0b101110 => Opcode::Lmw,
|
|
||||||
0b101111 => Opcode::Stmw,
|
|
||||||
0b110000 => Opcode::Lfs,
|
|
||||||
0b110001 => Opcode::Lfsu,
|
|
||||||
0b110010 => Opcode::Lfd,
|
|
||||||
0b110011 => Opcode::Lfdu,
|
|
||||||
0b110100 => Opcode::Stfs,
|
|
||||||
0b110101 => Opcode::Stfsu,
|
|
||||||
0b110110 => Opcode::Stfd,
|
|
||||||
0b110111 => Opcode::Stfdu,
|
|
||||||
_ => disasm_unreachable!(x),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_code_psq(x: u32) -> Self {
|
|
||||||
match bits(x, 0..6) {
|
|
||||||
0b111000 => Opcode::PsqL,
|
|
||||||
0b111001 => Opcode::PsqLu,
|
|
||||||
0b111100 => Opcode::PsqSt,
|
|
||||||
0b111101 => Opcode::PsqStu,
|
|
||||||
_ => disasm_unreachable!(x),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_code_111011(x: u32) -> Self {
|
|
||||||
match bits(x, 26..31) {
|
|
||||||
0b10010 => Opcode::Fdivs,
|
|
||||||
0b10100 => Opcode::Fsubs,
|
|
||||||
0b10101 => Opcode::Fadds,
|
|
||||||
0b11000 => Opcode::Fres,
|
|
||||||
0b11001 => Opcode::Fmuls,
|
|
||||||
0b11100 => Opcode::Fmsubs,
|
|
||||||
0b11101 => Opcode::Fmadds,
|
|
||||||
0b11110 => Opcode::Fnmsubs,
|
|
||||||
0b11111 => Opcode::Fnmadds,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_code_111111(x: u32) -> Self {
|
|
||||||
match bits::<u32>(x, 26..31) {
|
|
||||||
0b00000 => match bits(x, 24..26) {
|
|
||||||
0b00 => Opcode::Fcmpu,
|
|
||||||
0b01 => Opcode::Fcmpo,
|
|
||||||
0b10 => Opcode::Mcrfs,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
},
|
|
||||||
0b00110 => match bits(x, 23..26) {
|
|
||||||
0b001 => Opcode::Mtfsb1,
|
|
||||||
0b010 => Opcode::Mtfsb0,
|
|
||||||
0b100 => Opcode::Mtfsfi,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
},
|
|
||||||
0b00111 => match bits(x, 21..26) {
|
|
||||||
0b10010 => Opcode::Mffs,
|
|
||||||
0b10110 => Opcode::Mtfsf,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
},
|
|
||||||
0b01000 => match bits(x, 22..26) {
|
|
||||||
0b0001 => Opcode::Fneg,
|
|
||||||
0b0010 => Opcode::Fmr,
|
|
||||||
0b0100 => Opcode::Fnabs,
|
|
||||||
0b1000 => Opcode::Fabs,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
},
|
|
||||||
0b01100 => Opcode::Frsp,
|
|
||||||
0b01110 => Opcode::Fctiw,
|
|
||||||
0b01111 => Opcode::Fctiwz,
|
|
||||||
0b10010 => Opcode::Fdiv,
|
|
||||||
0b10100 => Opcode::Fsub,
|
|
||||||
0b10101 => Opcode::Fadd,
|
|
||||||
0b10111 => Opcode::Fsel,
|
|
||||||
0b11001 => Opcode::Fmul,
|
|
||||||
0b11010 => Opcode::Frsqrte,
|
|
||||||
0b11100 => Opcode::Fmsub,
|
|
||||||
0b11101 => Opcode::Fmadd,
|
|
||||||
0b11110 => Opcode::Fnmsub,
|
|
||||||
0b11111 => Opcode::Fnmadd,
|
|
||||||
_ => Opcode::Illegal,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
2132
disasm/src/lib.rs
2132
disasm/src/lib.rs
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +0,0 @@
|
||||||
macro_rules! disasm_unreachable {
|
|
||||||
($msg:expr $(,)?) => {{
|
|
||||||
panic!(
|
|
||||||
"internal error: entered unreachable code disassembling instruction 0x{:08x}",
|
|
||||||
$msg
|
|
||||||
)
|
|
||||||
}};
|
|
||||||
}
|
|
|
@ -0,0 +1,980 @@
|
||||||
|
use ppc750cl::prelude::*;
|
||||||
|
|
||||||
|
macro_rules! assert_asm {
|
||||||
|
($ins:ident, $disasm:literal) => {{
|
||||||
|
assert_eq!(format!("{}", FormattedIns($ins)), $disasm)
|
||||||
|
}};
|
||||||
|
($code:literal, $disasm:literal) => {{
|
||||||
|
let ins = Ins::new($code, 0x8000_0000);
|
||||||
|
assert_eq!(format!("{}", FormattedIns(ins)), $disasm)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_addc() {
|
||||||
|
let ins = Ins::new(0x7c002014, 0x8000_0000u32);
|
||||||
|
assert_eq!(ins.op, Addc);
|
||||||
|
assert_eq!(ins.fields(), vec![rD(GPR(0)), rA(GPR(0)), rB(GPR(4))]);
|
||||||
|
assert_asm!(ins, "addc r0, r0, r4");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_addi() {
|
||||||
|
let ins = Ins::new(0x38010140, 0x8000_0000u32);
|
||||||
|
assert_eq!(ins.op, Addi);
|
||||||
|
assert_eq!(
|
||||||
|
ins.fields(),
|
||||||
|
vec![rD(GPR(0)), rA(GPR(1)), simm(Simm(0x140))]
|
||||||
|
);
|
||||||
|
assert_eq!(ins.defs(), vec![rD(GPR(0))]);
|
||||||
|
assert_eq!(ins.uses(), vec![rA(GPR(1))]);
|
||||||
|
assert_asm!(ins, "addi r0, r1, 0x140");
|
||||||
|
|
||||||
|
assert_asm!(0x38010008, "addi r0, r1, 0x8");
|
||||||
|
assert_asm!(0x38010010, "addi r0, r1, 0x10");
|
||||||
|
assert_asm!(0x38010018, "addi r0, r1, 0x18");
|
||||||
|
assert_asm!(0x38010140, "addi r0, r1, 0x140");
|
||||||
|
assert_asm!(0x38049000, "addi r0, r4, -0x7000");
|
||||||
|
assert_asm!(0x38a00000, "li r5, 0x0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_adde() {
|
||||||
|
assert_asm!(0x7c006114, "adde r0, r0, r12");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_addic() {
|
||||||
|
assert_asm!(0x3060ffff, "addic r3, r0, -0x1");
|
||||||
|
assert_asm!(0x30840800, "addic r4, r4, 0x800");
|
||||||
|
assert_asm!(0x30a50008, "addic r5, r5, 0x8");
|
||||||
|
assert_asm!(0x37DF001C, "addic. r30, r31, 0x1c");
|
||||||
|
assert_asm!(0x37E06278, "addic. r31, r0, 0x6278");
|
||||||
|
assert_asm!(0x37E3FFFF, "addic. r31, r3, -0x1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_addis() {
|
||||||
|
assert_asm!(0x3C030000, "addis r0, r3, 0x0");
|
||||||
|
assert_asm!(0x3C038000, "addis r0, r3, 0x8000");
|
||||||
|
assert_asm!(0x3D00EFCE, "lis r8, 0xefce");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_addze() {
|
||||||
|
assert_asm!(0x7C000194, "addze r0, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_and() {
|
||||||
|
assert_asm!(0x7C001838, "and r0, r0, r3");
|
||||||
|
assert_asm!(0x7C001839, "and. r0, r0, r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_andc() {
|
||||||
|
assert_asm!(0x7C001878, "andc r0, r0, r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_andi_() {
|
||||||
|
assert_asm!(0x70000009, "andi. r0, r0, 0x9");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_andis_() {
|
||||||
|
assert_asm!(0x77c802ff, "andis. r8, r30, 0x2ff");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_b() {
|
||||||
|
assert_asm!(0x48000000, "b 0x0");
|
||||||
|
assert_asm!(0x48000004, "b 0x4");
|
||||||
|
assert_asm!(0x4800A5C9, "bl 0xa5c8");
|
||||||
|
assert_asm!(0x4823B4D9, "bl 0x23b4d8");
|
||||||
|
assert_asm!(0x4BE03C99, "bl -0x1fc368");
|
||||||
|
assert_asm!(0x4BDC1A59, "bl -0x23e5a8");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_bc() {
|
||||||
|
assert_asm!(0x40800008, "bge 0x8");
|
||||||
|
assert_asm!(0x40802350, "bge 0x2350");
|
||||||
|
assert_asm!(0x4080FC7C, "bge -0x384");
|
||||||
|
assert_asm!(0x408100AC, "ble 0xac");
|
||||||
|
assert_asm!(0x4081F788, "ble -0x878");
|
||||||
|
assert_asm!(0x40821BA0, "bne 0x1ba0");
|
||||||
|
assert_asm!(0x4082E3C4, "bne -0x1c3c");
|
||||||
|
assert_asm!(0x408600D8, "bne cr1, 0xd8");
|
||||||
|
assert_asm!(0x4086FECC, "bne cr1, -0x134");
|
||||||
|
assert_asm!(0x409C000C, "bge cr7, 0xc");
|
||||||
|
assert_asm!(0x4180000C, "blt 0xc");
|
||||||
|
assert_asm!(0x4180F9C0, "blt -0x640");
|
||||||
|
assert_asm!(0x4181021C, "bgt 0x21c");
|
||||||
|
assert_asm!(0x4181FD80, "bgt -0x280");
|
||||||
|
assert_asm!(0x41822304, "beq 0x2304");
|
||||||
|
assert_asm!(0x4182FE3C, "beq -0x1c4");
|
||||||
|
assert_asm!(0x418401AC, "blt cr1, 0x1ac");
|
||||||
|
assert_asm!(0x4184FCE4, "blt cr1, -0x31c");
|
||||||
|
assert_asm!(0x418500C0, "bgt cr1, 0xc0");
|
||||||
|
assert_asm!(0x418502E4, "bgt cr1, 0x2e4");
|
||||||
|
assert_asm!(0x419A0138, "beq cr6, 0x138");
|
||||||
|
assert_asm!(0x419C0008, "blt cr7, 0x8");
|
||||||
|
assert_asm!(0x4200F560, "bdnz -0xaa0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_bcctr() {
|
||||||
|
assert_asm!(0x4E800420, "bctr");
|
||||||
|
assert_asm!(0x4E800421, "bctrl");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_bclr() {
|
||||||
|
assert_asm!(0x4C800020, "bgelr");
|
||||||
|
assert_asm!(0x4C810020, "blelr");
|
||||||
|
assert_asm!(0x4C820020, "bnelr");
|
||||||
|
assert_asm!(0x4C9E0020, "bnelr cr7");
|
||||||
|
assert_asm!(0x4D800020, "bltlr");
|
||||||
|
assert_asm!(0x4D810020, "bgtlr");
|
||||||
|
assert_asm!(0x4D820020, "beqlr");
|
||||||
|
assert_asm!(0x4D860020, "beqlr cr1");
|
||||||
|
assert_asm!(0x4E800020, "blr");
|
||||||
|
assert_asm!(0x4E800021, "blrl");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_cmp() {
|
||||||
|
assert_asm!(0x7C030000, "cmpw r3, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[test]
|
||||||
|
fn test_ins_cmpi() {
|
||||||
|
assert_asm!(0x2C050D00, "cmpwi r5, 0xd00");
|
||||||
|
assert_asm!(0x2F1F0000, "cmpwi cr6, r31, 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_cmpl() {
|
||||||
|
assert_asm!(0x7C9A2040, "cmplw cr1, r26, r4");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_cmpli() {
|
||||||
|
assert_asm!(0x2803FFF3, "cmplwi r3, 0xfff3");
|
||||||
|
assert_asm!(0x2884F8F0, "cmplwi cr1, r4, 0xf8f0");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_cntlzw() {
|
||||||
|
assert_asm!(0x7C030034, "cntlzw r3, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[test]
|
||||||
|
fn test_ins_cror() {
|
||||||
|
assert_asm!(0x4C411382, "cror cr2, cr1, cr2");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_dcbf() {
|
||||||
|
assert_asm!(0x7C0028AC, "dcbf r0, r5");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_dcbi() {
|
||||||
|
assert_asm!(0x7C001BAC, "dcbi r0, r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_dcbst() {
|
||||||
|
assert_asm!(0x7C00286C, "dcbst r0, r5");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_dcbt() {
|
||||||
|
assert_asm!(0x7C001A2C, "dcbt r0, r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_dcbz() {
|
||||||
|
assert_asm!(0x7C001FEC, "dcbz r0, r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_dcbz_l() {
|
||||||
|
assert_asm!(0x10061FEC, "dcbz_l r6, r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_divw() {
|
||||||
|
assert_asm!(0x7C8073D6, "divw r4, r0, r14");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_divwu() {
|
||||||
|
assert_asm!(0x7C69E396, "divwu r3, r9, r28");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_extsb() {
|
||||||
|
assert_asm!(0x7C650774, "extsb r5, r3");
|
||||||
|
assert_asm!(0x7C650775, "extsb. r5, r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_extsh() {
|
||||||
|
assert_asm!(0x7C000734, "extsh r0, r0");
|
||||||
|
assert_asm!(0x7C000735, "extsh. r0, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fabs() {
|
||||||
|
assert_asm!(0xFC000A10, "fabs f0, f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fadd() {
|
||||||
|
assert_asm!(0xFC00282A, "fadd f0, f0, f5");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fadds() {
|
||||||
|
assert_asm!(0xEC41602A, "fadds f2, f1, f12");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fcmpo() {
|
||||||
|
assert_asm!(0xFC00C840, "fcmpo cr0, f0, f25");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fcmpu() {
|
||||||
|
assert_asm!(0xFC00D000, "fcmpu cr0, f0, f26");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fctiwz() {
|
||||||
|
assert_asm!(0xFC20001E, "fctiwz f1, f0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fdiv() {
|
||||||
|
assert_asm!(0xFC200024, "fdiv f1, f0, f0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fdivs() {
|
||||||
|
assert_asm!(0xEC01F824, "fdivs f0, f1, f31");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fmadds() {
|
||||||
|
assert_asm!(0xEC0200FA, "fmadds f0, f2, f3, f0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fmsub() {
|
||||||
|
assert_asm!(0xFC000028, "fsub f0, f0, f0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fmsubs() {
|
||||||
|
assert_asm!(0xEC00B828, "fsubs f0, f0, f23");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fmul() {
|
||||||
|
assert_asm!(0xFC0000B2, "fmul f0, f0, f2");
|
||||||
|
assert_asm!(0xFC0000F2, "fmul f0, f0, f3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fmuls() {
|
||||||
|
assert_asm!(0xEC0007B2, "fmuls f0, f0, f30");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fneg() {
|
||||||
|
assert_asm!(0xFCE00050, "fneg f7, f0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fnmsub() {
|
||||||
|
assert_asm!(0xFCC640BC, "fnmsub f6, f6, f2, f8");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fnmsubs() {
|
||||||
|
assert_asm!(0xEC022B3C, "fnmsubs f0, f2, f12, f5");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fres() {
|
||||||
|
assert_asm!(0xEC000830, "fres f0, f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_frsp() {
|
||||||
|
assert_asm!(0xFC000018, "frsp f0, f0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_frsqrte() {
|
||||||
|
assert_asm!(0xFC000834, "frsqrte f0, f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fsel() {
|
||||||
|
assert_asm!(0xFC01F82E, "fsel f0, f1, f0, f31");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fsub() {
|
||||||
|
assert_asm!(0xFC000828, "fsub f0, f0, f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_fsubs() {
|
||||||
|
assert_asm!(0xEC000828, "fsubs f0, f0, f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_icbi() {
|
||||||
|
assert_asm!(0x7C001FAC, "icbi r0, r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_isync() {
|
||||||
|
assert_asm!(0x4C00012C, "isync");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lbz() {
|
||||||
|
assert_asm!(0x880104CC, "lbz r0, 0x4cc(r1)");
|
||||||
|
assert_asm!(0x8802801B, "lbz r0, -0x7fe5(r2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lbzu() {
|
||||||
|
assert_asm!(0x8D9DCA10, "lbzu r12, -0x35f0(r29)");
|
||||||
|
assert_asm!(0x8E3053EC, "lbzu r17, 0x53ec(r16)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lbzux() {
|
||||||
|
assert_asm!(0x7C0400EE, "lbzux r0, r4, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lbzx() {
|
||||||
|
assert_asm!(0x7C0300AE, "lbzx r0, r3, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lfd() {
|
||||||
|
assert_asm!(0xC80140C8, "lfd f0, 0x40c8(r1)");
|
||||||
|
assert_asm!(0xC8028090, "lfd f0, -0x7f70(r2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lfdu() {
|
||||||
|
assert_asm!(0xCC03FFC0, "lfdu f0, -0x40(r3)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lfdx() {
|
||||||
|
assert_asm!(0x7C0404AE, "lfdx f0, r4, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lfs() {
|
||||||
|
assert_asm!(0xC001027C, "lfs f0, 0x27c(r1)");
|
||||||
|
assert_asm!(0xC0028000, "lfs f0, -0x8000(r2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lfsu() {
|
||||||
|
assert_asm!(0xC404FFF4, "lfsu f0, -0xc(r4)");
|
||||||
|
assert_asm!(0xC4170084, "lfsu f0, 0x84(r23)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lfsux() {
|
||||||
|
assert_asm!(0x7C03846E, "lfsux f0, r3, r16");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lfsx() {
|
||||||
|
assert_asm!(0x7C03042E, "lfsx f0, r3, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lha() {
|
||||||
|
assert_asm!(0xA861000E, "lha r3, 0xe(r1)");
|
||||||
|
assert_asm!(0xA80D9F64, "lha r0, -0x609c(r13)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lhau() {
|
||||||
|
assert_asm!(0xAC060006, "lhau r0, 0x6(r6)");
|
||||||
|
assert_asm!(0xAC06FFFA, "lhau r0, -0x6(r6)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lhax() {
|
||||||
|
assert_asm!(0x7C0402AE, "lhax r0, r4, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lhz() {
|
||||||
|
assert_asm!(0xA00104D6, "lhz r0, 0x4d6(r1)");
|
||||||
|
assert_asm!(0xA00296DA, "lhz r0, -0x6926(r2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lhzu() {
|
||||||
|
assert_asm!(0xA40A0004, "lhzu r0, 0x4(r10)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lhzux() {
|
||||||
|
assert_asm!(0x7C04026E, "lhzux r0, r4, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lhzx() {
|
||||||
|
assert_asm!(0x7C03022E, "lhzx r0, r3, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lmw() {
|
||||||
|
assert_asm!(0xBB210444, "lmw r25, 0x444(r1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lwbrx() {
|
||||||
|
assert_asm!(0x7D80242C, "lwbrx r12, r0, r4");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lwz() {
|
||||||
|
assert_asm!(0x800294F4, "lwz r0, -0x6b0c(r2)");
|
||||||
|
assert_asm!(0x80011254, "lwz r0, 0x1254(r1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lwzu() {
|
||||||
|
assert_asm!(0x84038608, "lwzu r0, -0x79f8(r3)");
|
||||||
|
assert_asm!(0x873E5058, "lwzu r25, 0x5058(r30)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lwzux() {
|
||||||
|
assert_asm!(0x7C03006E, "lwzux r0, r3, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_lwzx() {
|
||||||
|
assert_asm!(0x7C03002E, "lwzx r0, r3, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mfcr() {
|
||||||
|
assert_asm!(0x7C000026, "mfcr cr0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mffs() {
|
||||||
|
assert_asm!(0xFC00048E, "mffs f0");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mfmsr() {
|
||||||
|
assert_asm!(0x7C0000A6, "mfmsr r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mfspr() {
|
||||||
|
assert_asm!(0x7E1A02A6, "mfspr r16, 832");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mfsr() {
|
||||||
|
assert_asm!(0x7E0004A6, "mfsr r16, 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mftb() {
|
||||||
|
assert_asm!(0x7C8C42E6, "mftb r4, 392");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mtcrf() {
|
||||||
|
assert_asm!(0x7C6FF120, "mtcrf 255, r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mtfsb0() {}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mtfsb1() {
|
||||||
|
assert_asm!(0xFFA0004C, "mtfsb1 0x1d");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mtfsf() {
|
||||||
|
assert_asm!(0xFDFE058E, "mtfsf 255, f0");
|
||||||
|
assert_asm!(0xFDFEFD8E, "mtfsf 255, f31");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mtmsr() {
|
||||||
|
assert_asm!(0x7C000124, "mtmsr r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mtspr() {
|
||||||
|
assert_asm!(0x7E75FBA6, "mtspr 703, r19");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mtsr() {
|
||||||
|
assert_asm!(0x7E0001A4, "mtsr 0, r16");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mulhw() {
|
||||||
|
assert_asm!(0x7C7F2096, "mulhw r3, r31, r4");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mulhwu() {
|
||||||
|
assert_asm!(0x7C7D0016, "mulhwu r3, r29, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mulli() {
|
||||||
|
assert_asm!(0x1C001880, "mulli r0, r0, 0x1880");
|
||||||
|
assert_asm!(0x1FBD0030, "mulli r29, r29, 0x30");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_mullw() {
|
||||||
|
assert_asm!(0x7C7D01D6, "mullw r3, r29, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_nand() {
|
||||||
|
assert_asm!(0x7C7D03B8, "nand r29, r3, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_neg() {
|
||||||
|
assert_asm!(0x7C0600D0, "neg r0, r6");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_nor() {
|
||||||
|
assert_asm!(0x7C0500F8, "nor r5, r0, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_or() {
|
||||||
|
assert_asm!(0x7C04DB78, "or r4, r0, r27");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_orc() {
|
||||||
|
assert_asm!(0x7C042338, "orc r4, r0, r4");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ori() {
|
||||||
|
assert_asm!(0x60002204, "ori r0, r0, 0x2204");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_oris() {
|
||||||
|
assert_asm!(0x67A06800, "oris r0, r29, 0x6800");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_psq_l() {
|
||||||
|
assert_asm!(0xE02500AC, "psq_l f1, 0xac(r5), 0, qr0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[test]
|
||||||
|
fn test_ins_psq_lu() {
|
||||||
|
assert_asm!(0xE5435010, "psq_lu f10, 0x10(r3), 0, qr5");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_psq_lx() {
|
||||||
|
let ins = Ins::new(0x1000000C, 0x8000_0000u32);
|
||||||
|
assert_eq!(ins.op, PsqLx);
|
||||||
|
assert_eq!(
|
||||||
|
ins.fields(),
|
||||||
|
vec![
|
||||||
|
frD(FPR(0)),
|
||||||
|
rA(GPR(0)),
|
||||||
|
rB(GPR(0)),
|
||||||
|
ps_W(OpaqueU(0)),
|
||||||
|
ps_l(GQR(0))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(ins.defs(), vec![frD(FPR(0))]);
|
||||||
|
assert_eq!(ins.uses(), vec![rB(GPR(0))]);
|
||||||
|
|
||||||
|
assert_asm!(0x1000000C, "psq_lx f0, r0, r0, 0, qr0");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[test]
|
||||||
|
fn test_ins_psq_st() {
|
||||||
|
assert_asm!(0xF1230210, "psq_st f9, 0x210(r3), 0, qr0");
|
||||||
|
assert_asm!(0xF1238008, "psq_st f9, 8(r3), 1, qr0");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_psq_stu() {
|
||||||
|
assert_asm!(0xF40A0020, "psq_stu f0, 0x20(r10), 0, qr0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_psq_stx() {
|
||||||
|
assert_asm!(0x13E1000E, "psq_stx f31, r1, r0, 0, qr0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_abs() {
|
||||||
|
assert_asm!(0x10A03210, "ps_abs f5, f6");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_add() {
|
||||||
|
assert_asm!(0x1006382A, "ps_add f0, f6, f7");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_cmpo0() {
|
||||||
|
assert_asm!(0x10070840, "ps_cmpo0 cr0, f7, f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_cmpu0() {
|
||||||
|
assert_asm!(0x10003000, "ps_cmpu0 cr0, f0, f6");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_cmpu1() {
|
||||||
|
assert_asm!(0x10003080, "ps_cmpu1 cr0, f0, f6");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_madd() {
|
||||||
|
assert_asm!(0x112141FA, "ps_madd f9, f1, f7, f8");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_madds0() {
|
||||||
|
assert_asm!(0x10AC299C, "ps_madds0 f5, f12, f6, f5");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_madds1() {
|
||||||
|
assert_asm!(0x110640DE, "ps_madds1 f8, f6, f3, f8");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_merge00() {
|
||||||
|
assert_asm!(0x10400420, "ps_merge00 f2, f0, f0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_merge01() {
|
||||||
|
assert_asm!(0x10400C60, "ps_merge01 f2, f0, f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_merge10() {
|
||||||
|
assert_asm!(0x104004A0, "ps_merge10 f2, f0, f0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_merge11() {
|
||||||
|
assert_asm!(0x10AA14E0, "ps_merge11 f5, f10, f2");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_msub() {
|
||||||
|
assert_asm!(0x10A53778, "ps_msub f5, f5, f29, f6");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_mul() {
|
||||||
|
assert_asm!(0x10000032, "ps_mul f0, f0, f0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_muls0() {
|
||||||
|
assert_asm!(0x100002D8, "ps_muls0 f0, f0, f11");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_muls1() {
|
||||||
|
assert_asm!(0x10A2005A, "ps_muls1 f5, f2, f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_nabs() {
|
||||||
|
assert_asm!(0x10803210, "ps_abs f4, f6");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_neg() {
|
||||||
|
assert_asm!(0x10E03850, "ps_neg f7, f7");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_nmadd() {
|
||||||
|
assert_asm!(0x10CB30FE, "ps_nmadd f6, f11, f3, f6");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_nmsub() {
|
||||||
|
assert_asm!(0x107E083C, "ps_nmsub f3, f30, f0, f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_sel() {
|
||||||
|
assert_asm!(0x106428EE, "ps_sel f3, f4, f3, f5");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_sub() {
|
||||||
|
assert_asm!(0x10A92828, "ps_sub f5, f9, f5");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_sum0() {
|
||||||
|
assert_asm!(0x10230854, "ps_sum0 f1, f3, f1, f1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_ps_sum1() {
|
||||||
|
assert_asm!(0x10A12956, "ps_sum1 f5, f1, f5, f5");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_rfi() {
|
||||||
|
assert_asm!(0x4C000064, "rfi");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_rlwimi() {
|
||||||
|
assert_asm!(0x500306FE, "rlwimi r3, r0, 0, 27, 31");
|
||||||
|
assert_asm!(0x50032D74, "rlwimi r3, r0, 5, 21, 26");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_rlwinm() {
|
||||||
|
assert_asm!(0x54000423, "rlwinm. r0, r0, 0, 16, 17");
|
||||||
|
assert_asm!(0x54000432, "rlwinm r0, r0, 0, 16, 25");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_rlwnm() {
|
||||||
|
assert_asm!(0x5D6A67FE, "rlwnm r10, r11, r12, 31, 31");
|
||||||
|
assert_asm!(0x5FC52EFE, "rlwnm r5, r30, r5, 27, 31");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_sc() {
|
||||||
|
assert_asm!(0x44000002, "sc");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_slw() {
|
||||||
|
assert_asm!(0x7C042830, "slw r4, r0, r5");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_sraw() {
|
||||||
|
assert_asm!(0x7C043E30, "sraw r4, r0, r7");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_srawi() {
|
||||||
|
assert_asm!(0x7C000E70, "srawi r0, r0, 1");
|
||||||
|
assert_asm!(0x7C001670, "srawi r0, r0, 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_srw() {
|
||||||
|
assert_asm!(0x7C001C30, "srw r0, r0, r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stb() {
|
||||||
|
assert_asm!(0x980105EC, "stb r0, 0x5ec(r1)");
|
||||||
|
assert_asm!(0x98030000, "stb r0, 0x0(r3)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stbu() {
|
||||||
|
assert_asm!(0x9D2A7428, "stbu r9, 0x7428(r10)");
|
||||||
|
assert_asm!(0x9D66FFFF, "stbu r11, -0x1(r6)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stbux() {
|
||||||
|
assert_asm!(0x7C08F9EE, "stbux r0, r8, r31");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stbx() {
|
||||||
|
assert_asm!(0x7C03F9AE, "stbx r0, r3, r31");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stfd() {
|
||||||
|
assert_asm!(0xD80D97B0, "stfd f0, -0x6850(r13)");
|
||||||
|
assert_asm!(0xD8050090, "stfd f0, 0x90(r5)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stfdu() {
|
||||||
|
assert_asm!(0xDC24FFC0, "stfdu f1, -0x40(r4)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stfdx() {
|
||||||
|
assert_asm!(0x7C4405AE, "stfdx f2, r4, r0");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stfs() {
|
||||||
|
assert_asm!(0xD003086C, "stfs f0, 0x86c(r3)");
|
||||||
|
assert_asm!(0xD0038000, "stfs f0, -0x8000(r3)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stfsx() {
|
||||||
|
assert_asm!(0x7C465D2E, "stfsx f2, r6, r11");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_sth() {
|
||||||
|
assert_asm!(0xB0038A7C, "sth r0, -0x7584(r3)");
|
||||||
|
assert_asm!(0xB0035036, "sth r0, 0x5036(r3)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_sthbrx() {
|
||||||
|
assert_asm!(0x7C60072C, "sthbrx r3, r0, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_sthu() {
|
||||||
|
assert_asm!(0xB4055B88, "sthu r0, 0x5b88(r5)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_sthux() {
|
||||||
|
assert_asm!(0x7C03236E, "sthux r0, r3, r4");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_sthx() {
|
||||||
|
assert_asm!(0x7C1C2B2E, "sthx r0, r28, r5");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stmw() {
|
||||||
|
assert_asm!(0xBFA202A4, "stmw r29, 0x2a4(r2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stw() {
|
||||||
|
assert_asm!(0x900140CC, "stw r0, 0x40cc(r1)");
|
||||||
|
assert_asm!(0x9003FFBC, "stw r0, -0x44(r3)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stwbrx() {
|
||||||
|
assert_asm!(0x7C00FD2C, "stwbrx r0, r0, r31");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stwu() {
|
||||||
|
assert_asm!(0x9421EBC0, "stwu r1, -0x1440(r1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stwux() {
|
||||||
|
assert_asm!(0x7C01B96E, "stwux r0, r1, r23");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_stwx() {
|
||||||
|
assert_asm!(0x7C03212E, "stwx r0, r3, r4");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_subf() {
|
||||||
|
assert_asm!(0x7C051850, "subf r0, r5, r3");
|
||||||
|
assert_asm!(0x7C051851, "subf. r0, r5, r3");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_subfc() {
|
||||||
|
assert_asm!(0x7C040010, "subfc r0, r4, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_subfe() {
|
||||||
|
assert_asm!(0x7C030110, "subfe r0, r3, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_subfic() {
|
||||||
|
assert_asm!(0x200602FF, "subfic r0, r6, 0x2ff");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_subfze() {
|
||||||
|
assert_asm!(0x7C000190, "subfze r0, r0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_sync() {
|
||||||
|
assert_asm!(0x7C0004AC, "sync");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_xor() {
|
||||||
|
assert_asm!(0x7C052A78, "xor r5, r0, r5");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_xori() {
|
||||||
|
assert_asm!(0x68E71021, "xori r7, r7, 0x1021");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ins_xoris() {
|
||||||
|
assert_asm!(0x6E3D8000, "xoris r29, r17, 0x8000");
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "dol"
|
name = "dol"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
authors = ["Richard Patel <me@terorie.dev>"]
|
authors = ["Richard Patel <me@terorie.dev>"]
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
description = "Deserializer for the DOL executable format"
|
description = "Deserializer for the DOL executable format"
|
||||||
|
|
|
@ -121,7 +121,7 @@ pub enum DolSectionType {
|
||||||
Bss,
|
Bss,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive()]
|
#[derive(Debug, Clone)]
|
||||||
pub struct DolSection {
|
pub struct DolSection {
|
||||||
pub kind: DolSectionType,
|
pub kind: DolSectionType,
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
[package]
|
[package]
|
||||||
name = "ppc750cl-flow-graph"
|
name = "ppc750cl-flow-graph"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
authors = ["riidefi <riidefi@rii.dev>", "Richard Patel <me@terorie.dev>"]
|
authors = ["riidefi <riidefi@rii.dev>", "Richard Patel <me@terorie.dev>"]
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
description = "Control flow graph analysis for PowerPC 750CL"
|
description = "Control flow graph analysis for PowerPC 750CL"
|
||||||
repository = "https://github.com/terorie/ppc750cl"
|
repository = "https://github.com/terorie/ppc750cl"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33"
|
clap = "3"
|
||||||
dol = { version = "0.1.0", path = "../dol" }
|
dol = { version = "0.1.0", path = "../dol" }
|
||||||
itertools = "0.10"
|
itertools = "0.10"
|
||||||
parse_int = "0.5"
|
parse_int = "0.6"
|
||||||
petgraph = "0.6"
|
petgraph = "0.6"
|
||||||
ppc750cl = { version = "0.1.1", path = "../disasm" }
|
ppc750cl = { version = "0.2.0", path = "../disasm" }
|
||||||
|
|
|
@ -8,6 +8,7 @@ use petgraph::algo::dominators::Dominators;
|
||||||
use petgraph::graph::{DefaultIx, NodeIndex};
|
use petgraph::graph::{DefaultIx, NodeIndex};
|
||||||
use petgraph::Graph;
|
use petgraph::Graph;
|
||||||
|
|
||||||
|
use ppc750cl::formatter::FormattedIns;
|
||||||
use ppc750cl::{Ins, Opcode};
|
use ppc750cl::{Ins, Opcode};
|
||||||
|
|
||||||
use crate::slices::{BasicSlices, CodeIdx};
|
use crate::slices::{BasicSlices, CodeIdx};
|
||||||
|
@ -53,18 +54,21 @@ impl<'a> BasicBlock<'a> {
|
||||||
for ins in code {
|
for ins in code {
|
||||||
match ins.op {
|
match ins.op {
|
||||||
Opcode::Addis => {
|
Opcode::Addis => {
|
||||||
if ins.a() == 0 {
|
if ins.field_rA() == 0 {
|
||||||
// lis
|
// lis
|
||||||
defs.insert(ins.d(), ins.uimm());
|
defs.insert(ins.field_rD() as u8, ins.field_uimm() as u16);
|
||||||
} else {
|
} else {
|
||||||
defs.remove(&ins.d());
|
defs.remove(&(ins.field_rD() as u8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::Addi => {
|
Opcode::Addi => {
|
||||||
if let Some(hi) = defs.get(&ins.a()) {
|
if let Some(hi) = defs.get(&(ins.field_rA() as u8)) {
|
||||||
data_refs.insert(ins.addr / 4, ((*hi as u32) << 16) + (ins.uimm() as u32));
|
data_refs.insert(
|
||||||
|
ins.addr / 4,
|
||||||
|
((*hi as u32) << 16) + (ins.field_uimm() as u32),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
defs.remove(&ins.d());
|
defs.remove(&(ins.field_rD() as u8));
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
@ -88,7 +92,7 @@ impl<'a> Debug for BasicBlock<'a> {
|
||||||
self.range.end * 4
|
self.range.end * 4
|
||||||
)?;
|
)?;
|
||||||
for ins in self.code {
|
for ins in self.code {
|
||||||
writeln!(f, "{}", ins.to_string())?;
|
writeln!(f, "{}", FormattedIns(ins.clone()))?;
|
||||||
if let Some(addr) = self.data_refs.get(&(ins.addr / 4)) {
|
if let Some(addr) = self.data_refs.get(&(ins.addr / 4)) {
|
||||||
writeln!(f, " ref: {:0>#8x}", addr)?;
|
writeln!(f, " ref: {:0>#8x}", addr)?;
|
||||||
}
|
}
|
||||||
|
@ -151,8 +155,8 @@ impl<'a> FlowGraph<'a> {
|
||||||
// Get last instruction of left block.
|
// Get last instruction of left block.
|
||||||
// Unless it's an unconditional branch, we can connect the blocks.
|
// Unless it's an unconditional branch, we can connect the blocks.
|
||||||
let last_ins = &src_block.code.last().unwrap();
|
let last_ins = &src_block.code.last().unwrap();
|
||||||
if last_ins.code == Opcode::BLR
|
if last_ins.code == 0x4E800020
|
||||||
|| (last_ins.op == Opcode::B && last_ins.bo() == 0b10100)
|
|| (last_ins.op == Opcode::B && last_ins.field_BO() == 0b10100)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use clap::clap_app;
|
|
||||||
use petgraph::dot::{Config as DotConfig, Dot};
|
use petgraph::dot::{Config as DotConfig, Dot};
|
||||||
|
|
||||||
use ppc750cl::{disasm_iter, Ins};
|
use ppc750cl::{disasm_iter, Ins};
|
||||||
|
@ -11,14 +10,29 @@ use crate::slices::BasicSlices;
|
||||||
use dol::Dol;
|
use dol::Dol;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let matches = clap_app!(myapp =>
|
let matches = clap::Command::new("ppc750cl-flow-graph")
|
||||||
(version: "1.0")
|
.version("0.2.0")
|
||||||
(about: "Control flow graph analysis for PowerPC 750CL")
|
.about("Control flow graph analysis for PowerPC 750CL")
|
||||||
(@arg START: --start +required +takes_value "Start address")
|
.arg(
|
||||||
(@arg STOP: --stop +required +takes_value "Stop address")
|
clap::Arg::new("START")
|
||||||
(@arg INPUT: +required "Binary input file")
|
.long("--start")
|
||||||
)
|
.required(true)
|
||||||
.get_matches();
|
.takes_value(true)
|
||||||
|
.help("Start address"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
clap::Arg::new("STOP")
|
||||||
|
.long("--stop")
|
||||||
|
.required(true)
|
||||||
|
.takes_value(true)
|
||||||
|
.help("Stop address"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
clap::Arg::new("INPUT")
|
||||||
|
.required(true)
|
||||||
|
.help("Binary input file"),
|
||||||
|
)
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
let start_addr = matches.value_of("START").unwrap();
|
let start_addr = matches.value_of("START").unwrap();
|
||||||
let start_addr: u32 = ::parse_int::parse(start_addr).expect("Invalid address flag");
|
let start_addr: u32 = ::parse_int::parse(start_addr).expect("Invalid address flag");
|
||||||
|
|
|
@ -24,7 +24,7 @@ impl BasicSlices {
|
||||||
let is_control_flow_ins = match ins.op {
|
let is_control_flow_ins = match ins.op {
|
||||||
// Direct branches are control flow instructions if they don't save the link register.
|
// Direct branches are control flow instructions if they don't save the link register.
|
||||||
// If they do, we encountered a function call.
|
// If they do, we encountered a function call.
|
||||||
Opcode::B | Opcode::Bc => ins.lk() == 0,
|
Opcode::B | Opcode::Bc => !ins.field_LK(),
|
||||||
// Switch table
|
// Switch table
|
||||||
Opcode::Bcctr => panic!("jump tables not supported yet"),
|
Opcode::Bcctr => panic!("jump tables not supported yet"),
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -33,7 +33,7 @@ impl BasicSlices {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// We encountered some kind of control flow instruction.
|
// We encountered some kind of control flow instruction.
|
||||||
if ins.code != Opcode::BLR {
|
if ins.field_BO() == 20 && ins.field_BI() == 0 {
|
||||||
// There's a possibility that branch can be taken.
|
// There's a possibility that branch can be taken.
|
||||||
// Branch destinations are always the first instruction of a block.
|
// Branch destinations are always the first instruction of a block.
|
||||||
// Thus, we also found the end of another block.
|
// Thus, we also found the end of another block.
|
||||||
|
@ -58,5 +58,5 @@ fn is_conditional_branch(ins: &Ins) -> bool {
|
||||||
_ => return false,
|
_ => return false,
|
||||||
};
|
};
|
||||||
// Check whether bits "branch always".
|
// Check whether bits "branch always".
|
||||||
ins.bo() & 0b10100 != 0b10100
|
ins.field_BO() & 0b10100 != 0b10100
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "ppc750cl-fuzz"
|
name = "ppc750cl-fuzz"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
authors = ["Richard Patel <me@terorie.dev>"]
|
authors = ["Richard Patel <me@terorie.dev>"]
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
description = "Complete fuzzer for ppc750cl"
|
description = "Complete fuzzer for ppc750cl"
|
||||||
|
@ -9,4 +9,4 @@ repository = "https://github.com/terorie/ppc750cl"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
num_cpus = "1.13"
|
num_cpus = "1.13"
|
||||||
ppc750cl = { path = "../disasm", version = "0.1.1" }
|
ppc750cl = { path = "../disasm", version = "0.2.0" }
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
use std::io::Write;
|
||||||
|
use std::ops::Range;
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use ppc750cl::formatter::SimpleFormatter;
|
use ppc750cl::formatter::FormattedIns;
|
||||||
use ppc750cl::Ins;
|
use ppc750cl::Ins;
|
||||||
use std::ops::Range;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
@ -62,7 +63,6 @@ impl MultiFuzzer {
|
||||||
// for most of the time.
|
// for most of the time.
|
||||||
handle.join().expect("thread panicked");
|
handle.join().expect("thread panicked");
|
||||||
}
|
}
|
||||||
disasm(0xFFFF_FFFF);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,11 +81,14 @@ impl Fuzzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dispatch(&self) -> std::thread::JoinHandle<()> {
|
fn dispatch(&self) -> std::thread::JoinHandle<()> {
|
||||||
|
let mut devnull = DevNull;
|
||||||
|
|
||||||
let counter = Arc::clone(&self.counter);
|
let counter = Arc::clone(&self.counter);
|
||||||
let range = self.range.clone();
|
let range = self.range.clone();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
for x in range.clone() {
|
for x in range.clone() {
|
||||||
disasm(x);
|
let ins = Ins::new(x, 0x8000_0000);
|
||||||
|
writeln!(&mut devnull, "{}", FormattedIns(ins)).unwrap();
|
||||||
if x % (1 << 19) == 0 {
|
if x % (1 << 19) == 0 {
|
||||||
counter.store(x, Ordering::Relaxed);
|
counter.store(x, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
@ -95,13 +98,6 @@ impl Fuzzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disasm(x: u32) {
|
|
||||||
let devnull = DevNull;
|
|
||||||
let mut formatter = SimpleFormatter { writer: devnull };
|
|
||||||
let ins = Ins::new(x, 0x8000_0000u32);
|
|
||||||
ins.write_string(&mut formatter).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DevNull;
|
struct DevNull;
|
||||||
|
|
||||||
impl std::io::Write for DevNull {
|
impl std::io::Write for DevNull {
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
[package]
|
||||||
|
name = "ppc750cl-genisa"
|
||||||
|
version = "0.2.0"
|
||||||
|
edition = "2021"
|
||||||
|
authors = ["Richard Patel <me@terorie.dev>"]
|
||||||
|
license = "GPL-3.0-or-later"
|
||||||
|
description = "Rust code generator for ppc750cl"
|
||||||
|
repository = "https://github.com/terorie/ppc750cl"
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
itertools = "0.10"
|
||||||
|
proc-macro2 = "1.0"
|
||||||
|
quote = "1.0"
|
||||||
|
syn = "1.0"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_yaml = "0.8"
|
|
@ -0,0 +1,693 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::ops::Range;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
|
use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree};
|
||||||
|
use quote::quote;
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
use syn::{LitChar, LitInt, LitStr};
|
||||||
|
|
||||||
|
macro_rules! token_stream {
|
||||||
|
($stream:ident) => {
|
||||||
|
TokenStream::from_iter($stream.into_iter())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if let Err(err) = _main() {
|
||||||
|
eprintln!("{}", err);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error = Box<dyn std::error::Error>;
|
||||||
|
type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
fn _main() -> Result<()> {
|
||||||
|
let isa = load_isa()?;
|
||||||
|
|
||||||
|
let mut unformatted_code = Vec::<u8>::new();
|
||||||
|
writeln!(
|
||||||
|
&mut unformatted_code,
|
||||||
|
"{}",
|
||||||
|
quote! {
|
||||||
|
use crate::prelude::*;
|
||||||
|
}
|
||||||
|
)?;
|
||||||
|
writeln!(&mut unformatted_code, "{}", isa.gen_opcode_enum()?)?;
|
||||||
|
writeln!(&mut unformatted_code, "{}", isa.gen_field_enum()?)?;
|
||||||
|
writeln!(&mut unformatted_code, "{}", isa.gen_ins_impl()?)?;
|
||||||
|
|
||||||
|
let formatted_code = rustfmt(unformatted_code);
|
||||||
|
File::create("./disasm/src/generated.rs")?.write_all(&formatted_code)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rustfmt(code: Vec<u8>) -> Vec<u8> {
|
||||||
|
let mut rustfmt = Command::new("rustfmt")
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.expect("failed to spawn rustfmt");
|
||||||
|
|
||||||
|
let mut stdin = rustfmt.stdin.take().unwrap();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let _ = stdin.write_all(&code);
|
||||||
|
});
|
||||||
|
|
||||||
|
let rustfmt_res = rustfmt.wait_with_output().expect("failed to run rustfmt");
|
||||||
|
if !rustfmt_res.status.success() {
|
||||||
|
panic!("rustfmt failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
rustfmt_res.stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(crate) struct BitRange(Range<u8>);
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for BitRange {
|
||||||
|
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let range_str: String = Deserialize::deserialize(deserializer)?;
|
||||||
|
if let Some((start_str, stop_str)) = range_str.split_once("..") {
|
||||||
|
let start = start_str.parse::<u8>().map_err(serde::de::Error::custom)?;
|
||||||
|
let stop = stop_str.parse::<u8>().map_err(serde::de::Error::custom)?;
|
||||||
|
Ok(Self(start..stop))
|
||||||
|
} else {
|
||||||
|
let bit_idx = range_str.parse::<u8>().map_err(serde::de::Error::custom)?;
|
||||||
|
Ok(Self(bit_idx..bit_idx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) struct Field {
|
||||||
|
name: String,
|
||||||
|
desc: String,
|
||||||
|
bits: BitRange,
|
||||||
|
signed: bool,
|
||||||
|
split: bool,
|
||||||
|
arg: Option<String>,
|
||||||
|
shift_left: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Field {
|
||||||
|
fn variant_identifier(&self) -> Option<TokenTree> {
|
||||||
|
self.identifier("")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn identifier(&self, prefix: &str) -> Option<TokenTree> {
|
||||||
|
if self.name.strip_suffix(".nz").is_none() {
|
||||||
|
Some(to_rust_ident(prefix, &self.name))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn express_value(&self, code: TokenStream) -> TokenStream {
|
||||||
|
let mut val = quote!(#code);
|
||||||
|
|
||||||
|
let shift = 32 - self.bits.0.end;
|
||||||
|
if shift > 0 {
|
||||||
|
val = quote!((#val >> #shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mask = (1u32 << self.bits.0.len()) - 1;
|
||||||
|
if mask != 0xFFFF_FFFF {
|
||||||
|
let mask = LitInt::new(&format!("0x{:x}", mask), Span::call_site());
|
||||||
|
val = quote!((#val & #mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend
|
||||||
|
if self.signed {
|
||||||
|
let mask2 = 1u32 << (self.bits.0.len() - 1);
|
||||||
|
let mask2 = LitInt::new(&format!("0x{:x}", mask2), Span::call_site());
|
||||||
|
val = quote!(((#val ^ #mask2).wrapping_sub(#mask2)))
|
||||||
|
}
|
||||||
|
|
||||||
|
let val_shift = self.shift_left;
|
||||||
|
if val_shift > 0 {
|
||||||
|
val = quote!((#val << #val_shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
fn express_value_self(&self) -> TokenStream {
|
||||||
|
self.express_value(quote!(self.code))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enum_variant_definition(&self) -> Option<TokenStream> {
|
||||||
|
let ident = self.variant_identifier()?;
|
||||||
|
Some(if let Some(arg) = &self.arg {
|
||||||
|
let arg = TokenTree::Ident(Ident::new(arg, Span::call_site()));
|
||||||
|
quote! {
|
||||||
|
#ident(#arg),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
#ident,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_variant(&self, code: TokenStream) -> TokenStream {
|
||||||
|
let field_variant = self.variant_identifier();
|
||||||
|
if let Some(arg) = &self.arg {
|
||||||
|
let field_arg = TokenTree::Ident(Ident::new(arg, Span::call_site()));
|
||||||
|
let value = self.express_value(code);
|
||||||
|
quote! {
|
||||||
|
Field::#field_variant(#field_arg(#value as _))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
Field::#field_variant
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_variant_self(&self) -> TokenStream {
|
||||||
|
self.construct_variant(quote!(self.code))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_accessor(&self) -> TokenStream {
|
||||||
|
let field_variant = match self.identifier("field_") {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return TokenStream::new(),
|
||||||
|
};
|
||||||
|
if self.arg.is_none() {
|
||||||
|
return TokenStream::new();
|
||||||
|
}
|
||||||
|
let value = self.express_value_self();
|
||||||
|
let ret_type = if self.signed {
|
||||||
|
quote!(isize)
|
||||||
|
} else {
|
||||||
|
quote!(usize)
|
||||||
|
};
|
||||||
|
quote! {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn #field_variant(&self) -> #ret_type {
|
||||||
|
#value as _
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) struct Opcode {
|
||||||
|
name: String,
|
||||||
|
desc: String,
|
||||||
|
bitmask: u32,
|
||||||
|
pattern: u32,
|
||||||
|
modifiers: Vec<String>,
|
||||||
|
side_effects: Vec<String>,
|
||||||
|
args: Vec<String>,
|
||||||
|
defs: Vec<String>,
|
||||||
|
uses: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Opcode {
|
||||||
|
fn variant_identifier(&self) -> Result<TokenTree> {
|
||||||
|
to_rust_variant(&self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) struct Mnemonic {
|
||||||
|
name: String,
|
||||||
|
opcode: String,
|
||||||
|
modifiers: Vec<String>,
|
||||||
|
args: Vec<String>,
|
||||||
|
condition: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) struct Modifier {
|
||||||
|
name: String,
|
||||||
|
suffix: char,
|
||||||
|
bit: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Modifier {
|
||||||
|
fn express_value_self(&self) -> TokenStream {
|
||||||
|
let modifier_bit = self.bit as usize;
|
||||||
|
quote!(self.bit(#modifier_bit))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_accessor(&self) -> TokenStream {
|
||||||
|
let field_variant = to_rust_ident("field_", &self.name);
|
||||||
|
let value = self.express_value_self();
|
||||||
|
quote! {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn #field_variant(&self) -> bool {
|
||||||
|
#value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default)]
|
||||||
|
#[serde(default)]
|
||||||
|
pub(crate) struct Isa {
|
||||||
|
fields: Vec<Field>,
|
||||||
|
modifiers: Vec<Modifier>,
|
||||||
|
opcodes: Vec<Opcode>,
|
||||||
|
mnemonics: Vec<Mnemonic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_isa() -> Result<Isa> {
|
||||||
|
let yaml_file = File::open("isa.yaml")?;
|
||||||
|
let isa: Isa = serde_yaml::from_reader(yaml_file)?;
|
||||||
|
Ok(isa)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Isa {
|
||||||
|
fn gen_opcode_enum(&self) -> Result<TokenStream> {
|
||||||
|
// Create enum variants.
|
||||||
|
let enum_variants = self
|
||||||
|
.opcodes
|
||||||
|
.iter()
|
||||||
|
.map(|opcode| -> Result<TokenStream> {
|
||||||
|
let ident = opcode.variant_identifier()?;
|
||||||
|
Ok(quote! {
|
||||||
|
#ident,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.try_collect::<TokenStream, Vec<TokenStream>, Error>()?;
|
||||||
|
let enum_variants = token_stream!(enum_variants);
|
||||||
|
|
||||||
|
// Create functions.
|
||||||
|
let mnemonic_fn = self.gen_mnemonic_fn()?;
|
||||||
|
let detect_fn = self.gen_opcode_detect()?;
|
||||||
|
|
||||||
|
// Create final enum.
|
||||||
|
let opcode_enum = quote! {
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum Opcode {
|
||||||
|
Illegal = -1,
|
||||||
|
#enum_variants
|
||||||
|
}
|
||||||
|
#[allow(clippy::all)]
|
||||||
|
impl Opcode {
|
||||||
|
#mnemonic_fn
|
||||||
|
#detect_fn
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(opcode_enum)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gen_mnemonic_fn(&self) -> Result<TokenStream> {
|
||||||
|
// Create match arms.
|
||||||
|
let match_arms = self
|
||||||
|
.opcodes
|
||||||
|
.iter()
|
||||||
|
.map(|opcode| {
|
||||||
|
let variant = opcode.variant_identifier()?;
|
||||||
|
let literal = Literal::string(&opcode.name);
|
||||||
|
Ok(quote! {
|
||||||
|
Opcode::#variant => #literal,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.try_collect::<TokenStream, Vec<TokenStream>, Error>()?;
|
||||||
|
let match_arms = token_stream!(match_arms);
|
||||||
|
// Create final function.
|
||||||
|
let mnemonic_fn = quote! {
|
||||||
|
pub(crate) fn _mnemonic(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Opcode::Illegal => "<illegal>",
|
||||||
|
#match_arms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(mnemonic_fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn gen_opcode_detect(&self) -> Result<TokenStream> {
|
||||||
|
// Generate if chain.
|
||||||
|
let if_chain = self
|
||||||
|
.opcodes
|
||||||
|
.iter()
|
||||||
|
.map(|opcode| {
|
||||||
|
let bitmask_str = format!("{:>#8x}", opcode.bitmask);
|
||||||
|
let bitmask = LitInt::new(&bitmask_str, Span::call_site());
|
||||||
|
let pattern_str = format!("{:>#8x}", opcode.pattern);
|
||||||
|
let pattern = LitInt::new(&pattern_str, Span::call_site());
|
||||||
|
let identifier = opcode.variant_identifier()?;
|
||||||
|
Ok(quote! {
|
||||||
|
if code & #bitmask == #pattern {
|
||||||
|
return Opcode::#identifier;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.try_collect::<TokenStream, Vec<TokenStream>, Error>()?;
|
||||||
|
let if_chain = token_stream!(if_chain);
|
||||||
|
// Generate function.
|
||||||
|
let func = quote! {
|
||||||
|
pub(crate) fn _detect(code: u32) -> Self {
|
||||||
|
#if_chain
|
||||||
|
Opcode::Illegal
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(func)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn gen_field_enum(&self) -> Result<TokenStream> {
|
||||||
|
// Create enum variants.
|
||||||
|
let mut enum_variants = Vec::new();
|
||||||
|
for field in &self.fields {
|
||||||
|
if let Some(field) = field.enum_variant_definition() {
|
||||||
|
enum_variants.push(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let enum_variants = token_stream!(enum_variants);
|
||||||
|
|
||||||
|
// Create final enum.
|
||||||
|
let field_enum = quote! {
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum Field {
|
||||||
|
#enum_variants
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(field_enum)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn gen_ins_impl(&self) -> Result<TokenStream> {
|
||||||
|
// Map fields by name.
|
||||||
|
let mut field_by_name = HashMap::<String, &Field>::new();
|
||||||
|
for field in &self.fields {
|
||||||
|
field_by_name.insert(field.name.clone(), field);
|
||||||
|
}
|
||||||
|
let mut modifier_by_name = HashMap::<String, &Modifier>::new();
|
||||||
|
for modifier in &self.modifiers {
|
||||||
|
modifier_by_name.insert(modifier.name.clone(), modifier);
|
||||||
|
}
|
||||||
|
// Map mnemonics by opcode.
|
||||||
|
let mut mnemonics_by_opcode = HashMap::<&String, Vec<&Mnemonic>>::new();
|
||||||
|
for simple in &self.mnemonics {
|
||||||
|
mnemonics_by_opcode
|
||||||
|
.entry(&simple.opcode)
|
||||||
|
.or_insert_with(Vec::new)
|
||||||
|
.push(simple)
|
||||||
|
}
|
||||||
|
// Generate match arms for each opcode.
|
||||||
|
let mut field_match_arms = Vec::new();
|
||||||
|
let mut def_match_arms = Vec::new();
|
||||||
|
let mut use_match_arms = Vec::new();
|
||||||
|
let mut suffix_match_arms = Vec::new();
|
||||||
|
let mut simplified_ins_match_arms = Vec::new();
|
||||||
|
for opcode in &self.opcodes {
|
||||||
|
// Generate fields of opcode.
|
||||||
|
let mut fields = Vec::new();
|
||||||
|
for arg in &opcode.args {
|
||||||
|
let field: &Field = field_by_name
|
||||||
|
.get(arg)
|
||||||
|
.ok_or_else(|| Error::from(format!("undefined field {}", arg)))?;
|
||||||
|
let variant = field.construct_variant_self();
|
||||||
|
fields.extend(quote! { #variant, })
|
||||||
|
}
|
||||||
|
let fields = token_stream!(fields);
|
||||||
|
// Emit match arm.
|
||||||
|
let ident = opcode.variant_identifier()?;
|
||||||
|
field_match_arms.push(quote! {
|
||||||
|
Opcode::#ident => vec![#fields],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate modifiers.
|
||||||
|
let suffix = express_suffix(&modifier_by_name, opcode)?;
|
||||||
|
suffix_match_arms.push(quote! {
|
||||||
|
Opcode::#ident => #suffix,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate defs.
|
||||||
|
let mut defs = Vec::new();
|
||||||
|
for arg in &opcode.defs {
|
||||||
|
let field: &Field = field_by_name.get(arg).ok_or_else(|| {
|
||||||
|
syn::Error::new(Span::call_site(), format!("undefined field {}", arg))
|
||||||
|
})?;
|
||||||
|
let variant = field.construct_variant_self();
|
||||||
|
defs.extend(quote! { #variant, })
|
||||||
|
}
|
||||||
|
let defs = token_stream!(defs);
|
||||||
|
let ident = opcode.variant_identifier()?;
|
||||||
|
def_match_arms.push(quote! {
|
||||||
|
Opcode::#ident => vec![#defs],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate uses.
|
||||||
|
let mut uses = Vec::new();
|
||||||
|
let mut special_uses = Vec::new();
|
||||||
|
for arg in &opcode.uses {
|
||||||
|
// Detect non-zero modifier.
|
||||||
|
let mut arg = arg.as_str();
|
||||||
|
let mut non_zero = false;
|
||||||
|
if let Some(substr) = arg.strip_suffix(".nz") {
|
||||||
|
non_zero = true;
|
||||||
|
arg = substr;
|
||||||
|
}
|
||||||
|
// Get underlying field.
|
||||||
|
let field: &Field = field_by_name.get(arg).ok_or_else(|| {
|
||||||
|
syn::Error::new(Span::call_site(), format!("undefined field {}", arg))
|
||||||
|
})?;
|
||||||
|
let variant = field.construct_variant_self();
|
||||||
|
if non_zero {
|
||||||
|
let value = field.express_value_self();
|
||||||
|
special_uses.extend(quote! {
|
||||||
|
if (#value) != 0 {
|
||||||
|
uses.push(#variant);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
uses.extend(quote! {
|
||||||
|
#variant,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let uses = token_stream!(uses);
|
||||||
|
let ident = opcode.variant_identifier()?;
|
||||||
|
let special_uses = token_stream!(special_uses);
|
||||||
|
use_match_arms.push(quote! {
|
||||||
|
Opcode::#ident => {
|
||||||
|
let mut uses = vec![#uses];
|
||||||
|
#special_uses
|
||||||
|
uses
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Generate instruction simplification.
|
||||||
|
if let Some(mnemonics) = mnemonics_by_opcode.get(&opcode.name) {
|
||||||
|
let mut simplified_conditions = Vec::new();
|
||||||
|
for mnemonic in mnemonics {
|
||||||
|
if mnemonic.condition.is_empty() {
|
||||||
|
continue; // TODO else branch
|
||||||
|
}
|
||||||
|
simplified_conditions.push(quote!(if));
|
||||||
|
simplified_conditions.push(compile_mnemonic_condition(
|
||||||
|
&field_by_name,
|
||||||
|
&mnemonic.condition,
|
||||||
|
)?);
|
||||||
|
// Emit branch.
|
||||||
|
let mnemonic_lit = LitStr::new(&mnemonic.name, Span::call_site());
|
||||||
|
// Extract arguments.
|
||||||
|
let mut args = Vec::new();
|
||||||
|
for arg in &mnemonic.args {
|
||||||
|
let field = field_by_name
|
||||||
|
.get(arg)
|
||||||
|
.unwrap_or_else(|| panic!("field not found: {}", arg));
|
||||||
|
let variant = Ident::new(field.arg.as_ref().unwrap(), Span::call_site());
|
||||||
|
let value = field.express_value_self();
|
||||||
|
args.push(quote!(Argument::#variant(#variant(#value as _)),));
|
||||||
|
}
|
||||||
|
let args = token_stream!(args);
|
||||||
|
simplified_conditions.push(quote! {
|
||||||
|
{
|
||||||
|
return SimplifiedIns {
|
||||||
|
mnemonic: #mnemonic_lit,
|
||||||
|
args: vec![#args],
|
||||||
|
ins: self,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let simplified_conditions = token_stream!(simplified_conditions);
|
||||||
|
simplified_ins_match_arms.push(quote! {
|
||||||
|
Opcode::#ident => {
|
||||||
|
#simplified_conditions
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let field_match_arms = token_stream!(field_match_arms);
|
||||||
|
let def_match_arms = token_stream!(def_match_arms);
|
||||||
|
let use_match_arms = token_stream!(use_match_arms);
|
||||||
|
let suffix_match_arms = token_stream!(suffix_match_arms);
|
||||||
|
let simplified_ins_match_arms = token_stream!(simplified_ins_match_arms);
|
||||||
|
let field_accessors = self
|
||||||
|
.fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| field.construct_accessor())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let field_accessors = token_stream!(field_accessors);
|
||||||
|
let modifier_accessors = self
|
||||||
|
.modifiers
|
||||||
|
.iter()
|
||||||
|
.map(|modifier| modifier.construct_accessor())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let modifier_accessors = token_stream!(modifier_accessors);
|
||||||
|
// Generate final fields function.
|
||||||
|
let ins_impl = quote! {
|
||||||
|
#[allow(clippy::all, unused_mut)]
|
||||||
|
impl Ins {
|
||||||
|
pub(crate) fn _fields(&self) -> Vec<Field> {
|
||||||
|
match self.op {
|
||||||
|
Opcode::Illegal => vec![],
|
||||||
|
#field_match_arms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn _defs(&self) -> Vec<Field> {
|
||||||
|
match self.op {
|
||||||
|
Opcode::Illegal => vec![],
|
||||||
|
#def_match_arms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn _uses(&self) -> Vec<Field> {
|
||||||
|
match self.op {
|
||||||
|
Opcode::Illegal => vec![],
|
||||||
|
#use_match_arms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn _suffix(&self) -> String {
|
||||||
|
match self.op {
|
||||||
|
Opcode::Illegal => String::new(),
|
||||||
|
#suffix_match_arms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn _simplified(self) -> SimplifiedIns {
|
||||||
|
match self.op {
|
||||||
|
#simplified_ins_match_arms
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
SimplifiedIns::basic_form(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(clippy::all, non_snake_case)]
|
||||||
|
impl Ins {
|
||||||
|
#field_accessors
|
||||||
|
#modifier_accessors
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(ins_impl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the given key into an identifier.
|
||||||
|
fn to_rust_ident(prefix: &str, key: &str) -> TokenTree {
|
||||||
|
TokenTree::Ident(Ident::new(
|
||||||
|
&(prefix.to_owned() + &key.replace('.', "_")),
|
||||||
|
Span::call_site(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts the given key into an enum variant key.
|
||||||
|
fn to_rust_variant(key: &str) -> Result<TokenTree> {
|
||||||
|
Ok(TokenTree::Ident(Ident::new(
|
||||||
|
&to_rust_variant_str(key)?,
|
||||||
|
Span::call_site(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_rust_variant_str(key: &str) -> Result<String> {
|
||||||
|
let mut s = String::new();
|
||||||
|
let mut chars = key.chars();
|
||||||
|
loop {
|
||||||
|
// Make first char uppercase.
|
||||||
|
let c = match chars.next() {
|
||||||
|
None => return Ok(s),
|
||||||
|
Some(c) => c,
|
||||||
|
};
|
||||||
|
s.push(match c {
|
||||||
|
'a'..='z' => c.to_ascii_uppercase(),
|
||||||
|
'A'..='Z' => c,
|
||||||
|
_ => return Err(format!("invalid identifier: {}", key).into()),
|
||||||
|
});
|
||||||
|
loop {
|
||||||
|
let c = match chars.next() {
|
||||||
|
None => return Ok(s),
|
||||||
|
Some(c) => c,
|
||||||
|
};
|
||||||
|
match c.to_ascii_lowercase() {
|
||||||
|
'0'..='9' | 'a'..='z' => s.push(c),
|
||||||
|
'_' => break,
|
||||||
|
'.' => {
|
||||||
|
s.push('_');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => return Err(format!("invalid character in opcode name: {}", key).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compiles conditions such as `S == B` into valid Rust expressions on a PowerPC instruction.
|
||||||
|
fn compile_mnemonic_condition(
|
||||||
|
field_by_name: &HashMap<String, &Field>,
|
||||||
|
code: &str,
|
||||||
|
) -> Result<TokenStream> {
|
||||||
|
let src_stream = TokenStream::from_str(code)?;
|
||||||
|
let token_iter = src_stream.into_iter().flat_map(|token| {
|
||||||
|
if let TokenTree::Ident(ref ident) = token {
|
||||||
|
if let Some(field) = field_by_name.get(&ident.to_string()) {
|
||||||
|
return field.express_value_self();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
token.into()
|
||||||
|
});
|
||||||
|
Ok(TokenStream::from_iter(token_iter))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn express_suffix(
|
||||||
|
modifier_by_name: &HashMap<String, &Modifier>,
|
||||||
|
opcode: &Opcode,
|
||||||
|
) -> Result<TokenStream> {
|
||||||
|
Ok(if opcode.modifiers.is_empty() {
|
||||||
|
quote!(String::new())
|
||||||
|
} else {
|
||||||
|
let mut chars = Vec::new();
|
||||||
|
for mod_name in &opcode.modifiers {
|
||||||
|
let modifier: &Modifier = modifier_by_name
|
||||||
|
.get(mod_name)
|
||||||
|
.ok_or_else(|| Error::from(format!("undefined modifier {}", mod_name)))?;
|
||||||
|
let lit_char = LitChar::new(modifier.suffix, Span::call_site());
|
||||||
|
let modifier_bit = modifier.express_value_self();
|
||||||
|
chars.push(quote! {
|
||||||
|
if #modifier_bit {
|
||||||
|
s.push(#lit_char);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let chars = token_stream!(chars);
|
||||||
|
quote!({
|
||||||
|
{
|
||||||
|
let mut s = String::with_capacity(4);
|
||||||
|
#chars
|
||||||
|
s
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,16 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "ppc750cl-macros"
|
|
||||||
version = "0.1.1"
|
|
||||||
edition = "2018"
|
|
||||||
authors = ["Richard Patel <me@terorie.dev>"]
|
|
||||||
license = "GPL-3.0-or-later"
|
|
||||||
description = "Procedural macros for powerpc750cl"
|
|
||||||
repository = "https://github.com/terorie/ppc750cl"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
proc-macro = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
proc-macro2 = "1.0.28"
|
|
||||||
quote = "1.0.9"
|
|
||||||
syn = { version = "1.0.74", features = ["full", "parsing"] }
|
|
|
@ -1,215 +0,0 @@
|
||||||
use std::iter::FromIterator;
|
|
||||||
|
|
||||||
use proc_macro2::{Delimiter, Group, Ident, Literal, Span, TokenStream, TokenTree};
|
|
||||||
use quote::quote;
|
|
||||||
use syn::parse::{Parse, ParseStream};
|
|
||||||
use syn::punctuated::Punctuated;
|
|
||||||
use syn::token::{And, EqEq, Semi};
|
|
||||||
use syn::{LitInt, LitStr};
|
|
||||||
|
|
||||||
struct Opcodes {
|
|
||||||
opcodes: Punctuated<Opcode, Semi>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for Opcodes {
|
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
|
||||||
Ok(Self {
|
|
||||||
opcodes: Punctuated::parse_terminated(input)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Opcode {
|
|
||||||
name: String,
|
|
||||||
variant_name: String,
|
|
||||||
mask: u32,
|
|
||||||
bits: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for Opcode {
|
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
|
||||||
let name = input.parse::<LitStr>()?;
|
|
||||||
input.parse::<And>()?;
|
|
||||||
let mask = input.parse::<LitInt>()?;
|
|
||||||
input.parse::<EqEq>()?;
|
|
||||||
let bits = input.parse::<LitInt>()?;
|
|
||||||
Ok(Self {
|
|
||||||
name: name.value(),
|
|
||||||
variant_name: opcode_to_variant_name(&name)?,
|
|
||||||
mask: hex_from_lit_int(&mask)?,
|
|
||||||
bits: hex_from_lit_int(&bits)?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hex_from_lit_int(int: &LitInt) -> syn::Result<u32> {
|
|
||||||
let str = int.to_string();
|
|
||||||
let hex = match str.strip_prefix("0x") {
|
|
||||||
None => return Err(syn::Error::new(int.span(), "not a hex integer")),
|
|
||||||
Some(x) => x,
|
|
||||||
};
|
|
||||||
u32::from_str_radix(hex, 16).map_err(|e| syn::Error::new(int.span(), e))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn opcode_to_variant_name(opcode: &LitStr) -> syn::Result<String> {
|
|
||||||
let mut s = String::new();
|
|
||||||
let opcode_value = opcode.value();
|
|
||||||
let mut chars = opcode_value.chars();
|
|
||||||
loop {
|
|
||||||
// Make first char uppercase.
|
|
||||||
let c = match chars.next() {
|
|
||||||
None => return Ok(s),
|
|
||||||
Some(c) => c,
|
|
||||||
};
|
|
||||||
match c {
|
|
||||||
'a'..='z' => s.push(c.to_ascii_uppercase()),
|
|
||||||
_ => return Err(syn::Error::new(opcode.span(), "invalid opcode name")),
|
|
||||||
}
|
|
||||||
loop {
|
|
||||||
let c = match chars.next() {
|
|
||||||
None => return Ok(s),
|
|
||||||
Some(c) => c,
|
|
||||||
};
|
|
||||||
match c {
|
|
||||||
'0'..='9' | 'a'..='z' => s.push(c),
|
|
||||||
'_' => break,
|
|
||||||
'.' => {
|
|
||||||
s.push('_');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return Err(syn::Error::new(
|
|
||||||
opcode.span(),
|
|
||||||
"invalid character in opcode name",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_is_valid_fn(tokens: &mut Vec<TokenTree>, opcodes: &Opcodes) {
|
|
||||||
tokens.extend(quote!(pub fn is_valid(self, code: u32) -> bool));
|
|
||||||
|
|
||||||
let mut parts = Vec::<TokenTree>::new();
|
|
||||||
parts.extend(quote!(match self));
|
|
||||||
|
|
||||||
let mut match_parts = Vec::<TokenTree>::new();
|
|
||||||
match_parts.extend(quote!(Opcode::Illegal => false,));
|
|
||||||
|
|
||||||
for opcode in &opcodes.opcodes {
|
|
||||||
match_parts.extend(quote!(Opcode::));
|
|
||||||
match_parts.push(TokenTree::Ident(Ident::new(
|
|
||||||
&opcode.variant_name,
|
|
||||||
Span::call_site(),
|
|
||||||
)));
|
|
||||||
match_parts.extend(quote!(=> code &));
|
|
||||||
match_parts.push(TokenTree::Literal(Literal::u32_suffixed(opcode.mask)));
|
|
||||||
match_parts.extend(quote!(==));
|
|
||||||
match_parts.push(TokenTree::Literal(Literal::u32_suffixed(opcode.bits)));
|
|
||||||
match_parts.extend(quote!(,));
|
|
||||||
}
|
|
||||||
let match_body = Group::new(Delimiter::Brace, TokenStream::from_iter(match_parts));
|
|
||||||
parts.push(TokenTree::Group(match_body));
|
|
||||||
let body = Group::new(Delimiter::Brace, TokenStream::from_iter(parts));
|
|
||||||
tokens.push(TokenTree::Group(body));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn gen_mnemonic_fn(tokens: &mut Vec<TokenTree>, opcodes: &Opcodes) {
|
|
||||||
tokens.extend(quote!(pub fn mnemonic(self) -> &'static str));
|
|
||||||
|
|
||||||
let mut parts = Vec::<TokenTree>::new();
|
|
||||||
parts.extend(quote!(match self));
|
|
||||||
|
|
||||||
let mut match_parts = Vec::<TokenTree>::new();
|
|
||||||
match_parts.extend(quote!(Opcode::Illegal => "<illegal>",));
|
|
||||||
for opcode in &opcodes.opcodes {
|
|
||||||
match_parts.extend(quote!(Opcode::));
|
|
||||||
match_parts.push(TokenTree::Ident(Ident::new(
|
|
||||||
&opcode.variant_name,
|
|
||||||
Span::call_site(),
|
|
||||||
)));
|
|
||||||
match_parts.extend(quote!(=>));
|
|
||||||
match_parts.push(TokenTree::Literal(Literal::string(&opcode.name)));
|
|
||||||
match_parts.extend(quote!(,));
|
|
||||||
}
|
|
||||||
|
|
||||||
let match_body = Group::new(Delimiter::Brace, TokenStream::from_iter(match_parts));
|
|
||||||
parts.push(TokenTree::Group(match_body));
|
|
||||||
|
|
||||||
let body = Group::new(Delimiter::Brace, TokenStream::from_iter(parts));
|
|
||||||
tokens.push(TokenTree::Group(body));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn isa(input: TokenStream) -> syn::Result<TokenStream> {
|
|
||||||
let opcodes: Opcodes = syn::parse2(input)?;
|
|
||||||
|
|
||||||
// Assemble root stream.
|
|
||||||
let mut root = Vec::<TokenTree>::new();
|
|
||||||
|
|
||||||
// Define enum derives and header.
|
|
||||||
root.extend(quote!(#[derive(Debug, Copy, Clone, Eq, PartialEq)]));
|
|
||||||
root.extend(quote!(pub enum Opcode));
|
|
||||||
|
|
||||||
// Create entries.
|
|
||||||
// First entry is going to be the illegal entry.
|
|
||||||
let mut enum_entries = Vec::<TokenTree>::new();
|
|
||||||
enum_entries.extend(quote!(Illegal = -1,));
|
|
||||||
// Append the actual opcodes.
|
|
||||||
for opcode in &opcodes.opcodes {
|
|
||||||
enum_entries.push(TokenTree::Ident(Ident::new(
|
|
||||||
&opcode.variant_name,
|
|
||||||
Span::call_site(),
|
|
||||||
)));
|
|
||||||
enum_entries.extend(quote!(,));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create body.
|
|
||||||
let enum_body = Group::new(Delimiter::Brace, TokenStream::from_iter(enum_entries));
|
|
||||||
root.push(TokenTree::Group(enum_body));
|
|
||||||
|
|
||||||
// impl Opcode block.
|
|
||||||
root.extend(quote!(impl Opcode));
|
|
||||||
let mut impl_opcode_body_parts = Vec::<TokenTree>::new();
|
|
||||||
gen_is_valid_fn(&mut impl_opcode_body_parts, &opcodes);
|
|
||||||
gen_mnemonic_fn(&mut impl_opcode_body_parts, &opcodes);
|
|
||||||
let impl_opcode_body = Group::new(
|
|
||||||
Delimiter::Brace,
|
|
||||||
TokenStream::from_iter(impl_opcode_body_parts),
|
|
||||||
);
|
|
||||||
root.push(TokenTree::Group(impl_opcode_body));
|
|
||||||
|
|
||||||
// Extra code.
|
|
||||||
root.extend(quote! {
|
|
||||||
impl Default for Opcode {
|
|
||||||
fn default() -> Self {
|
|
||||||
Opcode::Illegal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::string::ToString for Opcode {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
let mnemonic = self.mnemonic();
|
|
||||||
mnemonic.to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(TokenStream::from_iter(root))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
fn _opcode_to_variant_name(input: &str) -> String {
|
|
||||||
opcode_to_variant_name(&LitStr::new(input, proc_macro2::Span::call_site())).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_opcode_to_variant_name() {
|
|
||||||
assert_eq!(_opcode_to_variant_name("lol_lel."), "LolLel_");
|
|
||||||
assert_eq!(_opcode_to_variant_name("ps_nmsub"), "PsNmsub");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
mod isa;
|
|
||||||
mod writer;
|
|
||||||
|
|
||||||
#[proc_macro]
|
|
||||||
pub fn isa(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
||||||
let input = proc_macro2::TokenStream::from(input);
|
|
||||||
let output = match crate::isa::isa(input) {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(err) => return proc_macro::TokenStream::from(err.to_compile_error()),
|
|
||||||
};
|
|
||||||
proc_macro::TokenStream::from(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro]
|
|
||||||
pub fn write_asm(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
||||||
let input = proc_macro2::TokenStream::from(input);
|
|
||||||
let output = match crate::writer::write_asm(input) {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(err) => return proc_macro::TokenStream::from(err.to_compile_error()),
|
|
||||||
};
|
|
||||||
proc_macro::TokenStream::from(output)
|
|
||||||
}
|
|
|
@ -1,170 +0,0 @@
|
||||||
use std::iter::FromIterator;
|
|
||||||
use std::string::ToString;
|
|
||||||
|
|
||||||
use proc_macro2::{Delimiter, Group, TokenStream};
|
|
||||||
use quote::quote;
|
|
||||||
use quote::ToTokens;
|
|
||||||
use syn::parse::{Parse, ParseStream};
|
|
||||||
use syn::punctuated::Punctuated;
|
|
||||||
use syn::spanned::Spanned;
|
|
||||||
use syn::{Expr, ExprLit, ExprPath, Ident};
|
|
||||||
|
|
||||||
struct Arguments {
|
|
||||||
formatter: Expr,
|
|
||||||
ins: Expr,
|
|
||||||
args: Punctuated<Argument, syn::token::Semi>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for Arguments {
|
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
|
||||||
let formatter = input.parse()?;
|
|
||||||
input.parse::<syn::token::Comma>()?;
|
|
||||||
let ins = input.parse()?;
|
|
||||||
input.parse::<syn::token::FatArrow>()?;
|
|
||||||
let content;
|
|
||||||
syn::braced!(content in input);
|
|
||||||
let args = Punctuated::parse_terminated(&content)?;
|
|
||||||
Ok(Self {
|
|
||||||
formatter,
|
|
||||||
ins,
|
|
||||||
args,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A single part of an instruction.
|
|
||||||
///
|
|
||||||
/// Examples:
|
|
||||||
/// ```ignore
|
|
||||||
/// (op.mnemonic, rc, oe) -> mnemonic;
|
|
||||||
/// d -> fpr;
|
|
||||||
/// ```
|
|
||||||
struct Argument {
|
|
||||||
sources: Vec<Expr>,
|
|
||||||
target: Ident,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for Argument {
|
|
||||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
|
||||||
// Parse source part.
|
|
||||||
let lookahead = input.lookahead1();
|
|
||||||
let sources;
|
|
||||||
if lookahead.peek(syn::token::Paren) {
|
|
||||||
// Parse multiple if we found a parenthesis.
|
|
||||||
let content;
|
|
||||||
syn::parenthesized!(content in input);
|
|
||||||
sources = content
|
|
||||||
.parse_terminated::<Expr, syn::token::Comma>(Expr::parse)?
|
|
||||||
.into_iter()
|
|
||||||
.collect();
|
|
||||||
} else if lookahead.peek(syn::LitStr) || lookahead.peek(syn::LitInt) {
|
|
||||||
let expr = input.parse::<ExprLit>()?.into();
|
|
||||||
sources = vec![expr];
|
|
||||||
} else {
|
|
||||||
let expr = input.parse::<ExprPath>()?.into();
|
|
||||||
sources = vec![expr];
|
|
||||||
}
|
|
||||||
input.parse::<syn::token::Colon>()?;
|
|
||||||
let target = input.parse()?;
|
|
||||||
Ok(Self { sources, target })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Arguments {
|
|
||||||
fn format_mnemonic(&self) -> Vec<TokenStream> {
|
|
||||||
let arg = &self.args[0];
|
|
||||||
assert!(!arg.sources.is_empty());
|
|
||||||
// Print the mnemonic.
|
|
||||||
let mut calls = vec![self.format_call(&arg.target, self.ins_call(&arg.sources[0]))];
|
|
||||||
// Print any mnemonic suffixes.
|
|
||||||
for src in arg.sources.iter().skip(1) {
|
|
||||||
calls.push(self.format_call(
|
|
||||||
&Ident::new(&src.into_token_stream().to_string(), src.span()),
|
|
||||||
self.ins_call(src),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
calls
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_call(&self, method_arg: &Ident, args: TokenStream) -> TokenStream {
|
|
||||||
let arg_str = method_arg.to_string();
|
|
||||||
let method_name = format!("write_{}", arg_str);
|
|
||||||
let method_name = Ident::new(&method_name, method_arg.span());
|
|
||||||
let formatter = &self.formatter;
|
|
||||||
if arg_str == "branch_target" {
|
|
||||||
quote!(#formatter.write_branch_target(#args, self.addr)?)
|
|
||||||
} else {
|
|
||||||
quote!(#formatter.#method_name(#args)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ins_call(&self, call: &Expr) -> TokenStream {
|
|
||||||
match call {
|
|
||||||
Expr::Lit(_) => call.to_token_stream(),
|
|
||||||
_ => {
|
|
||||||
let ins = &self.ins;
|
|
||||||
quote!(#ins.#call())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn write_asm(input: TokenStream) -> syn::Result<TokenStream> {
|
|
||||||
let arguments: Arguments = syn::parse2(input)?;
|
|
||||||
assert!(!arguments.args.is_empty());
|
|
||||||
|
|
||||||
// Create a list of calls to execute.
|
|
||||||
let mut calls = Vec::<TokenStream>::new();
|
|
||||||
calls.extend(arguments.format_mnemonic());
|
|
||||||
let mut offset_open = false;
|
|
||||||
for (i, arg) in arguments.args.iter().enumerate().skip(1) {
|
|
||||||
// Separate operands from one another unless the last one was an offset.
|
|
||||||
if !offset_open {
|
|
||||||
if i == 1 {
|
|
||||||
calls.push(
|
|
||||||
arguments
|
|
||||||
.format_call(&Ident::new("opcode_separator", arg.target.span()), quote!()),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
calls.push(arguments.format_call(
|
|
||||||
&Ident::new("operand_separator", arg.target.span()),
|
|
||||||
quote!(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Arguments to out.write_x(...);
|
|
||||||
let format_args = arg.sources.iter().map(|src| arguments.ins_call(src));
|
|
||||||
let format_args_punct: Punctuated<TokenStream, syn::token::Comma> =
|
|
||||||
Punctuated::from_iter(format_args);
|
|
||||||
// Create call.
|
|
||||||
if arg.target.to_string().starts_with("offset") {
|
|
||||||
// Offsets are a special case since we need to call close afterwards.
|
|
||||||
if offset_open {
|
|
||||||
return Err(syn::Error::new(
|
|
||||||
arg.target.span(),
|
|
||||||
"two consecutive offset arguments",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
calls.push(arguments.format_call(
|
|
||||||
&Ident::new(&(arg.target.to_string() + "_open"), arg.target.span()),
|
|
||||||
format_args_punct.to_token_stream(),
|
|
||||||
));
|
|
||||||
offset_open = true;
|
|
||||||
} else {
|
|
||||||
calls.push(arguments.format_call(&arg.target, format_args_punct.to_token_stream()));
|
|
||||||
if offset_open {
|
|
||||||
calls.push(
|
|
||||||
arguments.format_call(&Ident::new("offset_close", arg.target.span()), quote!()),
|
|
||||||
);
|
|
||||||
offset_open = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap calls in a block returning Ok(()).
|
|
||||||
calls.push(quote!(std::io::Result::Ok(())));
|
|
||||||
let statements = Punctuated::<TokenStream, syn::token::Semi>::from_iter(calls);
|
|
||||||
let tokens = Group::new(Delimiter::Brace, statements.to_token_stream());
|
|
||||||
|
|
||||||
Ok(tokens.to_token_stream())
|
|
||||||
}
|
|
|
@ -1,13 +1,13 @@
|
||||||
[package]
|
[package]
|
||||||
name = "ppc750cl-rand"
|
name = "ppc750cl-rand"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
authors = ["Richard Patel <me@terorie.dev>"]
|
authors = ["Richard Patel <me@terorie.dev>"]
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
description = "Generate random PowerPC 750CL instructions"
|
description = "Generate random PowerPC 750CL instructions"
|
||||||
repository = "https://github.com/terorie/ppc750cl"
|
repository = "https://github.com/terorie/ppc750cl"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ppc750cl = { path = "../disasm", version = "0.1.1" }
|
ppc750cl = { path = "../disasm", version = "0.2.0" }
|
||||||
rand_core = "0.5"
|
rand_core = "0.6"
|
||||||
sfmt = "0.6"
|
sfmt = "0.7"
|
||||||
|
|
|
@ -1,26 +1,16 @@
|
||||||
use rand_core::{RngCore, SeedableRng};
|
use rand_core::{RngCore, SeedableRng};
|
||||||
use sfmt::SFMT;
|
use sfmt::SFMT;
|
||||||
|
|
||||||
use ppc750cl::formatter::SimpleFormatter;
|
use ppc750cl::formatter::FormattedIns;
|
||||||
use ppc750cl::{Ins, Opcode};
|
use ppc750cl::{Ins, Opcode};
|
||||||
use std::io::{BufWriter, Write};
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut rng = SFMT::seed_from_u64(42);
|
let mut rng = SFMT::seed_from_u64(42);
|
||||||
let stdout = std::io::stdout();
|
|
||||||
let stdout_lock = stdout.lock();
|
|
||||||
let stream = BufWriter::with_capacity(1_000_000, stdout_lock);
|
|
||||||
let mut formatter = SimpleFormatter { writer: stream };
|
|
||||||
loop {
|
loop {
|
||||||
let ins = Ins::new(rng.next_u32(), 0);
|
let ins = Ins::new(rng.next_u32(), 0);
|
||||||
if ins.op == Opcode::Illegal {
|
if ins.op == Opcode::Illegal {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ins.write_string(&mut formatter).is_err() {
|
println!("{}", FormattedIns(ins));
|
||||||
return;
|
|
||||||
}
|
|
||||||
if formatter.writer.write_all("\n".as_ref()).is_err() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue