add cmp instruction, add reg, reg, and reg, imm variations
This commit is contained in:
parent
57bbca6cb2
commit
4166b0e543
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
mov a, 10
|
||||||
|
mov b, 10
|
||||||
|
cmp a, b
|
||||||
|
hlt
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
mov a, 10
|
||||||
|
mov b, a
|
||||||
|
cmp a, b
|
||||||
|
cmp a, 10
|
||||||
|
hlt
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
mov a, 15
|
|
||||||
mov b, 15
|
|
||||||
sub a, b
|
|
||||||
hlt
|
|
||||||
|
|
@ -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,11 +77,17 @@ 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]);
|
||||||
let imm: u8 = tokens[2].parse().unwrap();
|
if is_reg(&tokens[2]) {
|
||||||
|
let r2 = parse_reg(&tokens[2]);
|
||||||
bytes.push(Instruction::MOV as u8);
|
bytes.push(Instruction::MOV_RR as u8);
|
||||||
bytes.push(reg);
|
bytes.push(reg);
|
||||||
bytes.push(imm);
|
bytes.push(r2);
|
||||||
|
} else {
|
||||||
|
let imm: u8 = tokens[2].parse().unwrap();
|
||||||
|
bytes.push(Instruction::MOV_RI as u8);
|
||||||
|
bytes.push(reg);
|
||||||
|
bytes.push(imm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"add" => {
|
"add" => {
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
72
src/cpu.rs
72
src/cpu.rs
|
|
@ -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,
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
_ => "???",
|
_ => "???",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue