Added initial support for executing instructions.

This commit is contained in:
Filipe Rodrigues 2021-05-01 16:24:07 +01:00
parent 233db9b200
commit 3c02d93dd9
18 changed files with 596 additions and 17 deletions

View File

@ -5,6 +5,7 @@ pub mod basic;
pub mod decode;
pub mod directive;
pub mod error;
pub mod exec;
pub mod fmt;
pub mod parse;
pub mod pseudo;

View File

@ -18,6 +18,7 @@ pub mod sys;
// Imports
use super::{
exec::{ExecError, ExecState, Executable},
parse::{LineArg, Parsable},
DisplayCtx, InstDisplay, InstFmtArg, InstSize, ParseCtx, ParseError, Register,
};
@ -194,6 +195,25 @@ impl ModifiesReg for Inst {
}
}
impl Executable for Inst {
#[rustfmt::skip]
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
match self {
Inst::Alu (inst) => inst.exec(state),
Inst::Cond (inst) => inst.exec(state),
Inst::Jmp (inst) => inst.exec(state),
Inst::Load (inst) => inst.exec(state),
Inst::Lui (inst) => inst.exec(state),
Inst::Mult (inst) => inst.exec(state),
Inst::Shift(inst) => inst.exec(state),
Inst::Store(inst) => inst.exec(state),
//Inst::Sys (inst) => inst.exec(state),
//Inst::Co (inst) => inst.exec(state),
_ => todo!(),
}
}
}
// Any basic decodable instruction is 4 bytes
impl<T: Decode> InstSize for T {
fn size(&self) -> usize {

View File

@ -8,6 +8,7 @@ pub mod reg;
use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError,
};
@ -78,3 +79,12 @@ impl ModifiesReg for Inst {
}
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
match self {
Inst::Imm(inst) => inst.exec(state),
Inst::Reg(inst) => inst.exec(state),
}
}
}

View File

@ -3,10 +3,11 @@
// Imports
use crate::inst::{
basic::{Decode, Encode, ModifiesReg},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::{Signed, Truncated, ZeroExtended};
use int_conv::{SignExtended, Signed, Truncated, ZeroExtended};
use std::{array, convert::TryInto};
/// Instruction kind
@ -184,3 +185,29 @@ impl ModifiesReg for Inst {
self.dst == reg
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
state[self.dst] = match self.kind {
Kind::Add(rhs) => state[self.lhs]
.as_signed()
.checked_add(rhs.sign_extended::<i32>())
.ok_or(ExecError::Overflow)?
.as_unsigned(),
Kind::AddUnsigned(rhs) => state[self.lhs]
.as_signed()
.wrapping_add(rhs.sign_extended::<i32>())
.as_unsigned(),
Kind::SetLessThan(rhs) => state[self.lhs].as_signed().lt(&rhs.sign_extended::<i32>()).into(),
// TODO: Verify it's sign extended
Kind::SetLessThanUnsigned(rhs) => state[self.lhs]
.lt(&rhs.as_signed().sign_extended::<i32>().as_unsigned())
.into(),
Kind::And(rhs) => state[self.lhs] & rhs.zero_extended::<u32>(),
Kind::Or(rhs) => state[self.lhs] | rhs.zero_extended::<u32>(),
Kind::Xor(rhs) => state[self.lhs] ^ rhs.zero_extended::<u32>(),
};
Ok(())
}
}

View File

@ -3,9 +3,11 @@
// Imports
use crate::inst::{
basic::{Decode, Encode, ModifiesReg},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::Signed;
use std::array;
/// Alu register instruction kind
@ -198,3 +200,33 @@ impl ModifiesReg for Inst {
self.dst == reg
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
let lhs = state[self.lhs];
let rhs = state[self.rhs];
state[self.dst] = match self.kind {
Kind::Add => lhs
.as_signed()
.checked_add(rhs.as_signed())
.ok_or(ExecError::Overflow)?
.as_unsigned(),
Kind::AddUnsigned => lhs.as_signed().wrapping_add(rhs.as_signed()).as_unsigned(),
Kind::Sub => lhs
.as_signed()
.checked_sub(rhs.as_signed())
.ok_or(ExecError::Overflow)?
.as_unsigned(),
Kind::SubUnsigned => lhs.as_signed().wrapping_sub(rhs.as_signed()).as_unsigned(),
Kind::And => lhs & rhs,
Kind::Or => lhs | rhs,
Kind::Xor => lhs ^ rhs,
Kind::Nor => !(lhs | rhs),
Kind::SetLessThan => (lhs.as_signed() < rhs.as_signed()).into(),
Kind::SetLessThanUnsigned => (lhs < rhs).into(),
};
Ok(())
}
}

