bench51467ec78
add SYS instruction
+71 −20
5 files changed
- M README.md +14 −3
- A examples/syscall.asm +7 −0
- M src/assembler.rs +7 −0
- M src/cpu.rs +41 −17
- M src/instructions.rs +2 −0
| @@ -20,6 +20,7 @@ | |||
| 20 | 20 | | MUL | mul r1, r2 | | |
| 21 | 21 | | DIV | div r1, r2 | | |
| 22 | 22 | | CALL | call \<label\> | | |
| 23 | + | | SYS | sys \<syscall_no\> | | |
| 23 | 24 | | HLT (Halt) | hlt | | |
| 24 | 25 | ||
| 25 | 26 | ||
| @@ -33,6 +34,7 @@ | |||
| 33 | 34 | | PC | 16-bit | Program Counter | | |
| 34 | 35 | | SP | 16-bit | Stack pointer | | |
| 35 | 36 | ||
| 37 | + | ||
| 36 | 38 | ## Flags | |
| 37 | 39 | | Flag | Description | | |
| 38 | 40 | | ----- | ------------ | | |
| @@ -40,6 +42,14 @@ | |||
| 40 | 42 | | C | Carry/Borrow | | |
| 41 | 43 | ||
| 42 | 44 | ||
| 45 | + | ## Syscalls | |
| 46 | + | | Imm | Meaning | | |
| 47 | + | | --- | ------- | | |
| 48 | + | | 0 | Exit Program | | |
| 49 | + | | 1 | Print register A as integer | | |
| 50 | + | | 2 | Print register A as ASCII char | | |
| 51 | + | ||
| 52 | + | ||
| 43 | 53 | # Usage | |
| 44 | 54 | ```bash | |
| 45 | 55 | cargo run -- --f <examples/filename.asc> | |
| @@ -49,11 +59,12 @@ cargo run -- --f <examples/filename.asc> | |||
| 49 | 59 | - [x] Assembler | |
| 50 | 60 | - [x] Lexer/Tokenizer | |
| 51 | 61 | - [x] Add label support (supporting JMP/JZ/JNZ) | |
| 52 | − | - [ ] Add instructions | |
| 62 | + | - [x] Add instructions | |
| 53 | 63 | - [x] CMP | |
| 54 | 64 | - [x] MUL | |
| 55 | 65 | - [x] DIV | |
| 56 | 66 | - [x] CALL | |
| 57 | 67 | - [x] RET | |
| 58 | − | - [ ] Error handling | |
| 59 | − | - [ ] Build Debugger | |
| 68 | + | - [x] SYS | |
| 69 | + | - [ ] Better Error handling | |
| 70 | + | - [ ] TUI Debugger | |
| @@ -0,0 +1,7 @@ | |||
| 1 | + | mov a, 72 ; 'H' | |
| 2 | + | sys 2 | |
| 3 | + | mov a, 105 ; 'i' | |
| 4 | + | sys 2 | |
| 5 | + | mov a, 10 ; '\n' | |
| 6 | + | sys 2 | |
| 7 | + | sys 0 | |
| @@ -26,6 +26,7 @@ fn is_reg(s: &str) -> bool { | |||
| 26 | 26 | fn instr_size(tokens: &[String]) -> u16 { | |
| 27 | 27 | match tokens[0].as_str() { | |
| 28 | 28 | "mov" | "add" | "sub" | "jmp" | "jz" | "jnz" | "cmp" | "mul" | "div" | "call" => 3, | |
| 29 | + | "sys" => 2, | |
| 29 | 30 | "hlt" | "ret" => 1, | |
| 30 | 31 | _ => panic!("Unknown instruction {}", tokens[0]), | |
| 31 | 32 | } | |
| @@ -190,6 +191,12 @@ pub fn assembler(source: &str) -> Vec<u8> { | |||
| 190 | 191 | bytes.push(Instruction::HLT as u8); | |
| 191 | 192 | } | |
| 192 | 193 | ||
| 194 | + | "sys" => { | |
| 195 | + | let imm = tokens[1].parse().unwrap(); | |
| 196 | + | bytes.push(Instruction::SYS as u8); | |
| 197 | + | bytes.push(imm); | |
| 198 | + | } | |
| 199 | + | ||
| 193 | 200 | _ => panic!("Line {}: unknown instruction", line_no + 1), | |
| 194 | 201 | } | |
| 195 | 202 | } | |
| @@ -69,21 +69,9 @@ impl CPU { | |||
| 69 | 69 | x if x == Instruction::CMP_RR as u8 => self.cmp_rr(mem), | |
| 70 | 70 | x if x == Instruction::MUL as u8 => self.mul(mem), | |
| 71 | 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 | − | }, | |
| 72 | + | x if x == Instruction::CALL as u8 => self.call(mem), | |
| 73 | + | x if x == Instruction::RET as u8 => self.ret(mem), | |
| 74 | + | x if x == Instruction::SYS as u8 => self.syscall(mem), | |
| 87 | 75 | x if x == Instruction::HLT as u8 => self.halt(), | |
| 88 | 76 | _ => panic!("Unknown opcode {:02X}", opcode), | |
| 89 | 77 | } | |
| @@ -94,12 +82,10 @@ impl CPU { | |||
| 94 | 82 | } | |
| 95 | 83 | ||
| 96 | 84 | pub fn inc_sp(&mut self) { | |
| 97 | − | // self.sp += 1; | |
| 98 | 85 | self.sp = self.sp.wrapping_add(1); | |
| 99 | 86 | } | |
| 100 | 87 | ||
| 101 | 88 | pub fn dec_sp(&mut self) { | |
| 102 | − | // self.sp -= 1; | |
| 103 | 89 | self.sp = self.sp.wrapping_sub(1); | |
| 104 | 90 | } | |
| 105 | 91 | ||
| @@ -379,6 +365,44 @@ impl CPU { | |||
| 379 | 365 | // carry unchanged | |
| 380 | 366 | } | |
| 381 | 367 | ||
| 368 | + | pub fn call(&mut self, mem: &mut Memory ) { | |
| 369 | + | let low = mem.read(self.pc) as u16; self.inc_pc(); | |
| 370 | + | let high = mem.read(self.pc) as u16; self.inc_pc(); | |
| 371 | + | let addr = (high << 8) | low; | |
| 372 | + | ||
| 373 | + | let return_addr = self.pc; | |
| 374 | + | ||
| 375 | + | self.push16(mem, return_addr); | |
| 376 | + | self.pc = addr; | |
| 377 | + | ||
| 378 | + | } | |
| 379 | + | ||
| 380 | + | pub fn ret(&mut self, mem: &mut Memory) { | |
| 381 | + | let addr = self.pop16(mem); | |
| 382 | + | self.pc = addr; | |
| 383 | + | } | |
| 384 | + | ||
| 385 | + | ||
| 386 | + | pub fn syscall(&mut self, mem: &Memory) { | |
| 387 | + | let num = mem.read(self.pc); | |
| 388 | + | self.pc = self.pc.wrapping_add(1); | |
| 389 | + | match num { | |
| 390 | + | 0 => { | |
| 391 | + | // exit | |
| 392 | + | self.halted = true; | |
| 393 | + | } | |
| 394 | + | 1 => { | |
| 395 | + | // print A as number | |
| 396 | + | println!("{}", self.a); | |
| 397 | + | } | |
| 398 | + | 2 => { | |
| 399 | + | // print A as ASCII char | |
| 400 | + | print!("{}", self.a as char); | |
| 401 | + | } | |
| 402 | + | _ => panic!("Unknown syscall {}", num), | |
| 403 | + | } | |
| 404 | + | } | |
| 405 | + | ||
| 382 | 406 | fn get_reg(&self, r: u8) -> u8 { | |
| 383 | 407 | match r { | |
| 384 | 408 | 0 => self.a, | |
| @@ -16,6 +16,7 @@ pub enum Instruction { | |||
| 16 | 16 | DIV = 0x0D, | |
| 17 | 17 | CALL = 0x0E, | |
| 18 | 18 | RET = 0x0F, | |
| 19 | + | SYS = 0x10, | |
| 19 | 20 | HLT = 0xFF, | |
| 20 | 21 | } | |
| 21 | 22 | ||
| @@ -33,6 +34,7 @@ impl Instruction { | |||
| 33 | 34 | 0x0D => "DIV", | |
| 34 | 35 | 0x0E => "CALL", | |
| 35 | 36 | 0x0F => "RET", | |
| 37 | + | 0x10 => "SYS", | |
| 36 | 38 | 0xFF => "HLT", | |
| 37 | 39 | ||
| 38 | 40 | _ => "???", | |