bench51133f6f7
add CALL, RET
+72 −4
6 files changed
- A examples/call.asm +7 −0
- M examples/div.asm +1 −1
- M src/assembler.rs +16 −2
- M src/cpu.rs +42 −0
- M src/instructions.rs +5 −0
- M src/main.rs +1 −1
| @@ -0,0 +1,7 @@ | |||
| 1 | + | mov a, 2 | |
| 2 | + | call square | |
| 3 | + | hlt | |
| 4 | + | ||
| 5 | + | square: | |
| 6 | + | mul a, a | |
| 7 | + | ret | |
| @@ -1,4 +1,4 @@ | |||
| 1 | 1 | mov a, 10 | |
| 2 | − | mov b, 2 | |
| 2 | + | mov b, 10 | |
| 3 | 3 | div a, b | |
| 4 | 4 | hlt | |
| @@ -25,8 +25,8 @@ fn is_reg(s: &str) -> bool { | |||
| 25 | 25 | ||
| 26 | 26 | fn instr_size(tokens: &[String]) -> u16 { | |
| 27 | 27 | match tokens[0].as_str() { | |
| 28 | − | "mov" | "add" | "sub" | "jmp" | "jz" | "jnz" | "cmp" | "mul" | "div" => 3, | |
| 29 | − | "hlt" => 1, | |
| 28 | + | "mov" | "add" | "sub" | "jmp" | "jz" | "jnz" | "cmp" | "mul" | "div" | "call" => 3, | |
| 29 | + | "hlt" | "ret" => 1, | |
| 30 | 30 | _ => panic!("Unknown instruction {}", tokens[0]), | |
| 31 | 31 | } | |
| 32 | 32 | } | |
| @@ -172,6 +172,20 @@ pub fn assembler(source: &str) -> Vec<u8> { | |||
| 172 | 172 | bytes.push(r2); | |
| 173 | 173 | } | |
| 174 | 174 | ||
| 175 | + | "call" => { | |
| 176 | + | let addr = *symbols | |
| 177 | + | .get(&tokens[1]) | |
| 178 | + | .expect("Unknown label"); | |
| 179 | + | ||
| 180 | + | bytes.push(Instruction::CALL as u8); | |
| 181 | + | bytes.push((addr & 0xFF) as u8); // low | |
| 182 | + | bytes.push((addr >> 8) as u8); // high | |
| 183 | + | } | |
| 184 | + | ||
| 185 | + | "ret" => { | |
| 186 | + | bytes.push(Instruction::RET as u8); | |
| 187 | + | } | |
| 188 | + | ||
| 175 | 189 | "hlt" => { | |
| 176 | 190 | bytes.push(Instruction::HLT as u8); | |
| 177 | 191 | } | |
| @@ -19,6 +19,22 @@ pub struct CPU { | |||
| 19 | 19 | } | |
| 20 | 20 | ||
| 21 | 21 | impl CPU { | |
| 22 | + | fn push16(&mut self, mem: &mut Memory, val: u16) { | |
| 23 | + | self.dec_sp(); | |
| 24 | + | mem.write(self.sp, (val >> 8) as u8); // high | |
| 25 | + | self.dec_sp(); | |
| 26 | + | mem.write(self.sp, (val & 0xFF) as u8); // low | |
| 27 | + | } | |
| 28 | + | ||
| 29 | + | fn pop16(&mut self, mem: &mut Memory) -> u16 { | |
| 30 | + | let low = mem.read(self.sp) as u16; | |
| 31 | + | self.inc_sp(); | |
| 32 | + | let high = mem.read(self.sp) as u16; | |
| 33 | + | self.inc_sp(); | |
| 34 | + | ||
| 35 | + | (high << 8) | low | |
| 36 | + | } | |
| 37 | + | ||
| 22 | 38 | pub fn debug_instr(&self, mem: &Memory) { | |
| 23 | 39 | let opcode = mem.read(self.pc); | |
| 24 | 40 | ||
| @@ -53,6 +69,21 @@ impl CPU { | |||
| 53 | 69 | x if x == Instruction::CMP_RR as u8 => self.cmp_rr(mem), | |
| 54 | 70 | x if x == Instruction::MUL as u8 => self.mul(mem), | |
| 55 | 71 | x if x == Instruction::DIV as u8 => self.div(mem), | |
| 72 | + | x if x == Instruction::CALL as u8 => { | |
| 73 | + | let low = mem.read(self.pc) as u16; self.inc_pc(); | |
| 74 | + | let high = mem.read(self.pc) as u16; self.inc_pc(); | |
| 75 | + | let addr = (high << 8) | low; | |
| 76 | + | ||
| 77 | + | let return_addr = self.pc; | |
| 78 | + | ||
| 79 | + | self.push16(mem, return_addr); | |
| 80 | + | self.pc = addr; | |
| 81 | + | ||
| 82 | + | }, | |
| 83 | + | x if x == Instruction::RET as u8 => { | |
| 84 | + | let addr = self.pop16(mem); | |
| 85 | + | self.pc = addr; | |
| 86 | + | }, | |
| 56 | 87 | x if x == Instruction::HLT as u8 => self.halt(), | |
| 57 | 88 | _ => panic!("Unknown opcode {:02X}", opcode), | |
| 58 | 89 | } | |
| @@ -62,6 +93,17 @@ impl CPU { | |||
| 62 | 93 | self.pc += 1; | |
| 63 | 94 | } | |
| 64 | 95 | ||
| 96 | + | pub fn inc_sp(&mut self) { | |
| 97 | + | // self.sp += 1; | |
| 98 | + | self.sp = self.sp.wrapping_add(1); | |
| 99 | + | } | |
| 100 | + | ||
| 101 | + | pub fn dec_sp(&mut self) { | |
| 102 | + | // self.sp -= 1; | |
| 103 | + | self.sp = self.sp.wrapping_sub(1); | |
| 104 | + | } | |
| 105 | + | ||
| 106 | + | ||
| 65 | 107 | pub fn halt(&mut self) { | |
| 66 | 108 | self.halted = true; | |
| 67 | 109 | } | |
| @@ -14,6 +14,8 @@ pub enum Instruction { | |||
| 14 | 14 | CMP_RR = 0x09, | |
| 15 | 15 | MUL = 0x0C, | |
| 16 | 16 | DIV = 0x0D, | |
| 17 | + | CALL = 0x0E, | |
| 18 | + | RET = 0x0F, | |
| 17 | 19 | HLT = 0xFF, | |
| 18 | 20 | } | |
| 19 | 21 | ||
| @@ -29,7 +31,10 @@ impl Instruction { | |||
| 29 | 31 | 0x07 | 0x09 => "CMP", | |
| 30 | 32 | 0x0C => "MUL", | |
| 31 | 33 | 0x0D => "DIV", | |
| 34 | + | 0x0E => "CALL", | |
| 35 | + | 0x0F => "RET", | |
| 32 | 36 | 0xFF => "HLT", | |
| 37 | + | ||
| 33 | 38 | _ => "???", | |
| 34 | 39 | } | |
| 35 | 40 | } | |
| @@ -21,7 +21,7 @@ struct Args { | |||
| 21 | 21 | fn main() { | |
| 22 | 22 | let args = Args::parse(); | |
| 23 | 23 | ||
| 24 | − | let mut cpu = CPU::default(); | |
| 24 | + | let mut cpu = CPU {sp: 0xFFFE, ..Default::default( )}; | |
| 25 | 25 | let mut mem = Memory::new(); | |
| 26 | 26 | ||
| 27 | 27 | let asm = std::fs::read_to_string(args.filename).unwrap(); | |