2025-03-06 20:58:07 -05:00
|
|
|
use std::io::{Cursor};
|
|
|
|
use std::ops::{Index, IndexMut};
|
|
|
|
use AddressingMode::*;
|
|
|
|
use ConditionalExecutionFlag::*;
|
|
|
|
use Instruction::*;
|
|
|
|
use byteorder::{BigEndian, ReadBytesExt};
|
|
|
|
|
|
|
|
const ASM_PREFIX: &str = include_str!("foot.asm");
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
enum ConditionalExecutionFlag
|
|
|
|
{
|
|
|
|
Always,
|
|
|
|
LessThan,
|
|
|
|
LessThanOrEqual,
|
|
|
|
Equal,
|
|
|
|
GreaterThanOrEqual,
|
|
|
|
GreaterThan,
|
|
|
|
NotEqual
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<u32> for ConditionalExecutionFlag
|
|
|
|
{
|
|
|
|
type Error = ();
|
|
|
|
|
|
|
|
fn try_from(value: u32) -> Result<Self, Self::Error>
|
|
|
|
{
|
|
|
|
match value
|
|
|
|
{
|
|
|
|
0 => Ok(Always),
|
|
|
|
1 => Ok(LessThan),
|
|
|
|
2 => Ok(LessThanOrEqual),
|
|
|
|
3 => Ok(Equal),
|
|
|
|
4 => Ok(GreaterThanOrEqual),
|
|
|
|
5 => Ok(GreaterThan),
|
|
|
|
6 => Ok(NotEqual),
|
|
|
|
_ => Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
enum AddressingMode
|
|
|
|
{
|
|
|
|
Immediate,
|
|
|
|
Direct,
|
|
|
|
Indirect(u8),
|
|
|
|
IndirectAutoIncrement,
|
|
|
|
IndirectAutoDecrement
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<u32> for AddressingMode
|
|
|
|
{
|
|
|
|
type Error = ();
|
|
|
|
|
|
|
|
fn try_from(value: u32) -> Result<Self, Self::Error>
|
|
|
|
{
|
|
|
|
match value
|
|
|
|
{
|
|
|
|
0 => Ok(Immediate),
|
|
|
|
1 => Ok(Direct),
|
|
|
|
2 => Ok(IndirectAutoIncrement),
|
|
|
|
3 => Ok(IndirectAutoDecrement),
|
|
|
|
4..8 => Ok(Indirect((value - 4) as u8)),
|
|
|
|
_ => Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
struct Operand
|
|
|
|
{
|
|
|
|
pub addressing_mode: AddressingMode,
|
|
|
|
pub value: u8
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<u32> for Operand
|
|
|
|
{
|
|
|
|
type Error = ();
|
|
|
|
|
|
|
|
fn try_from(value: u32) -> Result<Self, Self::Error>
|
|
|
|
{
|
2025-03-07 02:58:45 -05:00
|
|
|
match ((value >> 5) & 0b111).try_into()
|
2025-03-06 20:58:07 -05:00
|
|
|
{
|
|
|
|
Ok(addressing_mode) => Ok(
|
|
|
|
Operand
|
|
|
|
{
|
|
|
|
addressing_mode,
|
|
|
|
value: (value as u8) & 0b00011111
|
|
|
|
},
|
|
|
|
),
|
|
|
|
Err(_) => Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum Instruction
|
|
|
|
{
|
|
|
|
CNST(ConditionalExecutionFlag, bool, Operand, u16),
|
|
|
|
CMPR(ConditionalExecutionFlag, bool, Operand, Operand),
|
|
|
|
BWNG(ConditionalExecutionFlag, bool, Operand, Operand),
|
|
|
|
ARNG(ConditionalExecutionFlag, bool, Operand, Operand),
|
|
|
|
LONG(ConditionalExecutionFlag, bool, Operand, Operand),
|
|
|
|
BWOR(ConditionalExecutionFlag, bool, Operand, Operand, Operand),
|
|
|
|
BAND(ConditionalExecutionFlag, bool, Operand, Operand, Operand),
|
|
|
|
BXOR(ConditionalExecutionFlag, bool, Operand, Operand, Operand),
|
|
|
|
URSH(ConditionalExecutionFlag, bool, Operand, Operand, Operand),
|
|
|
|
SRSH(ConditionalExecutionFlag, bool, Operand, Operand, Operand),
|
|
|
|
ZLSH(ConditionalExecutionFlag, bool, Operand, Operand, Operand),
|
|
|
|
CLSH(ConditionalExecutionFlag, bool, Operand, Operand, Operand),
|
|
|
|
ADDI(ConditionalExecutionFlag, bool, Operand, Operand, Operand),
|
|
|
|
SUBT(ConditionalExecutionFlag, bool, Operand, Operand, Operand),
|
|
|
|
MULT(ConditionalExecutionFlag, bool, Operand, Operand, Operand),
|
|
|
|
DIVI(ConditionalExecutionFlag, bool, Operand, Operand, Operand),
|
|
|
|
MODU(ConditionalExecutionFlag, bool, Operand, Operand, Operand)
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<u32> for Instruction
|
|
|
|
{
|
|
|
|
type Error = ();
|
|
|
|
|
|
|
|
fn try_from(value: u32) -> Result<Self, Self::Error>
|
|
|
|
{
|
|
|
|
let ceflag: ConditionalExecutionFlag = (value >> 29).try_into()?;
|
|
|
|
let rflag: bool = (value >> 28 & 1) == 1;
|
|
|
|
let dst: Operand = (value >> 16).try_into()?;
|
2025-03-07 02:58:45 -05:00
|
|
|
let opcode = (value >> 24) & 0xF;
|
|
|
|
match opcode
|
2025-03-06 20:58:07 -05:00
|
|
|
{
|
|
|
|
0 => Ok(CNST(ceflag, rflag, dst, (value & 0xFFFF) as u16)),
|
|
|
|
1 =>
|
|
|
|
{
|
|
|
|
let a: Operand = (value & 0xFF).try_into()?;
|
|
|
|
match (value >> 8) & 0xFF
|
|
|
|
{
|
|
|
|
0 => Ok(CMPR(ceflag, rflag, dst, a)),
|
|
|
|
1 => Ok(BWNG(ceflag, rflag, dst, a)),
|
|
|
|
2 => Ok(ARNG(ceflag, rflag, dst, a)),
|
|
|
|
3 => Ok(LONG(ceflag, rflag, dst, a)),
|
|
|
|
_ => Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
2..14 =>
|
|
|
|
{
|
|
|
|
let a: Operand = (value & 0xFF).try_into()?;
|
|
|
|
let b: Operand = ((value >> 8) & 0xFF).try_into()?;
|
2025-03-07 09:04:26 -05:00
|
|
|
match (value >> 24) & 0xF
|
2025-03-06 20:58:07 -05:00
|
|
|
{
|
|
|
|
2 => Ok(BWOR(ceflag, rflag, dst, b, a)),
|
|
|
|
3 => Ok(BAND(ceflag, rflag, dst, b, a)),
|
|
|
|
4 => Ok(BXOR(ceflag, rflag, dst, b, a)),
|
|
|
|
5 => Ok(URSH(ceflag, rflag, dst, b, a)),
|
|
|
|
6 => Ok(SRSH(ceflag, rflag, dst, b, a)),
|
|
|
|
7 => Ok(ZLSH(ceflag, rflag, dst, b, a)),
|
|
|
|
8 => Ok(CLSH(ceflag, rflag, dst, b, a)),
|
|
|
|
9 => Ok(ADDI(ceflag, rflag, dst, b, a)),
|
|
|
|
10 => Ok(SUBT(ceflag, rflag, dst, b, a)),
|
|
|
|
11 => Ok(MULT(ceflag, rflag, dst, b, a)),
|
|
|
|
12 => Ok(DIVI(ceflag, rflag, dst, b, a)),
|
|
|
|
13 => Ok(MODU(ceflag, rflag, dst, b, a)),
|
|
|
|
_ => Err(())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_ => Err(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq, Eq)]
|
|
|
|
enum Status
|
|
|
|
{
|
|
|
|
Less,
|
|
|
|
Equal,
|
|
|
|
Greater
|
|
|
|
}
|
|
|
|
|
|
|
|
const MEMORY_SIZE: usize = 1 << 16;
|
|
|
|
|
|
|
|
pub struct FootVM
|
|
|
|
{
|
|
|
|
memory: [u16; MEMORY_SIZE],
|
2025-03-07 09:04:26 -05:00
|
|
|
pub registers: [u16; 32],
|
2025-03-06 20:58:07 -05:00
|
|
|
status: Status
|
|
|
|
}
|
|
|
|
|
2025-03-07 02:58:45 -05:00
|
|
|
impl Default for FootVM
|
|
|
|
{
|
|
|
|
fn default() -> Self
|
|
|
|
{
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-06 20:58:07 -05:00
|
|
|
macro_rules! run_instruction
|
|
|
|
{
|
|
|
|
($self:ident, $cef:ident, $rep:ident, $name:ident, $d:ident, $a:ident) =>
|
|
|
|
{
|
|
|
|
if $rep
|
|
|
|
{
|
|
|
|
while $self.should_repeat()
|
|
|
|
{
|
|
|
|
if $self.check($cef)
|
|
|
|
{
|
|
|
|
$self.$name($d, $a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if $self.check($cef)
|
|
|
|
{
|
|
|
|
$self.$name($d, $a)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
($self:ident, $cef:ident, $rep:ident, $name:ident, $d:ident, $a:ident, $b:ident) =>
|
|
|
|
{
|
|
|
|
if $rep
|
|
|
|
{
|
|
|
|
while $self.should_repeat()
|
|
|
|
{
|
|
|
|
if $self.check($cef)
|
|
|
|
{
|
|
|
|
$self.$name($d, $a, $b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if $self.check($cef)
|
|
|
|
{
|
|
|
|
$self.$name($d, $a, $b)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FootVM
|
|
|
|
{
|
|
|
|
pub fn new() -> FootVM
|
|
|
|
{
|
|
|
|
FootVM
|
|
|
|
{
|
|
|
|
memory: [0; MEMORY_SIZE],
|
|
|
|
registers: [0; 32],
|
|
|
|
status: Status::Equal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load(&mut self, asm_src: &str, write: Option<&mut dyn std::io::Write>) -> Result<(), ()>
|
|
|
|
{
|
|
|
|
let mut asm_src = asm_src.to_owned();
|
|
|
|
asm_src.insert_str(0, ASM_PREFIX);
|
|
|
|
let asm_src = asm_src;
|
|
|
|
|
|
|
|
let virtual_filename = "loaded";
|
|
|
|
let mut report = customasm::diagn::Report::new();
|
|
|
|
let mut fileserver = customasm::util::FileServerMock::new();
|
|
|
|
fileserver.add(virtual_filename, asm_src);
|
|
|
|
|
|
|
|
let opts = customasm::asm::AssemblyOptions::new();
|
|
|
|
|
|
|
|
let assembly = customasm::asm::assemble(
|
|
|
|
&mut report,
|
|
|
|
&opts,
|
|
|
|
&mut fileserver,
|
|
|
|
&[virtual_filename]
|
|
|
|
);
|
|
|
|
|
|
|
|
let binary = assembly.output.map(|o| o.format_binary()).ok_or_else(
|
|
|
|
|| {
|
|
|
|
match write
|
|
|
|
{
|
|
|
|
Some(w) => report.print_all(w, &mut fileserver, true),
|
|
|
|
None => ()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)?;
|
|
|
|
|
|
|
|
let mut cursor = Cursor::new(binary);
|
|
|
|
let mut index = 0;
|
|
|
|
|
|
|
|
loop
|
|
|
|
{
|
|
|
|
match cursor.read_u16::<BigEndian>()
|
|
|
|
{
|
|
|
|
Ok(value) =>
|
|
|
|
{
|
|
|
|
self[index] = value;
|
|
|
|
index += 1;
|
|
|
|
},
|
|
|
|
Err(_) => break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn cycle(&mut self)
|
|
|
|
{
|
|
|
|
let first_word = self[self.program_counter()];
|
|
|
|
let second_word = self[self.program_counter() + 1];
|
2025-03-07 09:04:26 -05:00
|
|
|
let full_instruction_bits = (second_word as u32) << 16 | first_word as u32;
|
|
|
|
*self.mut_program_counter() = self.program_counter().wrapping_add(2);
|
|
|
|
match full_instruction_bits.try_into()
|
2025-03-06 20:58:07 -05:00
|
|
|
{
|
|
|
|
Ok(CNST(cef, rep, dst, imm)) =>
|
|
|
|
run_instruction!(self, cef, rep, cnst, dst, imm),
|
|
|
|
Ok(CMPR(cef, rep, a, b)) =>
|
|
|
|
run_instruction!(self, cef, rep, cmpr, a, b),
|
|
|
|
Ok(BWNG(cef, rep, dst, src)) =>
|
|
|
|
run_instruction!(self, cef, rep, bwng, dst, src),
|
|
|
|
Ok(ARNG(cef, rep, dst, src)) =>
|
|
|
|
run_instruction!(self, cef, rep, arng, dst, src),
|
|
|
|
Ok(LONG(cef, rep, dst, src)) =>
|
|
|
|
run_instruction!(self, cef, rep, long, dst, src),
|
|
|
|
Ok(BWOR(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, bwor, dst, a, b),
|
|
|
|
Ok(BAND(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, band, dst, a, b),
|
|
|
|
Ok(BXOR(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, bxor, dst, a, b),
|
|
|
|
Ok(URSH(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, ursh, dst, a, b),
|
|
|
|
Ok(SRSH(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, srsh, dst, a, b),
|
|
|
|
Ok(ZLSH(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, zlsh, dst, a, b),
|
|
|
|
Ok(CLSH(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, clsh, dst, a, b),
|
|
|
|
Ok(ADDI(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, addi, dst, a, b),
|
|
|
|
Ok(SUBT(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, subt, dst, a, b),
|
|
|
|
Ok(MULT(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, mult, dst, a, b),
|
|
|
|
Ok(DIVI(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, divi, dst, a, b),
|
|
|
|
Ok(MODU(cef, rep, dst, b, a)) =>
|
|
|
|
run_instruction!(self, cef, rep, modu, dst, a, b),
|
2025-03-07 09:04:26 -05:00
|
|
|
Err(_) => {}
|
2025-03-06 20:58:07 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn cnst(&mut self, dst: Operand, imm: u16)
|
|
|
|
{
|
|
|
|
self.store_operand(dst, imm)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn cmpr(&mut self, a: Operand, b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(a) as i16;
|
|
|
|
let b = self.load_operand(b) as i16;
|
|
|
|
|
|
|
|
self.status = match a - b
|
|
|
|
{
|
|
|
|
..0 => Status::Less,
|
|
|
|
0 => Status::Equal,
|
|
|
|
1.. => Status::Greater
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bwng(&mut self, dst: Operand, src: Operand)
|
|
|
|
{
|
|
|
|
let value = self.load_operand(src);
|
|
|
|
self.store_operand(dst, !value)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn arng(&mut self, dst: Operand, src: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src);
|
|
|
|
self.store_operand(dst, (-(a as i16)) as u16);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn long(&mut self, dst: Operand, src: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src);
|
|
|
|
match a
|
|
|
|
{
|
|
|
|
0 => self.store_operand(dst, 1),
|
|
|
|
_ => self.store_operand(dst, 0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bwor(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
|
|
|
self.store_operand(dst, a | b);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn band(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
|
|
|
self.store_operand(dst, a & b);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bxor(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
|
|
|
self.store_operand(dst, a ^ b);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ursh(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
|
|
|
self.store_operand(dst, a >> b);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn srsh(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
|
|
|
self.store_operand(dst, ((a as i16) >> (b as i16)) as u16);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn zlsh(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
|
|
|
self.store_operand(dst, a << b);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn clsh(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
|
|
|
self.store_operand(dst, a.rotate_left(b as u32));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn addi(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
2025-03-07 09:04:26 -05:00
|
|
|
self.store_operand(dst, a.wrapping_add(b));
|
2025-03-06 20:58:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn subt(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
2025-03-07 09:04:26 -05:00
|
|
|
self.store_operand(dst, a.wrapping_sub(b));
|
2025-03-06 20:58:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn mult(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
2025-03-07 09:04:26 -05:00
|
|
|
self.store_operand(dst, a.wrapping_mul(b));
|
2025-03-06 20:58:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn divi(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
2025-03-07 09:04:26 -05:00
|
|
|
self.store_operand(dst, a.wrapping_div(b));
|
2025-03-06 20:58:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn modu(&mut self, dst: Operand, src_a: Operand, src_b: Operand)
|
|
|
|
{
|
|
|
|
let a = self.load_operand(src_a);
|
|
|
|
let b = self.load_operand(src_b);
|
2025-03-07 09:04:26 -05:00
|
|
|
self.store_operand(dst, a.wrapping_rem(b));
|
2025-03-06 20:58:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn store_operand(&mut self, dst: Operand, value: u16)
|
|
|
|
{
|
|
|
|
match dst.addressing_mode
|
|
|
|
{
|
|
|
|
Immediate => (),
|
|
|
|
Direct => self.registers[dst.value as usize] = value,
|
|
|
|
Indirect(offset) =>
|
|
|
|
{
|
|
|
|
let ptr = self.registers[dst.value as usize] + offset as u16;
|
|
|
|
self[ptr] = value
|
|
|
|
}
|
|
|
|
IndirectAutoIncrement =>
|
|
|
|
{
|
|
|
|
let ptr = self.registers[dst.value as usize];
|
|
|
|
self[ptr] = value;
|
|
|
|
self.registers[dst.value as usize] += 1;
|
|
|
|
},
|
|
|
|
IndirectAutoDecrement =>
|
|
|
|
{
|
|
|
|
let ptr = self.registers[dst.value as usize];
|
|
|
|
self[ptr] = value;
|
|
|
|
self.registers[dst.value as usize] -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn load_operand(&mut self, src: Operand) -> u16
|
|
|
|
{
|
|
|
|
match src.addressing_mode
|
|
|
|
{
|
|
|
|
Immediate => src.value as u16,
|
|
|
|
Direct => self.registers[src.value as usize],
|
|
|
|
Indirect(offset) => self[self.registers[src.value as usize] + offset as u16],
|
|
|
|
IndirectAutoIncrement =>
|
|
|
|
{
|
|
|
|
let ptr = self.registers[src.value as usize];
|
|
|
|
let retval = self[ptr];
|
|
|
|
self.registers[src.value as usize] += 1;
|
|
|
|
retval
|
|
|
|
},
|
|
|
|
IndirectAutoDecrement =>
|
|
|
|
{
|
|
|
|
let ptr = self.registers[src.value as usize];
|
|
|
|
let retval = self[ptr];
|
|
|
|
self.registers[src.value as usize] -= 1;
|
|
|
|
retval
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn program_counter(&self) -> u16
|
|
|
|
{
|
|
|
|
self.registers[31]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mut_program_counter(&mut self) -> &mut u16
|
|
|
|
{
|
|
|
|
&mut self.registers[31]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn loop_count(&self) -> u16
|
|
|
|
{
|
|
|
|
self.registers[29]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mut_loop_count(&mut self) -> &mut u16
|
|
|
|
{
|
|
|
|
&mut self.registers[29]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn should_repeat(&mut self) -> bool
|
|
|
|
{
|
|
|
|
if self.loop_count() > 0
|
|
|
|
{
|
|
|
|
*self.mut_loop_count() -= 1;
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check(&self, cef: ConditionalExecutionFlag) -> bool
|
|
|
|
{
|
|
|
|
match cef
|
|
|
|
{
|
|
|
|
Always => true,
|
|
|
|
LessThan => self.status == Status::Less,
|
|
|
|
LessThanOrEqual => self.status == Status::Less || self.status == Status::Equal,
|
|
|
|
Equal => self.status == Status::Equal,
|
|
|
|
GreaterThanOrEqual => self.status == Status::Greater || self.status == Status::Equal,
|
|
|
|
GreaterThan => self.status == Status::Greater,
|
|
|
|
NotEqual => self.status != Status::Equal
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Index<u16> for FootVM
|
|
|
|
{
|
|
|
|
type Output = u16;
|
|
|
|
|
|
|
|
fn index(&self, index: u16) -> &Self::Output
|
|
|
|
{
|
|
|
|
&self.memory[index as usize]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl IndexMut<u16> for FootVM
|
|
|
|
{
|
|
|
|
fn index_mut(&mut self, index: u16) -> &mut Self::Output
|
|
|
|
{
|
|
|
|
&mut self.memory[index as usize]
|
|
|
|
}
|
|
|
|
}
|