more stuff i worked on
This commit is contained in:
@@ -2,6 +2,5 @@ pub const SIZE_1KB: usize = 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;
|
||||
+53
-22
@@ -11,33 +11,47 @@ use crate::constants::constants_system::*;
|
||||
use crate::instruction_table::INSTRUCTION_TABLE;
|
||||
|
||||
pub struct Mos6502Cpu {
|
||||
// this is public for rendering quickly.
|
||||
pub memory: Box<[u8]>,
|
||||
memory: [u8; SIZE_64KB],
|
||||
/// accumulator
|
||||
a: u8,
|
||||
/// x register
|
||||
x: u8,
|
||||
/// y register
|
||||
y: u8,
|
||||
/// cpu flags
|
||||
flags: Mos6502Flags,
|
||||
/// program counter
|
||||
pc: u16,
|
||||
/// stack offset
|
||||
s: u8,
|
||||
pub microcode_step: u8,
|
||||
pub address_bus: u16,
|
||||
pub data_bus: 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: Box<[u8]>
|
||||
ir_bytes: [u8; 4],
|
||||
/// CPU Read signal
|
||||
pub read_signal: bool
|
||||
}
|
||||
|
||||
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 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");
|
||||
|
||||
let mut working = Mos6502Cpu {
|
||||
memory: boxed_array,
|
||||
memory: [0x00; SIZE_64KB],
|
||||
a: 0x00,
|
||||
x: 0x00,
|
||||
y: 0x00,
|
||||
@@ -56,7 +70,8 @@ impl Default for Mos6502Cpu {
|
||||
has_reset: false,
|
||||
iv: 0xfffe,
|
||||
cycle_carry: 0x0000,
|
||||
ir_bytes: [].into()
|
||||
ir_bytes: [0x00; 4],
|
||||
read_signal: true
|
||||
};
|
||||
working.reset_cpu();
|
||||
working
|
||||
@@ -64,13 +79,19 @@ impl Default for Mos6502Cpu {
|
||||
}
|
||||
|
||||
impl Mos6502Cpu {
|
||||
pub fn address_bus(&self) -> u16 {
|
||||
self.address_bus
|
||||
}
|
||||
|
||||
pub fn data_bus(&self) -> u8 {
|
||||
self.data_bus
|
||||
}
|
||||
|
||||
pub fn new() -> 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");
|
||||
let array = [0x00u8; SIZE_64KB];
|
||||
let mut working = Mos6502Cpu {
|
||||
memory: boxed_array,
|
||||
ir_bytes: [].into(),
|
||||
memory: array,
|
||||
ir_bytes: [0x00; 4],
|
||||
..Default::default()
|
||||
};
|
||||
working.reset_cpu();
|
||||
@@ -105,6 +126,7 @@ impl Mos6502Cpu {
|
||||
}
|
||||
|
||||
pub fn poke(&mut self, offset: u16, value: u8) {
|
||||
println!("Setting memory at {offset:04x} to {value:02x}");
|
||||
self.memory[offset as usize] = value
|
||||
}
|
||||
|
||||
@@ -112,7 +134,10 @@ impl Mos6502Cpu {
|
||||
self.a
|
||||
}
|
||||
pub fn poke_a(&mut self, new_a: u8) {
|
||||
self.a = new_a;
|
||||
|
||||
println!("Updating register A from [{}] to [{}]", self.a, new_a);
|
||||
|
||||
self.a = new_a;
|
||||
}
|
||||
|
||||
pub fn peek_x(&self) -> u8 {
|
||||
@@ -284,6 +309,8 @@ impl Mos6502Cpu {
|
||||
let (new_x, new_carry) = self.x.overflowing_add(1);
|
||||
self.poke_x(new_x);
|
||||
self.poke_flag(Carry, new_carry);
|
||||
self.address_bus = self.pc;
|
||||
self.data_bus = 0x00;
|
||||
}
|
||||
}
|
||||
Operation::INY => {
|
||||
@@ -291,11 +318,15 @@ impl Mos6502Cpu {
|
||||
let (new_y, new_carry) = self.y.overflowing_add(1);
|
||||
self.poke_y(new_y);
|
||||
self.poke_flag(Carry, new_carry);
|
||||
self.address_bus = self.pc;
|
||||
self.data_bus = 0x00;
|
||||
} }
|
||||
Operation::JMP => {
|
||||
match self.ir.operand {
|
||||
Operand::Word(offset) => {
|
||||
self.pc = offset;
|
||||
self.address_bus = self.pc;
|
||||
self.data_bus = 0x00;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -597,8 +628,8 @@ mod test {
|
||||
let mut cpu = Mos6502Cpu::default();
|
||||
cpu.memory[0x6000] = ISA_OP_LDA_ABS;
|
||||
cpu.memory[0x6001] = 0xef;
|
||||
cpu.memory[0x6002] = 0xbe;
|
||||
cpu.memory[0xbeef] = 0xab;
|
||||
cpu.memory[0x6002] = 0x0e;
|
||||
cpu.memory[0x0eef] = 0xab;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABS) { cpu.tick(); }
|
||||
@@ -611,9 +642,9 @@ mod test {
|
||||
let mut cpu = Mos6502Cpu::default();
|
||||
cpu.memory[0x6000] = ISA_OP_LDA_ABSX;
|
||||
cpu.memory[0x6001] = 0xef;
|
||||
cpu.memory[0x6002] = 0xbe;
|
||||
cpu.memory[0x6002] = 0x0e;
|
||||
cpu.poke_x(0x01);
|
||||
cpu.memory[0xbef0] = 0xab;
|
||||
cpu.memory[0x0ef0] = 0xab;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSX) { cpu.tick(); }
|
||||
@@ -628,7 +659,7 @@ mod test {
|
||||
cpu.memory[0x6001] = 0xef;
|
||||
cpu.memory[0x6002] = 0xbe;
|
||||
cpu.poke_y(0x01);
|
||||
cpu.memory[0xbef0] = 0xab;
|
||||
cpu.memory[0x0ef0] = 0xab;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSY) { cpu.tick(); }
|
||||
|
||||
+132
-55
@@ -1,4 +1,12 @@
|
||||
use crate::mos6502flags::Mos6502Flag::{Break, Carry, Decimal, Interrupt, Negative, Overflow, Zero};
|
||||
|
||||
pub const BIT_NEGATIVE: u8 = 7;
|
||||
pub const BIT_OVERFLOW: u8 = 6;
|
||||
pub const BIT_BREAK: u8 = 4;
|
||||
pub const BIT_DECIMAL: u8 = 3;
|
||||
pub const BIT_INTERRUPT: u8 = 2;
|
||||
pub const BIT_ZERO: u8 = 1;
|
||||
pub const BIT_CARRY: u8 = 0;
|
||||
/// Represents the status flags in the 6502 processor's status register (P).
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum Mos6502Flag {
|
||||
@@ -42,7 +50,21 @@ pub enum Mos6502Flag {
|
||||
Negative,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
impl Mos6502Flag {
|
||||
pub fn index(&self) -> u8 {
|
||||
match self {
|
||||
Carry => BIT_CARRY,
|
||||
Zero => BIT_ZERO,
|
||||
Interrupt => BIT_INTERRUPT,
|
||||
Decimal => BIT_DECIMAL,
|
||||
Break => BIT_BREAK,
|
||||
Overflow => BIT_OVERFLOW,
|
||||
Negative => BIT_NEGATIVE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Debug)]
|
||||
pub struct Mos6502Flags {
|
||||
carry: bool,
|
||||
zero: bool,
|
||||
@@ -56,78 +78,133 @@ pub struct Mos6502Flags {
|
||||
impl Mos6502Flags {
|
||||
pub fn dump(&self) -> String {
|
||||
format!("{}{}{}{}{}{}{}",
|
||||
if self.carry { 'C' } else { 'c' },
|
||||
if self.zero { 'Z' } else { 'z' },
|
||||
if self.interrupt { 'I' } else { 'i' },
|
||||
if self.decimal { 'D' } else { 'd' },
|
||||
if self.break_flag { 'B' } else { 'b' },
|
||||
if self.overflow { 'O' } else { 'o' },
|
||||
if self.negative { 'N' } else { 'n' }
|
||||
if self.carry { 'C' } else { 'c' },
|
||||
if self.zero { 'Z' } else { 'z' },
|
||||
if self.interrupt { 'I' } else { 'i' },
|
||||
if self.decimal { 'D' } else { 'd' },
|
||||
if self.break_flag { 'B' } else { 'b' },
|
||||
if self.overflow { 'O' } else { 'o' },
|
||||
if self.negative { 'N' } else { 'n' }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mos6502Flags {
|
||||
|
||||
pub fn set_flag(&mut self, flag_to_set: Mos6502Flag) {
|
||||
self.change_flag(flag_to_set, true);
|
||||
println!("Setting {flag_to_set:?} flag");
|
||||
match flag_to_set {
|
||||
Carry => self.carry = true,
|
||||
Zero => self.zero = true,
|
||||
Interrupt => self.interrupt = true,
|
||||
Decimal => self.decimal = true,
|
||||
Break => self.break_flag = true,
|
||||
Overflow => self.overflow = true,
|
||||
Negative => self.negative = true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_flag(&mut self, flag_to_clear: Mos6502Flag) {
|
||||
self.change_flag(flag_to_clear, false);
|
||||
}
|
||||
println!("Clearing {flag_to_clear:?} flag");
|
||||
match flag_to_clear {
|
||||
Carry => self.carry = false,
|
||||
Zero => self.zero = false,
|
||||
Interrupt => self.interrupt = false,
|
||||
Decimal => self.decimal = false,
|
||||
Break => self.break_flag = false,
|
||||
Overflow => self.overflow = false,
|
||||
Negative => self.negative = false,
|
||||
} }
|
||||
|
||||
fn change_flag(&mut self, flag_to_change: Mos6502Flag, new_value: bool) {
|
||||
match flag_to_change {
|
||||
Mos6502Flag::Carry => {
|
||||
self.carry = new_value
|
||||
}
|
||||
Mos6502Flag::Zero => {
|
||||
self.zero = new_value
|
||||
}
|
||||
Mos6502Flag::Interrupt => {
|
||||
self.interrupt = new_value
|
||||
}
|
||||
Mos6502Flag::Decimal => {
|
||||
self.decimal = new_value
|
||||
}
|
||||
Mos6502Flag::Break => {
|
||||
self.break_flag = new_value
|
||||
}
|
||||
Mos6502Flag::Overflow => {
|
||||
self.overflow = new_value
|
||||
}
|
||||
Mos6502Flag::Negative => {
|
||||
self.negative = new_value
|
||||
}
|
||||
if new_value {
|
||||
self.set_flag(flag_to_change);
|
||||
} else {
|
||||
self.clear_flag(flag_to_change);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flag(&self, flag_to_read: Mos6502Flag) -> bool {
|
||||
match flag_to_read {
|
||||
Mos6502Flag::Carry => {
|
||||
self.carry
|
||||
}
|
||||
Mos6502Flag::Zero => {
|
||||
self.zero
|
||||
}
|
||||
Mos6502Flag::Interrupt => {
|
||||
self.interrupt
|
||||
}
|
||||
Mos6502Flag::Decimal => {
|
||||
self.decimal
|
||||
}
|
||||
Mos6502Flag::Break => {
|
||||
self.break_flag
|
||||
}
|
||||
Mos6502Flag::Overflow => {
|
||||
self.overflow
|
||||
}
|
||||
Mos6502Flag::Negative => {
|
||||
self.negative
|
||||
}
|
||||
Mos6502Flag::Negative => self.negative,
|
||||
Mos6502Flag::Overflow => self.overflow,
|
||||
// 5
|
||||
Mos6502Flag::Break => self.break_flag,
|
||||
Mos6502Flag::Decimal => self.decimal,
|
||||
Mos6502Flag::Interrupt => self.interrupt,
|
||||
Mos6502Flag::Zero => self.zero,
|
||||
Mos6502Flag::Carry => self.carry,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_byte(&self) -> u8 {
|
||||
let mut working = 0x00;
|
||||
|
||||
if self.flag(Negative) { working += 1 << Negative.index(); }
|
||||
if self.flag(Overflow) { working += 1 << Overflow.index(); }
|
||||
working += 1 << 5; // Always Set
|
||||
if self.flag(Break) { working += 1 << Break.index(); }
|
||||
if self.flag(Decimal) { working += 1 << Decimal.index(); }
|
||||
if self.flag(Interrupt) { working += 1 << Interrupt.index(); }
|
||||
if self.flag(Zero) { working += 1 << Zero.index(); }
|
||||
if self.flag(Carry) { working += 1 << Carry.index(); }
|
||||
|
||||
working
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn from_byte(src: u8) -> Self {
|
||||
let mut working = Self::default();
|
||||
|
||||
working.change_flag(Negative, Self::bit(src, Negative.index()));
|
||||
working.change_flag(Overflow, Self::bit(src, Overflow.index()));
|
||||
working.change_flag(Break, Self::bit(src, Break.index()));
|
||||
working.change_flag(Decimal, Self::bit(src, Decimal.index()));
|
||||
working.change_flag(Interrupt, Self::bit(src, Interrupt.index()));
|
||||
working.change_flag(Zero, Self::bit(src, Zero.index()));
|
||||
working.change_flag(Carry, Self::bit(src, Carry.index()));
|
||||
|
||||
working
|
||||
}
|
||||
|
||||
/// bit
|
||||
///
|
||||
/// src -> Source byte to check in
|
||||
/// pos -> Which bit to check
|
||||
///
|
||||
/// returns bool
|
||||
///
|
||||
/// True if the bit is set.
|
||||
/// False if the bit is not set
|
||||
#[inline]
|
||||
fn bit(src: u8, pos: u8) -> bool {
|
||||
(src >> pos) & 1 != 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke() { assert!(true); }
|
||||
|
||||
#[test]
|
||||
fn sanity() {
|
||||
let f = Mos6502Flags::default();
|
||||
let magic_byte = 0b1110_1101;
|
||||
let magic_flags = Mos6502Flags {
|
||||
carry: true,
|
||||
zero: false,
|
||||
interrupt: true,
|
||||
decimal: true,
|
||||
break_flag: false,
|
||||
overflow: true,
|
||||
negative: true,
|
||||
};
|
||||
|
||||
assert_eq!(magic_flags, Mos6502Flags::from_byte(magic_byte));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,12 @@ pub struct At28C256 {
|
||||
data: Box<[u8; SIZE_32KB]>,
|
||||
}
|
||||
|
||||
impl At28C256 {
|
||||
pub fn program(&mut self, new_program: &[u8; 32768]) {
|
||||
self.data= new_program.into();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::constants::constants_system::SIZE_1KB;
|
||||
|
||||
@@ -8,7 +8,7 @@ impl RomChip for At28C256 {
|
||||
self.data[*offset as usize]
|
||||
}
|
||||
|
||||
fn program(new_data: Box<[u8; SIZE_32KB]>) -> Box<At28C256> {
|
||||
fn program(new_data: &[u8; SIZE_32KB]) -> Box<At28C256> {
|
||||
println!("Writing new chip.");
|
||||
let mut working = At28C256::default();
|
||||
working.data = Box::new(*new_data);
|
||||
|
||||
@@ -29,7 +29,7 @@ impl RomChip for Hm62256 {
|
||||
self.data[effective as usize]
|
||||
}
|
||||
|
||||
fn program(_: Box<[u8; SIZE_32KB]>) -> Box<Self> {
|
||||
fn program(_: &[u8; SIZE_32KB]) -> Box<Self> {
|
||||
debug!("Dont program ram.");
|
||||
Hm62256::default().into()
|
||||
}
|
||||
|
||||
@@ -8,5 +8,5 @@ pub trait RomChip {
|
||||
/// Program
|
||||
///
|
||||
/// Replaces all data in the ROM chip
|
||||
fn program(new_data: Box<[u8; SIZE_32KB]>) -> Box<Self>;
|
||||
fn program(new_data: &[u8; SIZE_32KB]) -> Box<Self>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user