aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/assembler.rs73
-rw-r--r--src/cpu.rs30
-rw-r--r--src/main.rs52
3 files changed, 107 insertions, 48 deletions
diff --git a/src/assembler.rs b/src/assembler.rs
new file mode 100644
index 0000000..3cd2bf8
--- /dev/null
+++ b/src/assembler.rs
@@ -0,0 +1,73 @@
+use crate::instructions::Instruction;
+
+fn tokenize(line: &str) -> Vec<String> {
+ line.split(|c| c == ' ' || c == ',' || c == '\t')
+ .filter(|s| !s.is_empty())
+ .map(|s| s.to_lowercase())
+ .collect()
+}
+
+fn parse_reg(s: &str) -> u8 {
+ match s {
+ "a" => 0,
+ "b" => 1,
+ "c" => 2,
+ "d" => 3,
+ _ => panic!("Unknown register {}", s),
+ }
+}
+
+pub fn assembler(source: &str) -> Vec<u8> {
+ let mut bytes = Vec::new();
+
+ for (line_no, line) in source.lines().enumerate() {
+ let line = line.trim();
+
+ // Comments in assembly start with ";"
+ if line.is_empty() || line.starts_with(';') {
+ continue;
+ }
+
+ let tokens = tokenize(line);
+
+ match tokens[0].as_str() {
+ "mov" => {
+ // mov reg, imm
+ let reg = parse_reg(&tokens[1]);
+ let imm: u8 = tokens[2].parse().unwrap();
+
+ bytes.push(Instruction::MOV as u8);
+ bytes.push(reg);
+ bytes.push(imm);
+ }
+
+ "add" => {
+ // add a, b
+ let r1 = parse_reg(&tokens[1]);
+ let r2 = parse_reg(&tokens[2]);
+
+ bytes.push(Instruction::ADD as u8);
+ bytes.push(r1);
+ bytes.push(r2);
+ }
+
+ "sub" => {
+ // sub a, b
+ let r1 = parse_reg(&tokens[1]);
+ let r2 = parse_reg(&tokens[2]);
+
+ bytes.push(Instruction::SUB as u8);
+ bytes.push(r1);
+ bytes.push(r2);
+ }
+
+ "hlt" => {
+ bytes.push(Instruction::HLT as u8);
+ }
+
+ _ => panic!("Line {}: unknown instruction", line_no + 1),
+ }
+ }
+
+ bytes
+}
diff --git a/src/cpu.rs b/src/cpu.rs
index 78484fe..13d2fc8 100644
--- a/src/cpu.rs
+++ b/src/cpu.rs
@@ -1,4 +1,6 @@
+use crate::instructions::Instruction;
use crate::memory::Memory;
+
#[derive(Default, Debug)]
pub struct CPU {
pub a: u8,
@@ -16,6 +18,22 @@ pub struct CPU {
}
impl CPU {
+ pub fn step(&mut self, mem: &mut Memory) {
+ let opcode = mem.read(self.pc);
+ self.inc_pc();
+
+ match opcode {
+ x if x == Instruction::MOV as u8 => self.mov(mem),
+ x if x == Instruction::ADD as u8 => self.add(mem),
+ x if x == Instruction::SUB as u8 => self.sub(mem),
+ x if x == Instruction::JMP as u8 => self.jmp(mem),
+ x if x == Instruction::JZ as u8 => self.jz(mem),
+ x if x == Instruction::JNZ as u8 => self.jnz(mem),
+ x if x == Instruction::HLT as u8 => self.halt(),
+ _ => panic!("Unknown opcode {:02X}", opcode),
+ }
+ }
+
pub fn inc_pc(&mut self) {
self.pc += 1;
}
@@ -24,7 +42,7 @@ impl CPU {
self.halted = true;
}
- pub fn mov(&mut self, mem: &mut Memory) {
+ pub fn mov(&mut self, mem: &Memory) {
let reg = mem.read(self.pc);
self.inc_pc();
let val = mem.read(self.pc);
@@ -41,7 +59,7 @@ impl CPU {
self.zero = val == 0;
}
- pub fn add(&mut self, mem: &mut Memory) {
+ pub fn add(&mut self, mem: &Memory) {
let dest = mem.read(self.pc);
self.pc += 1;
let src = mem.read(self.pc);
@@ -83,7 +101,7 @@ impl CPU {
self.carry = carry;
}
- pub fn sub(&mut self, mem: &mut Memory) {
+ pub fn sub(&mut self, mem: &Memory) {
let dest = mem.read(self.pc);
self.pc += 1;
let src = mem.read(self.pc);
@@ -125,7 +143,7 @@ impl CPU {
self.carry = borrow;
}
- pub fn jmp(&mut self, mem: &mut Memory) {
+ pub fn jmp(&mut self, mem: &Memory) {
let low = mem.read(self.pc) as u16;
self.inc_pc();
let high = mem.read(self.pc) as u16;
@@ -136,7 +154,7 @@ impl CPU {
self.pc = addrs;
}
- pub fn jz(&mut self, mem: &mut Memory) {
+ pub fn jz(&mut self, mem: &Memory) {
let low = mem.read(self.pc) as u16;
self.inc_pc();
let high = mem.read(self.pc) as u16;
@@ -149,7 +167,7 @@ impl CPU {
}
}
- pub fn jnz(&mut self, mem: &mut Memory) {
+ pub fn jnz(&mut self, mem: &Memory) {
let low = mem.read(self.pc) as u16;
self.inc_pc();
let high = mem.read(self.pc) as u16;
diff --git a/src/main.rs b/src/main.rs
index fc7f311..811e0cf 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,58 +1,26 @@
+mod assembler;
mod cpu;
mod instructions;
mod memory;
use cpu::CPU;
-use instructions::Instruction;
use memory::Memory;
+use crate::assembler::assembler;
+
fn main() {
let mut cpu = CPU::default();
let mut mem = Memory::new();
- // a = 10
- mem.write(0x0000, Instruction::MOV as u8);
- mem.write(0x0001, 0);
- mem.write(0x0002, 5);
-
- // b = 2
- mem.write(0x0003, Instruction::MOV as u8);
- mem.write(0x0004, 1);
- mem.write(0x0005, 3);
-
- // a = a + b
- mem.write(0x0006, Instruction::SUB as u8);
- mem.write(0x0007, 0);
- mem.write(0x0008, 1);
-
- // JMP to halt
- mem.write(0x0009, Instruction::JNZ as u8);
- mem.write(0x000a, 0x0f); // Low
- mem.write(0x000b, 0x00); // High
+ let asm = std::fs::read_to_string("program.asm").unwrap();
+ let program = assembler(&asm);
- // set b = 0
- mem.write(0x000c, Instruction::MOV as u8);
- mem.write(0x000d, 1);
- mem.write(0x000e, 0);
-
- // halt
- mem.write(0x000f, Instruction::HLT as u8);
+ for (i, byte) in program.iter().enumerate() {
+ mem.write(i as u16, *byte);
+ }
while !cpu.halted {
- let opcode = mem.read(cpu.pc);
- cpu.inc_pc();
-
- match opcode {
- x if x == Instruction::MOV as u8 => cpu.mov(&mut mem),
- x if x == Instruction::ADD as u8 => cpu.add(&mut mem),
- x if x == Instruction::SUB as u8 => cpu.sub(&mut mem),
- x if x == Instruction::JMP as u8 => cpu.jmp(&mut mem),
- x if x == Instruction::JZ as u8 => cpu.jz(&mut mem),
- x if x == Instruction::JNZ as u8 => cpu.jnz(&mut mem),
- x if x == Instruction::HLT as u8 => cpu.halt(),
- _ => panic!("Unknown opcode {:02X}", opcode),
- }
+ cpu.step(&mut mem);
+ println!("{:?}", cpu);
}
-
- println!("{:#?}", cpu);
}