aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--examples/div.asm4
-rw-r--r--examples/mul.asm4
-rw-r--r--src/assembler.rs21
-rw-r--r--src/cpu.rs42
-rw-r--r--src/instructions.rs4
6 files changed, 74 insertions, 3 deletions
diff --git a/README.md b/README.md
index 0fda2d6..fd391d2 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,8 @@ cargo run -- --f <examples/filename.asc>
- [x] Add label support (supporting JMP/JZ/JNZ)
- [ ] Add instructions
- [x] CMP
+ - [x] MUL
+ - [x] DIV
- [ ] CALL
- [ ] RET
- [ ] Error handling
diff --git a/examples/div.asm b/examples/div.asm
new file mode 100644
index 0000000..f07766c
--- /dev/null
+++ b/examples/div.asm
@@ -0,0 +1,4 @@
+mov a, 10
+mov b, 2
+div a, b
+hlt
diff --git a/examples/mul.asm b/examples/mul.asm
new file mode 100644
index 0000000..a818dfd
--- /dev/null
+++ b/examples/mul.asm
@@ -0,0 +1,4 @@
+mov a, 99
+mov b, 99
+mul a, b
+hlt
diff --git a/src/assembler.rs b/src/assembler.rs
index e7aa305..1b9c85b 100644
--- a/src/assembler.rs
+++ b/src/assembler.rs
@@ -25,7 +25,7 @@ fn is_reg(s: &str) -> bool {
fn instr_size(tokens: &[String]) -> u16 {
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,
_ => 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" => {
bytes.push(Instruction::HLT as u8);
}
diff --git a/src/cpu.rs b/src/cpu.rs
index d0365ba..9416783 100644
--- a/src/cpu.rs
+++ b/src/cpu.rs
@@ -51,6 +51,8 @@ impl CPU {
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::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(),
_ => panic!("Unknown opcode {:02X}", opcode),
}
@@ -298,6 +300,42 @@ impl CPU {
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 {
match r {
@@ -305,7 +343,7 @@ impl CPU {
1 => self.b,
2 => self.c,
3 => self.d,
- _ => 0,
+ _ => panic!("Invalid Register"),
}
}
@@ -315,7 +353,7 @@ impl CPU {
1 => self.b = val,
2 => self.c = val,
3 => self.d = val,
- _ => {},
+ _ => panic!("Invalid register"),
}
}
diff --git a/src/instructions.rs b/src/instructions.rs
index bfc4fc6..9f81b9a 100644
--- a/src/instructions.rs
+++ b/src/instructions.rs
@@ -12,6 +12,8 @@ pub enum Instruction {
JNZ = 0x06,
CMP_RI = 0x07,
CMP_RR = 0x09,
+ MUL = 0x0C,
+ DIV = 0x0D,
HLT = 0xFF,
}
@@ -25,6 +27,8 @@ impl Instruction {
0x05 => "JZ",
0x06 => "JNZ",
0x07 | 0x09 => "CMP",
+ 0x0C => "MUL",
+ 0x0D => "DIV",
0xFF => "HLT",
_ => "???",
}