add CALL, RET

This commit is contained in:
krolxon 2026-01-08 19:02:18 +05:30
parent 3372e774e9
commit 133f6f748d
6 changed files with 72 additions and 4 deletions

7
examples/call.asm Normal file
View File

@ -0,0 +1,7 @@
mov a, 2
call square
hlt
square:
mul a, a
ret

View File

@ -1,4 +1,4 @@
mov a, 10 mov a, 10
mov b, 2 mov b, 10
div a, b div a, b
hlt hlt

View File

@ -25,8 +25,8 @@ fn is_reg(s: &str) -> bool {
fn instr_size(tokens: &[String]) -> u16 { fn instr_size(tokens: &[String]) -> u16 {
match tokens[0].as_str() { match tokens[0].as_str() {
"mov" | "add" | "sub" | "jmp" | "jz" | "jnz" | "cmp" | "mul" | "div" => 3, "mov" | "add" | "sub" | "jmp" | "jz" | "jnz" | "cmp" | "mul" | "div" | "call" => 3,
"hlt" => 1, "hlt" | "ret" => 1,
_ => panic!("Unknown instruction {}", tokens[0]), _ => panic!("Unknown instruction {}", tokens[0]),
} }
} }
@ -172,6 +172,20 @@ pub fn assembler(source: &str) -> Vec<u8> {
bytes.push(r2); bytes.push(r2);
} }
"call" => {
let addr = *symbols
.get(&tokens[1])
.expect("Unknown label");
bytes.push(Instruction::CALL as u8);
bytes.push((addr & 0xFF) as u8); // low
bytes.push((addr >> 8) as u8); // high
}
"ret" => {
bytes.push(Instruction::RET as u8);
}
"hlt" => { "hlt" => {
bytes.push(Instruction::HLT as u8); bytes.push(Instruction::HLT as u8);
} }

View File

@ -19,6 +19,22 @@ pub struct CPU {
} }
impl CPU { impl CPU {
fn push16(&mut self, mem: &mut Memory, val: u16) {
self.dec_sp();
mem.write(self.sp, (val >> 8) as u8); // high
self.dec_sp();
mem.write(self.sp, (val & 0xFF) as u8); // low
}
fn pop16(&mut self, mem: &mut Memory) -> u16 {
let low = mem.read(self.sp) as u16;
self.inc_sp();
let high = mem.read(self.sp) as u16;
self.inc_sp();
(high << 8) | low
}
pub fn debug_instr(&self, mem: &Memory) { pub fn debug_instr(&self, mem: &Memory) {
let opcode = mem.read(self.pc); let opcode = mem.read(self.pc);
@ -53,6 +69,21 @@ impl CPU {
x if x == Instruction::CMP_RR as u8 => self.cmp_rr(mem), x if x == Instruction::CMP_RR as u8 => self.cmp_rr(mem),
x if x == Instruction::MUL as u8 => self.mul(mem), x if x == Instruction::MUL as u8 => self.mul(mem),
x if x == Instruction::DIV as u8 => self.div(mem), x if x == Instruction::DIV as u8 => self.div(mem),
x if x == Instruction::CALL as u8 => {
let low = mem.read(self.pc) as u16; self.inc_pc();
let high = mem.read(self.pc) as u16; self.inc_pc();
let addr = (high << 8) | low;
let return_addr = self.pc;
self.push16(mem, return_addr);
self.pc = addr;
},
x if x == Instruction::RET as u8 => {
let addr = self.pop16(mem);
self.pc = addr;
},
x if x == Instruction::HLT as u8 => self.halt(), x if x == Instruction::HLT as u8 => self.halt(),
_ => panic!("Unknown opcode {:02X}", opcode), _ => panic!("Unknown opcode {:02X}", opcode),
} }
@ -62,6 +93,17 @@ impl CPU {
self.pc += 1; self.pc += 1;
} }
pub fn inc_sp(&mut self) {
// self.sp += 1;
self.sp = self.sp.wrapping_add(1);
}
pub fn dec_sp(&mut self) {
// self.sp -= 1;
self.sp = self.sp.wrapping_sub(1);
}
pub fn halt(&mut self) { pub fn halt(&mut self) {
self.halted = true; self.halted = true;
} }

View File

@ -14,6 +14,8 @@ pub enum Instruction {
CMP_RR = 0x09, CMP_RR = 0x09,
MUL = 0x0C, MUL = 0x0C,
DIV = 0x0D, DIV = 0x0D,
CALL = 0x0E,
RET = 0x0F,
HLT = 0xFF, HLT = 0xFF,
} }
@ -29,7 +31,10 @@ impl Instruction {
0x07 | 0x09 => "CMP", 0x07 | 0x09 => "CMP",
0x0C => "MUL", 0x0C => "MUL",
0x0D => "DIV", 0x0D => "DIV",
0x0E => "CALL",
0x0F => "RET",
0xFF => "HLT", 0xFF => "HLT",
_ => "???", _ => "???",
} }
} }

View File

@ -21,7 +21,7 @@ struct Args {
fn main() { fn main() {
let args = Args::parse(); let args = Args::parse();
let mut cpu = CPU::default(); let mut cpu = CPU {sp: 0xFFFE, ..Default::default( )};
let mut mem = Memory::new(); let mut mem = Memory::new();
let asm = std::fs::read_to_string(args.filename).unwrap(); let asm = std::fs::read_to_string(args.filename).unwrap();