2023-07-21 19:26:03 -05:00
|
|
|
//! Macros to generate [`crate::Assembler`]
|
|
|
|
|
|
|
|
/// Incremental token-tree muncher to implement specific instruction
|
|
|
|
/// functions based on generic function for instruction type
|
2023-07-10 16:18:23 -05:00
|
|
|
macro_rules! impl_asm_opcodes {
|
2023-07-21 19:26:03 -05:00
|
|
|
( // End case
|
2023-07-10 16:18:23 -05:00
|
|
|
$generic:ident
|
|
|
|
($($param_i:ident: $param_ty:ty),*)
|
|
|
|
=> []
|
|
|
|
) => {};
|
|
|
|
|
|
|
|
(
|
|
|
|
$generic:ident
|
|
|
|
($($param_i:ident: $param_ty:ty),*)
|
|
|
|
=> [$opcode:ident, $($rest:tt)*]
|
|
|
|
) => {
|
2023-07-21 19:26:03 -05:00
|
|
|
// Instruction-specific function
|
2023-07-10 16:18:23 -05:00
|
|
|
paste::paste! {
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn [<i_ $opcode:lower>](&mut self, $($param_i: $param_ty),*) {
|
|
|
|
self.$generic(hbbytecode::opcode::$opcode, $($param_i),*)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-21 19:26:03 -05:00
|
|
|
// And recurse!
|
2023-07-11 19:16:23 -05:00
|
|
|
macros::asm::impl_asm_opcodes!(
|
2023-07-10 16:18:23 -05:00
|
|
|
$generic($($param_i: $param_ty),*)
|
|
|
|
=> [$($rest)*]
|
|
|
|
);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-07-21 19:26:03 -05:00
|
|
|
/// Numeric value insert
|
2023-07-11 19:16:23 -05:00
|
|
|
macro_rules! impl_asm_insert {
|
2023-07-21 19:26:03 -05:00
|
|
|
// Immediate - this is trait-based,
|
|
|
|
// the insertion is delegated to its implementation
|
2023-07-11 19:16:23 -05:00
|
|
|
($self:expr, $id:ident, I) => {
|
|
|
|
Imm::insert(&$id, $self)
|
|
|
|
};
|
2023-07-10 16:18:23 -05:00
|
|
|
|
2023-07-24 13:41:10 -05:00
|
|
|
// Length - cannot be more than 2048
|
|
|
|
($self:expr, $id:ident, L) => {{
|
|
|
|
assert!($id <= 2048);
|
|
|
|
$self.buf.extend($id.to_le_bytes())
|
|
|
|
}};
|
|
|
|
|
2023-07-21 19:26:03 -05:00
|
|
|
// Other numbers, just insert their bytes, little endian
|
2023-07-11 19:16:23 -05:00
|
|
|
($self:expr, $id:ident, $_:ident) => {
|
|
|
|
$self.buf.extend($id.to_le_bytes())
|
2023-07-10 16:18:23 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-07-21 19:26:03 -05:00
|
|
|
/// Implement assembler
|
2023-07-10 16:18:23 -05:00
|
|
|
macro_rules! impl_asm {
|
|
|
|
(
|
|
|
|
$(
|
|
|
|
$ityn:ident
|
2023-07-11 19:16:23 -05:00
|
|
|
($($param_i:ident: $param_ty:ident),* $(,)?)
|
2023-07-10 16:18:23 -05:00
|
|
|
=> [$($opcode:ident),* $(,)?],
|
|
|
|
)*
|
|
|
|
) => {
|
|
|
|
paste::paste! {
|
|
|
|
$(
|
2023-07-21 19:26:03 -05:00
|
|
|
// Opcode-generic functions specific for instruction types
|
|
|
|
pub fn [<i_param_ $ityn>](&mut self, opcode: u8, $($param_i: macros::asm::ident_map_ty!($param_ty)),*) {
|
2023-07-10 16:18:23 -05:00
|
|
|
self.buf.push(opcode);
|
2023-07-11 19:16:23 -05:00
|
|
|
$(macros::asm::impl_asm_insert!(self, $param_i, $param_ty);)*
|
2023-07-10 16:18:23 -05:00
|
|
|
}
|
|
|
|
|
2023-07-21 19:26:03 -05:00
|
|
|
// Generate opcode-specific functions calling the opcode-generic ones
|
2023-07-11 19:16:23 -05:00
|
|
|
macros::asm::impl_asm_opcodes!(
|
|
|
|
[<i_param_ $ityn>]($($param_i: macros::asm::ident_map_ty!($param_ty)),*)
|
2023-07-10 16:18:23 -05:00
|
|
|
=> [$($opcode,)*]
|
|
|
|
);
|
|
|
|
)*
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-07-21 19:26:03 -05:00
|
|
|
/// Map operand type to Rust type
|
2023-07-11 19:16:23 -05:00
|
|
|
#[rustfmt::skip]
|
|
|
|
macro_rules! ident_map_ty {
|
2023-07-21 19:26:03 -05:00
|
|
|
(R) => { u8 }; // Register is just u8
|
|
|
|
(I) => { impl Imm }; // Immediate is anything implementing the trait
|
2023-07-24 13:41:10 -05:00
|
|
|
(L) => { u16 }; // Copy count
|
2023-07-21 19:26:03 -05:00
|
|
|
($id:ident) => { $id }; // Anything else → identity map
|
2023-07-11 19:16:23 -05:00
|
|
|
}
|
|
|
|
|
2023-07-21 19:26:03 -05:00
|
|
|
pub(crate) use {ident_map_ty, impl_asm, impl_asm_insert, impl_asm_opcodes};
|