diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/assembler.rs | 50 | ||||
| -rw-r--r-- | src/cpu.rs | 72 | ||||
| -rw-r--r-- | src/instructions.rs | 8 |
3 files changed, 113 insertions, 17 deletions
diff --git a/src/assembler.rs b/src/assembler.rs index 3eeec64..c4751c1 100644 --- a/src/assembler.rs +++ b/src/assembler.rs @@ -18,16 +18,21 @@ fn parse_reg(s: &str) -> u8 { } } -fn instr_size(tokens: &[String]) -> u16 { +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" => 3, + "mov" | "add" | "sub" | "jmp" | "jz" | "jnz" | "cmp" => 3, "hlt" => 1, - _ => panic!("Unknown instruction {}", tokens[0]) - + _ => panic!("Unknown instruction {}", tokens[0]), } } - fn first_pass(source: &str) -> HashMap<String, u16> { let mut symbols = HashMap::new(); let mut addr: u16 = 0; @@ -72,11 +77,17 @@ pub fn assembler(source: &str) -> Vec<u8> { "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<u8> { "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<u8> { "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<u8> { 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); } @@ -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", _ => "???", } |
