decodes all instructions i think.

start of a beneater pc
This commit is contained in:
Trevor Merritt 2025-06-27 12:14:54 -04:00
parent 57544589b3
commit d89fc1cd2b
22 changed files with 311 additions and 35 deletions

8
Cargo.lock generated
View File

@ -79,6 +79,14 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "beneater"
version = "0.1.0"
dependencies = [
"core",
"macroquad 0.4.14",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"

View File

@ -2,7 +2,8 @@
members = [ members = [
"core", "core",
"cli", "cli",
"macroquad" "macroquad",
"beneater"
] ]
resolver="2" resolver="2"
@ -15,3 +16,4 @@ clap = { version = "4.5", features = ["derive"] }
# trevors_utilities = { git = "https://git.geekback.dev/tmerritt/trevors_utilities" } # trevors_utilities = { git = "https://git.geekback.dev/tmerritt/trevors_utilities" }
trevors_utilities = { path = "/home/tmerritt/Projects/trevors_utilities" } trevors_utilities = { path = "/home/tmerritt/Projects/trevors_utilities" }
lipsum = "0.9" lipsum = "0.9"
macroquad = "0.4"

8
beneater/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "beneater"
version = "0.1.0"
edition = "2024"
[dependencies]
core = { path = "../core" }
macroquad.workspace = true

View File

@ -0,0 +1,16 @@
// This is the GUI for the BenEater PC
use macroquad::prelude::*;
#[macroquad::main("Ben Eaters PC")]
async fn main() {
println!("Taxation is Theft");
let computer = BenEaterPC::new();
loop {
clear_background(BLUE);
draw_text("Ben Eater", 20.0, 20.0, 30.0, BLACK);
next_frame().await
}
}

1
beneater/src/lib.rs Normal file
View File

@ -0,0 +1 @@
pub mod parts;

View File

@ -0,0 +1,25 @@
use crate::parts::clock::Clock;
use core::mos6502cpu::Mos6502Cpu;
struct BenEaterPC {
clock: Clock,
cpu: Mos6502Cpu,
}
impl BenEaterPC {
pub fn new() -> Self {
BenEaterPC {
clock: Clock::new(),
cpu: Mos6502Cpu::default()
}
}
pub fn tick_system(&mut self) {
let (address, data, rw) = self.cpu.tick();
if self.cpu.microcode_step == 0 {
// tick the clock.
// tick the memory
// tick the VIA
}
}
}

View File

@ -0,0 +1,24 @@
pub struct Clock {
ticks: u32
}
impl Clock {
pub fn new() -> Self {
Clock {
ticks: 0
}
}
pub fn tick(&mut self) {
self.ticks += 1;
}
pub fn ticks(&self) -> u32 {
self.ticks
}
pub fn reset(&mut self) {
self.ticks = 0;
}
}

View File

@ -0,0 +1,3 @@
pub mod clock;
mod ben_eater_pc;
mod via6522;

View File

@ -0,0 +1,31 @@
#[derive(Default)]
pub struct Via6522 {
port_a_state: u8,
port_b_data: u8,
port_a_direction: u8,
port_b_direction: u8,
memory_offset: u16,
}
impl Via6522 {
pub fn new(offset: u16) -> Self {
Via6522 {
memory_offset: offset,
..Default::default()
}
}
pub fn set_a_direction(&mut self, new_direction: u8) {
}
// check for output pins and see what they say
pub fn update_pins(&mut self) {
}
// check for input mode pins and see what they say
pub fn read_pins(&self) {
}
}

View File

@ -4,8 +4,8 @@ use core::address_mode::AddressMode;
fn main() { fn main() {
println!("Taxation is Theft"); println!("Taxation is Theft");
Instruction::from_bytes(vec![0b11100011]); // Instruction::from_bytes(vec![0b11100011]);
let instruction = Instruction::ADC(AddressMode::Immediate(0x45)); // let instruction = Instruction::ADC(AddressMode::Immediate);
println!("Instruction = {:?}", instruction.to_string()); // println!("Instruction = {:?}", instruction.to_string());
} }

View File

@ -1,10 +1,4 @@
use std::fmt::{Display, Formatter}; use std::fmt::{Display};
use std::ops::Add;
use crate::address_mode::Operation::*;
use crate::constants::constants_isa_op::*;
use crate::constants::constants_isa_stub::*;
use crate::mos6502cpu::Mos6502Cpu;
use crate::operation::Operation;
#[derive(PartialEq, Debug, Copy, Clone)] #[derive(PartialEq, Debug, Copy, Clone)]
pub enum AddressMode { pub enum AddressMode {

View File

@ -0,0 +1,9 @@
/// BenEater computer represents the 'Ben Eater' 6502 breadboard computer.
/// This was built along watching the video series where Ben builds a
/// 6502 on a breadboard and explains each step.
///
pub struct BenEater {
}

View File

@ -0,0 +1 @@
pub mod beneater;

View File

@ -0,0 +1,2 @@
pub mod beneater;

View File

@ -1,5 +1,5 @@
use crate::address_mode::AddressMode; use crate::address_mode::AddressMode;
use crate::constants::constants_isa_op::{ISA_OP_ADC_ABS, ISA_OP_ADC_ABSX, ISA_OP_ADC_ABSY, ISA_OP_ADC_I, ISA_OP_ADC_INDX, ISA_OP_ADC_INDY, ISA_OP_ADC_Z, ISA_OP_ADC_ZX, ISA_OP_AND_ABS, ISA_OP_AND_ABSX, ISA_OP_AND_ABSY, ISA_OP_AND_I, ISA_OP_AND_INDX, ISA_OP_AND_INDY, ISA_OP_AND_Z, ISA_OP_AND_ZX, ISA_OP_ASL_A, ISA_OP_ASL_ABS, ISA_OP_ASL_ABSX, ISA_OP_ASL_Z, ISA_OP_ASL_ZX, ISA_OP_BCC, ISA_OP_BCS, ISA_OP_BEQ, ISA_OP_BIT_ABS, ISA_OP_BIT_ZP, ISA_OP_BMI, ISA_OP_BNE, ISA_OP_BPL, ISA_OP_BRK, ISA_OP_BVC, ISA_OP_BVS, ISA_OP_CLC, ISA_OP_CLD, ISA_OP_CLI, ISA_OP_CLV, ISA_OP_CMP_ABS, ISA_OP_CMP_ABSX, ISA_OP_CMP_ABSY, ISA_OP_CMP_I, ISA_OP_CMP_INDX, ISA_OP_CMP_INDY, ISA_OP_CMP_ZP, ISA_OP_CMP_ZPX, ISA_OP_CPX_ABS, ISA_OP_CPX_I, ISA_OP_CPX_ZP, ISA_OP_CPY_ABS, ISA_OP_CPY_I, ISA_OP_CPY_ZP, ISA_OP_DEC_ABS, ISA_OP_DEC_ABSX, ISA_OP_DEC_ZP, ISA_OP_DEC_ZPX, ISA_OP_DEX, ISA_OP_DEY, ISA_OP_EOR_ABS, ISA_OP_EOR_ABSX, ISA_OP_EOR_ABSY, ISA_OP_EOR_I, ISA_OP_EOR_INDX, ISA_OP_EOR_ZP, ISA_OP_EOR_ZPX, ISA_OP_INC_ABS, ISA_OP_INC_ABSX, ISA_OP_INC_ZP, ISA_OP_INC_ZPX, ISA_OP_INX, ISA_OP_INY, ISA_OP_JMP_ABS, ISA_OP_JMP_IND, ISA_OP_JSR, ISA_OP_LDA_ABS, ISA_OP_LDA_ABSX, ISA_OP_LDA_ABSY, ISA_OP_LDA_I, ISA_OP_LDA_INDX, ISA_OP_LDA_INDY, ISA_OP_LDA_Z, ISA_OP_LDA_ZX, ISA_OP_LDX_ABS, ISA_OP_LDX_ABSY, ISA_OP_LDX_I, ISA_OP_LDX_ZP, ISA_OP_LDX_ZPY, ISA_OP_LDY_ABS, ISA_OP_LDY_ABSX, ISA_OP_LDY_I, ISA_OP_LDY_ZP, ISA_OP_LDY_ZPX, ISA_OP_LSR_A, ISA_OP_LSR_ABS, ISA_OP_LSR_ABSX, ISA_OP_LSR_ZP, ISA_OP_LSR_ZPX, ISA_OP_NOP, ISA_OP_ORA_ABS, ISA_OP_ORA_ABSY, ISA_OP_ORA_I, ISA_OP_ORA_INDX, ISA_OP_ORA_INDY, ISA_OP_ORA_ZP, ISA_OP_ORA_ZPX, ISA_OP_PHA, ISA_OP_PHP, ISA_OP_PLA, ISA_OP_PLP, ISA_OP_ROL_A, ISA_OP_ROL_ABS, ISA_OP_ROL_ABSX, ISA_OP_ROL_ZP, ISA_OP_ROL_ZPX, ISA_OP_ROR_A, ISA_OP_ROR_ABS, ISA_OP_ROR_ABSX, ISA_OP_ROR_ZP, ISA_OP_ROR_ZPX, ISA_OP_RTI, ISA_OP_RTS, ISA_OP_SBC_ABS, ISA_OP_SBC_ABSX, ISA_OP_SBC_ABSY, ISA_OP_SBC_I, ISA_OP_SBC_INDX, ISA_OP_SBC_INDY, ISA_OP_SBC_ZP, ISA_OP_SBC_ZPX, ISA_OP_SEC, ISA_OP_SED, ISA_OP_SEI, ISA_OP_STA_ABS, ISA_OP_STA_ABSX, ISA_OP_STA_ABSY, ISA_OP_STA_INDX, ISA_OP_STA_INDY, ISA_OP_STA_ZP, ISA_OP_STA_ZPX, ISA_OP_STX_ABS, ISA_OP_STX_ZP, ISA_OP_STX_ZPY, ISA_OP_STY_ABS, ISA_OP_STY_ZP, ISA_OP_STY_ZPX, ISA_OP_TAX, ISA_OP_TAY, ISA_OP_TSX, ISA_OP_TXA, ISA_OP_TXS, ISA_OP_TYA}; use crate::constants::constants_isa_op::{ISA_OP_ADC_ABS, ISA_OP_ADC_ABSX, ISA_OP_ADC_ABSY, ISA_OP_ADC_I, ISA_OP_ADC_INDX, ISA_OP_ADC_INDY, ISA_OP_ADC_Z, ISA_OP_ADC_ZX, ISA_OP_AND_ABS, ISA_OP_AND_ABSX, ISA_OP_AND_ABSY, ISA_OP_AND_I, ISA_OP_AND_INDX, ISA_OP_AND_INDY, ISA_OP_AND_Z, ISA_OP_AND_ZX, ISA_OP_ASL_A, ISA_OP_ASL_ABS, ISA_OP_ASL_ABSX, ISA_OP_ASL_Z, ISA_OP_ASL_ZX, ISA_OP_BCC, ISA_OP_BCS, ISA_OP_BEQ, ISA_OP_BIT_ABS, ISA_OP_BIT_ZP, ISA_OP_BMI, ISA_OP_BNE, ISA_OP_BPL, ISA_OP_BRK, ISA_OP_BVC, ISA_OP_BVS, ISA_OP_CLC, ISA_OP_CLD, ISA_OP_CLI, ISA_OP_CLV, ISA_OP_CMP_ABS, ISA_OP_CMP_ABSX, ISA_OP_CMP_ABSY, ISA_OP_CMP_I, ISA_OP_CMP_INDX, ISA_OP_CMP_INDY, ISA_OP_CMP_ZP, ISA_OP_CMP_ZPX, ISA_OP_CPX_ABS, ISA_OP_CPX_I, ISA_OP_CPX_ZP, ISA_OP_CPY_ABS, ISA_OP_CPY_I, ISA_OP_CPY_ZP, ISA_OP_DEC_ABS, ISA_OP_DEC_ABSX, ISA_OP_DEC_ZP, ISA_OP_DEC_ZPX, ISA_OP_DEX, ISA_OP_DEY, ISA_OP_EOR_ABS, ISA_OP_EOR_ABSX, ISA_OP_EOR_ABSY, ISA_OP_EOR_I, ISA_OP_EOR_INDX, ISA_OP_EOR_INDY, ISA_OP_EOR_ZP, ISA_OP_EOR_ZPX, ISA_OP_INC_ABS, ISA_OP_INC_ABSX, ISA_OP_INC_ZP, ISA_OP_INC_ZPX, ISA_OP_INX, ISA_OP_INY, ISA_OP_JMP_ABS, ISA_OP_JMP_IND, ISA_OP_JSR, ISA_OP_LDA_ABS, ISA_OP_LDA_ABSX, ISA_OP_LDA_ABSY, ISA_OP_LDA_I, ISA_OP_LDA_INDX, ISA_OP_LDA_INDY, ISA_OP_LDA_Z, ISA_OP_LDA_ZX, ISA_OP_LDX_ABS, ISA_OP_LDX_ABSY, ISA_OP_LDX_I, ISA_OP_LDX_ZP, ISA_OP_LDX_ZPY, ISA_OP_LDY_ABS, ISA_OP_LDY_ABSX, ISA_OP_LDY_I, ISA_OP_LDY_ZP, ISA_OP_LDY_ZPX, ISA_OP_LSR_A, ISA_OP_LSR_ABS, ISA_OP_LSR_ABSX, ISA_OP_LSR_ZP, ISA_OP_LSR_ZPX, ISA_OP_NOP, ISA_OP_ORA_ABS, ISA_OP_ORA_ABSX, ISA_OP_ORA_ABSY, ISA_OP_ORA_I, ISA_OP_ORA_INDX, ISA_OP_ORA_INDY, ISA_OP_ORA_ZP, ISA_OP_ORA_ZPX, ISA_OP_PHA, ISA_OP_PHP, ISA_OP_PLA, ISA_OP_PLP, ISA_OP_ROL_A, ISA_OP_ROL_ABS, ISA_OP_ROL_ABSX, ISA_OP_ROL_ZP, ISA_OP_ROL_ZPX, ISA_OP_ROR_A, ISA_OP_ROR_ABS, ISA_OP_ROR_ABSX, ISA_OP_ROR_ZP, ISA_OP_ROR_ZPX, ISA_OP_RTI, ISA_OP_RTS, ISA_OP_SBC_ABS, ISA_OP_SBC_ABSX, ISA_OP_SBC_ABSY, ISA_OP_SBC_I, ISA_OP_SBC_INDX, ISA_OP_SBC_INDY, ISA_OP_SBC_ZP, ISA_OP_SBC_ZPX, ISA_OP_SEC, ISA_OP_SED, ISA_OP_SEI, ISA_OP_STA_ABS, ISA_OP_STA_ABSX, ISA_OP_STA_ABSY, ISA_OP_STA_INDX, ISA_OP_STA_INDY, ISA_OP_STA_ZP, ISA_OP_STA_ZPX, ISA_OP_STX_ABS, ISA_OP_STX_ZP, ISA_OP_STX_ZPY, ISA_OP_STY_ABS, ISA_OP_STY_ZP, ISA_OP_STY_ZPX, ISA_OP_TAX, ISA_OP_TAY, ISA_OP_TSX, ISA_OP_TXA, ISA_OP_TXS, ISA_OP_TYA};
use crate::op_info::OpInfo; use crate::op_info::OpInfo;
use crate::operation::Operation; use crate::operation::Operation;
use crate::operation::Operation::*; use crate::operation::Operation::*;
@ -180,7 +180,6 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
length: 2, length: 2,
cycles: 2, cycles: 2,
}); });
table[ISA_OP_BPL as usize] = Some(OpInfo { table[ISA_OP_BPL as usize] = Some(OpInfo {
operation: Operation::BPL, operation: Operation::BPL,
mode: AddressMode::Implied, mode: AddressMode::Implied,
@ -226,8 +225,8 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
table[ISA_OP_CLV as usize] = Some(OpInfo { table[ISA_OP_CLV as usize] = Some(OpInfo {
operation: CLV, operation: CLV,
mode: AddressMode::Implied, mode: AddressMode::Implied,
length: 2, length: 1,
cycles: 1, cycles: 2,
}); });
table[ISA_OP_CMP_I as usize] = Some(OpInfo { table[ISA_OP_CMP_I as usize] = Some(OpInfo {
@ -382,7 +381,7 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
length: 3, length: 3,
cycles: 4, cycles: 4,
}); });
table[ISA_OP_EOR_ABSX as usize] = Some(OpInfo { table[ISA_OP_EOR_ABSY as usize] = Some(OpInfo {
operation: EOR, operation: EOR,
mode: AddressMode::AbsoluteY, mode: AddressMode::AbsoluteY,
length: 3, length: 3,
@ -394,7 +393,7 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
length: 2, length: 2,
cycles: 6, cycles: 6,
}); });
table[ISA_OP_EOR_ABSY as usize] = Some(OpInfo { table[ISA_OP_EOR_INDY as usize] = Some(OpInfo {
operation: EOR, operation: EOR,
mode: AddressMode::IndirectY, mode: AddressMode::IndirectY,
length: 2, length: 2,
@ -421,7 +420,7 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
}); });
table[ISA_OP_INC_ABSX as usize] = Some(OpInfo { table[ISA_OP_INC_ABSX as usize] = Some(OpInfo {
operation: INC, operation: INC,
mode: AddressMode::ZeroPageX, mode: AddressMode::AbsoluteX,
length: 3, length: 3,
cycles: 7, cycles: 7,
}); });
@ -537,13 +536,13 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
}); });
table[ISA_OP_LDY_I as usize] = Some(OpInfo { table[ISA_OP_LDY_I as usize] = Some(OpInfo {
operation: Operation::LDY, operation: LDY,
mode: AddressMode::Immediate, mode: AddressMode::Immediate,
length: 2, length: 2,
cycles: 2, cycles: 2,
}); });
table[ISA_OP_LDY_ZP as usize] = Some(OpInfo { table[ISA_OP_LDY_ZP as usize] = Some(OpInfo {
operation: Operation::LDY, operation: LDY,
mode: AddressMode::ZeroPage, mode: AddressMode::ZeroPage,
length: 2, length: 2,
cycles: 3, cycles: 3,
@ -555,13 +554,13 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
cycles: 4, cycles: 4,
}); });
table[ISA_OP_LDY_ABS as usize] = Some(OpInfo { table[ISA_OP_LDY_ABS as usize] = Some(OpInfo {
operation: Operation::LDY, operation: LDY,
mode: AddressMode::Absolute, mode: AddressMode::Absolute,
length: 3, length: 3,
cycles: 4, cycles: 4,
}); });
table[ISA_OP_LDY_ABSX as usize] = Some(OpInfo { table[ISA_OP_LDY_ABSX as usize] = Some(OpInfo {
operation: Operation::LDY, operation: LDY,
mode: AddressMode::AbsoluteX, mode: AddressMode::AbsoluteX,
length: 3, length: 3,
cycles: 4, cycles: 4,
@ -574,13 +573,13 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
cycles: 2, cycles: 2,
}); });
table[ISA_OP_LSR_ZP as usize] = Some(OpInfo { table[ISA_OP_LSR_ZP as usize] = Some(OpInfo {
operation: Operation::LSR, operation: LSR,
mode: AddressMode::ZeroPage, mode: AddressMode::ZeroPage,
length: 2, length: 2,
cycles: 5, cycles: 5,
}); });
table[ISA_OP_LSR_ZPX as usize] = Some(OpInfo { table[ISA_OP_LSR_ZPX as usize] = Some(OpInfo {
operation: Operation::LSR, operation: LSR,
mode: AddressMode::ZeroPageX, mode: AddressMode::ZeroPageX,
length: 2, length: 2,
cycles: 6, cycles: 6,
@ -629,6 +628,13 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
length: 3, length: 3,
cycles: 4, cycles: 4,
}); });
table[ISA_OP_ORA_ABSX as usize] = Some(OpInfo {
operation: Operation::ORA,
mode: AddressMode::AbsoluteX,
length: 3,
cycles: 4,
});
table[ISA_OP_ORA_ABSY as usize] = Some(OpInfo { table[ISA_OP_ORA_ABSY as usize] = Some(OpInfo {
operation: Operation::ORA, operation: Operation::ORA,
mode: AddressMode::AbsoluteY, mode: AddressMode::AbsoluteY,
@ -835,7 +841,7 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
cycles: 4, cycles: 4,
}); });
table[ISA_OP_STA_ABSX as usize] = Some(OpInfo { table[ISA_OP_STA_ABSX as usize] = Some(OpInfo {
operation: STA, operation: Operation::STA,
mode: AddressMode::AbsoluteX, mode: AddressMode::AbsoluteX,
length: 3, length: 3,
cycles: 5, cycles: 5,
@ -936,3 +942,49 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
table table
}; };
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_instruction_table_completeness() {
use INSTRUCTION_TABLE; // Adjust to your actual path
let mut defined_count = 0;
let mut defined_opcodes = vec![];
for (i, entry) in INSTRUCTION_TABLE.iter().enumerate() {
if let Some(info) = entry {
defined_count += 1;
defined_opcodes.push(i);
// Optional: sanity check
assert!(
info.length > 0 && info.cycles > 0,
"Invalid OpInfo at opcode {:#04x?}",
i
);
}
}
println!("Defined opcodes: {}", defined_count);
for i in 0..256 {
if defined_opcodes.contains(&i) {
print!("{:02x} ", i);
}
}
println!("\nMissing opcodes:");
for i in 0..256 {
if !defined_opcodes.contains(&i) {
print!("{:02X} ", i);
}
}
println!();
// The standard 6502 has 151 documented opcodes
assert_eq!(
defined_count, 151,
"Expected 151 opcodes, found {}",
defined_count
);
}
}

View File

@ -1,9 +1,11 @@
pub mod periph;
pub mod address_mode; pub mod address_mode;
pub mod mos6502cpu; pub mod mos6502cpu;
pub mod instruction; pub mod instruction;
pub mod mos6502flags; pub mod mos6502flags;
pub mod constants; pub mod constants;
mod operation; pub mod operation;
mod op_info; pub mod op_info;
mod operand; pub mod operand;
mod instruction_table; pub mod instruction_table;
pub mod computers;

View File

@ -1,6 +1,7 @@
use crate::mos6502flags::{Mos6502Flag, Mos6502Flags}; use crate::mos6502flags::{Mos6502Flag, Mos6502Flags};
pub const SIZE_1KB: usize = 1024 * 1024; pub const SIZE_1KB: usize = 1024 * 1024;
pub const SIZE_32KB: usize = SIZE_1KB * 32;
pub const SIZE_64KB: usize = SIZE_1KB * 64; pub const SIZE_64KB: usize = SIZE_1KB * 64;
pub struct Mos6502Cpu { pub struct Mos6502Cpu {
@ -11,9 +12,28 @@ pub struct Mos6502Cpu {
flags: Mos6502Flags, flags: Mos6502Flags,
pc: u16, pc: u16,
s: u8, s: u8,
microcode_step: u8, pub microcode_step: u8,
address_bus: u16, address_bus: u16,
data_bus: u8 data_bus: u8,
ir: u8 // Instruction Register
}
impl Default for Mos6502Cpu {
fn default() -> Self {
Mos6502Cpu {
memory: [0x00; SIZE_64KB],
a: 0,
x: 0,
y: 0,
flags: Default::default(),
pc: 0,
s: 0,
microcode_step: 0,
address_bus: 0,
data_bus: 0,
ir: 0x00
}
}
} }
impl Mos6502Cpu { impl Mos6502Cpu {
@ -28,7 +48,8 @@ impl Mos6502Cpu {
s: 0xfd, s: 0xfd,
microcode_step: 0, microcode_step: 0,
address_bus: 0x0000, address_bus: 0x0000,
data_bus: 0x00 data_bus: 0x00,
ir: 0x00
} }
} }
@ -70,12 +91,17 @@ impl Mos6502Cpu {
self.y = new_y self.y = new_y
} }
pub fn tick(&mut self) { /// Ticks the CPU
/// Returns
/// AddressBus, DataBus, RW flag
pub fn tick(&mut self) -> (u16, u8, bool) {
(0,0,false)
} }
pub fn dump(&self) { pub fn dump(&self) {
println!("CPU State: PC: {:04x} / A: {:02x} / X: {:02x} / Y: {:02x} / ADDRESS: {:04x} / DATA: {:02x}", println!("CPU State: PC: {:04x} / A: {:02x} / X: {:02x} / Y: {:02x} / ADDRESS: {:04x} / DATA: {:02x}",
self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus); self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus);
} }
} }

