mod common;
mod execute;
mod register;
mod utils;
pub mod ast;
pub mod b;
pub mod i;
pub mod m;
pub mod rvc;
pub use self::register::Register;
use super::Error;
pub use ckb_vm_definitions::instructions::{
self as insts, instruction_opcode_name, Instruction, InstructionOpcode,
};
pub use execute::{execute, execute_instruction};
type RegisterIndex = usize;
type Immediate = i32;
type UImmediate = u32;
#[inline(always)]
pub fn extract_opcode(i: Instruction) -> InstructionOpcode {
(((i >> 8) & 0xff00) | (i & 0x00ff)) as u16
}
pub type InstructionFactory = fn(instruction_bits: u32) -> Option<Instruction>;
pub fn blank_instruction(op: InstructionOpcode) -> Instruction {
(op as u64 >> 8 << 16) | (op as u64 & 0xff)
}
#[derive(Debug, Clone, Copy)]
pub struct Rtype(pub Instruction);
impl Rtype {
pub fn new(
op: InstructionOpcode,
rd: RegisterIndex,
rs1: RegisterIndex,
rs2: RegisterIndex,
) -> Self {
Rtype(
(u64::from(op) >> 8 << 16)
| u64::from(op as u8)
| (u64::from(rd as u8) << 8)
| (u64::from(rs1 as u8) << 32)
| (u64::from(rs2 as u8) << 40),
)
}
pub fn op(self) -> InstructionOpcode {
((self.0 >> 16 << 8) | (self.0 & 0xFF)) as InstructionOpcode
}
pub fn rd(self) -> RegisterIndex {
(self.0 >> 8) as u8 as RegisterIndex
}
pub fn rs1(self) -> RegisterIndex {
(self.0 >> 32) as u8 as RegisterIndex
}
pub fn rs2(self) -> RegisterIndex {
(self.0 >> 40) as u8 as RegisterIndex
}
}
#[derive(Debug, Clone, Copy)]
pub struct Itype(pub Instruction);
impl Itype {
pub fn new(
op: InstructionOpcode,
rd: RegisterIndex,
rs1: RegisterIndex,
immediate: UImmediate,
) -> Self {
Itype(
(u64::from(op) >> 8 << 16) |
u64::from(op as u8) |
(u64::from(rd as u8) << 8) |
(u64::from(rs1 as u8) << 32) |
(u64::from(immediate) << 40),
)
}
pub fn new_s(
op: InstructionOpcode,
rd: RegisterIndex,
rs1: RegisterIndex,
immediate: Immediate,
) -> Self {
Self::new(op, rd, rs1, immediate as UImmediate)
}
pub fn op(self) -> InstructionOpcode {
((self.0 >> 16 << 8) | (self.0 & 0xFF)) as InstructionOpcode
}
pub fn rd(self) -> RegisterIndex {
(self.0 >> 8) as u8 as RegisterIndex
}
pub fn rs1(self) -> RegisterIndex {
(self.0 >> 32) as u8 as RegisterIndex
}
pub fn immediate(self) -> UImmediate {
self.immediate_s() as UImmediate
}
pub fn immediate_s(self) -> Immediate {
((self.0 as i64) >> 40) as Immediate
}
}
#[derive(Debug, Clone, Copy)]
pub struct Stype(pub Instruction);
impl Stype {
pub fn new(
op: InstructionOpcode,
immediate: UImmediate,
rs1: RegisterIndex,
rs2: RegisterIndex,
) -> Self {
Stype(
(u64::from(op) >> 8 << 16) |
u64::from(op as u8) |
(u64::from(rs2 as u8) << 8) |
(u64::from(rs1 as u8) << 32) |
(u64::from(immediate) << 40),
)
}
pub fn new_s(
op: InstructionOpcode,
immediate: Immediate,
rs1: RegisterIndex,
rs2: RegisterIndex,
) -> Self {
Self::new(op, immediate as UImmediate, rs1, rs2)
}
pub fn op(self) -> InstructionOpcode {
((self.0 >> 16 << 8) | (self.0 & 0xFF)) as InstructionOpcode
}
pub fn rs1(self) -> RegisterIndex {
(self.0 >> 32) as u8 as RegisterIndex
}
pub fn rs2(self) -> RegisterIndex {
(self.0 >> 8) as u8 as RegisterIndex
}
pub fn immediate(self) -> UImmediate {
self.immediate_s() as UImmediate
}
pub fn immediate_s(self) -> Immediate {
((self.0 as i64) >> 40) as Immediate
}
}
#[derive(Debug, Clone, Copy)]
pub struct Utype(pub Instruction);
impl Utype {
pub fn new(op: InstructionOpcode, rd: RegisterIndex, immediate: UImmediate) -> Self {
Utype(
(u64::from(op) >> 8 << 16)
| u64::from(op as u8)
| (u64::from(rd as u8) << 8)
| (u64::from(immediate) << 32),
)
}
pub fn new_s(op: InstructionOpcode, rd: RegisterIndex, immediate: Immediate) -> Self {
Self::new(op, rd, immediate as UImmediate)
}
pub fn op(self) -> InstructionOpcode {
((self.0 >> 16 << 8) | (self.0 & 0xFF)) as InstructionOpcode
}
pub fn rd(self) -> RegisterIndex {
(self.0 >> 8) as u8 as RegisterIndex
}
pub fn immediate(self) -> UImmediate {
self.immediate_s() as UImmediate
}
pub fn immediate_s(self) -> Immediate {
((self.0 as i64) >> 32) as Immediate
}
}
#[derive(Debug, Clone, Copy)]
pub struct R4type(pub Instruction);
impl R4type {
pub fn new(
op: InstructionOpcode,
rd: RegisterIndex,
rs1: RegisterIndex,
rs2: RegisterIndex,
rs3: RegisterIndex,
) -> Self {
R4type(
(u64::from(op) >> 8 << 16)
| u64::from(op as u8)
| (u64::from(rd as u8) << 8)
| (u64::from(rs1 as u8) << 32)
| (u64::from(rs2 as u8) << 40)
| (u64::from(rs3 as u8) << 48),
)
}
pub fn op(self) -> InstructionOpcode {
((self.0 >> 16 << 8) | (self.0 & 0xFF)) as InstructionOpcode
}
pub fn rd(self) -> RegisterIndex {
(self.0 >> 8) as u8 as RegisterIndex
}
pub fn rs1(self) -> RegisterIndex {
(self.0 >> 32) as u8 as RegisterIndex
}
pub fn rs2(self) -> RegisterIndex {
(self.0 >> 40) as u8 as RegisterIndex
}
pub fn rs3(self) -> RegisterIndex {
(self.0 >> 48) as u8 as RegisterIndex
}
}
pub fn is_slowpath_instruction(i: Instruction) -> bool {
i as u8 >= 0xF0
}
pub fn is_basic_block_end_instruction(i: Instruction) -> bool {
matches!(
extract_opcode(i),
insts::OP_AUIPC
| insts::OP_JALR
| insts::OP_BEQ
| insts::OP_BNE
| insts::OP_BLT
| insts::OP_BGE
| insts::OP_BLTU
| insts::OP_BGEU
| insts::OP_ECALL
| insts::OP_EBREAK
| insts::OP_JAL
| insts::OP_FAR_JUMP_ABS
| insts::OP_FAR_JUMP_REL
) | is_slowpath_instruction(i)
}
#[inline(always)]
pub fn set_instruction_length_2(i: u64) -> u64 {
i | 0x1000000
}
#[inline(always)]
pub fn set_instruction_length_4(i: u64) -> u64 {
i | 0x2000000
}
#[inline(always)]
pub fn set_instruction_length_n(i: u64, n: u8) -> u64 {
i | ((n as u64 & 0x0f) >> 1 << 24)
}
#[inline(always)]
pub fn instruction_length(i: Instruction) -> u8 {
(((i >> 24) & 0x0f) << 1) as u8
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem::size_of;
#[test]
fn test_instruction_op_should_fit_in_byte() {
assert_eq!(2, size_of::<InstructionOpcode>());
}
}