add simple assembler
This commit is contained in:
parent
a566c1737b
commit
debe2ecbc4
|
|
@ -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
|
||||
}
|
||||
30
src/cpu.rs
30
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;
|
||||
|
|
|
|||
52
src/main.rs
52
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);
|
||||
let asm = std::fs::read_to_string("program.asm").unwrap();
|
||||
let program = assembler(&asm);
|
||||
|
||||
// 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
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue