1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
4#![cfg_attr(not(feature = "std"), no_std)]
5#![cfg_attr(feature = "std", doc = include_str!("../README.md"))]
6#![deny(
7 clippy::arithmetic_side_effects,
8 clippy::cast_sign_loss,
9 clippy::cast_possible_truncation,
10 clippy::cast_possible_wrap,
11 clippy::string_slice
12)]
13#![deny(missing_docs)]
14#![deny(unsafe_code)]
15#![deny(unused_crate_dependencies)]
16
17#[cfg(feature = "alloc")]
18extern crate alloc;
19
20mod args;
21mod panic_instruction;
22#[macro_use]
25pub mod macros;
26pub mod op;
27mod pack;
28mod panic_reason;
29mod unpack;
30
31#[cfg(test)]
32mod encoding_tests;
33
34#[doc(no_inline)]
35pub use args::{
36 wideint,
37 GMArgs,
38 GTFArgs,
39};
40
41pub type RegisterId = usize;
43
44pub type Word = u64;
46
47pub use panic_instruction::PanicInstruction;
48pub use panic_reason::PanicReason;
49
50#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
52#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
53pub struct RegId(u8);
54
55#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
57#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
58pub struct Imm06(u8);
59
60#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
62#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
63pub struct Imm12(u16);
64
65#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
67#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
68pub struct Imm18(u32);
69
70#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
72#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
73pub struct Imm24(u32);
74
75pub type RawInstruction = u32;
77
78#[derive(Debug, Eq, PartialEq)]
81pub struct InvalidOpcode;
82
83bitflags::bitflags! {
84 pub struct Flags: Word {
87 const UNSAFEMATH = 0x01;
92 const WRAPPING = 0x02;
94 }
95}
96pub trait CheckRegId {
98 fn check(self) -> RegId;
100}
101
102impl CheckRegId for RegId {
103 fn check(self) -> RegId {
104 self
105 }
106}
107
108impl CheckRegId for u8 {
109 fn check(self) -> RegId {
110 RegId::new_checked(self).expect("CheckRegId was given invalid RegId")
111 }
112}
113
114impl_instructions! {
118 "Adds two registers."
119 0x10 ADD add [dst: RegId lhs: RegId rhs: RegId]
120 "Bitwise ANDs two registers."
121 0x11 AND and [dst: RegId lhs: RegId rhs: RegId]
122 "Divides two registers."
123 0x12 DIV div [dst: RegId lhs: RegId rhs: RegId]
124 "Compares two registers for equality."
125 0x13 EQ eq [dst: RegId lhs: RegId rhs: RegId]
126 "Raises one register to the power of another."
127 0x14 EXP exp [dst: RegId lhs: RegId rhs: RegId]
128 "Compares two registers for greater-than."
129 0x15 GT gt [dst: RegId lhs: RegId rhs: RegId]
130 "Compares two registers for less-than."
131 0x16 LT lt [dst: RegId lhs: RegId rhs: RegId]
132 "The integer logarithm of a register."
133 0x17 MLOG mlog [dst: RegId lhs: RegId rhs: RegId]
134 "The integer root of a register."
135 0x18 MROO mroo [dst: RegId lhs: RegId rhs: RegId]
136 "Modulo remainder of two registers."
137 0x19 MOD mod_ [dst: RegId lhs: RegId rhs: RegId]
138 "Copy from one register to another."
139 0x1A MOVE move_ [dst: RegId src: RegId]
140 "Multiplies two registers."
141 0x1B MUL mul [dst: RegId lhs: RegId rhs: RegId]
142 "Bitwise NOT a register."
143 0x1C NOT not [dst: RegId arg: RegId]
144 "Bitwise ORs two registers."
145 0x1D OR or [dst: RegId lhs: RegId rhs: RegId]
146 "Left shifts a register by a register."
147 0x1E SLL sll [dst: RegId lhs: RegId rhs: RegId]
148 "Right shifts a register by a register."
149 0x1F SRL srl [dst: RegId lhs: RegId rhs: RegId]
150 "Subtracts two registers."
151 0x20 SUB sub [dst: RegId lhs: RegId rhs: RegId]
152 "Bitwise XORs two registers."
153 0x21 XOR xor [dst: RegId lhs: RegId rhs: RegId]
154 "Fused multiply-divide with arbitrary precision intermediate step."
155 0x22 MLDV mldv [dst: RegId mul_lhs: RegId mul_rhs: RegId divisor: RegId]
156
157 "Return from context."
158 0x24 RET ret [value: RegId]
159 "Return from context with data."
160 0x25 RETD retd [addr: RegId len: RegId]
161 "Allocate a number of bytes from the heap."
162 0x26 ALOC aloc [bytes: RegId]
163 "Clear a variable number of bytes in memory."
164 0x27 MCL mcl [dst_addr: RegId len: RegId]
165 "Copy a variable number of bytes in memory."
166 0x28 MCP mcp [dst_addr: RegId src_addr: RegId len: RegId]
167 "Compare bytes in memory."
168 0x29 MEQ meq [result: RegId lhs_addr: RegId rhs_addr: RegId len: RegId]
169 "Get block header hash for height."
170 0x2A BHSH bhsh [dst: RegId heigth: RegId]
171 "Get current block height."
172 0x2B BHEI bhei [dst: RegId]
173 "Burns `amount` coins of the asset ID created from `sub_id` for the current contract."
174 0x2C BURN burn [amount: RegId sub_id_addr: RegId]
175 "Call a contract."
176 0x2D CALL call [target_struct: RegId fwd_coins: RegId asset_id_addr: RegId fwd_gas: RegId]
177 "Copy contract code for a contract."
178 0x2E CCP ccp [dst_addr: RegId contract_id_addr: RegId offset: RegId len: RegId]
179 "Get code root of a contract."
180 0x2F CROO croo [dst_addr: RegId contract_id_addr: RegId]
181 "Get code size of a contract."
182 0x30 CSIZ csiz [dst: RegId contract_id_addr: RegId]
183 "Get current block proposer's address."
184 0x31 CB cb [dst: RegId]
185 "Load code as executable either from contract, blob, or memory."
186 0x32 LDC ldc [src_addr: RegId offset: RegId len: RegId mode: Imm06]
187 "Log an event."
188 0x33 LOG log [a: RegId b: RegId c: RegId d: RegId]
189 "Log data."
190 0x34 LOGD logd [a: RegId b: RegId addr: RegId len: RegId]
191 "Mints `amount` coins of the asset ID created from `sub_id` for the current contract."
192 0x35 MINT mint [amount: RegId sub_id_addr: RegId]
193 "Halt execution, reverting state changes and returning a value."
194 0x36 RVRT rvrt [value: RegId]
195 "Clear a series of slots from contract storage."
196 0x37 SCWQ scwq [key_addr: RegId status: RegId lenq: RegId]
197 "Load a word from contract storage."
198 0x38 SRW srw [dst: RegId status: RegId key_addr: RegId]
199 "Load a series of 32 byte slots from contract storage."
200 0x39 SRWQ srwq [dst_addr: RegId status: RegId key_addr:RegId lenq: RegId]
201 "Store a word in contract storage."
202 0x3A SWW sww [key_addr: RegId status: RegId value: RegId]
203 "Store a series of 32 byte slots in contract storage."
204 0x3B SWWQ swwq [key_addr: RegId status: RegId src_addr: RegId lenq: RegId]
205 "Transfer coins to a contract unconditionally."
206 0x3C TR tr [contract_id_addr: RegId amount: RegId asset_id_addr: RegId]
207 "Transfer coins to a variable output."
208 0x3D TRO tro [contract_id_addr: RegId output_index: RegId amount: RegId asset_id_addr: RegId]
209 "The 64-byte public key (x, y) recovered from 64-byte signature on 32-byte message hash."
210 0x3E ECK1 eck1 [dst_addr: RegId sig_addr: RegId msg_hash_addr: RegId]
211 "The 64-byte Secp256r1 public key (x, y) recovered from 64-byte signature on 32-byte message hash."
212 0x3F ECR1 ecr1 [dst_addr: RegId sig_addr: RegId msg_hash_addr: RegId]
213 "Verify ED25519 public key and signature match a message."
214 0x40 ED19 ed19 [pub_key_addr: RegId sig_addr: RegId msg_addr: RegId msg_len: RegId]
215 "The keccak-256 hash of a slice."
216 0x41 K256 k256 [dst_addr: RegId src_addr: RegId len: RegId]
217 "The SHA-2-256 hash of a slice."
218 0x42 S256 s256 [dst_addr: RegId src_addr: RegId len: RegId]
219 "Get timestamp of block at given height."
220 0x43 TIME time [dst: RegId heigth: RegId]
221
222 "Performs no operation."
223 0x47 NOOP noop []
224 "Set flag register to a register."
225 0x48 FLAG flag [value: RegId]
226 "Get the balance of contract of an asset ID."
227 0x49 BAL bal [dst: RegId asset_id_addr: RegId contract_id_addr: RegId]
228 "Dynamic jump."
229 0x4A JMP jmp [abs_target: RegId]
230 "Conditional dynamic jump."
231 0x4B JNE jne [abs_target: RegId lhs: RegId rhs: RegId]
232 "Send a message to recipient address with call abi, coins, and output."
233 0x4C SMO smo [recipient_addr: RegId data_addr: RegId data_len: RegId coins: RegId]
234
235 "Adds a register and an immediate value."
236 0x50 ADDI addi [dst: RegId lhs: RegId rhs: Imm12]
237 "Bitwise ANDs a register and an immediate value."
238 0x51 ANDI andi [dst: RegId lhs: RegId rhs: Imm12]
239 "Divides a register and an immediate value."
240 0x52 DIVI divi [dst: RegId lhs: RegId rhs: Imm12]
241 "Raises one register to the power of an immediate value."
242 0x53 EXPI expi [dst: RegId lhs: RegId rhs: Imm12]
243 "Modulo remainder of a register and an immediate value."
244 0x54 MODI modi [dst: RegId lhs: RegId rhs: Imm12]
245 "Multiplies a register and an immediate value."
246 0x55 MULI muli [dst: RegId lhs: RegId rhs: Imm12]
247 "Bitwise ORs a register and an immediate value."
248 0x56 ORI ori [dst: RegId lhs: RegId rhs: Imm12]
249 "Left shifts a register by an immediate value."
250 0x57 SLLI slli [dst: RegId lhs: RegId rhs: Imm12]
251 "Right shifts a register by an immediate value."
252 0x58 SRLI srli [dst: RegId lhs: RegId rhs: Imm12]
253 "Subtracts a register and an immediate value."
254 0x59 SUBI subi [dst: RegId lhs: RegId rhs: Imm12]
255 "Bitwise XORs a register and an immediate value."
256 0x5A XORI xori [dst: RegId lhs: RegId rhs: Imm12]
257 "Conditional jump."
258 0x5B JNEI jnei [cond_lhs: RegId cond_rhs: RegId abs_target: Imm12]
259 "A byte is loaded from the specified address offset by an immediate value."
260 0x5C LB lb [dst: RegId addr: RegId offset: Imm12]
261 "A word is loaded from the specified address offset by an immediate value."
262 0x5D LW lw [dst: RegId addr: RegId offset: Imm12]
263 "Write the least significant byte of a register to memory."
264 0x5E SB sb [addr: RegId value: RegId offset: Imm12]
265 "Write a register to memory."
266 0x5F SW sw [addr: RegId value: RegId offset: Imm12]
267 "Copy an immediate number of bytes in memory."
268 0x60 MCPI mcpi [dst_addr: RegId src_addr: RegId len: Imm12]
269 "Get transaction fields."
270 0x61 GTF gtf [dst: RegId arg: RegId selector: Imm12]
271
272 "Clear an immediate number of bytes in memory."
273 0x70 MCLI mcli [addr: RegId count: Imm18]
274 "Get metadata from memory."
275 0x71 GM gm [dst: RegId selector: Imm18]
276 "Copy immediate value into a register"
277 0x72 MOVI movi [dst: RegId val: Imm18]
278 "Conditional jump against zero."
279 0x73 JNZI jnzi [cond_nz: RegId abs_target: Imm18]
280 "Unconditional dynamic relative jump forwards, with a constant offset."
281 0x74 JMPF jmpf [dynamic: RegId fixed: Imm18]
282 "Unconditional dynamic relative jump backwards, with a constant offset."
283 0x75 JMPB jmpb [dynamic: RegId fixed: Imm18]
284 "Dynamic relative jump forwards, conditional against zero, with a constant offset."
285 0x76 JNZF jnzf [cond_nz: RegId dynamic: RegId fixed: Imm12]
286 "Dynamic relative jump backwards, conditional against zero, with a constant offset."
287 0x77 JNZB jnzb [cond_nz: RegId dynamic: RegId fixed: Imm12]
288 "Dynamic relative jump forwards, conditional on comparsion, with a constant offset."
289 0x78 JNEF jnef [cond_lhs: RegId cond_rhs: RegId dynamic: RegId fixed: Imm06]
290 "Dynamic relative jump backwards, conditional on comparsion, with a constant offset."
291 0x79 JNEB jneb [cond_lhs: RegId cond_rhs: RegId dynamic: RegId fixed: Imm06]
292
293 "Jump."
294 0x90 JI ji [abs_target: Imm24]
295 "Extend the current call frame's stack by an immediate value."
296 0x91 CFEI cfei [amount: Imm24]
297 "Shrink the current call frame's stack by an immediate value."
298 0x92 CFSI cfsi [amount: Imm24]
299 "Extend the current call frame's stack"
300 0x93 CFE cfe [amount: RegId]
301 "Shrink the current call frame's stack"
302 0x94 CFS cfs [amount: RegId]
303 "Push a bitmask-selected set of registers in range 16..40 to the stack."
304 0x95 PSHL pshl [bitmask: Imm24]
305 "Push a bitmask-selected set of registers in range 40..64 to the stack."
306 0x96 PSHH pshh [bitmask: Imm24]
307 "Pop a bitmask-selected set of registers in range 16..40 to the stack."
308 0x97 POPL popl [bitmask: Imm24]
309 "Pop a bitmask-selected set of registers in range 40..64 to the stack."
310 0x98 POPH poph [bitmask: Imm24]
311
312 "Compare 128bit integers"
313 0xa0 WDCM wdcm [dst: RegId lhs: RegId rhs: RegId flags: Imm06]
314 "Compare 256bit integers"
315 0xa1 WQCM wqcm [dst: RegId lhs: RegId rhs: RegId flags: Imm06]
316 "Simple 128bit operations"
317 0xa2 WDOP wdop [dst: RegId lhs: RegId rhs: RegId flags: Imm06]
318 "Simple 256bit operations"
319 0xa3 WQOP wqop [dst: RegId lhs: RegId rhs: RegId flags: Imm06]
320 "Multiply 128bit"
321 0xa4 WDML wdml [dst: RegId lhs: RegId rhs: RegId flags: Imm06]
322 "Multiply 256bit"
323 0xa5 WQML wqml [dst: RegId lhs: RegId rhs: RegId flags: Imm06]
324 "Divide 128bit"
325 0xa6 WDDV wddv [dst: RegId lhs: RegId rhs: RegId flags: Imm06]
326 "Divide 256bit"
327 0xa7 WQDV wqdv [dst: RegId lhs: RegId rhs: RegId flags: Imm06]
328 "Fused multiply-divide 128bit"
329 0xa8 WDMD wdmd [dst: RegId mul_lhs: RegId mul_rhs: RegId divisor: RegId]
330 "Fused multiply-divide 256bit"
331 0xa9 WQMD wqmd [dst: RegId mul_lhs: RegId mul_rhs: RegId divisor: RegId]
332 "AddMod 128bit"
333 0xaa WDAM wdam [dst: RegId add_lhs: RegId add_rhs: RegId modulo: RegId]
334 "AddMod 256bit"
335 0xab WQAM wqam [dst: RegId add_lhs: RegId add_rhs: RegId modulo: RegId]
336 "MulMod 128bit"
337 0xac WDMM wdmm [dst: RegId mul_lhs: RegId mul_rhs: RegId modulo: RegId]
338 "MulMod 256bit"
339 0xad WQMM wqmm [dst: RegId mul_lhs: RegId mul_rhs: RegId modulo: RegId]
340
341 "Call external function"
342 0xb0 ECAL ecal [a: RegId b: RegId c: RegId d: RegId]
343
344 "Get blob size"
345 0xba BSIZ bsiz [dst: RegId blob_id_ptr: RegId]
346 "Load blob as data"
347 0xbb BLDD bldd [dst_ptr: RegId blob_id_ptr: RegId offset: RegId len: RegId]
348 "Given some curve, performs an operation on points"
349 0xbc ECOP ecop [dst: RegId curve_id: RegId operation_type: RegId points_ptr: RegId]
350 "Given some curve, performs a pairing on groups of points"
351 0xbe EPAR epar [success: RegId curve_id: RegId number_elements: RegId points_ptr: RegId]
352}
353
354impl Instruction {
355 pub const SIZE: usize = core::mem::size_of::<Instruction>();
357
358 pub fn to_bytes(self) -> [u8; 4] {
360 self.into()
361 }
362}
363
364#[cfg(feature = "typescript")]
365mod typescript {
366 #[derive(Clone, Eq, Hash, PartialEq)]
374 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
375 #[wasm_bindgen::prelude::wasm_bindgen]
376 pub struct Instruction(Box<crate::Instruction>);
377
378 impl Instruction {
379 pub fn new(instruction: crate::Instruction) -> Self {
380 Self(Box::new(instruction))
381 }
382 }
383
384 #[wasm_bindgen::prelude::wasm_bindgen]
385 impl Instruction {
386 pub fn to_bytes(&self) -> Vec<u8> {
388 use core::ops::Deref;
389 self.deref().to_bytes().to_vec()
390 }
391
392 pub fn size() -> usize {
394 crate::Instruction::SIZE
395 }
396 }
397
398 impl core::ops::Deref for Instruction {
399 type Target = crate::Instruction;
400
401 fn deref(&self) -> &crate::Instruction {
402 self.0.as_ref()
403 }
404 }
405
406 impl core::ops::DerefMut for Instruction {
407 fn deref_mut(&mut self) -> &mut crate::Instruction {
408 self.0.as_mut()
409 }
410 }
411
412 impl core::borrow::Borrow<crate::Instruction> for Instruction {
413 fn borrow(&self) -> &crate::Instruction {
414 self.0.as_ref()
415 }
416 }
417
418 impl core::borrow::BorrowMut<crate::Instruction> for Instruction {
419 fn borrow_mut(&mut self) -> &mut crate::Instruction {
420 self.0.as_mut()
421 }
422 }
423}
424
425impl RegId {
426 pub const BAL: Self = Self(0x0B);
428 pub const CGAS: Self = Self(0x0A);
430 pub const ERR: Self = Self(0x08);
432 pub const FLAG: Self = Self(0x0F);
434 pub const FP: Self = Self(0x06);
436 pub const GGAS: Self = Self(0x09);
438 pub const HP: Self = Self(0x07);
441 pub const IS: Self = Self(0x0C);
443 pub const OF: Self = Self(0x02);
445 pub const ONE: Self = Self(0x01);
447 pub const PC: Self = Self(0x03);
449 pub const RET: Self = Self(0x0D);
451 pub const RETL: Self = Self(0x0E);
453 pub const SP: Self = Self(0x05);
456 pub const SSP: Self = Self(0x04);
458 pub const WRITABLE: Self = Self(0x10);
460 pub const ZERO: Self = Self(0x00);
462
463 pub const fn new(u: u8) -> Self {
467 Self(u & 0b_0011_1111)
468 }
469
470 pub const fn to_u8(self) -> u8 {
472 self.0
473 }
474}
475
476#[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
477impl RegId {
478 pub fn new_checked(u: u8) -> Option<RegId> {
482 let r = Self::new(u);
483 (r.0 == u).then_some(r)
484 }
485}
486
487#[cfg(feature = "typescript")]
488#[wasm_bindgen::prelude::wasm_bindgen]
489impl RegId {
490 pub fn bal() -> Self {
492 Self::BAL
493 }
494
495 pub fn cgas() -> Self {
497 Self::CGAS
498 }
499
500 pub fn err() -> Self {
502 Self::ERR
503 }
504
505 pub fn flag() -> Self {
507 Self::FLAG
508 }
509
510 pub fn fp() -> Self {
512 Self::FP
513 }
514
515 pub fn ggas() -> Self {
517 Self::GGAS
518 }
519
520 pub fn hp() -> Self {
523 Self::HP
524 }
525
526 pub fn is() -> Self {
528 Self::IS
529 }
530
531 pub fn of() -> Self {
533 Self::OF
534 }
535
536 pub fn one() -> Self {
538 Self::ONE
539 }
540
541 pub fn pc() -> Self {
543 Self::PC
544 }
545
546 pub fn ret() -> Self {
548 Self::RET
549 }
550
551 pub fn retl() -> Self {
553 Self::RETL
554 }
555
556 pub fn sp() -> Self {
559 Self::SP
560 }
561
562 pub fn spp() -> Self {
564 Self::SSP
565 }
566
567 pub fn writable() -> Self {
569 Self::WRITABLE
570 }
571
572 pub fn zero() -> Self {
574 Self::ZERO
575 }
576
577 #[wasm_bindgen(constructor)]
581 pub fn new_typescript(u: u8) -> Self {
582 Self::new(u)
583 }
584
585 #[wasm_bindgen(js_name = to_u8)]
587 pub fn to_u8_typescript(self) -> u8 {
588 self.to_u8()
589 }
590}
591
592impl Imm06 {
593 pub const MAX: Self = Self(0b_0011_1111);
595
596 pub const fn new(u: u8) -> Self {
600 Self(u & Self::MAX.0)
601 }
602
603 pub fn new_checked(u: u8) -> Option<Self> {
607 let imm = Self::new(u);
608 (imm.0 == u).then_some(imm)
609 }
610
611 pub const fn to_u8(self) -> u8 {
613 self.0
614 }
615}
616
617impl Imm12 {
618 pub const MAX: Self = Self(0b_0000_1111_1111_1111);
620
621 pub const fn new(u: u16) -> Self {
625 Self(u & Self::MAX.0)
626 }
627
628 pub fn new_checked(u: u16) -> Option<Self> {
632 let imm = Self::new(u);
633 (imm.0 == u).then_some(imm)
634 }
635
636 pub const fn to_u16(self) -> u16 {
638 self.0
639 }
640}
641
642impl Imm18 {
643 pub const MAX: Self = Self(0b_0000_0000_0000_0011_1111_1111_1111_1111);
645
646 pub const fn new(u: u32) -> Self {
650 Self(u & Self::MAX.0)
651 }
652
653 pub fn new_checked(u: u32) -> Option<Self> {
657 let imm = Self::new(u);
658 (imm.0 == u).then_some(imm)
659 }
660
661 pub const fn to_u32(self) -> u32 {
663 self.0
664 }
665}
666
667impl Imm24 {
668 pub const MAX: Self = Self(0b_0000_0000_1111_1111_1111_1111_1111_1111);
670
671 pub const fn new(u: u32) -> Self {
675 Self(u & Self::MAX.0)
676 }
677
678 pub fn new_checked(u: u32) -> Option<Self> {
682 let imm = Self::new(u);
683 (imm.0 == u).then_some(imm)
684 }
685
686 pub const fn to_u32(self) -> u32 {
688 self.0
689 }
690}
691
692impl Opcode {
693 #[allow(clippy::match_like_matches_macro)]
698 pub fn is_predicate_allowed(&self) -> bool {
699 use Opcode::*;
700 match self {
701 ADD | AND | DIV | EQ | EXP | GT | LT | MLOG | MROO | MOD | MOVE | MUL
702 | NOT | OR | SLL | SRL | SUB | XOR | WDCM | WQCM | WDOP | WQOP | WDML
703 | WQML | WDDV | WQDV | WDMD | WQMD | WDAM | WQAM | WDMM | WQMM | PSHH
704 | PSHL | POPH | POPL | RET | ALOC | MCL | MCP | MEQ | ECK1 | ECR1 | ED19
705 | K256 | S256 | NOOP | FLAG | ADDI | ANDI | DIVI | EXPI | MODI | MULI
706 | MLDV | ORI | SLLI | SRLI | SUBI | XORI | JNEI | LB | LW | SB | SW
707 | MCPI | MCLI | GM | MOVI | JNZI | JI | JMP | JNE | JMPF | JMPB | JNZF
708 | JNZB | JNEF | JNEB | CFEI | CFSI | CFE | CFS | GTF | LDC | BSIZ | BLDD
709 | ECOP | EPAR => true,
710 _ => false,
711 }
712 }
713}
714
715impl From<u8> for RegId {
718 fn from(u: u8) -> Self {
719 RegId::new(u)
720 }
721}
722
723impl From<u8> for Imm06 {
724 fn from(u: u8) -> Self {
725 Imm06::new(u)
726 }
727}
728
729impl From<u16> for Imm12 {
730 fn from(u: u16) -> Self {
731 Imm12::new(u)
732 }
733}
734
735impl From<u32> for Imm18 {
736 fn from(u: u32) -> Self {
737 Imm18::new(u)
738 }
739}
740
741impl From<u32> for Imm24 {
742 fn from(u: u32) -> Self {
743 Imm24::new(u)
744 }
745}
746
747impl From<RegId> for u8 {
748 fn from(RegId(u): RegId) -> Self {
749 u
750 }
751}
752
753impl From<Imm06> for u8 {
754 fn from(Imm06(u): Imm06) -> Self {
755 u
756 }
757}
758
759impl From<Imm12> for u16 {
760 fn from(Imm12(u): Imm12) -> Self {
761 u
762 }
763}
764
765impl From<Imm18> for u32 {
766 fn from(Imm18(u): Imm18) -> Self {
767 u
768 }
769}
770
771impl From<Imm24> for u32 {
772 fn from(Imm24(u): Imm24) -> Self {
773 u
774 }
775}
776
777impl From<RegId> for usize {
780 fn from(r: RegId) -> usize {
781 u8::from(r).into()
782 }
783}
784
785impl From<Imm06> for u16 {
786 fn from(imm: Imm06) -> Self {
787 u8::from(imm).into()
788 }
789}
790
791impl From<Imm06> for u32 {
792 fn from(imm: Imm06) -> Self {
793 u8::from(imm).into()
794 }
795}
796
797impl From<Imm06> for u64 {
798 fn from(imm: Imm06) -> Self {
799 u8::from(imm).into()
800 }
801}
802
803impl From<Imm06> for u128 {
804 fn from(imm: Imm06) -> Self {
805 u8::from(imm).into()
806 }
807}
808
809impl From<Imm12> for u32 {
810 fn from(imm: Imm12) -> Self {
811 u16::from(imm).into()
812 }
813}
814
815impl From<Imm12> for u64 {
816 fn from(imm: Imm12) -> Self {
817 u16::from(imm).into()
818 }
819}
820
821impl From<Imm12> for u128 {
822 fn from(imm: Imm12) -> Self {
823 u16::from(imm).into()
824 }
825}
826
827impl From<Imm18> for u64 {
828 fn from(imm: Imm18) -> Self {
829 u32::from(imm).into()
830 }
831}
832
833impl From<Imm18> for u128 {
834 fn from(imm: Imm18) -> Self {
835 u32::from(imm).into()
836 }
837}
838
839impl From<Imm24> for u64 {
840 fn from(imm: Imm24) -> Self {
841 u32::from(imm).into()
842 }
843}
844
845impl From<Imm24> for u128 {
846 fn from(imm: Imm24) -> Self {
847 u32::from(imm).into()
848 }
849}
850
851impl From<Opcode> for u8 {
852 fn from(op: Opcode) -> Self {
853 op as u8
854 }
855}
856
857impl From<Instruction> for RawInstruction {
858 fn from(inst: Instruction) -> Self {
859 RawInstruction::from_be_bytes(inst.into())
860 }
861}
862
863impl core::convert::TryFrom<RawInstruction> for Instruction {
864 type Error = InvalidOpcode;
865
866 fn try_from(u: RawInstruction) -> Result<Self, Self::Error> {
867 Self::try_from(u.to_be_bytes())
868 }
869}
870
871impl<T> core::ops::Index<RegId> for [T]
874where
875 [T]: core::ops::Index<usize, Output = T>,
876{
877 type Output = T;
878
879 fn index(&self, ix: RegId) -> &Self::Output {
880 &self[usize::from(ix)]
881 }
882}
883
884impl<T> core::ops::IndexMut<RegId> for [T]
885where
886 [T]: core::ops::IndexMut<usize, Output = T>,
887{
888 fn index_mut(&mut self, ix: RegId) -> &mut Self::Output {
889 &mut self[usize::from(ix)]
890 }
891}
892
893#[cfg(feature = "alloc")]
896impl core::iter::FromIterator<Instruction> for alloc::vec::Vec<u8> {
897 fn from_iter<I: IntoIterator<Item = Instruction>>(iter: I) -> Self {
898 iter.into_iter().flat_map(Instruction::to_bytes).collect()
899 }
900}
901
902#[cfg(feature = "alloc")]
903impl core::iter::FromIterator<Instruction> for alloc::vec::Vec<u32> {
904 fn from_iter<I: IntoIterator<Item = Instruction>>(iter: I) -> Self {
905 iter.into_iter().map(u32::from).collect()
906 }
907}
908
909pub fn from_bytes<I>(bs: I) -> impl Iterator<Item = Result<Instruction, InvalidOpcode>>
916where
917 I: IntoIterator<Item = u8>,
918{
919 let mut iter = bs.into_iter();
920 core::iter::from_fn(move || {
921 let a = iter.next()?;
922 let b = iter.next()?;
923 let c = iter.next()?;
924 let d = iter.next()?;
925 Some(Instruction::try_from([a, b, c, d]))
926 })
927}
928
929pub fn from_u32s<I>(us: I) -> impl Iterator<Item = Result<Instruction, InvalidOpcode>>
936where
937 I: IntoIterator<Item = u32>,
938{
939 us.into_iter().map(Instruction::try_from)
940}
941
942fn check_imm06(u: u8) -> Imm06 {
946 Imm06::new_checked(u)
947 .unwrap_or_else(|| panic!("Value `{u}` out of range for 6-bit immediate"))
948}
949
950fn check_imm12(u: u16) -> Imm12 {
951 Imm12::new_checked(u)
952 .unwrap_or_else(|| panic!("Value `{u}` out of range for 12-bit immediate"))
953}
954
955fn check_imm18(u: u32) -> Imm18 {
956 Imm18::new_checked(u)
957 .unwrap_or_else(|| panic!("Value `{u}` out of range for 18-bit immediate"))
958}
959
960fn check_imm24(u: u32) -> Imm24 {
961 Imm24::new_checked(u)
962 .unwrap_or_else(|| panic!("Value `{u}` out of range for 24-bit immediate"))
963}
964
965#[test]
970fn test_instruction_size() {
971 assert_eq!(
979 core::mem::size_of::<Instruction>(),
980 core::mem::size_of::<RawInstruction>()
981 );
982
983 assert_eq!(core::mem::size_of::<Instruction>(), Instruction::SIZE);
984}
985
986#[test]
988fn test_opcode_size() {
989 assert_eq!(core::mem::size_of::<Opcode>(), 1);
990}
991
992#[test]
993#[allow(clippy::match_like_matches_macro)]
994fn check_predicate_allowed() {
995 use Opcode::*;
996 for byte in 0..u8::MAX {
997 if let Ok(repr) = Opcode::try_from(byte) {
998 let should_allow = match repr {
999 BAL | BHEI | BHSH | BURN | CALL | CB | CCP | CROO | CSIZ | LOG | LOGD
1000 | MINT | RETD | RVRT | SMO | SCWQ | SRW | SRWQ | SWW | SWWQ | TIME
1001 | TR | TRO | ECAL => false,
1002 _ => true,
1003 };
1004 assert_eq!(should_allow, repr.is_predicate_allowed());
1005 }
1006 }
1007}
1008
1009#[test]
1011fn test_opcode_u8_conv() {
1012 for u in 0..=u8::MAX {
1013 if let Ok(op) = Opcode::try_from(u) {
1014 assert_eq!(op as u8, u);
1015 }
1016 }
1017}