Krolyxon
Commit 4166b0e

Branches

Tags

Refs →

bench514166b0e

add cmp instruction, add reg, reg, and reg, imm variations

Author
krolxon
Date
2026-01-05 13:15 +0530
Parent
57bbca6
Commit
4166b0e5430bd723e31c1198b8d940381aded499

+125 −23

7 files changed

  1. M README.md +3 −2
  2. A examples/cmp.asm +4 −0
  3. A examples/mov.asm +5 −0
  4. D examples/subtraction.asm +0 −4
  5. M src/assembler.rs +38 −12
  6. M src/cpu.rs +69 −3
  7. M src/instructions.rs +6 −2
M README.md View
@@ -10,12 +10,13 @@
1010
1111 | Instruction | Syntax |
1212 | ----------- | ------------ |
13−| MOV | mov reg, imm |
13+| MOV | mov reg, imm OR mov reg, reg |
1414 | ADD | add r1, r2 |
1515 | SUB | sub r1, r2 |
1616 | JMP | jmp addr |
1717 | JZ | jz addr |
1818 | JNZ | jnz addr |
19+| CMP | cmp reg, imm OR cmp reg, reg |
1920 | HLT (Halt) | hlt |
2021
2122
@@ -46,7 +47,7 @@ cargo run -- --f <examples/filename.asc>
4647 - [x] Lexer/Tokenizer
4748 - [x] Add label support (supporting JMP/JZ/JNZ)
4849 - [ ] Add instructions
49− - [ ] CMP
50+ - [x] CMP
5051 - [ ] CALL
5152 - [ ] RET
5253 - [ ] Error handling
A examples/cmp.asm View
@@ -0,0 +1,4 @@
1+mov a, 10
2+mov b, 10
3+cmp a, b
4+hlt
A examples/mov.asm View
@@ -0,0 +1,5 @@
1+mov a, 10
2+mov b, a
3+cmp a, b
4+cmp a, 10
5+hlt
D examples/subtraction.asm View
@@ -1,4 +0,0 @@
1−mov a, 15
2−mov b, 15
3−sub a, b
4−hlt
M src/assembler.rs View
@@ -18,16 +18,21 @@ fn parse_reg(s: &str) -> u8 {
1818 }
1919 }
2020
21−fn instr_size(tokens: &[String]) -> u16 {
21+fn is_reg(s: &str) -> bool {
22+ match s {
23+ "a" | "b" | "c" | "d" => true,
24+ _ => false,
25+ }
26+}
27+
28+fn instr_size(tokens: &[String]) -> u16 {
2229 match tokens[0].as_str() {
23− "mov" | "add" | "sub" | "jmp" | "jz" | "jnz" => 3,
30+ "mov" | "add" | "sub" | "jmp" | "jz" | "jnz" | "cmp" => 3,
2431 "hlt" => 1,
25− _ => panic!("Unknown instruction {}", tokens[0])
26−
32+ _ => panic!("Unknown instruction {}", tokens[0]),
2733 }
2834 }
2935
30−
3136 fn first_pass(source: &str) -> HashMap<String, u16> {
3237 let mut symbols = HashMap::new();
3338 let mut addr: u16 = 0;
@@ -72,11 +77,17 @@ pub fn assembler(source: &str) -> Vec<u8> {
7277 "mov" => {
7378 // mov reg, imm
7479 let reg = parse_reg(&tokens[1]);
75− let imm: u8 = tokens[2].parse().unwrap();
76−
77− bytes.push(Instruction::MOV as u8);
78− bytes.push(reg);
79− bytes.push(imm);
80+ if is_reg(&tokens[2]) {
81+ let r2 = parse_reg(&tokens[2]);
82+ bytes.push(Instruction::MOV_RR as u8);
83+ bytes.push(reg);
84+ bytes.push(r2);
85+ } else {
86+ let imm: u8 = tokens[2].parse().unwrap();
87+ bytes.push(Instruction::MOV_RI as u8);
88+ bytes.push(reg);
89+ bytes.push(imm);
90+ }
8091 }
8192
8293 "add" => {
@@ -91,8 +102,8 @@ pub fn assembler(source: &str) -> Vec<u8> {
91102
92103 "sub" => {
93104 // sub a, b
94− let r1 = parse_reg(&tokens[1]);
95105 let r2 = parse_reg(&tokens[2]);
106+ let r1 = parse_reg(&tokens[1]);
96107
97108 bytes.push(Instruction::SUB as u8);
98109 bytes.push(r1);
@@ -104,7 +115,7 @@ pub fn assembler(source: &str) -> Vec<u8> {
104115 "jmp" => Instruction::JMP,
105116 "jz" => Instruction::JZ,
106117 "jnz" => Instruction::JNZ,
107− _ => unreachable!()
118+ _ => unreachable!(),
108119 };
109120
110121 let label = &tokens[1];
@@ -115,6 +126,21 @@ pub fn assembler(source: &str) -> Vec<u8> {
115126 bytes.push((addr >> 8) as u8); // high
116127 }
117128
129+ "cmp" => {
130+ let r1 = parse_reg(&tokens[1]);
131+ if tokens[2].chars().all(|c| c.is_ascii_digit()) {
132+ let imm: u8 = tokens[2].parse().unwrap();
133+ bytes.push(Instruction::CMP_RI as u8);
134+ bytes.push(r1);
135+ bytes.push(imm);
136+ } else {
137+ let r2 = parse_reg(&tokens[2]);
138+ bytes.push(Instruction::CMP_RR as u8);
139+ bytes.push(r1);
140+ bytes.push(r2);
141+ }
142+ }
143+
118144 "hlt" => {
119145 bytes.push(Instruction::HLT as u8);
120146 }
M src/cpu.rs View
@@ -19,7 +19,6 @@ pub struct CPU {
1919 }
2020
2121 impl CPU {
22−
2322 pub fn debug_instr(&self, mem: &Memory) {
2423 let opcode = mem.read(self.pc);
2524
@@ -41,12 +40,15 @@ impl CPU {
4140 self.inc_pc();
4241
4342 match opcode {
44− x if x == Instruction::MOV as u8 => self.mov(mem),
43+ x if x == Instruction::MOV_RI as u8 => self.mov_ri(mem),
44+ x if x == Instruction::MOV_RR as u8 => self.mov_rr(mem),
4545 x if x == Instruction::ADD as u8 => self.add(mem),
4646 x if x == Instruction::SUB as u8 => self.sub(mem),
4747 x if x == Instruction::JMP as u8 => self.jmp(mem),
4848 x if x == Instruction::JZ as u8 => self.jz(mem),
4949 x if x == Instruction::JNZ as u8 => self.jnz(mem),
50+ x if x == Instruction::CMP_RI as u8 => self.cmp_ri(mem),
51+ x if x == Instruction::CMP_RR as u8 => self.cmp_rr(mem),
5052 x if x == Instruction::HLT as u8 => self.halt(),
5153 _ => panic!("Unknown opcode {:02X}", opcode),
5254 }
@@ -60,7 +62,7 @@ impl CPU {
6062 self.halted = true;
6163 }
6264
63− pub fn mov(&mut self, mem: &Memory) {
65+ pub fn mov_ri(&mut self, mem: &Memory) {
6466 let reg = mem.read(self.pc);
6567 self.inc_pc();
6668 let val = mem.read(self.pc);
@@ -77,6 +79,19 @@ impl CPU {
7779 self.zero = val == 0;
7880 }
7981
82+ pub fn mov_rr(&mut self, mem: &Memory) {
83+ let dest = mem.read(self.pc);
84+ self.inc_pc();
85+ let src= mem.read(self.pc);
86+ self.inc_pc();
87+
88+ let val = self.get_reg(src);
89+ self.set_reg(dest, val);
90+
91+ self.zero = val == 0;
92+ }
93+
94+
8095 pub fn add(&mut self, mem: &Memory) {
8196 let dest = mem.read(self.pc);
8297 self.pc += 1;
@@ -197,4 +212,55 @@ impl CPU {
197212 self.pc = addrs;
198213 }
199214 }
215+
216+ pub fn cmp_rr(&mut self, mem: &Memory) {
217+ let r1 = mem.read(self.pc);
218+ self.inc_pc();
219+ let r2 = mem.read(self.pc);
220+ self.inc_pc();
221+
222+ let v1 = self.get_reg(r1);
223+ let v2 = self.get_reg(r2);
224+
225+ let (result, borrow) = v1.overflowing_sub(v2);
226+
227+ self.zero = result == 0;
228+ self.carry = borrow;
229+ }
230+
231+ pub fn cmp_ri(&mut self, mem: &Memory) {
232+ let r1 = mem.read(self.pc);
233+ self.inc_pc();
234+ let r2 = mem.read(self.pc);
235+ self.inc_pc();
236+
237+ let v1 = self.get_reg(r1);
238+
239+ let (result, borrow) = v1.overflowing_sub(r2);
240+
241+ self.zero = result == 0;
242+ self.carry = borrow;
243+ }
244+
245+
246+ fn get_reg(&self, r: u8) -> u8 {
247+ match r {
248+ 0 => self.a,
249+ 1 => self.b,
250+ 2 => self.c,
251+ 3 => self.d,
252+ _ => 0,
253+ }
254+ }
255+
256+ fn set_reg(&mut self, dest: u8, val: u8) {
257+ match dest {
258+ 0 => self.a = val,
259+ 1 => self.b = val,
260+ 2 => self.c = val,
261+ 3 => self.d = val,
262+ _ => {},
263+ }
264+ }
265+
200266 }
M src/instructions.rs View
@@ -1,23 +1,27 @@
11 #[repr(u8)]
22 pub enum Instruction {
3− MOV = 0x01,
3+ MOV_RI = 0x01,
4+ MOV_RR = 0x08,
45 ADD = 0x02,
56 SUB = 0x03,
67 JMP = 0x04,
78 JZ = 0x05,
89 JNZ = 0x06,
10+ CMP_RI = 0x07,
11+ CMP_RR = 0x09,
912 HLT = 0xFF,
1013 }
1114
1215 impl Instruction {
1316 pub fn opcode_name(op: u8) -> &'static str{
1417 match op {
15− 0x01 => "MOV",
18+ 0x01 | 0x08 => "MOV",
1619 0x02 => "ADD",
1720 0x03 => "SUB",
1821 0x04 => "JMP",
1922 0x05 => "JZ",
2023 0x06 => "JNZ",
24+ 0x07 | 0x09 => "CMP",
2125 0xFF => "HLT",
2226 _ => "???",
2327 }