Krolyxon
Commit deac6a4

Branches

Tags

Refs →

bench51deac6a4

add add_ri, sub_ri

Author
krolxon
Date
2026-01-05 19:46 +0530
Parent
4166b0e
Commit
deac6a4448be93c3c70655cea821e84a7a1b116c

+101 −29

5 files changed

  1. M README.md +3 −3
  2. M examples/addition.asm +2 −1
  3. M src/assembler.rs +29 −17
  4. M src/cpu.rs +60 −4
  5. M src/instructions.rs +7 −4
M README.md View
@@ -4,15 +4,15 @@
44 - Word Size
55 - **Data Width:** 8 bits
66 - **Address width:** 16 bits
7− - **Address space:** 64 KB (0x0000- 0xFFFF)
7+ - **Address space:** 64 KB (0x0000-0xFFFF)
88
99 ## Supported Instructions
1010
1111 | Instruction | Syntax |
1212 | ----------- | ------------ |
1313 | MOV | mov reg, imm OR mov reg, reg |
14−| ADD | add r1, r2 |
15−| SUB | sub r1, r2 |
14+| ADD | add reg, imm OR add r1, r2 |
15+| SUB | sub reg, imm OR add r1, r2 |
1616 | JMP | jmp addr |
1717 | JZ | jz addr |
1818 | JNZ | jnz addr |
M examples/addition.asm View
@@ -3,6 +3,7 @@ mov a, 10
33 ; move imm 5 to register B
44 mov b, 5
55 ; Add a & B
6−add a, b
6+add a, 2
7+sub a, 2
78 ; Halt
89 hlt
M src/assembler.rs View
@@ -2,12 +2,13 @@ use crate::instructions::Instruction;
22 use std::collections::HashMap;
33
44 fn tokenize(line: &str) -> Vec<String> {
5− line.split(|c| c == ' ' || c == ',' || c == '\t')
5+ line.split([' ', ',', '\t'])
66 .filter(|s| !s.is_empty())
77 .map(|s| s.to_lowercase())
88 .collect()
99 }
1010
11+// Returns corrensponding u8 value of the register
1112 fn parse_reg(s: &str) -> u8 {
1213 match s {
1314 "a" => 0,
@@ -19,10 +20,7 @@ fn parse_reg(s: &str) -> u8 {
1920 }
2021
2122 fn is_reg(s: &str) -> bool {
22− match s {
23− "a" | "b" | "c" | "d" => true,
24− _ => false,
25− }
23+ matches!(s, "a" | "b" | "c" | "d")
2624 }
2725
2826 fn instr_size(tokens: &[String]) -> u16 {
@@ -76,16 +74,16 @@ pub fn assembler(source: &str) -> Vec<u8> {
7674 match tokens[0].as_str() {
7775 "mov" => {
7876 // mov reg, imm
79− let reg = parse_reg(&tokens[1]);
77+ let r1= parse_reg(&tokens[1]);
8078 if is_reg(&tokens[2]) {
8179 let r2 = parse_reg(&tokens[2]);
8280 bytes.push(Instruction::MOV_RR as u8);
83− bytes.push(reg);
81+ bytes.push(r1);
8482 bytes.push(r2);
8583 } else {
8684 let imm: u8 = tokens[2].parse().unwrap();
8785 bytes.push(Instruction::MOV_RI as u8);
88− bytes.push(reg);
86+ bytes.push(r1);
8987 bytes.push(imm);
9088 }
9189 }
@@ -93,21 +91,35 @@ pub fn assembler(source: &str) -> Vec<u8> {
9391 "add" => {
9492 // add a, b
9593 let r1 = parse_reg(&tokens[1]);
96− let r2 = parse_reg(&tokens[2]);
9794
98− bytes.push(Instruction::ADD as u8);
99− bytes.push(r1);
100− bytes.push(r2);
95+ if is_reg(&tokens[2]) {
96+ let r2 = parse_reg(&tokens[2]);
97+ bytes.push(Instruction::ADD_RR as u8);
98+ bytes.push(r1);
99+ bytes.push(r2);
100+ } else {
101+ let imm: u8 = tokens[2].parse().unwrap();
102+ bytes.push(Instruction::ADD_RI as u8);
103+ bytes.push(r1);
104+ bytes.push(imm);
105+ }
106+
101107 }
102108
103109 "sub" => {
104110 // sub a, b
105− let r2 = parse_reg(&tokens[2]);
106111 let r1 = parse_reg(&tokens[1]);
107−
108− bytes.push(Instruction::SUB as u8);
109− bytes.push(r1);
110− bytes.push(r2);
112+ if is_reg(&tokens[2]) {
113+ let r2 = parse_reg(&tokens[2]);
114+ bytes.push(Instruction::SUB_RR as u8);
115+ bytes.push(r1);
116+ bytes.push(r2);
117+ } else {
118+ let imm: u8 = tokens[2].parse().unwrap();
119+ bytes.push(Instruction::SUB_RI as u8);
120+ bytes.push(r1);
121+ bytes.push(imm);
122+ }
111123 }
112124
113125 "jmp" | "jz" | "jnz" => {
M src/cpu.rs View
@@ -42,8 +42,10 @@ impl CPU {
4242 match opcode {
4343 x if x == Instruction::MOV_RI as u8 => self.mov_ri(mem),
4444 x if x == Instruction::MOV_RR as u8 => self.mov_rr(mem),
45− x if x == Instruction::ADD as u8 => self.add(mem),
46− x if x == Instruction::SUB as u8 => self.sub(mem),
45+ x if x == Instruction::ADD_RR as u8 => self.add_rr(mem),
46+ x if x == Instruction::ADD_RI as u8 => self.add_ri(mem),
47+ x if x == Instruction::SUB_RR as u8 => self.sub_rr(mem),
48+ x if x == Instruction::SUB_RI as u8 => self.sub_ri(mem),
4749 x if x == Instruction::JMP as u8 => self.jmp(mem),
4850 x if x == Instruction::JZ as u8 => self.jz(mem),
4951 x if x == Instruction::JNZ as u8 => self.jnz(mem),
@@ -92,7 +94,7 @@ impl CPU {
9294 }
9395
9496
95− pub fn add(&mut self, mem: &Memory) {
97+ pub fn add_rr(&mut self, mem: &Memory) {
9698 let dest = mem.read(self.pc);
9799 self.pc += 1;
98100 let src = mem.read(self.pc);
@@ -133,8 +135,35 @@ impl CPU {
133135 self.zero = result == 0;
134136 self.carry = carry;
135137 }
138+ pub fn add_ri(&mut self, mem: &Memory) {
136139
137− pub fn sub(&mut self, mem: &Memory) {
140+ let dest = mem.read(self.pc);
141+ self.pc += 1;
142+ let imm = mem.read(self.pc);
143+ self.pc += 1;
144+
145+ let (result, carry) = match dest {
146+ 0 => self.a.overflowing_add(imm),
147+ 1 => self.b.overflowing_add(imm),
148+ 2 => self.c.overflowing_add(imm),
149+ 3 => self.d.overflowing_add(imm),
150+ _ => (0, false),
151+ };
152+
153+ match dest {
154+ 0 => self.a = result,
155+ 1 => self.b = result,
156+ 2 => self.c = result,
157+ 3 => self.d = result,
158+ _ => {}
159+ }
160+
161+ self.zero = result == 0;
162+ self.carry = carry;
163+ }
164+
165+
166+ pub fn sub_rr(&mut self, mem: &Memory) {
138167 let dest = mem.read(self.pc);
139168 self.pc += 1;
140169 let src = mem.read(self.pc);
@@ -176,6 +205,33 @@ impl CPU {
176205 self.carry = borrow;
177206 }
178207
208+ pub fn sub_ri(&mut self, mem: &Memory) {
209+ let dest = mem.read(self.pc);
210+ self.pc += 1;
211+ let imm = mem.read(self.pc);
212+ self.pc += 1;
213+
214+ let (result, borrow) = match dest {
215+ 0 => self.a.overflowing_sub(imm),
216+ 1 => self.b.overflowing_sub(imm),
217+ 2 => self.c.overflowing_sub(imm),
218+ 3 => self.d.overflowing_sub(imm),
219+ _ => (0, false),
220+ };
221+
222+ match dest {
223+ 0 => self.a = result,
224+ 1 => self.b = result,
225+ 2 => self.c = result,
226+ 3 => self.d = result,
227+ _ => {}
228+ }
229+
230+ self.zero = result == 0;
231+ self.carry = borrow;
232+ }
233+
234+
179235 pub fn jmp(&mut self, mem: &Memory) {
180236 let low = mem.read(self.pc) as u16;
181237 self.inc_pc();
M src/instructions.rs View
@@ -1,9 +1,12 @@
11 #[repr(u8)]
2+#[allow(non_camel_case_types)]
23 pub enum Instruction {
34 MOV_RI = 0x01,
45 MOV_RR = 0x08,
5− ADD = 0x02,
6− SUB = 0x03,
6+ ADD_RR = 0x02,
7+ ADD_RI = 0x0A,
8+ SUB_RR = 0x03,
9+ SUB_RI = 0x0B,
710 JMP = 0x04,
811 JZ = 0x05,
912 JNZ = 0x06,
@@ -16,8 +19,8 @@ impl Instruction {
1619 pub fn opcode_name(op: u8) -> &'static str{
1720 match op {
1821 0x01 | 0x08 => "MOV",
19− 0x02 => "ADD",
20− 0x03 => "SUB",
22+ 0x02 | 0x0A => "ADD",
23+ 0x03 | 0x0B => "SUB",
2124 0x04 => "JMP",
2225 0x05 => "JZ",
2326 0x06 => "JNZ",