177 lines
4.9 KiB
Rust
177 lines
4.9 KiB
Rust
use byteorder::{ReadBytesExt, LE};
|
|
use std::io::Result;
|
|
|
|
type Word = u16;
|
|
//type Memory = [Word; Word::MAX as usize + 1];
|
|
|
|
struct Memory {
|
|
words: [Word; Word::MAX as usize + 1],
|
|
}
|
|
|
|
impl Memory {
|
|
fn get(&self, index: Word) -> Word {
|
|
self.words[index as usize]
|
|
}
|
|
|
|
fn get_ref(&self, index: Word) -> Word {
|
|
// equivalent to get(get(index))
|
|
self.words[self.words[index as usize] as usize]
|
|
}
|
|
|
|
fn put(&mut self, index: Word, value: Word) {
|
|
self.words[index as usize] = value;
|
|
}
|
|
|
|
//fn put_ref(&mut self, index: Word, value: Word) {}
|
|
|
|
fn new(path_str: &str) -> Memory {
|
|
let mut file = match std::fs::File::open(path_str) {
|
|
Result::Ok(x) => x,
|
|
Result::Err(_) => panic!("could not open program"),
|
|
};
|
|
let mut mem = Memory {
|
|
words: [0x0; u16::MAX as usize + 1],
|
|
};
|
|
let mut index = 0;
|
|
loop {
|
|
match file.read_u16::<LE>() {
|
|
Result::Ok(word) => {
|
|
mem.words[index] = word;
|
|
//println!("DEBUG: WORD: {:#06x}", word);
|
|
index += 1;
|
|
}
|
|
Result::Err(error) => match error.kind() {
|
|
std::io::ErrorKind::UnexpectedEof => {
|
|
//println!("DEBUG: EOF");
|
|
break;
|
|
}
|
|
other_error => panic!("Other error: {:?}", other_error),
|
|
},
|
|
}
|
|
}
|
|
mem
|
|
}
|
|
}
|
|
|
|
struct Cpu {
|
|
//ax: Word, // Accumulator
|
|
//bx: Word, // Base
|
|
//cx: Word, // Counter
|
|
//dx: Word, // Data
|
|
|
|
//si: Word, // Source Index
|
|
//di: Word, // Destination Index
|
|
//bp: Word, // Base Pointer
|
|
//sp: Word, // Stack Pointer
|
|
ip: Word, // Instruction Pointer
|
|
|
|
// Segment & Status registers ignored for now
|
|
memory: Memory, // for convenience, the CPU has ownership of the memory
|
|
|
|
//registers are part of the memory now...
|
|
|
|
// TODO proper input handling (probably read from command line)
|
|
input: Vec<u8>,
|
|
input_index: usize,
|
|
}
|
|
|
|
impl Cpu {
|
|
fn _read_input(&mut self) -> Word {
|
|
// TODO length check or something...
|
|
let byte = self.input[self.input_index] as Word;
|
|
self.input_index += 1;
|
|
//println!("DEBUG: read byte {}", byte);
|
|
byte
|
|
}
|
|
fn _first_arg(&self) -> Word {
|
|
self.memory
|
|
.get(match self.memory.get(self.ip).checked_add(1) {
|
|
Some(x) => x,
|
|
None => panic!("malformed instruction at {}", self.memory.get(self.ip)),
|
|
})
|
|
}
|
|
|
|
fn _second_arg(&self) -> Word {
|
|
self.memory
|
|
.get(match self.memory.get(self.ip).checked_add(2) {
|
|
Some(x) => x,
|
|
None => panic!("malformed instruction at {}", self.memory.get(self.ip)),
|
|
})
|
|
}
|
|
|
|
fn step(&mut self) {
|
|
//println!("DEBUG: IP: {}", self.memory.get(self.ip));
|
|
// fetch and decode instruction
|
|
let (op, len) = match self.memory.get_ref(self.ip) {
|
|
0x10 => (Op::Input(self._first_arg()), 2),
|
|
0x11 => (Op::Output(self._first_arg()), 2),
|
|
0x20 => (Op::Mov(self._first_arg(), self._second_arg()), 3),
|
|
0x90 => (Op::Nop, 1),
|
|
0xFF => (Op::Exit(self._first_arg()), 2),
|
|
x => panic!("unknown instruction {} at {}", x, self.memory.get(self.ip)),
|
|
};
|
|
|
|
// increment ip
|
|
self.memory
|
|
.put(self.ip, self.memory.get(self.ip).wrapping_add(len));
|
|
|
|
// execute instruction
|
|
match op {
|
|
Op::Input(address) => {
|
|
//println!("DEBUG: INPUT: {}", address);
|
|
let x = self._read_input();
|
|
self.memory.put(address, x);
|
|
}
|
|
Op::Mov(dest, src) => self.memory.put(dest, self.memory.get(src)),
|
|
Op::Nop => {}
|
|
Op::Output(address) => {
|
|
//println!("DEBUG: OUTPUT: {}", address);
|
|
print!("{} ", self.memory.get(address));
|
|
}
|
|
Op::Exit(status) => std::process::exit(status as i32),
|
|
}
|
|
}
|
|
|
|
fn new(memory: Memory) -> Cpu {
|
|
// TODO number registers, leave 0 for NULL
|
|
// TODO either put at end of address space
|
|
// or offset programs
|
|
Cpu {
|
|
ip: 9,
|
|
memory,
|
|
input: vec![54, 65, 73, 74], // TODO proper input from command line or stdin
|
|
input_index: 0,
|
|
}
|
|
}
|
|
}
|
|
|
|
enum Op {
|
|
Input(Word),
|
|
Mov(Word, Word),
|
|
Nop,
|
|
Output(Word),
|
|
Exit(Word),
|
|
}
|
|
|
|
/*
|
|
impl Op {
|
|
fn length(&self) -> Word {
|
|
match *self {
|
|
Op::Nop => 1,
|
|
Op::Input(_) | Op::Output(_) => 2,
|
|
Op::Mov(_, _) => 3,
|
|
}
|
|
}
|
|
}*/
|
|
|
|
fn main() {
|
|
let args: Vec<String> = std::env::args().collect();
|
|
let memory = Memory::new(&args[1]);
|
|
let mut cpu = Cpu::new(memory);
|
|
|
|
for _ in 0..=255 {
|
|
cpu.step();
|
|
}
|
|
println!();
|
|
}
|