mod single_word_multi_format;
mod single_word_single_format;
mod three_words;
mod two_words;
use crate::emulator::constants::*;
use crate::emulator::core::sign_extend;
use crate::emulator::instructions::*;
use crate::emulator::RegisterFile;
use std::collections::vec_deque::VecDeque;
pub struct Decoder(
VecDeque<DecodedInstruction>,
);
impl Decoder {
#[inline]
pub fn get_next_instruction(
&mut self,
ip: usize,
memory: &[u8],
register_file: &RegisterFile,
) -> (DecodedInstruction, bool) {
if let Some(micro_op) = self.0.pop_front() {
log::trace!("Got another micro-op, {} left", self.0.len());
(micro_op, !self.0.is_empty())
} else {
match decode(ip, memory, register_file) {
DecodeResult::Simple(instruction) => (instruction, false),
DecodeResult::Complex(instruction) => {
(instruction.generate_function)(
instruction,
register_file,
memory,
&mut self.0,
);
log::debug!("Generated {} micro-ops", self.0.len());
let first = self.0.pop_front().unwrap();
(first, !self.0.is_empty())
}
}
}
}
}
impl Default for Decoder {
fn default() -> Self {
Self(VecDeque::with_capacity(32))
}
}
pub struct DecodedInstruction {
pub address: usize,
pub size: u8,
pub instruction: &'static SimpleIsaInstruction,
pub operands: [Operand; 4],
pub operand_count: u8,
pub operand_type: OperandType,
pub memory_address: usize,
pub branch_address: usize,
pub mask_index: u8,
pub option_bits: u8,
pub operand_extension: OperandExtension,
}
impl Default for DecodedInstruction {
fn default() -> Self {
Self {
address: 0,
size: 0,
instruction: &NOP,
operands: [Operand::None, Operand::None, Operand::None, Operand::None],
operand_type: OperandType::I32,
operand_count: 0,
memory_address: 0,
branch_address: 0,
mask_index: default_values::MASK,
option_bits: 0,
operand_extension: OperandExtension::None,
}
}
}
pub struct DecodedComplexInstruction {
pub generate_function: ComplexInstructionFunction,
pub address: usize,
pub stack_pointer: u32,
pub data_register: u32,
pub option_bits: u8,
pub operand_type: OperandType,
pub vector_instruction: bool,
}
pub enum DecodeResult {
Simple(DecodedInstruction),
Complex(DecodedComplexInstruction),
}
#[derive(Clone)]
pub struct MemoryOperand {
pub register_count: u8,
pub registers: [u32; 2],
}
#[derive(Clone)]
pub enum Operand {
None,
GeneralPurposeRegister(u32),
SpecialRegister(u32),
VectorRegister(u32),
Immediate(u64),
Memory(MemoryOperand),
}
impl Operand {
pub fn override_type(self, other: &Operand) -> Operand {
let index = match self {
Self::GeneralPurposeRegister(index)
| Self::SpecialRegister(index)
| Self::VectorRegister(index) => index,
_ => panic!("Tried to override non-register type!"),
};
match other {
Self::GeneralPurposeRegister(_) => Self::GeneralPurposeRegister(index),
Self::SpecialRegister(_) => Self::SpecialRegister(index),
Self::VectorRegister(_) => Self::VectorRegister(index),
_ => panic!("Tried to override with non-register type!"),
}
}
}
#[derive(Clone, Copy)]
pub enum OperandType {
I8,
I16,
I32,
I64,
I128,
F16,
F32,
F64,
F128,
}
impl OperandType {
#[inline]
fn from_value(value: u32) -> Self {
match value {
0 => Self::I8,
1 => Self::I16,
2 => Self::I32,
3 => Self::I64,
4 => Self::I128,
5 => Self::F32,
6 => Self::F64,
7 => Self::F128,
_ => Self::F16,
}
}
#[inline]
pub fn log_size(&self) -> usize {
match self {
OperandType::I8 => 0,
OperandType::I16 => 1,
OperandType::I32 => 2,
OperandType::I64 => 3,
OperandType::I128 => 4,
OperandType::F16 => 1,
OperandType::F32 => 2,
OperandType::F64 => 3,
OperandType::F128 => 4,
}
}
#[inline]
pub fn is_float(&self) -> bool {
match self {
Self::I8 | Self::I16 | Self::I32 | Self::I64 | Self::I128 => false,
Self::F16 | Self::F32 | Self::F64 | Self::F128 => true,
}
}
}
pub enum OperandExtension {
None,
Scalar,
Default(u16),
Broadcast(u16),
}
fn decode(ip: usize, memory: &[u8], register_file: &RegisterFile) -> DecodeResult {
let first_word = u32::from_le_bytes(memory[ip..ip + 4].try_into().unwrap());
let il_field = (first_word & parse_masks::IL) >> parse_shifts::IL;
let mode_field;
let ot_field;
let mode_base = (first_word & parse_masks::MODE) >> parse_shifts::MODE;
if mode_base < 2 {
mode_field = ((first_word & parse_masks::M) >> parse_shifts::M_MODE) | mode_base;
ot_field = (first_word & parse_masks::OT) >> parse_shifts::OT;
} else {
mode_field = mode_base;
ot_field = ((first_word & parse_masks::M) >> parse_shifts::M_OT)
| ((first_word & parse_masks::OT) >> parse_shifts::OT);
}
match il_field {
0 => single_word_multi_format::decode(ip, first_word, mode_field, ot_field, register_file),
1 => single_word_single_format::decode(ip, first_word, mode_field, ot_field, register_file),
2 => two_words::decode(
ip,
first_word,
u32::from_le_bytes(memory[ip + 4..ip + 8].try_into().unwrap()),
mode_field,
ot_field,
register_file,
),
3 => three_words::decode(ip, memory, first_word, mode_field, ot_field, register_file),
_ => unreachable!(),
}
}
#[inline]
fn interpret_immediate(raw: u64, size: u8, operand_type: OperandType) -> u64 {
match operand_type {
OperandType::I8 | OperandType::I16 | OperandType::I32 | OperandType::I64 => {
sign_extend(raw, 8 << size)
}
OperandType::I128 => raw,
OperandType::F16 => {
match size {
0 => half::f16::from(raw as u8).to_bits() as u64,
1 => raw,
2 => half::f16::from_f32(f32::from_bits(raw as u32)).to_bits() as u64,
3 => half::f16::from_f64(f64::from_bits(raw)).to_bits() as u64,
_ => raw,
}
}
OperandType::F32 => {
match size {
0 => (raw as u8 as f32).to_bits() as u64,
1 => half::f16::from_bits(raw as u16).to_f32().to_bits() as u64,
2 => raw,
3 => (f64::from_bits(raw) as f32).to_bits() as u64,
_ => raw,
}
}
OperandType::F64 => {
match size {
0 => (raw as u8 as f64).to_bits(),
1 => half::f16::from_bits(raw as u16).to_f64().to_bits(),
2 => (f32::from_bits(raw as u32) as f64).to_bits(),
3 => raw,
_ => raw,
}
}
OperandType::F128 => raw,
}
}