View File

@ -5,6 +5,7 @@ use super::ModifiesReg;
use crate::{
inst::{
basic::{Decode, Encode},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
},
@ -264,3 +265,30 @@ impl ModifiesReg for Inst {
false
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
let lhs = state[self.arg].as_signed();
let do_jump = match self.kind {
Kind::Equal(rhs) => lhs == state[rhs].as_signed(),
Kind::NotEqual(rhs) => lhs != state[rhs].as_signed(),
Kind::LessOrEqualZero => lhs <= 0i32,
Kind::GreaterThanZero => lhs > 0i32,
Kind::LessThanZero | Kind::LessThanZeroLink => lhs < 0i32,
Kind::GreaterOrEqualZero | Kind::GreaterOrEqualZeroLink => lhs >= 0i32,
};
match do_jump {
true => {
// If we should link, set `$ra`
if matches!(self.kind, Kind::LessThanZeroLink | Kind::GreaterOrEqualZeroLink) {
state[Register::Ra] = (state.pc() + 8u32).0;
}
// Then set the jump
state.set_jump(self.target(state.pc()))
},
false => Ok(()),
}
}
}

View File

@ -8,6 +8,7 @@ pub mod reg;
use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
@ -78,3 +79,12 @@ impl ModifiesReg for Inst {
}
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
match self {
Inst::Imm(inst) => inst.exec(state),
Inst::Reg(inst) => inst.exec(state),
}
}
}

View File

@ -4,6 +4,7 @@
use crate::{
inst::{
basic::{Decode, Encode, ModifiesReg},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
},
@ -134,3 +135,15 @@ impl ModifiesReg for Inst {
false
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
// If we should link, set `$ra`
if matches!(self.kind, Kind::JumpLink) {
state[Register::Ra] = (state.pc() + 8u32).0;
}
// Then set the jump
state.set_jump(self.target(state.pc()))
}
}

View File

@ -1,10 +1,14 @@
//! Jump register instructions
// Imports
use crate::inst::{
basic::{Decode, Encode, ModifiesReg},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
use crate::{
inst::{
basic::{Decode, Encode, ModifiesReg},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
},
Pos,
};
use std::array;
@ -122,3 +126,15 @@ impl ModifiesReg for Inst {
false
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
// If we should link, set `$ra`
if let Kind::JumpLink(link) = self.kind {
state[link] = (state.pc() + 8u32).0;
}
// Then set the jump
state.set_jump(Pos(state[self.target]))
}
}

View File

@ -2,12 +2,16 @@
// Imports
use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
use crate::{
inst::{
basic::{Decode, Encode},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
},
Pos,
};
use int_conv::{Signed, Truncated, ZeroExtended};
use int_conv::{SignExtended, Signed, Truncated, ZeroExtended};
use std::array;
/// Instruction kind
@ -174,3 +178,27 @@ impl ModifiesReg for Inst {
self.value == reg
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
state[self.value] = match self.kind {
Kind::Byte => state
.read_byte(Pos(state[self.addr]))?
.as_signed()
.sign_extended::<i32>()
.as_unsigned(),
Kind::HalfWord => state
.read_half_word(Pos(state[self.addr]))?
.as_signed()
.sign_extended::<i32>()
.as_unsigned(),
Kind::Word => state.read_word(Pos(state[self.addr]))?,
Kind::ByteUnsigned => state.read_byte(Pos(state[self.addr]))?.zero_extended(),
Kind::HalfWordUnsigned => state.read_half_word(Pos(state[self.addr]))?.zero_extended(),
Kind::WordLeft | Kind::WordRight => todo!(),
};
Ok(())
}
}

View File

@ -4,10 +4,11 @@
use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::{Truncated, ZeroExtended};
use int_conv::{Join, Truncated, ZeroExtended};
use std::array;
/// Load instructions
@ -82,3 +83,10 @@ impl ModifiesReg for Inst {
self.dst == reg
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
state[self.dst] = u32::join(0, self.value);
Ok(())
}
}

