add MUL & DIV

This commit is contained in:
krolxon 2026-01-08 18:47:07 +05:30
parent 68d85406ef
commit 3372e774e9
6 changed files with 74 additions and 3 deletions

View File

@ -47,6 +47,8 @@ cargo run -- --f <examples/filename.asc>
- [x] Add label support (supporting JMP/JZ/JNZ) - [x] Add label support (supporting JMP/JZ/JNZ)
- [ ] Add instructions - [ ] Add instructions
- [x] CMP - [x] CMP
- [x] MUL
- [x] DIV
- [ ] CALL - [ ] CALL
- [ ] RET - [ ] RET
- [ ] Error handling - [ ] Error handling

4
examples/div.asm Normal file
View File

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

4
examples/mul.asm Normal file
View File

@ -0,0 +1,4 @@
mov a, 99
mov b, 99
mul a, b
hlt

View File

@ -25,7 +25,7 @@ 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" => 3, "mov" | "add" | "sub" | "jmp" | "jz" | "jnz" | "cmp" | "mul" | "div" => 3,
"hlt" => 1, "hlt" => 1,
_ => panic!("Unknown instruction {}", tokens[0]), _ => panic!("Unknown instruction {}", tokens[0]),
} }
@ -153,6 +153,25 @@ pub fn assembler(source: &str) -> Vec<u8> {
} }
} }
"mul" => {
let r1 = parse_reg(&tokens[1]);
let r2 = parse_reg(&tokens[2]);
bytes.push(Instruction::MUL as u8);
bytes.push(r1);
bytes.push(r2);
}
"div" => {
let r1 = parse_reg(&tokens[1]);
let r2 = parse_reg(&tokens[2]);
bytes.push(Instruction::DIV as u8);
bytes.push(r1);
bytes.push(r2);
}
"hlt" => { "hlt" => {
bytes.push(Instruction::HLT as u8); bytes.push(Instruction::HLT as u8);
} }

View File

@ -51,6 +51,8 @@ impl CPU {
x if x == Instruction::JNZ as u8 => self.jnz(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_RI as u8 => self.cmp_ri(mem),
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::DIV as u8 => self.div(mem),
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),
} }
@ -298,6 +300,42 @@ impl CPU {
self.carry = borrow; self.carry = borrow;
} }
pub fn mul(&mut self, mem: &Memory) {
let dest = mem.read(self.pc); self.inc_pc();
let src = mem.read(self.pc); self.inc_pc();
let lhs = self.get_reg(dest);
let rhs = self.get_reg(src);
let result16 = (lhs as u16) * (rhs as u16);
let result8 = (result16 & 0xFF) as u8;
self.set_reg(dest, result8);
self.zero = result8 == 0;
self.carry = result16 > 0xFF;
}
pub fn div(&mut self, mem: &Memory) {
let dest = mem.read(self.pc); self.inc_pc();
let src = mem.read(self.pc); self.inc_pc();
let lhs = self.get_reg(dest);
let rhs = self.get_reg(src);
if rhs == 0 {
panic!("Division by zero");
// OR: set halted = true
// OR: define a syscall/exception later
}
let result = lhs / rhs;
self.set_reg(dest, result);
self.zero = result == 0;
// carry unchanged
}
fn get_reg(&self, r: u8) -> u8 { fn get_reg(&self, r: u8) -> u8 {
match r { match r {
@ -305,7 +343,7 @@ impl CPU {
1 => self.b, 1 => self.b,
2 => self.c, 2 => self.c,
3 => self.d, 3 => self.d,
_ => 0, _ => panic!("Invalid Register"),
} }
} }
@ -315,7 +353,7 @@ impl CPU {
1 => self.b = val, 1 => self.b = val,
2 => self.c = val, 2 => self.c = val,
3 => self.d = val, 3 => self.d = val,
_ => {}, _ => panic!("Invalid register"),
} }
} }

View File

@ -12,6 +12,8 @@ pub enum Instruction {
JNZ = 0x06, JNZ = 0x06,
CMP_RI = 0x07, CMP_RI = 0x07,
CMP_RR = 0x09, CMP_RR = 0x09,
MUL = 0x0C,
DIV = 0x0D,
HLT = 0xFF, HLT = 0xFF,
} }
@ -25,6 +27,8 @@ impl Instruction {
0x05 => "JZ", 0x05 => "JZ",
0x06 => "JNZ", 0x06 => "JNZ",
0x07 | 0x09 => "CMP", 0x07 | 0x09 => "CMP",
0x0C => "MUL",
0x0D => "DIV",
0xFF => "HLT", 0xFF => "HLT",
_ => "???", _ => "???",
} }