use super::config::*;
use super::consts::*;
use super::formatter::*;
use super::operand::*;
use crate::error::*;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum Encoding {
None,
Alt1,
Alt2,
Alt3,
Alt4,
Alt5,
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub struct Instruction {
pub code: Code,
pub encoding: Encoding,
pub mnemonic: Mnemonic,
pub pc: u32,
pub size: usize,
pub operands: [Operand; MAX_OPERAND_COUNT],
}
impl Instruction {
pub fn builder(code: Code) -> InstructionBuilder {
let mut instruction = Instruction::default();
instruction.code = code;
instruction.encoding = Encoding::None;
instruction.mnemonic = code.mnemonic(&instruction);
instruction.pc = 0;
instruction.size = code.size(&instruction);
InstructionBuilder { inner: instruction }
}
pub fn with_0(code: Code) -> Instruction {
Instruction::builder(code).build()
}
pub fn with_1(code: Code, op0: impl Into<Operand>) -> Result<Instruction> {
Ok(Instruction::builder(code).op0(op0)?.build())
}
pub fn with_2(
code: Code,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder(code).op0(op0)?.op1(op1)?.build())
}
pub fn with_3(
code: Code,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
op2: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder(code)
.op0(op0)?
.op1(op1)?
.op2(op2)?
.build())
}
pub fn with_4(
code: Code,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
op2: impl Into<Operand>,
op3: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder(code)
.op0(op0)?
.op1(op1)?
.op2(op2)?
.op3(op3)?
.build())
}
pub fn with_5(
code: Code,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
op2: impl Into<Operand>,
op3: impl Into<Operand>,
op4: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder(code)
.op0(op0)?
.op1(op1)?
.op2(op2)?
.op3(op3)?
.op4(op4)?
.build())
}
pub fn with_6(
code: Code,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
op2: impl Into<Operand>,
op3: impl Into<Operand>,
op4: impl Into<Operand>,
op5: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder(code)
.op0(op0)?
.op1(op1)?
.op2(op2)?
.op3(op3)?
.op4(op4)?
.op5(op5)?
.build())
}
pub fn with_7(
code: Code,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
op2: impl Into<Operand>,
op3: impl Into<Operand>,
op4: impl Into<Operand>,
op5: impl Into<Operand>,
op6: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder(code)
.op0(op0)?
.op1(op1)?
.op2(op2)?
.op3(op3)?
.op4(op4)?
.op5(op5)?
.op6(op6)?
.build())
}
pub fn with_encoding_0(code: Code, encoding: Encoding) -> Instruction {
Instruction::builder_multi(code, encoding).build()
}
pub fn with_encoding_1(
code: Code,
encoding: Encoding,
op0: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder_multi(code, encoding).op0(op0)?.build())
}
pub fn with_encoding_2(
code: Code,
encoding: Encoding,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder_multi(code, encoding)
.op0(op0)?
.op1(op1)?
.build())
}
pub fn with_encoding_3(
code: Code,
encoding: Encoding,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
op2: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder_multi(code, encoding)
.op0(op0)?
.op1(op1)?
.op2(op2)?
.build())
}
pub fn with_encoding_4(
code: Code,
encoding: Encoding,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
op2: impl Into<Operand>,
op3: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder_multi(code, encoding)
.op0(op0)?
.op1(op1)?
.op2(op2)?
.op3(op3)?
.build())
}
pub fn with_encoding_5(
code: Code,
encoding: Encoding,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
op2: impl Into<Operand>,
op3: impl Into<Operand>,
op4: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder_multi(code, encoding)
.op0(op0)?
.op1(op1)?
.op2(op2)?
.op3(op3)?
.op4(op4)?
.build())
}
pub fn with_encoding_6(
code: Code,
encoding: Encoding,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
op2: impl Into<Operand>,
op3: impl Into<Operand>,
op4: impl Into<Operand>,
op5: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder_multi(code, encoding)
.op0(op0)?
.op1(op1)?
.op2(op2)?
.op3(op3)?
.op4(op4)?
.op5(op5)?
.build())
}
pub fn with_encoding_7(
code: Code,
encoding: Encoding,
op0: impl Into<Operand>,
op1: impl Into<Operand>,
op2: impl Into<Operand>,
op3: impl Into<Operand>,
op4: impl Into<Operand>,
op5: impl Into<Operand>,
op6: impl Into<Operand>,
) -> Result<Instruction> {
Ok(Instruction::builder_multi(code, encoding)
.op0(op0)?
.op1(op1)?
.op2(op2)?
.op3(op3)?
.op4(op4)?
.op5(op5)?
.op6(op6)?
.build())
}
pub fn builder_multi(code: Code, encoding: Encoding) -> InstructionBuilder {
let mut instruction = Instruction::default();
instruction.code = code;
instruction.encoding = encoding;
instruction.mnemonic = code.mnemonic(&instruction);
instruction.pc = 0;
instruction.size = code.size(&instruction);
InstructionBuilder { inner: instruction }
}
pub fn get_op(&self, index: usize) -> &Operand {
if index >= MAX_OPERAND_COUNT {
todo!()
}
&self.operands[index]
}
pub fn set_op(&mut self, index: usize, operand: impl Into<Operand>) -> Result<()> {
if index >= MAX_OPERAND_COUNT {
return Err(OperandError::OperandIndexOutOfRange(
index,
MAX_OPERAND_COUNT,
))?;
}
let operand = operand.into();
self.code.check_op(index, &self, &operand)?;
self.operands[index] = operand;
Ok(())
}
pub fn op0(&self) -> &Operand {
&self.operands[0]
}
pub fn op1(&self) -> &Operand {
&self.operands[1]
}
pub fn op2(&self) -> &Operand {
&self.operands[2]
}
pub fn op3(&self) -> &Operand {
&self.operands[3]
}
pub fn op4(&self) -> &Operand {
&self.operands[4]
}
pub fn op5(&self) -> &Operand {
&self.operands[5]
}
pub fn op6(&self) -> &Operand {
&self.operands[6]
}
pub fn format(
&self,
fmt: &mut impl Formatter,
output: &mut impl FormatterOutput,
config: &Config,
) -> Result<()> {
self.code.format(self, fmt, output, config)
}
pub fn condition(&self) -> ConditionalInstruction {
self.code.condition(self)
}
}
impl Default for Instruction {
fn default() -> Self {
Self {
code: Code::Invalid,
mnemonic: Mnemonic::Invalid,
encoding: Encoding::None,
operands: [Operand::default(); MAX_OPERAND_COUNT],
pc: 0,
size: 0,
}
}
}
pub struct InstructionBuilder {
inner: Instruction,
}
impl From<Instruction> for InstructionBuilder {
fn from(value: Instruction) -> Self {
Self { inner: value }
}
}
impl InstructionBuilder {
pub fn operand(mut self, index: usize, operand: impl Into<Operand>) -> Result<Self> {
if index >= MAX_OPERAND_COUNT {
return Err(OperandError::OperandIndexOutOfRange(
index,
MAX_OPERAND_COUNT,
))?;
}
let operand = operand.into();
self.inner.code.check_op(index, &self.inner, &operand)?;
self.inner.operands[index] = operand;
Ok(self)
}
pub fn op0(self, operand: impl Into<Operand>) -> Result<Self> {
self.operand(0, operand)
}
pub fn op1(self, operand: impl Into<Operand>) -> Result<Self> {
self.operand(1, operand)
}
pub fn op2(self, operand: impl Into<Operand>) -> Result<Self> {
self.operand(2, operand)
}
pub fn op3(self, operand: impl Into<Operand>) -> Result<Self> {
self.operand(3, operand)
}
pub fn op4(self, operand: impl Into<Operand>) -> Result<Self> {
self.operand(4, operand)
}
pub fn op5(self, operand: impl Into<Operand>) -> Result<Self> {
self.operand(5, operand)
}
pub fn op6(self, operand: impl Into<Operand>) -> Result<Self> {
self.operand(6, operand)
}
pub fn build(self) -> Instruction {
self.inner
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub enum InstructionBlockElement {
Instruction(Instruction),
Label(u64),
}
impl From<Instruction> for InstructionBlockElement {
fn from(value: Instruction) -> Self {
InstructionBlockElement::Instruction(value)
}
}
impl From<u64> for InstructionBlockElement {
fn from(value: u64) -> Self {
InstructionBlockElement::Label(value)
}
}
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash, Default)]
pub struct InstructionBlock {
pub pc: u32,
pub instructions: Vec<InstructionBlockElement>,
}
impl InstructionBlock {
pub fn new(pc: u32) -> Self {
Self {
pc,
instructions: vec![],
}
}
pub fn with_instructions(pc: u32, instructions: Vec<InstructionBlockElement>) -> Self {
Self { pc, instructions }
}
pub fn push_instruction(&mut self, instruction: Instruction) {
self.instructions.push(instruction.into())
}
pub fn push_label(&mut self, label: u64) {
self.instructions.push(label.into())
}
}