closer to ticking.
has microsteps in the UI decodes from a NOP only binary some basic instructions are starting to move data around
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
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 OFFSET_RESET_VECTOR: u16 = 0xfffc;
|
||||
pub const OFFSET_INT_VECTOR: u16 = 0xfffe;
|
||||
@@ -1,2 +1,3 @@
|
||||
pub mod constants_isa_stub;
|
||||
pub mod constants_isa_op;
|
||||
pub mod constants_system;
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::address_mode::AddressMode;
|
||||
use crate::address_mode::AddressMode::*;
|
||||
use crate::address_mode::AddressMode::{Absolute, AbsoluteX, AbsoluteY, Accumulator, Immediate, Implied, Indirect, IndirectX, IndirectY, ZeroPage, ZeroPageX};
|
||||
use crate::instruction_table::INSTRUCTION_TABLE;
|
||||
use crate::op_info::OpInfo;
|
||||
use crate::operand::Operand;
|
||||
use crate::operation::Operation;
|
||||
use crate::operation::Operation::{ADC, AND, ASL, BCC, BCS, BEQ, BIT, BMI, BNE, BPL, BRK, BVC, BVS, CLC, CLD, CLI, CLV, CMP, CPX, CPY, DEC, DEX, DEY, EOR, INC, INX, JMP, JSR, LDA, LDX, LDY, NOP, ORA, PHA, PHP, PLA, PLP, ROL, ROR, RTI, RTS, SBC, SEC, SED, SEI, STA, STX, STY, TAX, TAY, TSX, TXA, TXS, TYA};
|
||||
@@ -14,11 +15,14 @@ pub struct Instruction {
|
||||
}
|
||||
|
||||
impl Instruction {
|
||||
pub fn decode(bytes: &[u8]) -> Option<Instruction> {
|
||||
pub fn opinfo(bytes: &[u8]) -> Option<OpInfo> {
|
||||
println!("DECODING : {bytes:?}");
|
||||
let opcode = bytes.get(0).copied()?;
|
||||
let info = INSTRUCTION_TABLE[opcode as usize]?;
|
||||
Some(INSTRUCTION_TABLE[opcode as usize])?
|
||||
}
|
||||
|
||||
pub fn decode(bytes: &[u8]) -> Option<Instruction> {
|
||||
let info = Instruction::opinfo(bytes).unwrap();
|
||||
let operand = match info.length {
|
||||
2 => Operand::Byte(bytes.get(1).copied()?),
|
||||
3 => {
|
||||
|
||||
+198
-25
@@ -1,13 +1,11 @@
|
||||
use crate::address_mode::AddressMode;
|
||||
use crate::constants::constants_system::{OFFSET_INT_VECTOR, OFFSET_RESET_VECTOR, SIZE_64KB};
|
||||
use crate::instruction::Instruction;
|
||||
use crate::mos6502flags::{Mos6502Flag, Mos6502Flags};
|
||||
use crate::mos6502flags::Mos6502Flag::{Carry, Decimal, Interrupt, Overflow};
|
||||
use crate::op_info::OpInfo;
|
||||
use crate::operand::Operand;
|
||||
use crate::operation::Operation;
|
||||
use crate::operation::Operation::NOP;
|
||||
|
||||
pub const SIZE_1KB: usize = 1024 * 1024;
|
||||
pub const SIZE_32KB: usize = SIZE_1KB * 32;
|
||||
pub const SIZE_64KB: usize = SIZE_1KB * 64;
|
||||
|
||||
pub struct Mos6502Cpu {
|
||||
// this is public for rendering quickly.
|
||||
@@ -21,7 +19,10 @@ pub struct Mos6502Cpu {
|
||||
pub microcode_step: u8,
|
||||
pub address_bus: u16,
|
||||
pub data_bus: u8,
|
||||
ir: Instruction // Instruction Register
|
||||
ir: Instruction, // Instruction Register
|
||||
oi: OpInfo,
|
||||
has_reset: bool,
|
||||
iv: u16 // Interrupt Vector
|
||||
}
|
||||
|
||||
impl Default for Mos6502Cpu {
|
||||
@@ -30,7 +31,7 @@ impl Default for Mos6502Cpu {
|
||||
let boxed_slize: Box<[u8]> = vec.into_boxed_slice();
|
||||
let boxed_array: Box<[u8; SIZE_64KB]> = boxed_slize.try_into().expect("Failed to allocate system memory");
|
||||
|
||||
Mos6502Cpu {
|
||||
let mut working = Mos6502Cpu {
|
||||
memory: boxed_array,
|
||||
a: 0,
|
||||
x: 0,
|
||||
@@ -45,8 +46,18 @@ impl Default for Mos6502Cpu {
|
||||
op: Operation::NOP,
|
||||
mode: AddressMode::Implied,
|
||||
operand: Operand::None,
|
||||
}
|
||||
}
|
||||
},
|
||||
oi: OpInfo {
|
||||
operation: Operation::NOP,
|
||||
mode: AddressMode::Implied,
|
||||
length: 1,
|
||||
cycles: 2,
|
||||
},
|
||||
has_reset: false,
|
||||
iv: 0xfffe
|
||||
};
|
||||
working.reset_cpu();
|
||||
working
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +66,7 @@ impl Mos6502Cpu {
|
||||
let vec = vec![0x00; SIZE_64KB];
|
||||
let boxed_slize: Box<[u8]> = vec.into_boxed_slice();
|
||||
let boxed_array: Box<[u8; SIZE_64KB]> = boxed_slize.try_into().expect("Failed to allocate system memory");
|
||||
Mos6502Cpu {
|
||||
let mut working = Mos6502Cpu {
|
||||
memory: boxed_array,
|
||||
a: 0,
|
||||
x: 0,
|
||||
@@ -70,8 +81,33 @@ impl Mos6502Cpu {
|
||||
op: Operation::NOP,
|
||||
mode: AddressMode::Implied,
|
||||
operand: Operand::None,
|
||||
}
|
||||
}
|
||||
},
|
||||
oi: OpInfo {
|
||||
operation: Operation::NOP,
|
||||
mode: AddressMode::Implied,
|
||||
length: 1,
|
||||
cycles: 2,
|
||||
},
|
||||
has_reset: false,
|
||||
iv: 0xfffe
|
||||
};
|
||||
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);
|
||||
self.iv = self.read_word(&OFFSET_INT_VECTOR);
|
||||
}
|
||||
|
||||
fn read_word(&self, offset: &u16) -> u16 {
|
||||
let low = self.memory[*offset as usize];
|
||||
let high = self.memory[*offset as usize + 1];
|
||||
(high as u16) << 8 | low as u16
|
||||
}
|
||||
|
||||
pub fn peek_flag(&self, flag_to_read: Mos6502Flag) -> bool {
|
||||
@@ -112,35 +148,172 @@ impl Mos6502Cpu {
|
||||
self.y = new_y
|
||||
}
|
||||
|
||||
fn advance_pc(&mut self, how_far: u16) {
|
||||
self.pc += how_far;
|
||||
}
|
||||
|
||||
fn set_pc_to(&mut self, new_pc: u16) {
|
||||
self.pc = new_pc;
|
||||
}
|
||||
|
||||
/// Ticks the CPU
|
||||
/// Returns
|
||||
/// AddressBus, DataBus, RW flag
|
||||
pub fn tick(&mut self) -> (u16, u8, bool) {
|
||||
|
||||
println!("PREPARiNG TO TICK CPU AT {:04x}", self.pc);
|
||||
|
||||
let mut num_microsteps_left = 0;
|
||||
|
||||
if num_microsteps_left == 0 {
|
||||
println!("OUT OF MICROSTEPS. Time To do something that isnt microstep.");
|
||||
println!("PREPARiNG TO TICK CPU AT PC 0x{:04x}", self.pc);
|
||||
if self.microcode_step == 0 {
|
||||
println!("OUT OF MICROSTEPS. Decoding the next instruction");
|
||||
let offset = self.pc as usize;
|
||||
// TODO: this calls opinfo 2x
|
||||
self.oi = Instruction::opinfo(&self.memory[offset..offset + 4]).unwrap();
|
||||
self.ir = Instruction::decode(&self.memory[offset..offset + 2]).unwrap();
|
||||
self.microcode_step = self.oi.cycles;
|
||||
println!("Decoded [[{:?}]]", self.ir);
|
||||
self.advance_pc(self.oi.length as u16);
|
||||
// load the microstep buffer with what steps to run
|
||||
// set the counter to the number of steps left
|
||||
} else {
|
||||
// run 1 microcode step
|
||||
println!("Microstep {num_microsteps_left}");
|
||||
num_microsteps_left -= 1;
|
||||
println!("Microstep {}", self.microcode_step);
|
||||
match self.ir.op {
|
||||
Operation::ADC => {
|
||||
}
|
||||
Operation::AND => {}
|
||||
Operation::ASL => {}
|
||||
Operation::BCC => {}
|
||||
Operation::BCS => {}
|
||||
Operation::BEQ => {}
|
||||
Operation::BIT => {}
|
||||
Operation::BMI => {}
|
||||
Operation::BNE => {}
|
||||
Operation::BPL => {}
|
||||
Operation::BRK => {}
|
||||
Operation::BVC => {}
|
||||
Operation::BVS => {}
|
||||
Operation::CLC => {
|
||||
self.flags.clear_flag(Carry);
|
||||
}
|
||||
Operation::CLD => {
|
||||
self.flags.clear_flag(Decimal);
|
||||
}
|
||||
Operation::CLI => {
|
||||
self.flags.clear_flag(Interrupt);
|
||||
}
|
||||
Operation::CLV => {
|
||||
self.flags.clear_flag(Overflow);
|
||||
}
|
||||
Operation::CMP => {}
|
||||
Operation::CPX => {}
|
||||
Operation::CPY => {}
|
||||
Operation::DEC => {}
|
||||
Operation::DEX => {
|
||||
self.x -= 1;
|
||||
}
|
||||
Operation::DEY => {
|
||||
self.y -= 1;
|
||||
}
|
||||
Operation::EOR => { }
|
||||
Operation::INC => { }
|
||||
Operation::INX => {
|
||||
self.x += 1;
|
||||
}
|
||||
Operation::INY => {
|
||||
self.y += 1;
|
||||
}
|
||||
Operation::JMP => {
|
||||
match self.ir.operand {
|
||||
Operand::Word(offset) => {
|
||||
self.pc = offset;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Operation::JSR => {}
|
||||
Operation::LDA => {
|
||||
match self.oi.mode {
|
||||
AddressMode::Immediate => {
|
||||
match self.ir.operand {
|
||||
Operand::Byte(value) => {
|
||||
println!("Loading {} into A", value);
|
||||
self.a = value;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
AddressMode::ZeroPage => {}
|
||||
AddressMode::ZeroPageX => {}
|
||||
AddressMode::ZeroPageY => {}
|
||||
AddressMode::Absolute => {}
|
||||
AddressMode::AbsoluteX => {}
|
||||
AddressMode::AbsoluteY => {}
|
||||
AddressMode::Indirect => {}
|
||||
AddressMode::IndirectX => {}
|
||||
AddressMode::IndirectY => {}
|
||||
_ => {
|
||||
println!("INVALID ADDRESS MODE FOR LDA");
|
||||
}
|
||||
}
|
||||
}
|
||||
Operation::LDX => {}
|
||||
Operation::LDY => {}
|
||||
Operation::LSR => {}
|
||||
Operation::NOP => {
|
||||
// do nothing.
|
||||
}
|
||||
Operation::ORA => {}
|
||||
Operation::PHA => {}
|
||||
Operation::PHP => {}
|
||||
Operation::PLA => {}
|
||||
Operation::PLP => {}
|
||||
Operation::ROL => {}
|
||||
Operation::ROR => {
|
||||
// rotate A
|
||||
self.a = self.a.rotate_right(1);
|
||||
}
|
||||
Operation::RTI => {}
|
||||
Operation::RTS => {}
|
||||
Operation::SBC => {}
|
||||
Operation::SEC => {
|
||||
self.flags.set_flag(Carry);
|
||||
}
|
||||
Operation::SED => {
|
||||
self.flags.set_flag(Decimal);
|
||||
}
|
||||
Operation::SEI => {
|
||||
self.flags.set_flag(Mos6502Flag::Interrupt);
|
||||
}
|
||||
Operation::STA => {}
|
||||
Operation::STX => {}
|
||||
Operation::STY => {}
|
||||
Operation::TAX => {
|
||||
self.x = self.a;
|
||||
}
|
||||
Operation::TAY => {
|
||||
self.y = self.a;
|
||||
}
|
||||
Operation::TSX => {}
|
||||
Operation::TXA => {
|
||||
self.a = self.x;
|
||||
}
|
||||
Operation::TXS => {
|
||||
}
|
||||
Operation::TYA => {
|
||||
self.y = self.a;
|
||||
}
|
||||
}
|
||||
self.microcode_step -= 1;
|
||||
}
|
||||
|
||||
(0,0,false)
|
||||
}
|
||||
|
||||
pub fn dump(&self) {
|
||||
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);
|
||||
println!("CPU State: PC: {:04x} / A: {:02x} / X: {:02x} / Y: {:02x} / ADDRESS: {:04x} / DATA: {:02x} / MICROSTEPS: {:02x}",
|
||||
self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus, self.microcode_step);
|
||||
}
|
||||
|
||||
pub fn dump_data(&self) -> ( u16, u8, u8, u8, u16, u8) {
|
||||
(self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus)
|
||||
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)
|
||||
}
|
||||
|
||||
fn run_microstep(&self, instruction: Instruction, step: u8) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::mos6502cpu::{SIZE_32KB};
|
||||
use crate::constants::constants_system::SIZE_32KB;
|
||||
use crate::periph::rom_chip::RomChip;
|
||||
|
||||
/// At28C256
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// HM62256 Static Ram
|
||||
|
||||
use log::debug;
|
||||
use crate::mos6502cpu::SIZE_32KB;
|
||||
use crate::constants::constants_system::SIZE_32KB;
|
||||
use crate::periph::ram_chip::RamChip;
|
||||
use crate::periph::rom_chip::RomChip;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::mos6502cpu::SIZE_32KB;
|
||||
use crate::constants::constants_system::SIZE_32KB;
|
||||
|
||||
pub trait RomChip {
|
||||
/// Read
|
||||
|
||||
Reference in New Issue
Block a user