View File

@ -0,0 +1,52 @@
use crate::mos6502cpu::SIZE_32KB;
use crate::periph::rom_chip::RomChip;
/// At28C256
///
/// Represents a single At28C256 Chip
///
/// 256kbit storage
/// 32kbyte storage
pub struct At28C256 {
data: [u8; SIZE_32KB]
}
impl RomChip for At28C256 {
fn read(&self, offset: &u16) -> u8 {
self.data[*offset as usize]
}
fn program(new_data: &[u8; SIZE_32KB]) -> Self {
println!("Writing new chip.");
At28C256 {
data: *new_data
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() {
assert!(true)
}
#[test]
fn programmed_data_reads_back_same() {
print!("Starting test...");
let data_to_write = [0xea; SIZE_32KB];
print!("allocated data for rom...");
let chip: At28C256 = At28C256::program(&data_to_write);
println!("programmed chip...");
print!("testing");
for offset in 0..SIZE_32KB {
if offset.is_multiple_of(1000) {
print!(".");
};
assert_eq!(0xea, chip.read(&(offset as u16)));
}
println!("passed!");
}
}

3
core/src/periph/mod.rs Normal file
View File

@ -0,0 +1,3 @@
pub mod rom_chip;
pub mod at28c256;

View File

@ -0,0 +1,17 @@
use crate::mos6502cpu::SIZE_32KB;
pub trait RomChip {
/// Read
///
/// Reads a single byte from the specified address
fn read(&self, offset: &u16) -> u8;
/// Program
///
/// Replaces all data in the ROM chip
fn program(new_data: &[u8; SIZE_32KB]) -> Self;
}
pub trait RamChip: RomChip {
fn write(&mut self, offset: &u16, value: &u8);
}

View File

@ -4,4 +4,4 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
macroquad = "0.4" macroquad.workspace = true

Binary file not shown.