View File

@ -4,9 +4,11 @@
use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::{SignExtended, Signed, Split, ZeroExtended};
use std::array;
/// Operation kind
@ -243,3 +245,48 @@ impl ModifiesReg for Inst {
}
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
match *self {
Inst::Mult { kind, mode, lhs, rhs } => {
let (lo, hi) = match (kind, mode) {
(MultKind::Mult, MultMode::Signed) => {
let lhs: i64 = state[lhs].as_signed().sign_extended();
let rhs: i64 = state[rhs].as_signed().sign_extended();
lhs.wrapping_mul(rhs).as_unsigned().lo_hi()
},
(MultKind::Mult, MultMode::Unsigned) => {
let lhs: u64 = state[lhs].zero_extended();
let rhs: u64 = state[rhs].zero_extended();
lhs.wrapping_mul(rhs).as_unsigned().lo_hi()
},
(MultKind::Div, MultMode::Signed) => match (state[lhs].as_signed(), state[rhs].as_signed()) {
(lhs @ 0i32..=i32::MAX, 0i32) => ((-1i32).as_unsigned(), lhs.as_unsigned()),
(lhs @ i32::MIN..0i32, 0i32) => (1u32, lhs.as_unsigned()),
(lhs, rhs) => (lhs.wrapping_div(rhs).as_unsigned(), lhs.wrapping_rem(rhs).as_unsigned()),
},
(MultKind::Div, MultMode::Unsigned) => match (state[lhs], state[rhs]) {
(lhs, 0) => ((-1i32).as_unsigned(), lhs),
(lhs, rhs) => (lhs / rhs, lhs % rhs),
},
};
state[MultReg::Lo] = lo;
state[MultReg::Hi] = hi;
Ok(())
},
Inst::MoveFrom { dst, src } => {
state[dst] = state[src];
Ok(())
},
Inst::MoveTo { src, dst } => {
state[dst] = state[src];
Ok(())
},
}
}
}

View File

@ -7,6 +7,7 @@ pub mod reg;
// Imports
use crate::inst::{
basic::{Decode, Encode, ModifiesReg, TryEncode},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
@ -87,3 +88,12 @@ impl ModifiesReg for Inst {
}
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
match self {
Inst::Imm(inst) => inst.exec(state),
Inst::Reg(inst) => inst.exec(state),
}
}
}

View File

@ -3,10 +3,11 @@
// Imports
use crate::inst::{
basic::{Decode, ModifiesReg, TryEncode},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::{Truncated, ZeroExtended};
use int_conv::{Signed, Truncated, ZeroExtended};
use std::array;
/// Shift immediate instruction kind
@ -157,3 +158,18 @@ impl ModifiesReg for Inst {
self.dst == reg
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
state[self.dst] = match self.kind {
Kind::LeftLogical => state[self.lhs].wrapping_shl(self.rhs.zero_extended()),
Kind::RightLogical => state[self.lhs].wrapping_shr(self.rhs.zero_extended()),
Kind::RightArithmetic => state[self.lhs]
.as_signed()
.wrapping_shr(self.rhs.zero_extended())
.as_unsigned(),
};
Ok(())
}
}

View File

@ -3,9 +3,11 @@
// Imports
use crate::inst::{
basic::{Decode, Encode, ModifiesReg},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
};
use int_conv::Signed;
use std::array;
/// Shift register instruction kind
@ -142,3 +144,15 @@ impl ModifiesReg for Inst {
self.dst == reg
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
state[self.dst] = match self.kind {
Kind::LeftLogical => state[self.lhs].wrapping_shl(state[self.rhs]),
Kind::RightLogical => state[self.lhs].wrapping_shr(state[self.rhs]),
Kind::RightArithmetic => state[self.lhs].as_signed().wrapping_shr(state[self.rhs]).as_unsigned(),
};
Ok(())
}
}

View File

