bench51debe2ec
add simple assembler
+107 −48
4 files changed
- R code.asm → program.asm +0 −0
- A src/assembler.rs +73 −0
- M src/cpu.rs +24 −6
- M src/main.rs +10 −42
[No content changes]
| @@ -0,0 +1,73 @@ | |||
| 1 | + | use crate::instructions::Instruction; | |
| 2 | + | ||
| 3 | + | fn tokenize(line: &str) -> Vec<String> { | |
| 4 | + | line.split(|c| c == ' ' || c == ',' || c == '\t') | |
| 5 | + | .filter(|s| !s.is_empty()) | |
| 6 | + | .map(|s| s.to_lowercase()) | |
| 7 | + | .collect() | |
| 8 | + | } | |
| 9 | + | ||
| 10 | + | fn parse_reg(s: &str) -> u8 { | |
| 11 | + | match s { | |
| 12 | + | "a" => 0, | |
| 13 | + | "b" => 1, | |
| 14 | + | "c" => 2, | |
| 15 | + | "d" => 3, | |
| 16 | + | _ => panic!("Unknown register {}", s), | |
| 17 | + | } | |
| 18 | + | } | |
| 19 | + | ||
| 20 | + | pub fn assembler(source: &str) -> Vec<u8> { | |
| 21 | + | let mut bytes = Vec::new(); | |
| 22 | + | ||
| 23 | + | for (line_no, line) in source.lines().enumerate() { | |
| 24 | + | let line = line.trim(); | |
| 25 | + | ||
| 26 | + | // Comments in assembly start with ";" | |
| 27 | + | if line.is_empty() || line.starts_with(';') { | |
| 28 | + | continue; | |
| 29 | + | } | |
| 30 | + | ||
| 31 | + | let tokens = tokenize(line); | |
| 32 | + | ||
| 33 | + | match tokens[0].as_str() { | |
| 34 | + | "mov" => { | |
| 35 | + | // mov reg, imm | |
| 36 | + | let reg = parse_reg(&tokens[1]); | |
| 37 | + | let imm: u8 = tokens[2].parse().unwrap(); | |
| 38 | + | ||
| 39 | + | bytes.push(Instruction::MOV as u8); | |
| 40 | + | bytes.push(reg); | |
| 41 | + | bytes.push(imm); | |
| 42 | + | } | |
| 43 | + | ||
| 44 | + | "add" => { | |
| 45 | + | // add a, b | |
| 46 | + | let r1 = parse_reg(&tokens[1]); | |
| 47 | + | let r2 = parse_reg(&tokens[2]); | |
| 48 | + | ||
| 49 | + | bytes.push(Instruction::ADD as u8); | |
| 50 | + | bytes.push(r1); | |
| 51 | + | bytes.push(r2); | |
| 52 | + | } | |
| 53 | + | ||
| 54 | + | "sub" => { | |
| 55 | + | // sub a, b | |
| 56 | + | let r1 = parse_reg(&tokens[1]); | |
| 57 | + | let r2 = parse_reg(&tokens[2]); | |
| 58 | + | ||
| 59 | + | bytes.push(Instruction::SUB as u8); | |
| 60 | + | bytes.push(r1); | |
| 61 | + | bytes.push(r2); | |
| 62 | + | } | |
| 63 | + | ||
| 64 | + | "hlt" => { | |
| 65 | + | bytes.push(Instruction::HLT as u8); | |
| 66 | + | } | |
| 67 | + | ||
| 68 | + | _ => panic!("Line {}: unknown instruction", line_no + 1), | |
| 69 | + | } | |
| 70 | + | } | |
| 71 | + | ||
| 72 | + | bytes | |
| 73 | + | } | |
| @@ -1,4 +1,6 @@ | |||
| 1 | + | use crate::instructions::Instruction; | |
| 1 | 2 | use crate::memory::Memory; | |
| 3 | + | ||
| 2 | 4 | #[derive(Default, Debug)] | |
| 3 | 5 | pub struct CPU { | |
| 4 | 6 | pub a: u8, | |
| @@ -16,6 +18,22 @@ pub struct CPU { | |||
| 16 | 18 | } | |
| 17 | 19 | ||
| 18 | 20 | impl CPU { | |
| 21 | + | pub fn step(&mut self, mem: &mut Memory) { | |
| 22 | + | let opcode = mem.read(self.pc); | |
| 23 | + | self.inc_pc(); | |
| 24 | + | ||
| 25 | + | match opcode { | |
| 26 | + | x if x == Instruction::MOV as u8 => self.mov(mem), | |
| 27 | + | x if x == Instruction::ADD as u8 => self.add(mem), | |
| 28 | + | x if x == Instruction::SUB as u8 => self.sub(mem), | |
| 29 | + | x if x == Instruction::JMP as u8 => self.jmp(mem), | |
| 30 | + | x if x == Instruction::JZ as u8 => self.jz(mem), | |
| 31 | + | x if x == Instruction::JNZ as u8 => self.jnz(mem), | |
| 32 | + | x if x == Instruction::HLT as u8 => self.halt(), | |
| 33 | + | _ => panic!("Unknown opcode {:02X}", opcode), | |
| 34 | + | } | |
| 35 | + | } | |
| 36 | + | ||
| 19 | 37 | pub fn inc_pc(&mut self) { | |
| 20 | 38 | self.pc += 1; | |
| 21 | 39 | } | |
| @@ -24,7 +42,7 @@ impl CPU { | |||
| 24 | 42 | self.halted = true; | |
| 25 | 43 | } | |
| 26 | 44 | ||
| 27 | − | pub fn mov(&mut self, mem: &mut Memory) { | |
| 45 | + | pub fn mov(&mut self, mem: &Memory) { | |
| 28 | 46 | let reg = mem.read(self.pc); | |
| 29 | 47 | self.inc_pc(); | |
| 30 | 48 | let val = mem.read(self.pc); | |
| @@ -41,7 +59,7 @@ impl CPU { | |||
| 41 | 59 | self.zero = val == 0; | |
| 42 | 60 | } | |
| 43 | 61 | ||
| 44 | − | pub fn add(&mut self, mem: &mut Memory) { | |
| 62 | + | pub fn add(&mut self, mem: &Memory) { | |
| 45 | 63 | let dest = mem.read(self.pc); | |
| 46 | 64 | self.pc += 1; | |
| 47 | 65 | let src = mem.read(self.pc); | |
| @@ -83,7 +101,7 @@ impl CPU { | |||
| 83 | 101 | self.carry = carry; | |
| 84 | 102 | } | |
| 85 | 103 | ||
| 86 | − | pub fn sub(&mut self, mem: &mut Memory) { | |
| 104 | + | pub fn sub(&mut self, mem: &Memory) { | |
| 87 | 105 | let dest = mem.read(self.pc); | |
| 88 | 106 | self.pc += 1; | |
| 89 | 107 | let src = mem.read(self.pc); | |
| @@ -125,7 +143,7 @@ impl CPU { | |||
| 125 | 143 | self.carry = borrow; | |
| 126 | 144 | } | |
| 127 | 145 | ||
| 128 | − | pub fn jmp(&mut self, mem: &mut Memory) { | |
| 146 | + | pub fn jmp(&mut self, mem: &Memory) { | |
| 129 | 147 | let low = mem.read(self.pc) as u16; | |
| 130 | 148 | self.inc_pc(); | |
| 131 | 149 | let high = mem.read(self.pc) as u16; | |
| @@ -136,7 +154,7 @@ impl CPU { | |||
| 136 | 154 | self.pc = addrs; | |
| 137 | 155 | } | |
| 138 | 156 | ||
| 139 | − | pub fn jz(&mut self, mem: &mut Memory) { | |
| 157 | + | pub fn jz(&mut self, mem: &Memory) { | |
| 140 | 158 | let low = mem.read(self.pc) as u16; | |
| 141 | 159 | self.inc_pc(); | |
| 142 | 160 | let high = mem.read(self.pc) as u16; | |
| @@ -149,7 +167,7 @@ impl CPU { | |||
| 149 | 167 | } | |
| 150 | 168 | } | |
| 151 | 169 | ||
| 152 | − | pub fn jnz(&mut self, mem: &mut Memory) { | |
| 170 | + | pub fn jnz(&mut self, mem: &Memory) { | |
| 153 | 171 | let low = mem.read(self.pc) as u16; | |
| 154 | 172 | self.inc_pc(); | |
| 155 | 173 | let high = mem.read(self.pc) as u16; | |
| @@ -1,58 +1,26 @@ | |||
| 1 | + | mod assembler; | |
| 1 | 2 | mod cpu; | |
| 2 | 3 | mod instructions; | |
| 3 | 4 | mod memory; | |
| 4 | 5 | ||
| 5 | 6 | use cpu::CPU; | |
| 6 | − | use instructions::Instruction; | |
| 7 | 7 | use memory::Memory; | |
| 8 | 8 | ||
| 9 | + | use crate::assembler::assembler; | |
| 10 | + | ||
| 9 | 11 | fn main() { | |
| 10 | 12 | let mut cpu = CPU::default(); | |
| 11 | 13 | let mut mem = Memory::new(); | |
| 12 | 14 | ||
| 13 | − | // a = 10 | |
| 14 | − | mem.write(0x0000, Instruction::MOV as u8); | |
| 15 | − | mem.write(0x0001, 0); | |
| 16 | − | mem.write(0x0002, 5); | |
| 17 | − | ||
| 18 | − | // b = 2 | |
| 19 | − | mem.write(0x0003, Instruction::MOV as u8); | |
| 20 | − | mem.write(0x0004, 1); | |
| 21 | − | mem.write(0x0005, 3); | |
| 22 | − | ||
| 23 | − | // a = a + b | |
| 24 | − | mem.write(0x0006, Instruction::SUB as u8); | |
| 25 | − | mem.write(0x0007, 0); | |
| 26 | − | mem.write(0x0008, 1); | |
| 27 | − | ||
| 28 | − | // JMP to halt | |
| 29 | − | mem.write(0x0009, Instruction::JNZ as u8); | |
| 30 | − | mem.write(0x000a, 0x0f); // Low | |
| 31 | − | mem.write(0x000b, 0x00); // High | |
| 15 | + | let asm = std::fs::read_to_string("program.asm").unwrap(); | |
| 16 | + | let program = assembler(&asm); | |
| 32 | 17 | ||
| 33 | − | // set b = 0 | |
| 34 | − | mem.write(0x000c, Instruction::MOV as u8); | |
| 35 | − | mem.write(0x000d, 1); | |
| 36 | − | mem.write(0x000e, 0); | |
| 37 | − | ||
| 38 | − | // halt | |
| 39 | − | mem.write(0x000f, Instruction::HLT as u8); | |
| 18 | + | for (i, byte) in program.iter().enumerate() { | |
| 19 | + | mem.write(i as u16, *byte); | |
| 20 | + | } | |
| 40 | 21 | ||
| 41 | 22 | while !cpu.halted { | |
| 42 | − | let opcode = mem.read(cpu.pc); | |
| 43 | − | cpu.inc_pc(); | |
| 44 | − | ||
| 45 | − | match opcode { | |
| 46 | − | x if x == Instruction::MOV as u8 => cpu.mov(&mut mem), | |
| 47 | − | x if x == Instruction::ADD as u8 => cpu.add(&mut mem), | |
| 48 | − | x if x == Instruction::SUB as u8 => cpu.sub(&mut mem), | |
| 49 | − | x if x == Instruction::JMP as u8 => cpu.jmp(&mut mem), | |
| 50 | − | x if x == Instruction::JZ as u8 => cpu.jz(&mut mem), | |
| 51 | − | x if x == Instruction::JNZ as u8 => cpu.jnz(&mut mem), | |
| 52 | − | x if x == Instruction::HLT as u8 => cpu.halt(), | |
| 53 | − | _ => panic!("Unknown opcode {:02X}", opcode), | |
| 54 | − | } | |
| 23 | + | cpu.step(&mut mem); | |
| 24 | + | println!("{:?}", cpu); | |
| 55 | 25 | } | |
| 56 | − | ||
| 57 | − | println!("{:#?}", cpu); | |
| 58 | 26 | } | |