24 Commits

Author SHA1 Message Date
tmerritt 6fcf1547d1 more fixed stuff 2025-07-16 15:01:16 -04:00
tmerritt ff43a99e0c boxswap 2025-07-15 08:19:32 -04:00
tmerritt b7e161ef0b more instructions decompiled 2025-07-09 14:53:02 -04:00
tmerritt 258e4dc59b box swap 2025-07-09 10:36:21 -04:00
tmerritt a5042383c9 improved de6502 - needs to write to disk instead of cli 2025-07-09 08:11:49 -04:00
tmerritt 8c08555003 writes bins better now 2025-07-07 16:28:13 -04:00
tmerritt 9c672741ed start of rom_only PC 2025-07-07 07:36:41 -04:00
tmerritt b9242b1943 rustfmt cleanup 2025-07-06 13:38:55 -04:00
tmerritt cf14804df2 more stuff 2025-07-05 11:49:04 -04:00
tmerritt 2cfd570789 more stuff i worked on 2025-07-03 16:32:55 -04:00
tmerritt e4405cc225 attempt chatgpt emulator for display 2025-07-03 11:41:54 -04:00
tmerritt 8509b20109 improved matrix display stuff 2025-07-03 09:29:46 -04:00
tmerritt 1a53f1d782 more instructions and tests passing. 2025-07-01 16:58:59 -04:00
tmerritt 9b9462c98c fixed size from 32mb to 32kb 2025-07-01 13:14:01 -04:00
tmerritt f9c938757f box swap 2025-07-01 13:08:23 -04:00
tmerritt d97774e97b some instructions have code and tests 2025-06-30 13:55:35 -04:00
tmerritt 9e0e8b5910 closer to ticking.
has microsteps in the UI
decodes from a NOP only binary
some basic instructions are starting to move data around
2025-06-30 08:50:18 -04:00
tmerritt 8ed93fc90e closer to being able to run a cycle? 2025-06-30 07:17:17 -04:00
tmerritt 0c475127f6 BUGFIX: Decoder now decodes instructions without parameters 2025-06-29 10:55:47 -04:00
tmerritt e5c2319803 removes sccache
updates display of ben eater pc
doesnt blow up when creating a rom chip anymore
doesnt blow up when creating a pc anymore
2025-06-28 12:37:01 -04:00
tmerritt d89fc1cd2b decodes all instructions i think.
start of a beneater pc
2025-06-27 12:14:54 -04:00
tmerritt 57544589b3 applies chatgpt suggestions.
...
does not appear to decode everything
2025-06-25 09:34:19 -04:00
tmerritt 1b2fb2c221 from_bytes needs tests
instruction.to_string() passes all its tests.
2025-06-24 11:05:02 -04:00
tmerritt 768e83dfb8 more decode and encode code 2025-06-23 15:35:36 -04:00
45 changed files with 514 additions and 3433 deletions
+5
View File
@@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/mos6502.iml" filepath="$PROJECT_DIR$/.idea/mos6502.iml" />
</modules>
</component>
</project>
+13
View File
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="EMPTY_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/cli/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/core/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/macroquad/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
Generated
+208 -2885
View File
File diff suppressed because it is too large Load Diff
+1 -5
View File
@@ -8,10 +8,6 @@ fn main() {
let mut backplane = Backplane::new();
for i in 0..12 {
backplane.tick();
}
//backplane.load_rom();
println!("Backplane is live.");
@@ -20,7 +16,7 @@ fn main() {
new_program[(OFFSET_RESET_VECTOR + 1 - SIZE_32KB as u16) as usize] = 0x60;
println!("Set offset in rom...");
println!(
"VALUE AT OFFSET_RESET_VECTOR = 0x{:04x} ",
"VALUE AT OFFSET_RESET_VECTOR = 0x{:02x} ",
new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize]
);
// println!("{:?}", new_program);
+2 -2
View File
@@ -19,7 +19,7 @@ pub struct Backplane {
// pub for dev
pub cpu: Mos6502Cpu,
pub via: VIA6522,
pub memory: Box<[u8]>,
pub memory: Box<[u8; SIZE_32KB]>,
pub rom: At28C256,
data_bus: u8,
address_bus: u16
@@ -38,7 +38,7 @@ impl Backplane {
}
pub fn load_rom(&mut self, to_load: &[u8; SIZE_32KB]) {
self.rom.program((*to_load).into());
self.rom.program(to_load);
}
pub fn tick(&mut self) {
-1
View File
@@ -201,7 +201,6 @@ mod tests {
}
#[test]
#[ignore]
fn test_write_data() {
let mut lcd = HD44780::new();
lcd.set_data_bus(0x41); // 'A'
-4
View File
@@ -162,7 +162,6 @@ mod tests {
}
#[test]
#[ignore]
fn test_timer1_write_and_tick() {
let mut via = VIA6522::new();
@@ -181,7 +180,6 @@ mod tests {
}
#[test]
#[ignore]
fn test_timer2_write_and_tick() {
let mut via = VIA6522::new();
via.t2_enabled = true;
@@ -196,7 +194,6 @@ mod tests {
}
#[test]
#[ignore]
fn test_interrupt_enable_disable() {
let mut via = VIA6522::new();
@@ -208,7 +205,6 @@ mod tests {
}
#[test]
#[ignore]
fn test_clear_interrupt_flags() {
let mut via = VIA6522::new();
via.ifr = 0xFF;
+2
View File
@@ -18,4 +18,6 @@ fn main() {
for (op, bytes) in instructions {
assert_eq!(Instruction::decode(bytes), Some(op));
}
// let instruction = Instruction::decode(&[0xea]);
// println!("NOP Decoded -> {:?}", instruction);
}
+1 -1
View File
@@ -12,7 +12,7 @@ fn main() {
kim.tick();
num_ticks += 1;
if num_ticks == MOS6502_RESET_CYCLE_COUNT {
if num_ticks == 11 {
println!("Got our 11 ticks. time to hotwire this pc.");
kim.running = true;
kim.dump();
+1 -28
View File
@@ -1,5 +1,3 @@
use core::computers::ram_rom::backplane::RamRomComputer;
use core::periph::backplane::Backplane;
use std::fs;
fn main() {
@@ -20,29 +18,4 @@ fn main() {
};
let mut computer = RamRomComputer::new();
// Read byte from ROM 0x4000
println!("-- ");
computer.set_read_mode(true);
computer.set_address_bus(0x4020);
computer.tick();
println!("-- ");
// Data Bus contains value from ROM
let read_from_rom = computer.data_bus();
// Write byte to RAM 0x0000
computer.set_read_mode(false);
computer.set_address_bus(0x0001);
computer.tick();
println!("-- ");
// Read byte from RAM
computer.set_read_mode(true);
computer.set_address_bus(0x0001);
computer.tick();
println!("-- ");
let read_from_ram = computer.data_bus();
assert_eq!(read_from_rom, read_from_ram);
println!("Test passed. We read the same from ROM as we did from RAM - {} == {}", read_from_rom, read_from_ram);
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
use std::fs;
use clap::Parser;
use core::computers::rom_only::RomOnlyComputer;
use core::computers::rom_only::backplane::RomOnlyComputer;
use core::periph::backplane::Backplane;
#[derive(Parser)]
@@ -44,4 +44,4 @@ fn main() {
println!("COMPUTER: Read {:02x} from ROM", rom_only.data_bus()) ;
println!("COMPUTER: Read {:04x} from Address Bus", rom_only.address_bus());
println!("----");
}
}
+25
View File
@@ -0,0 +1,25 @@
use crate::mos6502cpu::cpu::Mos6502Cpu;
use crate::periph::ram_chip::RamChip;
/// BackplaneBuilder
///
/// Builds a Backplane for a 6502 Emulated PC
struct BackplaneBuilder {
cpu: Mos6502Cpu,
// ram_modules: Vec<dyn RamChip>
}
impl BackplaneBuilder {
pub fn add_cpu(mut self, new_cpu: Mos6502Cpu) -> Self {
self.cpu = new_cpu;
self
}
pub fn add_ram(mut self, new_ram: impl RamChip) -> Self {
// self.ram_modules.push(new_ram);
self
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ pub mod reset;
use std::fs;
use std::path::Path;
use crate::constants::constants_system::SIZE_1KB;
use crate::mos6502cpu::Mos6502Cpu;
use crate::mos6502cpu::cpu::Mos6502Cpu;
use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256;
use crate::periph::kim1_keypad::Kim1Keypad;
+2 -24
View File
@@ -24,28 +24,7 @@ impl Backplane for RamRomComputer {
}
fn tick(&mut self) {
println!("Preparing to tick the backplane. - ${:04x} ${:02x} {}", self.address_bus, self.data_bus, self.read_mode);
// who are we talking to?
match self.address_bus {
0x0000..=0x3fff => {
// RAM
println!("ADDRESSING RAM");
let (ram_address_bus, ram_data_bus) = self.ram.tick(self.address_bus, self.data_bus, self.read_mode, true);
if self.read_mode {
self.data_bus = ram_data_bus;
}
},
0x4000..=0x7fff => {
// ROM
println!("ADDRESSING ROM");
let (rom_address_bus, rom_data_bus) = self.rom.tick(self.address_bus, self.data_bus, self.read_mode);
self.data_bus = rom_data_bus;
}
_ => {
// Out of range
}
}
todo!()
}
fn set_read_mode(&mut self, new_mode: bool) {
self.read_mode = new_mode;
@@ -62,9 +41,8 @@ impl Backplane for RamRomComputer {
impl RamRomComputer {
pub fn new() -> RamRomComputer {
let rom = At28C256::new(0x4000, 0x7fff, (0..255).collect());
RamRomComputer {
rom,
rom: At28C256::default(),
ram: Hm62256::default(),
data_bus: 0x00,
address_bus: 0x0000,
+31 -1
View File
@@ -1,16 +1,27 @@
use crate::computers::rom_only::RomOnlyComputer;
use crate::constants::constants_system::{SIZE_32KB, SIZE_64KB};
use crate::periph::at28c256::At28C256;
use crate::periph::backplane::Backplane;
use crate::periph::rom_chip::RomChip;
pub struct RomOnlyComputer {
rom: At28C256,
data_bus: u8,
address_bus: u16,
read_mode: bool,
}
impl Backplane for RomOnlyComputer {
fn data_bus(&self) -> u8 { self.data_bus }
fn address_bus(&self) -> u16 { self.address_bus }
fn read_mode(&self) -> bool { self.read_mode }
fn set_read_mode(&mut self, new_mode: bool) {
self.read_mode = new_mode
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
@@ -27,3 +38,22 @@ impl Backplane for RomOnlyComputer {
println!("COMPUTER: Done ticking.");
}
}
impl RomOnlyComputer {
pub fn new() -> RomOnlyComputer {
let mut working = vec![0x00u8; SIZE_32KB];
for index in 0..SIZE_32KB {
working[index] = index as u8;
}
RomOnlyComputer::program(working)
}
pub fn program(rom: Vec<u8>) -> RomOnlyComputer {
RomOnlyComputer {
rom: At28C256::new(0x000, 0x3fff, rom),
address_bus: 0x0000,
data_bus: 0x00,
read_mode: true,
}
}
}
@@ -1,13 +0,0 @@
use crate::computers::rom_only::RomOnlyComputer;
impl RomOnlyComputer {
pub fn debug_memory(&self, start_offset: u16, end_offset: u16) -> Vec<u8> {
let mut data = vec![];
let size = end_offset - start_offset;
for index in 0..size {
println!("Index {index} for {}", index + start_offset);
}
data
}
}
-13
View File
@@ -1,14 +1 @@
use crate::periph::at28c256::At28C256;
pub mod backplane;
pub mod new;
pub mod program;
pub mod debug_memory;
mod rom_chunks;
pub struct RomOnlyComputer {
pub(crate) rom: At28C256,
pub(crate) data_bus: u8,
pub(crate) address_bus: u16,
pub(crate) read_mode: bool,
}
-13
View File
@@ -1,13 +0,0 @@
use crate::computers::rom_only::RomOnlyComputer;
use crate::constants::constants_system::SIZE_32KB;
impl RomOnlyComputer {
pub fn new() -> RomOnlyComputer {
let mut working = vec![0x00u8; SIZE_32KB];
for index in 0..SIZE_32KB {
working[index] = index as u8;
}
RomOnlyComputer::program(working)
}
}
-14
View File
@@ -1,14 +0,0 @@
use crate::computers::rom_only::RomOnlyComputer;
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
impl RomOnlyComputer {
pub fn program(rom: Vec<u8>) -> RomOnlyComputer {
RomOnlyComputer {
rom: At28C256::new(0x000, 0x3fff, rom),
address_bus: 0x0000,
data_bus: 0x00,
read_mode: true,
}
}
}
@@ -1,8 +0,0 @@
use std::slice::Chunks;
use crate::computers::rom_only::RomOnlyComputer;
impl RomOnlyComputer {
pub fn rom_chunks(&self, size: usize) -> Chunks<u8> {
self.rom.chunks(size)
}
}
-5
View File
@@ -9,8 +9,3 @@ pub const OFFSET_RESET_VECTOR: u16 = 0xfffc;
pub const OFFSET_RESET_VECTORS: usize = 0xffff;
pub const OFFSET_INT_VECTOR: u16 = 0xfffe;
pub const OFFSET_INT_VECTORS: usize = 0xfffe;
// 7 cycles for internal reset
// 6 to read the vectors from RAM
pub const MOS6502_RESET_CYCLE_COUNT: u16 = 8;
+8 -8
View File
@@ -245,7 +245,7 @@ mod test {
vec![0x10, 0xab],
Instruction {
op: BPL,
mode: Immediate,
mode: Implied,
operand: Operand::Byte(0xab),
},
),
@@ -253,7 +253,7 @@ mod test {
vec![0x30, 0xab],
Instruction {
op: BMI,
mode: Immediate,
mode: Implied,
operand: Operand::Byte(0xab),
},
),
@@ -261,7 +261,7 @@ mod test {
vec![0x50, 0xab],
Instruction {
op: BVC,
mode: Immediate,
mode: Implied,
operand: Operand::Byte(0xab),
},
),
@@ -269,7 +269,7 @@ mod test {
vec![0x70, 0xab],
Instruction {
op: BVS,
mode: Immediate,
mode: Implied,
operand: Operand::Byte(0xab),
},
),
@@ -277,7 +277,7 @@ mod test {
vec![0x90, 0xab],
Instruction {
op: BCC,
mode: Immediate,
mode: Implied,
operand: Operand::Byte(0xab),
},
),
@@ -285,7 +285,7 @@ mod test {
vec![0xb0, 0xab],
Instruction {
op: BCS,
mode: Immediate,
mode: Implied,
operand: Operand::Byte(0xab),
},
),
@@ -293,7 +293,7 @@ mod test {
vec![0xd0, 0xab],
Instruction {
op: BNE,
mode: Immediate,
mode: Implied,
operand: Operand::Byte(0xab),
},
),
@@ -301,7 +301,7 @@ mod test {
vec![0xf0, 0xab],
Instruction {
op: BEQ,
mode: Immediate,
mode: Implied,
operand: Operand::Byte(0xab),
},
),
+1 -1
View File
@@ -215,7 +215,7 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
table[ISA_OP_BCC as usize] = Some(OpInfo {
operation: BCC,
mode: AddressMode::Immediate,
mode: AddressMode::Implied,
length: 2,
cycles: 2,
format_prefix: "BCC $",
+1 -1
View File
@@ -11,4 +11,4 @@ pub mod op_info;
pub mod operand;
pub mod operation;
pub mod periph;
pub mod traits;
mod backplane;
-20
View File
@@ -1,20 +0,0 @@
use crate::mos6502cpu::Mos6502Cpu;
use crate::traits::bus_device::BusDevice;
impl BusDevice for Mos6502Cpu {
fn address_bus(&self) -> u16 {
self.address_bus
}
fn data_bus(&self) -> u8 {
self.data_bus
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value;
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value;
}
}
+114 -26
View File
@@ -9,17 +9,93 @@ use crate::op_info::OpInfo;
use crate::operand::Operand;
use crate::operation::Operation;
use log::trace;
use crate::mos6502cpu::Mos6502Cpu;
use crate::mos6502cpu::tick_stages::Mos6502TickStates;
use crate::mos6502cpu::tick_stages::Mos6502TickStates::*;
enum Mos6502Registers {
A,
X,
Y
pub struct Mos6502Cpu {
pub(crate) memory: [u8; SIZE_64KB],
/// accumulator
pub(crate) a: u8,
/// x register
pub(crate) x: u8,
/// y register
pub(crate) y: u8,
/// cpu flags
pub(crate) flags: Mos6502Flags,
/// program counter
pub pc: u16,
/// stack offset
pub(crate) s: u8,
pub microcode_step: u8,
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,
pub(crate) nmi_vector: u16,
pub tick_stage: Mos6502TickStates
}
impl Mos6502Cpu {
/// set_data_bus
///
/// Sets data on the data bus.
/// Used when CPU is in "R" mode
pub fn set_data_bus(&mut self, to_set: u8) {
self.data_bus = to_set;
}
}
impl Default for Mos6502Cpu {
fn default() -> Self {
let mut working = Mos6502Cpu {
memory: [0x00; SIZE_64KB],
a: 0x00,
x: 0x00,
y: 0x00,
flags: Default::default(),
pc: 0xfffd,
s: 0x00,
microcode_step: 0x00,
address_bus: 0x00,
data_bus: 0x00,
ir: Instruction {
op: Operation::NOP,
mode: AddressMode::Implied,
operand: Operand::None,
},
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].clone().unwrap(),
has_reset: false,
iv: 0xfffe,
cycle_carry: 0x0000,
ir_bytes: [0x00; 4],
read_signal: true,
reset_vector: 0x0000,
int_vector: 0x0000,
nmi_vector: 0x0000,
tick_stage: LoadingInstruction
};
working.reset_cpu();
working
}
}
impl Mos6502Cpu {
pub fn address_bus(&self) -> u16 {
self.address_bus
}
pub fn data_bus(&self) -> u8 {
self.data_bus
}
//
// fn read_word(&self, offset: &u16) -> u16 {
// println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1);
@@ -32,22 +108,6 @@ impl Mos6502Cpu {
// result
// }
pub fn peek_register(&self, register_to_peek: Mos6502Registers) -> u8 {
match register_to_peek {
Mos6502Registers::A => self.a,
Mos6502Registers::X => self.x,
Mos6502Registers::Y => self.y
}
}
pub fn poke_register(&mut self, register_to_poke: Mos6502Registers, new_value: u8) {
match register_to_poke {
Mos6502Registers::A => self.a = new_value,
Mos6502Registers::X => self.x = new_value,
Mos6502Registers::Y => self.y = new_value
}
}
pub fn peek_flag(&self, flag_to_read: Mos6502Flag) -> bool {
self.flags.flag(flag_to_read)
}
@@ -59,15 +119,42 @@ impl Mos6502Cpu {
}
}
pub fn peek_memory(&self, offset: u16) -> u8 {
pub fn peek(&self, offset: u16) -> u8 {
self.memory[offset as usize]
}
pub fn poke_memory(&mut self, offset: u16, value: u8) {
pub fn poke(&mut self, offset: u16, value: u8) {
println!("Setting memory at {offset:04x} to {value:02x}");
self.memory[offset as usize] = value
}
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
}
pub fn poke_x(&mut self, new_x: u8) {
println!("Updating register X from [{}] to [{}]", self.x, new_x);
self.x = new_x
}
pub fn peek_y(&self) -> u8 {
self.y
}
pub fn poke_y(&mut self, new_y: u8) {
self.y = new_y
}
fn advance_pc(&mut self, how_far: u16) {
self.pc += how_far;
}
@@ -120,6 +207,7 @@ impl Mos6502Cpu {
}
}
if self.microcode_step == 0 {
println!("OUT OF MICROSTEPS. Decoding the next instruction");
let offset = self.pc as usize;
@@ -233,7 +321,7 @@ impl Mos6502Cpu {
Operation::DEX => {
if self.microcode_step == 1 {
let (new_x, new_carry) = self.x.overflowing_sub(1);
self.poke_register(Mos6502Registers::X, new_x);
self.poke_x(new_x);
self.poke_flag(Carry, new_carry);
}
}
@@ -247,7 +335,7 @@ impl Mos6502Cpu {
Operation::INX => {
if self.microcode_step == 1 {
let (new_x, new_carry) = self.x.overflowing_add(1);
self.poke_register(Mos6502Registers::X, new_x);
self.poke_x(new_x);
self.poke_flag(Carry, new_carry);
self.address_bus = self.pc;
self.data_bus = 0x00;
@@ -256,7 +344,7 @@ impl Mos6502Cpu {
Operation::INY => {
if self.microcode_step == 1 {
let (new_y, new_carry) = self.y.overflowing_add(1);
self.poke_register(Mos6502Registers::Y, new_y);
self.poke_y(new_y);
self.poke_flag(Carry, new_carry);
self.address_bus = self.pc;
self.data_bus = 0x00;
+1 -1
View File
@@ -1,4 +1,4 @@
use crate::mos6502cpu::Mos6502Cpu;
use crate::mos6502cpu::cpu::Mos6502Cpu;
impl Mos6502Cpu {
/// dump_data
-43
View File
@@ -1,43 +0,0 @@
use crate::address_mode::AddressMode;
use crate::constants::constants_isa_op::ISA_OP_NOP;
use crate::constants::constants_system::SIZE_64KB;
use crate::instruction::Instruction;
use crate::instruction_table::INSTRUCTION_TABLE;
use crate::mos6502cpu::Mos6502Cpu;
use crate::mos6502cpu::tick_stages::Mos6502TickStates::LoadingInstruction;
use crate::operand::Operand;
use crate::operation::Operation;
impl Default for Mos6502Cpu {
fn default() -> Self {
let mut working = Mos6502Cpu {
memory: [0x00; SIZE_64KB],
a: 0x00,
x: 0x00,
y: 0x00,
flags: Default::default(),
pc: 0xfffd,
s: 0x00,
microcode_step: 0x00,
address_bus: 0x00,
data_bus: 0x00,
ir: Instruction {
op: Operation::NOP,
mode: AddressMode::Implied,
operand: Operand::None,
},
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].clone().unwrap(),
has_reset: false,
iv: 0xfffe,
cycle_carry: 0x0000,
ir_bytes: [0x00; 4],
read_signal: true,
reset_vector: 0x0000,
int_vector: 0x0000,
nmi_vector: 0x0000,
tick_stage: LoadingInstruction
};
working.reset_cpu();
working
}
}
+1 -39
View File
@@ -1,44 +1,6 @@
use crate::constants::constants_system::SIZE_64KB;
use crate::instruction::Instruction;
use crate::mos6502cpu::tick_stages::Mos6502TickStates;
use crate::mos6502flags::Mos6502Flags;
use crate::op_info::OpInfo;
pub mod cpu;
pub mod new;
pub mod tick2;
pub mod dbg;
pub mod tick_stages;
pub mod default;
pub mod bus_device;
pub struct Mos6502Cpu {
pub(crate) memory: [u8; SIZE_64KB],
/// accumulator
pub(crate) a: u8,
/// x register
pub(crate) x: u8,
/// y register
pub(crate) y: u8,
/// cpu flags
pub(crate) flags: Mos6502Flags,
/// program counter
pub pc: u16,
/// stack offset
pub(crate) s: u8,
pub microcode_step: u8,
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,
pub(crate) nmi_vector: u16,
pub tick_stage: Mos6502TickStates
}
+3 -3
View File
@@ -1,5 +1,5 @@
use crate::constants::constants_system::{MOS6502_RESET_CYCLE_COUNT, OFFSET_RESET_VECTOR, SIZE_64KB};
use crate::mos6502cpu::Mos6502Cpu;
use crate::constants::constants_system::{OFFSET_RESET_VECTOR, SIZE_64KB};
use crate::mos6502cpu::cpu::Mos6502Cpu;
impl Mos6502Cpu {
pub fn new() -> Mos6502Cpu {
@@ -14,7 +14,7 @@ impl Mos6502Cpu {
}
pub(crate) fn reset_cpu(&mut self) {
self.microcode_step = MOS6502_RESET_CYCLE_COUNT as u8;
self.microcode_step = 7 + 6;
// self = &mut Mos6502Cpu::default();
println!("Should tick 7 times, then 6 cycles to read the reset and int vectors.");
// read the value at 0xfffa 0xfffb for our NMI vector.
+61 -71
View File
@@ -1,69 +1,9 @@
use crate::constants::constants_system::{OFFSET_INT_VECTOR, OFFSET_RESET_VECTOR};
use crate::mos6502cpu::Mos6502Cpu;
use crate::mos6502cpu::cpu::Mos6502Cpu;
enum Mos6502ResetSteps {
/// there are 6 of these
DummyRead(u8),
ReadRstVectorLow,
ReadRstVectorHigh,
ReadPcLow,
ReadPcHigh
}
impl Mos6502Cpu {
fn reset_step(&mut self, address_bus: u16, data_bus: u8, read: bool) -> (u16, u8, bool) {
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 {
6 => {
// NMI High byte
}
5 => {
// NMI low byte
}
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;
println!("Loaded reset vector of 0x{:04x}", self.reset_vector);
// 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!");
println!("START HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK");
// the KIM-1 uses 0x0000 for its initial PC
self.pc = 0x0000;
println!("END HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK");
self.has_reset = true;
}
_ => {
}
}
if self.microcode_step > 0 {
self.microcode_step -= 1;
}
(address_bus, data_bus, read)
}
/// AccurateTick
///
/// In: address_bus > Address of data operationm
@@ -76,16 +16,66 @@ impl Mos6502Cpu {
/// 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) {
println!("STARTING TICK2");
if !self.has_reset { return self.reset_step(address_bus, data_bus, self.read_signal) }
// 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;
println!("READ 0x{read_data:02x} from data bus.");
self.data_bus = read_data;
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;
println!("READ 0x{read_data:02x} from data bus.");
self.data_bus = read_data;
} else {
// we are writing to the bus.
}
} else {
// we are writing to the bus.
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 {
6 => {
// NMI High byte
}
5 => {
// NMI low byte
}
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;
println!("Loaded reset vector of 0x{:04x}", self.reset_vector);
// 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!");
println!("START HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK");
// the KIM-1 uses 0x0000 for its initial PC
self.pc = 0x0000;
println!("END HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK");
self.has_reset = true;
}
_ => {
}
}
if self.microcode_step > 0 {
self.microcode_step -= 1;
}
}
(self.address_bus, self.data_bus, self.read_signal)
}
-37
View File
@@ -1,37 +0,0 @@
use std::slice::Chunks;
use crate::periph::at28c256::At28C256;
impl At28C256 {
pub fn chunks(&self, size: usize) -> Chunks<u8> {
self.data.chunks(size)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() { assert!(true); }
#[test]
fn full_chunks_come_back_ok() {
let test_data = (0..255).collect();
let mut chip = At28C256::new(0x0000, 0x3fff, test_data);
let chunks = chip.chunks(16);
assert_eq!(chunks.len(), 16);
}
#[test]
fn partial_blocks_come_back_ok() {
let test_data = (0..=3).collect();
let mut chip = At28C256::new(0x0000, 0x3fff, test_data);
let chunks = chip.chunks(16);
assert_eq!(chunks.len(), 1);
for chunk in chunks {
assert_eq!(chunk.len(), 4);
}
}
}
+2 -4
View File
@@ -1,15 +1,13 @@
use crate::periph::at28c256::At28C256;
pub struct At28C256State {
offset: u16,
max_offset: u16
offset: u16
}
impl At28C256 {
pub fn dump(&self) -> At28C256State {
At28C256State {
offset: self.offset,
max_offset: self.max_offset
offset: self.offset
}
}
}
+4 -5
View File
@@ -1,11 +1,10 @@
pub mod default;
pub mod rom_chip;
pub mod tick;
pub mod new;
pub mod program;
pub mod dump;
pub mod checksum;
pub mod blocks;
mod new;
mod program;
mod dump;
mod checksum;
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::rom_chip::RomChip;
+2 -22
View File
@@ -2,29 +2,9 @@ use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
impl At28C256 {
pub fn program(&mut self, new_program: Box<[u8]>) {
pub fn program(&mut self, new_program: &[u8; SIZE_32KB]) {
// panic!("FAIL. Cant program the chip.");
// println!("PROGRAMMING {:?}", new_program);
self.data = new_program;
}
}
#[cfg(test)]
mod test {
use crate::periph::rom_chip::RomChip;
use super::*;
#[test]
fn smoke() { assert!(true) }
#[test]
fn programming_chip_changes_contents() {
let mut chip = At28C256::new(0x0000, 0x3fff, vec![]);
assert_eq!(0x00, chip.read(&0x0000));
let new_data: Vec<u8> = vec![0xff, 0xff, 0xff, 0xff];
chip.program(new_data.into());
assert_eq!(0xff, chip.read(&0x0000));
self.data = Box::new(*new_program);
}
}
+1 -21
View File
@@ -3,30 +3,10 @@ use crate::periph::at28c256::At28C256;
use crate::periph::rom_chip::RomChip;
impl RomChip for At28C256 {
/// read
///
/// Reads a byte from memory.
/// Returns a 0x00 if there is no data at that location but is still in ROM address range
fn read(&self, offset: &u16) -> u8 {
println!("STARTING READ FROM At28C256 ${:04x} | ${:04x} | ${:04x}", self.offset, offset, self.max_offset);
if offset < &self.offset || offset > &self.max_offset {
println!("Unable to read from ${offset:04x} as it it out of range.");
return 0x00;
} else {
println!("OK READ FROM GOOD AREA total len = {}", self.data.len());
}
if *offset >= self.data.len() as u16 {
0x00
} else {
self.data[*offset as usize]
}
self.data[*offset as usize]
}
/// program
///
/// Writes new data to the memory chip
fn program(new_data: &[u8; SIZE_32KB]) -> Box<At28C256> {
println!("Writing new chip.");
let mut working = At28C256::default();
+3 -5
View File
@@ -4,12 +4,11 @@ use crate::periph::hm62256::Hm62256;
impl At28C256 {
fn talking_to_me(&self, address: u16) -> bool {
//println!("Checking on {address:04x} in range of {:04x} {:04x}", self.offset, self.max_offset);
address >= self.offset && address < self.max_offset
}
pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) {
print!("At28C256: Tick starting for A${address_bus:04x} D${data_bus:02x} R{read_mode}");
println!("At28C256: Tick starting for A${address_bus:04x} D${data_bus:02x} R{read_mode}");
// we aren't being addressed
// OR
@@ -17,11 +16,9 @@ impl At28C256 {
if !self.talking_to_me(address_bus) ||
!read_mode {
// ...go away.
// println!("At28C256 Tick not for me.");
return (address_bus, data_bus)
}
// print!("At28C256 tick for me.");
let effective = address_bus - self.offset;
if effective < self.max_offset {
if effective < self.data.len() as u16 {
@@ -34,7 +31,8 @@ impl At28C256 {
return (address_bus, data_bus)
}
// print!("At28C256: Read... {:02x}", self.data_bus);
println!("At28C256: Read... {:02x}", self.data_bus);
println!("At28C256: Done with ticking the AtC256");
(address_bus, self.data_bus)
}
}
-1
View File
@@ -7,4 +7,3 @@ pub trait Backplane {
fn set_address_bus(&mut self, new_value: u16);
fn tick(&mut self);
}
+3 -5
View File
@@ -8,7 +8,7 @@ impl Hm62256 {
pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool, cs: bool) -> (u16, u8) {
println!("HM62256RAM TICK START -> 0x{address_bus:04x} 0x{data_bus:02x} {read_mode} {cs}");
if !(address_bus >= self.offset && address_bus < self.max_address()) {
if !(address_bus.gt( &self.offset) && address_bus.le(&self.max_address())) {
return (address_bus, data_bus);
}
@@ -17,7 +17,7 @@ impl Hm62256 {
let addr = address_bus.wrapping_sub(self.offset) + self.offset;
// did we want to talk to the chip...
if !cs {
if !cs {
return (address_bus, data_bus);
}
@@ -26,11 +26,9 @@ impl Hm62256 {
return (address_bus, data_bus);
}
// ok. lets see what we are dealing with
self.data_bus = if read_mode {
let new_value = self.data[addr as usize];
new_value
self.data[addr as usize]
} else {
// writing to ram
self.data[addr as usize] = data_bus.into();
-8
View File
@@ -1,8 +0,0 @@
pub trait BusDevice {
fn address_bus(&self) -> u16;
fn data_bus(&self) -> u8;
fn set_address_bus(&mut self, new_value: u16);
fn set_data_bus(&mut self, new_value: u8);
}
-1
View File
@@ -1 +0,0 @@
pub mod bus_device;
+1 -3
View File
@@ -6,6 +6,4 @@ edition = "2024"
[dependencies]
macroquad.workspace = true
core = { path = "../core" }
egui_extras = "0.32"
egui = "0.27"
eframe = "0.27"
egui-macroquad = "0.17"
-88
View File
@@ -1,88 +0,0 @@
use eframe::egui;
use core::computers::rom_only::RomOnlyComputer;
struct MyApp {
address: String,
data: String,
cpu_read: bool,
computer: RomOnlyComputer
}
impl Default for MyApp {
fn default() -> Self {
let rom_data = vec![0x01, 0x02, 0x03, 0x04];
Self {
address: String::new(),
data: String::new(),
cpu_read: false,
computer: RomOnlyComputer::program(rom_data), // Example memory: 0x00 to 0xFF
}
}
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Memory Inspector");
ui.horizontal(|ui| {
ui.label("Address:");
ui.text_edit_singleline(&mut self.address);
});
ui.horizontal(|ui| {
ui.label("Data:");
ui.text_edit_singleline(&mut self.data);
});
ui.checkbox(&mut self.cpu_read, "CPU Read");
if ui.button("Tick").clicked() {
println!(
"Ticked with Address: {}, Data: {}, CPU Read: {}",
self.address, self.data, self.cpu_read
);
}
ui.horizontal(|ui| {
ui.label(format!("Address Bus ${:?}", self.address).as_str());
ui.label(format!("Data Bus ${:?}", self.data).as_str());
});
ui.separator();
ui.label("Memory View (Hex Dump):");
egui::ScrollArea::vertical().show(ui, |ui| {
let bytes_per_row = 16;
for (i, chunk) in self.computer.rom_chunks(bytes_per_row).enumerate() {
let address = i * bytes_per_row;
let hex_values: String = chunk
.iter()
.map(|b| format!("{:02X} ", b))
.collect();
let ascii_values: String = chunk
.iter()
.map(|b| {
if b.is_ascii_graphic() {
*b as char
} else {
'.'
}
})
.collect();
ui.monospace(format!("{:08X}: {:<48} {}", address, hex_values, ascii_values));
}
});
});
}
}
fn main() -> eframe::Result<()> {
let options = eframe::NativeOptions::default();
eframe::run_native(
"Memory Inspector",
options,
Box::new(|_cc| Box::new(MyApp::default())),
)
}