initial commit

This commit is contained in:
shylie 2025-03-06 20:58:07 -05:00
commit 6ab27289a8
6 changed files with 1045 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/.idea/
/target

400
Cargo.lock generated Normal file
View File

@ -0,0 +1,400 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "customasm"
version = "0.13.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "570773ea039d836498dbadc8de4ea40609325b1bdbd159adc82aecc7f790a2dd"
dependencies = [
"getopts",
"num-bigint",
"vergen",
]
[[package]]
name = "footvm"
version = "0.1.0"
dependencies = [
"byteorder",
"customasm",
]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width",
]
[[package]]
name = "iana-time-zone"
version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "js-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.170"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
[[package]]
name = "log"
version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
[[package]]
name = "num-bigint"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "rustversion"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "semver"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
version = "2.0.99"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "unicode-width"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
[[package]]
name = "vergen"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7141e445af09c8919f1d5f8a20dae0b20c3b57a45dee0d5823c6ed5d237f15a"
dependencies = [
"bitflags",
"chrono",
"rustc_version",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-link"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

8
Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "footvm"
version = "0.1.0"
edition = "2021"
[dependencies]
byteorder = "1"
customasm = "0.13.9"

42
src/foot.asm Normal file
View File

@ -0,0 +1,42 @@
#subruledef operand
{
#{immediate: s5} => 0b000 @ immediate
r{register: u5} => 0b001 @ register
[r{register: u5}++] => 0b010 @ register
[r{register: u5}--] => 0b011 @ register
[r{register: u5}] => 0b100 @ register
[r{register: u5} + {offset: u2} => 0b1 @ offset @ register
}
#subruledef crflags
{
. => 0b0000
.l => 0b0010
.le => 0b0100
.e => 0b0110
.ge => 0b1000
.g => 0b1010
.ne => 0b1100
.r => 0b0001
.rl => 0b0011
.rle => 0b0101
.re => 0b0111
.rge => 0b1001
.re => 0b1011
.rne => 0b1101
}
#ruledef
{
CNST{flags: crflags} {dst: operand}, {imm: i16} => imm @ 0b0000 @ flags @ dst
}
#bankdef mem
{
#bits 16
#addr 0
#size 0x10000
#outp 0
}
#bank mem

18
src/main.rs Normal file
View File

@ -0,0 +1,18 @@
mod vm;
use vm::{FootVM};
fn main()
{
let mut vm = FootVM::new();
vm[0] = 0xFEED;
vm[1] = 0b0000_0000_001_00000;
let result = vm.load("CNST. r0, 0xBEEF", Some(&mut std::io::stderr()));
if result.is_ok()
{
vm.cycle();
println!("{}", vm.registers[0]);
}
}

574
src/vm.rs Normal file
View File

@ -0,0 +1,574 @@
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>
{
match (value >> 5).try_into()
{
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()?;
match value >> 24
{
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()?;
match value >> 24
{
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],
pub registers: [u16; 32],
status: Status
}
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];
match ((second_word as u32) << 16 | first_word as u32).try_into()
{
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),
Err(_) => ()
}
*self.mut_program_counter() += 2;
}
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);
self.store_operand(dst, ((a as i16) + (b as i16)) as u16);
}
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);
self.store_operand(dst, ((a as i16) - (b as i16)) as u16);
}
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);
self.store_operand(dst, ((a as i16) * (b as i16)) as u16);
}
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);
self.store_operand(dst, ((a as i16) / (b as i16)) as u16);
}
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);
self.store_operand(dst, ((a as i16) % (b as i16)) as u16);
}
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 stack_pointer(&self) -> u16
{
self.registers[30]
}
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]
}
}