#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Field {
P,
Wp,
Xs,
X,
S,
M,
B,
W,
A,
}
impl Field {
pub const fn from_a_code(code: u8) -> Option<Field> {
match code {
0 => Some(Field::P),
1 => Some(Field::Wp),
2 => Some(Field::Xs),
3 => Some(Field::X),
4 => Some(Field::S),
5 => Some(Field::M),
6 => Some(Field::B),
7 => Some(Field::W),
_ => None,
}
}
pub const fn from_f_code(code: u8) -> Option<Field> {
match code {
0xF => Some(Field::A),
c => Field::from_a_code(c),
}
}
pub const fn range(self, p: u8) -> (u8, u8) {
let p = p & 0xF;
match self {
Field::P => (p, p),
Field::Wp => (0, p),
Field::Xs => (2, 2),
Field::X => (0, 2),
Field::S => (15, 15),
Field::M => (3, 14),
Field::B => (0, 1),
Field::W => (0, 15),
Field::A => (0, 4),
}
}
pub const fn name(self) -> &'static str {
match self {
Field::P => "P",
Field::Wp => "WP",
Field::Xs => "XS",
Field::X => "X",
Field::S => "S",
Field::M => "M",
Field::B => "B",
Field::W => "W",
Field::A => "A",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Reg {
A,
B,
C,
D,
}
impl Reg {
pub const fn from_index(i: u8) -> Reg {
match i & 3 {
0 => Reg::A,
1 => Reg::B,
2 => Reg::C,
_ => Reg::D,
}
}
pub const fn name(self) -> &'static str {
match self {
Reg::A => "A",
Reg::B => "B",
Reg::C => "C",
Reg::D => "D",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Ptr {
D0,
D1,
}
impl Ptr {
pub const fn name(self) -> &'static str {
match self {
Ptr::D0 => "D0",
Ptr::D1 => "D1",
}
}
pub const fn dat(self) -> &'static str {
match self {
Ptr::D0 => "DAT0",
Ptr::D1 => "DAT1",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Scratch {
R0,
R1,
R2,
R3,
R4,
}
impl Scratch {
pub const fn from_index(i: u8) -> Option<Scratch> {
match i {
0 => Some(Scratch::R0),
1 => Some(Scratch::R1),
2 => Some(Scratch::R2),
3 => Some(Scratch::R3),
4 => Some(Scratch::R4),
_ => None,
}
}
pub const fn index(self) -> usize {
match self {
Scratch::R0 => 0,
Scratch::R1 => 1,
Scratch::R2 => 2,
Scratch::R3 => 3,
Scratch::R4 => 4,
}
}
pub const fn name(self) -> &'static str {
match self {
Scratch::R0 => "R0",
Scratch::R1 => "R1",
Scratch::R2 => "R2",
Scratch::R3 => "R3",
Scratch::R4 => "R4",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DatSize {
Field(Field),
Nibbles(u8),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Cmp {
Eq,
Ne,
Gt,
Lt,
Ge,
Le,
}
impl Cmp {
pub const fn symbol(self) -> &'static str {
match self {
Cmp::Eq => "=",
Cmp::Ne => "#",
Cmp::Gt => ">",
Cmp::Lt => "<",
Cmp::Ge => ">=",
Cmp::Le => "<=",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum OnTrue {
RtnYes,
GoYes(u32),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Instruction {
RtnSxm,
Rtn,
RtnSc,
RtnCc,
SetHex,
SetDec,
RstkEqC,
CEqRstk,
ClrSt,
CEqSt,
StEqC,
CStEx,
PInc,
PDec,
Rti,
And { dst: Reg, src: Reg, field: Field },
Or { dst: Reg, src: Reg, field: Field },
ScratchFromReg {
ss: Scratch,
src: Reg,
field: Option<Field>,
},
RegFromScratch {
dst: Reg,
ss: Scratch,
field: Option<Field>,
},
RegScratchEx {
reg: Reg,
ss: Scratch,
field: Option<Field>,
},
PtrFromReg { ptr: Ptr, src: Reg, short: bool },
PtrRegEx { ptr: Ptr, reg: Reg, short: bool },
PtrAdd { ptr: Ptr, n: u8 },
PtrSub { ptr: Ptr, n: u8 },
PtrLoad { ptr: Ptr, nibbles: u8, value: u32 },
DatWrite { ptr: Ptr, src: Reg, size: DatSize },
DatRead { dst: Reg, ptr: Ptr, size: DatSize },
PSet { n: u8 },
LoadConst { reg: Reg, nibbles: u8, value: u64 },
CPlusPPlus1,
CEqP { n: u8 },
PEqC { n: u8 },
CpEx { n: u8 },
RtnC,
RtnNc,
Goc { target: u32 },
Gonc { target: u32 },
Goto { target: u32 },
Gosub { target: u32 },
GoLong { target: u32 },
GoVLong { target: u32 },
GosubL { target: u32 },
GosbVL { target: u32 },
PcEqReg { reg: Reg },
PcEqInd { reg: Reg },
RegPcEx { reg: Reg },
RegEqPc { reg: Reg },
Nop3,
Nop4,
Nop5,
OutCs,
OutC,
In { dst: Reg },
Uncnfg,
Config,
CId,
Shutdn,
IntOn,
Rsi,
BusCb,
IntOff,
BusCd,
Reset,
BusCc,
Sreq,
BitClear { reg: Reg, bit: u8 },
BitSet { reg: Reg, bit: u8 },
HsClear { mask: u8 },
StClear { bit: u8 },
StSet { bit: u8 },
Slc { reg: Reg },
Src { reg: Reg },
Srb { reg: Reg, field: Option<Field> },
Sl { reg: Reg, field: Field },
Sr { reg: Reg, field: Field },
Add { dst: Reg, src: Reg, field: Field },
Sub { dst: Reg, src: Reg, field: Field },
SubRev { dst: Reg, src: Reg, field: Field },
Inc { reg: Reg, field: Field },
Dec { reg: Reg, field: Field },
AddConst { reg: Reg, field: Field, n: u8 },
SubConst { reg: Reg, field: Field, n: u8 },
Zero { reg: Reg, field: Field },
Copy { dst: Reg, src: Reg, field: Field },
Exch { a: Reg, b: Reg, field: Field },
Neg { reg: Reg, field: Field },
Not { reg: Reg, field: Field },
TestCmp {
op: Cmp,
lhs: Reg,
rhs: Reg,
field: Field,
yes: OnTrue,
},
TestZero {
op: Cmp,
reg: Reg,
field: Field,
yes: OnTrue,
},
TestHs { mask: u8, yes: OnTrue },
TestSt { bit: u8, set: bool, yes: OnTrue },
TestP { n: u8, eq: bool, yes: OnTrue },
TestBit {
reg: Reg,
bit: u8,
set: bool,
yes: OnTrue,
},
Invalid { nibbles: [u8; 8], len: u8 },
}
impl Instruction {
pub const fn on_true(&self) -> Option<OnTrue> {
match *self {
Instruction::TestCmp { yes, .. }
| Instruction::TestZero { yes, .. }
| Instruction::TestHs { yes, .. }
| Instruction::TestSt { yes, .. }
| Instruction::TestP { yes, .. }
| Instruction::TestBit { yes, .. } => Some(yes),
_ => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn field_ranges() {
assert_eq!(Field::P.range(7), (7, 7));
assert_eq!(Field::Wp.range(7), (0, 7));
assert_eq!(Field::Wp.range(0x17), (0, 7));
assert_eq!(Field::Xs.range(0), (2, 2));
assert_eq!(Field::X.range(0), (0, 2));
assert_eq!(Field::S.range(0), (15, 15));
assert_eq!(Field::M.range(0), (3, 14));
assert_eq!(Field::B.range(0), (0, 1));
assert_eq!(Field::W.range(0), (0, 15));
assert_eq!(Field::A.range(9), (0, 4));
}
#[test]
fn field_codes() {
assert_eq!(Field::from_a_code(0), Some(Field::P));
assert_eq!(Field::from_a_code(7), Some(Field::W));
assert_eq!(Field::from_a_code(8), None);
assert_eq!(Field::from_f_code(0xF), Some(Field::A));
assert_eq!(Field::from_f_code(0x8), None);
assert_eq!(Field::from_f_code(0xE), None);
}
}