decodes all instructions i think.
start of a beneater pc
This commit is contained in:
parent
57544589b3
commit
d89fc1cd2b
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -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"
|
||||||
|
|||||||
@ -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
8
beneater/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "beneater"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
core = { path = "../core" }
|
||||||
|
macroquad.workspace = true
|
||||||
16
beneater/src/bin/beneater.rs
Normal file
16
beneater/src/bin/beneater.rs
Normal 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
1
beneater/src/lib.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod parts;
|
||||||
25
beneater/src/parts/ben_eater_pc.rs
Normal file
25
beneater/src/parts/ben_eater_pc.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
beneater/src/parts/clock.rs
Normal file
24
beneater/src/parts/clock.rs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
3
beneater/src/parts/mod.rs
Normal file
3
beneater/src/parts/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod clock;
|
||||||
|
mod ben_eater_pc;
|
||||||
|
mod via6522;
|
||||||
31
beneater/src/parts/via6522.rs
Normal file
31
beneater/src/parts/via6522.rs
Normal 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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
9
core/src/computers/beneater/beneater.rs
Normal file
9
core/src/computers/beneater/beneater.rs
Normal 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 {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
1
core/src/computers/beneater/mod.rs
Normal file
1
core/src/computers/beneater/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod beneater;
|
||||||
2
core/src/computers/mod.rs
Normal file
2
core/src/computers/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod beneater;
|
||||||
|
|
||||||
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
52
core/src/periph/at28c256.rs
Normal file
52
core/src/periph/at28c256.rs
Normal 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
3
core/src/periph/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod rom_chip;
|
||||||
|
|
||||||
|
pub mod at28c256;
|
||||||
17
core/src/periph/rom_chip.rs
Normal file
17
core/src/periph/rom_chip.rs
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
@ -4,4 +4,4 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
macroquad = "0.4"
|
macroquad.workspace = true
|
||||||
BIN
resources/beneater/roms/nop.bin
Normal file
BIN
resources/beneater/roms/nop.bin
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user