This commit is contained in:
IOException 2020-12-12 04:08:12 -06:00
commit 512826ce1d
7 changed files with 355 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

28
Cargo.lock generated Normal file
View file

@ -0,0 +1,28 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "anyhow"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4"
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "emu"
version = "0.1.0"
dependencies = [
"anyhow",
"base64",
"lazy_static",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"

12
Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "emu"
version = "0.1.0"
authors = ["IOException <ioexceptionosu@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.34"
base64 = "0.13.0"
lazy_static = "1.4.0"

1
mandelflag.rom Normal file
View file

@ -0,0 +1 @@
COA6CPAA6QDAQIJACMA4CNAAQIKACLAPCQAACRAACSAACTAAQILA6QDACDSACETACFSACGTAC/ABSQHAQQCBEXBfnQDACUBACVCADCACDBABETCAXBB/CWBACXCACDQACERACFQACGRAC/ACSQHAQQCCEXBfnQDABVVCEGVCXUUBBUUBEXUflQDAnIMABXXCEGXCXWWBBWWBCDSACETACFQACGRAC/ADSQHAQQCDCSBACTCABTTCEGTCXSSBBSSBBRXNEGRNXWWBBQWMBTTPEGTPXSSBBSSOCLL/ETLAmILAQIMAEWLBXLAynLfAEfELXLA6nLfAEWLJXLAmnLfAEfMLXLA7nLfAEWLPXLA8nLfAEfSLXLA0nLfACLAkQLfATACLCNNGEWNGXMMB6QDAETMEmIKACBA+TACBCPPMEWPMXOOBETOGnIJAC1ANSLeA6QDAQQHACIAACBAACCAAEEDAdIIBdEE/dDD/XEEBZSEAXDDBEUFAdIIBdGG/dFF/XGGBZSGAXFFBLHDCLJFCUHJACJAABCCHEGCHXJJBBHADUHGCBCCHEGCHXJJBBHAEUHFCBCCHEGCHXJJBBHAEUHGIBCCHEGCHXJJBCBJACJAABHADUHFCBBBHEGBHmQDABHADUHGIBBBHEGBHmQDABHAEUHFIBBBHEGBHC0AXnQDACJDAUJFIETJAnQDAETIAdCC/dBB/XCCBZSCAXBBBRQC/QLeACBARTACBCBAOTACBCBAiTACBCBA+TACBTAEBQYAATBEAEXBB7YAACBARTACBCBAOTACBCBAiTACBCBAkTACBCzAOCBAUTACBCBASTACBCBANTACBCBA+TACBTAEBQYAATBEAEXBB7YAACBAgTACBCBAKTACBCBAXTACBCBAdTACBCBAkTACBCBAcTACBCBAeTACBCBAWTACBCBA8TACBTACBTACBTAEBQYAATBEAEXBB7YAACBAPTACBCBAVTACBCBAKTACBCBAQTACBCBA1TACBCBAkTACBCBA+TACBQYBATBAAEXBD7YBAT8BAT9BATABATABACCAAQYDABBC8C/ABSYCAQYEBBDABHBC9C/ACSYCAQYECDDDBTACDPDCoCCCBESCM7YDACBAACyAQQYDAOCByTACCCBBBESBE7YDACBAKCCAeCDAyCEA1CFA+CGAVCKAAQYDACHAACMAAQYFALHHBOIMBKIIBFHHIOIMBLIIJPIMBCMMBESMG7YFATACHCKKBESKG7YDARYGAQYHAAAAAQYCAESBjdBBomYE/ESBddBBpmYE/ESBidBB0mYE/ESBQdBBImYE/ESBMdBB2mYE/ESBNdBBFmYE/ESBydBBSmYE/ESBAdBBHmYE/ESBqdBBjmYE/ESBxdBBVmYE/ESBwdBBLmYE/ESBfdBB2mYE/ESBOdBB7mYE/ESBcdBBrmYE/ESBSdBBUmYE/ESB9dBBDmYE/ESBHdBBEmYE/ESB1dBBimYE/ESBzdBBgmYE/ESB2dBBsmYE/ESBXdBBrmYE/ESB/dBBdmYE/ESBJdBBQmYE/ESBadBBemYE/ESB7dBBumYE/ESBDdBBOmYE/ESBGdBBtmYE/ESBgdBBfmYE/ESBCdBBqmYE/ESBpdBBGmYE/ESBZdBBpmYE/ESB3dBBOmYE/ESBUdBB6mYE/ESBKdBBPmYE/ESBbdBBtmYE/ESBLdBBKmYE/ESBEdBBZmYE/ESB6dBB1mYE/ESBkdBB0mYE/ESB8dBBwmYE/ESB4dBB4mYE/ESBIdBBimYE/ESBWdBBYmYE/ESBTdBBRmYE/ESBldBB3mYE/ESBRdBBFmYE/ESBudBBNmYE/ESBndBBWmYE/ESBedBBPmYE/ESB5dBBfmYE/ESBsdBBemYE/ESBFdBBemYE/ESBYdBBrmYE/ESBodBBQmYE/ESBVdBBfmYE/ESBhdBBNmYE/ESBtdBBzmYE/ESB0dBBTmYE/ESBrdBBWmYE/ESBvdBBzmYE/ESBPdBBqmYE/ESBBdBBsmYE/ESBmdBBHmYE/ESB+dBBhmYE/QYGAIoo6IppSIqqbIrrLIssSIttBJBBAQYDAOCBoTACCCBBBETBGmYDARYHA

158
src/instr.rs Normal file
View file

@ -0,0 +1,158 @@
#[derive(Clone, Debug)]
pub enum Instr {
Invalid,
Normal {
cond: Cond,
op: Op,
a: u8,
b: u8,
c: u8,
}
}
#[derive(Clone, Debug)]
pub enum Cond {
Uncond,
IfTrue,
IfFalse,
}
#[derive(Clone, Debug)]
pub enum Op {
// arithmetic and logic
Add,
AddI,
Sub,
Or,
OrI,
Xor,
XorI,
And,
AndI,
Shl,
Shr,
// comparison
CmpRR(Cm),
CmpRI(Cm),
CmpII(Cm),
// shift/rotate by immediate
ShlI,
ShrI,
Sar,
Rol,
// indirect memory access
Load,
Store,
// fixed-point multiply
Fmu,
Fms,
// control flow
Label,
JmpUp,
JmpDn,
// device io
IO,
}
#[derive(Clone, Debug)]
pub enum Cm {
Tr,
Fa,
Eq,
Ne,
Sl,
Sg,
Ul,
Ug,
}
impl Instr {
pub fn decode(instr: u32) -> Instr {
let opc = instr >> 18;
let a = ((instr >> 12) & 0b111111) as u8;
let b = ((instr >> 6) & 0b111111) as u8;
let c = (instr & 0b111111) as u8;
if opc == 0 { return Instr::Invalid; }
let cond = match (opc - 1) / 21 {
0 => Cond::Uncond,
1 => Cond::IfTrue,
2 => Cond::IfFalse,
_ => unreachable!("invalid cond: {:o}", opc),
};
let op = match (opc - 1) % 21 {
// arithmetic and logic
0o000 => Op::Add,
0o001 => Op::AddI,
0o002 => Op::Sub,
0o004 => Op::Or,
0o005 => Op::OrI,
0o006 => Op::Xor,
0o007 => Op::XorI,
0o010 => Op::And,
0o011 => Op::AndI,
0o013 => Op::Shl,
0o014 => Op::Shr,
// comparison
0o003 => {
let cc = match a % 0o010 {
0 => Cm::Tr,
1 => Cm::Fa,
2 => Cm::Eq,
3 => Cm::Ne,
4 => Cm::Sl,
5 => Cm::Sg,
6 => Cm::Ul,
7 => Cm::Ug,
v => unreachable!("invalid 003 cc: {:o}", a),
};
match a / 0o010 {
0 => Op::CmpRR(cc),
2 => Op::CmpRI(cc),
3 => Op::CmpII(cc),
v => unreachable!("invalid 003: {:o}", a),
}
},
// shift/rotate by immediate
0o012 => match c / 0o010 {
0 => Op::ShlI,
1 => Op::ShrI,
2 => Op::Sar,
3 => Op::Rol,
v => unreachable!("invalid 012: {:o}", c),
}
// indirect memory access
0o015 => Op::Load,
0o016 => Op::Store,
// fixed-point multiply
0o023 => match c / 0o020 {
0 => Op::Fmu,
1 => Op::Fms,
v => unreachable!("invalid 023: {:o}", c),
}
// control flow
0o017 => Op::Label,
0o020 => Op::JmpUp,
0o021 => Op::JmpDn,
// device io
0o022 => Op::IO,
v if v >= 21 => unreachable!("invalid {:o}", v),
_ => unreachable!("shiet"),
};
Instr::Normal {cond, op, a, b, c}
}
}

125
src/main.rs Normal file
View file

@ -0,0 +1,125 @@
mod instr;
mod memory;
use std::fs::File;
use std::io::{Read, Write};
use std::collections::HashMap;
use anyhow::Result;
use crate::memory::*;
use crate::instr::*;
lazy_static::lazy_static! {
static ref CH: (HashMap<u8, usize>, HashMap<usize, u8>) = {
let mut chmap = HashMap::new();
let mut chmap2 = HashMap::new();
let m = [
b"0123456789ABCDEF",
b"GHIJKLMNOPQRSTUV",
b"WXYZ +-*/<=>()[]",
b"{}#$_?|^&!~,.:\n\x00",
];
for (nrow, row) in m.iter().enumerate() {
for (ncol, cell) in row.iter().enumerate() {
let n = nrow * 0o20 + ncol;
chmap.insert(*cell, n);
chmap2.insert(n, *cell);
}
}
(chmap, chmap2)
};
}
struct Clock {
}
#[derive(Default)]
pub struct Control {
instrs: Vec<Instr>,
memory: Memory,
condition: bool,
overflow: bool,
zero: bool,
carry: bool,
sign: bool,
ip: usize,
}
impl Control {
fn step(&mut self) {
let instr = &self.instrs[self.ip];
self.ip += 1;
let (cond, op, a, b, c) = match instr {
Instr::Invalid => panic!("halt"),
Instr::Normal { cond, op, a, b, c } => (cond, op, *a, *b, *c),
};
println!("instr: {:?}", instr);
// skip conditionals that aren't taken
match (self.condition, cond) {
(false, Cond::IfTrue) | (true, Cond::IfFalse) => return,
_ => {},
}
match op {
Op::AddI => { self.memory.write(a, b + c) },
Op::Label => { /* don't do anything here */ },
Op::CmpRR(cm) | Op::CmpRI(cm) | Op::CmpII(cm) => {
let (op1, op2) = match op {
Op::CmpRR(_) => (self.memory.read(b), self.memory.read(c)),
Op::CmpRI(_) => (self.memory.read(b), c),
Op::CmpII(_) => (b, c),
_ => unreachable!(),
};
let result = match cm {
Cm::Tr => true,
Cm::Fa => false,
Cm::Eq =>
};
}
Op::JmpUp | Op::JmpDn => {
let lab = (a, b);
let rc = self.memory.read(c);
loop {
if let Op::JmpUp = op { self.ip -= 1; } else { self.ip += 1; }
let (cond, op, a, b, c) = match &self.instrs[self.ip] {
Instr::Invalid => panic!("halt"),
Instr::Normal { cond, op, a, b, c } => (cond, op, *a, *b, *c),
};
if lab == (a, b) && c == rc {
println!("JUMPED TO {:?}", self.ip);
break;
}
}
},
_ => unreachable!("unhandled {:?}", op),
};
println!("memory: {:?}", self.memory);
println!("{:?}", std::str::from_utf8(self.memory.array.iter().map(|i| *CH.1.get(&(*i as usize)).unwrap()).collect::<Vec<_>>().as_slice()));
}
}
fn main() -> Result<()> {
let mut file = File::open("mandelflag.rom")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let contents = base64::decode(&contents)?;
let instrs = contents.chunks(3)
.map(|c| ((c[0] as u32) << 16) | ((c[1] as u32) << 8) | c[2] as u32)
.map(Instr::decode)
.collect::<Vec<_>>();
let mut cpu = Control::default();
cpu.instrs = instrs;
for _ in 0..1000 {
cpu.step();
}
Ok(())
}

30
src/memory.rs Normal file
View file

@ -0,0 +1,30 @@
#[derive(Clone, Debug)]
pub struct Memory {
pub array: [u8; 64],
}
impl Default for Memory {
fn default() -> Self {
Memory {
array: [0; 64],
}
}
}
pub struct In {
addr: u8,
op1: u8,
op2: u8,
}
impl Memory {
pub fn write(&mut self, addr: u8, val: u8) {
if addr == 0 { /* nop */ }
else { self.array[addr as usize] = val & 0b111111; }
}
pub fn read(&mut self, addr: u8) -> u8 {
if addr == 0 { 0 }
else { self.array[addr as usize] }
}
}