├── .github
└── FUNDING.yml
├── .gitignore
├── .rustfmt.toml
├── Cargo.lock
├── Cargo.toml
├── LICENSE
├── README.md
├── misc
├── Disassembly1.png
├── Screenshot1.png
├── Spore.png
└── Usage.png
└── src
├── CLI.txt
├── argument.rs
├── bits.rs
├── instruction.rs
├── main.rs
├── natural_index.rs
├── opcode.rs
├── operand.rs
├── options.rs
├── tests
└── mod.rs
└── theme.rs
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [pebaz]
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 |
--------------------------------------------------------------------------------
/.rustfmt.toml:
--------------------------------------------------------------------------------
1 | # https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=
2 |
3 | # indent_style = "Block"
4 | # reorder_imports = false
5 |
6 | use_small_heuristics = "Off"
7 | comment_width = 120
8 | max_width = 120
9 | fn_call_width = 120
10 | attr_fn_like_width = 120
11 | struct_lit_width = 120
12 | struct_variant_width = 120
13 | array_width = 120
14 | chain_width = 120
15 | single_line_if_else_max_width = 120
16 |
17 | reorder_impl_items = true
18 | reorder_imports = true
19 | group_imports = "StdExternalCrate"
20 |
21 | merge_derives = true
22 | indent_style = "Block"
23 | brace_style = "AlwaysNextLine"
24 | control_brace_style = "AlwaysNextLine"
25 | combine_control_expr = false
26 | fn_args_layout = "Tall"
27 | condense_wildcard_suffixes = true
28 | spaces_around_ranges = true
29 | wrap_comments = true
30 | blank_lines_upper_bound = 1
31 | newline_style = "Unix"
32 | overflow_delimited_expr = true
33 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 4
4 |
5 | [[package]]
6 | name = "arrayvec"
7 | version = "0.7.6"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
10 |
11 | [[package]]
12 | name = "colored"
13 | version = "2.1.0"
14 | source = "registry+https://github.com/rust-lang/crates.io-index"
15 | checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
16 | dependencies = [
17 | "lazy_static",
18 | "windows-sys",
19 | ]
20 |
21 | [[package]]
22 | name = "dataview"
23 | version = "0.1.2"
24 | source = "registry+https://github.com/rust-lang/crates.io-index"
25 | checksum = "47a802a2cad0ff4dfc4f3110da174b7a6928c315cae523e88638cfb72941b4d5"
26 | dependencies = [
27 | "derive_pod",
28 | ]
29 |
30 | [[package]]
31 | name = "derive_pod"
32 | version = "0.1.2"
33 | source = "registry+https://github.com/rust-lang/crates.io-index"
34 | checksum = "c2ea6706d74fca54e15f1d40b5cf7fe7f764aaec61352a9fcec58fe27e042fc8"
35 |
36 | [[package]]
37 | name = "lazy_static"
38 | version = "1.5.0"
39 | source = "registry+https://github.com/rust-lang/crates.io-index"
40 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
41 |
42 | [[package]]
43 | name = "libc"
44 | version = "0.2.165"
45 | source = "registry+https://github.com/rust-lang/crates.io-index"
46 | checksum = "fcb4d3d38eab6c5239a362fa8bae48c03baf980a6e7079f063942d563ef3533e"
47 |
48 | [[package]]
49 | name = "no-std-compat"
50 | version = "0.4.1"
51 | source = "registry+https://github.com/rust-lang/crates.io-index"
52 | checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
53 |
54 | [[package]]
55 | name = "pelite"
56 | version = "0.9.2"
57 | source = "registry+https://github.com/rust-lang/crates.io-index"
58 | checksum = "9a821dd5a5c4744099b50dc94a6a381c8b4b007f4d80da5334428e220945319b"
59 | dependencies = [
60 | "dataview",
61 | "libc",
62 | "no-std-compat",
63 | "pelite-macros",
64 | "winapi",
65 | ]
66 |
67 | [[package]]
68 | name = "pelite-macros"
69 | version = "0.1.1"
70 | source = "registry+https://github.com/rust-lang/crates.io-index"
71 | checksum = "7a7cf3f8ecebb0f4895f4892a8be0a0dc81b498f9d56735cb769dc31bf00815b"
72 |
73 | [[package]]
74 | name = "spore-disassembler"
75 | version = "0.1.1"
76 | dependencies = [
77 | "arrayvec",
78 | "colored",
79 | "pelite",
80 | ]
81 |
82 | [[package]]
83 | name = "winapi"
84 | version = "0.3.9"
85 | source = "registry+https://github.com/rust-lang/crates.io-index"
86 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
87 | dependencies = [
88 | "winapi-i686-pc-windows-gnu",
89 | "winapi-x86_64-pc-windows-gnu",
90 | ]
91 |
92 | [[package]]
93 | name = "winapi-i686-pc-windows-gnu"
94 | version = "0.4.0"
95 | source = "registry+https://github.com/rust-lang/crates.io-index"
96 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
97 |
98 | [[package]]
99 | name = "winapi-x86_64-pc-windows-gnu"
100 | version = "0.4.0"
101 | source = "registry+https://github.com/rust-lang/crates.io-index"
102 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
103 |
104 | [[package]]
105 | name = "windows-sys"
106 | version = "0.48.0"
107 | source = "registry+https://github.com/rust-lang/crates.io-index"
108 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
109 | dependencies = [
110 | "windows-targets",
111 | ]
112 |
113 | [[package]]
114 | name = "windows-targets"
115 | version = "0.48.5"
116 | source = "registry+https://github.com/rust-lang/crates.io-index"
117 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
118 | dependencies = [
119 | "windows_aarch64_gnullvm",
120 | "windows_aarch64_msvc",
121 | "windows_i686_gnu",
122 | "windows_i686_msvc",
123 | "windows_x86_64_gnu",
124 | "windows_x86_64_gnullvm",
125 | "windows_x86_64_msvc",
126 | ]
127 |
128 | [[package]]
129 | name = "windows_aarch64_gnullvm"
130 | version = "0.48.5"
131 | source = "registry+https://github.com/rust-lang/crates.io-index"
132 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
133 |
134 | [[package]]
135 | name = "windows_aarch64_msvc"
136 | version = "0.48.5"
137 | source = "registry+https://github.com/rust-lang/crates.io-index"
138 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
139 |
140 | [[package]]
141 | name = "windows_i686_gnu"
142 | version = "0.48.5"
143 | source = "registry+https://github.com/rust-lang/crates.io-index"
144 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
145 |
146 | [[package]]
147 | name = "windows_i686_msvc"
148 | version = "0.48.5"
149 | source = "registry+https://github.com/rust-lang/crates.io-index"
150 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
151 |
152 | [[package]]
153 | name = "windows_x86_64_gnu"
154 | version = "0.48.5"
155 | source = "registry+https://github.com/rust-lang/crates.io-index"
156 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
157 |
158 | [[package]]
159 | name = "windows_x86_64_gnullvm"
160 | version = "0.48.5"
161 | source = "registry+https://github.com/rust-lang/crates.io-index"
162 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
163 |
164 | [[package]]
165 | name = "windows_x86_64_msvc"
166 | version = "0.48.5"
167 | source = "registry+https://github.com/rust-lang/crates.io-index"
168 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
169 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "spore-disassembler"
3 | version = "0.1.1"
4 | description = "UEFI Bytecode Disassembler"
5 | authors = ["https://github.com/Pebaz"]
6 | edition = "2021"
7 | license = "Zlib"
8 | keywords = ["disassembler", "UEFI", "bytecode", "assembly"]
9 | categories = ["compilers"]
10 | repository = "https://github.com/Pebaz/spore"
11 | homepage = "https://github.com/Pebaz/spore"
12 | readme = "README.md"
13 |
14 | [[bin]]
15 | name = "spore"
16 | path = "src/main.rs"
17 |
18 | [dependencies]
19 | colored = "2.0.0"
20 | arrayvec = "0.7.1"
21 | pelite = "0.9.0"
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | zlib License
2 |
3 | (C) Copyright 2021 Samuel Wilder
4 |
5 | This software is provided 'as-is', without any express or implied
6 | warranty. In no event will the authors be held liable for any damages
7 | arising from the use of this software.
8 |
9 | Permission is granted to anyone to use this software for any purpose,
10 | including commercial applications, and to alter it and redistribute it
11 | freely, subject to the following restrictions:
12 |
13 | 1. The origin of this software must not be misrepresented; you must not
14 | claim that you wrote the original software. If you use this software
15 | in a product, an acknowledgment in the product documentation would be
16 | appreciated but is not required.
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 | 3. This notice may not be removed or altered from any source distribution.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spore - UEFI Bytecode Disassembler
2 |
3 |
4 |
5 |
6 |
7 | |
8 |
9 |
10 | |
11 |
12 |
13 |
14 | > 🍄 A disassembler for the UEFI Bytecode Virtual Machine. For details on the
15 | VM, see [section 22 of the UEFI Specification](https://uefi.org/sites/default/files/resources/UEFI_Spec_2_9_2021_03_18.pdf).
16 |
17 | ## Installation
18 |
19 | ```bash
20 | $ cargo install spore-disassembler
21 |
22 | # Or alternatively
23 | $ cargo install --git https://github.com/Pebaz/spore
24 | ```
25 |
26 | ## Demo
27 |
28 | Although Spore will work with any EBC binary, users will most likely benefit
29 | from [fasmg-ebc-rs](https://github.com/Pebaz/fasmg-ebc-rs) which makes it much
30 | simpler to work with the [fasmg-ebc](https://github.com/pbatard/fasmg-ebc)
31 | assembler.
32 |
33 | Given the following fasmg-ebc UEFI Bytecode Assembly file:
34 |
35 | ```x86asm
36 | ;; Adapted from https://github.com/pbatard/fasmg-ebc/blob/master/hello.asm
37 |
38 | include 'ebc.inc'
39 | include 'efi.inc'
40 | include 'format.inc'
41 | include 'utf8.inc'
42 |
43 | format peebc efi ;; PE executable format, EFI Byte Code
44 |
45 | entry efi_main
46 |
47 | section '.text' code executable readable
48 |
49 | efi_main:
50 | MOVn R1, @R0(EFI_MAIN_PARAMETERS.SystemTable)
51 | MOVn R1, @R1(EFI_SYSTEM_TABLE.ConOut)
52 | MOVREL R2, string_hello
53 | PUSHn R2
54 | PUSHn R1
55 | CALLEX @R1(SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString)
56 | MOV R0, R0(+2,0)
57 | JMP efi_main
58 | RET
59 |
60 | section '.data' data readable writeable
61 | string_hello: du "Hello World!", 0x0A, 0x0
62 | ```
63 |
64 | Compile it using [fasmg-ebc-rs](https://github.com/Pebaz/fasmg-ebc-rs) by using
65 | the below command:
66 |
67 | ```bash
68 | $ cargo install fasmg-ebc-rs
69 | $ fasmg-ebc-rs bc.asm bc.efi
70 |
71 | # This is a PE executable that contains UEFI Bytecode
72 | $ file bc.efi
73 | bc.efi: PE32+ executable (DLL) (EFI application) EFI byte code, for MS Windows
74 | ```
75 |
76 | Now that we have a bootable PE executable, we can output the bytecode
77 | instructions inside of it:
78 |
79 | ```bash
80 | $ spore bc.efi
81 | ```
82 |
83 | The disassembled bytecode instructions are then emitted by Spore:
84 |
85 | ```x86asm
86 | 72 81 41 10 MOVnw R1, @R0(+1, +16)
87 | 72 91 85 21 MOVnw R1, @R1(+5, +24)
88 | 79 02 F4 0F MOVRELw R2, 4084
89 | 35 02 PUSHn R2
90 | 35 01 PUSHn R1
91 | 83 29 01 00 00 10 CALL32EXa @R1(+1, +0)
92 | 60 00 02 10 MOVqw R0, R0(+2, +0)
93 | 02 F2 JMP8 -14
94 | 04 RET
95 | ```
96 |
97 | ## Usage
98 |
99 |
100 |
101 |
102 |
103 | ## Why
104 |
105 | I am learning about making operating systems because I think it is fun. It is
106 | actually quite difficult, but the rewards are pretty satisfying.
107 |
108 | While learning about operating systems, I discovered the Unified Extensible
109 | Firmware Interface (UEFI). It's basically a set of C ABI interfaces that allow
110 | you to write pre-OS recovery software, OS installers, or boot managers.
111 |
112 | The UEFI Virtual Machine is literally preinstalled by default on most modern
113 | motherboards. Most of the time, you write applications that adhere to the UEFI
114 | API in C, and then you can boot into them directly. Astoundingly, you can also
115 | boot right into applications written with UEFI Bytecode (EBC)!
116 |
117 | The reason this is astonishing is that EBC is cross-platform, so it
118 | is truly like Java Bytecode in that regard.
119 |
120 | Even more surprising is that EBC has access to the same Boot &
121 | Runtime Services that normal UEFI applications have. *This means you can write
122 | a bootloader using EBC.*
123 |
124 | After I discovered this I set out to learn UEFI Bytecode, but didn't find very
125 | much on it. Thankfully, [Pete Batard](https://github.com/pbatard) built
126 | [FASMG-EBC](https://github.com/pbatard/fasmg-ebc), an assembler for EBC.
127 |
128 | I wanted to better understand the output of the assembler and to do that, I
129 | would need to work with it more. That's when I decided to build Spore. 😄
130 |
131 | ## How did I do it?
132 |
133 | I started out by perusing the [UEFI Specification](https://uefi.org/sites/default/files/resources/UEFI_Spec_2_9_2021_03_18.pdf)
134 | very carefully and found that all of the information I would need was contained
135 | in section 22. From there, I decided to use Rust to build the disassembler
136 | since it is my current favorite language for many reasons.
137 |
138 | I then created a Python script that would generate some specific bytecode
139 | sequences without having to deal with the PE file format. This was one of the
140 | most important steps in the entire project because I learned how to interpret
141 | the binary structure of a few of the instructions.
142 |
143 | Once I had some bytes to work with, I wrote some Rust code that would open the
144 | file and iterate through the bytes. Amazingly enough, the entire application
145 | runs by passing a single iterator to all the functions that parse out
146 | instructions! All the parsing functions just advance the iterator and return
147 | any errors.
148 |
149 | This really made the whole process easier because all I had to do was look at
150 | the first byte to determine the opcode of the instruction and route it to the
151 | appropriate parser function. Since many instructions have varying lengths of
152 | bytes, the iterator approach worked amazingly well.
153 |
154 | After I had written a fair bit, I noticed that many of the instructions were
155 | using the exact same parsing routines. I also noticed that I was implementing 1
156 | instruction at a time and there were 55 total instructions so this was not
157 | going to work well. I then had to step back and see what could be reused and
158 | what had to be kept. I then read through all 55 instructions in the
159 | specification and grouped each instruction type by how it was parsed. Once that
160 | was done, I just had to write 1 parsing function per type (total of 7)!
161 |
162 | At this point, I knew what I was getting myself into and determined that I
163 | needed to have some better unit testing to ensure I was not messing anything up
164 | during refactoring. I had been incrementally adding to the Python script to
165 | output each and every instruction as well as every combination of arguments but
166 | I knew that I would need to somehow verify that I was not breaking anything.
167 |
168 | The bytecode generator script looked like this:
169 |
170 | ```python
171 | bc = open('bc.bin')
172 |
173 | bc.write(0b00101010_00000001.to_bytes(2, 'big')) # $ STORESP R1, FLAGS
174 |
175 | # The rest of the instructions ...
176 | # This totaled 1162 lines of code
177 | ```
178 |
179 | I wrote another Python script that would scrape out all of the assembly
180 | instructions from the bytecode generation script and write them to a file.
181 |
182 | It worked by looking for all the comments that contained the dollar sign `$`
183 | and writing them to a file. The result looked like this:
184 |
185 | ```x86asm
186 | STORESP R1, FLAGS
187 |
188 | ;; The rest of the instructions
189 | ```
190 |
191 | Now that I had what I expected to come out of the disassembler, I could simply
192 | compare the output with this file to determine if I had any regressions!
193 |
194 | Once I had this, I could implement the rest of the instruction parsers and
195 | modify the existing ones at will and be sure that nothing would break.
196 |
197 | Implementing the rest of the parsers took a while, but once I was done, I
198 | needed to convert the Python test scripts to Rust unit tests.
199 |
200 | Again, I started by converting them one at a time by hand, but this soon became
201 | slightly ridiculous.
202 |
203 | I wrote another Python script that parsed the `bc.write(...)` directives from
204 | the bytecode generator script and converted them to Rust unit tests. This was
205 | immensely satisfying! 🙃
206 |
207 | Once I had working Rust unit tests, I went on to polish the CLI and fix bits
208 | and bobs of miscellaneous todo items. The rest is what you see in this README!
209 |
210 |
211 |
212 | **All in all, the project took me 20 days to complete.**
213 |
214 | Some things that I noticed while working on Spore:
215 |
216 | * Python was absolutely essential for rapid prototyping. I will continue to
217 | remember how well Rust + Python pair together for future projects. I used
218 | Python for:
219 | * Generating bytecode
220 | * Verifying disassembler output
221 | * Converting Python tests to Rust unit tests
222 | * Rust was amazing to use because it did not force me to think about
223 | structuring my code. It was just functions + structs + 1 trait 😛
224 | * One other thing that was amazing was that after I got the code to
225 | compile, very rarely was it incorrect. Rust's compiler is world-class. It
226 | also made refactoring fearless because I knew it would catch all the
227 | things.
228 | * The Rust ecosystem is amazing. I needed a PE file loader, so I used the
229 | [pelite](https://github.com/CasualX/pelite) crate, and it was a breeze.
230 | * The [colored](https://github.com/mackwic/colored) crate made outputting
231 | colored text very fun!
232 | * Rust doesn't have a Vec-like data structure that is allocated on the stack. I
233 | know this might be a strange requirement, but I don't like allocating
234 | everything on the heap all the time. The [arrayvec](https://github.com/bluss/arrayvec)
235 | crate allowed me to have a fixed-size buffer that had a Vec-like interface.
236 | * I used `include_str!()` for the CLI usage information and this was oddly
237 | satisfying! 😆
238 | * Strings. Let's talk about strings. I mean, why can't I stack allocate them
239 | very easily? I essentially want like a stack-allocated string builder to
240 | allow me to not make even a single allocation but implementing this would
241 | have taken forever. 😕
242 |
243 | ## Stargazers over time
244 |
245 | [](https://starchart.cc/Pebaz/Spore)
246 |
247 | ## Notes
248 |
249 | * 🍄 Spore is named after mushroom spores.
250 | * 👏 Thank you to [Pete Batard](https://github.com/pbatard) for creating
251 | [FASMG-EBC](https://github.com/pbatard/fasmg-ebc) which is based on the Flat
252 | Assembler. Without this tool, I would not have had the assembly files to
253 | disassemble!
254 | * 🤯 The [UEFI Specification](https://uefi.org/sites/default/files/resources/UEFI_Spec_2_9_2021_03_18.pdf)
255 | is exceptionally well-written and contained all the information necessary to
256 | implement Spore.
257 | * 🤷♂️ Although Spore is cross-platform (Windows, MacOS, Linux), I have not tested
258 | whether FASMG-EBC works on other platforms.
259 |
--------------------------------------------------------------------------------
/misc/Disassembly1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pebaz/spore/e5060714f216672ffd7f98d53d3a889c0e2ed50c/misc/Disassembly1.png
--------------------------------------------------------------------------------
/misc/Screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pebaz/spore/e5060714f216672ffd7f98d53d3a889c0e2ed50c/misc/Screenshot1.png
--------------------------------------------------------------------------------
/misc/Spore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pebaz/spore/e5060714f216672ffd7f98d53d3a889c0e2ed50c/misc/Spore.png
--------------------------------------------------------------------------------
/misc/Usage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pebaz/spore/e5060714f216672ffd7f98d53d3a889c0e2ed50c/misc/Usage.png
--------------------------------------------------------------------------------
/src/CLI.txt:
--------------------------------------------------------------------------------
1 | Spore - Disassembler for UEFI Bytecode
2 |
3 | Usage:
4 | $ spore [OPTIONS]
5 |
6 | OPTIONS (default is first item in list):
7 | theme: [SPORE | INDUSTRIAL_COMPUTER | MATTERHORN_ZERMATT_VILLAGE | OFF]
8 | Color theme to output assembly in
9 |
10 | bytecode: [ON | OFF]
11 | Determines whether to also print out bytecode alongside assembly
12 |
13 | pe: [ON | OFF]
14 | ON = Windows PE file, OFF = binary file containing only UEFI Bytecode
15 |
16 | EXAMPLES:
17 | $ spore bytecode-file.efi
18 | $ spore bytecode: OFF bytecode-file.efi
19 | $ spore bytecode: OFF bytecode-file.efi
20 | $ spore theme: SPORE bytecode-file.efi
21 | $ spore bytecode: ON theme: SPORE bytecode-file.efi
22 | $ spore bytecode: ON theme: SPORE bytecode-file.efi
23 | $ spore pe: ON bytecode-file.efi
24 | $ spore pe: OFF bytecode-file.bin
25 | $ spore pe: OFF theme: SPORE bytecode-file.bin
26 |
--------------------------------------------------------------------------------
/src/argument.rs:
--------------------------------------------------------------------------------
1 | use crate::natural_index::NaturalIndex;
2 | use crate::options::Options;
3 | use crate::theme::*;
4 |
5 | pub enum Argument
6 | {
7 | Index16(u16),
8 | Index32(u32),
9 | Index64(u64),
10 | ImmediateU16(u16),
11 | ImmediateU32(u32),
12 | ImmediateI16(i16),
13 | ImmediateI32(i32),
14 | ImmediateI64(i64),
15 | }
16 |
17 | impl Emit for Argument
18 | {
19 | fn emit(&self, options: &Options) -> String
20 | {
21 | match self
22 | {
23 | Self::Index16(index) =>
24 | {
25 | let natural_index = NaturalIndex::from_u16(*index);
26 |
27 | format!("{}", natural_index.emit(options))
28 | }
29 |
30 | Self::Index32(index) =>
31 | {
32 | let natural_index = NaturalIndex::from_u32(*index);
33 |
34 | format!("{}", natural_index.emit(options))
35 | }
36 |
37 | Self::Index64(index) =>
38 | {
39 | let natural_index = NaturalIndex::from_u64(*index);
40 |
41 | format!("{}", natural_index.emit(options))
42 | }
43 |
44 | Self::ImmediateU16(immediate) => color_immediate(immediate.to_string(), options),
45 |
46 | Self::ImmediateU32(immediate) => color_immediate(immediate.to_string(), options),
47 |
48 | Self::ImmediateI16(immediate) => color_immediate(immediate.to_string(), options),
49 |
50 | Self::ImmediateI32(immediate) => color_immediate(immediate.to_string(), options),
51 |
52 | Self::ImmediateI64(immediate) => color_immediate(immediate.to_string(), options),
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/bits.rs:
--------------------------------------------------------------------------------
1 | pub fn bits_u16(byte: u16) -> [bool; 16]
2 | {
3 | let mut bits = [false; 16];
4 |
5 | for i in 0 .. 16
6 | {
7 | if byte & 2u16.pow(i) > 0
8 | {
9 | bits[(bits.len() - 1) - i as usize] = true;
10 | }
11 | }
12 |
13 | bits
14 | }
15 |
16 | pub fn bits_to_byte_u16(bits: &[bool]) -> u16
17 | {
18 | let mut byte = 0;
19 |
20 | for (i, bit) in bits.iter().rev().enumerate()
21 | {
22 | if *bit
23 | {
24 | byte += 2u16.pow((i) as u32);
25 | }
26 | }
27 | byte
28 | }
29 |
30 | pub fn bits_u32(byte: u32) -> [bool; 32]
31 | {
32 | let mut bits = [false; 32];
33 |
34 | for i in 0 .. 32
35 | {
36 | if byte & 2u32.pow(i) > 0
37 | {
38 | bits[(bits.len() - 1) - i as usize] = true;
39 | }
40 | }
41 |
42 | bits
43 | }
44 |
45 | pub fn bits_to_byte_u32(bits: &[bool]) -> u32
46 | {
47 | let mut byte = 0;
48 |
49 | for (i, bit) in bits.iter().rev().enumerate()
50 | {
51 | if *bit
52 | {
53 | byte += 2u32.pow((i) as u32);
54 | }
55 | }
56 | byte
57 | }
58 |
59 | pub fn bits_u64(byte: u64) -> [bool; 64]
60 | {
61 | let mut bits = [false; 64];
62 |
63 | for i in 0 .. 64
64 | {
65 | if byte & 2u64.pow(i) > 0
66 | {
67 | bits[(bits.len() - 1) - i as usize] = true;
68 | }
69 | }
70 |
71 | bits
72 | }
73 |
74 | pub fn bits_to_byte_u64(bits: &[bool]) -> u64
75 | {
76 | let mut byte = 0;
77 |
78 | for (i, bit) in bits.iter().rev().enumerate()
79 | {
80 | if *bit
81 | {
82 | byte += 2u64.pow((i) as u32);
83 | }
84 | }
85 | byte
86 | }
87 |
88 | /// Returns the bits of a byte in reverse so that indexing works as expected.
89 | pub fn bits_rev(byte: u8) -> [bool; 8]
90 | {
91 | let mut bits = [false; 8];
92 |
93 | for i in 0 .. 8
94 | {
95 | if byte & 2u8.pow(i) > 0
96 | {
97 | bits[i as usize] = true;
98 | }
99 | }
100 |
101 | bits
102 | }
103 |
104 | /// Converts a slice of bits sorted in reverse to a byte.
105 | pub fn bits_to_byte_rev(bits: &[bool]) -> u8
106 | {
107 | let mut byte = 0;
108 |
109 | for (i, bit) in bits.iter().enumerate()
110 | {
111 | if *bit
112 | {
113 | byte += 2u8.pow((i) as u32);
114 | }
115 | }
116 | byte
117 | }
118 |
119 | #[cfg(test)]
120 | mod tests
121 | {
122 | use super::*;
123 |
124 | #[test]
125 | pub fn test_bits_to_byte()
126 | {
127 | assert_eq!(bits_to_byte_u32(&[true, false]), 2u32);
128 | assert_eq!(bits_to_byte_u32(&[false, true, false]), 2u32);
129 | assert_eq!(bits_to_byte_u32(&[true, false, false]), 4u32);
130 | assert_eq!(bits_to_byte_u32(&[true, false, false, false]), 8u32);
131 | assert_eq!(bits_to_byte_u32(&[true, false, false, true]), 9u32);
132 | assert_eq!(bits_to_byte_u32(&[true, false, true, true]), 11u32);
133 |
134 | assert_eq!(bits_to_byte_u64(&[true, false]), 2u64);
135 | assert_eq!(bits_to_byte_u64(&[false, true, false]), 2u64);
136 | assert_eq!(bits_to_byte_u64(&[true, false, false]), 4u64);
137 | assert_eq!(bits_to_byte_u64(&[true, false, false, false]), 8u64);
138 | assert_eq!(bits_to_byte_u64(&[true, false, false, true]), 9u64);
139 | assert_eq!(bits_to_byte_u64(&[true, false, true, true]), 11u64);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/instruction.rs:
--------------------------------------------------------------------------------
1 | /*
2 | Instruction Type Breakdown:
3 |
4 | 7. ✅ INSTRUCTION OP1 ARGUMENT, OP2 ARGUMENT
5 | MOVnw
6 | MOVnd
7 | MOVbw
8 | MOVww
9 | MOVdw
10 | MOVqw
11 | MOVbd
12 | MOVwd
13 | MOVdd
14 | MOVqd
15 | MOVqq
16 | MOVsnw
17 | MOVsnd
18 |
19 | 6. ✅ INSTRUCTION OP1, OP2 ARGUMENT (16 bit optional index/immediate)
20 | ADD
21 | AND
22 | ASHR
23 | CMP
24 | DIV
25 | DIVU
26 | EXTENDB
27 | EXTENDD
28 | EXTENDW
29 | MOD
30 | MODU
31 | MUL
32 | MULU
33 | NEG
34 | NOT
35 | OR
36 | SHL
37 | SHR
38 | SUB
39 | XOR
40 |
41 | 5. ✅ INSTRUCTION OP1 ARGUMENT, ARGUMENT
42 | CMPI
43 | MOVI
44 | MOVIn
45 | MOVREL
46 |
47 | 4. ✅ INSTRUCTION OP1, OP2
48 | STORESP
49 | LOADSP
50 |
51 | 3. ✅ INSTRUCTION OP1 ARGUMENT
52 | CALL32
53 | JMP32
54 | PUSH
55 | PUSHn
56 | POP
57 | POPn
58 | JMP64
59 | CALL64
60 |
61 | 2. ✅ INSTRUCTION ARGUMENT
62 | JMP8
63 | BREAK
64 | JMP64
65 | CALL64
66 |
67 | 1. ✅ INSTRUCTION
68 | RET
69 | */
70 |
71 | use arrayvec::ArrayVec;
72 |
73 | use crate::argument::*;
74 | use crate::bits::*;
75 | use crate::opcode::*;
76 | use crate::operand::*;
77 | use crate::options::Options;
78 | use crate::theme::*;
79 |
80 | fn read_value, const WIDTH: usize>(bytes: &mut T) -> Result<[u8; WIDTH], String>
81 | {
82 | let mut value = [0u8; WIDTH];
83 |
84 | for i in 0 .. value.len()
85 | {
86 | value[i] = bytes.next().ok_or("Unexpected end of byte stream")?;
87 | }
88 |
89 | Ok(value)
90 | }
91 |
92 | pub fn parse_instruction1>(
93 | writer: &mut W,
94 | options: &Options,
95 | _bytes: &mut T,
96 | byte0: u8,
97 | _byte0_bits: [bool; 8],
98 | op: OpCode,
99 | ) -> Result<(), String>
100 | {
101 | let bytecode = [byte0];
102 | disassemble_instruction(writer, options, &bytecode, op.emit(options), None, None, None, None, None);
103 |
104 | Ok(())
105 | }
106 |
107 | pub fn parse_instruction2>(
108 | writer: &mut W,
109 | options: &Options,
110 | bytes: &mut T,
111 | byte0: u8,
112 | byte0_bits: [bool; 8],
113 | op: OpCode,
114 | ) -> Result<(), String>
115 | {
116 | let mut name = op.emit(options);
117 |
118 | let byte1 = bytes.next().ok_or("Unexpected end of bytes")?;
119 |
120 | let arg1 = match op
121 | {
122 | OpCode::BREAK =>
123 | {
124 | if byte1 == 0
125 | {
126 | let msg = String::from("Runaway program break (found 2 zeros in a row, BREAK 0)");
127 |
128 | return Err(color_error(msg, options));
129 | }
130 |
131 | Argument::ImmediateU16(byte1 as u16)
132 | }
133 |
134 | OpCode::JMP8 =>
135 | {
136 | let conditional = byte0_bits[7];
137 |
138 | if conditional
139 | {
140 | let condition_bit_set = byte0_bits[6];
141 | let postfix = if condition_bit_set
142 | {
143 | color_opcode(String::from("cs"), options)
144 | }
145 | else
146 | {
147 | color_opcode(String::from("cc"), options)
148 | };
149 |
150 | name += &postfix;
151 | }
152 |
153 | Argument::ImmediateI16((byte1 as i8) as i16)
154 | }
155 |
156 | _ => unreachable!(),
157 | };
158 |
159 | let bytecode = [byte0, byte1];
160 | disassemble_instruction(writer, options, &bytecode, name, None, Some(arg1), None, None, None);
161 |
162 | Ok(())
163 | }
164 |
165 | pub fn parse_instruction3>(
166 | writer: &mut W,
167 | options: &Options,
168 | bytes: &mut T,
169 | byte0: u8,
170 | byte0_bits: [bool; 8],
171 | op: OpCode,
172 | ) -> Result<(), String>
173 | {
174 | let mut name = op.emit(options);
175 | let mut postfix = String::with_capacity(5);
176 | let immediate_data_present = byte0_bits[7];
177 | let is_64_bit = byte0_bits[6]; // Not used by PUSHn & POPn
178 |
179 | let byte1 = bytes.next().ok_or("Unexpected end of bytes")?;
180 | let byte1_bits = bits_rev(byte1);
181 |
182 | let mut bytecode = ArrayVec::<_, 18>::new();
183 | bytecode.push(byte0);
184 | bytecode.push(byte1);
185 |
186 | match op
187 | {
188 | OpCode::CALL | OpCode::JMP | OpCode::PUSH | OpCode::POP =>
189 | {
190 | let width_postfix =
191 | if is_64_bit { color_x64(String::from("64"), options) } else { color_x32(String::from("32"), options) };
192 |
193 | postfix += &width_postfix;
194 | }
195 |
196 | _ => (),
197 | }
198 |
199 | let (op1, arg1, op2, arg2, comment) = match op
200 | {
201 | OpCode::CALL =>
202 | {
203 | let is_native_call = byte1_bits[5];
204 | postfix += if is_native_call { "EX" } else { "" };
205 |
206 | let is_relative_address = byte1_bits[4];
207 | let operand1_is_indirect = byte1_bits[3];
208 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]);
209 | let op1 = if !is_64_bit
210 | {
211 | Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect))
212 | }
213 | else
214 | {
215 | None
216 | };
217 |
218 | let arg1 = if is_64_bit
219 | {
220 | postfix += "a"; // CALL64 is always an absolute address
221 |
222 | let value = read_value::(bytes)?;
223 | bytecode.extend(value.iter().cloned());
224 |
225 | Some(Argument::ImmediateI64(i64::from_le_bytes(value)))
226 | }
227 | else
228 | {
229 | postfix += if is_relative_address { "" } else { "a" };
230 |
231 | let arg = if immediate_data_present
232 | {
233 | let value = read_value::(bytes)?;
234 |
235 | bytecode.extend(value.iter().cloned());
236 |
237 | if operand1_is_indirect
238 | {
239 | Some(Argument::Index32(u32::from_le_bytes(value)))
240 | }
241 | else
242 | {
243 | Some(Argument::ImmediateI32(i32::from_le_bytes(value)))
244 | }
245 | }
246 | else
247 | {
248 | None
249 | };
250 |
251 | arg
252 | };
253 |
254 | (op1, arg1, None, None, None)
255 | }
256 |
257 | OpCode::JMP =>
258 | {
259 | let conditional_jump = byte1_bits[7];
260 | let jump_if_condition_bit_set = byte1_bits[6];
261 |
262 | if conditional_jump
263 | {
264 | postfix += if jump_if_condition_bit_set { "cs" } else { "cc" };
265 | }
266 |
267 | let relative_address = byte1_bits[4];
268 | let operand1_is_indirect = byte1_bits[3];
269 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]);
270 | let op1 = if !is_64_bit
271 | {
272 | Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect))
273 | }
274 | else
275 | {
276 | None
277 | };
278 |
279 | let arg1 = if is_64_bit
280 | {
281 | let value = read_value::(bytes)?;
282 | bytecode.extend(value.iter().cloned());
283 |
284 | Some(Argument::ImmediateI64(i64::from_le_bytes(value)))
285 | }
286 | else
287 | {
288 | let arg = if immediate_data_present
289 | {
290 | let value = read_value::(bytes)?;
291 | bytecode.extend(value.iter().cloned());
292 |
293 | if operand1_is_indirect
294 | {
295 | Some(Argument::Index32(u32::from_le_bytes(value)))
296 | }
297 | else
298 | {
299 | Some(Argument::ImmediateI32(i32::from_le_bytes(value)))
300 | }
301 | }
302 | else
303 | {
304 | None
305 | };
306 |
307 | arg
308 | };
309 |
310 | let comment = if relative_address
311 | {
312 | Some(String::from("Relative Address"))
313 | }
314 | else
315 | {
316 | Some(String::from("Absolute Address"))
317 | };
318 |
319 | (op1, arg1, None, None, comment)
320 | }
321 |
322 | OpCode::PUSH | OpCode::POP | OpCode::PUSHn | OpCode::POPn =>
323 | {
324 | let operand1_is_indirect = byte1_bits[3];
325 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]);
326 | let arg1 = if immediate_data_present
327 | {
328 | let value = read_value::(bytes)?;
329 | bytecode.extend(value.iter().cloned());
330 |
331 | let arg = if operand1_is_indirect
332 | {
333 | Argument::Index16(u16::from_le_bytes(value))
334 | }
335 | else
336 | {
337 | Argument::ImmediateI16(i16::from_le_bytes(value))
338 | };
339 |
340 | Some(arg)
341 | }
342 | else
343 | {
344 | None
345 | };
346 |
347 | (Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect)), arg1, None, None, None)
348 | }
349 |
350 | _ => unreachable!(),
351 | };
352 |
353 | name += &postfix;
354 |
355 | disassemble_instruction(writer, options, &bytecode, name, op1, arg1, op2, arg2, comment);
356 |
357 | Ok(())
358 | }
359 |
360 | pub fn parse_instruction4>(
361 | writer: &mut W,
362 | options: &Options,
363 | bytes: &mut T,
364 | byte0: u8,
365 | _byte0_bits: [bool; 8],
366 | op: OpCode,
367 | ) -> Result<(), String>
368 | {
369 | let name = op.emit(options);
370 |
371 | let byte1 = bytes.next().ok_or("Unexpected end of bytes")?;
372 | let byte1_bits = bits_rev(byte1);
373 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]);
374 | let operand2_value = bits_to_byte_rev(&byte1_bits[4 ..= 6]);
375 |
376 | let mut bytecode = ArrayVec::<_, 18>::new();
377 | bytecode.push(byte0);
378 | bytecode.push(byte1);
379 |
380 | let (op1, op2) = match op
381 | {
382 | OpCode::STORESP =>
383 | {
384 | (Operand::new_general_purpose(operand1_value, false), Operand::new_dedicated(operand2_value, false))
385 | }
386 |
387 | OpCode::LOADSP =>
388 | {
389 | (Operand::new_dedicated(operand1_value, false), Operand::new_general_purpose(operand2_value, false))
390 | }
391 |
392 | _ => unreachable!(),
393 | };
394 |
395 | disassemble_instruction(writer, options, &bytecode, name, Some(op1), None, Some(op2), None, None);
396 |
397 | Ok(())
398 | }
399 |
400 | pub fn parse_instruction5>(
401 | writer: &mut W,
402 | options: &Options,
403 | bytes: &mut T,
404 | byte0: u8,
405 | byte0_bits: [bool; 8],
406 | op: OpCode,
407 | ) -> Result<(), String>
408 | {
409 | let mut name = op.emit(options);
410 | let mut postfixes = String::with_capacity(7);
411 | let byte1 = bytes.next().ok_or("Unexpected end of byte stream")?;
412 | let byte1_bits = bits_rev(byte1);
413 |
414 | let mut bytecode = ArrayVec::<_, 18>::new();
415 | bytecode.push(byte0);
416 | bytecode.push(byte1);
417 |
418 | let (op1, arg1, arg2) = match op
419 | {
420 | OpCode::MOVI =>
421 | {
422 | let move_width = bits_to_byte_rev(&byte1_bits[4 ..= 5]);
423 | let postfix = match move_width
424 | {
425 | 0 => color_x8(String::from("b"), options),
426 | 1 => color_x16(String::from("w"), options),
427 | 2 => color_x32(String::from("d"), options),
428 | 3 => color_x64(String::from("q"), options),
429 | _ => unreachable!(),
430 | };
431 |
432 | postfixes += &postfix;
433 |
434 | let immediate_data_width = bits_to_byte_rev(&byte0_bits[6 ..= 7]);
435 | let postfix = match immediate_data_width
436 | {
437 | 1 => color_x16(String::from("w"), options),
438 | 2 => color_x32(String::from("d"), options),
439 | 3 => color_x64(String::from("q"), options),
440 | _ => unreachable!(),
441 | };
442 |
443 | postfixes += &postfix;
444 |
445 | let operand1_index_present = byte1_bits[6];
446 | let operand1_is_indirect = byte1_bits[3];
447 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]);
448 |
449 | let op1 = Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect));
450 |
451 | let arg1 = if operand1_index_present
452 | {
453 | let value = read_value::(bytes)?;
454 | bytecode.extend(value.iter().cloned());
455 |
456 | let arg = if operand1_is_indirect
457 | {
458 | Argument::Index16(u16::from_le_bytes(value))
459 | }
460 | else
461 | {
462 | let msg = format!("Immediate data not supported for {}", op.emit(options));
463 |
464 | return Err(color_error(msg, options));
465 | };
466 |
467 | Some(arg)
468 | }
469 | else
470 | {
471 | None
472 | };
473 |
474 | let arg2 = {
475 | match immediate_data_width
476 | {
477 | 1 =>
478 | // 16 bit
479 | {
480 | let value = read_value::(bytes)?;
481 | bytecode.extend(value.iter().cloned());
482 |
483 | Some(Argument::ImmediateI16(i16::from_le_bytes(value)))
484 | }
485 |
486 | 2 =>
487 | // 32 bit
488 | {
489 | let value = read_value::(bytes)?;
490 | bytecode.extend(value.iter().cloned());
491 |
492 | Some(Argument::ImmediateI32(i32::from_le_bytes(value)))
493 | }
494 |
495 | 3 =>
496 | // 64 bit
497 | {
498 | let value = read_value::(bytes)?;
499 | bytecode.extend(value.iter().cloned());
500 |
501 | Some(Argument::ImmediateI64(i64::from_le_bytes(value)))
502 | }
503 |
504 | _ => unreachable!(),
505 | }
506 | };
507 |
508 | name += &postfixes;
509 |
510 | (op1, arg1, arg2)
511 | }
512 |
513 | OpCode::CMPIeq | OpCode::CMPIlte | OpCode::CMPIgte | OpCode::CMPIulte | OpCode::CMPIugte =>
514 | {
515 | let immediate_data_is_32_bit = byte0_bits[7];
516 | let comparison_is_64_bit = byte0_bits[6];
517 |
518 | // Have to obliterate name due to the reordering below:
519 | name = color_opcode(String::from("CMPI"), options);
520 |
521 | let postfix = if comparison_is_64_bit
522 | {
523 | color_x64(String::from("64"), options)
524 | }
525 | else
526 | {
527 | color_x32(String::from("32"), options)
528 | };
529 |
530 | name += &postfix;
531 |
532 | let postfix = if immediate_data_is_32_bit
533 | {
534 | color_x32(String::from("d"), options)
535 | }
536 | else
537 | {
538 | color_x16(String::from("w"), options)
539 | };
540 |
541 | name += &postfix;
542 |
543 | let postfix = match op
544 | {
545 | OpCode::CMPIeq => color_opcode(String::from("eq"), options),
546 | OpCode::CMPIlte => color_opcode(String::from("lte"), options),
547 | OpCode::CMPIgte => color_opcode(String::from("gte"), options),
548 | OpCode::CMPIulte => color_opcode(String::from("ulte"), options),
549 |
550 | OpCode::CMPIugte => color_opcode(String::from("ugte"), options),
551 |
552 | _ => unreachable!(),
553 | };
554 |
555 | name += &postfix;
556 |
557 | let operand1_index_present = byte1_bits[4];
558 | let operand1_is_indirect = byte1_bits[3];
559 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]);
560 |
561 | let op1 = Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect));
562 |
563 | let arg1 = if operand1_index_present
564 | {
565 | let value = read_value::(bytes)?;
566 | bytecode.extend(value.iter().cloned());
567 |
568 | let arg = if operand1_is_indirect
569 | {
570 | Argument::Index16(u16::from_le_bytes(value))
571 | }
572 | else
573 | {
574 | let msg = format!("Immediate data not supported for {}", op.emit(options));
575 |
576 | return Err(color_error(msg, options));
577 | };
578 |
579 | Some(arg)
580 | }
581 | else
582 | {
583 | None
584 | };
585 |
586 | let arg2 = {
587 | if immediate_data_is_32_bit
588 | {
589 | let value = read_value::(bytes)?;
590 | bytecode.extend(value.iter().cloned());
591 |
592 | match op
593 | {
594 | OpCode::CMPIulte | OpCode::CMPIugte => Some(Argument::ImmediateU32(u32::from_le_bytes(value))),
595 |
596 | _ => Some(Argument::ImmediateI32(i32::from_le_bytes(value))),
597 | }
598 | }
599 | else
600 | {
601 | let value = read_value::(bytes)?;
602 | bytecode.extend(value.iter().cloned());
603 |
604 | match op
605 | {
606 | OpCode::CMPIulte | OpCode::CMPIugte => Some(Argument::ImmediateU16(u16::from_le_bytes(value))),
607 |
608 | _ => Some(Argument::ImmediateI16(i16::from_le_bytes(value))),
609 | }
610 | }
611 | };
612 |
613 | (op1, arg1, arg2)
614 | }
615 |
616 | OpCode::MOVIn =>
617 | {
618 | let operand2_index_width = bits_to_byte_rev(&byte0_bits[6 ..= 7]);
619 | let postfix = match operand2_index_width
620 | {
621 | 1 => color_x16(String::from("w"), options),
622 | 2 => color_x32(String::from("d"), options),
623 | 3 => color_x64(String::from("q"), options),
624 | _ => unreachable!(),
625 | };
626 |
627 | postfixes += &postfix;
628 |
629 | let operand1_index_present = byte1_bits[6];
630 | let operand1_is_indirect = byte1_bits[3];
631 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]);
632 |
633 | let op1 = Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect));
634 |
635 | let arg1 = if operand1_index_present
636 | {
637 | let value = read_value::(bytes)?;
638 | bytecode.extend(value.iter().cloned());
639 |
640 | let arg = if operand1_is_indirect
641 | {
642 | Argument::Index16(u16::from_le_bytes(value))
643 | }
644 | else
645 | {
646 | let msg = format!("Immediate data not supported for {}", op.emit(options));
647 |
648 | return Err(color_error(msg, options));
649 | };
650 |
651 | Some(arg)
652 | }
653 | else
654 | {
655 | None
656 | };
657 |
658 | let arg2 = {
659 | match operand2_index_width
660 | {
661 | 1 =>
662 | // 16 bit
663 | {
664 | let value = read_value::(bytes)?;
665 | bytecode.extend(value.iter().cloned());
666 |
667 | Some(Argument::Index16(u16::from_le_bytes(value)))
668 | }
669 |
670 | 2 =>
671 | // 32 bit
672 | {
673 | let value = read_value::(bytes)?;
674 | bytecode.extend(value.iter().cloned());
675 |
676 | Some(Argument::Index32(u32::from_le_bytes(value)))
677 | }
678 |
679 | 3 =>
680 | // 64 bit
681 | {
682 | let value = read_value::(bytes)?;
683 | bytecode.extend(value.iter().cloned());
684 |
685 | Some(Argument::Index64(u64::from_le_bytes(value)))
686 | }
687 |
688 | _ => unreachable!(),
689 | }
690 | };
691 |
692 | name += &postfixes;
693 |
694 | (op1, arg1, arg2)
695 | }
696 |
697 | OpCode::MOVREL =>
698 | {
699 | let immediate_data_width = bits_to_byte_rev(&byte0_bits[6 ..= 7]);
700 | let postfix = match immediate_data_width
701 | {
702 | 1 => color_x16(String::from("w"), options),
703 | 2 => color_x32(String::from("d"), options),
704 | 3 => color_x64(String::from("q"), options),
705 | _ => unreachable!(),
706 | };
707 |
708 | postfixes += &postfix;
709 |
710 | let operand1_index_present = byte1_bits[6];
711 | let operand1_is_indirect = byte1_bits[3];
712 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]);
713 |
714 | let op1 = Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect));
715 |
716 | let arg1 = if operand1_index_present
717 | {
718 | let value = read_value::(bytes)?;
719 | bytecode.extend(value.iter().cloned());
720 |
721 | let arg = if operand1_is_indirect
722 | {
723 | Argument::Index16(u16::from_le_bytes(value))
724 | }
725 | else
726 | {
727 | let msg = format!("Immediate data not supported for {}", op.emit(options));
728 |
729 | return Err(color_error(msg, options));
730 | };
731 |
732 | Some(arg)
733 | }
734 | else
735 | {
736 | None
737 | };
738 |
739 | let arg2 = {
740 | match immediate_data_width
741 | {
742 | 1 =>
743 | // 16 bit
744 | {
745 | let value = read_value::(bytes)?;
746 | bytecode.extend(value.iter().cloned());
747 |
748 | Some(Argument::ImmediateI16(i16::from_le_bytes(value)))
749 | }
750 |
751 | 2 =>
752 | // 32 bit
753 | {
754 | let value = read_value::(bytes)?;
755 | bytecode.extend(value.iter().cloned());
756 |
757 | Some(Argument::ImmediateI32(i32::from_le_bytes(value)))
758 | }
759 |
760 | 3 =>
761 | // 64 bit
762 | {
763 | let value = read_value::(bytes)?;
764 | bytecode.extend(value.iter().cloned());
765 |
766 | Some(Argument::ImmediateI64(i64::from_le_bytes(value)))
767 | }
768 |
769 | _ => unreachable!(),
770 | }
771 | };
772 |
773 | name += &postfixes;
774 |
775 | (op1, arg1, arg2)
776 | }
777 |
778 | _ => unreachable!(),
779 | };
780 |
781 | disassemble_instruction(writer, options, &bytecode, name, op1, arg1, None, arg2, None);
782 |
783 | Ok(())
784 | }
785 |
786 | pub fn parse_instruction6>(
787 | writer: &mut W,
788 | options: &Options,
789 | bytes: &mut T,
790 | byte0: u8,
791 | byte0_bits: [bool; 8],
792 | op: OpCode,
793 | ) -> Result<(), String>
794 | {
795 | let mut name = op.emit(options);
796 | let immediate_data_present = byte0_bits[7];
797 | let is_64_bit = byte0_bits[6];
798 | let postfix =
799 | if is_64_bit { color_x64(String::from("64"), options) } else { color_x32(String::from("32"), options) };
800 |
801 | name += &postfix;
802 |
803 | let byte1 = bytes.next().ok_or("Unexpected end of bytes")?;
804 | let byte1_bits = bits_rev(byte1);
805 | let operand1_is_indirect = byte1_bits[3];
806 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]);
807 | let operand2_is_indirect = byte1_bits[7];
808 | let operand2_value = bits_to_byte_rev(&byte1_bits[4 ..= 6]);
809 |
810 | let mut bytecode = ArrayVec::<_, 18>::new();
811 | bytecode.push(byte0);
812 | bytecode.push(byte1);
813 |
814 | let op1_x16_index_or_immediate = {
815 | if immediate_data_present
816 | {
817 | let value = read_value::(bytes)?;
818 | bytecode.extend(value.iter().cloned());
819 |
820 | let arg = if operand2_is_indirect
821 | {
822 | Argument::Index16(u16::from_le_bytes(value))
823 | }
824 | else
825 | {
826 | Argument::ImmediateI16(i16::from_le_bytes(value))
827 | };
828 |
829 | Some(arg)
830 | }
831 | else
832 | {
833 | None
834 | }
835 | };
836 |
837 | disassemble_instruction(
838 | writer,
839 | options,
840 | &bytecode,
841 | name,
842 | Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect)),
843 | None,
844 | Some(Operand::new_general_purpose(operand2_value, operand2_is_indirect)),
845 | op1_x16_index_or_immediate,
846 | None,
847 | );
848 |
849 | Ok(())
850 | }
851 |
852 | pub fn parse_instruction7>(
853 | writer: &mut W,
854 | options: &Options,
855 | bytes: &mut T,
856 | byte0: u8,
857 | byte0_bits: [bool; 8],
858 | op: OpCode,
859 | ) -> Result<(), String>
860 | {
861 | let operand1_index_present = byte0_bits[7];
862 | let operand2_index_present = byte0_bits[6];
863 |
864 | let byte1 = bytes.next().ok_or("Unexpected end of bytes")?;
865 | let byte1_bits = bits_rev(byte1);
866 | let operand1_is_indirect = byte1_bits[3];
867 | let operand1_value = bits_to_byte_rev(&byte1_bits[0 ..= 2]);
868 | let operand2_is_indirect = byte1_bits[7];
869 | let operand2_value = bits_to_byte_rev(&byte1_bits[4 ..= 6]);
870 |
871 | let mut bytecode = ArrayVec::<_, 18>::new();
872 | bytecode.push(byte0);
873 | bytecode.push(byte1);
874 |
875 | let op1 = Some(Operand::new_general_purpose(operand1_value, operand1_is_indirect));
876 |
877 | let op2 = Some(Operand::new_general_purpose(operand2_value, operand2_is_indirect));
878 |
879 | let (arg1, arg2) = match op
880 | {
881 | OpCode::MOVsnw | OpCode::MOVsnd =>
882 | {
883 | let arg1 = {
884 | if operand1_index_present
885 | {
886 | let arg = match op
887 | {
888 | OpCode::MOVsnw =>
889 | // 16 bit
890 | {
891 | let value = read_value::(bytes)?;
892 | bytecode.extend(value.iter().cloned());
893 |
894 | Argument::Index16(u16::from_le_bytes(value))
895 | }
896 |
897 | OpCode::MOVsnd =>
898 | // 32 bit
899 | {
900 | let value = read_value::(bytes)?;
901 | bytecode.extend(value.iter().cloned());
902 |
903 | Argument::Index32(u32::from_le_bytes(value))
904 | }
905 |
906 | _ => unreachable!(),
907 | };
908 |
909 | Some(arg)
910 | }
911 | else
912 | {
913 | None
914 | }
915 | };
916 |
917 | let arg2 = {
918 | if operand2_index_present
919 | {
920 | let arg = match op
921 | {
922 | OpCode::MOVsnw =>
923 | // 16 bit
924 | {
925 | let value = read_value::(bytes)?;
926 | bytecode.extend(value.iter().cloned());
927 |
928 | if operand2_is_indirect
929 | {
930 | Argument::Index16(u16::from_le_bytes(value))
931 | }
932 | else
933 | {
934 | Argument::ImmediateI16(i16::from_le_bytes(value))
935 | }
936 | }
937 |
938 | OpCode::MOVsnd =>
939 | // 32 bit
940 | {
941 | let value = read_value::(bytes)?;
942 | bytecode.extend(value.iter().cloned());
943 |
944 | if operand2_is_indirect
945 | {
946 | Argument::Index32(u32::from_le_bytes(value))
947 | }
948 | else
949 | {
950 | Argument::ImmediateI32(i32::from_le_bytes(value))
951 | }
952 | }
953 |
954 | _ => unreachable!(),
955 | };
956 |
957 | Some(arg)
958 | }
959 | else
960 | {
961 | None
962 | }
963 | };
964 |
965 | (arg1, arg2)
966 | }
967 |
968 | // Try to combine this with MOVsnw and MOVsnd
969 | OpCode::MOVnw | OpCode::MOVnd =>
970 | {
971 | let arg1 = {
972 | if operand1_index_present
973 | {
974 | let arg = match op
975 | {
976 | OpCode::MOVnw =>
977 | // 16 bit
978 | {
979 | let value = read_value::(bytes)?;
980 | bytecode.extend(value.iter().cloned());
981 |
982 | Argument::Index16(u16::from_le_bytes(value))
983 | }
984 |
985 | OpCode::MOVnd =>
986 | // 32 bit
987 | {
988 | let value = read_value::(bytes)?;
989 | bytecode.extend(value.iter().cloned());
990 |
991 | Argument::Index32(u32::from_le_bytes(value))
992 | }
993 |
994 | _ => unreachable!(),
995 | };
996 |
997 | Some(arg)
998 | }
999 | else
1000 | {
1001 | None
1002 | }
1003 | };
1004 |
1005 | let arg2 = {
1006 | if operand2_index_present
1007 | {
1008 | let arg = match op
1009 | {
1010 | OpCode::MOVnw =>
1011 | // 16 bit
1012 | {
1013 | let value = read_value::(bytes)?;
1014 | bytecode.extend(value.iter().cloned());
1015 |
1016 | if operand2_is_indirect
1017 | {
1018 | Argument::Index16(u16::from_le_bytes(value))
1019 | }
1020 | else
1021 | {
1022 | Argument::ImmediateI16(i16::from_le_bytes(value))
1023 | }
1024 | }
1025 |
1026 | OpCode::MOVnd =>
1027 | // 32 bit
1028 | {
1029 | let value = read_value::(bytes)?;
1030 | bytecode.extend(value.iter().cloned());
1031 |
1032 | if operand2_is_indirect
1033 | {
1034 | Argument::Index32(u32::from_le_bytes(value))
1035 | }
1036 | else
1037 | {
1038 | Argument::ImmediateI32(i32::from_le_bytes(value))
1039 | }
1040 | }
1041 |
1042 | _ => unreachable!(),
1043 | };
1044 |
1045 | Some(arg)
1046 | }
1047 | else
1048 | {
1049 | None
1050 | }
1051 | };
1052 |
1053 | (arg1, arg2)
1054 | }
1055 |
1056 | _ =>
1057 | // MOV
1058 | {
1059 | let arg1 = {
1060 | if operand1_index_present
1061 | {
1062 | let arg = match op
1063 | {
1064 | OpCode::MOVbw | OpCode::MOVww | OpCode::MOVdw | OpCode::MOVqw =>
1065 | // 16 bit
1066 | {
1067 | let value = read_value::(bytes)?;
1068 | bytecode.extend(value.iter().cloned());
1069 |
1070 | Argument::Index16(u16::from_le_bytes(value))
1071 | }
1072 |
1073 | OpCode::MOVbd | OpCode::MOVwd | OpCode::MOVdd | OpCode::MOVqd =>
1074 | // 32 bit
1075 | {
1076 | let value = read_value::(bytes)?;
1077 | bytecode.extend(value.iter().cloned());
1078 |
1079 | Argument::Index32(u32::from_le_bytes(value))
1080 | }
1081 |
1082 | OpCode::MOVqq =>
1083 | // 64 bit
1084 | {
1085 | let value = read_value::(bytes)?;
1086 | bytecode.extend(value.iter().cloned());
1087 |
1088 | Argument::Index64(u64::from_le_bytes(value))
1089 | }
1090 |
1091 | _ => unreachable!(),
1092 | };
1093 |
1094 | Some(arg)
1095 | }
1096 | else
1097 | {
1098 | None
1099 | }
1100 | };
1101 |
1102 | let arg2 = {
1103 | if operand2_index_present
1104 | {
1105 | let arg = match op
1106 | {
1107 | OpCode::MOVbw | OpCode::MOVww | OpCode::MOVdw | OpCode::MOVqw =>
1108 | // 16 bit
1109 | {
1110 | let value = read_value::(bytes)?;
1111 | bytecode.extend(value.iter().cloned());
1112 |
1113 | Argument::Index16(u16::from_le_bytes(value))
1114 | }
1115 |
1116 | OpCode::MOVbd | OpCode::MOVwd | OpCode::MOVdd | OpCode::MOVqd =>
1117 | // 32 bit
1118 | {
1119 | let value = read_value::(bytes)?;
1120 | bytecode.extend(value.iter().cloned());
1121 |
1122 | Argument::Index32(u32::from_le_bytes(value))
1123 | }
1124 |
1125 | OpCode::MOVqq =>
1126 | // 64 bit
1127 | {
1128 | let value = read_value::(bytes)?;
1129 | bytecode.extend(value.iter().cloned());
1130 |
1131 | Argument::Index64(u64::from_le_bytes(value))
1132 | }
1133 |
1134 | _ => unreachable!(),
1135 | };
1136 |
1137 | Some(arg)
1138 | }
1139 | else
1140 | {
1141 | None
1142 | }
1143 | };
1144 |
1145 | (arg1, arg2)
1146 | }
1147 | };
1148 |
1149 | let mut name = format!("{:?}", op);
1150 | let mut chars = name.chars();
1151 | let indices_present = operand1_index_present || operand2_index_present;
1152 |
1153 | let postfix = match op
1154 | {
1155 | OpCode::MOVnw | OpCode::MOVsnw =>
1156 | {
1157 | // If indices are present, keep them
1158 | let move_width = if indices_present
1159 | {
1160 | String::from(chars.next_back().unwrap())
1161 | }
1162 | else
1163 | // Remove it to get to the guaranteed move width
1164 | {
1165 | chars.next_back().unwrap();
1166 | String::from("")
1167 | };
1168 |
1169 | // COLOR IT
1170 | color_x16(move_width, options)
1171 | }
1172 |
1173 | OpCode::MOVnd | OpCode::MOVsnd =>
1174 | {
1175 | // If indices are present, keep them
1176 | let move_width = if indices_present
1177 | {
1178 | String::from(chars.next_back().unwrap())
1179 | }
1180 | else
1181 | // Remove it to get to the guaranteed move width
1182 | {
1183 | chars.next_back().unwrap();
1184 | String::from("")
1185 | };
1186 |
1187 | // COLOR IT
1188 |
1189 | color_x32(move_width, options)
1190 | }
1191 |
1192 | OpCode::MOVbw
1193 | | OpCode::MOVww
1194 | | OpCode::MOVdw
1195 | | OpCode::MOVqw
1196 | | OpCode::MOVbd
1197 | | OpCode::MOVwd
1198 | | OpCode::MOVdd
1199 | | OpCode::MOVqd
1200 | | OpCode::MOVqq =>
1201 | {
1202 | // If indices are present, keep them
1203 | let index_width = if indices_present
1204 | {
1205 | let width = String::from(chars.next_back().unwrap());
1206 |
1207 | match op
1208 | {
1209 | OpCode::MOVbw | OpCode::MOVww | OpCode::MOVdw | OpCode::MOVqw => color_x16(width, options),
1210 |
1211 | OpCode::MOVbd | OpCode::MOVwd | OpCode::MOVdd | OpCode::MOVqd => color_x32(width, options),
1212 |
1213 | OpCode::MOVqq => color_x64(width, options),
1214 |
1215 | _ => unreachable!(),
1216 | }
1217 | }
1218 | else
1219 | // Remove it to get to the guaranteed move width
1220 | {
1221 | chars.next_back().unwrap();
1222 | String::from("")
1223 | };
1224 |
1225 | let move_width = String::from(chars.next_back().unwrap());
1226 | let move_width = match op
1227 | {
1228 | OpCode::MOVbw | OpCode::MOVbd => color_x8(move_width, options),
1229 |
1230 | OpCode::MOVww | OpCode::MOVwd => color_x16(move_width, options),
1231 |
1232 | OpCode::MOVdw | OpCode::MOVdd => color_x32(move_width, options),
1233 |
1234 | OpCode::MOVqw | OpCode::MOVqd | OpCode::MOVqq => color_x64(move_width, options),
1235 |
1236 | _ => unreachable!(),
1237 | };
1238 |
1239 | move_width + &index_width
1240 | }
1241 |
1242 | _ => unreachable!(),
1243 | };
1244 |
1245 | let postfixes_removed = chars.as_str().to_string();
1246 | name = color_opcode(postfixes_removed, options);
1247 | name += &postfix;
1248 |
1249 | disassemble_instruction(writer, options, &bytecode, name, op1, arg1, op2, arg2, None);
1250 |
1251 | Ok(())
1252 | }
1253 |
1254 | pub fn disassemble_instruction(
1255 | writer: &mut W,
1256 | options: &Options,
1257 | bytecode: &[u8],
1258 | instruction: String, // Must concatenate postfixes manually
1259 | operand1: Option,
1260 | argument1: Option,
1261 | operand2: Option,
1262 | argument2: Option,
1263 | comment: Option,
1264 | )
1265 | {
1266 | if options.bytecode
1267 | {
1268 | const TWO_CHARS_AND_A_SPACE: usize = 3;
1269 | let mut bytecode_output = String::with_capacity(bytecode.len() * TWO_CHARS_AND_A_SPACE);
1270 |
1271 | for byte in bytecode.iter()
1272 | {
1273 | bytecode_output += format!("{:<02X?} ", byte).as_str();
1274 | }
1275 |
1276 | bytecode_output = color_bytecode(bytecode_output, options);
1277 |
1278 | write!(writer, "{:>84} ", bytecode_output).unwrap();
1279 | }
1280 |
1281 | if options.pad_output
1282 | {
1283 | write!(writer, "{}", instruction).unwrap();
1284 | }
1285 | else
1286 | {
1287 | write!(writer, "{}", instruction).unwrap();
1288 | }
1289 |
1290 | if let Some(op1) = operand1
1291 | {
1292 | write!(writer, " {}", op1.emit(options)).unwrap();
1293 | }
1294 |
1295 | if let Some(arg1) = argument1
1296 | {
1297 | let text = arg1.emit(options);
1298 |
1299 | match arg1
1300 | {
1301 | Argument::Index16(_index) => write!(writer, "{}", text).unwrap(),
1302 | Argument::Index32(_index) => write!(writer, "{}", text).unwrap(),
1303 | Argument::Index64(_index) => write!(writer, "{}", text).unwrap(),
1304 | _ => write!(writer, " {}", text).unwrap(),
1305 | }
1306 | }
1307 |
1308 | if operand2.is_some() || argument2.is_some()
1309 | {
1310 | write!(writer, ",").unwrap();
1311 | }
1312 |
1313 | if let Some(ref op2) = operand2
1314 | {
1315 | write!(writer, " {}", op2.emit(options)).unwrap();
1316 | }
1317 |
1318 | if let Some(arg2) = argument2
1319 | {
1320 | match arg2
1321 | {
1322 | Argument::Index16(_index) =>
1323 | {
1324 | if operand2.is_none()
1325 | {
1326 | write!(writer, " ").unwrap();
1327 | }
1328 | write!(writer, "{}", arg2.emit(options)).unwrap();
1329 | }
1330 |
1331 | Argument::Index32(_index) =>
1332 | {
1333 | if operand2.is_none()
1334 | {
1335 | write!(writer, " ").unwrap();
1336 | }
1337 | write!(writer, "{}", arg2.emit(options)).unwrap();
1338 | }
1339 |
1340 | Argument::Index64(_index) =>
1341 | {
1342 | if operand2.is_none()
1343 | {
1344 | write!(writer, " ").unwrap();
1345 | }
1346 | write!(writer, "{}", arg2.emit(options)).unwrap();
1347 | }
1348 |
1349 | _ => write!(writer, " {}", arg2.emit(options)).unwrap(),
1350 | }
1351 | }
1352 |
1353 | if let Some(line_comment) = comment
1354 | {
1355 | let the_comment = color_comment(format!(" ;; {}", line_comment), options);
1356 |
1357 | write!(writer, "{}", the_comment).unwrap();
1358 | }
1359 |
1360 | writeln!(writer, "").unwrap();
1361 | }
1362 |
--------------------------------------------------------------------------------
/src/main.rs:
--------------------------------------------------------------------------------
1 | mod argument;
2 | mod bits;
3 | mod instruction;
4 | mod natural_index;
5 | mod opcode;
6 | mod operand;
7 | mod options;
8 | mod theme;
9 |
10 | #[cfg(test)]
11 | mod tests; // Integration tests
12 |
13 | use pelite::pe64::{Pe, PeFile};
14 | use pelite::FileMap;
15 |
16 | use crate::opcode::OpCode;
17 | use crate::options::Options;
18 | use crate::theme::*;
19 |
20 | const CODE_SECTION: u32 = pelite::image::IMAGE_SCN_CNT_CODE;
21 | const HELP: &'static str = include_str!("CLI.txt");
22 |
23 | /// Reads in an EFI Bytecode filename from STDIN and prints the disassembly.
24 | fn main()
25 | {
26 | let mut args = std::env::args().skip(1).collect::>();
27 |
28 | if args.len() == 0
29 | {
30 | return println!("{}", HELP);
31 | }
32 |
33 | let filename = args.pop().unwrap();
34 |
35 | if args.len() % 2 != 0
36 | {
37 | return println!("{}", HELP);
38 | }
39 |
40 | let mut options = Options { theme: Some(SPORE), bytecode: true, pe: true, pad_output: true };
41 |
42 | for i in (0 .. args.len()).step_by(2)
43 | {
44 | let option = args[i].clone();
45 | let value = args[i + 1].clone();
46 |
47 | match option.as_str()
48 | {
49 | "theme:" =>
50 | {
51 | if !"SPORE INDUSTRIAL_COMPUTER MATTERHORN_ZERMATT_VILLAGE OFF".contains(&value)
52 | {
53 | println!("{}", color_error(format!("Unknown theme: {}", value), &options),);
54 | return println!("{}", HELP);
55 | }
56 |
57 | options.theme = match value.as_str()
58 | {
59 | "SPORE" => Some(SPORE),
60 | "INDUSTRIAL_COMPUTER" => Some(INDUSTRIAL_COMPUTER),
61 | "MATTERHORN_ZERMATT_VILLAGE" => Some(MATTERHORN_ZERMATT_VILLAGE),
62 | "OFF" => None,
63 |
64 | _ => unreachable!(),
65 | };
66 | }
67 |
68 | "bytecode:" =>
69 | {
70 | if value != "ON".to_string() && value != "OFF".to_string()
71 | {
72 | return println!("{}", color_error(format!("Invalid bytecode setting: {}", value), &options),);
73 | }
74 |
75 | options.bytecode = value == "ON";
76 | }
77 |
78 | "pe:" =>
79 | {
80 | if value != "ON".to_string() && value != "OFF".to_string()
81 | {
82 | return println!("{}", color_error(format!("Invalid pe setting: {}", value), &options),);
83 | }
84 |
85 | options.pe = value == "ON";
86 | }
87 |
88 | _ =>
89 | {
90 | return println!("{}", color_error(format!("Invalid setting: {}", option), &options),);
91 | }
92 | }
93 | }
94 |
95 | match FileMap::open(filename.as_str())
96 | {
97 | Ok(file_bytes) =>
98 | {
99 | let byte_slice = if options.pe
100 | {
101 | let file = PeFile::from_bytes(&file_bytes);
102 |
103 | if let Err(msg) = file
104 | {
105 | let err_msg = format!(
106 | "Failed to open PE executable: {}\n{}",
107 | msg,
108 | ["Are you trying to load a binary file as a PE ", "executable (try pe: OFF)?"].join("")
109 | );
110 |
111 | return println!("{}", color_error(err_msg, &options));
112 | }
113 |
114 | let file = file.unwrap();
115 | let mut bytecode_section = None;
116 |
117 | // Find the section header for code
118 | for section_header in file.section_headers()
119 | {
120 | if section_header.Characteristics & CODE_SECTION != 0
121 | {
122 | bytecode_section = Some(file.get_section_bytes(section_header).unwrap());
123 |
124 | break;
125 | }
126 | }
127 |
128 | match bytecode_section
129 | {
130 | Some(bytecode) => bytecode,
131 | None =>
132 | {
133 | return println!("{}", color_error("PE file is missing code section".to_string(), &options));
134 | }
135 | }
136 | }
137 | else
138 | {
139 | file_bytes.as_ref()
140 | };
141 |
142 | let mut bytes = byte_slice.iter().cloned().peekable();
143 |
144 | loop
145 | {
146 | let result = OpCode::disassemble(&options, &mut std::io::stdout(), &mut bytes);
147 |
148 | match result
149 | {
150 | Ok(_) => (),
151 |
152 | Err(msg) =>
153 | {
154 | println!("{}", msg);
155 | break;
156 | }
157 | }
158 | }
159 | }
160 |
161 | Err(msg) =>
162 | {
163 | return println!("{}", color_error(format!("Error opening file: {}", msg), &options));
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/src/natural_index.rs:
--------------------------------------------------------------------------------
1 | use crate::bits::*;
2 | use crate::options::Options;
3 | use crate::theme::*;
4 |
5 | const SIZE_OF_VOID_PTR: u16 = 8;
6 | const HEADER_SIZE: usize = 4;
7 |
8 | pub struct NaturalIndex
9 | {
10 | pub value: u64,
11 | pub sign: i8,
12 | pub constant: u64,
13 | pub natural: u64,
14 | pub offset: i64,
15 | }
16 |
17 | impl NaturalIndex
18 | {
19 | /// It is critical that the right method be selected per index size.
20 | /// Do not use `from_u64()` for a 16 bit value.
21 | pub fn from_u16(value: u16) -> Self
22 | {
23 | const ENCODING_SIZE: u16 = 2;
24 |
25 | let bits = bits_u16(value);
26 | let sign = if bits[0] { -1i64 } else { 1i64 };
27 | let width_base = bits_to_byte_u16(&bits[1 .. 4]);
28 | let actual_width = width_base * ENCODING_SIZE;
29 | let natural = bits_to_byte_u16(&bits[bits.len() - actual_width as usize ..]);
30 | let constant = bits_to_byte_u16(&bits[HEADER_SIZE .. bits.len() - actual_width as usize]);
31 | let offset = sign * (constant + natural * SIZE_OF_VOID_PTR) as i64;
32 |
33 | Self {
34 | value: value as u64,
35 | sign: sign as i8,
36 | constant: constant as u64,
37 | natural: natural as u64,
38 | offset: offset as i64,
39 | }
40 | }
41 |
42 | /// It is critical that the right method be selected per index size.
43 | /// Do not use `from_u64()` for a 16 bit value.
44 | pub fn from_u32(value: u32) -> Self
45 | {
46 | const ENCODING_SIZE: u32 = 4;
47 |
48 | let bits = bits_u32(value);
49 | let sign = if bits[0] { -1i64 } else { 1i64 };
50 | let width_base = bits_to_byte_u32(&bits[1 .. 4]);
51 | let actual_width = width_base * ENCODING_SIZE;
52 | let natural = bits_to_byte_u32(&bits[bits.len() - actual_width as usize ..]);
53 | let constant = bits_to_byte_u32(&bits[HEADER_SIZE .. bits.len() - actual_width as usize]);
54 | let offset = { sign * (constant + natural * SIZE_OF_VOID_PTR as u32) as i64 };
55 |
56 | Self {
57 | value: value as u64,
58 | sign: sign as i8,
59 | constant: constant as u64,
60 | natural: natural as u64,
61 | offset: offset as i64,
62 | }
63 | }
64 |
65 | /// It is critical that the right method be selected per index size.
66 | /// Do not use `from_u64()` for a 16 bit value.
67 | pub fn from_u64(value: u64) -> Self
68 | {
69 | const ENCODING_SIZE: u64 = 8;
70 |
71 | let bits = bits_u64(value);
72 | let sign = if bits[0] { -1i64 } else { 1i64 };
73 | let width_base = bits_to_byte_u64(&bits[1 .. 4]);
74 | let actual_width = width_base * ENCODING_SIZE;
75 | let natural = bits_to_byte_u64(&bits[bits.len() - actual_width as usize ..]);
76 | let constant = bits_to_byte_u64(&bits[HEADER_SIZE .. bits.len() - actual_width as usize]);
77 | let offset = { sign * (constant + natural * SIZE_OF_VOID_PTR as u64) as i64 };
78 |
79 | Self { value: value, sign: sign as i8, constant: constant, natural: natural, offset: offset as i64 }
80 | }
81 | }
82 |
83 | impl Emit for NaturalIndex
84 | {
85 | fn emit(&self, options: &Options) -> String
86 | {
87 | format!(
88 | "({}{}, {}{})",
89 | if self.sign < 0 { "-" } else { "+" },
90 | color_index(self.natural.to_string(), options),
91 | if self.sign < 0 { "-" } else { "+" },
92 | color_index(self.constant.to_string(), options)
93 | )
94 | }
95 | }
96 |
97 | #[cfg(test)]
98 | mod tests
99 | {
100 | use super::*;
101 |
102 | #[test]
103 | pub fn test_natural_indexing()
104 | {
105 | let index = NaturalIndex::from_u16(4161);
106 | assert_eq!(index.constant, 16u64);
107 | assert_eq!(index.natural, 1u64);
108 | assert_eq!(index.offset, 24i64);
109 |
110 | let index = NaturalIndex::from_u16(4114);
111 | assert_eq!(index.constant, 4u64);
112 | assert_eq!(index.natural, 2u64);
113 | assert_eq!(index.offset, 20i64);
114 |
115 | let index = NaturalIndex::from_u16(8581);
116 | assert_eq!(index.constant, 24u64);
117 | assert_eq!(index.natural, 5u64);
118 | assert_eq!(index.offset, 64i64);
119 |
120 | let index = NaturalIndex::from_u32(805324752);
121 | assert_eq!(index.constant, 4u64);
122 | assert_eq!(index.natural, 2000u64);
123 | assert_eq!(index.offset, 16004i64);
124 |
125 | let index = NaturalIndex::from_u32(111111);
126 | assert_eq!(index.constant, 111111u64);
127 | assert_eq!(index.natural, 0u64);
128 | assert_eq!(index.offset, 111111i64);
129 |
130 | let index = NaturalIndex::from_u64(2305843035428095952);
131 | assert_eq!(index.constant, 400000u64);
132 | assert_eq!(index.natural, 2000u64);
133 | assert_eq!(index.offset, 416000i64);
134 |
135 | let index = NaturalIndex::from_u32(591751049);
136 | assert_eq!(index.constant, 214375u64);
137 | assert_eq!(index.natural, 137u64);
138 | assert_eq!(index.offset, 215471i64);
139 |
140 | let index = NaturalIndex::from_u64(11529215072282871760);
141 | assert_eq!(index.sign, -1i8);
142 | assert_eq!(index.constant, 400000u64);
143 | assert_eq!(index.natural, 2000u64);
144 | assert_eq!(index.offset, -416000i64);
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/src/opcode.rs:
--------------------------------------------------------------------------------
1 | use crate::bits::*;
2 | use crate::instruction::*;
3 | use crate::options::Options;
4 | use crate::theme::*;
5 |
6 | #[derive(Debug)]
7 | pub enum OpCode
8 | {
9 | ADD = 0x0C,
10 | AND = 0x14,
11 | ASHR = 0x19,
12 | BREAK = 0x00,
13 | CALL = 0x03,
14 | CMPeq = 0x05,
15 | CMPlte = 0x06,
16 | CMPgte = 0x07,
17 | CMPulte = 0x08,
18 | CMPugte = 0x09,
19 | CMPIeq = 0x2D,
20 | CMPIlte = 0x2E,
21 | CMPIgte = 0x2F,
22 | CMPIulte = 0x30,
23 | CMPIugte = 0x31,
24 | DIV = 0x10,
25 | DIVU = 0x11,
26 | EXTNDB = 0x1A,
27 | EXTNDD = 0x1C,
28 | EXTNDW = 0x1B,
29 | JMP = 0x01,
30 | JMP8 = 0x02,
31 | LOADSP = 0x29,
32 | MOD = 0x12,
33 | MODU = 0x13,
34 | MOVbw = 0x1D,
35 | MOVww = 0x1E,
36 | MOVdw = 0x1F,
37 | MOVqw = 0x20,
38 | MOVbd = 0x21,
39 | MOVwd = 0x22,
40 | MOVdd = 0x23,
41 | MOVqd = 0x24,
42 | MOVqq = 0x28,
43 | MOVI = 0x37,
44 | MOVIn = 0x38,
45 | MOVnw = 0x32,
46 | MOVnd = 0x33,
47 | MOVREL = 0x39,
48 | MOVsnw = 0x25,
49 | MOVsnd = 0x26,
50 | MUL = 0x0E,
51 | MULU = 0x0F,
52 | NEG = 0x0B,
53 | NOT = 0x0A,
54 | OR = 0x15,
55 | POP = 0x2C,
56 | POPn = 0x36,
57 | PUSH = 0x2B,
58 | PUSHn = 0x35,
59 | RET = 0x04,
60 | SHL = 0x17,
61 | SHR = 0x18,
62 | STORESP = 0x2A,
63 | SUB = 0x0D,
64 | XOR = 0x16,
65 | }
66 |
67 | impl std::convert::TryFrom for u8
68 | {
69 | type Error = ();
70 |
71 | fn try_from(v: OpCode) -> Result
72 | {
73 | match v
74 | {
75 | OpCode::ADD => Ok(0x0C),
76 | OpCode::AND => Ok(0x14),
77 | OpCode::ASHR => Ok(0x19),
78 | OpCode::BREAK => Ok(0x00),
79 | OpCode::CALL => Ok(0x03),
80 | OpCode::CMPeq => Ok(0x05),
81 | OpCode::CMPlte => Ok(0x06),
82 | OpCode::CMPgte => Ok(0x07),
83 | OpCode::CMPulte => Ok(0x08),
84 | OpCode::CMPugte => Ok(0x09),
85 | OpCode::CMPIeq => Ok(0x2D),
86 | OpCode::CMPIlte => Ok(0x2E),
87 | OpCode::CMPIgte => Ok(0x2F),
88 | OpCode::CMPIulte => Ok(0x30),
89 | OpCode::CMPIugte => Ok(0x31),
90 | OpCode::DIV => Ok(0x10),
91 | OpCode::DIVU => Ok(0x11),
92 | OpCode::EXTNDB => Ok(0x1A),
93 | OpCode::EXTNDD => Ok(0x1C),
94 | OpCode::EXTNDW => Ok(0x1B),
95 | OpCode::JMP => Ok(0x01),
96 | OpCode::JMP8 => Ok(0x02),
97 | OpCode::LOADSP => Ok(0x29),
98 | OpCode::MOD => Ok(0x12),
99 | OpCode::MODU => Ok(0x13),
100 | OpCode::MOVbw => Ok(0x1D),
101 | OpCode::MOVww => Ok(0x1E),
102 | OpCode::MOVdw => Ok(0x1F),
103 | OpCode::MOVqw => Ok(0x20),
104 | OpCode::MOVbd => Ok(0x21),
105 | OpCode::MOVwd => Ok(0x22),
106 | OpCode::MOVdd => Ok(0x23),
107 | OpCode::MOVqd => Ok(0x24),
108 | OpCode::MOVqq => Ok(0x28),
109 | OpCode::MOVI => Ok(0x37),
110 | OpCode::MOVIn => Ok(0x38),
111 | OpCode::MOVnw => Ok(0x32),
112 | OpCode::MOVnd => Ok(0x33),
113 | OpCode::MOVREL => Ok(0x39),
114 | OpCode::MOVsnw => Ok(0x25),
115 | OpCode::MOVsnd => Ok(0x26),
116 | OpCode::MUL => Ok(0x0E),
117 | OpCode::MULU => Ok(0x0F),
118 | OpCode::NEG => Ok(0x0B),
119 | OpCode::NOT => Ok(0x0A),
120 | OpCode::OR => Ok(0x15),
121 | OpCode::POP => Ok(0x2C),
122 | OpCode::POPn => Ok(0x36),
123 | OpCode::PUSH => Ok(0x2B),
124 | OpCode::PUSHn => Ok(0x35),
125 | OpCode::RET => Ok(0x04),
126 | OpCode::SHL => Ok(0x17),
127 | OpCode::SHR => Ok(0x18),
128 | OpCode::STORESP => Ok(0x2A),
129 | OpCode::SUB => Ok(0x0D),
130 | OpCode::XOR => Ok(0x16),
131 | }
132 | }
133 | }
134 |
135 | impl std::convert::TryFrom for OpCode
136 | {
137 | type Error = ();
138 |
139 | fn try_from(v: u8) -> Result
140 | {
141 | match v
142 | {
143 | x if x == Self::ADD as u8 => Ok(Self::ADD),
144 | x if x == Self::AND as u8 => Ok(Self::AND),
145 | x if x == Self::ASHR as u8 => Ok(Self::ASHR),
146 | x if x == Self::BREAK as u8 => Ok(Self::BREAK),
147 | x if x == Self::CALL as u8 => Ok(Self::CALL),
148 | x if x == Self::CMPeq as u8 => Ok(Self::CMPeq),
149 | x if x == Self::CMPlte as u8 => Ok(Self::CMPlte),
150 | x if x == Self::CMPgte as u8 => Ok(Self::CMPgte),
151 | x if x == Self::CMPulte as u8 => Ok(Self::CMPulte),
152 | x if x == Self::CMPugte as u8 => Ok(Self::CMPugte),
153 | x if x == Self::CMPIeq as u8 => Ok(Self::CMPIeq),
154 | x if x == Self::CMPIlte as u8 => Ok(Self::CMPIlte),
155 | x if x == Self::CMPIgte as u8 => Ok(Self::CMPIgte),
156 | x if x == Self::CMPIulte as u8 => Ok(Self::CMPIulte),
157 | x if x == Self::CMPIugte as u8 => Ok(Self::CMPIugte),
158 | x if x == Self::DIV as u8 => Ok(Self::DIV),
159 | x if x == Self::DIVU as u8 => Ok(Self::DIVU),
160 | x if x == Self::EXTNDB as u8 => Ok(Self::EXTNDB),
161 | x if x == Self::EXTNDD as u8 => Ok(Self::EXTNDD),
162 | x if x == Self::EXTNDW as u8 => Ok(Self::EXTNDW),
163 | x if x == Self::JMP as u8 => Ok(Self::JMP),
164 | x if x == Self::JMP8 as u8 => Ok(Self::JMP8),
165 | x if x == Self::LOADSP as u8 => Ok(Self::LOADSP),
166 | x if x == Self::MOD as u8 => Ok(Self::MOD),
167 | x if x == Self::MODU as u8 => Ok(Self::MODU),
168 | x if x == Self::MOVbw as u8 => Ok(Self::MOVbw),
169 | x if x == Self::MOVww as u8 => Ok(Self::MOVww),
170 | x if x == Self::MOVdw as u8 => Ok(Self::MOVdw),
171 | x if x == Self::MOVqw as u8 => Ok(Self::MOVqw),
172 | x if x == Self::MOVbd as u8 => Ok(Self::MOVbd),
173 | x if x == Self::MOVwd as u8 => Ok(Self::MOVwd),
174 | x if x == Self::MOVdd as u8 => Ok(Self::MOVdd),
175 | x if x == Self::MOVqd as u8 => Ok(Self::MOVqd),
176 | x if x == Self::MOVqq as u8 => Ok(Self::MOVqq),
177 | x if x == Self::MOVI as u8 => Ok(Self::MOVI),
178 | x if x == Self::MOVIn as u8 => Ok(Self::MOVIn),
179 | x if x == Self::MOVnw as u8 => Ok(Self::MOVnw),
180 | x if x == Self::MOVnd as u8 => Ok(Self::MOVnd),
181 | x if x == Self::MOVREL as u8 => Ok(Self::MOVREL),
182 | x if x == Self::MOVsnw as u8 => Ok(Self::MOVsnw),
183 | x if x == Self::MOVsnd as u8 => Ok(Self::MOVsnd),
184 | x if x == Self::MUL as u8 => Ok(Self::MUL),
185 | x if x == Self::MULU as u8 => Ok(Self::MULU),
186 | x if x == Self::NEG as u8 => Ok(Self::NEG),
187 | x if x == Self::NOT as u8 => Ok(Self::NOT),
188 | x if x == Self::OR as u8 => Ok(Self::OR),
189 | x if x == Self::POP as u8 => Ok(Self::POP),
190 | x if x == Self::POPn as u8 => Ok(Self::POPn),
191 | x if x == Self::PUSH as u8 => Ok(Self::PUSH),
192 | x if x == Self::PUSHn as u8 => Ok(Self::PUSHn),
193 | x if x == Self::RET as u8 => Ok(Self::RET),
194 | x if x == Self::SHL as u8 => Ok(Self::SHL),
195 | x if x == Self::SHR as u8 => Ok(Self::SHR),
196 | x if x == Self::STORESP as u8 => Ok(Self::STORESP),
197 | x if x == Self::SUB as u8 => Ok(Self::SUB),
198 | x if x == Self::XOR as u8 => Ok(Self::XOR),
199 | _ => Err(()),
200 | }
201 | }
202 | }
203 |
204 | impl OpCode
205 | {
206 | /// Bytes are read from left to right. Bits are read from right to left.
207 | // pub fn disassemble, W: std::io::Write>(
208 | // options: &Options,
209 | // writer: &mut W,
210 | // bytes: &mut T
211 | // ) -> Result<(), String>
212 | pub fn disassemble, W: std::io::Write>(
213 | options: &Options,
214 | writer: &mut W,
215 | bytes: &mut std::iter::Peekable,
216 | ) -> Result<(), String>
217 | {
218 | let byte0 = if let Some(byte) = bytes.next()
219 | {
220 | byte
221 | }
222 | else
223 | {
224 | return Err(String::from("Completed Disassembly"));
225 | };
226 |
227 | // * Using reverse number parsing to make indexing the individual bits
228 | // * easier since the UEFI spec specifies them in reverse.
229 |
230 | let byte0_bits = bits_rev(byte0);
231 | let op_value = bits_to_byte_rev(&byte0_bits[0 ..= 5]);
232 | let op: OpCode = op_value.try_into().expect(format!("Invalid OpCode: {}", op_value).as_str());
233 |
234 | match op
235 | {
236 | OpCode::BREAK =>
237 | {
238 | if let Some(byte) = bytes.peek()
239 | {
240 | if *byte == 0
241 | {
242 | bytes.next(); // Skip this and the next zero
243 | Ok(())
244 | }
245 | else if *byte > 6
246 | // 1-6 are valid break codes
247 | {
248 | Ok(()) // Only skip this zero
249 | }
250 | else
251 | {
252 | // 2. INSTRUCTION ARGUMENT (BREAK)
253 | parse_instruction2(writer, options, bytes, byte0, byte0_bits, op)
254 | }
255 | }
256 | else
257 | {
258 | Ok(())
259 | }
260 | }
261 |
262 | // 1. INSTRUCTION (RET)
263 | OpCode::RET => parse_instruction1(writer, options, bytes, byte0, byte0_bits, op),
264 |
265 | OpCode::JMP8 =>
266 | {
267 | // 2. INSTRUCTION ARGUMENT (BREAK)
268 | parse_instruction2(writer, options, bytes, byte0, byte0_bits, op)
269 | }
270 |
271 | OpCode::CALL | OpCode::JMP | OpCode::PUSH | OpCode::PUSHn | OpCode::POP | OpCode::POPn =>
272 | {
273 | // 3. INSTRUCTION OP1 ARGUMENT (CALL)
274 | parse_instruction3(writer, options, bytes, byte0, byte0_bits, op)
275 | }
276 |
277 | OpCode::LOADSP | OpCode::STORESP =>
278 | {
279 | // 4. INSTRUCTION OP1, OP2 (STORESP)
280 | parse_instruction4(writer, options, bytes, byte0, byte0_bits, op)
281 | }
282 |
283 | OpCode::CMPIeq
284 | | OpCode::CMPIlte
285 | | OpCode::CMPIgte
286 | | OpCode::CMPIulte
287 | | OpCode::CMPIugte
288 | | OpCode::MOVI
289 | | OpCode::MOVIn
290 | | OpCode::MOVREL =>
291 | {
292 | // 5. INSTRUCTION OP1 ARGUMENT, ARGUMENT (CMPI)
293 | parse_instruction5(writer, options, bytes, byte0, byte0_bits, op)
294 | }
295 |
296 | OpCode::ADD
297 | | OpCode::AND
298 | | OpCode::ASHR
299 | | OpCode::CMPeq
300 | | OpCode::CMPlte
301 | | OpCode::CMPgte
302 | | OpCode::CMPulte
303 | | OpCode::CMPugte
304 | | OpCode::DIV
305 | | OpCode::DIVU
306 | | OpCode::EXTNDB
307 | | OpCode::EXTNDD
308 | | OpCode::EXTNDW
309 | | OpCode::MOD
310 | | OpCode::MODU
311 | | OpCode::MUL
312 | | OpCode::MULU
313 | | OpCode::NEG
314 | | OpCode::NOT
315 | | OpCode::OR
316 | | OpCode::SHL
317 | | OpCode::SHR
318 | | OpCode::SUB
319 | | OpCode::XOR =>
320 | {
321 | // 6. INSTRUCTION OP1, OP2 ARGUMENT
322 | parse_instruction6(writer, options, bytes, byte0, byte0_bits, op)
323 | }
324 |
325 | OpCode::MOVnw
326 | | OpCode::MOVnd
327 | | OpCode::MOVbw
328 | | OpCode::MOVww
329 | | OpCode::MOVdw
330 | | OpCode::MOVqw
331 | | OpCode::MOVbd
332 | | OpCode::MOVwd
333 | | OpCode::MOVdd
334 | | OpCode::MOVqd
335 | | OpCode::MOVqq
336 | | OpCode::MOVsnw
337 | | OpCode::MOVsnd =>
338 | {
339 | // 7. INSTRUCTION OP1 ARGUMENT, OP2 ARGUMENT (MOV)
340 | parse_instruction7(writer, options, bytes, byte0, byte0_bits, op)
341 | }
342 | }
343 | }
344 |
345 | pub fn to(self) -> u8
346 | {
347 | self.try_into().unwrap()
348 | }
349 | }
350 |
351 | impl Emit for OpCode
352 | {
353 | fn emit(&self, options: &Options) -> String
354 | {
355 | color_opcode(format!("{:?}", self), options)
356 | }
357 | }
358 |
--------------------------------------------------------------------------------
/src/operand.rs:
--------------------------------------------------------------------------------
1 | use crate::options::Options;
2 | use crate::theme::*;
3 |
4 | pub enum Operand
5 | {
6 | GeneralPurpose
7 | {
8 | register_index: u8, indirect: bool
9 | },
10 |
11 | Dedicated
12 | {
13 | register_index: u8, indirect: bool
14 | },
15 | }
16 |
17 | impl Operand
18 | {
19 | pub fn new_general_purpose(register_index: u8, indirect: bool) -> Self
20 | {
21 | assert!((0u8 ..= 7u8).contains(®ister_index));
22 |
23 | Self::GeneralPurpose { register_index, indirect }
24 | }
25 |
26 | pub fn new_dedicated(register_index: u8, indirect: bool) -> Self
27 | {
28 | assert!((0u8 ..= 1u8).contains(®ister_index));
29 |
30 | Self::Dedicated { register_index, indirect }
31 | }
32 | }
33 |
34 | impl Emit for Operand
35 | {
36 | fn emit(&self, options: &Options) -> String
37 | {
38 | match self
39 | {
40 | Self::GeneralPurpose { register_index: index, indirect: at } =>
41 | {
42 | let at_sym = if *at { color_indirect("@".to_string(), options) } else { "".to_string() };
43 |
44 | assert!((0u8 ..= 7u8).contains(&index));
45 |
46 | color_operand(format!("{}R{}", at_sym, index), options)
47 | }
48 |
49 | Self::Dedicated { register_index: index, indirect: at } =>
50 | {
51 | let at_sym = if *at { color_indirect("@".to_string(), options) } else { "".to_string() };
52 |
53 | assert!((0u8 ..= 1u8).contains(&index));
54 |
55 | let result = if *index == 0 { format!("{}FLAGS", at_sym) } else { format!("{}IP", at_sym) };
56 |
57 | color_operand(result, options)
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/options.rs:
--------------------------------------------------------------------------------
1 | use crate::theme::Theme;
2 |
3 | pub struct Options
4 | {
5 | pub pad_output: bool, // Padding is great for output but not for testing
6 | pub theme: Option, // Colorize assembly output (optional for pipes)
7 | pub bytecode: bool, // Output bytecode in hex notation beside assembly
8 | pub pe: bool, // Load a Windows PE file rather than a binary file
9 | }
10 |
--------------------------------------------------------------------------------
/src/tests/mod.rs:
--------------------------------------------------------------------------------
1 | use std::io::Cursor;
2 |
3 | use super::*;
4 |
5 | fn dis(options: &Options, cursor: &mut Cursor>, bytecode: &[u8]) -> String
6 | {
7 | let result = OpCode::disassemble(&options, cursor, &mut bytecode.into_iter().cloned().peekable());
8 |
9 | match result
10 | {
11 | Ok(_) => assert!(true),
12 | Err(msg) => assert!(false, "{}", msg.to_string()),
13 | }
14 |
15 | let disassembly = String::from_utf8(cursor.get_ref().clone()).unwrap();
16 | cursor.get_mut().clear();
17 | cursor.set_position(0);
18 |
19 | // Remove last character since that will always be a "\n"
20 | let mut chars = disassembly.chars();
21 | chars.next_back();
22 | chars.as_str().to_string()
23 | }
24 |
25 | fn byte(bit8: u8, bit7: u8, op: OpCode) -> u8
26 | {
27 | let mut byte = op.to();
28 | if bit8 > 0
29 | {
30 | byte |= 1 << 7;
31 | }
32 | if bit7 > 0
33 | {
34 | byte |= 1 << 6;
35 | }
36 | byte
37 | }
38 |
39 | #[test]
40 | pub fn test_instruction_disassembly()
41 | {
42 | let opts = &Options { theme: None, bytecode: false, pad_output: false, pe: false };
43 |
44 | let cur = &mut Cursor::new(Vec::with_capacity(50));
45 |
46 | assert_eq!("RET", dis(opts, cur, &[OpCode::RET.to()]));
47 | assert_eq!("STORESP R1, FLAGS", dis(opts, cur, &[OpCode::STORESP.to(), 0b00000001]));
48 | assert_eq!("STORESP R1, IP", dis(opts, cur, &[OpCode::STORESP.to(), 0b00010001]));
49 | assert_eq!("LOADSP FLAGS, R1", dis(opts, cur, &[OpCode::LOADSP.to(), 0b00010000]));
50 | assert_eq!("LOADSP IP, R1", dis(opts, cur, &[OpCode::LOADSP.to(), 0b00010001]));
51 | assert_eq!("BREAK 3", dis(opts, cur, &[OpCode::BREAK.to(), 0b00000011]));
52 |
53 | assert_eq!("JMP8 -3", dis(opts, cur, &[&[byte(0, 0, OpCode::JMP8)][..], &(-3i8).to_le_bytes()[..],].concat()));
54 |
55 | assert_eq!(
56 | "JMP8 -3",
57 | dis(
58 | opts,
59 | cur,
60 | &[
61 | // Test that CC or CS have not effect on unconditional jump
62 | &[byte(0, 1, OpCode::JMP8)][..],
63 | &(-3i8).to_le_bytes()[..],
64 | ]
65 | .concat()
66 | )
67 | );
68 |
69 | assert_eq!("JMP8cc -3", dis(opts, cur, &[&[byte(1, 0, OpCode::JMP8)][..], &(-3i8).to_le_bytes()[..],].concat()));
70 |
71 | assert_eq!("JMP8cs -3", dis(opts, cur, &[&[byte(1, 1, OpCode::JMP8)][..], &(-3i8).to_le_bytes()[..],].concat()));
72 |
73 | assert_eq!("POPn R1", dis(opts, cur, &[OpCode::POPn.to(), 0b00000001]));
74 |
75 | assert_eq!("PUSHn R1", dis(opts, cur, &[OpCode::PUSHn.to(), 0b00000001]));
76 |
77 | assert_eq!("POPn @R1", dis(opts, cur, &[OpCode::POPn.to(), 0b00001001]));
78 |
79 | assert_eq!("PUSHn @R1", dis(opts, cur, &[OpCode::PUSHn.to(), 0b00001001]));
80 |
81 | assert_eq!(
82 | "POPn R1 -3",
83 | dis(opts, cur, &[&[byte(1, 0, OpCode::POPn), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat())
84 | );
85 |
86 | assert_eq!(
87 | "PUSHn R1 -3",
88 | dis(opts, cur, &[&[byte(1, 0, OpCode::PUSHn), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat())
89 | );
90 |
91 | assert_eq!(
92 | "POPn @R1(-3, -3)",
93 | dis(opts, cur, &[&[byte(1, 0, OpCode::POPn), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat())
94 | );
95 |
96 | assert_eq!(
97 | "PUSHn @R1(-3, -3)",
98 | dis(opts, cur, &[&[byte(1, 0, OpCode::PUSHn), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat())
99 | );
100 |
101 | assert_eq!("POP32 R1", dis(opts, cur, &[OpCode::POP.to(), 0b00000001]));
102 | assert_eq!("PUSH32 R1", dis(opts, cur, &[OpCode::PUSH.to(), 0b00000001]));
103 | assert_eq!("POP32 @R1", dis(opts, cur, &[OpCode::POP.to(), 0b00001001]));
104 | assert_eq!("PUSH32 @R1", dis(opts, cur, &[OpCode::PUSH.to(), 0b00001001]));
105 |
106 | assert_eq!(
107 | "POP32 R1 -3",
108 | dis(opts, cur, &[&[byte(1, 0, OpCode::POP), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat())
109 | );
110 |
111 | assert_eq!(
112 | "PUSH32 R1 -3",
113 | dis(opts, cur, &[&[byte(1, 0, OpCode::PUSH), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat())
114 | );
115 |
116 | assert_eq!(
117 | "POP32 @R1(-3, -3)",
118 | dis(opts, cur, &[&[byte(1, 0, OpCode::POP), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat())
119 | );
120 |
121 | assert_eq!(
122 | "PUSH32 @R1(-3, -3)",
123 | dis(opts, cur, &[&[byte(1, 0, OpCode::PUSH), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat())
124 | );
125 |
126 | assert_eq!("POP64 R1", dis(opts, cur, &[byte(0, 1, OpCode::POP), 0b00000001]));
127 |
128 | assert_eq!("PUSH64 R1", dis(opts, cur, &[byte(0, 1, OpCode::PUSH), 0b00000001]));
129 |
130 | assert_eq!("POP64 @R1", dis(opts, cur, &[byte(0, 1, OpCode::POP), 0b00001001]));
131 |
132 | assert_eq!("PUSH64 @R1", dis(opts, cur, &[byte(0, 1, OpCode::PUSH), 0b00001001]));
133 |
134 | assert_eq!(
135 | "POP64 R1 -3",
136 | dis(opts, cur, &[&[byte(1, 1, OpCode::POP), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat())
137 | );
138 |
139 | assert_eq!(
140 | "PUSH64 R1 -3",
141 | dis(opts, cur, &[&[byte(1, 1, OpCode::PUSH), 0b00000001][..], &(-3i16).to_le_bytes()[..],].concat())
142 | );
143 |
144 | assert_eq!(
145 | "POP64 @R1(-3, -3)",
146 | dis(opts, cur, &[&[byte(1, 1, OpCode::POP), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat())
147 | );
148 |
149 | assert_eq!(
150 | "PUSH64 @R1(-3, -3)",
151 | dis(opts, cur, &[&[byte(1, 1, OpCode::PUSH), 0b00001001][..], &(36879u16).to_le_bytes()[..],].concat())
152 | );
153 |
154 | assert_eq!("CALL32 R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00010001]));
155 | assert_eq!("CALL32a R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00000001]));
156 |
157 | assert_eq!(
158 | "CALL32 R1 -3",
159 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00010001][..], &(-3i32).to_le_bytes()[..],].concat())
160 | );
161 |
162 | assert_eq!(
163 | "CALL32a R1 -3",
164 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00000001][..], &(-3i32).to_le_bytes()[..],].concat())
165 | );
166 |
167 | assert_eq!(
168 | "CALL32 @R1(-300, -300)",
169 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00011001][..], &(2954019116u32).to_le_bytes()[..],].concat())
170 | );
171 |
172 | assert_eq!("CALL32 @R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00011001]));
173 |
174 | assert_eq!(
175 | "CALL32a @R1(-300, -300)",
176 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00001001][..], &(2954019116u32).to_le_bytes()[..],].concat())
177 | );
178 |
179 | assert_eq!("CALL32EX R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00110001]));
180 | assert_eq!("CALL32EXa R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00100001]));
181 | assert_eq!("CALL32EX @R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00111001]));
182 | assert_eq!("CALL32EXa @R1", dis(opts, cur, &[OpCode::CALL.to(), 0b00101001]));
183 |
184 | assert_eq!(
185 | "CALL32EX R1 -3",
186 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00110001][..], &(-3i32).to_le_bytes()[..],].concat())
187 | );
188 |
189 | assert_eq!(
190 | "CALL32EXa R1 -3",
191 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00100001][..], &(-3i32).to_le_bytes()[..],].concat())
192 | );
193 |
194 | assert_eq!(
195 | "CALL32EX @R1(-300, -300)",
196 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00111001][..], &(2954019116u32).to_le_bytes()[..],].concat())
197 | );
198 |
199 | assert_eq!(
200 | "CALL32EXa @R1(-300, -300)",
201 | dis(opts, cur, &[&[byte(1, 0, OpCode::CALL), 0b00101001][..], &(2954019116u32).to_le_bytes()[..],].concat())
202 | );
203 |
204 | assert_eq!(
205 | "CALL64EXa -3",
206 | dis(opts, cur, &[&[byte(1, 1, OpCode::CALL), 0b00110001][..], &(-3i64).to_le_bytes()[..],].concat())
207 | );
208 |
209 | assert_eq!("JMP32 R1 ;; Absolute Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b00000001]));
210 |
211 | assert_eq!("JMP32cc R1 ;; Absolute Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b10000001]));
212 |
213 | assert_eq!("JMP32cs R1 ;; Absolute Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b11000001]));
214 |
215 | assert_eq!("JMP32 R1 ;; Relative Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b00010001]));
216 |
217 | assert_eq!("JMP32cc R1 ;; Relative Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b10010001]));
218 |
219 | assert_eq!("JMP32cs R1 ;; Relative Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b11010001]));
220 |
221 | assert_eq!("JMP32 @R1 ;; Relative Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b00011001]));
222 |
223 | assert_eq!("JMP32 @R1 ;; Absolute Address", dis(opts, cur, &[byte(0, 0, OpCode::JMP), 0b00001001]));
224 |
225 | assert_eq!("MOVb R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVbw), 0b00100001]));
226 |
227 | assert_eq!("MOVw R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVww), 0b00100001]));
228 |
229 | assert_eq!("MOVd R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVdw), 0b00100001]));
230 |
231 | assert_eq!("MOVq R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVqw), 0b00100001]));
232 |
233 | assert_eq!("MOVb @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVbw), 0b00101001]));
234 |
235 | assert_eq!("MOVw @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVww), 0b00101001]));
236 |
237 | assert_eq!("MOVd @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVdw), 0b00101001]));
238 |
239 | assert_eq!("MOVq @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVqw), 0b00101001]));
240 |
241 | assert_eq!("MOVb R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVbw), 0b10100001]));
242 |
243 | assert_eq!("MOVw R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVww), 0b10100001]));
244 |
245 | assert_eq!("MOVd R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVdw), 0b10100001]));
246 |
247 | assert_eq!("MOVq R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVqw), 0b10100001]));
248 |
249 | assert_eq!("MOVb @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVbw), 0b10101001]));
250 |
251 | assert_eq!("MOVw @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVww), 0b10101001]));
252 |
253 | assert_eq!("MOVd @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVdw), 0b10101001]));
254 |
255 | assert_eq!("MOVq @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOVqw), 0b10101001]));
256 |
257 | assert_eq!("ADD32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::ADD), 0b00100001]));
258 |
259 | assert_eq!("ADD32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::ADD), 0b00101001]));
260 |
261 | assert_eq!("ADD32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::ADD), 0b10100001]));
262 |
263 | assert_eq!("ADD32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::ADD), 0b10101001]));
264 |
265 | assert_eq!("ADD64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::ADD), 0b00100001]));
266 |
267 | assert_eq!("ADD64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::ADD), 0b00101001]));
268 |
269 | assert_eq!("ADD64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::ADD), 0b10100001]));
270 |
271 | assert_eq!("ADD64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::ADD), 0b10101001]));
272 |
273 | assert_eq!("AND32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::AND), 0b00100001]));
274 |
275 | assert_eq!("AND32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::AND), 0b00101001]));
276 |
277 | assert_eq!("AND32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::AND), 0b10100001]));
278 |
279 | assert_eq!("AND32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::AND), 0b10101001]));
280 |
281 | assert_eq!("AND64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::AND), 0b00100001]));
282 |
283 | assert_eq!("AND64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::AND), 0b00101001]));
284 |
285 | assert_eq!("AND64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::AND), 0b10100001]));
286 |
287 | assert_eq!("AND64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::AND), 0b10101001]));
288 |
289 | assert_eq!("ASHR32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::ASHR), 0b00100001]));
290 |
291 | assert_eq!("ASHR32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::ASHR), 0b00101001]));
292 |
293 | assert_eq!("ASHR32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::ASHR), 0b10100001]));
294 |
295 | assert_eq!("ASHR32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::ASHR), 0b10101001]));
296 |
297 | assert_eq!("ASHR64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::ASHR), 0b00100001]));
298 |
299 | assert_eq!("ASHR64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::ASHR), 0b00101001]));
300 |
301 | assert_eq!("ASHR64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::ASHR), 0b10100001]));
302 |
303 | assert_eq!("ASHR64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::ASHR), 0b10101001]));
304 |
305 | assert_eq!("DIV32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::DIV), 0b00100001]));
306 |
307 | assert_eq!("DIV32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::DIV), 0b00101001]));
308 |
309 | assert_eq!("DIV32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::DIV), 0b10100001]));
310 |
311 | assert_eq!("DIV32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::DIV), 0b10101001]));
312 |
313 | assert_eq!("DIV64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::DIV), 0b00100001]));
314 |
315 | assert_eq!("DIV64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::DIV), 0b00101001]));
316 |
317 | assert_eq!("DIV64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::DIV), 0b10100001]));
318 |
319 | assert_eq!("DIV64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::DIV), 0b10101001]));
320 |
321 | assert_eq!("DIVU32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::DIVU), 0b00100001]));
322 |
323 | assert_eq!("DIVU32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::DIVU), 0b00101001]));
324 |
325 | assert_eq!("DIVU32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::DIVU), 0b10100001]));
326 |
327 | assert_eq!("DIVU32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::DIVU), 0b10101001]));
328 |
329 | assert_eq!("DIVU64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::DIVU), 0b00100001]));
330 |
331 | assert_eq!("DIVU64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::DIVU), 0b00101001]));
332 |
333 | assert_eq!("DIVU64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::DIVU), 0b10100001]));
334 |
335 | assert_eq!("DIVU64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::DIVU), 0b10101001]));
336 |
337 | assert_eq!("EXTNDB32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDB), 0b00100001]));
338 |
339 | assert_eq!("EXTNDB32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDB), 0b00101001]));
340 |
341 | assert_eq!("EXTNDB32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDB), 0b10100001]));
342 |
343 | assert_eq!("EXTNDB32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDB), 0b10101001]));
344 |
345 | assert_eq!("EXTNDB64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDB), 0b00100001]));
346 |
347 | assert_eq!("EXTNDB64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDB), 0b00101001]));
348 |
349 | assert_eq!("EXTNDB64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDB), 0b10100001]));
350 |
351 | assert_eq!("EXTNDB64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDB), 0b10101001]));
352 |
353 | assert_eq!("EXTNDD32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDD), 0b00100001]));
354 |
355 | assert_eq!("EXTNDD32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDD), 0b00101001]));
356 |
357 | assert_eq!("EXTNDD32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDD), 0b10100001]));
358 |
359 | assert_eq!("EXTNDD32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDD), 0b10101001]));
360 |
361 | assert_eq!("EXTNDD64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDD), 0b00100001]));
362 |
363 | assert_eq!("EXTNDD64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDD), 0b00101001]));
364 |
365 | assert_eq!("EXTNDD64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDD), 0b10100001]));
366 |
367 | assert_eq!("EXTNDD64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDD), 0b10101001]));
368 |
369 | assert_eq!("EXTNDW32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDW), 0b00100001]));
370 |
371 | assert_eq!("EXTNDW32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDW), 0b00101001]));
372 |
373 | assert_eq!("EXTNDW32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDW), 0b10100001]));
374 |
375 | assert_eq!("EXTNDW32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::EXTNDW), 0b10101001]));
376 |
377 | assert_eq!("EXTNDW64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDW), 0b00100001]));
378 |
379 | assert_eq!("EXTNDW64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDW), 0b00101001]));
380 |
381 | assert_eq!("EXTNDW64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDW), 0b10100001]));
382 |
383 | assert_eq!("EXTNDW64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::EXTNDW), 0b10101001]));
384 |
385 | assert_eq!("MOD32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOD), 0b00100001]));
386 |
387 | assert_eq!("MOD32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MOD), 0b00101001]));
388 |
389 | assert_eq!("MOD32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOD), 0b10100001]));
390 |
391 | assert_eq!("MOD32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MOD), 0b10101001]));
392 |
393 | assert_eq!("MOD64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MOD), 0b00100001]));
394 |
395 | assert_eq!("MOD64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MOD), 0b00101001]));
396 |
397 | assert_eq!("MOD64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MOD), 0b10100001]));
398 |
399 | assert_eq!("MOD64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MOD), 0b10101001]));
400 |
401 | assert_eq!("MODU32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MODU), 0b00100001]));
402 |
403 | assert_eq!("MODU32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MODU), 0b00101001]));
404 |
405 | assert_eq!("MODU32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MODU), 0b10100001]));
406 |
407 | assert_eq!("MODU32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MODU), 0b10101001]));
408 |
409 | assert_eq!("MODU64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MODU), 0b00100001]));
410 |
411 | assert_eq!("MODU64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MODU), 0b00101001]));
412 |
413 | assert_eq!("MODU64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MODU), 0b10100001]));
414 |
415 | assert_eq!("MODU64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MODU), 0b10101001]));
416 |
417 | assert_eq!("SHL32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SHL), 0b00100001]));
418 |
419 | assert_eq!("SHL32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SHL), 0b00101001]));
420 |
421 | assert_eq!("SHL32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SHL), 0b10100001]));
422 |
423 | assert_eq!("SHL32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SHL), 0b10101001]));
424 |
425 | assert_eq!("SHL64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SHL), 0b00100001]));
426 |
427 | assert_eq!("SHL64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SHL), 0b00101001]));
428 |
429 | assert_eq!("SHL64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SHL), 0b10100001]));
430 |
431 | assert_eq!("SHL64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SHL), 0b10101001]));
432 |
433 | assert_eq!("SHR32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SHR), 0b00100001]));
434 |
435 | assert_eq!("SHR32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SHR), 0b00101001]));
436 |
437 | assert_eq!("SHR32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SHR), 0b10100001]));
438 |
439 | assert_eq!("SHR32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SHR), 0b10101001]));
440 |
441 | assert_eq!("SHR64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SHR), 0b00100001]));
442 |
443 | assert_eq!("SHR64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SHR), 0b00101001]));
444 |
445 | assert_eq!("SHR64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SHR), 0b10100001]));
446 |
447 | assert_eq!("SHR64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SHR), 0b10101001]));
448 |
449 | assert_eq!("SUB32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SUB), 0b00100001]));
450 |
451 | assert_eq!("SUB32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::SUB), 0b00101001]));
452 |
453 | assert_eq!("SUB32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SUB), 0b10100001]));
454 |
455 | assert_eq!("SUB32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::SUB), 0b10101001]));
456 |
457 | assert_eq!("SUB64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SUB), 0b00100001]));
458 |
459 | assert_eq!("SUB64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::SUB), 0b00101001]));
460 |
461 | assert_eq!("SUB64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SUB), 0b10100001]));
462 |
463 | assert_eq!("SUB64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::SUB), 0b10101001]));
464 |
465 | assert_eq!("XOR32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::XOR), 0b00100001]));
466 |
467 | assert_eq!("XOR32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::XOR), 0b00101001]));
468 |
469 | assert_eq!("XOR32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::XOR), 0b10100001]));
470 |
471 | assert_eq!("XOR32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::XOR), 0b10101001]));
472 |
473 | assert_eq!("XOR64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::XOR), 0b00100001]));
474 |
475 | assert_eq!("XOR64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::XOR), 0b00101001]));
476 |
477 | assert_eq!("XOR64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::XOR), 0b10100001]));
478 |
479 | assert_eq!("XOR64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::XOR), 0b10101001]));
480 |
481 | assert_eq!("CMPeq32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPeq), 0b00100001]));
482 |
483 | assert_eq!("CMPeq32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPeq), 0b00101001]));
484 |
485 | assert_eq!("CMPeq32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPeq), 0b10100001]));
486 |
487 | assert_eq!("CMPeq32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPeq), 0b10101001]));
488 |
489 | assert_eq!("CMPeq64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPeq), 0b00100001]));
490 |
491 | assert_eq!("CMPeq64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPeq), 0b00101001]));
492 |
493 | assert_eq!("CMPeq64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPeq), 0b10100001]));
494 |
495 | assert_eq!("CMPeq64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPeq), 0b10101001]));
496 |
497 | assert_eq!("CMPlte32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPlte), 0b00100001]));
498 |
499 | assert_eq!("CMPlte32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPlte), 0b00101001]));
500 |
501 | assert_eq!("CMPlte32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPlte), 0b10100001]));
502 |
503 | assert_eq!("CMPlte32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPlte), 0b10101001]));
504 |
505 | assert_eq!("CMPlte64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPlte), 0b00100001]));
506 |
507 | assert_eq!("CMPlte64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPlte), 0b00101001]));
508 |
509 | assert_eq!("CMPlte64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPlte), 0b10100001]));
510 |
511 | assert_eq!("CMPlte64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPlte), 0b10101001]));
512 |
513 | assert_eq!("CMPgte32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPgte), 0b00100001]));
514 |
515 | assert_eq!("CMPgte32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPgte), 0b00101001]));
516 |
517 | assert_eq!("CMPgte32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPgte), 0b10100001]));
518 |
519 | assert_eq!("CMPgte32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPgte), 0b10101001]));
520 |
521 | assert_eq!("CMPgte64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPgte), 0b00100001]));
522 |
523 | assert_eq!("CMPgte64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPgte), 0b00101001]));
524 |
525 | assert_eq!("CMPgte64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPgte), 0b10100001]));
526 |
527 | assert_eq!("CMPgte64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPgte), 0b10101001]));
528 |
529 | assert_eq!("CMPulte32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPulte), 0b00100001]));
530 |
531 | assert_eq!("CMPulte32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPulte), 0b00101001]));
532 |
533 | assert_eq!("CMPulte32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPulte), 0b10100001]));
534 |
535 | assert_eq!("CMPulte32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPulte), 0b10101001]));
536 |
537 | assert_eq!("CMPulte64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPulte), 0b00100001]));
538 |
539 | assert_eq!("CMPulte64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPulte), 0b00101001]));
540 |
541 | assert_eq!("CMPulte64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPulte), 0b10100001]));
542 |
543 | assert_eq!("CMPulte64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPulte), 0b10101001]));
544 |
545 | assert_eq!("CMPugte32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPugte), 0b00100001]));
546 |
547 | assert_eq!("CMPugte32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPugte), 0b00101001]));
548 |
549 | assert_eq!("CMPugte32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPugte), 0b10100001]));
550 |
551 | assert_eq!("CMPugte32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::CMPugte), 0b10101001]));
552 |
553 | assert_eq!("CMPugte64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPugte), 0b00100001]));
554 |
555 | assert_eq!("CMPugte64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPugte), 0b00101001]));
556 |
557 | assert_eq!("CMPugte64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPugte), 0b10100001]));
558 |
559 | assert_eq!("CMPugte64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::CMPugte), 0b10101001]));
560 |
561 | assert_eq!("MUL32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MUL), 0b00100001]));
562 |
563 | assert_eq!("MUL32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MUL), 0b00101001]));
564 |
565 | assert_eq!("MUL32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MUL), 0b10100001]));
566 |
567 | assert_eq!("MUL32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MUL), 0b10101001]));
568 |
569 | assert_eq!("MUL64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MUL), 0b00100001]));
570 |
571 | assert_eq!("MUL64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MUL), 0b00101001]));
572 |
573 | assert_eq!("MUL64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MUL), 0b10100001]));
574 |
575 | assert_eq!("MUL64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MUL), 0b10101001]));
576 |
577 | assert_eq!("MULU32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MULU), 0b00100001]));
578 |
579 | assert_eq!("MULU32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::MULU), 0b00101001]));
580 |
581 | assert_eq!("MULU32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MULU), 0b10100001]));
582 |
583 | assert_eq!("MULU32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::MULU), 0b10101001]));
584 |
585 | assert_eq!("MULU64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MULU), 0b00100001]));
586 |
587 | assert_eq!("MULU64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::MULU), 0b00101001]));
588 |
589 | assert_eq!("MULU64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MULU), 0b10100001]));
590 |
591 | assert_eq!("MULU64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::MULU), 0b10101001]));
592 |
593 | assert_eq!("NEG32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::NEG), 0b00100001]));
594 |
595 | assert_eq!("NEG32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::NEG), 0b00101001]));
596 |
597 | assert_eq!("NEG32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::NEG), 0b10100001]));
598 |
599 | assert_eq!("NEG32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::NEG), 0b10101001]));
600 |
601 | assert_eq!("NEG64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::NEG), 0b00100001]));
602 |
603 | assert_eq!("NEG64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::NEG), 0b00101001]));
604 |
605 | assert_eq!("NEG64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::NEG), 0b10100001]));
606 |
607 | assert_eq!("NEG64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::NEG), 0b10101001]));
608 |
609 | assert_eq!("NOT32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::NOT), 0b00100001]));
610 |
611 | assert_eq!("NOT32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::NOT), 0b00101001]));
612 |
613 | assert_eq!("NOT32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::NOT), 0b10100001]));
614 |
615 | assert_eq!("NOT32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::NOT), 0b10101001]));
616 |
617 | assert_eq!("NOT64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::NOT), 0b00100001]));
618 |
619 | assert_eq!("NOT64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::NOT), 0b00101001]));
620 |
621 | assert_eq!("NOT64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::NOT), 0b10100001]));
622 |
623 | assert_eq!("NOT64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::NOT), 0b10101001]));
624 |
625 | assert_eq!("OR32 R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::OR), 0b00100001]));
626 |
627 | assert_eq!("OR32 @R1, R2", dis(opts, cur, &[byte(0, 0, OpCode::OR), 0b00101001]));
628 |
629 | assert_eq!("OR32 R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::OR), 0b10100001]));
630 |
631 | assert_eq!("OR32 @R1, @R2", dis(opts, cur, &[byte(0, 0, OpCode::OR), 0b10101001]));
632 |
633 | assert_eq!("OR64 R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::OR), 0b00100001]));
634 |
635 | assert_eq!("OR64 @R1, R2", dis(opts, cur, &[byte(0, 1, OpCode::OR), 0b00101001]));
636 |
637 | assert_eq!("OR64 R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::OR), 0b10100001]));
638 |
639 | assert_eq!("OR64 @R1, @R2", dis(opts, cur, &[byte(0, 1, OpCode::OR), 0b10101001]));
640 |
641 | assert_eq!(
642 | "JMP32 R1 -3 ;; Absolute Address",
643 | dis(opts, cur, &[&[byte(1, 0, OpCode::JMP), 0b00000001][..], &(-3i32).to_le_bytes()[..],].concat())
644 | );
645 |
646 | assert_eq!(
647 | "JMP32 R1 -3 ;; Relative Address",
648 | dis(opts, cur, &[&[byte(1, 0, OpCode::JMP), 0b00010001][..], &(-3i32).to_le_bytes()[..],].concat())
649 | );
650 |
651 | assert_eq!(
652 | "JMP32 @R1(-300, -300) ;; Absolute Address",
653 | dis(opts, cur, &[&[byte(1, 0, OpCode::JMP), 0b00001001][..], &(2954019116u32).to_le_bytes()[..],].concat())
654 | );
655 |
656 | assert_eq!(
657 | "JMP32 @R1(-300, -300) ;; Relative Address",
658 | dis(opts, cur, &[&[byte(1, 0, OpCode::JMP), 0b00011001][..], &(2954019116u32).to_le_bytes()[..],].concat())
659 | );
660 |
661 | assert_eq!(
662 | "JMP64 1000 ;; Absolute Address",
663 | dis(opts, cur, &[&[byte(0, 1, OpCode::JMP), 0b00000001][..], &(1000u64).to_le_bytes()[..],].concat())
664 | );
665 |
666 | assert_eq!(
667 | "JMP64 1000 ;; Relative Address",
668 | dis(opts, cur, &[&[byte(0, 1, OpCode::JMP), 0b00010001][..], &(1000u64).to_le_bytes()[..],].concat())
669 | );
670 |
671 | assert_eq!(
672 | "MOVIbw R1, 1000",
673 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVI), 0b00000001][..], &(1000u16).to_le_bytes()[..],].concat())
674 | );
675 |
676 | assert_eq!(
677 | "MOVIww R1, 1000",
678 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVI), 0b00010001][..], &(1000u16).to_le_bytes()[..],].concat())
679 | );
680 |
681 | assert_eq!(
682 | "MOVIdw R1, 1000",
683 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVI), 0b00100001][..], &(1000u16).to_le_bytes()[..],].concat())
684 | );
685 |
686 | assert_eq!(
687 | "MOVIqw R1, 1000",
688 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVI), 0b00110001][..], &(1000u16).to_le_bytes()[..],].concat())
689 | );
690 |
691 | assert_eq!(
692 | "MOVIbd R1, 1000",
693 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVI), 0b00000001][..], &(1000u32).to_le_bytes()[..],].concat())
694 | );
695 |
696 | assert_eq!(
697 | "MOVIwd R1, 1000",
698 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVI), 0b00010001][..], &(1000u32).to_le_bytes()[..],].concat())
699 | );
700 |
701 | assert_eq!(
702 | "MOVIdd R1, 1000",
703 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVI), 0b00100001][..], &(1000u32).to_le_bytes()[..],].concat())
704 | );
705 |
706 | assert_eq!(
707 | "MOVIqd R1, 1000",
708 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVI), 0b00110001][..], &(1000u32).to_le_bytes()[..],].concat())
709 | );
710 |
711 | assert_eq!(
712 | "MOVIbq R1, 1000",
713 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOVI), 0b00000001][..], &(1000u64).to_le_bytes()[..],].concat())
714 | );
715 |
716 | assert_eq!(
717 | "MOVIwq R1, 1000",
718 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOVI), 0b00010001][..], &(1000u64).to_le_bytes()[..],].concat())
719 | );
720 |
721 | assert_eq!(
722 | "MOVIdq R1, 1000",
723 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOVI), 0b00100001][..], &(1000u64).to_le_bytes()[..],].concat())
724 | );
725 |
726 | assert_eq!(
727 | "MOVIqq R1, 1000",
728 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOVI), 0b00110001][..], &(1000u64).to_le_bytes()[..],].concat())
729 | );
730 |
731 | assert_eq!(
732 | "CMPI32weq R1, -1000",
733 | dis(opts, cur, &[&[byte(0, 0, OpCode::CMPIeq), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat())
734 | );
735 |
736 | assert_eq!(
737 | "CMPI64weq R1, -1000",
738 | dis(opts, cur, &[&[byte(0, 1, OpCode::CMPIeq), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat())
739 | );
740 |
741 | assert_eq!(
742 | "CMPI32wlte R1, -1000",
743 | dis(opts, cur, &[&[byte(0, 0, OpCode::CMPIlte), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat())
744 | );
745 |
746 | assert_eq!(
747 | "CMPI64wlte R1, -1000",
748 | dis(opts, cur, &[&[byte(0, 1, OpCode::CMPIlte), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat())
749 | );
750 |
751 | assert_eq!(
752 | "CMPI32wgte R1, -1000",
753 | dis(opts, cur, &[&[byte(0, 0, OpCode::CMPIgte), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat())
754 | );
755 |
756 | assert_eq!(
757 | "CMPI64wgte R1, -1000",
758 | dis(opts, cur, &[&[byte(0, 1, OpCode::CMPIgte), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat())
759 | );
760 |
761 | assert_eq!(
762 | "CMPI32wulte R1, 1000",
763 | dis(opts, cur, &[&[byte(0, 0, OpCode::CMPIulte), 0b00000001][..], &(1000u16).to_le_bytes()[..],].concat())
764 | );
765 |
766 | assert_eq!(
767 | "CMPI64wulte R1, 1000",
768 | dis(opts, cur, &[&[byte(0, 1, OpCode::CMPIulte), 0b00000001][..], &(1000u16).to_le_bytes()[..],].concat())
769 | );
770 |
771 | assert_eq!(
772 | "CMPI32wugte R1, 1000",
773 | dis(opts, cur, &[&[byte(0, 0, OpCode::CMPIugte), 0b00000001][..], &(1000u16).to_le_bytes()[..],].concat())
774 | );
775 |
776 | assert_eq!(
777 | "CMPI64wugte R1, 1000",
778 | dis(opts, cur, &[&[byte(0, 1, OpCode::CMPIugte), 0b00000001][..], &(1000u16).to_le_bytes()[..],].concat())
779 | );
780 |
781 | assert_eq!(
782 | "CMPI32deq R1, -1000",
783 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPIeq), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat())
784 | );
785 |
786 | assert_eq!(
787 | "CMPI64deq R1, -1000",
788 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPIeq), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat())
789 | );
790 |
791 | assert_eq!(
792 | "CMPI32dlte R1, -1000",
793 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPIlte), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat())
794 | );
795 |
796 | assert_eq!(
797 | "CMPI64dlte R1, -1000",
798 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPIlte), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat())
799 | );
800 |
801 | assert_eq!(
802 | "CMPI32dgte R1, -1000",
803 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPIgte), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat())
804 | );
805 |
806 | assert_eq!(
807 | "CMPI64dgte R1, -1000",
808 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPIgte), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat())
809 | );
810 |
811 | assert_eq!(
812 | "CMPI32dulte R1, 1000",
813 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPIulte), 0b00000001][..], &(1000u32).to_le_bytes()[..],].concat())
814 | );
815 |
816 | assert_eq!(
817 | "CMPI64dulte R1, 1000",
818 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPIulte), 0b00000001][..], &(1000u32).to_le_bytes()[..],].concat())
819 | );
820 |
821 | assert_eq!(
822 | "CMPI32dugte R1, 1000",
823 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPIugte), 0b00000001][..], &(1000u32).to_le_bytes()[..],].concat())
824 | );
825 |
826 | assert_eq!(
827 | "CMPI64dugte R1, 1000",
828 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPIugte), 0b00000001][..], &(1000u32).to_le_bytes()[..],].concat())
829 | );
830 |
831 | assert_eq!(
832 | "CMPI32weq @R1(-3, -3), -1000",
833 | dis(
834 | opts,
835 | cur,
836 | &[
837 | &[byte(0, 0, OpCode::CMPIeq), 0b00011001][..],
838 | &(36879u16).to_le_bytes()[..],
839 | &(-1000i16).to_le_bytes()[..],
840 | ]
841 | .concat()
842 | )
843 | );
844 |
845 | assert_eq!(
846 | "CMPI64weq @R1(-3, -3), -1000",
847 | dis(
848 | opts,
849 | cur,
850 | &[
851 | &[byte(0, 1, OpCode::CMPIeq), 0b00011001][..],
852 | &(36879u16).to_le_bytes()[..],
853 | &(-1000i16).to_le_bytes()[..],
854 | ]
855 | .concat()
856 | )
857 | );
858 |
859 | assert_eq!(
860 | "CMPI32wlte @R1(-3, -3), -1000",
861 | dis(
862 | opts,
863 | cur,
864 | &[
865 | &[byte(0, 0, OpCode::CMPIlte), 0b00011001][..],
866 | &(36879u16).to_le_bytes()[..],
867 | &(-1000i16).to_le_bytes()[..],
868 | ]
869 | .concat()
870 | )
871 | );
872 |
873 | assert_eq!(
874 | "CMPI64wlte @R1(-3, -3), -1000",
875 | dis(
876 | opts,
877 | cur,
878 | &[
879 | &[byte(0, 1, OpCode::CMPIlte), 0b00011001][..],
880 | &(36879u16).to_le_bytes()[..],
881 | &(-1000i16).to_le_bytes()[..],
882 | ]
883 | .concat()
884 | )
885 | );
886 |
887 | assert_eq!(
888 | "CMPI32wgte @R1(-3, -3), -1000",
889 | dis(
890 | opts,
891 | cur,
892 | &[
893 | &[byte(0, 0, OpCode::CMPIgte), 0b00011001][..],
894 | &(36879u16).to_le_bytes()[..],
895 | &(-1000i16).to_le_bytes()[..],
896 | ]
897 | .concat()
898 | )
899 | );
900 |
901 | assert_eq!(
902 | "CMPI64wgte @R1(-3, -3), -1000",
903 | dis(
904 | opts,
905 | cur,
906 | &[
907 | &[byte(0, 1, OpCode::CMPIgte), 0b00011001][..],
908 | &(36879u16).to_le_bytes()[..],
909 | &(-1000i16).to_le_bytes()[..],
910 | ]
911 | .concat()
912 | )
913 | );
914 |
915 | assert_eq!(
916 | "CMPI32wulte @R1(-3, -3), 1000",
917 | dis(
918 | opts,
919 | cur,
920 | &[
921 | &[byte(0, 0, OpCode::CMPIulte), 0b00011001][..],
922 | &(36879u16).to_le_bytes()[..],
923 | &(1000u16).to_le_bytes()[..],
924 | ]
925 | .concat()
926 | )
927 | );
928 |
929 | assert_eq!(
930 | "CMPI64wulte @R1(-3, -3), 1000",
931 | dis(
932 | opts,
933 | cur,
934 | &[
935 | &[byte(0, 1, OpCode::CMPIulte), 0b00011001][..],
936 | &(36879u16).to_le_bytes()[..],
937 | &(1000u16).to_le_bytes()[..],
938 | ]
939 | .concat()
940 | )
941 | );
942 |
943 | assert_eq!(
944 | "CMPI32wugte @R1(-3, -3), 1000",
945 | dis(
946 | opts,
947 | cur,
948 | &[
949 | &[byte(0, 0, OpCode::CMPIugte), 0b00011001][..],
950 | &(36879u16).to_le_bytes()[..],
951 | &(1000u16).to_le_bytes()[..],
952 | ]
953 | .concat()
954 | )
955 | );
956 |
957 | assert_eq!(
958 | "CMPI64wugte @R1(-3, -3), 1000",
959 | dis(
960 | opts,
961 | cur,
962 | &[
963 | &[byte(0, 1, OpCode::CMPIugte), 0b00011001][..],
964 | &(36879u16).to_le_bytes()[..],
965 | &(1000u16).to_le_bytes()[..],
966 | ]
967 | .concat()
968 | )
969 | );
970 |
971 | assert_eq!(
972 | "CMPI32deq @R1(-3, -3), -1000",
973 | dis(
974 | opts,
975 | cur,
976 | &[
977 | &[byte(1, 0, OpCode::CMPIeq), 0b00011001][..],
978 | &(36879u16).to_le_bytes()[..],
979 | &(-1000i32).to_le_bytes()[..],
980 | ]
981 | .concat()
982 | )
983 | );
984 |
985 | assert_eq!(
986 | "CMPI64deq @R1(-3, -3), -1000",
987 | dis(
988 | opts,
989 | cur,
990 | &[
991 | &[byte(1, 1, OpCode::CMPIeq), 0b00011001][..],
992 | &(36879u16).to_le_bytes()[..],
993 | &(-1000i32).to_le_bytes()[..],
994 | ]
995 | .concat()
996 | )
997 | );
998 |
999 | assert_eq!(
1000 | "CMPI32dlte @R1(-3, -3), -1000",
1001 | dis(
1002 | opts,
1003 | cur,
1004 | &[
1005 | &[byte(1, 0, OpCode::CMPIlte), 0b00011001][..],
1006 | &(36879u16).to_le_bytes()[..],
1007 | &(-1000i32).to_le_bytes()[..],
1008 | ]
1009 | .concat()
1010 | )
1011 | );
1012 |
1013 | assert_eq!(
1014 | "CMPI64dlte @R1(-3, -3), -1000",
1015 | dis(
1016 | opts,
1017 | cur,
1018 | &[
1019 | &[byte(1, 1, OpCode::CMPIlte), 0b00011001][..],
1020 | &(36879u16).to_le_bytes()[..],
1021 | &(-1000i32).to_le_bytes()[..],
1022 | ]
1023 | .concat()
1024 | )
1025 | );
1026 |
1027 | assert_eq!(
1028 | "CMPI32dgte @R1(-3, -3), -1000",
1029 | dis(
1030 | opts,
1031 | cur,
1032 | &[
1033 | &[byte(1, 0, OpCode::CMPIgte), 0b00011001][..],
1034 | &(36879u16).to_le_bytes()[..],
1035 | &(-1000i32).to_le_bytes()[..],
1036 | ]
1037 | .concat()
1038 | )
1039 | );
1040 |
1041 | assert_eq!(
1042 | "CMPI64dgte @R1(-3, -3), -1000",
1043 | dis(
1044 | opts,
1045 | cur,
1046 | &[
1047 | &[byte(1, 1, OpCode::CMPIgte), 0b00011001][..],
1048 | &(36879u16).to_le_bytes()[..],
1049 | &(-1000i32).to_le_bytes()[..],
1050 | ]
1051 | .concat()
1052 | )
1053 | );
1054 |
1055 | assert_eq!(
1056 | "CMPI32dulte @R1(-3, -3), 1000",
1057 | dis(
1058 | opts,
1059 | cur,
1060 | &[
1061 | &[byte(1, 0, OpCode::CMPIulte), 0b00011001][..],
1062 | &(36879u16).to_le_bytes()[..],
1063 | &(1000u32).to_le_bytes()[..],
1064 | ]
1065 | .concat()
1066 | )
1067 | );
1068 |
1069 | assert_eq!(
1070 | "CMPI64dulte @R1(-3, -3), 1000",
1071 | dis(
1072 | opts,
1073 | cur,
1074 | &[
1075 | &[byte(1, 1, OpCode::CMPIulte), 0b00011001][..],
1076 | &(36879u16).to_le_bytes()[..],
1077 | &(1000u32).to_le_bytes()[..],
1078 | ]
1079 | .concat()
1080 | )
1081 | );
1082 |
1083 | assert_eq!(
1084 | "CMPI32dugte @R1(-3, -3), 1000",
1085 | dis(
1086 | opts,
1087 | cur,
1088 | &[
1089 | &[byte(1, 0, OpCode::CMPIugte), 0b00011001][..],
1090 | &(36879u16).to_le_bytes()[..],
1091 | &(1000u32).to_le_bytes()[..],
1092 | ]
1093 | .concat()
1094 | )
1095 | );
1096 |
1097 | assert_eq!(
1098 | "CMPI64dugte @R1(-3, -3), 1000",
1099 | dis(
1100 | opts,
1101 | cur,
1102 | &[
1103 | &[byte(1, 1, OpCode::CMPIugte), 0b00011001][..],
1104 | &(36879u16).to_le_bytes()[..],
1105 | &(1000u32).to_le_bytes()[..],
1106 | ]
1107 | .concat()
1108 | )
1109 | );
1110 |
1111 | assert_eq!(
1112 | "MOVInw R1, (-3, -3)",
1113 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVIn), 0b00000001][..], &(36879u16).to_le_bytes()[..],].concat())
1114 | );
1115 |
1116 | assert_eq!(
1117 | "MOVInd R1, (-300, -300)",
1118 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVIn), 0b00000001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1119 | );
1120 |
1121 | assert_eq!(
1122 | "MOVInq R1, (-30000, -30000)",
1123 | dis(
1124 | opts,
1125 | cur,
1126 | &[&[byte(1, 1, OpCode::MOVIn), 0b00000001][..], &(11529215048034579760u64).to_le_bytes()[..],].concat()
1127 | )
1128 | );
1129 |
1130 | assert_eq!(
1131 | "MOVInw @R1(-3, -3), (-3, -3)",
1132 | dis(
1133 | opts,
1134 | cur,
1135 | &[
1136 | &[byte(0, 1, OpCode::MOVIn), 0b01001001][..],
1137 | &(36879u16).to_le_bytes()[..],
1138 | &(36879u16).to_le_bytes()[..],
1139 | ]
1140 | .concat()
1141 | )
1142 | );
1143 |
1144 | assert_eq!(
1145 | "MOVInd @R1(-3, -3), (-300, -300)",
1146 | dis(
1147 | opts,
1148 | cur,
1149 | &[
1150 | &[byte(1, 0, OpCode::MOVIn), 0b01001001][..],
1151 | &(36879u16).to_le_bytes()[..],
1152 | &(2954019116u32).to_le_bytes()[..],
1153 | ]
1154 | .concat()
1155 | )
1156 | );
1157 |
1158 | assert_eq!(
1159 | "MOVInq @R1(-3, -3), (-30000, -30000)",
1160 | dis(
1161 | opts,
1162 | cur,
1163 | &[
1164 | &[byte(1, 1, OpCode::MOVIn), 0b01001001][..],
1165 | &(36879u16).to_le_bytes()[..],
1166 | &(11529215048034579760u64).to_le_bytes()[..],
1167 | ]
1168 | .concat()
1169 | )
1170 | );
1171 |
1172 | assert_eq!(
1173 | "MOVRELw R1, -1000",
1174 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVREL), 0b00000001][..], &(-1000i16).to_le_bytes()[..],].concat())
1175 | );
1176 |
1177 | assert_eq!(
1178 | "MOVRELd R1, -1000",
1179 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVREL), 0b00000001][..], &(-1000i32).to_le_bytes()[..],].concat())
1180 | );
1181 |
1182 | assert_eq!(
1183 | "MOVRELq R1, -1000",
1184 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOVREL), 0b00000001][..], &(-1000i64).to_le_bytes()[..],].concat())
1185 | );
1186 |
1187 | assert_eq!(
1188 | "MOVRELw @R1(-3, -3), -1000",
1189 | dis(
1190 | opts,
1191 | cur,
1192 | &[
1193 | &[byte(0, 1, OpCode::MOVREL), 0b01001001][..],
1194 | &(36879u16).to_le_bytes()[..],
1195 | &(-1000i16).to_le_bytes()[..],
1196 | ]
1197 | .concat()
1198 | )
1199 | );
1200 |
1201 | assert_eq!(
1202 | "MOVRELd @R1(-3, -3), -1000",
1203 | dis(
1204 | opts,
1205 | cur,
1206 | &[
1207 | &[byte(1, 0, OpCode::MOVREL), 0b01001001][..],
1208 | &(36879u16).to_le_bytes()[..],
1209 | &(-1000i32).to_le_bytes()[..],
1210 | ]
1211 | .concat()
1212 | )
1213 | );
1214 |
1215 | assert_eq!(
1216 | "MOVRELq @R1(-3, -3), -1000",
1217 | dis(
1218 | opts,
1219 | cur,
1220 | &[
1221 | &[byte(1, 1, OpCode::MOVREL), 0b01001001][..],
1222 | &(36879u16).to_le_bytes()[..],
1223 | &(-1000i64).to_le_bytes()[..],
1224 | ]
1225 | .concat()
1226 | )
1227 | );
1228 |
1229 | assert_eq!(
1230 | "MOVnw R1, R2 -1000",
1231 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnw), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1232 | );
1233 |
1234 | assert_eq!(
1235 | "MOVnd R1, R2 -1000",
1236 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnd), 0b00100001][..], &(-1000i32).to_le_bytes()[..],].concat())
1237 | );
1238 |
1239 | assert_eq!(
1240 | "MOVnw @R1, R2 -1000",
1241 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnw), 0b00101001][..], &(-1000i16).to_le_bytes()[..],].concat())
1242 | );
1243 |
1244 | assert_eq!(
1245 | "MOVnd @R1, R2 -1000",
1246 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnd), 0b00101001][..], &(-1000i32).to_le_bytes()[..],].concat())
1247 | );
1248 |
1249 | assert_eq!(
1250 | "MOVnw @R1, @R2(-3, -3)",
1251 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnw), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1252 | );
1253 |
1254 | assert_eq!(
1255 | "MOVnd @R1, @R2(-300, -300)",
1256 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVnd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1257 | );
1258 |
1259 | assert_eq!(
1260 | "MOVnw @R1(-3, -3), R2 -1000",
1261 | dis(
1262 | opts,
1263 | cur,
1264 | &[
1265 | &[byte(1, 1, OpCode::MOVnw), 0b00101001][..],
1266 | &(36879u16).to_le_bytes()[..],
1267 | &(-1000i16).to_le_bytes()[..],
1268 | ]
1269 | .concat()
1270 | )
1271 | );
1272 |
1273 | assert_eq!(
1274 | "MOVnd @R1(-300, -300), R2 -1000",
1275 | dis(
1276 | opts,
1277 | cur,
1278 | &[
1279 | &[byte(1, 1, OpCode::MOVnd), 0b00101001][..],
1280 | &(2954019116u32).to_le_bytes()[..],
1281 | &(-1000i32).to_le_bytes()[..],
1282 | ]
1283 | .concat()
1284 | )
1285 | );
1286 |
1287 | assert_eq!(
1288 | "MOVnw @R1(-3, -3), @R2(-3, -3)",
1289 | dis(
1290 | opts,
1291 | cur,
1292 | &[
1293 | &[byte(1, 1, OpCode::MOVnw), 0b10101001][..],
1294 | &(36879u16).to_le_bytes()[..],
1295 | &(36879u16).to_le_bytes()[..],
1296 | ]
1297 | .concat()
1298 | )
1299 | );
1300 |
1301 | assert_eq!(
1302 | "MOVnd @R1(-300, -300), @R2(-300, -300)",
1303 | dis(
1304 | opts,
1305 | cur,
1306 | &[
1307 | &[byte(1, 1, OpCode::MOVnd), 0b10101001][..],
1308 | &(2954019116u32).to_le_bytes()[..],
1309 | &(2954019116u32).to_le_bytes()[..],
1310 | ]
1311 | .concat()
1312 | )
1313 | );
1314 |
1315 | assert_eq!(
1316 | "MOVsnw R1, R2 -1000",
1317 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnw), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1318 | );
1319 |
1320 | assert_eq!(
1321 | "MOVsnd R1, R2 -1000",
1322 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnd), 0b00100001][..], &(-1000i32).to_le_bytes()[..],].concat())
1323 | );
1324 |
1325 | assert_eq!(
1326 | "MOVsnw @R1, R2 -1000",
1327 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnw), 0b00101001][..], &(-1000i16).to_le_bytes()[..],].concat())
1328 | );
1329 |
1330 | assert_eq!(
1331 | "MOVsnd @R1, R2 -1000",
1332 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnd), 0b00101001][..], &(-1000i32).to_le_bytes()[..],].concat())
1333 | );
1334 |
1335 | assert_eq!(
1336 | "MOVsnw @R1, @R2(-3, -3)",
1337 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnw), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1338 | );
1339 |
1340 | assert_eq!(
1341 | "MOVsnd @R1, @R2(-300, -300)",
1342 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVsnd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1343 | );
1344 |
1345 | assert_eq!(
1346 | "MOVsnw @R1(-3, -3), R2 -1000",
1347 | dis(
1348 | opts,
1349 | cur,
1350 | &[
1351 | &[byte(1, 1, OpCode::MOVsnw), 0b00101001][..],
1352 | &(36879u16).to_le_bytes()[..],
1353 | &(-1000i16).to_le_bytes()[..],
1354 | ]
1355 | .concat()
1356 | )
1357 | );
1358 |
1359 | assert_eq!(
1360 | "MOVsnd @R1(-300, -300), R2 -1000",
1361 | dis(
1362 | opts,
1363 | cur,
1364 | &[
1365 | &[byte(1, 1, OpCode::MOVsnd), 0b00101001][..],
1366 | &(2954019116u32).to_le_bytes()[..],
1367 | &(-1000i32).to_le_bytes()[..],
1368 | ]
1369 | .concat()
1370 | )
1371 | );
1372 |
1373 | assert_eq!(
1374 | "MOVsnw @R1(-3, -3), @R2(-3, -3)",
1375 | dis(
1376 | opts,
1377 | cur,
1378 | &[
1379 | &[byte(1, 1, OpCode::MOVsnw), 0b10101001][..],
1380 | &(36879u16).to_le_bytes()[..],
1381 | &(36879u16).to_le_bytes()[..],
1382 | ]
1383 | .concat()
1384 | )
1385 | );
1386 |
1387 | assert_eq!(
1388 | "MOVsnd @R1(-300, -300), @R2(-300, -300)",
1389 | dis(
1390 | opts,
1391 | cur,
1392 | &[
1393 | &[byte(1, 1, OpCode::MOVsnd), 0b10101001][..],
1394 | &(2954019116u32).to_le_bytes()[..],
1395 | &(2954019116u32).to_le_bytes()[..],
1396 | ]
1397 | .concat()
1398 | )
1399 | );
1400 |
1401 | assert_eq!(
1402 | "MOVbw @R1(-3, -3), R2",
1403 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVbw), 0b00101001][..], &(36879u16).to_le_bytes()[..],].concat())
1404 | );
1405 |
1406 | assert_eq!(
1407 | "MOVww @R1(-3, -3), R2",
1408 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVww), 0b00101001][..], &(36879u16).to_le_bytes()[..],].concat())
1409 | );
1410 |
1411 | assert_eq!(
1412 | "MOVdw @R1(-3, -3), R2",
1413 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVdw), 0b00101001][..], &(36879u16).to_le_bytes()[..],].concat())
1414 | );
1415 |
1416 | assert_eq!(
1417 | "MOVqw @R1(-3, -3), R2",
1418 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVqw), 0b00101001][..], &(36879u16).to_le_bytes()[..],].concat())
1419 | );
1420 |
1421 | assert_eq!(
1422 | "MOVbw @R1(-3, -3), @R2",
1423 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVbw), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1424 | );
1425 |
1426 | assert_eq!(
1427 | "MOVww @R1(-3, -3), @R2",
1428 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVww), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1429 | );
1430 |
1431 | assert_eq!(
1432 | "MOVdw @R1(-3, -3), @R2",
1433 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVdw), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1434 | );
1435 |
1436 | assert_eq!(
1437 | "MOVqw @R1(-3, -3), @R2",
1438 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVqw), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1439 | );
1440 |
1441 | assert_eq!(
1442 | "MOVbw R1, @R2(-3, -3)",
1443 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVbw), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1444 | );
1445 |
1446 | assert_eq!(
1447 | "MOVww R1, @R2(-3, -3)",
1448 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVww), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1449 | );
1450 |
1451 | assert_eq!(
1452 | "MOVdw R1, @R2(-3, -3)",
1453 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVdw), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1454 | );
1455 |
1456 | assert_eq!(
1457 | "MOVqw R1, @R2(-3, -3)",
1458 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVqw), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1459 | );
1460 |
1461 | assert_eq!(
1462 | "MOVbw @R1(-3, -3), @R2(-3, -3)",
1463 | dis(
1464 | opts,
1465 | cur,
1466 | &[
1467 | &[byte(1, 1, OpCode::MOVbw), 0b10101001][..],
1468 | &(36879u16).to_le_bytes()[..],
1469 | &(36879u16).to_le_bytes()[..],
1470 | ]
1471 | .concat()
1472 | )
1473 | );
1474 |
1475 | assert_eq!(
1476 | "MOVww @R1(-3, -3), @R2(-3, -3)",
1477 | dis(
1478 | opts,
1479 | cur,
1480 | &[
1481 | &[byte(1, 1, OpCode::MOVww), 0b10101001][..],
1482 | &(36879u16).to_le_bytes()[..],
1483 | &(36879u16).to_le_bytes()[..],
1484 | ]
1485 | .concat()
1486 | )
1487 | );
1488 |
1489 | assert_eq!(
1490 | "MOVdw @R1(-3, -3), @R2(-3, -3)",
1491 | dis(
1492 | opts,
1493 | cur,
1494 | &[
1495 | &[byte(1, 1, OpCode::MOVdw), 0b10101001][..],
1496 | &(36879u16).to_le_bytes()[..],
1497 | &(36879u16).to_le_bytes()[..],
1498 | ]
1499 | .concat()
1500 | )
1501 | );
1502 |
1503 | assert_eq!(
1504 | "MOVqw @R1(-3, -3), @R2(-3, -3)",
1505 | dis(
1506 | opts,
1507 | cur,
1508 | &[
1509 | &[byte(1, 1, OpCode::MOVqw), 0b10101001][..],
1510 | &(36879u16).to_le_bytes()[..],
1511 | &(36879u16).to_le_bytes()[..],
1512 | ]
1513 | .concat()
1514 | )
1515 | );
1516 |
1517 | assert_eq!(
1518 | "MOVbd @R1(-300, -300), R2",
1519 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVbd), 0b00101001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1520 | );
1521 |
1522 | assert_eq!(
1523 | "MOVwd @R1(-300, -300), R2",
1524 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVwd), 0b00101001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1525 | );
1526 |
1527 | assert_eq!(
1528 | "MOVdd @R1(-300, -300), R2",
1529 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVdd), 0b00101001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1530 | );
1531 |
1532 | assert_eq!(
1533 | "MOVqd @R1(-300, -300), R2",
1534 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVqd), 0b00101001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1535 | );
1536 |
1537 | assert_eq!(
1538 | "MOVbd @R1(-300, -300), @R2",
1539 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVbd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1540 | );
1541 |
1542 | assert_eq!(
1543 | "MOVwd @R1(-300, -300), @R2",
1544 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVwd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1545 | );
1546 |
1547 | assert_eq!(
1548 | "MOVdd @R1(-300, -300), @R2",
1549 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVdd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1550 | );
1551 |
1552 | assert_eq!(
1553 | "MOVqd @R1(-300, -300), @R2",
1554 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOVqd), 0b10101001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1555 | );
1556 |
1557 | assert_eq!(
1558 | "MOVbd R1, @R2(-300, -300)",
1559 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVbd), 0b10100001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1560 | );
1561 |
1562 | assert_eq!(
1563 | "MOVwd R1, @R2(-300, -300)",
1564 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVwd), 0b10100001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1565 | );
1566 |
1567 | assert_eq!(
1568 | "MOVdd R1, @R2(-300, -300)",
1569 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVdd), 0b10100001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1570 | );
1571 |
1572 | assert_eq!(
1573 | "MOVqd R1, @R2(-300, -300)",
1574 | dis(opts, cur, &[&[byte(0, 1, OpCode::MOVqd), 0b10100001][..], &(2954019116u32).to_le_bytes()[..],].concat())
1575 | );
1576 |
1577 | assert_eq!(
1578 | "MOVbd @R1(-300, -300), @R2(-300, -300)",
1579 | dis(
1580 | opts,
1581 | cur,
1582 | &[
1583 | &[byte(1, 1, OpCode::MOVbd), 0b10101001][..],
1584 | &(2954019116u32).to_le_bytes()[..],
1585 | &(2954019116u32).to_le_bytes()[..],
1586 | ]
1587 | .concat()
1588 | )
1589 | );
1590 |
1591 | assert_eq!(
1592 | "MOVwd @R1(-300, -300), @R2(-300, -300)",
1593 | dis(
1594 | opts,
1595 | cur,
1596 | &[
1597 | &[byte(1, 1, OpCode::MOVwd), 0b10101001][..],
1598 | &(2954019116u32).to_le_bytes()[..],
1599 | &(2954019116u32).to_le_bytes()[..],
1600 | ]
1601 | .concat()
1602 | )
1603 | );
1604 |
1605 | assert_eq!(
1606 | "MOVdd @R1(-300, -300), @R2(-300, -300)",
1607 | dis(
1608 | opts,
1609 | cur,
1610 | &[
1611 | &[byte(1, 1, OpCode::MOVdd), 0b10101001][..],
1612 | &(2954019116u32).to_le_bytes()[..],
1613 | &(2954019116u32).to_le_bytes()[..],
1614 | ]
1615 | .concat()
1616 | )
1617 | );
1618 |
1619 | assert_eq!(
1620 | "MOVqd @R1(-300, -300), @R2(-300, -300)",
1621 | dis(
1622 | opts,
1623 | cur,
1624 | &[
1625 | &[byte(1, 1, OpCode::MOVqd), 0b10101001][..],
1626 | &(2954019116u32).to_le_bytes()[..],
1627 | &(2954019116u32).to_le_bytes()[..],
1628 | ]
1629 | .concat()
1630 | )
1631 | );
1632 |
1633 | assert_eq!(
1634 | "MOVqq @R1(-30000, -30000), R2",
1635 | dis(
1636 | opts,
1637 | cur,
1638 | &[&[byte(1, 0, OpCode::MOVqq), 0b00101001][..], &(11529215048034579760u64).to_le_bytes()[..],].concat()
1639 | )
1640 | );
1641 |
1642 | assert_eq!(
1643 | "MOVqq @R1(-30000, -30000), @R2",
1644 | dis(
1645 | opts,
1646 | cur,
1647 | &[&[byte(1, 0, OpCode::MOVqq), 0b10101001][..], &(11529215048034579760u64).to_le_bytes()[..],].concat()
1648 | )
1649 | );
1650 |
1651 | assert_eq!(
1652 | "MOVqq R1, @R2(-30000, -30000)",
1653 | dis(
1654 | opts,
1655 | cur,
1656 | &[&[byte(0, 1, OpCode::MOVqq), 0b10100001][..], &(11529215048034579760u64).to_le_bytes()[..],].concat()
1657 | )
1658 | );
1659 |
1660 | assert_eq!(
1661 | "MOVqq @R1(-30000, -30000), @R2(-30000, -30000)",
1662 | dis(
1663 | opts,
1664 | cur,
1665 | &[
1666 | &[byte(1, 1, OpCode::MOVqq), 0b10101001][..],
1667 | &(11529215048034579760u64).to_le_bytes()[..],
1668 | &(11529215048034579760u64).to_le_bytes()[..],
1669 | ]
1670 | .concat()
1671 | )
1672 | );
1673 |
1674 | assert_eq!(
1675 | "ADD32 R1, R2 -1000",
1676 | dis(opts, cur, &[&[byte(1, 0, OpCode::ADD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1677 | );
1678 |
1679 | assert_eq!(
1680 | "ADD32 R1, @R2(-3, -3)",
1681 | dis(opts, cur, &[&[byte(1, 0, OpCode::ADD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1682 | );
1683 |
1684 | assert_eq!(
1685 | "ADD32 @R1, @R2(-3, -3)",
1686 | dis(opts, cur, &[&[byte(1, 0, OpCode::ADD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1687 | );
1688 |
1689 | assert_eq!(
1690 | "ADD64 R1, R2 -1000",
1691 | dis(opts, cur, &[&[byte(1, 1, OpCode::ADD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1692 | );
1693 |
1694 | assert_eq!(
1695 | "ADD64 R1, @R2(-3, -3)",
1696 | dis(opts, cur, &[&[byte(1, 1, OpCode::ADD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1697 | );
1698 |
1699 | assert_eq!(
1700 | "ADD64 @R1, @R2(-3, -3)",
1701 | dis(opts, cur, &[&[byte(1, 1, OpCode::ADD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1702 | );
1703 |
1704 | assert_eq!(
1705 | "AND32 R1, R2 -1000",
1706 | dis(opts, cur, &[&[byte(1, 0, OpCode::AND), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1707 | );
1708 |
1709 | assert_eq!(
1710 | "AND32 R1, @R2(-3, -3)",
1711 | dis(opts, cur, &[&[byte(1, 0, OpCode::AND), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1712 | );
1713 |
1714 | assert_eq!(
1715 | "AND32 @R1, @R2(-3, -3)",
1716 | dis(opts, cur, &[&[byte(1, 0, OpCode::AND), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1717 | );
1718 |
1719 | assert_eq!(
1720 | "AND64 R1, R2 -1000",
1721 | dis(opts, cur, &[&[byte(1, 1, OpCode::AND), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1722 | );
1723 |
1724 | assert_eq!(
1725 | "AND64 R1, @R2(-3, -3)",
1726 | dis(opts, cur, &[&[byte(1, 1, OpCode::AND), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1727 | );
1728 |
1729 | assert_eq!(
1730 | "AND64 @R1, @R2(-3, -3)",
1731 | dis(opts, cur, &[&[byte(1, 1, OpCode::AND), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1732 | );
1733 |
1734 | assert_eq!(
1735 | "ASHR32 R1, R2 -1000",
1736 | dis(opts, cur, &[&[byte(1, 0, OpCode::ASHR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1737 | );
1738 |
1739 | assert_eq!(
1740 | "ASHR32 R1, @R2(-3, -3)",
1741 | dis(opts, cur, &[&[byte(1, 0, OpCode::ASHR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1742 | );
1743 |
1744 | assert_eq!(
1745 | "ASHR32 @R1, @R2(-3, -3)",
1746 | dis(opts, cur, &[&[byte(1, 0, OpCode::ASHR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1747 | );
1748 |
1749 | assert_eq!(
1750 | "ASHR64 R1, R2 -1000",
1751 | dis(opts, cur, &[&[byte(1, 1, OpCode::ASHR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1752 | );
1753 |
1754 | assert_eq!(
1755 | "ASHR64 R1, @R2(-3, -3)",
1756 | dis(opts, cur, &[&[byte(1, 1, OpCode::ASHR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1757 | );
1758 |
1759 | assert_eq!(
1760 | "ASHR64 @R1, @R2(-3, -3)",
1761 | dis(opts, cur, &[&[byte(1, 1, OpCode::ASHR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1762 | );
1763 |
1764 | assert_eq!(
1765 | "DIV32 R1, R2 -1000",
1766 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIV), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1767 | );
1768 |
1769 | assert_eq!(
1770 | "DIV32 R1, @R2(-3, -3)",
1771 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIV), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1772 | );
1773 |
1774 | assert_eq!(
1775 | "DIV32 @R1, @R2(-3, -3)",
1776 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIV), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1777 | );
1778 |
1779 | assert_eq!(
1780 | "DIV64 R1, R2 -1000",
1781 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIV), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1782 | );
1783 |
1784 | assert_eq!(
1785 | "DIV64 R1, @R2(-3, -3)",
1786 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIV), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1787 | );
1788 |
1789 | assert_eq!(
1790 | "DIV64 @R1, @R2(-3, -3)",
1791 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIV), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1792 | );
1793 |
1794 | assert_eq!(
1795 | "DIVU32 R1, R2 -1000",
1796 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIVU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1797 | );
1798 |
1799 | assert_eq!(
1800 | "DIVU32 R1, @R2(-3, -3)",
1801 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIVU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1802 | );
1803 |
1804 | assert_eq!(
1805 | "DIVU32 @R1, @R2(-3, -3)",
1806 | dis(opts, cur, &[&[byte(1, 0, OpCode::DIVU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1807 | );
1808 |
1809 | assert_eq!(
1810 | "DIVU64 R1, R2 -1000",
1811 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIVU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1812 | );
1813 |
1814 | assert_eq!(
1815 | "DIVU64 R1, @R2(-3, -3)",
1816 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIVU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1817 | );
1818 |
1819 | assert_eq!(
1820 | "DIVU64 @R1, @R2(-3, -3)",
1821 | dis(opts, cur, &[&[byte(1, 1, OpCode::DIVU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1822 | );
1823 |
1824 | assert_eq!(
1825 | "EXTNDB32 R1, R2 -1000",
1826 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDB), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1827 | );
1828 |
1829 | assert_eq!(
1830 | "EXTNDB32 R1, @R2(-3, -3)",
1831 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDB), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1832 | );
1833 |
1834 | assert_eq!(
1835 | "EXTNDB32 @R1, @R2(-3, -3)",
1836 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDB), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1837 | );
1838 |
1839 | assert_eq!(
1840 | "EXTNDB64 R1, R2 -1000",
1841 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDB), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1842 | );
1843 |
1844 | assert_eq!(
1845 | "EXTNDB64 R1, @R2(-3, -3)",
1846 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDB), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1847 | );
1848 |
1849 | assert_eq!(
1850 | "EXTNDB64 @R1, @R2(-3, -3)",
1851 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDB), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1852 | );
1853 |
1854 | assert_eq!(
1855 | "EXTNDD32 R1, R2 -1000",
1856 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1857 | );
1858 |
1859 | assert_eq!(
1860 | "EXTNDD32 R1, @R2(-3, -3)",
1861 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1862 | );
1863 |
1864 | assert_eq!(
1865 | "EXTNDD32 @R1, @R2(-3, -3)",
1866 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1867 | );
1868 |
1869 | assert_eq!(
1870 | "EXTNDD64 R1, R2 -1000",
1871 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1872 | );
1873 |
1874 | assert_eq!(
1875 | "EXTNDD64 R1, @R2(-3, -3)",
1876 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1877 | );
1878 |
1879 | assert_eq!(
1880 | "EXTNDD64 @R1, @R2(-3, -3)",
1881 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1882 | );
1883 |
1884 | assert_eq!(
1885 | "EXTNDW32 R1, R2 -1000",
1886 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDW), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1887 | );
1888 |
1889 | assert_eq!(
1890 | "EXTNDW32 R1, @R2(-3, -3)",
1891 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDW), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1892 | );
1893 |
1894 | assert_eq!(
1895 | "EXTNDW32 @R1, @R2(-3, -3)",
1896 | dis(opts, cur, &[&[byte(1, 0, OpCode::EXTNDW), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1897 | );
1898 |
1899 | assert_eq!(
1900 | "EXTNDW64 R1, R2 -1000",
1901 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDW), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1902 | );
1903 |
1904 | assert_eq!(
1905 | "EXTNDW64 R1, @R2(-3, -3)",
1906 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDW), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1907 | );
1908 |
1909 | assert_eq!(
1910 | "EXTNDW64 @R1, @R2(-3, -3)",
1911 | dis(opts, cur, &[&[byte(1, 1, OpCode::EXTNDW), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1912 | );
1913 |
1914 | assert_eq!(
1915 | "MOD32 R1, R2 -1000",
1916 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1917 | );
1918 |
1919 | assert_eq!(
1920 | "MOD32 R1, @R2(-3, -3)",
1921 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1922 | );
1923 |
1924 | assert_eq!(
1925 | "MOD32 @R1, @R2(-3, -3)",
1926 | dis(opts, cur, &[&[byte(1, 0, OpCode::MOD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1927 | );
1928 |
1929 | assert_eq!(
1930 | "MOD64 R1, R2 -1000",
1931 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOD), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1932 | );
1933 |
1934 | assert_eq!(
1935 | "MOD64 R1, @R2(-3, -3)",
1936 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOD), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1937 | );
1938 |
1939 | assert_eq!(
1940 | "MOD64 @R1, @R2(-3, -3)",
1941 | dis(opts, cur, &[&[byte(1, 1, OpCode::MOD), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1942 | );
1943 |
1944 | assert_eq!(
1945 | "MODU32 R1, R2 -1000",
1946 | dis(opts, cur, &[&[byte(1, 0, OpCode::MODU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1947 | );
1948 |
1949 | assert_eq!(
1950 | "MODU32 R1, @R2(-3, -3)",
1951 | dis(opts, cur, &[&[byte(1, 0, OpCode::MODU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1952 | );
1953 |
1954 | assert_eq!(
1955 | "MODU32 @R1, @R2(-3, -3)",
1956 | dis(opts, cur, &[&[byte(1, 0, OpCode::MODU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1957 | );
1958 |
1959 | assert_eq!(
1960 | "MODU64 R1, R2 -1000",
1961 | dis(opts, cur, &[&[byte(1, 1, OpCode::MODU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1962 | );
1963 |
1964 | assert_eq!(
1965 | "MODU64 R1, @R2(-3, -3)",
1966 | dis(opts, cur, &[&[byte(1, 1, OpCode::MODU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1967 | );
1968 |
1969 | assert_eq!(
1970 | "MODU64 @R1, @R2(-3, -3)",
1971 | dis(opts, cur, &[&[byte(1, 1, OpCode::MODU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1972 | );
1973 |
1974 | assert_eq!(
1975 | "SHL32 R1, R2 -1000",
1976 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHL), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1977 | );
1978 |
1979 | assert_eq!(
1980 | "SHL32 R1, @R2(-3, -3)",
1981 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHL), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1982 | );
1983 |
1984 | assert_eq!(
1985 | "SHL32 @R1, @R2(-3, -3)",
1986 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHL), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
1987 | );
1988 |
1989 | assert_eq!(
1990 | "SHL64 R1, R2 -1000",
1991 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHL), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
1992 | );
1993 |
1994 | assert_eq!(
1995 | "SHL64 R1, @R2(-3, -3)",
1996 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHL), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
1997 | );
1998 |
1999 | assert_eq!(
2000 | "SHL64 @R1, @R2(-3, -3)",
2001 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHL), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2002 | );
2003 |
2004 | assert_eq!(
2005 | "SHR32 R1, R2 -1000",
2006 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2007 | );
2008 |
2009 | assert_eq!(
2010 | "SHR32 R1, @R2(-3, -3)",
2011 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2012 | );
2013 |
2014 | assert_eq!(
2015 | "SHR32 @R1, @R2(-3, -3)",
2016 | dis(opts, cur, &[&[byte(1, 0, OpCode::SHR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2017 | );
2018 |
2019 | assert_eq!(
2020 | "SHR64 R1, R2 -1000",
2021 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2022 | );
2023 |
2024 | assert_eq!(
2025 | "SHR64 R1, @R2(-3, -3)",
2026 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2027 | );
2028 |
2029 | assert_eq!(
2030 | "SHR64 @R1, @R2(-3, -3)",
2031 | dis(opts, cur, &[&[byte(1, 1, OpCode::SHR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2032 | );
2033 |
2034 | assert_eq!(
2035 | "SUB32 R1, R2 -1000",
2036 | dis(opts, cur, &[&[byte(1, 0, OpCode::SUB), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2037 | );
2038 |
2039 | assert_eq!(
2040 | "SUB32 R1, @R2(-3, -3)",
2041 | dis(opts, cur, &[&[byte(1, 0, OpCode::SUB), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2042 | );
2043 |
2044 | assert_eq!(
2045 | "SUB32 @R1, @R2(-3, -3)",
2046 | dis(opts, cur, &[&[byte(1, 0, OpCode::SUB), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2047 | );
2048 |
2049 | assert_eq!(
2050 | "SUB64 R1, R2 -1000",
2051 | dis(opts, cur, &[&[byte(1, 1, OpCode::SUB), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2052 | );
2053 |
2054 | assert_eq!(
2055 | "SUB64 R1, @R2(-3, -3)",
2056 | dis(opts, cur, &[&[byte(1, 1, OpCode::SUB), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2057 | );
2058 |
2059 | assert_eq!(
2060 | "SUB64 @R1, @R2(-3, -3)",
2061 | dis(opts, cur, &[&[byte(1, 1, OpCode::SUB), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2062 | );
2063 |
2064 | assert_eq!(
2065 | "XOR32 R1, R2 -1000",
2066 | dis(opts, cur, &[&[byte(1, 0, OpCode::XOR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2067 | );
2068 |
2069 | assert_eq!(
2070 | "XOR32 R1, @R2(-3, -3)",
2071 | dis(opts, cur, &[&[byte(1, 0, OpCode::XOR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2072 | );
2073 |
2074 | assert_eq!(
2075 | "XOR32 @R1, @R2(-3, -3)",
2076 | dis(opts, cur, &[&[byte(1, 0, OpCode::XOR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2077 | );
2078 |
2079 | assert_eq!(
2080 | "XOR64 R1, R2 -1000",
2081 | dis(opts, cur, &[&[byte(1, 1, OpCode::XOR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2082 | );
2083 |
2084 | assert_eq!(
2085 | "XOR64 R1, @R2(-3, -3)",
2086 | dis(opts, cur, &[&[byte(1, 1, OpCode::XOR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2087 | );
2088 |
2089 | assert_eq!(
2090 | "XOR64 @R1, @R2(-3, -3)",
2091 | dis(opts, cur, &[&[byte(1, 1, OpCode::XOR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2092 | );
2093 |
2094 | assert_eq!(
2095 | "CMPeq32 R1, R2 -1000",
2096 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPeq), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2097 | );
2098 |
2099 | assert_eq!(
2100 | "CMPeq32 R1, @R2(-3, -3)",
2101 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPeq), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2102 | );
2103 |
2104 | assert_eq!(
2105 | "CMPeq32 @R1, @R2(-3, -3)",
2106 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPeq), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2107 | );
2108 |
2109 | assert_eq!(
2110 | "CMPeq64 R1, R2 -1000",
2111 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPeq), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2112 | );
2113 |
2114 | assert_eq!(
2115 | "CMPeq64 R1, @R2(-3, -3)",
2116 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPeq), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2117 | );
2118 |
2119 | assert_eq!(
2120 | "CMPeq64 @R1, @R2(-3, -3)",
2121 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPeq), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2122 | );
2123 |
2124 | assert_eq!(
2125 | "CMPlte32 R1, R2 -1000",
2126 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPlte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2127 | );
2128 |
2129 | assert_eq!(
2130 | "CMPlte32 R1, @R2(-3, -3)",
2131 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPlte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2132 | );
2133 |
2134 | assert_eq!(
2135 | "CMPlte32 @R1, @R2(-3, -3)",
2136 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPlte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2137 | );
2138 |
2139 | assert_eq!(
2140 | "CMPlte64 R1, R2 -1000",
2141 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPlte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2142 | );
2143 |
2144 | assert_eq!(
2145 | "CMPlte64 R1, @R2(-3, -3)",
2146 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPlte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2147 | );
2148 |
2149 | assert_eq!(
2150 | "CMPlte64 @R1, @R2(-3, -3)",
2151 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPlte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2152 | );
2153 |
2154 | assert_eq!(
2155 | "CMPgte32 R1, R2 -1000",
2156 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPgte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2157 | );
2158 |
2159 | assert_eq!(
2160 | "CMPgte32 R1, @R2(-3, -3)",
2161 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPgte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2162 | );
2163 |
2164 | assert_eq!(
2165 | "CMPgte32 @R1, @R2(-3, -3)",
2166 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPgte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2167 | );
2168 |
2169 | assert_eq!(
2170 | "CMPgte64 R1, R2 -1000",
2171 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPgte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2172 | );
2173 |
2174 | assert_eq!(
2175 | "CMPgte64 R1, @R2(-3, -3)",
2176 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPgte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2177 | );
2178 |
2179 | assert_eq!(
2180 | "CMPgte64 @R1, @R2(-3, -3)",
2181 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPgte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2182 | );
2183 |
2184 | assert_eq!(
2185 | "CMPulte32 R1, R2 -1000",
2186 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPulte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2187 | );
2188 |
2189 | assert_eq!(
2190 | "CMPulte32 R1, @R2(-3, -3)",
2191 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPulte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2192 | );
2193 |
2194 | assert_eq!(
2195 | "CMPulte32 @R1, @R2(-3, -3)",
2196 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPulte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2197 | );
2198 |
2199 | assert_eq!(
2200 | "CMPulte64 R1, R2 -1000",
2201 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPulte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2202 | );
2203 |
2204 | assert_eq!(
2205 | "CMPulte64 R1, @R2(-3, -3)",
2206 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPulte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2207 | );
2208 |
2209 | assert_eq!(
2210 | "CMPulte64 @R1, @R2(-3, -3)",
2211 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPulte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2212 | );
2213 |
2214 | assert_eq!(
2215 | "CMPugte32 R1, R2 -1000",
2216 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPugte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2217 | );
2218 |
2219 | assert_eq!(
2220 | "CMPugte32 R1, @R2(-3, -3)",
2221 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPugte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2222 | );
2223 |
2224 | assert_eq!(
2225 | "CMPugte32 @R1, @R2(-3, -3)",
2226 | dis(opts, cur, &[&[byte(1, 0, OpCode::CMPugte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2227 | );
2228 |
2229 | assert_eq!(
2230 | "CMPugte64 R1, R2 -1000",
2231 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPugte), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2232 | );
2233 |
2234 | assert_eq!(
2235 | "CMPugte64 R1, @R2(-3, -3)",
2236 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPugte), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2237 | );
2238 |
2239 | assert_eq!(
2240 | "CMPugte64 @R1, @R2(-3, -3)",
2241 | dis(opts, cur, &[&[byte(1, 1, OpCode::CMPugte), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2242 | );
2243 |
2244 | assert_eq!(
2245 | "MUL32 R1, R2 -1000",
2246 | dis(opts, cur, &[&[byte(1, 0, OpCode::MUL), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2247 | );
2248 |
2249 | assert_eq!(
2250 | "MUL32 R1, @R2(-3, -3)",
2251 | dis(opts, cur, &[&[byte(1, 0, OpCode::MUL), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2252 | );
2253 |
2254 | assert_eq!(
2255 | "MUL32 @R1, @R2(-3, -3)",
2256 | dis(opts, cur, &[&[byte(1, 0, OpCode::MUL), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2257 | );
2258 |
2259 | assert_eq!(
2260 | "MUL64 R1, R2 -1000",
2261 | dis(opts, cur, &[&[byte(1, 1, OpCode::MUL), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2262 | );
2263 |
2264 | assert_eq!(
2265 | "MUL64 R1, @R2(-3, -3)",
2266 | dis(opts, cur, &[&[byte(1, 1, OpCode::MUL), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2267 | );
2268 |
2269 | assert_eq!(
2270 | "MUL64 @R1, @R2(-3, -3)",
2271 | dis(opts, cur, &[&[byte(1, 1, OpCode::MUL), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2272 | );
2273 |
2274 | assert_eq!(
2275 | "MULU32 R1, R2 -1000",
2276 | dis(opts, cur, &[&[byte(1, 0, OpCode::MULU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2277 | );
2278 |
2279 | assert_eq!(
2280 | "MULU32 R1, @R2(-3, -3)",
2281 | dis(opts, cur, &[&[byte(1, 0, OpCode::MULU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2282 | );
2283 |
2284 | assert_eq!(
2285 | "MULU32 @R1, @R2(-3, -3)",
2286 | dis(opts, cur, &[&[byte(1, 0, OpCode::MULU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2287 | );
2288 |
2289 | assert_eq!(
2290 | "MULU64 R1, R2 -1000",
2291 | dis(opts, cur, &[&[byte(1, 1, OpCode::MULU), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2292 | );
2293 |
2294 | assert_eq!(
2295 | "MULU64 R1, @R2(-3, -3)",
2296 | dis(opts, cur, &[&[byte(1, 1, OpCode::MULU), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2297 | );
2298 |
2299 | assert_eq!(
2300 | "MULU64 @R1, @R2(-3, -3)",
2301 | dis(opts, cur, &[&[byte(1, 1, OpCode::MULU), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2302 | );
2303 |
2304 | assert_eq!(
2305 | "NEG32 R1, R2 -1000",
2306 | dis(opts, cur, &[&[byte(1, 0, OpCode::NEG), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2307 | );
2308 |
2309 | assert_eq!(
2310 | "NEG32 R1, @R2(-3, -3)",
2311 | dis(opts, cur, &[&[byte(1, 0, OpCode::NEG), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2312 | );
2313 |
2314 | assert_eq!(
2315 | "NEG32 @R1, @R2(-3, -3)",
2316 | dis(opts, cur, &[&[byte(1, 0, OpCode::NEG), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2317 | );
2318 |
2319 | assert_eq!(
2320 | "NEG64 R1, R2 -1000",
2321 | dis(opts, cur, &[&[byte(1, 1, OpCode::NEG), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2322 | );
2323 |
2324 | assert_eq!(
2325 | "NEG64 R1, @R2(-3, -3)",
2326 | dis(opts, cur, &[&[byte(1, 1, OpCode::NEG), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2327 | );
2328 |
2329 | assert_eq!(
2330 | "NEG64 @R1, @R2(-3, -3)",
2331 | dis(opts, cur, &[&[byte(1, 1, OpCode::NEG), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2332 | );
2333 |
2334 | assert_eq!(
2335 | "NOT32 R1, R2 -1000",
2336 | dis(opts, cur, &[&[byte(1, 0, OpCode::NOT), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2337 | );
2338 |
2339 | assert_eq!(
2340 | "NOT32 R1, @R2(-3, -3)",
2341 | dis(opts, cur, &[&[byte(1, 0, OpCode::NOT), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2342 | );
2343 |
2344 | assert_eq!(
2345 | "NOT32 @R1, @R2(-3, -3)",
2346 | dis(opts, cur, &[&[byte(1, 0, OpCode::NOT), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2347 | );
2348 |
2349 | assert_eq!(
2350 | "NOT64 R1, R2 -1000",
2351 | dis(opts, cur, &[&[byte(1, 1, OpCode::NOT), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2352 | );
2353 |
2354 | assert_eq!(
2355 | "NOT64 R1, @R2(-3, -3)",
2356 | dis(opts, cur, &[&[byte(1, 1, OpCode::NOT), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2357 | );
2358 |
2359 | assert_eq!(
2360 | "NOT64 @R1, @R2(-3, -3)",
2361 | dis(opts, cur, &[&[byte(1, 1, OpCode::NOT), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2362 | );
2363 |
2364 | assert_eq!(
2365 | "OR32 R1, R2 -1000",
2366 | dis(opts, cur, &[&[byte(1, 0, OpCode::OR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2367 | );
2368 |
2369 | assert_eq!(
2370 | "OR32 R1, @R2(-3, -3)",
2371 | dis(opts, cur, &[&[byte(1, 0, OpCode::OR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2372 | );
2373 |
2374 | assert_eq!(
2375 | "OR32 @R1, @R2(-3, -3)",
2376 | dis(opts, cur, &[&[byte(1, 0, OpCode::OR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2377 | );
2378 |
2379 | assert_eq!(
2380 | "OR64 R1, R2 -1000",
2381 | dis(opts, cur, &[&[byte(1, 1, OpCode::OR), 0b00100001][..], &(-1000i16).to_le_bytes()[..],].concat())
2382 | );
2383 |
2384 | assert_eq!(
2385 | "OR64 R1, @R2(-3, -3)",
2386 | dis(opts, cur, &[&[byte(1, 1, OpCode::OR), 0b10100001][..], &(36879u16).to_le_bytes()[..],].concat())
2387 | );
2388 |
2389 | assert_eq!(
2390 | "OR64 @R1, @R2(-3, -3)",
2391 | dis(opts, cur, &[&[byte(1, 1, OpCode::OR), 0b10101001][..], &(36879u16).to_le_bytes()[..],].concat())
2392 | );
2393 | }
2394 |
--------------------------------------------------------------------------------
/src/theme.rs:
--------------------------------------------------------------------------------
1 | use colored::*;
2 |
3 | use crate::options::Options;
4 |
5 | pub const SPORE: Theme = Theme {
6 | opcode: color(217, 207, 199),
7 | error: color(207, 66, 31),
8 | bytecode: color(84, 71, 52),
9 | indirect: color(227, 202, 113),
10 | operand: color(135, 75, 41),
11 | index: color(217, 182, 130),
12 | immediate: color(191, 151, 169),
13 | comment: color(135, 107, 55),
14 | x8: color(173, 152, 169),
15 | x16: color(221, 217, 159),
16 | x32: color(168, 132, 88),
17 | x64: color(125, 95, 102),
18 | };
19 |
20 | pub const INDUSTRIAL_COMPUTER: Theme = Theme {
21 | opcode: color(161, 156, 148),
22 | error: color(255, 0, 0),
23 | bytecode: color(77, 75, 73),
24 | indirect: color(255, 153, 0),
25 | operand: color(161, 156, 148),
26 | index: color(255, 153, 0),
27 | immediate: color(255, 153, 0),
28 | comment: color(82, 214, 0),
29 | x8: color(0, 45, 122),
30 | x16: color(161, 78, 0),
31 | x32: color(3, 99, 0),
32 | x64: color(110, 18, 0),
33 | };
34 |
35 | pub const MATTERHORN_ZERMATT_VILLAGE: Theme = Theme {
36 | opcode: color(173, 185, 201),
37 | error: color(255, 153, 0),
38 | bytecode: color(211, 195, 212),
39 | indirect: color(107, 129, 138),
40 | operand: color(115, 131, 153),
41 | index: color(140, 135, 128),
42 | immediate: color(199, 131, 64),
43 | comment: color(97, 93, 88),
44 | x8: color(110, 73, 35),
45 | x16: color(156, 103, 50),
46 | x32: color(199, 131, 64),
47 | x64: color(237, 156, 76),
48 | };
49 |
50 | pub struct Theme
51 | {
52 | pub opcode: Color,
53 | pub error: Color,
54 | pub bytecode: Color,
55 | pub indirect: Color,
56 | pub operand: Color,
57 | pub index: Color,
58 | pub immediate: Color,
59 | pub comment: Color,
60 | pub x8: Color,
61 | pub x16: Color,
62 | pub x32: Color,
63 | pub x64: Color,
64 | }
65 |
66 | pub const fn color(r: u8, g: u8, b: u8) -> Color
67 | {
68 | Color::TrueColor { r, g, b }
69 | }
70 |
71 | pub fn colored_string(string: String, color: Color) -> String
72 | {
73 | if let Color::TrueColor { r, g, b } = color
74 | {
75 | string.truecolor(r, g, b).to_string()
76 | }
77 | else
78 | {
79 | string
80 | }
81 | }
82 |
83 | pub fn color_opcode(string: String, options: &Options) -> String
84 | {
85 | if let Some(color_theme) = &options.theme
86 | {
87 | colored_string(string, color_theme.opcode)
88 | }
89 | else
90 | {
91 | string
92 | }
93 | }
94 |
95 | pub fn color_error(string: String, options: &Options) -> String
96 | {
97 | if let Some(color_theme) = &options.theme
98 | {
99 | colored_string(string, color_theme.error)
100 | }
101 | else
102 | {
103 | string
104 | }
105 | }
106 |
107 | pub fn color_bytecode(string: String, options: &Options) -> String
108 | {
109 | if let Some(color_theme) = &options.theme
110 | {
111 | colored_string(string, color_theme.bytecode)
112 | }
113 | else
114 | {
115 | string
116 | }
117 | }
118 |
119 | pub fn color_indirect(string: String, options: &Options) -> String
120 | {
121 | if let Some(color_theme) = &options.theme
122 | {
123 | colored_string(string, color_theme.indirect)
124 | }
125 | else
126 | {
127 | string
128 | }
129 | }
130 |
131 | pub fn color_operand(string: String, options: &Options) -> String
132 | {
133 | if let Some(color_theme) = &options.theme
134 | {
135 | colored_string(string, color_theme.operand)
136 | }
137 | else
138 | {
139 | string
140 | }
141 | }
142 |
143 | pub fn color_index(string: String, options: &Options) -> String
144 | {
145 | if let Some(color_theme) = &options.theme
146 | {
147 | colored_string(string, color_theme.index)
148 | }
149 | else
150 | {
151 | string
152 | }
153 | }
154 |
155 | pub fn color_immediate(string: String, options: &Options) -> String
156 | {
157 | if let Some(color_theme) = &options.theme
158 | {
159 | colored_string(string, color_theme.immediate)
160 | }
161 | else
162 | {
163 | string
164 | }
165 | }
166 |
167 | pub fn color_comment(string: String, options: &Options) -> String
168 | {
169 | if let Some(color_theme) = &options.theme
170 | {
171 | colored_string(string, color_theme.comment)
172 | }
173 | else
174 | {
175 | string
176 | }
177 | }
178 |
179 | pub fn color_x8(string: String, options: &Options) -> String
180 | {
181 | if let Some(color_theme) = &options.theme
182 | {
183 | colored_string(string, color_theme.x8)
184 | }
185 | else
186 | {
187 | string
188 | }
189 | }
190 |
191 | pub fn color_x16(string: String, options: &Options) -> String
192 | {
193 | if let Some(color_theme) = &options.theme
194 | {
195 | colored_string(string, color_theme.x16)
196 | }
197 | else
198 | {
199 | string
200 | }
201 | }
202 |
203 | pub fn color_x32(string: String, options: &Options) -> String
204 | {
205 | if let Some(color_theme) = &options.theme
206 | {
207 | colored_string(string, color_theme.x32)
208 | }
209 | else
210 | {
211 | string
212 | }
213 | }
214 |
215 | pub fn color_x64(string: String, options: &Options) -> String
216 | {
217 | if let Some(color_theme) = &options.theme
218 | {
219 | colored_string(string, color_theme.x64)
220 | }
221 | else
222 | {
223 | string
224 | }
225 | }
226 |
227 | pub trait Emit
228 | {
229 | fn emit(&self, options: &Options) -> String;
230 | }
231 |
--------------------------------------------------------------------------------