@ -2,10 +2,14 @@
// Imports
use super::ModifiesReg;
use crate::inst::{
basic::{Decode, Encode},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
use crate::{
inst::{
basic::{Decode, Encode},
exec::{ExecError, ExecState, Executable},
parse::LineArg,
DisplayCtx, InstDisplay, InstFmtArg, Parsable, ParseCtx, ParseError, Register,
},
Pos,
};
use int_conv::{Signed, Truncated, ZeroExtended};
use std::array;
@ -162,3 +166,14 @@ impl ModifiesReg for Inst {
false
}
}
impl Executable for Inst {
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError> {
match self.kind {
Kind::Byte => state.write_byte(Pos(state[self.addr]), state[self.value].truncated()),
Kind::HalfWord => state.write_half_word(Pos(state[self.addr]), state[self.value].truncated()),
Kind::Word => state.write_word(Pos(state[self.addr]), state[self.value]),
Kind::WordLeft | Kind::WordRight => todo!(),
}
}
}

283
dcb-exe/src/inst/exec.rs Normal file
View File

@ -0,0 +1,283 @@
//! Execution
// Imports
use crate::{
inst::{
basic::{self, mult::MultReg, Decode},
Register,
},
Pos,
};
use byteorder::{ByteOrder, LittleEndian};
use std::{
convert::TryInto,
ops::{Index, IndexMut},
};
/// Execution state
pub struct ExecState {
/// Program counter
pc: Pos,
/// Registers
regs: [u32; 32],
/// Lo / Hi
lo_hi_reg: [u32; 2],
/// Memory
memory: Box<[u8]>,
/// Jump target
jump_target: JumpTargetState,
}
impl ExecState {
/// Creates a new execution state
#[must_use]
pub fn new(memory: Box<[u8]>, pc: Pos) -> Self {
Self {
pc,
regs: [0; 32],
lo_hi_reg: [0; 2],
memory,
jump_target: JumpTargetState::None,
}
}
/// Executes the next instruction
pub fn exec(&mut self) -> Result<(), ExecError> {
// Read the next instruction
let inst = self.read_word(self.pc)?;
// Parse the instruction
let inst = basic::Inst::decode(inst).ok_or(ExecError::DecodeInst)?;
// Then execute it
inst.exec(self)?;
// Then update our pc depending on whether we have a jump
self.pc = match self.jump_target {
JumpTargetState::None => self.pc + 4u32,
JumpTargetState::JumpNext(pos) => {
self.jump_target = JumpTargetState::JumpNow(pos);
self.pc + 4u32
},
JumpTargetState::JumpNow(pos) => {
self.jump_target = JumpTargetState::None;
pos
},
};
// And increment out program counter
self.pc += 4u32;
Ok(())
}
/// Returns the current program counter
#[must_use]
pub const fn pc(&self) -> Pos {
self.pc
}
/// Sets a jump to happen
pub fn set_jump(&mut self, pos: Pos) -> Result<(), ExecError> {
match self.jump_target {
JumpTargetState::None => {
self.jump_target = JumpTargetState::JumpNext(pos);
Ok(())
},
_ => Err(ExecError::JumpWhileJumping),
}
}
/// Reads a word from a memory position
pub fn read_word(&self, pos: Pos) -> Result<u32, ExecError> {
// If the position isn't aligned, return Err
if !pos.is_word_aligned() {
return Err(ExecError::MemoryUnalignedAccess { pos });
}
// Ignore the top 3 bits
let idx = pos.0 & 0x7FFF_FFFF;
let idx = idx.try_into().expect("Memory position didn't fit into `usize`");
// Then read from memory
let mem = self
.memory
.get(idx..(idx + 4))
.ok_or(ExecError::MemoryOutOfBounds { pos })?;
Ok(LittleEndian::read_u32(mem))
}
/// Reads a half-word from a memory position
pub fn read_half_word(&self, pos: Pos) -> Result<u16, ExecError> {
// If the position isn't aligned, return Err
if !pos.is_half_word_aligned() {
return Err(ExecError::MemoryUnalignedAccess { pos });
}
// Ignore the top 3 bits
let idx = pos.0 & 0x7FFF_FFFF;
let idx = idx.try_into().expect("Memory position didn't fit into `usize`");
// Then read from memory
let mem = self
.memory
.get(idx..(idx + 2))
.ok_or(ExecError::MemoryOutOfBounds { pos })?;
Ok(LittleEndian::read_u16(mem))
}
/// Reads a byte from a memory position
pub fn read_byte(&self, pos: Pos) -> Result<u8, ExecError> {
// Ignore the top 3 bits
let idx = pos.0 & 0x7FFF_FFFF;
let idx: usize = idx.try_into().expect("Memory position didn't fit into `usize`");
// Then read from memory
self.memory
.get(idx)
.copied()
.ok_or(ExecError::MemoryOutOfBounds { pos })
}
/// Stores a word to a memory position
pub fn write_word(&mut self, pos: Pos, value: u32) -> Result<(), ExecError> {
// If the position isn't aligned, return Err
if !pos.is_word_aligned() {
return Err(ExecError::MemoryUnalignedAccess { pos });
}
// Ignore the top 3 bits
let idx = pos.0 & 0x7FFF_FFFF;
let idx = idx.try_into().expect("Memory position didn't fit into `usize`");
// Then write to memory
let mem = self
.memory
.get_mut(idx..(idx + 4))
.ok_or(ExecError::MemoryOutOfBounds { pos })?;
LittleEndian::write_u32(mem, value);
Ok(())
}
/// Writes a half-word to a memory position
pub fn write_half_word(&mut self, pos: Pos, value: u16) -> Result<(), ExecError> {
// If the position isn't aligned, return Err
if !pos.is_half_word_aligned() {
return Err(ExecError::MemoryUnalignedAccess { pos });
}
// Ignore the top 3 bits
let idx = pos.0 & 0x7FFF_FFFF;
let idx = idx.try_into().expect("Memory position didn't fit into `usize`");
// Then write to memory
let mem = self
.memory
.get_mut(idx..(idx + 2))
.ok_or(ExecError::MemoryOutOfBounds { pos })?;
LittleEndian::write_u16(mem, value);
Ok(())
}
/// Writes a byte to a memory position
pub fn write_byte(&mut self, pos: Pos, value: u8) -> Result<(), ExecError> {
// Ignore the top 3 bits
let idx = pos.0 & 0x7FFF_FFFF;
let idx: usize = idx.try_into().expect("Memory position didn't fit into `usize`");
// Then write to memory
let mem = self.memory.get_mut(idx).ok_or(ExecError::MemoryOutOfBounds { pos })?;
*mem = value;
Ok(())
}
}
impl Index<Register> for ExecState {
type Output = u32;
fn index(&self, reg: Register) -> &Self::Output {
let idx: usize = reg.idx().try_into().expect("Register index didn't fit into `usize`");
&self.regs[idx]
}
}
impl IndexMut<Register> for ExecState {
fn index_mut(&mut self, reg: Register) -> &mut Self::Output {
let idx: usize = reg.idx().try_into().expect("Register index didn't fit into `usize`");
&mut self.regs[idx]
}
}
impl Index<MultReg> for ExecState {
type Output = u32;
fn index(&self, reg: MultReg) -> &Self::Output {
match reg {
MultReg::Lo => &self.lo_hi_reg[0],
MultReg::Hi => &self.lo_hi_reg[1],
}
}
}
impl IndexMut<MultReg> for ExecState {
fn index_mut(&mut self, reg: MultReg) -> &mut Self::Output {
match reg {
MultReg::Lo => &mut self.lo_hi_reg[0],
MultReg::Hi => &mut self.lo_hi_reg[1],
}
}
}
/// An executable instruction
pub trait Executable {
/// Executes this instruction in `state`
fn exec(&self, state: &mut ExecState) -> Result<(), ExecError>;
}
/// Executing error
#[derive(Debug, thiserror::Error)]
pub enum ExecError {
/// Memory address was out of bounds
#[error("Memory access for {pos} is out of bounds")]
MemoryOutOfBounds {
/// Position the instruction tried to access
pos: Pos,
},
/// Memory address was unaligned
#[error("Memory access for {pos} was unaligned")]
MemoryUnalignedAccess {
/// Position which is unaligned
pos: Pos,
},
/// Unable to decode instruction
#[error("Unable to decode instruction")]
DecodeInst,
/// Overflow
#[error("Overflow")]
Overflow,
/// Attempted to jump while jumping
#[error("Cannot jump while jumping")]
JumpWhileJumping,
}
/// Jump target state
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum JumpTargetState {
/// No jump
None,
/// Jump next
JumpNext(Pos),
/// Jump now
JumpNow(Pos),
}

View File

@ -19,7 +19,8 @@
min_type_alias_impl_trait,
external_doc,
assert_matches,
extend_one
extend_one,
exclusive_range_pattern
)]
// Lints
#![warn(clippy::restriction, clippy::pedantic, clippy::nursery)]