From a2695b5ca1cc8029e97cc139bde686d173d8ebb2 Mon Sep 17 00:00:00 2001 From: Lauchmelder Date: Wed, 24 Aug 2022 01:57:42 +0200 Subject: [PATCH] add more instructions --- src/addressing.rs | 15 +++++ src/cpu.rs | 39 ++++++++++-- src/instructions.rs | 140 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 178 insertions(+), 16 deletions(-) diff --git a/src/addressing.rs b/src/addressing.rs index 24fb736..67cafe7 100644 --- a/src/addressing.rs +++ b/src/addressing.rs @@ -25,6 +25,21 @@ impl CPU print!("{: <30}", format!("#${:02X}", bus.borrow().read_cpu(self.absolute_addr))); } + pub fn imp(&mut self) + { + print!("{: <30}", ""); + } + + pub fn rel(&mut self) + { + let bus = self.bus.upgrade().unwrap(); + + self.relative_addr = bus.borrow().read_cpu(self.pc) as i8; + self.pc += 1; + + print!("{: <30}", format!("${:02X}", self.relative_addr)); + } + pub fn zpg(&mut self) { let bus = self.bus.upgrade().unwrap(); diff --git a/src/cpu.rs b/src/cpu.rs index f9cfe38..29ced63 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -22,7 +22,7 @@ macro_rules! instr { ($instr: ident, $addr: ident, $cyc: literal, $len: literal) => { - Instruction + Option::Some(Instruction { action: CPU::$instr, addressing: CPU::$addr, @@ -30,7 +30,7 @@ macro_rules! instr length: $len, name: s3::new(stringify!($instr)).unwrap() - } + }) } } @@ -39,7 +39,7 @@ pub struct CPU pub cycle: u8, total_cycles: u64, pub absolute_addr: u16, - pub relative_addr: u8, + pub relative_addr: i8, pub acc: u8, pub x: u8, @@ -60,9 +60,36 @@ impl CPU const UNDEF_INSTR: Option = None; let mut instr_set = [UNDEF_INSTR; 256]; - instr_set[0x4C] = Option::Some(instr!(jmp, abs, 3, 3)); - instr_set[0x86] = Option::Some(instr!(stx, zpg, 3, 2)); - instr_set[0xA2] = Option::Some(instr!(ldx, imm, 2, 2)); + instr_set[0x10] = instr!(bpl, rel, 2, 2); + instr_set[0x18] = instr!(clc, imp, 2, 1); + + instr_set[0x20] = instr!(jsr, abs, 6, 3); + instr_set[0x24] = instr!(bit, zpg, 3, 2); + + instr_set[0x30] = instr!(bmi, rel, 2, 2); + instr_set[0x38] = instr!(sec, imp, 2, 1); + + instr_set[0x4C] = instr!(jmp, abs, 3, 3); + + instr_set[0x50] = instr!(bvc, rel, 2, 2); + + instr_set[0x70] = instr!(bvs, rel, 2, 2); + + instr_set[0x85] = instr!(sta, zpg, 3, 2); + instr_set[0x86] = instr!(stx, zpg, 3, 2); + + instr_set[0x90] = instr!(bcc, rel, 2, 2); + + instr_set[0xA2] = instr!(ldx, imm, 2, 2); + instr_set[0xA9] = instr!(lda, imm, 2, 2); + + instr_set[0xB0] = instr!(bcs, rel, 2, 2); + + instr_set[0xD0] = instr!(bne, rel, 2, 2); + + instr_set[0xEA] = instr!(nop, imp, 2, 1); + + instr_set[0xF0] = instr!(beq, rel, 2, 2); CPU { cycle: 0, diff --git a/src/instructions.rs b/src/instructions.rs index 8e8037a..a1e5d3f 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -35,6 +35,94 @@ macro_rules! set_flag_to } } +macro_rules! test_flag +{ + ($target: expr, $flag: expr) => + { + ($target & (1u8 << ($flag as u8))) != 0 + } +} + +macro_rules! push +{ + ($bus: expr, $sp: expr, $val: expr) => + { + $bus.write_cpu(0x0100 + $sp as u16, ($val & 0xFF) as u8); + $sp -= 1; + } +} + +macro_rules! branch +{ + ($self: ident) => + { + let branch_target = $self.pc.wrapping_add($self.relative_addr as u16); + + $self.cycle += 1; + if (branch_target & 0xFF00) != ($self.pc & 0xFF00) // Branched to different page + { + $self.cycle += 1; + } + + $self.pc = branch_target; + } +} + +macro_rules! branch_on_fn +{ + ($name: tt, $flag: expr, $result: literal) => + { + pub fn $name(&mut self) + { + if test_flag!(self.p, $flag) == $result + { + branch!(self); + } + } + } +} + +macro_rules! set_flag_fn +{ + ($name: tt, $flag: expr, $result: literal) => + { + pub fn $name(&mut self) + { + match $result + { + false => clear_flag!(self.p, $flag), + true => set_flag!(self.p, $flag) + } + } + } +} + +macro_rules! load_fn +{ + ($name: tt, $register: ident) => + { + pub fn $name(&mut self) + { + self.$register = self.fetch(); + + set_flag_to!(self.p, Bit::Negative, (self.$register & (1u8 << 7)) > 0); + set_flag_to!(self.p, Bit::Zero, self.$register == 0); + } + }; +} + +macro_rules! store_fn +{ + ($name: tt, $register: ident) => + { + pub fn $name(&mut self) + { + let bus = self.bus.upgrade().unwrap(); + bus.borrow_mut().write_cpu(self.absolute_addr, self.$register); + } + }; +} + impl CPU { fn fetch(&mut self) -> u8 @@ -43,23 +131,55 @@ impl CPU return bus.borrow().read_cpu(self.absolute_addr); } + branch_on_fn!(bcc, Bit::Carry, false); + branch_on_fn!(bcs, Bit::Carry, true); + branch_on_fn!(bne, Bit::Zero, false); + branch_on_fn!(beq, Bit::Zero, true); + branch_on_fn!(bpl, Bit::Negative, false); + branch_on_fn!(bmi, Bit::Negative, true); + branch_on_fn!(bvc, Bit::Overflow, false); + branch_on_fn!(bvs, Bit::Overflow, true); + + set_flag_fn!(clc, Bit::Carry, false); + set_flag_fn!(sec, Bit::Carry, true); + + load_fn!(lda, acc); + load_fn!(ldx, x); + load_fn!(ldy, y); + + store_fn!(sta, acc); + store_fn!(stx, x); + store_fn!(sty, y); + + pub fn bit(&mut self) + { + let bus = self.bus.upgrade().unwrap(); + let value = bus.borrow().read_cpu(self.absolute_addr); + + set_flag_to!(self.p, Bit::Negative, (value >> 7) & 0x1); + set_flag_to!(self.p, Bit::Overflow, (value >> 6) & 0x1); + set_flag_to!(self.p, Bit::Zero, (self.acc & value) == 0); + } + pub fn jmp(&mut self) { self.pc = self.absolute_addr; } - pub fn ldx(&mut self) - { - self.x = self.fetch(); - - set_flag_to!(self.p, Bit::Negative, (self.x & (1u8 << 7)) > 0); - set_flag_to!(self.p, Bit::Zero, self.x == 0); - } - - pub fn stx(&mut self) + pub fn jsr(&mut self) { let bus = self.bus.upgrade().unwrap(); - bus.borrow_mut().write_cpu(self.absolute_addr, self.x); + push!(bus.borrow_mut(), self.sp, self.pc >> 8); + push!(bus.borrow_mut(), self.sp, self.pc); + + self.pc = self.absolute_addr; + } + + + + pub fn nop(&mut self) + { + } } \ No newline at end of file