Architecture changes

This commit is contained in:
august kline 2024-06-19 17:26:09 -04:00
parent 0ec54d6672
commit f9198cd0b1
7 changed files with 393 additions and 253 deletions

View File

@ -1,17 +1,11 @@
use crate::instructions::{get_instruction, Instruction}; use crate::instructions::{get_instruction, Instruction};
use crate::memory::Mem; use crate::memory::{MemHandle, MemoryReader, MemoryWriter};
use crate::types::{Byte, Word}; use crate::types::{Byte, Word};
use std::cell::RefCell; use std::sync::mpsc::{Receiver, Sender};
use std::path::PathBuf;
use std::rc::Rc;
use std::str::FromStr;
use std::sync::mpsc::Receiver;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
use anyhow::{bail, Result}; use anyhow::Result;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum StatusFlag { pub enum StatusFlag {
@ -25,6 +19,55 @@ pub enum StatusFlag {
Carry = 0b0000_0001, Carry = 0b0000_0001,
} }
pub struct CpuController(Sender<CpuControl>);
pub enum CpuControl {
Irq,
Nmi,
Stop,
Resume,
Data,
}
impl CpuController {
pub fn new(sender: Sender<CpuControl>) -> Self {
Self(sender)
}
pub fn irq(&self) {
self.0.send(CpuControl::Irq);
}
pub fn nmi(&self) {
self.0.send(CpuControl::Nmi);
}
pub fn stop(&self) {
self.0.send(CpuControl::Stop);
}
pub fn resume(&self) {
self.0.send(CpuControl::Resume);
}
pub fn data(&self) {
self.0.send(CpuControl::Data);
}
}
pub struct CpuReceiver(Receiver<CpuControl>);
impl CpuReceiver {
pub fn new(receiver: Receiver<CpuControl>) -> Self {
Self(receiver)
}
}
pub struct CpuState {
pub a: Byte, // Accumulator Register
pub x: Byte, // X Register
pub y: Byte, // Y Register
pub pc: Word, // Program Counter
pub s: Byte, // Stack Pointer
pub p: Byte, // Status Register
pub irq: bool,
pub nmi: bool,
}
pub struct Cpu { pub struct Cpu {
pub a: Byte, // Accumulator Register pub a: Byte, // Accumulator Register
pub x: Byte, // X Register pub x: Byte, // X Register
@ -32,15 +75,29 @@ pub struct Cpu {
pub pc: Word, // Program Counter pub pc: Word, // Program Counter
pub s: Byte, // Stack Pointer pub s: Byte, // Stack Pointer
pub p: Byte, // Status Register pub p: Byte, // Status Register
pub irq: Receiver<bool>, pub irq: bool,
pub nmi: bool, pub nmi: bool,
pub memory: Arc<Mutex<Mem>>, pub memory: MemHandle,
pub pending_cycles: usize, pub pending_cycles: usize,
receiver: CpuReceiver,
stopped: bool,
cycle_count: usize, cycle_count: usize,
state_tx: Sender<CpuState>,
}
impl MemoryReader for Cpu {
fn read(&self, address: Word) -> Byte {
self.memory.read(address)
}
}
impl MemoryWriter for Cpu {
fn write(&self, address: Word, data: Byte) {
self.memory.write(address, data);
}
} }
impl Cpu { impl Cpu {
pub fn new(memory: Arc<Mutex<Mem>>, irq: Receiver<bool>) -> Self { pub fn new(memory: MemHandle, receiver: CpuReceiver, state_tx: Sender<CpuState>) -> Self {
Cpu { Cpu {
a: 0x00, a: 0x00,
x: 0x00, x: 0x00,
@ -48,11 +105,14 @@ impl Cpu {
pc: 0x0000, pc: 0x0000,
s: 0xFF, s: 0xFF,
p: 0b0010_0100, p: 0b0010_0100,
irq, irq: false,
nmi: false, nmi: false,
receiver,
memory, memory,
stopped: false,
pending_cycles: 0, pending_cycles: 0,
cycle_count: 0, cycle_count: 0,
state_tx,
} }
} }
pub fn reset(&mut self) -> Result<()> { pub fn reset(&mut self) -> Result<()> {
@ -61,18 +121,18 @@ impl Cpu {
self.pending_cycles = 0; self.pending_cycles = 0;
Ok(()) Ok(())
} }
pub fn read(&self, address: Word) -> Result<Byte> { // pub fn read(&self, address: Word) -> Result<Byte> {
let memory = match self.memory.lock() { // let memory = match self.memory.lock() {
Ok(read) => read, // Ok(read) => read,
Err(_) => { // Err(_) => {
bail!("Couldn't acquire lock on memory in cpu thread") // bail!("Couldn't acquire lock on memory in cpu thread")
} // }
}; // };
Ok(memory.read(address)) // Ok(memory.read(address))
} // }
pub fn read_word(&self, address: Word) -> Result<Word> { pub fn read_word(&self, address: Word) -> Result<Word> {
let low_byte = self.read(address)?; let low_byte = self.read(address);
let high_byte = self.read(address + 0x1)?; let high_byte = self.read(address + 0x1);
Ok((high_byte as u16) << 8 | (low_byte as u16)) Ok((high_byte as u16) << 8 | (low_byte as u16))
} }
@ -83,20 +143,20 @@ impl Cpu {
pub fn push_stack(&mut self, data: Byte) -> Result<()> { pub fn push_stack(&mut self, data: Byte) -> Result<()> {
self.s = self.s.wrapping_sub(0x1); self.s = self.s.wrapping_sub(0x1);
self.write(self.stack_addr(), data)?; self.write(self.stack_addr(), data);
Ok(()) Ok(())
} }
pub fn push_stack_word(&mut self, address: Word) -> Result<()> { pub fn push_stack_word(&mut self, address: Word) -> Result<()> {
self.s = self.s.wrapping_sub(0x1); self.s = self.s.wrapping_sub(0x1);
self.write(self.stack_addr(), address.to_le_bytes()[1])?; // Upper byte first self.write(self.stack_addr(), address.to_le_bytes()[1]); // Upper byte first
self.s = self.s.wrapping_sub(0x1); self.s = self.s.wrapping_sub(0x1);
self.write(self.stack_addr(), address.to_le_bytes()[0])?; // Lower byte second self.write(self.stack_addr(), address.to_le_bytes()[0]); // Lower byte second
Ok(()) Ok(())
} }
pub fn pop_stack(&mut self) -> Result<Byte> { pub fn pop_stack(&mut self) -> Result<Byte> {
let byte = self.read(self.stack_addr())?; let byte = self.read(self.stack_addr());
self.s = self.s.wrapping_add(0x1); self.s = self.s.wrapping_add(0x1);
Ok(byte) Ok(byte)
} }
@ -123,17 +183,6 @@ impl Cpu {
value & 0b1000_0000 == 0b1000_0000 value & 0b1000_0000 == 0b1000_0000
} }
pub fn write(&mut self, address: Word, data: Byte) -> Result<()> {
let mut memory = match self.memory.lock() {
Ok(write) => write,
Err(_) => {
bail!("Couldn't acquire write lock on memory in cpu thread")
}
};
memory.write(address, data);
Ok(())
}
pub fn execute(&mut self) { pub fn execute(&mut self) {
self.cycle(); self.cycle();
while self.pending_cycles != 0 { while self.pending_cycles != 0 {
@ -146,28 +195,57 @@ impl Cpu {
} }
pub fn interrupt(&mut self) { pub fn interrupt(&mut self) {
self.irq = false;
self.push_stack_word(self.pc).unwrap(); self.push_stack_word(self.pc).unwrap();
self.push_stack(self.p).unwrap(); self.push_stack(self.p).unwrap();
self.set_flag(StatusFlag::IrqDisable, true); self.set_flag(StatusFlag::IrqDisable, true);
self.pc = self.read_word(0xFFFE).unwrap(); self.pc = self.read_word(0xFFFE).unwrap();
} }
fn receive_control(&mut self) {
let control = self.receiver.0.recv().unwrap();
match control {
CpuControl::Nmi => self.nmi = true,
CpuControl::Irq => self.irq = true,
CpuControl::Stop => self.stopped = true,
CpuControl::Resume => self.stopped = false,
CpuControl::Data => self
.state_tx
.send(CpuState {
a: self.a.clone(), // Accumulator Register
x: self.x.clone(), // X Register
y: self.y.clone(), // Y Register
pc: self.pc.clone(), // Program Counter
s: self.s.clone(), // Stack Pointer
p: self.p.clone(), // Status Register
irq: self.irq.clone(),
nmi: self.nmi.clone(),
})
.unwrap(),
}
}
pub fn cycle(&mut self) { pub fn cycle(&mut self) {
self.receive_control();
if self.stopped {
return;
}
while self.pending_cycles != 0 { while self.pending_cycles != 0 {
// roughly cycle-accurate timing // roughly cycle-accurate timing
sleep(Duration::from_nanos(100)); sleep(Duration::from_nanos(100));
self.pending_cycles -= 1; self.pending_cycles -= 1;
} }
// if !self.get_flag(StatusFlag::IrqDisable) && self.irq.recv().unwrap() { if !self.get_flag(StatusFlag::IrqDisable) && self.irq {
// self.interrupt(); self.interrupt();
// }
let opcode = match self.read(self.pc) {
Ok(byte) => byte,
Err(_) => {
println!("Failed to read from memory at address {:#06x}!", self.pc);
return;
} }
}; let opcode = self.read(self.pc);
// let opcode = match self.read(&self.memory, self.pc) {
// Ok(byte) => byte,
// Err(_) => {
// println!("Failed to read from memory at address {:#06x}!", self.pc);
// return;
// }
// };
let instruction = get_instruction(opcode); let instruction = get_instruction(opcode);
match instruction { match instruction {
Instruction::Valid(valid_instruction) => { Instruction::Valid(valid_instruction) => {
@ -189,18 +267,8 @@ impl Cpu {
} }
Instruction::Invalid(invalid_instruction) => match invalid_instruction.opcode { Instruction::Invalid(invalid_instruction) => match invalid_instruction.opcode {
0x02 => { 0x02 => {
let memory = match self.memory.lock() {
Ok(read) => read,
Err(_) => {
println!("Couldn't acquire read lock on memory in cpu thread");
return;
}
};
// 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.try_recv().unwrap_or_default(), nmi = self.nmi); // 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.try_recv().unwrap_or_default(), nmi = self.nmi);
memory &self.memory.dump();
.dump(PathBuf::from_str("./cpu_dump.bin").unwrap())
.unwrap();
} }
_ => { _ => {
println!( println!(
@ -212,8 +280,7 @@ impl Cpu {
} }
self.cycle_count += 1; self.cycle_count += 1;
} }
pub fn stop(&mut self) { pub fn stop(&mut self) {
unimplemented!() self.stopped = true;
} }
} }

View File

@ -1,6 +1,7 @@
#![allow(clippy::upper_case_acronyms)] #![allow(clippy::upper_case_acronyms)]
use crate::cpu::{Cpu, StatusFlag}; use crate::cpu::{Cpu, StatusFlag};
use crate::memory::{MemoryReader, MemoryWriter};
use crate::types::{Byte, Word}; use crate::types::{Byte, Word};
use std::collections::HashMap; use std::collections::HashMap;
@ -1869,7 +1870,7 @@ fn get_address(mode: &AddressingMode, cpu: &mut Cpu) -> Result<AddressingModeVal
fn zero_page(cpu: &mut Cpu) -> Result<AddressingModeValue> { fn zero_page(cpu: &mut Cpu) -> Result<AddressingModeValue> {
// zp // zp
let address = cpu.read(cpu.pc)?; let address = cpu.read(cpu.pc);
cpu.pc = cpu.pc.wrapping_add(1); cpu.pc = cpu.pc.wrapping_add(1);
Ok(AddressingModeValue::Absolute(address as Word)) Ok(AddressingModeValue::Absolute(address as Word))
} }
@ -1898,7 +1899,7 @@ fn get_address(mode: &AddressingMode, cpu: &mut Cpu) -> Result<AddressingModeVal
// zp, x // zp, x
cpu: &mut Cpu, cpu: &mut Cpu,
) -> Result<AddressingModeValue> { ) -> Result<AddressingModeValue> {
let byte = cpu.read(cpu.pc)?; let byte = cpu.read(cpu.pc);
cpu.pc = cpu.pc.wrapping_add(1); cpu.pc = cpu.pc.wrapping_add(1);
let address: Word = (byte.wrapping_add(cpu.x)) as Word; let address: Word = (byte.wrapping_add(cpu.x)) as Word;
Ok(AddressingModeValue::Absolute(address)) Ok(AddressingModeValue::Absolute(address))
@ -1908,7 +1909,7 @@ fn get_address(mode: &AddressingMode, cpu: &mut Cpu) -> Result<AddressingModeVal
// zp, y // zp, y
cpu: &mut Cpu, cpu: &mut Cpu,
) -> Result<AddressingModeValue> { ) -> Result<AddressingModeValue> {
let byte = cpu.read(cpu.pc)?; let byte = cpu.read(cpu.pc);
cpu.pc = cpu.pc.wrapping_add(1); cpu.pc = cpu.pc.wrapping_add(1);
let address: Word = (byte + cpu.y) as Word; let address: Word = (byte + cpu.y) as Word;
Ok(AddressingModeValue::Absolute(address)) Ok(AddressingModeValue::Absolute(address))
@ -1938,7 +1939,7 @@ fn get_address(mode: &AddressingMode, cpu: &mut Cpu) -> Result<AddressingModeVal
// (zp) // (zp)
cpu: &mut Cpu, cpu: &mut Cpu,
) -> Result<AddressingModeValue> { ) -> Result<AddressingModeValue> {
let byte: Byte = cpu.read(cpu.pc)?; let byte: Byte = cpu.read(cpu.pc);
let address: Word = cpu.read_word(byte as Word)?; let address: Word = cpu.read_word(byte as Word)?;
cpu.pc = cpu.pc.wrapping_add(1); cpu.pc = cpu.pc.wrapping_add(1);
Ok(AddressingModeValue::Absolute(address as Word)) Ok(AddressingModeValue::Absolute(address as Word))
@ -1948,7 +1949,7 @@ fn get_address(mode: &AddressingMode, cpu: &mut Cpu) -> Result<AddressingModeVal
// (zp, x) // (zp, x)
cpu: &mut Cpu, cpu: &mut Cpu,
) -> Result<AddressingModeValue> { ) -> Result<AddressingModeValue> {
let byte = cpu.read(cpu.pc)?; let byte = cpu.read(cpu.pc);
let address = cpu.read_word((byte.wrapping_add(cpu.x)) as Word)?; // Anytime you see something like `byte as Word`, it's using the byte as a zero-page address let address = cpu.read_word((byte.wrapping_add(cpu.x)) as Word)?; // Anytime you see something like `byte as Word`, it's using the byte as a zero-page address
cpu.pc = cpu.pc.wrapping_add(1); cpu.pc = cpu.pc.wrapping_add(1);
Ok(AddressingModeValue::Absolute(address)) Ok(AddressingModeValue::Absolute(address))
@ -1958,7 +1959,7 @@ fn get_address(mode: &AddressingMode, cpu: &mut Cpu) -> Result<AddressingModeVal
// (zp), y // (zp), y
cpu: &mut Cpu, cpu: &mut Cpu,
) -> Result<AddressingModeValue> { ) -> Result<AddressingModeValue> {
let byte: Byte = cpu.read(cpu.pc)?; let byte: Byte = cpu.read(cpu.pc);
let address: Word = cpu.read_word(byte.wrapping_add(cpu.y) as Word)?; let address: Word = cpu.read_word(byte.wrapping_add(cpu.y) as Word)?;
cpu.pc = cpu.pc.wrapping_add(1); cpu.pc = cpu.pc.wrapping_add(1);
Ok(AddressingModeValue::Absolute(address)) Ok(AddressingModeValue::Absolute(address))
@ -1968,7 +1969,7 @@ fn get_address(mode: &AddressingMode, cpu: &mut Cpu) -> Result<AddressingModeVal
// r // r
cpu: &mut Cpu, cpu: &mut Cpu,
) -> Result<AddressingModeValue> { ) -> Result<AddressingModeValue> {
let byte: Byte = cpu.read(cpu.pc)?; let byte: Byte = cpu.read(cpu.pc);
cpu.pc = cpu.pc.wrapping_add(1); cpu.pc = cpu.pc.wrapping_add(1);
Ok(AddressingModeValue::Relative(byte)) Ok(AddressingModeValue::Relative(byte))
} }
@ -1977,9 +1978,9 @@ fn get_address(mode: &AddressingMode, cpu: &mut Cpu) -> Result<AddressingModeVal
// r // r
cpu: &mut Cpu, cpu: &mut Cpu,
) -> Result<AddressingModeValue> { ) -> Result<AddressingModeValue> {
let byte: Byte = cpu.read(cpu.pc)?; let byte: Byte = cpu.read(cpu.pc);
cpu.pc = cpu.pc.wrapping_add(1); cpu.pc = cpu.pc.wrapping_add(1);
let address = cpu.read(cpu.pc)?; let address = cpu.read(cpu.pc);
cpu.pc = cpu.pc.wrapping_add(1); cpu.pc = cpu.pc.wrapping_add(1);
Ok(AddressingModeValue::RelativeTest(byte, address)) Ok(AddressingModeValue::RelativeTest(byte, address))
} }
@ -2055,7 +2056,7 @@ impl Opcode {
| AddressingMode::ZeroPageIndexedIndirect | AddressingMode::ZeroPageIndexedIndirect
| AddressingMode::ZeroPageIndirectIndexedWithY => { | AddressingMode::ZeroPageIndirectIndexedWithY => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let carry = cpu.get_flag(StatusFlag::Carry); let carry = cpu.get_flag(StatusFlag::Carry);
let result = cpu.a as Word + byte as Word + carry as Word; let result = cpu.a as Word + byte as Word + carry as Word;
cpu.set_flag(StatusFlag::Carry, result > Word::from(u8::max_value())); cpu.set_flag(StatusFlag::Carry, result > Word::from(u8::max_value()));
@ -2083,7 +2084,7 @@ impl Opcode {
| AddressingMode::ZeroPageIndexedIndirect | AddressingMode::ZeroPageIndexedIndirect
| AddressingMode::ZeroPageIndirectIndexedWithY => { | AddressingMode::ZeroPageIndirectIndexedWithY => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
cpu.a &= cpu.read(address.try_into()?)?; cpu.a &= cpu.read(address.try_into()?);
cpu.set_flag(StatusFlag::Zero, cpu.a == 0); cpu.set_flag(StatusFlag::Zero, cpu.a == 0);
cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a)); cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a));
Ok(()) Ok(())
@ -2108,9 +2109,9 @@ impl Opcode {
| AddressingMode::ZeroPage | AddressingMode::ZeroPage
| AddressingMode::ZeroPageIndexedWithX => { | AddressingMode::ZeroPageIndexedWithX => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let value = cpu.read(address.try_into()?)?; let value = cpu.read(address.try_into()?);
let result = asl(cpu, value); let result = asl(cpu, value);
cpu.write(address.try_into()?, result)?; cpu.write(address.try_into()?, result);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2123,7 +2124,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0000_0001 != 0b0000_0001, value)?; branch(cpu, test_byte & 0b0000_0001 != 0b0000_0001, value)?;
Ok(()) Ok(())
} }
@ -2138,7 +2139,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0000_0010 != 0b0000_0010, value)?; branch(cpu, test_byte & 0b0000_0010 != 0b0000_0010, value)?;
Ok(()) Ok(())
} }
@ -2153,7 +2154,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0000_0100 != 0b0000_0100, value)?; branch(cpu, test_byte & 0b0000_0100 != 0b0000_0100, value)?;
Ok(()) Ok(())
} }
@ -2168,7 +2169,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0000_1000 != 0b0000_1000, value)?; branch(cpu, test_byte & 0b0000_1000 != 0b0000_1000, value)?;
Ok(()) Ok(())
} }
@ -2183,7 +2184,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0001_0000 != 0b0001_0000, value)?; branch(cpu, test_byte & 0b0001_0000 != 0b0001_0000, value)?;
Ok(()) Ok(())
} }
@ -2198,7 +2199,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0010_0000 != 0b0010_0000, value)?; branch(cpu, test_byte & 0b0010_0000 != 0b0010_0000, value)?;
Ok(()) Ok(())
} }
@ -2213,7 +2214,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0100_0000 != 0b0100_0000, value)?; branch(cpu, test_byte & 0b0100_0000 != 0b0100_0000, value)?;
Ok(()) Ok(())
} }
@ -2228,7 +2229,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b1000_0000 != 0b1000_0000, value)?; branch(cpu, test_byte & 0b1000_0000 != 0b1000_0000, value)?;
Ok(()) Ok(())
} }
@ -2243,7 +2244,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0000_0001 == 0b0000_0001, value)?; branch(cpu, test_byte & 0b0000_0001 == 0b0000_0001, value)?;
Ok(()) Ok(())
} }
@ -2258,7 +2259,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0000_0010 == 0b0000_0010, value)?; branch(cpu, test_byte & 0b0000_0010 == 0b0000_0010, value)?;
Ok(()) Ok(())
} }
@ -2273,7 +2274,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0000_0100 == 0b0000_0100, value)?; branch(cpu, test_byte & 0b0000_0100 == 0b0000_0100, value)?;
Ok(()) Ok(())
} }
@ -2288,7 +2289,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0000_1000 == 0b0000_1000, value)?; branch(cpu, test_byte & 0b0000_1000 == 0b0000_1000, value)?;
Ok(()) Ok(())
} }
@ -2303,7 +2304,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0001_0000 == 0b0001_0000, value)?; branch(cpu, test_byte & 0b0001_0000 == 0b0001_0000, value)?;
Ok(()) Ok(())
} }
@ -2318,7 +2319,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0010_0000 == 0b0010_0000, value)?; branch(cpu, test_byte & 0b0010_0000 == 0b0010_0000, value)?;
Ok(()) Ok(())
} }
@ -2333,7 +2334,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b0100_0000 == 0b0100_0000, value)?; branch(cpu, test_byte & 0b0100_0000 == 0b0100_0000, value)?;
Ok(()) Ok(())
} }
@ -2348,7 +2349,7 @@ impl Opcode {
Ok(value) => match value { Ok(value) => match value {
AddressingModeValue::RelativeTest(byte, _address) => { AddressingModeValue::RelativeTest(byte, _address) => {
let zero_page_address = byte as Word; let zero_page_address = byte as Word;
let test_byte = cpu.read(zero_page_address)?; let test_byte = cpu.read(zero_page_address);
branch(cpu, test_byte & 0b1000_0000 == 0b1000_0000, value)?; branch(cpu, test_byte & 0b1000_0000 == 0b1000_0000, value)?;
Ok(()) Ok(())
} }
@ -2389,7 +2390,7 @@ impl Opcode {
| AddressingMode::AbsoluteA | AddressingMode::AbsoluteA
| AddressingMode::AbsoluteIndexedWithX => { | AddressingMode::AbsoluteIndexedWithX => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let result = cpu.a & cpu.read(address.try_into()?)?; let result = cpu.a & cpu.read(address.try_into()?);
cpu.set_flag(StatusFlag::Zero, result == 0); cpu.set_flag(StatusFlag::Zero, result == 0);
cpu.set_flag( cpu.set_flag(
StatusFlag::Overflow, StatusFlag::Overflow,
@ -2498,7 +2499,7 @@ impl Opcode {
| AddressingMode::ZeroPageIndexedIndirect | AddressingMode::ZeroPageIndexedIndirect
| AddressingMode::ZeroPageIndirectIndexedWithY => { | AddressingMode::ZeroPageIndirectIndexedWithY => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
cpu.set_flag(StatusFlag::Carry, cpu.a >= byte); cpu.set_flag(StatusFlag::Carry, cpu.a >= byte);
cpu.set_flag(StatusFlag::Zero, cpu.a == byte); cpu.set_flag(StatusFlag::Zero, cpu.a == byte);
cpu.set_flag(StatusFlag::Negative, cpu.a <= byte); cpu.set_flag(StatusFlag::Negative, cpu.a <= byte);
@ -2511,7 +2512,7 @@ impl Opcode {
| AddressingMode::ZeroPage | AddressingMode::ZeroPage
| AddressingMode::AbsoluteA => { | AddressingMode::AbsoluteA => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
cpu.set_flag(StatusFlag::Carry, cpu.x >= byte); cpu.set_flag(StatusFlag::Carry, cpu.x >= byte);
cpu.set_flag(StatusFlag::Zero, cpu.x == byte); cpu.set_flag(StatusFlag::Zero, cpu.x == byte);
cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.x - byte)); cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.x - byte));
@ -2524,7 +2525,7 @@ impl Opcode {
| AddressingMode::ZeroPage | AddressingMode::ZeroPage
| AddressingMode::AbsoluteA => { | AddressingMode::AbsoluteA => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
cpu.set_flag(StatusFlag::Carry, cpu.y >= byte); cpu.set_flag(StatusFlag::Carry, cpu.y >= byte);
cpu.set_flag(StatusFlag::Zero, cpu.y == byte); cpu.set_flag(StatusFlag::Zero, cpu.y == byte);
cpu.set_flag(StatusFlag::Negative, cpu.y <= byte); cpu.set_flag(StatusFlag::Negative, cpu.y <= byte);
@ -2538,9 +2539,9 @@ impl Opcode {
| AddressingMode::AbsoluteA | AddressingMode::AbsoluteA
| AddressingMode::AbsoluteIndexedWithX => { | AddressingMode::AbsoluteIndexedWithX => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let dec_byte = byte.wrapping_sub(1); let dec_byte = byte.wrapping_sub(1);
cpu.write(address.try_into()?, dec_byte)?; cpu.write(address.try_into()?, dec_byte);
cpu.set_flag(StatusFlag::Zero, dec_byte == 0); cpu.set_flag(StatusFlag::Zero, dec_byte == 0);
cpu.set_flag(StatusFlag::Negative, cpu.is_negative(dec_byte)); cpu.set_flag(StatusFlag::Negative, cpu.is_negative(dec_byte));
Ok(()) Ok(())
@ -2576,7 +2577,7 @@ impl Opcode {
| AddressingMode::ZeroPageIndexedIndirect | AddressingMode::ZeroPageIndexedIndirect
| AddressingMode::ZeroPageIndirectIndexedWithY => { | AddressingMode::ZeroPageIndirectIndexedWithY => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
cpu.a ^= cpu.read(address.try_into()?)?; cpu.a ^= cpu.read(address.try_into()?);
cpu.set_flag(StatusFlag::Zero, cpu.a == 0); cpu.set_flag(StatusFlag::Zero, cpu.a == 0);
cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a)); cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a));
Ok(()) Ok(())
@ -2595,10 +2596,10 @@ impl Opcode {
| AddressingMode::AbsoluteA | AddressingMode::AbsoluteA
| AddressingMode::AbsoluteIndexedWithX => { | AddressingMode::AbsoluteIndexedWithX => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
cpu.set_flag(StatusFlag::Zero, byte.wrapping_add(1) == 0); cpu.set_flag(StatusFlag::Zero, byte.wrapping_add(1) == 0);
cpu.set_flag(StatusFlag::Negative, cpu.is_negative(byte.wrapping_add(1))); cpu.set_flag(StatusFlag::Negative, cpu.is_negative(byte.wrapping_add(1)));
cpu.write(address.try_into()?, byte.wrapping_add(1))?; cpu.write(address.try_into()?, byte.wrapping_add(1));
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2652,7 +2653,7 @@ impl Opcode {
| AddressingMode::ZeroPageIndexedWithX | AddressingMode::ZeroPageIndexedWithX
| AddressingMode::ZeroPageIndirectIndexedWithY => { | AddressingMode::ZeroPageIndirectIndexedWithY => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
cpu.a = byte; cpu.a = byte;
cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a)); cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a));
cpu.set_flag(StatusFlag::Zero, cpu.a == 0); cpu.set_flag(StatusFlag::Zero, cpu.a == 0);
@ -2667,7 +2668,7 @@ impl Opcode {
| AddressingMode::ZeroPage | AddressingMode::ZeroPage
| AddressingMode::ZeroPageIndexedWithY => { | AddressingMode::ZeroPageIndexedWithY => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
cpu.x = byte; cpu.x = byte;
cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.x)); cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.x));
cpu.set_flag(StatusFlag::Zero, cpu.x == 0); cpu.set_flag(StatusFlag::Zero, cpu.x == 0);
@ -2682,7 +2683,7 @@ impl Opcode {
| AddressingMode::ZeroPage | AddressingMode::ZeroPage
| AddressingMode::ZeroPageIndexedWithX => { | AddressingMode::ZeroPageIndexedWithX => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
cpu.y = byte; cpu.y = byte;
cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.y)); cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.y));
cpu.set_flag(StatusFlag::Zero, cpu.y == 0); cpu.set_flag(StatusFlag::Zero, cpu.y == 0);
@ -2708,9 +2709,9 @@ impl Opcode {
| AddressingMode::ZeroPage | AddressingMode::ZeroPage
| AddressingMode::ZeroPageIndexedWithX => { | AddressingMode::ZeroPageIndexedWithX => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let value = cpu.read(address.try_into()?)?; let value = cpu.read(address.try_into()?);
let result = lsr(cpu, value); let result = lsr(cpu, value);
cpu.write(address.try_into()?, result)?; cpu.write(address.try_into()?, result);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2731,7 +2732,7 @@ impl Opcode {
| AddressingMode::ZeroPageIndexedIndirect | AddressingMode::ZeroPageIndexedIndirect
| AddressingMode::ZeroPageIndirectIndexedWithY => { | AddressingMode::ZeroPageIndirectIndexedWithY => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
cpu.a |= cpu.read(address.try_into()?)?; cpu.a |= cpu.read(address.try_into()?);
cpu.set_flag(StatusFlag::Zero, cpu.a == 0); cpu.set_flag(StatusFlag::Zero, cpu.a == 0);
cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a)); cpu.set_flag(StatusFlag::Negative, cpu.is_negative(cpu.a));
Ok(()) Ok(())
@ -2797,9 +2798,9 @@ impl Opcode {
Opcode::RMB0(mode) => match mode { Opcode::RMB0(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte & 0b1111_1110; let reset_byte = byte & 0b1111_1110;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2807,9 +2808,9 @@ impl Opcode {
Opcode::RMB1(mode) => match mode { Opcode::RMB1(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte & 0b1111_1101; let reset_byte = byte & 0b1111_1101;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2817,9 +2818,9 @@ impl Opcode {
Opcode::RMB2(mode) => match mode { Opcode::RMB2(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte & 0b1111_1011; let reset_byte = byte & 0b1111_1011;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2827,9 +2828,9 @@ impl Opcode {
Opcode::RMB3(mode) => match mode { Opcode::RMB3(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte & 0b1111_0111; let reset_byte = byte & 0b1111_0111;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2837,9 +2838,9 @@ impl Opcode {
Opcode::RMB4(mode) => match mode { Opcode::RMB4(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte & 0b1110_1111; let reset_byte = byte & 0b1110_1111;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2847,9 +2848,9 @@ impl Opcode {
Opcode::RMB5(mode) => match mode { Opcode::RMB5(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte & 0b1101_1111; let reset_byte = byte & 0b1101_1111;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2857,9 +2858,9 @@ impl Opcode {
Opcode::RMB6(mode) => match mode { Opcode::RMB6(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte & 0b1011_1111; let reset_byte = byte & 0b1011_1111;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2867,9 +2868,9 @@ impl Opcode {
Opcode::RMB7(mode) => match mode { Opcode::RMB7(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte & 0b0111_1111; let reset_byte = byte & 0b0111_1111;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2893,9 +2894,9 @@ impl Opcode {
| AddressingMode::ZeroPage | AddressingMode::ZeroPage
| AddressingMode::ZeroPageIndexedWithX => { | AddressingMode::ZeroPageIndexedWithX => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let value = cpu.read(address.try_into()?)?; let value = cpu.read(address.try_into()?);
let result = rol(cpu, value); let result = rol(cpu, value);
cpu.write(address.try_into()?, result)?; cpu.write(address.try_into()?, result);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2920,9 +2921,9 @@ impl Opcode {
| AddressingMode::ZeroPage | AddressingMode::ZeroPage
| AddressingMode::ZeroPageIndexedWithX => { | AddressingMode::ZeroPageIndexedWithX => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let value = cpu.read(address.try_into()?)?; let value = cpu.read(address.try_into()?);
let result = ror(cpu, value); let result = ror(cpu, value);
cpu.write(address.try_into()?, result)?; cpu.write(address.try_into()?, result);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -2955,7 +2956,7 @@ impl Opcode {
| AddressingMode::ZeroPageIndexedIndirect | AddressingMode::ZeroPageIndexedIndirect
| AddressingMode::ZeroPageIndirectIndexedWithY => { | AddressingMode::ZeroPageIndirectIndexedWithY => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let carry = cpu.get_flag(StatusFlag::Carry); let carry = cpu.get_flag(StatusFlag::Carry);
let result = cpu.a as Word + byte as Word + !carry as Word; let result = cpu.a as Word + byte as Word + !carry as Word;
cpu.set_flag(StatusFlag::Carry, result > Word::from(u8::max_value())); cpu.set_flag(StatusFlag::Carry, result > Word::from(u8::max_value()));
@ -2995,9 +2996,9 @@ impl Opcode {
Opcode::SMB0(mode) => match mode { Opcode::SMB0(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte | 0b0000_0001; let reset_byte = byte | 0b0000_0001;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3005,9 +3006,9 @@ impl Opcode {
Opcode::SMB1(mode) => match mode { Opcode::SMB1(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte | 0b0000_0010; let reset_byte = byte | 0b0000_0010;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3015,9 +3016,9 @@ impl Opcode {
Opcode::SMB2(mode) => match mode { Opcode::SMB2(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte | 0b0000_0100; let reset_byte = byte | 0b0000_0100;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3025,9 +3026,9 @@ impl Opcode {
Opcode::SMB3(mode) => match mode { Opcode::SMB3(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte | 0b0000_1000; let reset_byte = byte | 0b0000_1000;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3035,9 +3036,9 @@ impl Opcode {
Opcode::SMB4(mode) => match mode { Opcode::SMB4(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte | 0b0001_0000; let reset_byte = byte | 0b0001_0000;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3045,9 +3046,9 @@ impl Opcode {
Opcode::SMB5(mode) => match mode { Opcode::SMB5(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte | 0b0010_0000; let reset_byte = byte | 0b0010_0000;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3055,9 +3056,9 @@ impl Opcode {
Opcode::SMB6(mode) => match mode { Opcode::SMB6(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte & 0b0100_0000; let reset_byte = byte & 0b0100_0000;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3065,9 +3066,9 @@ impl Opcode {
Opcode::SMB7(mode) => match mode { Opcode::SMB7(mode) => match mode {
AddressingMode::ZeroPage => { AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
let reset_byte = byte | 0b1000_0000; let reset_byte = byte | 0b1000_0000;
cpu.write(address.try_into()?, reset_byte)?; cpu.write(address.try_into()?, reset_byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3082,7 +3083,7 @@ impl Opcode {
| AddressingMode::ZeroPageIndexedWithX | AddressingMode::ZeroPageIndexedWithX
| AddressingMode::ZeroPageIndirectIndexedWithY => { | AddressingMode::ZeroPageIndirectIndexedWithY => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
cpu.write(address.try_into()?, cpu.a)?; cpu.write(address.try_into()?, cpu.a);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3099,7 +3100,7 @@ impl Opcode {
| AddressingMode::ZeroPage | AddressingMode::ZeroPage
| AddressingMode::ZeroPageIndexedWithY => { | AddressingMode::ZeroPageIndexedWithY => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
cpu.write(address.try_into()?, cpu.x)?; cpu.write(address.try_into()?, cpu.x);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3109,7 +3110,7 @@ impl Opcode {
| AddressingMode::ZeroPage | AddressingMode::ZeroPage
| AddressingMode::ZeroPageIndexedWithX => { | AddressingMode::ZeroPageIndexedWithX => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
cpu.write(address.try_into()?, cpu.y)?; cpu.write(address.try_into()?, cpu.y);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3120,7 +3121,7 @@ impl Opcode {
| AddressingMode::ZeroPage | AddressingMode::ZeroPage
| AddressingMode::ZeroPageIndexedWithX => { | AddressingMode::ZeroPageIndexedWithX => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
cpu.write(address.try_into()?, 0)?; cpu.write(address.try_into()?, 0);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)
@ -3149,8 +3150,8 @@ impl Opcode {
// (Garth rocks) http://forum.6502.org/viewtopic.php?t=48 // (Garth rocks) http://forum.6502.org/viewtopic.php?t=48
AddressingMode::AbsoluteA | AddressingMode::ZeroPage => { AddressingMode::AbsoluteA | AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
cpu.write(address.try_into()?, !cpu.a & byte)?; cpu.write(address.try_into()?, !cpu.a & byte);
cpu.set_flag(StatusFlag::Zero, cpu.a & byte > 0); cpu.set_flag(StatusFlag::Zero, cpu.a & byte > 0);
Ok(()) Ok(())
} }
@ -3159,8 +3160,8 @@ impl Opcode {
Opcode::TSB(mode) => match mode { Opcode::TSB(mode) => match mode {
AddressingMode::AbsoluteA | AddressingMode::ZeroPage => { AddressingMode::AbsoluteA | AddressingMode::ZeroPage => {
let address = get_address(mode, cpu)?; let address = get_address(mode, cpu)?;
let byte = cpu.read(address.try_into()?)?; let byte = cpu.read(address.try_into()?);
cpu.write(address.try_into()?, cpu.a | byte)?; cpu.write(address.try_into()?, cpu.a | byte);
Ok(()) Ok(())
} }
_ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc) _ => bail!("An incompatible addressing mode was used for instruction {self:#?} at address {:#04x}", cpu.pc)

View File

@ -1,18 +1,23 @@
use minifb::{InputCallback, Key}; use minifb::{InputCallback, Key};
use std::sync::{Arc, Mutex};
use crate::memory::Mem; use crate::memory::{MemHandle, MemoryWriter};
pub struct Keyboard { pub struct Keyboard {
memory: Arc<Mutex<Mem>>, memory: MemHandle,
} }
impl Keyboard { impl Keyboard {
pub fn new(memory: Arc<Mutex<Mem>>) -> Self { pub fn new(memory: MemHandle) -> Self {
Self { memory } Self { memory }
} }
} }
impl MemoryWriter for Keyboard {
fn write(&self, address: u16, data: u8) {
self.memory.write(address, data);
}
}
impl InputCallback for Keyboard { impl InputCallback for Keyboard {
fn add_char(&mut self, _uni_char: u32) {} fn add_char(&mut self, _uni_char: u32) {}
fn set_key_state(&mut self, key: Key, _state: bool) { fn set_key_state(&mut self, key: Key, _state: bool) {
@ -70,18 +75,11 @@ impl InputCallback for Keyboard {
_ => {} _ => {}
}; };
match &mut self.memory.lock() { self.memory.write(0x4400, row0);
Ok(memory) => { self.memory.write(0x4401, row1);
memory.write(0x4400, row0); self.memory.write(0x4402, row2);
memory.write(0x4401, row1); self.memory.write(0x4403, row3);
memory.write(0x4402, row2); self.memory.write(0x4404, row4);
memory.write(0x4403, row3); self.memory.write(0x4405, row5);
memory.write(0x4404, row4);
memory.write(0x4405, row5);
}
Err(_error) => {
println!("couldnt get a lock on memory while saving keyboard registers");
}
}
} }
} }

View File

@ -14,6 +14,8 @@ use crate::keyboard::Keyboard;
use crate::memory::Mem; use crate::memory::Mem;
use crate::video::Crtc; use crate::video::Crtc;
use cpu::{CpuController, CpuReceiver};
use memory::MemHandle;
// use clap::Parser; // use clap::Parser;
use minifb::{Scale, ScaleMode, Window, WindowOptions}; use minifb::{Scale, ScaleMode, Window, WindowOptions};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -23,7 +25,7 @@ use std::{
io::{stdout, Read, Result}, io::{stdout, Read, Result},
path::PathBuf, path::PathBuf,
str::FromStr, str::FromStr,
sync::{mpsc, Arc, Mutex}, sync::mpsc,
thread, thread,
}; };
@ -78,20 +80,21 @@ fn main() -> Result<()> {
.dump(PathBuf::from_str("./coredump.bin").unwrap()) .dump(PathBuf::from_str("./coredump.bin").unwrap())
.unwrap(); .unwrap();
let shared_memory = Arc::new(Mutex::new(memory)); let shared_memory = MemHandle::new(memory);
let screen_memory = shared_memory.clone();
let cpu_memory = shared_memory.clone(); let cpu_memory = shared_memory.clone();
let display_memory = shared_memory.clone();
let keyboard_memory = shared_memory.clone(); let keyboard_memory = shared_memory.clone();
let (interrupt_tx, interrupt_rx) = mpsc::channel(); let (cpu_tx, cpu_rx) = mpsc::channel();
let (state_tx, state_rx) = mpsc::channel();
let screen_cpu_tx = cpu_tx.clone();
let (window_tx, window_rx) = mpsc::channel(); let (window_tx, window_rx) = mpsc::channel();
thread::spawn(move || { thread::spawn(move || {
let mut screen = Crtc::new( let mut screen = Crtc::new(
display_memory, screen_memory,
config.char_rom.as_ref(), config.char_rom.as_ref(),
interrupt_tx, CpuController::new(screen_cpu_tx),
window_tx, window_tx,
); );
screen.run(); screen.run();
@ -116,9 +119,16 @@ fn main() -> Result<()> {
window.set_input_callback(Box::new(Keyboard::new(keyboard_memory))); window.set_input_callback(Box::new(Keyboard::new(keyboard_memory)));
let cpu = Cpu::new(cpu_memory, interrupt_rx); let mut cpu = Cpu::new(cpu_memory, CpuReceiver::new(cpu_rx), state_tx);
let mut tui = tui::App::new(cpu); let mut tui = tui::App::new(
tui.init(); CpuController::new(cpu_tx.clone()),
shared_memory.clone(),
state_rx,
);
thread::spawn(move || {
cpu.reset().unwrap();
cpu.execute()
});
loop { loop {
if event::poll(std::time::Duration::from_millis(16))? { if event::poll(std::time::Duration::from_millis(16))? {

View File

@ -1,13 +1,56 @@
use crate::error::MemoryError;
use crate::types::{Byte, Word}; use crate::types::{Byte, Word};
use anyhow::{bail, Result};
use std::io::{self, Write}; use std::io::{self, Write};
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr;
use std::sync::{Arc, Mutex, MutexGuard};
use std::u16; use std::u16;
use std::{fs::File, io::Read}; use std::{fs::File, io::Read};
#[derive(Clone, Debug)]
pub struct MemHandle(Arc<Mutex<Mem>>);
impl MemHandle {
pub fn new(memory: Mem) -> Self {
Self(Arc::new(Mutex::new(memory)))
}
pub fn read(&self, address: Word) -> Byte {
let memory = self.lock().unwrap();
memory.read(address)
}
pub fn write(&self, address: Word, data: Byte) {
let mut memory = self.lock().unwrap();
memory.write(address, data);
}
pub fn dump(&self) {
let memory = self.lock().unwrap();
memory.dump(PathBuf::from_str("./cpu_dump.bin").unwrap());
}
fn lock(&self) -> Result<MutexGuard<'_, Mem>> {
match self.0.lock() {
Ok(result) => Ok(result),
Err(error) => bail!("{error}"),
}
}
}
// TODO: impl Iterator for MemHandle so we can get references to the underlying data from other threads without cloning
pub trait MemoryReader {
fn read(&self, address: u16) -> u8;
}
pub trait MemoryWriter {
fn write(&self, address: u16, data: u8);
}
// pub trait MemoryAccess: MemoryReader + MemoryWriter {}
// impl<T> MemoryAccess for T where T: MemoryReader + MemoryWriter {}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Mem { pub struct Mem {
pub data: Vec<Byte>, pub data: Vec<u8>,
} }
impl Mem { impl Mem {
@ -30,27 +73,25 @@ impl Mem {
self.data[address as usize] = data; self.data[address as usize] = data;
} }
pub fn load_rom(&mut self, rom: File) -> Result<(), MemoryError> { pub fn load_rom(&mut self, rom: File) -> Result<()> {
let bytes = rom.bytes(); let bytes = rom.bytes();
for (address, byte) in bytes.enumerate() { for (address, byte) in bytes.enumerate() {
match byte { match byte {
Ok(value) => self.write(address as Word + 0x8000, value), Ok(value) => self.write(address as Word + 0x8000, value),
Err(_) => { Err(_) => {
println!("Loading rom: couldn't write byte {:#04x}", address); bail!("Loading rom: couldn't write byte {:#04x}", address);
return Err(MemoryError::Unwritable);
} }
} }
} }
Ok(()) Ok(())
} }
//pub fn read_from_bin(&mut self, f: File) -> Result<(), MemoryError> { //pub fn read_from_bin(&mut self, f: File) -> Result<()> {
// let bytes = f.bytes(); // let bytes = f.bytes();
// for (address, byte) in bytes.enumerate() { // for (address, byte) in bytes.enumerate() {
// match byte { // match byte {
// Ok(value) => self.write(address as Word, value), // Ok(value) => self.write(address as Word, value),
// Err(_) => { // Err(_) => {
// println!("couldn't write byte {:#04x}", address); // bail!("couldn't write byte {:#04x}", address);
// return Err(MemoryError::Unwritable);
// } // }
// } // }
// } // }

View File

@ -2,44 +2,56 @@
mod tabs; mod tabs;
mod term; mod term;
use std::{io::Result, time::Duration}; use std::{
io::Result,
sync::{mpsc::Receiver, Arc, Mutex},
time::Duration,
};
use crossterm::event::{self, poll, Event, KeyCode, KeyEvent, KeyEventKind}; use crossterm::event::{self, poll, Event, KeyCode, KeyEvent, KeyEventKind};
use ratatui::{ use ratatui::{
layout::Layout,
prelude::*, prelude::*,
widgets::{Block, Cell, Paragraph, Row, Table, TableState}, widgets::{Block, Cell, Paragraph, Row, Table, TableState},
}; };
use crate::cpu::Cpu; use crate::{
cpu::{CpuController, CpuState},
memory::{MemHandle, MemoryReader, MemoryWriter},
};
pub struct App { pub struct App {
cpu: Cpu, cpu: CpuController,
state: Receiver<CpuState>,
memory: MemHandle,
running: bool, running: bool,
table_state: TableState, table_state: TableState,
} }
impl MemoryReader for App {
fn read(&self, address: u16) -> u8 {
self.memory.read(address)
}
}
impl MemoryWriter for App {
fn write(&self, address: u16, data: u8) {
self.memory.write(address, data)
}
}
impl App { impl App {
pub fn new(cpu: Cpu) -> Self { pub fn new(cpu: CpuController, memory: MemHandle, state: Receiver<CpuState>) -> Self {
Self { Self {
cpu, cpu,
memory,
running: true, running: true,
table_state: TableState::default(), table_state: TableState::default(),
state,
} }
} }
pub fn init(&mut self) {
let _ = self.cpu.reset();
}
pub fn update(&mut self, terminal: &mut Terminal<impl Backend>) -> Result<()> { pub fn update(&mut self, terminal: &mut Terminal<impl Backend>) -> Result<()> {
self.draw(terminal)?; self.draw(terminal)?;
self.handle_events()?; self.handle_events()?;
self.handle_cpu()?;
Ok(())
}
fn handle_cpu(&mut self) -> Result<()> {
if self.running {
self.cpu.cycle();
}
Ok(()) Ok(())
} }
@ -64,14 +76,19 @@ impl App {
} }
fn handle_key_press(&mut self, key: KeyEvent) { fn handle_key_press(&mut self, key: KeyEvent) {
// let mut cpu = self.cpu.lock().unwrap();
match key.code { match key.code {
KeyCode::Enter => { KeyCode::Enter => {
if !self.running { if !self.running {
self.cpu.cycle() // cpu.cycle()
} }
} }
KeyCode::Char(' ') => { KeyCode::Char(' ') => {
self.running = !self.running; self.running = !self.running;
match self.running {
true => self.cpu.stop(),
false => self.cpu.resume(),
}
} }
_ => {} _ => {}
}; };
@ -83,26 +100,32 @@ impl App {
/// matter, but for larger apps this can be a significant performance improvement. /// matter, but for larger apps this can be a significant performance improvement.
impl Widget for &App { impl Widget for &App {
fn render(self, area: Rect, buf: &mut Buffer) { fn render(self, area: Rect, buf: &mut Buffer) {
self.cpu.data();
let [cpu_area, memory_area] = let [cpu_area, memory_area] =
Layout::horizontal([Constraint::Percentage(50), Constraint::Fill(1)]).areas(area); Layout::horizontal([Constraint::Percentage(50), Constraint::Fill(1)]).areas(area);
let [memory_table, memory_info] =
Layout::vertical([Constraint::Fill(1), Constraint::Percentage(10)]).areas(memory_area);
let cpu_info = format!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.cpu.a, x = self.cpu.x, y = self.cpu.y, pc = self.cpu.pc, s = self.cpu.s, p = self.cpu.p, irq = self.cpu.irq, nmi = self.cpu.nmi); let cpu = self.state.recv().unwrap();
let cpu_info = format!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = cpu.a, x = cpu.x, y = cpu.y, pc = cpu.pc, s = cpu.s, p = cpu.p, irq = cpu.irq, nmi = cpu.nmi);
Paragraph::new(cpu_info) Paragraph::new(cpu_info)
.block(Block::bordered().title("cpu info!")) .block(Block::bordered().title("cpu info!"))
.render(cpu_area, buf); .render(cpu_area, buf);
let memory = self.cpu.memory.lock().unwrap(); // let table_height = memory_table.rows().count() - 2;
let table_height = memory_area.rows().count() - 2; // TODO: impl Iterator for MemHandle so we can get references to the underlying data from other threads without cloning
let rows: Vec<Row> = memory.data[0..table_height * 16] // let rows: Vec<Row> = self.memory.data()[0..table_height * 16]
.chunks(16) // .chunks(16)
.map(|chunk| { // .map(|chunk| {
chunk // chunk
.iter() // .iter()
.map(|content| Cell::from(Text::from(format!("{content:#02}")))) // .map(|content| Cell::from(Text::from(format!("{content:x}"))))
.collect::<Row>() // .collect::<Row>()
}) // })
.collect(); // .collect();
let zero = self.memory.read(0);
let rows: Vec<Row> = vec![Row::new([format!("{zero}")])];
let widths = vec![Constraint::Length(2); 16]; let widths = vec![Constraint::Length(2); 16];
Widget::render( Widget::render(
Table::new(rows, widths) Table::new(rows, widths)
@ -111,14 +134,16 @@ impl Widget for &App {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e",
"f", "f",
]) ])
.style(Style::new().bold()) .style(Style::new().bold()), // To add space between the header and the rest of the rows, specify the margin
// To add space between the header and the rest of the rows, specify the margin // .bottom_margin(1),
.bottom_margin(1),
) )
.block(Block::bordered().title("memory!")), .block(Block::bordered().title_top("memory")),
memory_area, memory_table,
buf, buf,
); );
Paragraph::new(format!("program counter: {:#04x}", cpu.pc))
.block(Block::bordered().title_top("info"))
.render(memory_info, buf);
} }
} }

View File

@ -1,24 +1,16 @@
use crate::Mem; use crate::{
use std::{ cpu::CpuController,
fs::File, memory::{MemHandle, MemoryReader},
io::Read, types::{Byte, Word},
path::Path,
sync::{mpsc::Sender, Arc, Mutex},
thread::sleep,
time::Duration,
}; };
use std::{fs::File, io::Read, path::Path, sync::mpsc::Sender, thread::sleep, time::Duration};
const FG_COLOR: u32 = 0xFFCC00; const FG_COLOR: u32 = 0xFFCC00;
const BG_COLOR: u32 = 0x110500; const BG_COLOR: u32 = 0x110500;
// // BGR for softbuffer
pub struct Crtc { // const FG_COLOR: u32 = 0x00CCFF;
memory: Arc<Mutex<Mem>>, // const BG_COLOR: u32 = 0x000511;
buffer: Vec<u32>, //
char_rom: Vec<u8>,
interrupt: Sender<bool>,
window: Sender<Vec<u32>>,
}
pub fn get_char_bin<P>(char_rom: Option<P>) -> Vec<u8> pub fn get_char_bin<P>(char_rom: Option<P>) -> Vec<u8>
where where
P: AsRef<Path>, P: AsRef<Path>,
@ -35,11 +27,25 @@ where
} }
} }
pub struct Crtc {
memory: MemHandle,
buffer: Vec<u32>,
char_rom: Vec<u8>,
cpu_controller: CpuController,
window: Sender<Vec<u32>>,
}
impl MemoryReader for Crtc {
fn read(&self, address: Word) -> Byte {
self.memory.read(address)
}
}
impl Crtc { impl Crtc {
pub fn new<P>( pub fn new<P>(
memory: Arc<Mutex<Mem>>, memory: MemHandle,
char_rom: Option<P>, char_rom: Option<P>,
interrupt: Sender<bool>, cpu_controller: CpuController,
window: Sender<Vec<u32>>, window: Sender<Vec<u32>>,
) -> Self ) -> Self
where where
@ -51,31 +57,24 @@ impl Crtc {
buffer: vec![0; 512 * 380], buffer: vec![0; 512 * 380],
window, window,
char_rom, char_rom,
interrupt, cpu_controller,
} }
} }
fn draw(&mut self) { fn draw(&mut self) {
let memory = match self.memory.lock() {
Ok(memory) => memory,
Err(_) => {
println!("Couldn't acquire read on shared memory in video thread");
return;
}
};
// the rest of this function is arcane wizardry // the rest of this function is arcane wizardry
// based on the specifics of george's weird // based on the specifics of george's weird
// display and characters... don't fuck around w it // display and characters... don't fuck around w it
let mut i = 0; let mut i = 0;
for char_row in 0..29 { for char_row in 0..29 {
for char_col in 0..64 { for char_col in 0..64 {
let ascii = memory.read(0x6000 + i); let ascii = self.memory.read(0x6000 + i);
i += 1; i += 1;
for row in 0..13 { for row in 0..13 {
let byte = self.char_rom[ascii as usize + (row * 0x100)]; let byte = self.char_rom[ascii as usize + (row * 0x100)];
for i in (0..8).rev() { for bit_index in (0..8).rev() {
let buffer_index = ((char_row) * 13 + (row)) * 512 + (char_col * 8 + i); let buffer_index =
if (byte << i) & 0x80 == 0x80 { ((char_row) * 13 + (row)) * 512 + (char_col * 8 + bit_index);
if (byte << bit_index) & 0x80 == 0x80 {
self.buffer[buffer_index] = FG_COLOR; self.buffer[buffer_index] = FG_COLOR;
} else { } else {
self.buffer[buffer_index] = BG_COLOR; self.buffer[buffer_index] = BG_COLOR;
@ -92,10 +91,9 @@ impl Crtc {
pub fn run(&mut self) { pub fn run(&mut self) {
loop { loop {
let _ = self.interrupt.send(false); let _ = self.cpu_controller.irq();
sleep(Duration::from_millis(16)); sleep(Duration::from_millis(16));
self.draw(); self.draw();
let _ = self.interrupt.send(true);
} }
} }
} }