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

This commit is contained in:
krolxon 2026-01-05 13:15:01 +05:30
parent 57bbca6cb2
commit 4166b0e543
7 changed files with 126 additions and 24 deletions

View File

@ -10,12 +10,13 @@
| Instruction | Syntax | | Instruction | Syntax |
| ----------- | ------------ | | ----------- | ------------ |
| MOV | mov reg, imm | | MOV | mov reg, imm OR mov reg, reg |
| ADD | add r1, r2 | | ADD | add r1, r2 |
| SUB | sub r1, r2 | | SUB | sub r1, r2 |
| JMP | jmp addr | | JMP | jmp addr |
| JZ | jz addr | | JZ | jz addr |
| JNZ | jnz addr | | JNZ | jnz addr |
| CMP | cmp reg, imm OR cmp reg, reg |
| HLT (Halt) | hlt | | HLT (Halt) | hlt |
@ -46,7 +47,7 @@ cargo run -- --f <examples/filename.asc>
- [x] Lexer/Tokenizer - [x] Lexer/Tokenizer
- [x] Add label support (supporting JMP/JZ/JNZ) - [x] Add label support (supporting JMP/JZ/JNZ)
- [ ] Add instructions - [ ] Add instructions
- [ ] CMP - [x] CMP
- [ ] CALL - [ ] CALL
- [ ] RET - [ ] RET
- [ ] Error handling - [ ] Error handling

4
examples/cmp.asm Normal file
View File

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

5
examples/mov.asm Normal file
View File

@ -0,0 +1,5 @@
mov a, 10
mov b, a
cmp a, b
cmp a, 10
hlt

View File

@ -1,4 +0,0 @@
mov a, 15
mov b, 15
sub a, b
hlt

View File

