diff --git a/src/george b/src/george index 6abc380..dea6a22 100644 Binary files a/src/george and b/src/george differ diff --git a/src/george.asm b/src/george.asm index 0fca809..517f023 100644 --- a/src/george.asm +++ b/src/george.asm @@ -1,6 +1,9 @@ .setcpu "65C02" .segment "CODE" +main: LDA #$25 - LDY #$25 - STY $2000 - ADC $2000 + LDY #$FF + STY $7000 + STY $7001 + STY $7002 + JMP main diff --git a/src/main.rs b/src/main.rs index 32c77b4..ba8b7ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,15 @@ #![allow(dead_code)] -use core::panic; -use minifb::{Key, Window, WindowOptions}; +use minifb::{Window, WindowOptions}; use std::{ + borrow::{Borrow, BorrowMut}, collections::HashMap, - fmt::write, fs::{self, File}, io::Read, - mem, path::PathBuf, - thread::sleep, - time::Duration, + str::FromStr, + sync::{Arc, Mutex, RwLock}, + thread::{self, sleep}, + time::{Duration, Instant}, u16, }; @@ -17,6 +17,100 @@ type Byte = u8; type Word = u16; #[derive(Debug)] +enum GeorgeErrorKind { + Memory(MemoryError), + Execution(ExecutionError), + AddrMode(AddressingModeError), +} + +impl From for GeorgeErrorKind { + fn from(value: MemoryError) -> Self { + Self::Memory(value) + } +} +impl From for GeorgeErrorKind { + fn from(value: AddressingModeError) -> Self { + Self::AddrMode(value) + } +} +impl From for GeorgeErrorKind { + fn from(value: ExecutionError) -> Self { + Self::Execution(value) + } +} + +#[derive(Debug)] +struct GeorgeError { + desc: String, + kind: GeorgeErrorKind, +} + +#[derive(Debug)] +enum MemoryError { + Unmapped, + NoDataAtAddress, + Unwritable, +} + +#[derive(Debug)] +enum MappingError { + RegionOccupied, + InvalidPage, +} + +struct Crtc { + char_width: u8, + char_height: u8, + graphics_mode: bool, + data: Vec, + start: Word, + end: Word, + page: usize, + pages: usize, +} + +impl Crtc { + fn new( + char_width: u8, + char_height: u8, + _graphics_mode: bool, + start: Word, + end: Word, + pages: usize, + ) -> Self { + Self { + char_height, + char_width, + graphics_mode: true, + data: vec![0x00; (end as usize + 1 - start as usize) * pages], + start, + end, + page: 0, + pages, + } + } + + fn get_buffer(&self) -> Result, GeorgeError> { + // let bitmask = [128, 64, 32, 16, 8, 4, 2, 1]; + let bitmask = [1, 2, 4, 8, 16, 32, 64, 128]; // I think this is how the bytes will be + // serialized? low bits first? + let mut buffer = vec![0; (self.end - self.start + 1) as usize * 8]; + for addr in self.start..self.end { + // eventually this will access memory in the weird interleaved way the hardware is + // designed, but this is easiest to implement for now + let byte = self.data[addr as usize]; + for i in 0..8 { + match byte & bitmask[i] == 0 { + true => buffer[(addr - self.start) as usize * 8 + i] = 0x110500, + false => buffer[(addr - 0x6000) as usize * 8 + i] = 0xFFCC00, + } + } + } + Ok(buffer) + } +} + +#[derive(Debug, Clone)] struct MemMappedDevice { start: Word, end: Word, @@ -58,24 +152,11 @@ impl MemMappedDevice { // for rom an address like 0xFFFF needs to be translated to Page X, 0xFFF } -#[derive(Debug)] +#[derive(Debug, Clone)] struct Mem { areas: Vec, } -#[derive(Debug)] -enum MemoryError { - Unmapped, - NoDataAtAddress, - Unwritable, -} - -#[derive(Debug)] -enum MappingError { - RegionOccupied, - InvalidPage, -} - impl Mem { fn new(area: MemMappedDevice) -> Self { Self { areas: vec![area] } @@ -130,10 +211,20 @@ enum ExecutionError { InvalidInstruction, InterruptsDisabled, StackOverflow, - IncompatibleAddrMode, MemoryError(MemoryError), } +#[derive(Debug)] +enum AddressingModeError { + IncompatibleAddrMode, +} + +impl From for AddressingModeError { + fn from(value: ExecutionError) -> Self { + Self::IncompatibleAddrMode + } +} + impl From for ExecutionError { fn from(error: MemoryError) -> Self { ExecutionError::MemoryError(error) @@ -161,13 +252,13 @@ struct Cpu { p: Byte, // Status Register irq: bool, nmi: bool, - memory: Mem, + memory: Arc>, pending_cycles: usize, cycle_count: usize, } impl Cpu { - fn new(memory: Mem) -> Self { + fn new(memory: Arc>) -> Self { Cpu { a: 0x00, x: 0x00, @@ -189,7 +280,14 @@ impl Cpu { Ok(()) } fn read(&self, address: Word) -> Result { - self.memory.read(address) + let memory = match self.memory.try_read() { + Ok(read) => read, + Err(_) => { + println!("Couldn't acquire read lock on memory in cpu thread"); + return Err(MemoryError::NoDataAtAddress); + } // TODO: upgrade this error type to a `GeorgeError` and make an errorkind for thread lock errors + }; + memory.read(address) } fn read_word(&self, address: Word) -> Result { let low_byte = self.read(address)?; @@ -244,13 +342,21 @@ impl Cpu { } fn write(&mut self, address: Word, data: Byte) -> Result<(), MemoryError> { - self.memory.write(address, data) + let mut memory = match self.memory.write() { + Ok(write) => write, + Err(_) => { + println!("Couldn't acquire write lock on memory in cpu thread"); + return Err(MemoryError::NoDataAtAddress); + } // TODO: upgrade this error type to a `GeorgeError` and make an errorkind for thread lock errors + }; + memory.write(address, data)?; + Ok(()) } fn execute(&mut self) { - self.cycle(); + self.cycle().unwrap(); while self.pending_cycles != 0 { - self.cycle(); + self.cycle().unwrap(); } } @@ -281,10 +387,7 @@ impl Cpu { // } // } // } - fn stop(&mut self) { - unimplemented!() - } - fn cycle(&mut self) { + fn cycle(&mut self) -> Result<(), GeorgeError> { sleep(Duration::from_nanos(500)); if self.pending_cycles == 0 { if self.nmi || (self.irq && !self.get_flag(StatusFlag::IrqDisable)) { @@ -293,15 +396,25 @@ impl Cpu { let _ = self.push_stack(self.p); self.set_flag(StatusFlag::IrqDisable, true); if self.nmi { - self.pc = match self.read_word(0xFFFA) { - Ok(word) => word, - Err(error) => panic!("{error:?}"), + match self.read_word(0xFFFA) { + Ok(word) => self.pc = word, + Err(error) => { + return Err(GeorgeError { + kind: GeorgeErrorKind::Memory(error), + desc: String::from_str("Couldn't read NMI vector").unwrap(), + }) + } }; self.pending_cycles = 8; } else { - self.pc = match self.read_word(0xFFFE) { - Ok(word) => word, - Err(error) => panic!("{error:?}"), + match self.read_word(0xFFFE) { + Ok(word) => self.pc = word, + Err(error) => { + return Err(GeorgeError { + kind: GeorgeErrorKind::Memory(error), + desc: String::from_str("Couldn't read IRQ vector").unwrap(), + }) + } }; self.pending_cycles = 7 } @@ -311,62 +424,54 @@ impl Cpu { } else { let opcode = match self.read(self.pc) { Ok(byte) => byte, - Err(error) => panic!("Something went wrong reading the program counter: {error:?}"), + Err(error) => { + return Err(GeorgeError { + desc: String::from_str("Failed to read the program counter!").unwrap(), + kind: GeorgeErrorKind::Memory(error), + }) + } }; let instruction = get_instruction(opcode); match instruction { Instruction::Valid(valid_instruction) => { - println!("Instruction: {:?}", valid_instruction.opcode); + println!("Instruction: {:?}, {:?}", valid_instruction.opcode, opcode); println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq, nmi = self.nmi); println!(""); self.pc += 1; match valid_instruction.opcode.call(self) { Ok(_) => { self.pending_cycles += valid_instruction.cycles as usize; - } - Err(error) => match error { - ExecutionError::InvalidInstruction => { - panic!( - "An invalid instruction was called at address {:#06x}", - self.pc - ) - } - ExecutionError::StackOverflow => panic!("Stack overflowed!"), - ExecutionError::MemoryError(error) => match error { - MemoryError::Unmapped => panic!( - "Cpu tried to access memory that hasn't yet been mapped at {:#06x}", - self.pc - ), - MemoryError::NoDataAtAddress => panic!( - "Cpu tried to read from address {:#06x} but there was no data", - self.pc - ), - _ => { - unimplemented!() - } - }, - ExecutionError::InterruptsDisabled => panic!("InterruptsDisabled"), - ExecutionError::IncompatibleAddrMode => { - panic!( - "An IncompatibleAddrMode was used at address {:#06x} for instruction {:?}", self.pc, - get_instruction(self.read(self.pc).unwrap()) - ) - } }, - } + Err(error) => return Err(GeorgeError{ + desc: format!("An IncompatibleAddrMode was used at address {:#06x} for instruction {:?}", + self.pc, valid_instruction).to_string(), kind: error}) + }; + } + Instruction::Invalid(invalid_instruction) => { + return Err(GeorgeError { + kind: GeorgeErrorKind::Execution(ExecutionError::InvalidInstruction), + desc: format!( + "An invalid instruction with opcode {:#04x} was called at address {:#06x}", + invalid_instruction.opcode, self.pc + ), + }) } - Instruction::Invalid => panic!("An invalid instruction was called"), } } self.pending_cycles -= 1; self.cycle_count += 1; + Ok(()) + } + + fn stop(&mut self) { + unimplemented!() } } #[derive(Clone, Debug)] enum Instruction { Valid(ValidInstruction), - Invalid, + Invalid(InvalidInstruction), } #[derive(Clone, Debug)] @@ -375,6 +480,11 @@ struct ValidInstruction { cycles: Byte, } +#[derive(Clone, Debug)] +struct InvalidInstruction { + opcode: Byte, +} + #[derive(Clone, Debug)] enum AddressingMode { AbsoluteA, // a @@ -415,8 +525,14 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 6, }), ), - (0x02, Instruction::Invalid), - (0x03, Instruction::Invalid), + ( + 0x02, + Instruction::Invalid(InvalidInstruction { opcode: 0x02 }), + ), + ( + 0x03, + Instruction::Invalid(InvalidInstruction { opcode: 0x03 }), + ), ( 0x04, Instruction::Valid(ValidInstruction { @@ -466,7 +582,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0x0b, Instruction::Invalid), + ( + 0x0b, + Instruction::Invalid(InvalidInstruction { opcode: 0x0b }), + ), ( 0x0c, Instruction::Valid(ValidInstruction { @@ -516,7 +635,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 5, }), ), - (0x13, Instruction::Invalid), + ( + 0x13, + Instruction::Invalid(InvalidInstruction { opcode: 0x13 }), + ), ( 0x14, Instruction::Valid(ValidInstruction { @@ -566,7 +688,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0x1b, Instruction::Invalid), + ( + 0x1b, + Instruction::Invalid(InvalidInstruction { opcode: 0x1b }), + ), ( 0x1c, Instruction::Valid(ValidInstruction { @@ -609,8 +734,14 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 6, }), ), - (0x22, Instruction::Invalid), - (0x23, Instruction::Invalid), + ( + 0x22, + Instruction::Invalid(InvalidInstruction { opcode: 0x22 }), + ), + ( + 0x23, + Instruction::Invalid(InvalidInstruction { opcode: 0x23 }), + ), ( 0x24, Instruction::Valid(ValidInstruction { @@ -660,7 +791,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0x2b, Instruction::Invalid), + ( + 0x2b, + Instruction::Invalid(InvalidInstruction { opcode: 0x2b }), + ), ( 0x2c, Instruction::Valid(ValidInstruction { @@ -710,7 +844,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 5, }), ), - (0x33, Instruction::Invalid), + ( + 0x33, + Instruction::Invalid(InvalidInstruction { opcode: 0x33 }), + ), ( 0x34, Instruction::Valid(ValidInstruction { @@ -760,7 +897,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0x3b, Instruction::Invalid), + ( + 0x3b, + Instruction::Invalid(InvalidInstruction { opcode: 0x3b }), + ), ( 0x3c, Instruction::Valid(ValidInstruction { @@ -803,9 +943,18 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 6, }), ), - (0x42, Instruction::Invalid), - (0x43, Instruction::Invalid), - (0x44, Instruction::Invalid), + ( + 0x42, + Instruction::Invalid(InvalidInstruction { opcode: 0x42 }), + ), + ( + 0x43, + Instruction::Invalid(InvalidInstruction { opcode: 0x43 }), + ), + ( + 0x44, + Instruction::Invalid(InvalidInstruction { opcode: 0x44 }), + ), ( 0x45, Instruction::Valid(ValidInstruction { @@ -848,7 +997,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0x4b, Instruction::Invalid), + ( + 0x4b, + Instruction::Invalid(InvalidInstruction { opcode: 0x4b }), + ), ( 0x4c, Instruction::Valid(ValidInstruction { @@ -898,8 +1050,14 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 5, }), ), - (0x53, Instruction::Invalid), - (0x54, Instruction::Invalid), + ( + 0x53, + Instruction::Invalid(InvalidInstruction { opcode: 0x53 }), + ), + ( + 0x54, + Instruction::Invalid(InvalidInstruction { opcode: 0x54 }), + ), ( 0x55, Instruction::Valid(ValidInstruction { @@ -942,8 +1100,14 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 3, }), ), - (0x5b, Instruction::Invalid), - (0x5c, Instruction::Invalid), + ( + 0x5b, + Instruction::Invalid(InvalidInstruction { opcode: 0x5b }), + ), + ( + 0x5c, + Instruction::Invalid(InvalidInstruction { opcode: 0x5c }), + ), ( 0x5d, Instruction::Valid(ValidInstruction { @@ -979,8 +1143,14 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 6, }), ), - (0x62, Instruction::Invalid), - (0x63, Instruction::Invalid), + ( + 0x62, + Instruction::Invalid(InvalidInstruction { opcode: 0x62 }), + ), + ( + 0x63, + Instruction::Invalid(InvalidInstruction { opcode: 0x63 }), + ), ( 0x64, Instruction::Valid(ValidInstruction { @@ -1030,7 +1200,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0x6b, Instruction::Invalid), + ( + 0x6b, + Instruction::Invalid(InvalidInstruction { opcode: 0x6b }), + ), ( 0x6c, Instruction::Valid(ValidInstruction { @@ -1080,7 +1253,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 5, }), ), - (0x73, Instruction::Invalid), + ( + 0x73, + Instruction::Invalid(InvalidInstruction { opcode: 0x73 }), + ), ( 0x74, Instruction::Valid(ValidInstruction { @@ -1130,7 +1306,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 4, }), ), - (0x7b, Instruction::Invalid), + ( + 0x7b, + Instruction::Invalid(InvalidInstruction { opcode: 0x7b }), + ), ( 0x7c, Instruction::Valid(ValidInstruction { @@ -1173,8 +1352,14 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 6, }), ), - (0x82, Instruction::Invalid), - (0x83, Instruction::Invalid), + ( + 0x82, + Instruction::Invalid(InvalidInstruction { opcode: 0x82 }), + ), + ( + 0x83, + Instruction::Invalid(InvalidInstruction { opcode: 0x83 }), + ), ( 0x84, Instruction::Valid(ValidInstruction { @@ -1224,7 +1409,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0x8b, Instruction::Invalid), + ( + 0x8b, + Instruction::Invalid(InvalidInstruction { opcode: 0x8b }), + ), ( 0x8c, Instruction::Valid(ValidInstruction { @@ -1274,7 +1462,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 5, }), ), - (0x93, Instruction::Invalid), + ( + 0x93, + Instruction::Invalid(InvalidInstruction { opcode: 0x93 }), + ), ( 0x94, Instruction::Valid(ValidInstruction { @@ -1324,7 +1515,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0x9b, Instruction::Invalid), + ( + 0x9b, + Instruction::Invalid(InvalidInstruction { opcode: 0x9b }), + ), ( 0x9c, Instruction::Valid(ValidInstruction { @@ -1374,7 +1568,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0xa3, Instruction::Invalid), + ( + 0xa3, + Instruction::Invalid(InvalidInstruction { opcode: 0xa3 }), + ), ( 0xa4, Instruction::Valid(ValidInstruction { @@ -1424,7 +1621,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0xab, Instruction::Invalid), + ( + 0xab, + Instruction::Invalid(InvalidInstruction { opcode: 0xab }), + ), ( 0xac, Instruction::Valid(ValidInstruction { @@ -1474,7 +1674,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 5, // Unsure, see https://cx16.dk/65c02/reference.html#LDA }), ), - (0xb3, Instruction::Invalid), + ( + 0xb3, + Instruction::Invalid(InvalidInstruction { opcode: 0xb3 }), + ), ( 0xb4, Instruction::Valid(ValidInstruction { @@ -1524,7 +1727,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0xbb, Instruction::Invalid), + ( + 0xbb, + Instruction::Invalid(InvalidInstruction { opcode: 0xbb }), + ), ( 0xbc, Instruction::Valid(ValidInstruction { @@ -1567,8 +1773,14 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 6, }), ), - (0xc2, Instruction::Invalid), - (0xc3, Instruction::Invalid), + ( + 0xc2, + Instruction::Invalid(InvalidInstruction { opcode: 0xc2 }), + ), + ( + 0xc3, + Instruction::Invalid(InvalidInstruction { opcode: 0xc3 }), + ), ( 0xc4, Instruction::Valid(ValidInstruction { @@ -1674,8 +1886,14 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 5, // Unsure, look here: https://cx16.dk/65c02/reference.html#CMP }), ), - (0xd3, Instruction::Invalid), - (0xd4, Instruction::Invalid), + ( + 0xd3, + Instruction::Invalid(InvalidInstruction { opcode: 0xd3 }), + ), + ( + 0xd4, + Instruction::Invalid(InvalidInstruction { opcode: 0xd4 }), + ), ( 0xd5, Instruction::Valid(ValidInstruction { @@ -1725,7 +1943,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 3, }), ), - (0xdc, Instruction::Invalid), + ( + 0xdc, + Instruction::Invalid(InvalidInstruction { opcode: 0xdc }), + ), ( 0xdd, Instruction::Valid(ValidInstruction { @@ -1761,8 +1982,14 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 6, }), ), - (0xe2, Instruction::Invalid), - (0xe3, Instruction::Invalid), + ( + 0xe2, + Instruction::Invalid(InvalidInstruction { opcode: 0xe2 }), + ), + ( + 0xe3, + Instruction::Invalid(InvalidInstruction { opcode: 0xe3 }), + ), ( 0xe4, Instruction::Valid(ValidInstruction { @@ -1812,7 +2039,10 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 2, }), ), - (0xeb, Instruction::Invalid), + ( + 0xeb, + Instruction::Invalid(InvalidInstruction { opcode: 0xeb }), + ), ( 0xec, Instruction::Valid(ValidInstruction { @@ -1862,8 +2092,14 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 5, }), ), - (0xf3, Instruction::Invalid), - (0xf4, Instruction::Invalid), + ( + 0xf3, + Instruction::Invalid(InvalidInstruction { opcode: 0xf3 }), + ), + ( + 0xf4, + Instruction::Invalid(InvalidInstruction { opcode: 0xf4 }), + ), ( 0xf5, Instruction::Valid(ValidInstruction { @@ -1906,8 +2142,14 @@ fn get_instruction(opcode: u8) -> Instruction { cycles: 4, }), ), - (0xfb, Instruction::Invalid), - (0xfc, Instruction::Invalid), + ( + 0xfb, + Instruction::Invalid(InvalidInstruction { opcode: 0xfb }), + ), + ( + 0xfc, + Instruction::Invalid(InvalidInstruction { opcode: 0xfc }), + ), ( 0xfd, Instruction::Valid(ValidInstruction { @@ -2047,10 +2289,10 @@ enum AddressingModeValue { } impl TryFrom for u16 { - type Error = ExecutionError; + type Error = AddressingModeError; fn try_from(value: AddressingModeValue) -> Result { match value { - AddressingModeValue::Implied => Err(ExecutionError::IncompatibleAddrMode), + AddressingModeValue::Implied => Err(AddressingModeError::IncompatibleAddrMode), AddressingModeValue::RelativeTest(_zero_page, offset) => Ok(offset as u16), AddressingModeValue::Relative(inner_value) => Ok(inner_value as u16), AddressingModeValue::Absolute(inner_value) => Ok(inner_value), @@ -2229,7 +2471,7 @@ fn branch( cpu: &mut Cpu, condition: bool, value: AddressingModeValue, -) -> Result<(), ExecutionError> { +) -> Result<(), AddressingModeError> { match value { AddressingModeValue::Relative(address) => { let address = signed_byte_to_word(address).wrapping_add(cpu.pc); @@ -2255,12 +2497,12 @@ fn branch( } Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(AddressingModeError::IncompatibleAddrMode), } } impl Opcode { - fn call(&self, cpu: &mut Cpu) -> Result<(), ExecutionError> { + fn call(&self, cpu: &mut Cpu) -> Result<(), GeorgeErrorKind> { match self { Opcode::ADC(mode) => match mode { AddressingMode::Immediate @@ -2287,7 +2529,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Negative, cpu.is_negative(result as Byte)); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::AND(mode) => match mode { AddressingMode::Immediate @@ -2305,7 +2549,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a)); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::ASL(mode) => { fn asl(cpu: &mut Cpu, value: Byte) -> Byte { @@ -2333,7 +2579,9 @@ impl Opcode { cpu.write(address.try_into()?, result)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), } } Opcode::BBR0(mode) => match mode { @@ -2347,11 +2595,15 @@ impl Opcode { branch(cpu, test_byte & 0b0000_0001 != 0b0000_0001, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBR1(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2362,11 +2614,15 @@ impl Opcode { branch(cpu, test_byte & 0b0000_0010 != 0b0000_0010, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBR2(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2377,11 +2633,15 @@ impl Opcode { branch(cpu, test_byte & 0b0000_0100 != 0b0000_0100, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBR3(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2392,11 +2652,15 @@ impl Opcode { branch(cpu, test_byte & 0b0000_1000 != 0b0000_1000, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBR4(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2407,11 +2671,15 @@ impl Opcode { branch(cpu, test_byte & 0b0001_0000 != 0b0001_0000, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBR5(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2422,11 +2690,15 @@ impl Opcode { branch(cpu, test_byte & 0b0010_0000 != 0b0010_0000, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBR6(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2437,11 +2709,15 @@ impl Opcode { branch(cpu, test_byte & 0b0100_0000 != 0b0100_0000, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBR7(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2452,11 +2728,15 @@ impl Opcode { branch(cpu, test_byte & 0b1000_0000 != 0b1000_0000, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBS0(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2467,11 +2747,15 @@ impl Opcode { branch(cpu, test_byte & 0b0000_0001 == 0b0000_0001, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBS1(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2482,11 +2766,15 @@ impl Opcode { branch(cpu, test_byte & 0b0000_0010 == 0b0000_0010, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBS2(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2497,11 +2785,15 @@ impl Opcode { branch(cpu, test_byte & 0b0000_0100 == 0b0000_0100, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBS3(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2512,11 +2804,15 @@ impl Opcode { branch(cpu, test_byte & 0b0000_1000 == 0b0000_1000, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBS4(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2527,11 +2823,15 @@ impl Opcode { branch(cpu, test_byte & 0b0001_0000 == 0b0001_0000, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBS5(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2542,11 +2842,15 @@ impl Opcode { branch(cpu, test_byte & 0b0010_0000 == 0b0010_0000, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBS6(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2557,11 +2861,15 @@ impl Opcode { branch(cpu, test_byte & 0b0100_0000 == 0b0100_0000, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BBS7(mode) => match mode { AddressingMode::ProgramCounterRelativeTest => match get_address(mode, cpu) { @@ -2572,11 +2880,15 @@ impl Opcode { branch(cpu, test_byte & 0b1000_0000 == 0b1000_0000, value)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, - Err(error) => Err(error), + Err(error) => Err(GeorgeErrorKind::Execution(error)), }, - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BCC(mode) => match mode { AddressingMode::ProgramCounterRelative => { @@ -2584,7 +2896,9 @@ impl Opcode { branch(cpu, !cpu.get_flag(StatusFlag::Carry), address)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BCS(mode) => match mode { AddressingMode::ProgramCounterRelative => { @@ -2592,7 +2906,9 @@ impl Opcode { branch(cpu, cpu.get_flag(StatusFlag::Carry), address)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BEQ(mode) => match mode { AddressingMode::ProgramCounterRelative => { @@ -2600,7 +2916,9 @@ impl Opcode { branch(cpu, cpu.get_flag(StatusFlag::Zero), address)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BIT(mode) => match mode { AddressingMode::Immediate @@ -2621,7 +2939,9 @@ impl Opcode { ); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BMI(mode) => match mode { AddressingMode::ProgramCounterRelative => { @@ -2629,7 +2949,9 @@ impl Opcode { branch(cpu, cpu.get_flag(StatusFlag::Negative), address)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BNE(mode) => match mode { AddressingMode::ProgramCounterRelative => { @@ -2637,7 +2959,9 @@ impl Opcode { branch(cpu, !cpu.get_flag(StatusFlag::Zero), address)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BPL(mode) => match mode { AddressingMode::ProgramCounterRelative => { @@ -2645,7 +2969,9 @@ impl Opcode { branch(cpu, !cpu.get_flag(StatusFlag::Negative), address)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BRA(mode) => match mode { AddressingMode::ProgramCounterRelative => { @@ -2653,14 +2979,18 @@ impl Opcode { branch(cpu, true, address)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BRK(mode) => match mode { AddressingMode::Implied => { cpu.set_flag(StatusFlag::Brk, true); panic!("Interrupts unimplemented!"); } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BVC(mode) => match mode { AddressingMode::ProgramCounterRelative => { @@ -2668,7 +2998,9 @@ impl Opcode { branch(cpu, !cpu.get_flag(StatusFlag::Overflow), address)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::BVS(mode) => match mode { AddressingMode::ProgramCounterRelative => { @@ -2676,35 +3008,45 @@ impl Opcode { branch(cpu, cpu.get_flag(StatusFlag::Overflow), address)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::CLC(mode) => match mode { AddressingMode::Implied => { cpu.set_flag(StatusFlag::Carry, false); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::CLD(mode) => match mode { AddressingMode::Implied => { cpu.set_flag(StatusFlag::Decimal, false); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::CLI(mode) => match mode { AddressingMode::Implied => { cpu.set_flag(StatusFlag::IrqDisable, false); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::CLV(mode) => match mode { AddressingMode::Implied => { cpu.set_flag(StatusFlag::Overflow, false); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::CMP(mode) => match mode { AddressingMode::Immediate @@ -2723,7 +3065,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a - byte)); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::CPX(mode) => match mode { AddressingMode::Immediate @@ -2736,7 +3080,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.x - byte)); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::CPY(mode) => match mode { AddressingMode::Immediate @@ -2749,7 +3095,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.y - byte)); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::DEC(mode) => match mode { AddressingMode::ZeroPage @@ -2760,21 +3108,27 @@ impl Opcode { cpu.write(address.try_into()?, cpu.read(address.try_into()?)? - 1)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::DEX(mode) => match mode { AddressingMode::Implied => { cpu.x -= 1; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::DEY(mode) => match mode { AddressingMode::Implied => { cpu.y -= 1; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::EOR(mode) => match mode { AddressingMode::Immediate @@ -2792,7 +3146,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a)); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::INC(mode) => match mode { AddressingMode::Accumulator => { @@ -2812,21 +3168,27 @@ impl Opcode { cpu.write(address.try_into()?, byte + 1)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::INX(mode) => match mode { AddressingMode::Implied => { cpu.x += 1; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::INY(mode) => match mode { AddressingMode::Implied => { cpu.y += 1; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::JMP(mode) => match mode { AddressingMode::AbsoluteA @@ -2836,7 +3198,9 @@ impl Opcode { cpu.pc = address.try_into()?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::JSR(mode) => match mode { AddressingMode::AbsoluteA => { @@ -2846,7 +3210,9 @@ impl Opcode { cpu.pc = address.try_into()?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::LDA(mode) => match mode { AddressingMode::AbsoluteA @@ -2865,7 +3231,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Zero, cpu.a == 0); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::LDX(mode) => match mode { AddressingMode::AbsoluteA @@ -2880,7 +3248,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Zero, cpu.x == 0); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::LDY(mode) => match mode { AddressingMode::AbsoluteA @@ -2895,7 +3265,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Zero, cpu.y == 0); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::LSR(mode) => { fn lsr(cpu: &mut Cpu, value: Byte) -> Byte { @@ -2923,7 +3295,9 @@ impl Opcode { cpu.write(address.try_into()?, result)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), } } Opcode::NOP(_mode) => { @@ -2946,63 +3320,81 @@ impl Opcode { cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a)); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::PHA(mode) => match mode { AddressingMode::Stack => { cpu.push_stack(cpu.a)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::PHP(mode) => match mode { AddressingMode::Stack => { cpu.push_stack(cpu.p)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::PHX(mode) => match mode { AddressingMode::Stack => { cpu.push_stack(cpu.x)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::PHY(mode) => match mode { AddressingMode::Stack => { cpu.push_stack(cpu.y)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::PLA(mode) => match mode { AddressingMode::Stack => { cpu.a = cpu.pop_stack()?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::PLP(mode) => match mode { AddressingMode::Stack => { cpu.p = cpu.pop_stack()?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::PLX(mode) => match mode { AddressingMode::Stack => { cpu.x = cpu.pop_stack()?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::PLY(mode) => match mode { AddressingMode::Stack => { cpu.y = cpu.pop_stack()?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::RMB0(mode) => match mode { AddressingMode::ZeroPage => { @@ -3012,7 +3404,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::RMB1(mode) => match mode { AddressingMode::ZeroPage => { @@ -3022,7 +3416,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::RMB2(mode) => match mode { AddressingMode::ZeroPage => { @@ -3032,7 +3428,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::RMB3(mode) => match mode { AddressingMode::ZeroPage => { @@ -3042,7 +3440,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::RMB4(mode) => match mode { AddressingMode::ZeroPage => { @@ -3052,7 +3452,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::RMB5(mode) => match mode { AddressingMode::ZeroPage => { @@ -3062,7 +3464,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::RMB6(mode) => match mode { AddressingMode::ZeroPage => { @@ -3072,7 +3476,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::RMB7(mode) => match mode { AddressingMode::ZeroPage => { @@ -3082,7 +3488,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::ROL(mode) => { fn rol(cpu: &mut Cpu, value: Byte) -> Byte { @@ -3111,7 +3519,9 @@ impl Opcode { cpu.write(address.try_into()?, result)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), } } Opcode::ROR(mode) => { @@ -3141,7 +3551,9 @@ impl Opcode { cpu.write(address.try_into()?, result)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), } } Opcode::RTI(mode) => match mode { @@ -3150,7 +3562,9 @@ impl Opcode { cpu.p = cpu.pop_stack()?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::RTS(mode) => match mode { AddressingMode::Implied => { @@ -3158,7 +3572,9 @@ impl Opcode { cpu.pc = return_address + 1; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SBC(mode) => match mode { AddressingMode::Immediate @@ -3185,28 +3601,36 @@ impl Opcode { cpu.set_flag(StatusFlag::Negative, cpu.is_negative(result as Byte)); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SEC(mode) => match mode { AddressingMode::Implied => { cpu.set_flag(StatusFlag::Carry, true); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SED(mode) => match mode { AddressingMode::Implied => { cpu.set_flag(StatusFlag::Decimal, true); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SEI(mode) => match mode { AddressingMode::Implied => { cpu.set_flag(StatusFlag::IrqDisable, true); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SMB0(mode) => match mode { AddressingMode::ZeroPage => { @@ -3216,7 +3640,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SMB1(mode) => match mode { AddressingMode::ZeroPage => { @@ -3226,7 +3652,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SMB2(mode) => match mode { AddressingMode::ZeroPage => { @@ -3236,7 +3664,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SMB3(mode) => match mode { AddressingMode::ZeroPage => { @@ -3246,7 +3676,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SMB4(mode) => match mode { AddressingMode::ZeroPage => { @@ -3256,7 +3688,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SMB5(mode) => match mode { AddressingMode::ZeroPage => { @@ -3266,7 +3700,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SMB6(mode) => match mode { AddressingMode::ZeroPage => { @@ -3276,7 +3712,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::SMB7(mode) => match mode { AddressingMode::ZeroPage => { @@ -3286,7 +3724,9 @@ impl Opcode { cpu.write(address.try_into()?, reset_byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::STA(mode) => match mode { AddressingMode::AbsoluteA @@ -3301,14 +3741,18 @@ impl Opcode { cpu.write(address.try_into()?, cpu.a)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::STP(mode) => match mode { AddressingMode::Implied => { cpu.stop(); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::STX(mode) => match mode { AddressingMode::AbsoluteA @@ -3318,7 +3762,9 @@ impl Opcode { cpu.write(address.try_into()?, cpu.x)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::STY(mode) => match mode { AddressingMode::AbsoluteA @@ -3328,7 +3774,9 @@ impl Opcode { cpu.write(address.try_into()?, cpu.y)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::STZ(mode) => match mode { AddressingMode::AbsoluteA @@ -3339,7 +3787,9 @@ impl Opcode { cpu.write(address.try_into()?, 0)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::TAX(mode) => match mode { AddressingMode::Implied => { @@ -3348,7 +3798,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Zero, cpu.x == 0); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::TAY(mode) => match mode { AddressingMode::Implied => { @@ -3357,7 +3809,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Zero, cpu.y == 0); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::TRB(mode) => match mode { // Still not really sure when you would @@ -3370,7 +3824,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Zero, cpu.a & byte > 0); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::TSB(mode) => match mode { AddressingMode::AbsoluteA | AddressingMode::ZeroPage => { @@ -3379,7 +3835,9 @@ impl Opcode { cpu.write(address.try_into()?, cpu.a | byte)?; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::TSX(mode) => match mode { AddressingMode::Implied => { @@ -3388,7 +3846,9 @@ impl Opcode { cpu.set_flag(StatusFlag::Zero, cpu.x == 0); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::TXA(mode) => match mode { AddressingMode::Implied => { @@ -3397,14 +3857,18 @@ impl Opcode { cpu.set_flag(StatusFlag::Zero, cpu.a == 0); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::TXS(mode) => match mode { AddressingMode::Implied => { cpu.s = cpu.x; Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::TYA(mode) => match mode { AddressingMode::Implied => { @@ -3413,19 +3877,79 @@ impl Opcode { cpu.set_flag(StatusFlag::Zero, cpu.a == 0); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, Opcode::WAI(mode) => match mode { AddressingMode::Implied => { cpu.wait_for_interrupt(); Ok(()) } - _ => Err(ExecutionError::IncompatibleAddrMode), + _ => Err(GeorgeErrorKind::AddrMode( + AddressingModeError::IncompatibleAddrMode, + )), }, } } } +struct Screen { + memory: Arc>, + buffer: Vec, + window: minifb::Window, +} + +impl Screen { + fn new(memory: Arc>) -> Self { + Self { + memory, + buffer: vec![0; 512 * 380 * 8], + window: Window::new("screen", 512, 380, WindowOptions::default()).unwrap(), + } + } + fn draw(&mut self) { + let memory = match self.memory.try_read() { + Ok(read) => read, + Err(_) => { + println!("Couldn't acquire read on shared memory in main thread"); + return; + } + }; + // let bitmask = [128, 64, 32, 16, 8, 4, 2, 1]; + let bitmask = [1, 2, 4, 8, 16, 32, 64, 128]; // I think this is how the bytes will be + // serialized? low bits first? + + for addr in 0x6000..0xDFFF { + // eventually this will access memory in the weird interleaved way the hardware is + // designed, but this is easiest to implement for now + let byte = memory.read(addr).unwrap(); + for i in 0..8 { + match byte & bitmask[i] == 0 { + true => self.buffer[(addr - 0x6000) as usize * 8 + i] = 0x110500, + false => self.buffer[(addr - 0x6000) as usize * 8 + i] = 0xFFCC00, + } + } + } + self.window + .update_with_buffer(&self.buffer, 512, 380) + .unwrap(); + } + fn run(&mut self) { + let frame_duration = Duration::from_millis(16); + let mut previous_draw = Instant::now(); + + loop { + let now = Instant::now(); + if now - previous_draw > frame_duration { + self.draw(); + previous_draw = now; + } + sleep(Duration::from_millis(1)); + } + } +} + fn main() { let ram = MemMappedDevice::new(0x0000, 0x3FFF, 2, "ram".into()); let control = MemMappedDevice::new(0x4000, 0x5FFF, 4, "control".into()); @@ -3454,38 +3978,17 @@ fn main() { Err(error) => println!("{:?}", error), Ok(_) => {} }; - for i in 0x6000..0xBF00 { - if i > 0 && i < 0x9000 { - memory.write(i, 0x01).unwrap(); - } else { - memory.write(i, 0x22).unwrap(); - } - } - // let bitmask = [128, 64, 32, 16, 8, 4, 2, 1]; - let bitmask = [1, 2, 4, 8, 16, 32, 64, 128]; // I think this is how the bytes will be - // serialized? low bits first? - let mut buffer: Vec = vec![0; 512 * 380]; - let mut window = match Window::new("george", 512, 380, WindowOptions::default()) { - Ok(win) => win, - Err(error) => { - println!("unable to create window {}", error); - return; - } - }; - while window.is_open() && !window.is_key_down(Key::Escape) { - for addr in 0x6000..0xBF00 { - let byte = memory.read(addr).unwrap(); - for i in 0..8 { - match byte & bitmask[i] == 0 { - true => buffer[(addr - 0x6000) as usize * 8 + i] = 0x000000, - false => buffer[(addr - 0x6000) as usize * 8 + i] = 0xFFCC00, - } - } - } - window.update_with_buffer(&buffer, 512, 380).unwrap(); - } - let mut cpu = Cpu::new(memory); - cpu.reset().unwrap(); - window.limit_update_rate(Some(std::time::Duration::from_micros(16600))); - cpu.execute(); + + let shared_memory = Arc::new(RwLock::new(memory)); + let cpu_memory = shared_memory.clone(); + let display_memory = shared_memory.clone(); + + let mut screen = Screen::new(display_memory); + + thread::spawn(move || { + let mut cpu = Cpu::new(cpu_memory); + cpu.reset().unwrap(); + cpu.execute(); + }); + screen.run(); }