do the do, this is unfinished don't touch

This commit is contained in:
abbie 2022-05-13 22:17:03 +01:00
commit a6c5af3382
No known key found for this signature in database
GPG key ID: 04DDE463F9200F87
5 changed files with 883 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
program.ram
/target

248
Cargo.lock generated Normal file
View file

@ -0,0 +1,248 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "clap"
version = "3.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47582c09be7c8b32c0ab3a6181825ababb713fde6fff20fc573a3870dd45c6a0"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"clap_lex",
"indexmap",
"lazy_static",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap_derive"
version = "3.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "foodie"
version = "0.1.0"
dependencies = [
"clap",
"termios",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "indexmap"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b"
[[package]]
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "termios"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b"
dependencies = [
"libc",
]
[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]]
name = "unicode-xid"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

10
Cargo.toml Normal file
View file

@ -0,0 +1,10 @@
[package]
name = "foodie"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "3.1.17", features = ["derive"] }
termios = "0.3.3"

604
src/food8.rs Normal file
View file

@ -0,0 +1,604 @@
use std::io::{Read, stdin};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicU16, Ordering};
use std::time::Duration;
use std::io;
use std::sync::atomic::{AtomicU8};
use std::os::unix::io::RawFd;
use std::io::Write;
use std::io::stdout;
use std::io::prelude::*;
use std::fs::File;
use std::thread;
use termios::{Termios, TCSANOW, ECHO, ICANON, tcsetattr};
struct StdinPoll {
exit: Arc<AtomicBool>,
byte: Arc<AtomicU16>
}
impl StdinPoll {
pub fn new() -> Self {
let exit = Arc::new(AtomicBool::new(false));
let byte = Arc::new(AtomicU16::new(256));
let exit2 = exit.clone();
let byte2 = byte.clone();
std::thread::spawn(move || {
let mut sin = stdin();
let mut lock = sin.lock();
let mut buf = [0u8; 1];
loop {
if exit2.load(Ordering::Relaxed) { break }
lock.read_exact(buf.as_mut_slice()).unwrap();
while byte2.compare_exchange(256, buf[0] as u16, Ordering::Relaxed, Ordering::Relaxed).is_err() {}
}
});
StdinPoll {
exit,
byte
}
}
pub fn poll_byte(&self) -> Option<u8> {
u8::try_from(self.byte.swap(256, Ordering::Relaxed)).ok()
}
}
impl Drop for StdinPoll {
fn drop(&mut self) {
self.exit.store(true, Ordering::Relaxed);
}
}
static KEEBIMP: AtomicU8 = AtomicU8::new(0);
struct Pointer {
bank: u8,
address: u16,
}
#[derive(Debug, Clone)]
struct MemoryBank {
content: Vec<u8>,
}
struct Cpu {
debug: bool,
memory: Vec<MemoryBank>,
pc: u16,
stack: Vec<Pointer>,
registers: Vec<u8>,
peripherals: Vec<u8>,
cache: MemoryBank,
cachebank: u8,
bank: u8,
}
impl Cpu {
fn ramread(&self, index: usize) -> &u8 {
&(self.memory[self.bank as usize]).content[index]
}
fn ramwrite(&mut self, index: usize, value: u8) {
(self.memory[self.bank as usize]).content[index] = value;
}
fn regread(&self, index: usize) -> &u8 {
&self.registers[index]
}
fn regwrite(&mut self, index: usize, value: u8) {
self.registers[index] = value;
}
fn refreshcache(&mut self) {
self.cache = self.memory[self.bank as usize].to_owned();
self.cachebank = self.bank;
}
fn incrementpc(&mut self) {
if self.pc >= 0xFFF9 {
let bank = self.bank;
self.setbank(self.cachebank);
self.incbank();
self.pc = 0;
self.refreshcache();
self.setbank(bank);
} else {
self.pc = self.pc + 4;
}
}
#[allow(unused_parens)]
fn fetch(&mut self) -> u32 {
return ((self.cache.content[self.pc as usize] as u32) << 24 | (self.cache.content[self.pc as usize + 1 as usize] as u32) << 16 | (self.cache.content[self.pc as usize + 2 as usize] as u32) << 8 | self.cache.content[self.pc as usize + 3 as usize] as u32)
}
fn setpc(&mut self, prc: u16) {
self.pc = prc;
}
fn stackpush(&mut self) {
if self.stack.len() == 4 {
self.dump("Stack overflow");
std::process::exit(0);
}
let example = Pointer { bank: self.bank, address: self.pc };
self.stack.push(example);
}
fn stackpop(&mut self) -> Pointer {
if self.stack.len() == 0 {
self.dump("Stack underflow");
std::process::exit(0);
}
let stacker = self.stack.pop().unwrap();
return stacker
}
fn getperph(&self, perph: u8) -> u8 {
self.peripherals[perph as usize]
}
fn setperph(&mut self, perph: u8, value: u8) {
self.peripherals[perph as usize] = value;
}
fn setbank(&mut self, bank: u8) {
self.bank = bank;
}
fn incbank(&mut self) {
self.bank = self.bank + 1;
}
fn dump(&self, msg: &str) {
if self.debug {
println!("{} at 0x{:x?}, bank 0x{:x?}", msg, self.pc, self.cachebank);
println!("Stack Length: {}", self.stack.len());
println!("Current working memory bank: {}", self.bank);
let mut i = 0;
for x in &self.registers {
if *x != 0 {
println!("Register 0x{:x?}: 0x{:x?}", i, x);
}
i = i + 1;
}
}
}
}
struct Instruction {
name: &'static str,
mask: u32,
pattern: u32,
masks: &'static [u32],
shifts: &'static [u8],
}
const ISET: [Instruction; 32] = [
Instruction { name: "NOP",
mask: 0xff000000,
pattern: 0x00000000,
masks: &[], shifts: &[] },
Instruction { name: "LOAD_MEM_REG",
mask: 0xff000000,
pattern: 0x01000000,
masks: &[0x00ffff00, 0x000000ff], shifts: &[8, 0] },
Instruction { name: "STOR_REG_MEM",
mask: 0xff000000,
pattern: 0x02000000,
masks: &[0x00ff0000, 0x0000ffff], shifts: &[16, 0] },
Instruction { name: "LOAD_REG_REG",
mask: 0xff000000,
pattern: 0x03000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "STOR_BYTE_REG",
mask: 0xff000000,
pattern: 0x04000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "SWAP_MEM_REG",
mask: 0xff000000,
pattern: 0x05000000,
masks: &[0x00ffff00, 0x000000ff], shifts: &[8, 0] },
Instruction { name: "SWAP_REG_REG",
mask: 0xff000000,
pattern: 0x06000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "INP",
mask: 0xff000000,
pattern: 0x0c000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "OUT",
mask: 0xff000000,
pattern: 0x0d000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "BANK",
mask: 0xff000000,
pattern: 0x0e000000,
masks: &[0x00ff0000], shifts: &[16] },
Instruction { name: "REF",
mask: 0xff000000,
pattern: 0x0f000000,
masks: &[], shifts: &[] },
Instruction { name: "ADD",
mask: 0xff000000,
pattern: 0x10000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "SUB",
mask: 0xff000000,
pattern: 0x11000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "MULT",
mask: 0xff000000,
pattern: 0x12000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "DIVD",
mask: 0xff000000,
pattern: 0x13000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "INC",
mask: 0xff000000,
pattern: 0x14000000,
masks: &[0x00ff0000], shifts: &[16] },
Instruction { name: "DEC",
mask: 0xff000000,
pattern: 0x15000000,
masks: &[0x00ff0000], shifts: &[16] },
Instruction { name: "NOT",
mask: 0xff000000,
pattern: 0x16000000,
masks: &[0x00ff0000], shifts: &[16] },
Instruction { name: "AND",
mask: 0xff000000,
pattern: 0x17000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "OR",
mask: 0xff000000,
pattern: 0x18000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "XOR",
mask: 0xff000000,
pattern: 0x19000000,
masks: &[0x00ff0000, 0x0000ff00], shifts: &[16, 8] },
Instruction { name: "LESS",
mask: 0xff000000,
pattern: 0x1a000000,
masks: &[0x00ff0000, 0x0000ff00, 0x000000ff], shifts: &[16, 8, 0] },
Instruction { name: "EQU",
mask: 0xff000000,
pattern: 0x1b000000,
masks: &[0x00ff0000, 0x0000ff00, 0x000000ff], shifts: &[16, 8, 0] },
Instruction { name: "JMP",
mask: 0xff000000,
pattern: 0x20000000,
masks: &[0x00ffff00], shifts: &[8] },
Instruction { name: "JMR",
mask: 0xff000000,
pattern: 0x21000000,
masks: &[0x00ffff00], shifts: &[8] },
Instruction { name: "JCZ",
mask: 0xff000000,
pattern: 0x22000000,
masks: &[0x00ffff00, 0x000000ff], shifts: &[8, 0] },
Instruction { name: "JCZR",
mask: 0xff000000,
pattern: 0x23000000,
masks: &[0x00ffff00, 0x000000ff], shifts: &[8, 0] },
Instruction { name: "CALL",
mask: 0xff000000,
pattern: 0x24000000,
masks: &[0x00ffff00], shifts: &[8] },
Instruction { name: "RET",
mask: 0xff000000,
pattern: 0x25000000,
masks: &[], shifts: &[] },
Instruction { name: "RET",
mask: 0xff000000,
pattern: 0x25000000,
masks: &[], shifts: &[] },
Instruction { name: "DUMP",
mask: 0xff000000,
pattern: 0xfe000000,
masks: &[], shifts: &[] },
Instruction { name: "HALT",
mask: 0xff000000,
pattern: 0xff000000,
masks: &[], shifts: &[] }
];
fn disassemble(opcode: u32) -> Instruction {
let mut instruction;
for instr in ISET {
if (opcode & instr.mask) == instr.pattern {
instruction = instr;
return instruction;
}
}
instruction = Instruction { name: "NOP", mask: 0xff000000, pattern: 0x00000000, masks: &[], shifts: &[] };
return instruction;
}
fn decodetest(opcode: u32, expected: &str) {
let instruction = disassemble(opcode);
if instruction.name != expected {
println!("Opcode 0x{} disassembled as instruction {}. Expected {}.", format!("{:x}", opcode), instruction.name, expected);
}
}
fn execute(opcode: u32, instruction: Instruction, mut cpu: Cpu) -> Cpu {
let mut args: Vec<u32> = vec![];
let mut i = 0;
if instruction.masks.len() != 0 {
for mask in instruction.masks {
let shift = instruction.shifts[i];
args.push((opcode & mask) >> shift);
i = i + 1;
}
}
if instruction.name == "NOP" {
cpu.incrementpc();
} else if instruction.name == "LOAD_MEM_REG" {
let value = cpu.ramread(args[0] as usize).to_owned();
cpu.regwrite(args[1] as usize, value);
cpu.incrementpc();
} else if instruction.name == "STOR_REG_MEM" {
let value = cpu.regread(args[0] as usize).to_owned();
cpu.ramwrite(args[1] as usize, value);
cpu.incrementpc();
} else if instruction.name == "LOAD_REG_REG" {
let value = cpu.ramread(args[0] as usize).to_owned();
cpu.regwrite(args[1] as usize, value);
cpu.incrementpc();
} else if instruction.name == "STOR_BYTE_REG" {
cpu.regwrite(args[1] as usize, args[0] as u8);
cpu.incrementpc();
} else if instruction.name == "SWAP_MEM_REG" {
let v1 = cpu.ramread(args[0] as usize).to_owned();
let v2 = cpu.regread(args[1] as usize).to_owned();
cpu.ramwrite(args[0] as usize, v2);
cpu.regwrite(args[1] as usize, v1);
cpu.incrementpc();
} else if instruction.name == "SWAP_REG_REG" {
let mut v1 = cpu.regread(args[0] as usize).to_owned();
let mut v2 = cpu.regread(args[1] as usize).to_owned();
cpu.regwrite(args[0] as usize, v2);
cpu.regwrite(args[1] as usize, v1);
cpu.incrementpc();
} else if instruction.name == "OUT" {
let v1 = cpu.regread(args[1] as usize).to_owned();
cpu.setperph(args[0] as u8, v1);
cpu.incrementpc();
} else if instruction.name == "INP" {
let v1 = cpu.getperph(args[0] as u8);
cpu.regwrite(args[1] as usize, v1);
cpu.incrementpc();
} else if instruction.name == "BANK" {
cpu.setbank(args[0] as u8);
cpu.incrementpc();
} else if instruction.name == "REF" {
cpu.refreshcache();
cpu.incrementpc();
} else if instruction.name == "ADD" {
let y = cpu.regread(args[0] as usize);
let z = cpu.regread(args[1] as usize);
let a;
if *y as u16 + *z as u16 > 0xFF {
a = 0;
} else {
a = y + z;
}
cpu.regwrite(args[0] as usize, a);
cpu.incrementpc();
} else if instruction.name == "SUB" {
let y = cpu.regread(args[0] as usize);
let z = cpu.regread(args[1] as usize);
let a;
if (*y as i16 - *z as i16) < 0 {
a = 255;
} else {
a = y - z;
}
cpu.regwrite(args[0] as usize, a);
cpu.incrementpc();
} else if instruction.name == "MULT" {
let y = cpu.regread(args[0] as usize);
let z = cpu.regread(args[1] as usize);
let a;
if *y as i16 * *z as i16 > 256 {
a = 255;
} else {
a = y * z;
}
cpu.regwrite(args[0] as usize, a);
cpu.incrementpc();
} else if instruction.name == "DIVD" {
let y = cpu.regread(args[0] as usize);
let z = cpu.regread(args[1] as usize);
let a;
if *z == 0 {
a = 0;
} else {
a = y / z;
}
cpu.regwrite(args[0] as usize, a);
cpu.incrementpc();
} else if instruction.name == "INC" {
let y = cpu.regread(args[0] as usize).to_owned();
if y == 0xFF {
cpu.regwrite(args[0] as usize, 0);
} else {
cpu.regwrite(args[0] as usize, y+1);
}
cpu.incrementpc();
} else if instruction.name == "NOT" {
let y = cpu.regread(args[0] as usize).to_owned();
cpu.regwrite(args[0] as usize, !y);
cpu.incrementpc();
} else if instruction.name == "AND" {
let y = cpu.regread(args[0] as usize);
let z = cpu.regread(args[1] as usize);
let a = y & z;
cpu.regwrite(args[0] as usize, a);
cpu.incrementpc();
} else if instruction.name == "OR" {
let y = cpu.regread(args[0] as usize);
let z = cpu.regread(args[1] as usize);
let a = y | z;
cpu.regwrite(args[0] as usize, a);
cpu.incrementpc();
} else if instruction.name == "XOR" {
let y = cpu.regread(args[0] as usize);
let z = cpu.regread(args[1] as usize);
let a = y ^ z;
cpu.regwrite(args[0] as usize, a);
cpu.incrementpc();
} else if instruction.name == "LESS" {
let y = cpu.regread(args[0] as usize);
let z = cpu.regread(args[1] as usize);
let b = (y < z) as u8;
cpu.regwrite(args[2] as usize, b);
cpu.incrementpc();
} else if instruction.name == "EQU" {
let y = cpu.regread(args[0] as usize);
let z = cpu.regread(args[1] as usize);
let b = (y == z) as u8;
cpu.regwrite(args[2] as usize, b);
cpu.incrementpc();
} else if instruction.name == "JMP" {
cpu.setpc(args[0] as u16);
} else if instruction.name == "JMR" {
cpu.refreshcache();
cpu.setpc(args[0] as u16);
} else if instruction.name == "JCZ" {
let y = cpu.regread(args[0] as usize);
if *y == 0 {
cpu.setpc(args[0] as u16);
} else {
cpu.incrementpc();
}
} else if instruction.name == "JCZR" {
cpu.refreshcache();
let y = cpu.regread(args[0] as usize);
if *y == 0 {
cpu.setpc(args[0] as u16);
} else {
cpu.incrementpc();
}
} else if instruction.name == "CALL" {
cpu.stackpush();
cpu.refreshcache();
cpu.setpc(args[0] as u16);
} else if instruction.name == "RET" {
let pointer = cpu.stackpop();
cpu.setbank(pointer.bank);
cpu.refreshcache();
cpu.setpc(pointer.address + 4);
} else if instruction.name == "DUMP" {
cpu.dump("Program executed dump");
cpu.incrementpc();
} else if instruction.name == "HALT" {
std::process::exit(0);
} else {
println!("Unimplemented instruction {}. Skipping.", instruction.name);
cpu.incrementpc();
}
return cpu;
}
fn peripherals(mut cpu: Cpu, stdpoll: &StdinPoll) -> Cpu {
let byte = stdpoll.poll_byte().unwrap_or(0x00);
cpu.setperph(0x02, byte);
let consoleout = cpu.getperph(0x01);
if consoleout != 0 {
let b = &[consoleout];
let string = std::str::from_utf8(b).unwrap_or("B");
print!("{}", string);
stdout().flush().unwrap();
cpu.setperph(0x01, 0);
}
return cpu
}
#[allow(unreachable_code)]
pub fn emulate(debug: bool) -> io::Result<()> {
let stdin = 0;
let mut stdout = io::stdout();
let termios = Termios::from_fd(stdin).unwrap();
let mut new_termios = termios.clone();
new_termios.c_lflag &= !(ICANON | ECHO);
tcsetattr(stdin, TCSANOW, &mut new_termios).unwrap();
if debug {
torture();
println!("If you see anything about opcodes above, there's a bug!");
}
let mut f = File::open("program.rom")?;
let mut buffer: Vec<u8> = vec![];
if debug { println!("Buffer initialised!"); }
f.read_to_end(&mut buffer)?;
let mut cpu = Cpu { memory: vec![ MemoryBank { content: vec![0; 65536] }; 256], pc: 0x0, registers: vec![0; 256], stack: vec![], peripherals: vec![0; 256], cache: MemoryBank { content: vec![0; 65536] }, bank: 0, cachebank: 0, debug: debug };
if debug { println!("CPU object initialised!"); }
cpu.setbank(0);
let mut i = 0;
let mut x = 0;
for byte in buffer {
cpu.ramwrite(i, byte);
i = i + 1;
if i == 65536 {
i = 0;
x = x + 1;
cpu.setbank(x);
}
}
cpu.setbank(0);
cpu.refreshcache();
let stdpoll = StdinPoll::new();
if debug {
println!("Program loaded into memory!");
}
loop {
let mut opcode = cpu.fetch();
let mut instruction = disassemble(opcode);
cpu = execute(opcode, instruction, cpu);
cpu = peripherals(cpu, &stdpoll);
}
Ok(())
}
fn torture() {
decodetest(0x00000000, "NOP");
decodetest(0x01000000, "LOAD_MEM_REG");
decodetest(0x02000000, "STOR_REG_MEM");
decodetest(0x03000000, "LOAD_REG_REG");
decodetest(0x04000000, "STOR_BYTE_REG");
decodetest(0x05000000, "SWAP_MEM_REG");
decodetest(0x06000000, "SWAP_REG_REG");
decodetest(0x0c000000, "INP");
decodetest(0x0d000000, "OUT");
decodetest(0x0e000000, "BANK");
decodetest(0x0f000000, "REF");
decodetest(0x10000000, "ADD");
decodetest(0x11000000, "SUB");
decodetest(0x12000000, "MULT");
decodetest(0x13000000, "DIVD");
decodetest(0x14000000, "INC");
decodetest(0x15000000, "DEC");
decodetest(0x16000000, "NOT");
decodetest(0x17000000, "AND");
decodetest(0x18000000, "OR");
decodetest(0x19000000, "XOR");
decodetest(0x1a000000, "LESS");
decodetest(0x1b000000, "EQU");
decodetest(0x20000000, "JMP");
decodetest(0x21000000, "JMR");
decodetest(0x22000000, "JCZ");
decodetest(0x23000000, "JCZR");
decodetest(0x24000000, "CALL");
decodetest(0x25000000, "RET");
decodetest(0xfe000000, "DUMP");
decodetest(0xff000000, "HALT");
}

19
src/main.rs Normal file
View file

@ -0,0 +1,19 @@
mod food8;
use self::food8::emulate;
use clap::Parser;
/// Field Of Operational Development Integral Emulator.
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
/// Shows dump information when a DUMP opcode is executed or when an erroneous operation occurs.
#[clap(short, long)]
debug: bool,
}
fn main() {
let args = Args::parse();
emulate(args.debug);
}