From debe2ecbc4f819dfec7f5ca7c1f0e2fd6bc37708 Mon Sep 17 00:00:00 2001 From: krolxon Date: Sun, 4 Jan 2026 23:49:04 +0530 Subject: [PATCH] add simple assembler --- code.asm => program.asm | 0 src/assembler.rs | 73 +++++++++++++++++++++++++++++++++++++++++ src/cpu.rs | 30 +++++++++++++---- src/main.rs | 54 +++++++----------------------- 4 files changed, 108 insertions(+), 49 deletions(-) rename code.asm => program.asm (100%) create mode 100644 src/assembler.rs diff --git a/code.asm b/program.asm similarity index 100% rename from code.asm rename to program.asm 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 { + 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 { + 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); + 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); - - 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), - } + for (i, byte) in program.iter().enumerate() { + mem.write(i as u16, *byte); } - println!("{:#?}", cpu); + while !cpu.halted { + cpu.step(&mut mem); + println!("{:?}", cpu); + } }