add add_ri, sub_ri
This commit is contained in:
parent
4166b0e543
commit
deac6a4448
|
|
@ -4,15 +4,15 @@
|
||||||
- Word Size
|
- Word Size
|
||||||
- **Data Width:** 8 bits
|
- **Data Width:** 8 bits
|
||||||
- **Address width:** 16 bits
|
- **Address width:** 16 bits
|
||||||
- **Address space:** 64 KB (0x0000- 0xFFFF)
|
- **Address space:** 64 KB (0x0000-0xFFFF)
|
||||||
|
|
||||||
## Supported Instructions
|
## Supported Instructions
|
||||||
|
|
||||||
| Instruction | Syntax |
|
| Instruction | Syntax |
|
||||||
| ----------- | ------------ |
|
| ----------- | ------------ |
|
||||||
| MOV | mov reg, imm OR mov reg, reg |
|
| MOV | mov reg, imm OR mov reg, reg |
|
||||||
| ADD | add r1, r2 |
|
| ADD | add reg, imm OR add r1, r2 |
|
||||||
| SUB | sub r1, r2 |
|
| SUB | sub reg, imm OR add r1, r2 |
|
||||||
| JMP | jmp addr |
|
| JMP | jmp addr |
|
||||||
| JZ | jz addr |
|
| JZ | jz addr |
|
||||||
| JNZ | jnz addr |
|
| JNZ | jnz addr |
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ mov a, 10
|
||||||
; move imm 5 to register B
|
; move imm 5 to register B
|
||||||
mov b, 5
|
mov b, 5
|
||||||
; Add a & B
|
; Add a & B
|
||||||
add a, b
|
add a, 2
|
||||||
|
sub a, 2
|
||||||
; Halt
|
; Halt
|
||||||
hlt
|
hlt
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,13 @@ use crate::instructions::Instruction;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
fn tokenize(line: &str) -> Vec<String> {
|
fn tokenize(line: &str) -> Vec<String> {
|
||||||
line.split(|c| c == ' ' || c == ',' || c == '\t')
|
line.split([' ', ',', '\t'])
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
.map(|s| s.to_lowercase())
|
.map(|s| s.to_lowercase())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns corrensponding u8 value of the register
|
||||||
fn parse_reg(s: &str) -> u8 {
|
fn parse_reg(s: &str) -> u8 {
|
||||||
match s {
|
match s {
|
||||||
"a" => 0,
|
"a" => 0,
|
||||||
|
|
@ -19,10 +20,7 @@ fn parse_reg(s: &str) -> u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_reg(s: &str) -> bool {
|
fn is_reg(s: &str) -> bool {
|
||||||
match s {
|
matches!(s, "a" | "b" | "c" | "d")
|
||||||
"a" | "b" | "c" | "d" => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instr_size(tokens: &[String]) -> u16 {
|
fn instr_size(tokens: &[String]) -> u16 {
|
||||||
|
|
@ -76,16 +74,16 @@ pub fn assembler(source: &str) -> Vec<u8> {
|
||||||
match tokens[0].as_str() {
|
match tokens[0].as_str() {
|
||||||
"mov" => {
|
"mov" => {
|
||||||
// mov reg, imm
|
// mov reg, imm
|
||||||
let reg = parse_reg(&tokens[1]);
|
let r1= parse_reg(&tokens[1]);
|
||||||
if is_reg(&tokens[2]) {
|
if is_reg(&tokens[2]) {
|
||||||
let r2 = parse_reg(&tokens[2]);
|
let r2 = parse_reg(&tokens[2]);
|
||||||
bytes.push(Instruction::MOV_RR as u8);
|
bytes.push(Instruction::MOV_RR as u8);
|
||||||
bytes.push(reg);
|
bytes.push(r1);
|
||||||
bytes.push(r2);
|
bytes.push(r2);
|
||||||
} else {
|
} 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_RI as u8);
|
||||||
bytes.push(reg);
|
bytes.push(r1);
|
||||||
bytes.push(imm);
|
bytes.push(imm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -93,21 +91,35 @@ pub fn assembler(source: &str) -> Vec<u8> {
|
||||||
"add" => {
|
"add" => {
|
||||||
// add a, b
|
// add a, b
|
||||||
let r1 = parse_reg(&tokens[1]);
|
let r1 = parse_reg(&tokens[1]);
|
||||||
let r2 = parse_reg(&tokens[2]);
|
|
||||||
|
|
||||||
bytes.push(Instruction::ADD as u8);
|
if is_reg(&tokens[2]) {
|
||||||
|
let r2 = parse_reg(&tokens[2]);
|
||||||
|
bytes.push(Instruction::ADD_RR as u8);
|
||||||
bytes.push(r1);
|
bytes.push(r1);
|
||||||
bytes.push(r2);
|
bytes.push(r2);
|
||||||
|
} else {
|
||||||
|
let imm: u8 = tokens[2].parse().unwrap();
|
||||||
|
bytes.push(Instruction::ADD_RI as u8);
|
||||||
|
bytes.push(r1);
|
||||||
|
bytes.push(imm);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"sub" => {
|
"sub" => {
|
||||||
// sub a, b
|
// sub a, b
|
||||||
let r2 = parse_reg(&tokens[2]);
|
|
||||||
let r1 = parse_reg(&tokens[1]);
|
let r1 = parse_reg(&tokens[1]);
|
||||||
|
if is_reg(&tokens[2]) {
|
||||||
bytes.push(Instruction::SUB as u8);
|
let r2 = parse_reg(&tokens[2]);
|
||||||
|
bytes.push(Instruction::SUB_RR as u8);
|
||||||
bytes.push(r1);
|
bytes.push(r1);
|
||||||
bytes.push(r2);
|
bytes.push(r2);
|
||||||
|
} else {
|
||||||
|
let imm: u8 = tokens[2].parse().unwrap();
|
||||||
|
bytes.push(Instruction::SUB_RI as u8);
|
||||||
|
bytes.push(r1);
|
||||||
|
bytes.push(imm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"jmp" | "jz" | "jnz" => {
|
"jmp" | "jz" | "jnz" => {
|
||||||
|
|
|
||||||
64
src/cpu.rs
64
src/cpu.rs
|
|
@ -42,8 +42,10 @@ impl CPU {
|
||||||
match opcode {
|
match opcode {
|
||||||
x if x == Instruction::MOV_RI as u8 => self.mov_ri(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::MOV_RR as u8 => self.mov_rr(mem),
|
||||||
x if x == Instruction::ADD as u8 => self.add(mem),
|
x if x == Instruction::ADD_RR as u8 => self.add_rr(mem),
|
||||||
x if x == Instruction::SUB as u8 => self.sub(mem),
|
x if x == Instruction::ADD_RI as u8 => self.add_ri(mem),
|
||||||
|
x if x == Instruction::SUB_RR as u8 => self.sub_rr(mem),
|
||||||
|
x if x == Instruction::SUB_RI as u8 => self.sub_ri(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),
|
||||||
|
|
@ -92,7 +94,7 @@ impl CPU {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn add(&mut self, mem: &Memory) {
|
pub fn add_rr(&mut self, mem: &Memory) {
|
||||||
let dest = mem.read(self.pc);
|
let dest = mem.read(self.pc);
|
||||||
self.pc += 1;
|
self.pc += 1;
|
||||||
let src = mem.read(self.pc);
|
let src = mem.read(self.pc);
|
||||||
|
|
@ -133,8 +135,35 @@ impl CPU {
|
||||||
self.zero = result == 0;
|
self.zero = result == 0;
|
||||||
self.carry = carry;
|
self.carry = carry;
|
||||||
}
|
}
|
||||||
|
pub fn add_ri(&mut self, mem: &Memory) {
|
||||||
|
|
||||||
pub fn sub(&mut self, mem: &Memory) {
|
let dest = mem.read(self.pc);
|
||||||
|
self.pc += 1;
|
||||||
|
let imm = mem.read(self.pc);
|
||||||
|
self.pc += 1;
|
||||||
|
|
||||||
|
let (result, carry) = match dest {
|
||||||
|
0 => self.a.overflowing_add(imm),
|
||||||
|
1 => self.b.overflowing_add(imm),
|
||||||
|
2 => self.c.overflowing_add(imm),
|
||||||
|
3 => self.d.overflowing_add(imm),
|
||||||
|
_ => (0, false),
|
||||||
|
};
|
||||||
|
|
||||||
|
match dest {
|
||||||
|
0 => self.a = result,
|
||||||
|
1 => self.b = result,
|
||||||
|
2 => self.c = result,
|
||||||
|
3 => self.d = result,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.zero = result == 0;
|
||||||
|
self.carry = carry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn sub_rr(&mut self, mem: &Memory) {
|
||||||
let dest = mem.read(self.pc);
|
let dest = mem.read(self.pc);
|
||||||
self.pc += 1;
|
self.pc += 1;
|
||||||
let src = mem.read(self.pc);
|
let src = mem.read(self.pc);
|
||||||
|
|
@ -176,6 +205,33 @@ impl CPU {
|
||||||
self.carry = borrow;
|
self.carry = borrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sub_ri(&mut self, mem: &Memory) {
|
||||||
|
let dest = mem.read(self.pc);
|
||||||
|
self.pc += 1;
|
||||||
|
let imm = mem.read(self.pc);
|
||||||
|
self.pc += 1;
|
||||||
|
|
||||||
|
let (result, borrow) = match dest {
|
||||||
|
0 => self.a.overflowing_sub(imm),
|
||||||
|
1 => self.b.overflowing_sub(imm),
|
||||||
|
2 => self.c.overflowing_sub(imm),
|
||||||
|
3 => self.d.overflowing_sub(imm),
|
||||||
|
_ => (0, false),
|
||||||
|
};
|
||||||
|
|
||||||
|
match dest {
|
||||||
|
0 => self.a = result,
|
||||||
|
1 => self.b = result,
|
||||||
|
2 => self.c = result,
|
||||||
|
3 => self.d = result,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.zero = result == 0;
|
||||||
|
self.carry = borrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn jmp(&mut self, mem: &Memory) {
|
pub fn jmp(&mut self, mem: &Memory) {
|
||||||
let low = mem.read(self.pc) as u16;
|
let low = mem.read(self.pc) as u16;
|
||||||
self.inc_pc();
|
self.inc_pc();
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
MOV_RI = 0x01,
|
MOV_RI = 0x01,
|
||||||
MOV_RR = 0x08,
|
MOV_RR = 0x08,
|
||||||
ADD = 0x02,
|
ADD_RR = 0x02,
|
||||||
SUB = 0x03,
|
ADD_RI = 0x0A,
|
||||||
|
SUB_RR = 0x03,
|
||||||
|
SUB_RI = 0x0B,
|
||||||
JMP = 0x04,
|
JMP = 0x04,
|
||||||
JZ = 0x05,
|
JZ = 0x05,
|
||||||
JNZ = 0x06,
|
JNZ = 0x06,
|
||||||
|
|
@ -16,8 +19,8 @@ impl Instruction {
|
||||||
pub fn opcode_name(op: u8) -> &'static str{
|
pub fn opcode_name(op: u8) -> &'static str{
|
||||||
match op {
|
match op {
|
||||||
0x01 | 0x08 => "MOV",
|
0x01 | 0x08 => "MOV",
|
||||||
0x02 => "ADD",
|
0x02 | 0x0A => "ADD",
|
||||||
0x03 => "SUB",
|
0x03 | 0x0B => "SUB",
|
||||||
0x04 => "JMP",
|
0x04 => "JMP",
|
||||||
0x05 => "JZ",
|
0x05 => "JZ",
|
||||||
0x06 => "JNZ",
|
0x06 => "JNZ",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue