diff --git a/README.md b/README.md index 2290da0..18a02e8 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,13 @@ | Instruction | Syntax | | ----------- | ------------ | -| MOV | mov reg, imm | +| MOV | mov reg, imm OR mov reg, reg | | ADD | add r1, r2 | | SUB | sub r1, r2 | | JMP | jmp addr | | JZ | jz addr | | JNZ | jnz addr | +| CMP | cmp reg, imm OR cmp reg, reg | | HLT (Halt) | hlt | @@ -46,7 +47,7 @@ cargo run -- --f - [x] Lexer/Tokenizer - [x] Add label support (supporting JMP/JZ/JNZ) - [ ] Add instructions - - [ ] CMP + - [x] CMP - [ ] CALL - [ ] RET - [ ] Error handling diff --git a/examples/cmp.asm b/examples/cmp.asm new file mode 100644 index 0000000..f35ccf4 --- /dev/null +++ b/examples/cmp.asm @@ -0,0 +1,4 @@ +mov a, 10 +mov b, 10 +cmp a, b +hlt diff --git a/examples/mov.asm b/examples/mov.asm new file mode 100644 index 0000000..4aa3c04 --- /dev/null +++ b/examples/mov.asm @@ -0,0 +1,5 @@ +mov a, 10 +mov b, a +cmp a, b +cmp a, 10 +hlt diff --git a/examples/subtraction.asm b/examples/subtraction.asm deleted file mode 100644 index cfc9db5..0000000 --- a/examples/subtraction.asm +++ /dev/null @@ -1,4 +0,0 @@ -mov a, 15 -mov b, 15 -sub a, b -hlt diff --git a/src/assembler.rs b/src/assembler.rs index 3eeec64..c4751c1 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -18,15 +18,20 @@ fn parse_reg(s: &str) -> u8 { } } -fn instr_size(tokens: &[String]) -> u16 { - match tokens[0].as_str() { - "mov" | "add" | "sub" | "jmp" | "jz" | "jnz" => 3, - "hlt" => 1, - _ => panic!("Unknown instruction {}", tokens[0]) - +fn is_reg(s: &str) -> bool { + match s { + "a" | "b" | "c" | "d" => true, + _ => false, } } +fn instr_size(tokens: &[String]) -> u16 { + match tokens[0].as_str() { + "mov" | "add" | "sub" | "jmp" | "jz" | "jnz" | "cmp" => 3, + "hlt" => 1, + _ => panic!("Unknown instruction {}", tokens[0]), + } +} fn first_pass(source: &str) -> HashMap { let mut symbols = HashMap::new(); @@ -72,11 +77,17 @@ pub fn assembler(source: &str) -> Vec { "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); + if is_reg(&tokens[2]) { + let r2 = parse_reg(&tokens[2]); + bytes.push(Instruction::MOV_RR as u8); + bytes.push(reg); + bytes.push(r2); + } else { + let imm: u8 = tokens[2].parse().unwrap(); + bytes.push(Instruction::MOV_RI as u8); + bytes.push(reg); + bytes.push(imm); + } } "add" => { @@ -91,8 +102,8 @@ pub fn assembler(source: &str) -> Vec { "sub" => { // sub a, b - let r1 = parse_reg(&tokens[1]); let r2 = parse_reg(&tokens[2]); + let r1 = parse_reg(&tokens[1]); bytes.push(Instruction::SUB as u8); bytes.push(r1); @@ -104,7 +115,7 @@ pub fn assembler(source: &str) -> Vec { "jmp" => Instruction::JMP, "jz" => Instruction::JZ, "jnz" => Instruction::JNZ, - _ => unreachable!() + _ => unreachable!(), }; let label = &tokens[1]; @@ -115,6 +126,21 @@ pub fn assembler(source: &str) -> Vec { bytes.push((addr >> 8) as u8); // high } + "cmp" => { + let r1 = parse_reg(&tokens[1]); + if tokens[2].chars().all(|c| c.is_ascii_digit()) { + let imm: u8 = tokens[2].parse().unwrap(); + bytes.push(Instruction::CMP_RI as u8); + bytes.push(r1); + bytes.push(imm); + } else { + let r2 = parse_reg(&tokens[2]); + bytes.push(Instruction::CMP_RR as u8); + bytes.push(r1); + bytes.push(r2); + } + } + "hlt" => { bytes.push(Instruction::HLT as u8); } diff --git a/src/cpu.rs b/src/cpu.rs index df8b3a2..116d20d 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -19,7 +19,6 @@ pub struct CPU { } impl CPU { - pub fn debug_instr(&self, mem: &Memory) { let opcode = mem.read(self.pc); @@ -41,12 +40,15 @@ impl CPU { self.inc_pc(); match opcode { - x if x == Instruction::MOV as u8 => self.mov(mem), + x if x == Instruction::MOV_RI as u8 => self.mov_ri(mem), + x if x == Instruction::MOV_RR as u8 => self.mov_rr(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::CMP_RI as u8 => self.cmp_ri(mem), + x if x == Instruction::CMP_RR as u8 => self.cmp_rr(mem), x if x == Instruction::HLT as u8 => self.halt(), _ => panic!("Unknown opcode {:02X}", opcode), } @@ -60,7 +62,7 @@ impl CPU { self.halted = true; } - pub fn mov(&mut self, mem: &Memory) { + pub fn mov_ri(&mut self, mem: &Memory) { let reg = mem.read(self.pc); self.inc_pc(); let val = mem.read(self.pc); @@ -77,6 +79,19 @@ impl CPU { self.zero = val == 0; } + pub fn mov_rr(&mut self, mem: &Memory) { + let dest = mem.read(self.pc); + self.inc_pc(); + let src= mem.read(self.pc); + self.inc_pc(); + + let val = self.get_reg(src); + self.set_reg(dest, val); + + self.zero = val == 0; + } + + pub fn add(&mut self, mem: &Memory) { let dest = mem.read(self.pc); self.pc += 1; @@ -197,4 +212,55 @@ impl CPU { self.pc = addrs; } } + + pub fn cmp_rr(&mut self, mem: &Memory) { + let r1 = mem.read(self.pc); + self.inc_pc(); + let r2 = mem.read(self.pc); + self.inc_pc(); + + let v1 = self.get_reg(r1); + let v2 = self.get_reg(r2); + + let (result, borrow) = v1.overflowing_sub(v2); + + self.zero = result == 0; + self.carry = borrow; + } + + pub fn cmp_ri(&mut self, mem: &Memory) { + let r1 = mem.read(self.pc); + self.inc_pc(); + let r2 = mem.read(self.pc); + self.inc_pc(); + + let v1 = self.get_reg(r1); + + let (result, borrow) = v1.overflowing_sub(r2); + + self.zero = result == 0; + self.carry = borrow; + } + + + fn get_reg(&self, r: u8) -> u8 { + match r { + 0 => self.a, + 1 => self.b, + 2 => self.c, + 3 => self.d, + _ => 0, + } + } + + fn set_reg(&mut self, dest: u8, val: u8) { + match dest { + 0 => self.a = val, + 1 => self.b = val, + 2 => self.c = val, + 3 => self.d = val, + _ => {}, + } + } + } diff --git a/src/instructions.rs b/src/instructions.rs index ac88e94..77de7f4 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -1,23 +1,27 @@ #[repr(u8)] pub enum Instruction { - MOV = 0x01, + MOV_RI = 0x01, + MOV_RR = 0x08, ADD = 0x02, SUB = 0x03, JMP = 0x04, JZ = 0x05, JNZ = 0x06, + CMP_RI = 0x07, + CMP_RR = 0x09, HLT = 0xFF, } impl Instruction { pub fn opcode_name(op: u8) -> &'static str{ match op { - 0x01 => "MOV", + 0x01 | 0x08 => "MOV", 0x02 => "ADD", 0x03 => "SUB", 0x04 => "JMP", 0x05 => "JZ", 0x06 => "JNZ", + 0x07 | 0x09 => "CMP", 0xFF => "HLT", _ => "???", }