From 9c672741ed4f5c2f68f3d0560eddb52f95640c1c Mon Sep 17 00:00:00 2001 From: Trevor Merritt Date: Mon, 7 Jul 2025 07:36:41 -0400 Subject: [PATCH] start of rom_only PC --- Cargo.lock | 1 + beneater/src/backplane/mod.rs | 0 beneater/src/lib.rs | 2 + beneater/src/parts/backplane.rs | 4 - core/Cargo.toml | 2 +- core/src/computers/mod.rs | 1 + core/src/computers/rom_only/backplane.rs | 25 ++++ core/src/computers/rom_only/mod.rs | 1 + core/src/lib.rs | 2 +- core/src/{mos6502cpu.rs => mos6502cpu/cpu.rs} | 113 +++++------------- core/src/mos6502cpu/dbg.rs | 35 ++++++ core/src/mos6502cpu/mod.rs | 6 + core/src/mos6502cpu/new.rs | 26 ++++ core/src/mos6502cpu/tick2.rs | 64 ++++++++++ core/src/mos6502cpu/tick_stages.rs | 19 +++ core/src/periph/at28c256/mod.rs | 5 +- core/src/periph/at28c256/tick.rs | 31 +++++ .../src/periph/{hm62256.rs => hm62256/mod.rs} | 28 +---- core/src/periph/hm62256/ramchip.rs | 12 ++ core/src/periph/hm62256/romchip.rs | 19 +++ core/src/periph/hm62256/tick.rs | 33 +++++ macroquad/Cargo.toml | 3 +- macroquad/src/bin/rom_only.rs | 31 +++++ 23 files changed, 349 insertions(+), 114 deletions(-) create mode 100644 beneater/src/backplane/mod.rs create mode 100644 core/src/computers/rom_only/backplane.rs create mode 100644 core/src/computers/rom_only/mod.rs rename core/src/{mos6502cpu.rs => mos6502cpu/cpu.rs} (90%) create mode 100644 core/src/mos6502cpu/dbg.rs create mode 100644 core/src/mos6502cpu/mod.rs create mode 100644 core/src/mos6502cpu/new.rs create mode 100644 core/src/mos6502cpu/tick2.rs create mode 100644 core/src/mos6502cpu/tick_stages.rs create mode 100644 core/src/periph/at28c256/tick.rs rename core/src/periph/{hm62256.rs => hm62256/mod.rs} (73%) create mode 100644 core/src/periph/hm62256/ramchip.rs create mode 100644 core/src/periph/hm62256/romchip.rs create mode 100644 core/src/periph/hm62256/tick.rs create mode 100644 macroquad/src/bin/rom_only.rs diff --git a/Cargo.lock b/Cargo.lock index af35df4..80588a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -366,6 +366,7 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" name = "macroquad" version = "0.1.0" dependencies = [ + "core", "macroquad 0.4.14", ] diff --git a/beneater/src/backplane/mod.rs b/beneater/src/backplane/mod.rs new file mode 100644 index 0000000..e69de29 diff --git a/beneater/src/lib.rs b/beneater/src/lib.rs index fb9dd06..9255f26 100644 --- a/beneater/src/lib.rs +++ b/beneater/src/lib.rs @@ -1 +1,3 @@ pub mod parts; +pub mod backplane; +mod backplane; diff --git a/beneater/src/parts/backplane.rs b/beneater/src/parts/backplane.rs index b4e00a2..1111e09 100644 --- a/beneater/src/parts/backplane.rs +++ b/beneater/src/parts/backplane.rs @@ -40,10 +40,6 @@ impl Backplane { self.rom.program(to_load); } - - - - pub fn tick(&mut self) { // is the CPU in read or write state self.address_bus = self.cpu.address_bus(); diff --git a/core/Cargo.toml b/core/Cargo.toml index 46439ac..8ca1694 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2024" [dependencies] log = "0.4" -rand = "0.9.0" \ No newline at end of file +rand = "0.9.0" diff --git a/core/src/computers/mod.rs b/core/src/computers/mod.rs index 0188360..8d9bc4d 100644 --- a/core/src/computers/mod.rs +++ b/core/src/computers/mod.rs @@ -1 +1,2 @@ pub mod beneater; +pub mod rom_only; diff --git a/core/src/computers/rom_only/backplane.rs b/core/src/computers/rom_only/backplane.rs new file mode 100644 index 0000000..6a47006 --- /dev/null +++ b/core/src/computers/rom_only/backplane.rs @@ -0,0 +1,25 @@ +use crate::constants::constants_system::{SIZE_32KB, SIZE_64KB}; +use crate::periph::hm62256::Hm62256; +use crate::periph::rom_chip::RomChip; + +pub struct Backplane { + rom: Hm62256 +} + +impl Backplane { + pub fn new() -> Backplane { + Backplane::program(&[0x00; SIZE_32KB]) + } + + pub fn program(rom: &[u8; SIZE_32KB]) -> Backplane { + Backplane { + rom: *Hm62256::program(rom) + } + } + + pub fn tick(&mut self) { + println!("Preparing to tick."); + + println!("Done ticking."); + } +} diff --git a/core/src/computers/rom_only/mod.rs b/core/src/computers/rom_only/mod.rs new file mode 100644 index 0000000..c8f345f --- /dev/null +++ b/core/src/computers/rom_only/mod.rs @@ -0,0 +1 @@ +pub mod backplane; diff --git a/core/src/lib.rs b/core/src/lib.rs index a5362e8..4e855e1 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,5 +1,5 @@ -pub mod address_mode; pub mod computers; +pub mod address_mode; pub mod constants; pub mod instruction; pub mod instruction_table; diff --git a/core/src/mos6502cpu.rs b/core/src/mos6502cpu/cpu.rs similarity index 90% rename from core/src/mos6502cpu.rs rename to core/src/mos6502cpu/cpu.rs index 266735c..4e67390 100644 --- a/core/src/mos6502cpu.rs +++ b/core/src/mos6502cpu/cpu.rs @@ -11,30 +11,32 @@ use crate::operation::Operation; use log::trace; pub struct Mos6502Cpu { - memory: [u8; SIZE_64KB], + pub(crate) memory: [u8; SIZE_64KB], /// accumulator - a: u8, + pub(crate) a: u8, /// x register - x: u8, + pub(crate) x: u8, /// y register - y: u8, + pub(crate) y: u8, /// cpu flags - flags: Mos6502Flags, + pub(crate) flags: Mos6502Flags, /// program counter pub pc: u16, /// stack offset - s: u8, + pub(crate) s: u8, pub microcode_step: u8, - address_bus: u16, - data_bus: u8, - ir: Instruction, // Instruction Register - oi: OpInfo, - has_reset: bool, - iv: u16, // Interrupt Vector - cycle_carry: u16, // Value to hold between microsteps - ir_bytes: [u8; 4], + pub(crate) address_bus: u16, + pub(crate) data_bus: u8, + pub(crate) ir: Instruction, // Instruction Register + pub(crate) oi: OpInfo, + pub(crate) has_reset: bool, + pub(crate) iv: u16, // Interrupt Vector + pub(crate) cycle_carry: u16, // Value to hold between microsteps + pub(crate) ir_bytes: [u8; 4], /// CPU Read signal pub read_signal: bool, + pub(crate) reset_vector: u16, + pub(crate) int_vector: u16 } impl Mos6502Cpu { @@ -71,6 +73,8 @@ impl Default for Mos6502Cpu { cycle_carry: 0x0000, ir_bytes: [0x00; 4], read_signal: true, + reset_vector: 0x0000, + int_vector: 0x0000 }; working.reset_cpu(); working @@ -86,43 +90,17 @@ impl Mos6502Cpu { self.data_bus } - pub fn new() -> Mos6502Cpu { - let array = [0x00u8; SIZE_64KB]; - let mut working = Mos6502Cpu { - memory: array, - ir_bytes: [0x00; 4], - ..Default::default() - }; - working.reset_cpu(); - working - } - - fn reset_cpu(&mut self) { - // self = &mut Mos6502Cpu::default(); - println!("Should tick 7 times."); - // read the value at 0xfffc 0xfffd for our reset vector. - // read the value at 0xfffe 0xffff for our int vector - self.pc = self.read_word(&OFFSET_RESET_VECTOR); - println!("READ FROM {OFFSET_RESET_VECTOR} AND GOT {}", self.pc); - self.iv = self.read_word(&OFFSET_INT_VECTOR); - self.address_bus = self.pc; - self.read_signal = true; - println!( - "PC and IV are now set from ROM addresses / AB = {:016b}", - self.address_bus - ); - } - - fn read_word(&self, offset: &u16) -> u16 { - println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1); - let low = self.memory[*offset as usize]; - let high = self.memory[*offset as usize + 1]; - println!("LOW = 0x{low:02x} HIGH = 0x{high:02x}"); - let result = (high as u16) << 8 | low as u16; - // println!("MEMORY: {:?}", self.memory); - println!("READ {result:04x}"); - result - } + // + // fn read_word(&self, offset: &u16) -> u16 { + // println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1); + // let low = self.memory[*offset as usize]; + // let high = self.memory[*offset as usize + 1]; + // println!("LOW = 0x{low:02x} HIGH = 0x{high:02x}"); + // let result = (high as u16) << 8 | low as u16; + // // println!("MEMORY: {:?}", self.memory); + // println!("READ {result:04x}"); + // result + // } pub fn peek_flag(&self, flag_to_read: Mos6502Flag) -> bool { self.flags.flag(flag_to_read) @@ -145,15 +123,16 @@ impl Mos6502Cpu { } pub fn peek_a(&self) -> u8 { + println!("Readding register A => 0x{:02x}", self.a); self.a } pub fn poke_a(&mut self, new_a: u8) { println!("Updating register A from [{}] to [{}]", self.a, new_a); - self.a = new_a; } pub fn peek_x(&self) -> u8 { + println!("Readding register X => 0x{}", self.x); self.x } @@ -498,36 +477,6 @@ impl Mos6502Cpu { self.microcode_step -= 1; } } - - pub fn dump(&self) { - println!( - "CPU State: PC: {:04x} / A: {:02x} / X: {:02x} / Y: {:02x} / ADDRESS: {:04x} / DATA: {:02x} / MICROSTEPS: {:02x} / S: {}", - self.pc, - self.a, - self.x, - self.y, - self.address_bus, - self.data_bus, - self.microcode_step, - self.flags.dump() - ); - } - - /// dump_data - /// - /// returns - /// PC, A, X, Y, Address_Bus, Data_Bus, Microcode_Step - pub fn dump_data(&self) -> (u16, u8, u8, u8, u16, u8, u8) { - ( - self.pc, - self.a, - self.x, - self.y, - self.address_bus, - self.data_bus, - self.microcode_step, - ) - } } #[cfg(test)] diff --git a/core/src/mos6502cpu/dbg.rs b/core/src/mos6502cpu/dbg.rs new file mode 100644 index 0000000..696b462 --- /dev/null +++ b/core/src/mos6502cpu/dbg.rs @@ -0,0 +1,35 @@ +use crate::mos6502cpu::cpu::Mos6502Cpu; + +impl Mos6502Cpu { + /// dump_data + /// + /// returns + /// PC, A, X, Y, Address_Bus, Data_Bus, Microcode_Step + pub fn dump_data(&self) -> (u16, u8, u8, u8, u16, u8, u8, u16, u16) { + ( + self.pc, + self.a, + self.x, + self.y, + self.address_bus, + self.data_bus, + self.microcode_step, + self.reset_vector, + self.int_vector + ) + } + + pub fn dump(&self) { + println!( + "CPU State: PC: {:04x} / A: {:02x} / X: {:02x} / Y: {:02x} / ADDRESS: {:04x} / DATA: {:02x} / MICROSTEPS: {:02x} / S: {}", + self.pc, + self.a, + self.x, + self.y, + self.address_bus, + self.data_bus, + self.microcode_step, + self.flags.dump() + ); + } +} diff --git a/core/src/mos6502cpu/mod.rs b/core/src/mos6502cpu/mod.rs new file mode 100644 index 0000000..a2362c5 --- /dev/null +++ b/core/src/mos6502cpu/mod.rs @@ -0,0 +1,6 @@ +pub mod cpu; +pub mod new; + +pub mod tick2; +mod dbg; +mod tick_stages; diff --git a/core/src/mos6502cpu/new.rs b/core/src/mos6502cpu/new.rs new file mode 100644 index 0000000..5923c06 --- /dev/null +++ b/core/src/mos6502cpu/new.rs @@ -0,0 +1,26 @@ +use crate::constants::constants_system::{OFFSET_RESET_VECTOR, SIZE_64KB}; +use crate::mos6502cpu::cpu::Mos6502Cpu; + +impl Mos6502Cpu { + pub fn new() -> Mos6502Cpu { + let array = [0x00u8; SIZE_64KB]; + let mut working = Mos6502Cpu { + memory: array, + ir_bytes: [0x00; 4], + ..Default::default() + }; + working.reset_cpu(); + working + } + + + pub(crate) fn reset_cpu(&mut self) { + self.microcode_step = 7 + 4; + // self = &mut Mos6502Cpu::default(); + println!("Should tick 7 times, then 4 cycles to read the reset and int vectors."); + // read the value at 0xfffc 0xfffd for our reset vector. + // read the value at 0xfffe 0xffff for our int vector + } + + +} \ No newline at end of file diff --git a/core/src/mos6502cpu/tick2.rs b/core/src/mos6502cpu/tick2.rs new file mode 100644 index 0000000..b0c2ae7 --- /dev/null +++ b/core/src/mos6502cpu/tick2.rs @@ -0,0 +1,64 @@ +use crate::constants::constants_system::{OFFSET_INT_VECTOR, OFFSET_RESET_VECTOR}; +use crate::mos6502cpu::cpu::Mos6502Cpu; + +impl Mos6502Cpu { + /// AccurateTick + /// + /// In: address_bus > Address of data operationm + /// data_bus > Data read or written + /// State: + /// read_bus > Flag for if cpu is reading or writing the data bus + /// cycle_step > Index for what step of the Decode->Load->Execute cycle we are in + /// Out: address_bus > address for operation + /// data_bus > data for the operation + /// read_bus > lets rest of the computer know if the CPU is reading from the address + /// provided or if we are writing to the address + pub fn tick2(&mut self, address_bus: u16, data_bus: u8) -> (u16, u8, bool) { + if self.has_reset { + // we have completed the reset cycle + if self.read_signal { + // we should see new data in the data_bus for us + let read_data = data_bus; + } else { + // we are writing to the bus. + } + } else { + println!("Reset microstep {}", self.microcode_step); + // we need to do the reset steps + // reduce the number of remaining microsteps + self.read_signal = true; + match self.microcode_step { + 4 => { + // read first byte of reset vector + self.address_bus = OFFSET_RESET_VECTOR; + } + 3 => { + // at this point data holds the upper byte of our reset vector + self.reset_vector = (data_bus as u16) << 8; + // read secondd byte of reset vector + self.address_bus = OFFSET_RESET_VECTOR + 1; + } + 2 => { + self.reset_vector |= data_bus as u16; + println!("Loaded reset vector of 0x{:04x}", self.reset_vector); + // read first byte of interrupt vector + self.address_bus = OFFSET_INT_VECTOR; + } + 1 => { + // read second byte of interrupt vector + self.address_bus = OFFSET_INT_VECTOR + 1; + } + 0 => { + self.int_vector |= data_bus as u16; + println!("Loaded interrupt vector of 0x{:04x}", self.int_vector); + self.pc = self.reset_vector; + println!("Set PC to Reset Vector. Giddy-up!"); + } + _ => { + } + } + self.microcode_step -= 1; + } + (self.address_bus, self.data_bus, self.read_signal) + } +} diff --git a/core/src/mos6502cpu/tick_stages.rs b/core/src/mos6502cpu/tick_stages.rs new file mode 100644 index 0000000..9c523d8 --- /dev/null +++ b/core/src/mos6502cpu/tick_stages.rs @@ -0,0 +1,19 @@ + +/// Mos6502TickStates +/// +/// The set of what a tick can be doing +/// +enum Mos6502TickStates { + /// Loading the first byte into the IR + LoadingInstruction, + /// Loading an 8 bit parameter + Loading8BitParameter, + /// Loading the MSB 8 bits + Loading16BitParameter1, + /// Loading the LSB 8 bits + Loading16BitParameter2, + /// Stalling for accurate emulation + Stall(u8), + /// Completed the instruction + Complete +} diff --git a/core/src/periph/at28c256/mod.rs b/core/src/periph/at28c256/mod.rs index bc2f44e..521318c 100644 --- a/core/src/periph/at28c256/mod.rs +++ b/core/src/periph/at28c256/mod.rs @@ -1,5 +1,6 @@ -mod default; -mod rom_chip; +pub mod default; +pub mod rom_chip; +pub mod tick; use crate::constants::constants_system::SIZE_32KB; use crate::periph::rom_chip::RomChip; diff --git a/core/src/periph/at28c256/tick.rs b/core/src/periph/at28c256/tick.rs new file mode 100644 index 0000000..96ff064 --- /dev/null +++ b/core/src/periph/at28c256/tick.rs @@ -0,0 +1,31 @@ +use crate::periph::at28c256::At28C256; +use crate::periph::hm62256::Hm62256; + +impl At28C256 { + fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) { + if !read_mode { + // has to be read mode. its a rom. + return (address_bus, data_bus) + } + (address_bus, self.data[address_bus as usize]) + } +} + + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn smoke() { assert!(true); } + + #[test] + fn write_to_memory_read_back_works_at_0() { + let mut rom = At28C256::default(); + + rom.tick(0x0000, 0xab, false); + let (_, new_data) = rom.tick(0x0000, 0x00, true); + + assert_eq!(new_data, 0xab); + } +} \ No newline at end of file diff --git a/core/src/periph/hm62256.rs b/core/src/periph/hm62256/mod.rs similarity index 73% rename from core/src/periph/hm62256.rs rename to core/src/periph/hm62256/mod.rs index de273c9..aed7f4b 100644 --- a/core/src/periph/hm62256.rs +++ b/core/src/periph/hm62256/mod.rs @@ -1,10 +1,13 @@ // HM62256 Static Ram +pub mod ramchip; +pub mod romchip; +pub mod tick; + use crate::constants::constants_system::SIZE_32KB; use crate::periph::ram_chip::RamChip; use crate::periph::rom_chip::RomChip; use log::debug; - pub struct Hm62256 { pub(crate) base_offset: u16, pub(crate) data: Box<[u8]>, @@ -23,27 +26,6 @@ impl Default for Hm62256 { } } -impl RomChip for Hm62256 { - fn read(&self, offset: &u16) -> u8 { - // loops memory around past 32k - let effective = *offset as i32 % SIZE_32KB as i32; - self.data[effective as usize] - } - - fn program(_: &[u8; SIZE_32KB]) -> Box { - debug!("Dont program ram."); - Hm62256::default().into() - } -} - -impl RamChip for Hm62256 { - fn write(&mut self, offset: &u16, value: &u8) { - let effective = *offset as i32 % SIZE_32KB as i32; - println!("Writing at E[{effective:04x}] / O[{offset:04x}]"); - self.data[effective as usize] = *value; - } -} - #[cfg(test)] mod test { use super::*; @@ -61,7 +43,7 @@ mod test { // 100,000 random read/writes to ram that all read back right for _ in 0..100_000 { let mut offset: u16 = random(); - println!("SIze = {SIZE_32KB}"); + println!("Size = {SIZE_32KB}"); let value: u8 = random(); println!("Wrote [{value:02x}] to [{offset:04x}]"); ram.write(&offset, &value); diff --git a/core/src/periph/hm62256/ramchip.rs b/core/src/periph/hm62256/ramchip.rs new file mode 100644 index 0000000..af27c86 --- /dev/null +++ b/core/src/periph/hm62256/ramchip.rs @@ -0,0 +1,12 @@ +use crate::constants::constants_system::SIZE_32KB; +use crate::periph::hm62256::Hm62256; +use crate::periph::ram_chip::RamChip; + +impl RamChip for Hm62256 { + fn write(&mut self, offset: &u16, value: &u8) { + let effective = *offset as i32 % SIZE_32KB as i32; + println!("Writing at E[{effective:04x}] / O[{offset:04x}]"); + self.data[effective as usize] = *value; + } +} + diff --git a/core/src/periph/hm62256/romchip.rs b/core/src/periph/hm62256/romchip.rs new file mode 100644 index 0000000..66b240b --- /dev/null +++ b/core/src/periph/hm62256/romchip.rs @@ -0,0 +1,19 @@ +use log::debug; +use crate::constants::constants_system::SIZE_32KB; +use crate::periph::hm62256::Hm62256; +use crate::periph::rom_chip::RomChip; + +impl RomChip for Hm62256 { + + + fn read(&self, offset: &u16) -> u8 { + // loops memory around past 32k + let effective = *offset as i32 % SIZE_32KB as i32; + self.data[effective as usize] + } + + fn program(_: &[u8; SIZE_32KB]) -> Box { + debug!("Dont program ram."); + Hm62256::default().into() + } +} diff --git a/core/src/periph/hm62256/tick.rs b/core/src/periph/hm62256/tick.rs new file mode 100644 index 0000000..b66af83 --- /dev/null +++ b/core/src/periph/hm62256/tick.rs @@ -0,0 +1,33 @@ +use crate::periph::hm62256::Hm62256; + +impl Hm62256 { + fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) { + let new_data_bus = if read_mode { + // reading from ram + self.data[address_bus as usize] + } else { + // writing to ram + self.data[address_bus as usize] = data_bus.into(); + data_bus + }; + (address_bus, new_data_bus) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn smoke() { assert!(true); } + + #[test] + fn write_to_memory_read_back_works_at_0() { + let mut ram = Hm62256::default(); + + ram.tick(0x0000, 0xab, false); + let (_, new_data) = ram.tick(0x0000, 0x00, true); + + assert_eq!(new_data, 0xab); + } +} diff --git a/macroquad/Cargo.toml b/macroquad/Cargo.toml index 9aea351..399f198 100644 --- a/macroquad/Cargo.toml +++ b/macroquad/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2024" [dependencies] -macroquad.workspace = true \ No newline at end of file +macroquad.workspace = true +core = { path = "../core" } \ No newline at end of file diff --git a/macroquad/src/bin/rom_only.rs b/macroquad/src/bin/rom_only.rs new file mode 100644 index 0000000..6d6ae69 --- /dev/null +++ b/macroquad/src/bin/rom_only.rs @@ -0,0 +1,31 @@ +use macroquad::prelude::*; +use core::computers::rom_only::backplane::Backplane; +pub struct UiState { + display_offset: u16, + current_offset: u16 +} + +#[macroquad::main("Rom_Only")] +async fn main() { + + let mut backplane = Backplane::new(); + let mut state = UiState { display_offset: 0x00, current_offset: 0x00 }; + + loop { + clear_background(BLUE); + + draw_text("ROM ONLY", 20.0, 20.0, 30.0, DARKGRAY); + + backplane.tick(); + + draw_text( + format!("Display Offset: 0x{:04x}", state.display_offset).as_str(), 20.0, 60.0, 30.0, DARKGRAY + ); + + draw_text( + format!("Current Offset: 0x{:04x}", state.current_offset).as_str(), 20.0, 100.0, 30.0, DARKGRAY + ); + + next_frame().await + } +}