@ -18,15 +18,20 @@ fn parse_reg(s: &str) -> u8 {
} }
} }
fn instr_size(tokens: &[String]) -> u16 { fn is_reg(s: &str) -> bool {
match tokens[0].as_str() { match s {
"mov" | "add" | "sub" | "jmp" | "jz" | "jnz" => 3, "a" | "b" | "c" | "d" => true,
"hlt" => 1, _ => false,
_ => panic!("Unknown instruction {}", tokens[0])
} }
} }
fn instr_size(tokens: &[String]) -> u16 {
match tokens[0].as_str() {
"mov" | "add" | "sub" | "jmp" | "jz" | "jnz" | "cmp" => 3,
"hlt" => 1,
_ => panic!("Unknown instruction {}", tokens[0]),
}
}
fn first_pass(source: &str) -> HashMap<String, u16> { fn first_pass(source: &str) -> HashMap<String, u16> {
let mut symbols = HashMap::new(); let mut symbols = HashMap::new();
@ -72,12 +77,18 @@ pub fn assembler(source: &str) -> Vec<u8> {
"mov" => { "mov" => {
// mov reg, imm // mov reg, imm
let reg = parse_reg(&tokens[1]); let reg = parse_reg(&tokens[1]);
if is_reg(&tokens[2]) {
let r2 = parse_reg(&tokens[2]);
bytes.push(Instruction::MOV_RR as u8);
bytes.push(reg);
bytes.push(r2);
} else {
let imm: u8 = tokens[2].parse().unwrap(); let imm: u8 = tokens[2].parse().unwrap();
bytes.push(Instruction::MOV_RI as u8);
bytes.push(Instruction::MOV as u8);
bytes.push(reg); bytes.push(reg);
bytes.push(imm); bytes.push(imm);
} }
}
"add" => { "add" => {
// add a, b // add a, b
@ -91,8 +102,8 @@ pub fn assembler(source: &str) -> Vec<u8> {
"sub" => { "sub" => {
// sub a, b // sub a, b
let r1 = parse_reg(&tokens[1]);
let r2 = parse_reg(&tokens[2]); let r2 = parse_reg(&tokens[2]);
let r1 = parse_reg(&tokens[1]);
bytes.push(Instruction::SUB as u8); bytes.push(Instruction::SUB as u8);
bytes.push(r1); bytes.push(r1);
@ -104,7 +115,7 @@ pub fn assembler(source: &str) -> Vec<u8> {
"jmp" => Instruction::JMP, "jmp" => Instruction::JMP,
"jz" => Instruction::JZ, "jz" => Instruction::JZ,
"jnz" => Instruction::JNZ, "jnz" => Instruction::JNZ,
_ => unreachable!() _ => unreachable!(),
}; };
let label = &tokens[1]; let label = &tokens[1];
@ -115,6 +126,21 @@ pub fn assembler(source: &str) -> Vec<u8> {
bytes.push((addr >> 8) as u8); // high bytes.push((addr >> 8) as u8); // high
} }
"cmp" => {
let r1 = parse_reg(&tokens[1]);
if tokens[2].chars().all(|c| c.is_ascii_digit()) {
let imm: u8 = tokens[2].parse().unwrap();
bytes.push(Instruction::CMP_RI as u8);
bytes.push(r1);
bytes.push(imm);
} else {
let r2 = parse_reg(&tokens[2]);
bytes.push(Instruction::CMP_RR as u8);
bytes.push(r1);
bytes.push(r2);
}
}
"hlt" => { "hlt" => {
bytes.push(Instruction::HLT as u8); bytes.push(Instruction::HLT as u8);
} }

View File

@ -19,7 +19,6 @@ pub struct CPU {
} }
impl CPU { impl CPU {
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);
@ -41,12 +40,15 @@ impl CPU {
self.inc_pc(); self.inc_pc();
match opcode { match opcode {
x if x == Instruction::MOV as u8 => self.mov(mem), x if x == Instruction::MOV_RI as u8 => self.mov_ri(mem),
x if x == Instruction::MOV_RR as u8 => self.mov_rr(mem),
x if x == Instruction::ADD as u8 => self.add(mem), x if x == Instruction::ADD as u8 => self.add(mem),
x if x == Instruction::SUB as u8 => self.sub(mem), x if x == Instruction::SUB as u8 => self.sub(mem),
x if x == Instruction::JMP as u8 => self.jmp(mem), x if x == Instruction::JMP as u8 => self.jmp(mem),
x if x == Instruction::JZ as u8 => self.jz(mem), x if x == Instruction::JZ as u8 => self.jz(mem),
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_RR as u8 => self.cmp_rr(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),
} }
@ -60,7 +62,7 @@ impl CPU {
self.halted = true; self.halted = true;
} }
pub fn mov(&mut self, mem: &Memory) { pub fn mov_ri(&mut self, mem: &Memory) {
let reg = mem.read(self.pc); let reg = mem.read(self.pc);
self.inc_pc(); self.inc_pc();
let val = mem.read(self.pc); let val = mem.read(self.pc);
@ -77,6 +79,19 @@ impl CPU {
self.zero = val == 0; self.zero = val == 0;
} }
pub fn mov_rr(&mut self, mem: &Memory) {
let dest = mem.read(self.pc);
self.inc_pc();
let src= mem.read(self.pc);
self.inc_pc();
let val = self.get_reg(src);
self.set_reg(dest, val);
self.zero = val == 0;
}
pub fn add(&mut self, mem: &Memory) { pub fn add(&mut self, mem: &Memory) {
let dest = mem.read(self.pc); let dest = mem.read(self.pc);
self.pc += 1; self.pc += 1;
@ -197,4 +212,55 @@ impl CPU {
self.pc = addrs; self.pc = addrs;
} }
} }
pub fn cmp_rr(&mut self, mem: &Memory) {
let r1 = mem.read(self.pc);
self.inc_pc();
let r2 = mem.read(self.pc);
self.inc_pc();
let v1 = self.get_reg(r1);
let v2 = self.get_reg(r2);
let (result, borrow) = v1.overflowing_sub(v2);
self.zero = result == 0;
self.carry = borrow;
}
pub fn cmp_ri(&mut self, mem: &Memory) {
let r1 = mem.read(self.pc);
self.inc_pc();
let r2 = mem.read(self.pc);
self.inc_pc();
let v1 = self.get_reg(r1);
let (result, borrow) = v1.overflowing_sub(r2);
self.zero = result == 0;
self.carry = borrow;
}
fn get_reg(&self, r: u8) -> u8 {
match r {
0 => self.a,
1 => self.b,
2 => self.c,
3 => self.d,
_ => 0,
}
}
fn set_reg(&mut self, dest: u8, val: u8) {
match dest {
0 => self.a = val,
1 => self.b = val,
2 => self.c = val,
3 => self.d = val,
_ => {},
}
}
} }

View File

@ -1,23 +1,27 @@
#[repr(u8)] #[repr(u8)]
pub enum Instruction { pub enum Instruction {
MOV = 0x01, MOV_RI = 0x01,
MOV_RR = 0x08,
ADD = 0x02, ADD = 0x02,
SUB = 0x03, SUB = 0x03,
JMP = 0x04, JMP = 0x04,
JZ = 0x05, JZ = 0x05,
JNZ = 0x06, JNZ = 0x06,
CMP_RI = 0x07,
CMP_RR = 0x09,
HLT = 0xFF, HLT = 0xFF,
} }
impl Instruction { impl Instruction {
pub fn opcode_name(op: u8) -> &'static str{ pub fn opcode_name(op: u8) -> &'static str{
match op { match op {
0x01 => "MOV", 0x01 | 0x08 => "MOV",
0x02 => "ADD", 0x02 => "ADD",
0x03 => "SUB", 0x03 => "SUB",
0x04 => "JMP", 0x04 => "JMP",
0x05 => "JZ", 0x05 => "JZ",
0x06 => "JNZ", 0x06 => "JNZ",
0x07 | 0x09 => "CMP",
0xFF => "HLT", 0xFF => "HLT",
_ => "???", _ => "???",
} }