Compare commits
2 Commits
cf14804df2
...
9c672741ed
| Author | SHA1 | Date | |
|---|---|---|---|
| 9c672741ed | |||
| b9242b1943 |
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -366,6 +366,7 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
|||||||
name = "macroquad"
|
name = "macroquad"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"core",
|
||||||
"macroquad 0.4.14",
|
"macroquad 0.4.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
0
beneater/src/backplane/mod.rs
Normal file
0
beneater/src/backplane/mod.rs
Normal file
@ -1,9 +1,9 @@
|
|||||||
// This is the GUI for the BenEater PC
|
// This is the GUI for the BenEater PC
|
||||||
|
use beneater::parts::backplane::Backplane;
|
||||||
|
use beneater::parts::ben_eater_pc::BenEaterPC;
|
||||||
use beneater::parts::cpu_display::CpuDisplay;
|
use beneater::parts::cpu_display::CpuDisplay;
|
||||||
use macroquad::prelude::*;
|
use macroquad::prelude::*;
|
||||||
use macroquad::telemetry::frame;
|
use macroquad::telemetry::frame;
|
||||||
use beneater::parts::ben_eater_pc::BenEaterPC;
|
|
||||||
use beneater::parts::backplane::Backplane;
|
|
||||||
#[macroquad::main("Ben Eaters PC")]
|
#[macroquad::main("Ben Eaters PC")]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
println!("Taxation is Theft");
|
println!("Taxation is Theft");
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use std::fs;
|
|
||||||
use core::constants::constants_system::SIZE_32KB;
|
use core::constants::constants_system::SIZE_32KB;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// make the rom data in memory.
|
// make the rom data in memory.
|
||||||
|
|||||||
@ -1,20 +1,24 @@
|
|||||||
|
use beneater::parts::backplane::Backplane;
|
||||||
|
use core::constants::constants_isa_op::*;
|
||||||
|
use core::constants::constants_system::*;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
use beneater::parts::backplane::Backplane;
|
|
||||||
use core::constants::constants_system::*;
|
|
||||||
use core::constants::constants_isa_op::*;
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Taxation is Theft");
|
println!("Taxation is Theft");
|
||||||
|
|
||||||
let mut backplane = Backplane::new();
|
let mut backplane = Backplane::new();
|
||||||
|
|
||||||
|
backplane.load_rom();
|
||||||
println!("Backplane is live.");
|
println!("Backplane is live.");
|
||||||
|
|
||||||
let mut new_program = [0x00u8; SIZE_32KB];
|
let mut new_program = [0x00u8; SIZE_32KB];
|
||||||
new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize] = 0x00;
|
new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize] = 0x00;
|
||||||
new_program[(OFFSET_RESET_VECTOR + 1 - SIZE_32KB as u16) as usize] = 0x60;
|
new_program[(OFFSET_RESET_VECTOR + 1 - SIZE_32KB as u16) as usize] = 0x60;
|
||||||
println!("Set offset in rom...");
|
println!("Set offset in rom...");
|
||||||
println!("VALUE AT OFFSET_RESET_VECTOR = 0x{:02x} ", new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize]);
|
println!(
|
||||||
|
"VALUE AT OFFSET_RESET_VECTOR = 0x{:02x} ",
|
||||||
|
new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize]
|
||||||
|
);
|
||||||
// println!("{:?}", new_program);
|
// println!("{:?}", new_program);
|
||||||
|
|
||||||
backplane.rom.program(&new_program);
|
backplane.rom.program(&new_program);
|
||||||
@ -22,5 +26,4 @@ fn main() {
|
|||||||
backplane.memory[0x6000] = ISA_OP_LDA_I;
|
backplane.memory[0x6000] = ISA_OP_LDA_I;
|
||||||
backplane.memory[0x6001] = 0xab;
|
backplane.memory[0x6001] = 0xab;
|
||||||
backplane.tick();
|
backplane.tick();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +1,3 @@
|
|||||||
pub mod parts;
|
pub mod parts;
|
||||||
|
pub mod backplane;
|
||||||
|
mod backplane;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
pub struct AddressBus {
|
pub struct AddressBus {
|
||||||
pub address: u16
|
pub address: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddressBus {
|
impl AddressBus {
|
||||||
|
|||||||
@ -1,15 +1,27 @@
|
|||||||
use core::mos6502cpu::Mos6502Cpu;
|
|
||||||
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
|
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
|
||||||
use crate::parts::via6522::VIA6522;
|
use crate::parts::via6522::VIA6522;
|
||||||
use core::constants::constants_system::*;
|
use core::constants::constants_system::*;
|
||||||
|
use core::mos6502cpu::Mos6502Cpu;
|
||||||
use core::periph::at28c256::At28C256;
|
use core::periph::at28c256::At28C256;
|
||||||
use core::periph::rom_chip::RomChip;
|
use core::periph::rom_chip::RomChip;
|
||||||
|
|
||||||
|
/// Backplane
|
||||||
|
///
|
||||||
|
/// A Backplane hold and coordinates the cpu with the
|
||||||
|
/// rest of the peripherals.
|
||||||
|
///
|
||||||
|
/// This system has
|
||||||
|
/// -> VIA6522 for peripherals
|
||||||
|
/// -> 322KB RAM
|
||||||
|
/// -> 32KB ROM
|
||||||
pub struct Backplane {
|
pub struct Backplane {
|
||||||
// pub for dev
|
// pub for dev
|
||||||
pub cpu: Mos6502Cpu,
|
pub cpu: Mos6502Cpu,
|
||||||
pub via: VIA6522,
|
pub via: VIA6522,
|
||||||
pub memory: Box<[u8; SIZE_64KB]>,
|
pub memory: Box<[u8; SIZE_32KB]>,
|
||||||
pub rom: At28C256
|
pub rom: At28C256,
|
||||||
|
data_bus: u8,
|
||||||
|
address_bus: u16
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backplane {
|
impl Backplane {
|
||||||
@ -17,8 +29,10 @@ impl Backplane {
|
|||||||
Backplane {
|
Backplane {
|
||||||
cpu: Mos6502Cpu::default(),
|
cpu: Mos6502Cpu::default(),
|
||||||
via: VIA6522::default(),
|
via: VIA6522::default(),
|
||||||
memory: Box::new([0x00; SIZE_64KB]),
|
memory: Box::new([0x00; SIZE_32KB]),
|
||||||
rom: At28C256::default()
|
rom: At28C256::default(),
|
||||||
|
data_bus: 0x00,
|
||||||
|
address_bus: 0x0000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,46 +42,85 @@ impl Backplane {
|
|||||||
|
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
// is the CPU in read or write state
|
// is the CPU in read or write state
|
||||||
let address = self.cpu.address_bus();
|
self.address_bus = self.cpu.address_bus();
|
||||||
let data = self.cpu.data_bus();
|
self.data_bus = self.cpu.data_bus();
|
||||||
let rw = self.cpu.read_signal;
|
let rw = self.cpu.read_signal;
|
||||||
println!("- TICK START:");
|
println!("- TICK START:");
|
||||||
println!("| CPU: Address: 0b{address:016b} Data: 0b{data:08b} CPU RW: {rw}");
|
println!("| CPU: Address: 0b{:016b} Data: 0b{:08b} CPU RW: {rw}", self.address_bus, self.data_bus);
|
||||||
// via state
|
// via state
|
||||||
println!("| VIA 0b{:08b}/0b{:08b}/0b{:08b}/0b{:08b}/",
|
println!(
|
||||||
|
"| VIA 0b{:08b}/0b{:08b}/0b{:08b}/0b{:08b}/",
|
||||||
self.via.read(VIA6522_ORA),
|
self.via.read(VIA6522_ORA),
|
||||||
self.via.read(VIA6522_ORA),
|
self.via.read(VIA6522_ORA),
|
||||||
self.via.read(VIA6522_DDRB),
|
self.via.read(VIA6522_DDRB),
|
||||||
self.via.read(VIA6522_DDRA),
|
self.via.read(VIA6522_DDRA),
|
||||||
);
|
);
|
||||||
println!("| LCD");
|
println!("| LCD");
|
||||||
match address {
|
|
||||||
/// VIA
|
|
||||||
0x6000..0x6010 => {
|
// if we are reading
|
||||||
if self.cpu.read_signal {
|
if rw {
|
||||||
self.cpu.set_data_bus(self.via.read((address - 0x6000) as u8));
|
println!("CPU HAS SET READ FLAG FOR ADDRESS {address:04x} with data 0x{data:02x}");
|
||||||
} else {
|
match self.address_bus {
|
||||||
self.via.write((address - 0x6000) as u8, self.cpu.data_bus());
|
|
||||||
}
|
|
||||||
self.via.tick();
|
|
||||||
}
|
|
||||||
/// RAM
|
|
||||||
0x0000..=0x3fff => {
|
0x0000..=0x3fff => {
|
||||||
if self.cpu.read_signal {
|
// read from ram
|
||||||
self.cpu.set_data_bus(self.memory[address as usize]);
|
|
||||||
} else {
|
},
|
||||||
self.memory[address as usize] = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// ROM
|
|
||||||
0x4000..=0x7fff => {
|
0x4000..=0x7fff => {
|
||||||
self.rom.read(&(address - 0x4000));
|
// read from ROM
|
||||||
|
|
||||||
}
|
}
|
||||||
/// The ether. Scarrrrrrrryyyy......
|
|
||||||
_ => {
|
_ => {
|
||||||
println!("Lost READ:?{} to {:04x}", self.cpu.read_signal, address);
|
println!("READ OUTSIDE DATA RANGE");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
println!("CPU HAS SET WRITE FLAG FOR ADDRESS 0x{address:04x} with data 0x{data:02x}");
|
||||||
|
match self.address_bus {
|
||||||
|
0x6000..=0x600f => {
|
||||||
|
self.via.write((self.address_bus - 0x6000) as u8, self.data_bus);
|
||||||
|
},
|
||||||
|
0x0000..=0x3fff => {
|
||||||
|
self.memory[self.address_bus] = self.data_bus;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("ATTEMPT TO WRITE OUTSIDE OF MEMORY");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// match address {
|
||||||
|
// /// VIA
|
||||||
|
// 0x6000..=0x600f => {
|
||||||
|
// if self.cpu.read_signal {
|
||||||
|
// self.cpu
|
||||||
|
// .set_data_bus(self.via.read((address - 0x6000) as u8));
|
||||||
|
// } else {
|
||||||
|
// self.via
|
||||||
|
// .write((address - 0x6000) as u8, self.cpu.data_bus());
|
||||||
|
// }
|
||||||
|
// self.via.tick();
|
||||||
|
// }
|
||||||
|
// /// RAM
|
||||||
|
// 0x0000..=0x3fff => {
|
||||||
|
// if self.cpu.read_signal {
|
||||||
|
// self.cpu.set_data_bus(self.memory[address as usize]);
|
||||||
|
// } else {
|
||||||
|
// self.memory[address as usize] = data;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// /// ROM
|
||||||
|
// 0x4000..=0x7fff => {
|
||||||
|
// println!("ROM READ AT {address:04x} / ROM OFFSET {:04x}", address - 0x4000);
|
||||||
|
// self.rom.read(&(address - 0x4000));
|
||||||
|
// }
|
||||||
|
// /// The ether. Scarrrrrrrryyyy......
|
||||||
|
// _ => {
|
||||||
|
// println!("XXXXLost READ:?{} to {:04x}", self.cpu.read_signal, address);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
println!("- TICK DONE");
|
println!("- TICK DONE");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,10 +1,10 @@
|
|||||||
|
use crate::parts::clock::Clock;
|
||||||
|
use core::constants::constants_system::*;
|
||||||
|
use core::mos6502cpu::Mos6502Cpu;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufReader, Read};
|
use std::io::{BufReader, Read};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use crate::parts::clock::Clock;
|
|
||||||
use core::mos6502cpu::Mos6502Cpu;
|
|
||||||
use core::constants::constants_system::*;
|
|
||||||
|
|
||||||
pub struct BenEaterPC {
|
pub struct BenEaterPC {
|
||||||
clock: Clock,
|
clock: Clock,
|
||||||
@ -19,7 +19,7 @@ impl BenEaterPC {
|
|||||||
println!("New BENEATERPC");
|
println!("New BENEATERPC");
|
||||||
BenEaterPC {
|
BenEaterPC {
|
||||||
clock: Clock::new(),
|
clock: Clock::new(),
|
||||||
cpu: Mos6502Cpu::default()
|
cpu: Mos6502Cpu::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,10 @@
|
|||||||
pub struct Clock {
|
pub struct Clock {
|
||||||
ticks: u32
|
ticks: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clock {
|
impl Clock {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
Clock { ticks: 0 }
|
||||||
Clock {
|
|
||||||
ticks: 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
|
use core::mos6502cpu::Mos6502Cpu;
|
||||||
use macroquad::color::{BLACK, Color};
|
use macroquad::color::{BLACK, Color};
|
||||||
use macroquad::prelude::*;
|
use macroquad::prelude::*;
|
||||||
use macroquad::text::draw_text;
|
use macroquad::text::draw_text;
|
||||||
use core::mos6502cpu::Mos6502Cpu;
|
|
||||||
|
|
||||||
pub struct CpuDisplay {}
|
pub struct CpuDisplay {}
|
||||||
impl CpuDisplay {
|
impl CpuDisplay {
|
||||||
@ -12,11 +12,41 @@ impl CpuDisplay {
|
|||||||
// ...build the interface
|
// ...build the interface
|
||||||
Self::draw_square(x_offset, y_offset, x_offset + 300.0, y_offset + 85.0, BLACK);
|
Self::draw_square(x_offset, y_offset, x_offset + 300.0, y_offset + 85.0, BLACK);
|
||||||
|
|
||||||
draw_text(format!("PC: 0x{:04x} / {}", pc, pc).as_str(), x_offset + 5.0, y_offset + 18.0, 15.0, BLACK);
|
draw_text(
|
||||||
draw_text(format!("A: 0x{:02x} X: 0x{:02x} Y: 0x{:02x}", a, x, y).as_str(), x_offset + 5.0, y_offset + 35.0, 15.0, BLACK);
|
format!("PC: 0x{:04x} / {}", pc, pc).as_str(),
|
||||||
draw_text(format!("Address: {:016b} | {:04x}", address_bus, address_bus).as_str(), x_offset + 5.0, y_offset + 55.0, 15.0, BLACK);
|
x_offset + 5.0,
|
||||||
draw_text(format!("Data: {:08b} | {:02x}", data_bus, data_bus).as_str(), x_offset + 5.0, y_offset + 75.0, 15.0, BLACK);
|
y_offset + 18.0,
|
||||||
draw_text(format!("MS: {:02x}", microsteps_remaining).as_str(), x_offset + 5.0, y_offset + 95.0, 15.0, BLACK);
|
15.0,
|
||||||
|
BLACK,
|
||||||
|
);
|
||||||
|
draw_text(
|
||||||
|
format!("A: 0x{:02x} X: 0x{:02x} Y: 0x{:02x}", a, x, y).as_str(),
|
||||||
|
x_offset + 5.0,
|
||||||
|
y_offset + 35.0,
|
||||||
|
15.0,
|
||||||
|
BLACK,
|
||||||
|
);
|
||||||
|
draw_text(
|
||||||
|
format!("Address: {:016b} | {:04x}", address_bus, address_bus).as_str(),
|
||||||
|
x_offset + 5.0,
|
||||||
|
y_offset + 55.0,
|
||||||
|
15.0,
|
||||||
|
BLACK,
|
||||||
|
);
|
||||||
|
draw_text(
|
||||||
|
format!("Data: {:08b} | {:02x}", data_bus, data_bus).as_str(),
|
||||||
|
x_offset + 5.0,
|
||||||
|
y_offset + 75.0,
|
||||||
|
15.0,
|
||||||
|
BLACK,
|
||||||
|
);
|
||||||
|
draw_text(
|
||||||
|
format!("MS: {:02x}", microsteps_remaining).as_str(),
|
||||||
|
x_offset + 5.0,
|
||||||
|
y_offset + 95.0,
|
||||||
|
15.0,
|
||||||
|
BLACK,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_square(x1: f32, y1: f32, x2: f32, y2: f32, color: Color) {
|
fn draw_square(x1: f32, y1: f32, x2: f32, y2: f32, color: Color) {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
pub struct DataBus {
|
pub struct DataBus {
|
||||||
pub data: u8
|
pub data: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataBus {
|
impl DataBus {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use std::time::{Duration, Instant};
|
|
||||||
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
|
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HD44780 {
|
pub struct HD44780 {
|
||||||
@ -46,7 +46,7 @@ impl Mos6522Peripheral for HD44780 {
|
|||||||
self.write_control_lines(
|
self.write_control_lines(
|
||||||
control & 1 << 2 == 0,
|
control & 1 << 2 == 0,
|
||||||
control & 1 << 1 == 0,
|
control & 1 << 1 == 0,
|
||||||
control & 1 == 0
|
control & 1 == 0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
pub mod clock;
|
|
||||||
pub mod ben_eater_pc;
|
|
||||||
pub mod via6522;
|
|
||||||
pub mod display_matrix;
|
|
||||||
pub mod address_bus;
|
pub mod address_bus;
|
||||||
pub mod data_bus;
|
|
||||||
pub mod cpu_display;
|
|
||||||
pub mod ram_display;
|
|
||||||
pub mod mos6522_peripheral;
|
|
||||||
pub mod backplane;
|
pub mod backplane;
|
||||||
|
pub mod ben_eater_pc;
|
||||||
|
pub mod clock;
|
||||||
|
pub mod cpu_display;
|
||||||
|
pub mod data_bus;
|
||||||
|
pub mod display_matrix;
|
||||||
|
pub mod mos6522_peripheral;
|
||||||
|
pub mod ram_display;
|
||||||
|
pub mod via6522;
|
||||||
|
|||||||
@ -4,10 +4,15 @@ pub struct RamDisplay {}
|
|||||||
|
|
||||||
impl RamDisplay {
|
impl RamDisplay {
|
||||||
pub fn render(ram: &Box<[u8]>, x_offset: f32, y_offset: f32) {
|
pub fn render(ram: &Box<[u8]>, x_offset: f32, y_offset: f32) {
|
||||||
Self::draw_square(x_offset, y_offset, x_offset + 200.0, y_offset + 300.0, BLACK);
|
Self::draw_square(
|
||||||
|
x_offset,
|
||||||
|
y_offset,
|
||||||
|
x_offset + 200.0,
|
||||||
|
y_offset + 300.0,
|
||||||
|
BLACK,
|
||||||
|
);
|
||||||
|
|
||||||
draw_text("RAM", x_offset + 5.0, y_offset + 5.0, 15.0, BLACK);
|
draw_text("RAM", x_offset + 5.0, y_offset + 5.0, 15.0, BLACK);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_square(x1: f32, y1: f32, x2: f32, y2: f32, color: Color) {
|
fn draw_square(x1: f32, y1: f32, x2: f32, y2: f32, color: Color) {
|
||||||
|
|||||||
@ -57,7 +57,6 @@ impl VIA6522 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn read(&self, addr: u8) -> u8 {
|
pub fn read(&self, addr: u8) -> u8 {
|
||||||
match (addr & 0x0F) {
|
match (addr & 0x0F) {
|
||||||
VIA6522_ORB => self.orb,
|
VIA6522_ORB => self.orb,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use core::instruction::Instruction;
|
|
||||||
use core::address_mode::AddressMode;
|
use core::address_mode::AddressMode;
|
||||||
|
use core::instruction::Instruction;
|
||||||
use core::operand::Operand;
|
use core::operand::Operand;
|
||||||
use core::operation::Operation;
|
use core::operation::Operation;
|
||||||
|
|
||||||
@ -11,7 +11,8 @@ fn main() {
|
|||||||
op: Operation::NOP,
|
op: Operation::NOP,
|
||||||
mode: AddressMode::Implied,
|
mode: AddressMode::Implied,
|
||||||
operand: Operand::None,
|
operand: Operand::None,
|
||||||
}, &[0xea]
|
},
|
||||||
|
&[0xea],
|
||||||
)];
|
)];
|
||||||
|
|
||||||
for (op, bytes) in instructions {
|
for (op, bytes) in instructions {
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
use core::mos6502cpu::Mos6502Cpu;
|
use core::mos6502cpu::Mos6502Cpu;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
let x = Mos6502Cpu::default();
|
let x = Mos6502Cpu::default();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/// Represents the various addressing modes of the 6502 CPU.
|
/// Represents the various addressing modes of the 6502 CPU.
|
||||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||||
pub enum AddressMode {
|
pub enum AddressMode {
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
|
|
||||||
/// BenEater computer represents the 'Ben Eater' 6502 breadboard computer.
|
/// BenEater computer represents the 'Ben Eater' 6502 breadboard computer.
|
||||||
/// This was built along watching the video series where Ben builds a
|
/// This was built along watching the video series where Ben builds a
|
||||||
/// 6502 on a breadboard and explains each step.
|
/// 6502 on a breadboard and explains each step.
|
||||||
///
|
///
|
||||||
pub struct BenEater {
|
pub struct BenEater {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
pub mod beneater;
|
pub mod beneater;
|
||||||
|
pub mod rom_only;
|
||||||
|
|||||||
25
core/src/computers/rom_only/backplane.rs
Normal file
25
core/src/computers/rom_only/backplane.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use crate::constants::constants_system::{SIZE_32KB, SIZE_64KB};
|
||||||
|
use crate::periph::hm62256::Hm62256;
|
||||||
|
use crate::periph::rom_chip::RomChip;
|
||||||
|
|
||||||
|
pub struct Backplane {
|
||||||
|
rom: Hm62256
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Backplane {
|
||||||
|
pub fn new() -> Backplane {
|
||||||
|
Backplane::program(&[0x00; SIZE_32KB])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn program(rom: &[u8; SIZE_32KB]) -> Backplane {
|
||||||
|
Backplane {
|
||||||
|
rom: *Hm62256::program(rom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tick(&mut self) {
|
||||||
|
println!("Preparing to tick.");
|
||||||
|
|
||||||
|
println!("Done ticking.");
|
||||||
|
}
|
||||||
|
}
|
||||||
1
core/src/computers/rom_only/mod.rs
Normal file
1
core/src/computers/rom_only/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod backplane;
|
||||||
@ -107,7 +107,6 @@ pub const ISA_OP_LDY_ZP: u8 = 0xa4;
|
|||||||
pub const ISA_OP_LDY_ZPX: u8 = 0xb4;
|
pub const ISA_OP_LDY_ZPX: u8 = 0xb4;
|
||||||
pub const ISA_OP_LDY_ABS: u8 = 0xac;
|
pub const ISA_OP_LDY_ABS: u8 = 0xac;
|
||||||
pub const ISA_OP_LDY_ABSX: u8 = 0xbc;
|
pub const ISA_OP_LDY_ABSX: u8 = 0xbc;
|
||||||
|
|
||||||
pub const ISA_OP_LSR_A: u8 = 0x4a;
|
pub const ISA_OP_LSR_A: u8 = 0x4a;
|
||||||
pub const ISA_OP_LSR_ZP: u8 = 0x46;
|
pub const ISA_OP_LSR_ZP: u8 = 0x46;
|
||||||
pub const ISA_OP_LSR_ZPX: u8 = 0x56;
|
pub const ISA_OP_LSR_ZPX: u8 = 0x56;
|
||||||
|
|||||||
@ -5,7 +5,6 @@ pub const SIZE_64KB: usize = SIZE_1KB * 64;
|
|||||||
pub const OFFSET_RESET_VECTOR: u16 = 0xfffc;
|
pub const OFFSET_RESET_VECTOR: u16 = 0xfffc;
|
||||||
pub const OFFSET_INT_VECTOR: u16 = 0xfffe;
|
pub const OFFSET_INT_VECTOR: u16 = 0xfffe;
|
||||||
|
|
||||||
|
|
||||||
pub const VIA6522_ORB: u8 = 0;
|
pub const VIA6522_ORB: u8 = 0;
|
||||||
pub const VIA6522_ORA: u8 = 1;
|
pub const VIA6522_ORA: u8 = 1;
|
||||||
pub const VIA6522_DDRB: u8 = 2;
|
pub const VIA6522_DDRB: u8 = 2;
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
pub mod constants_isa_stub;
|
|
||||||
pub mod constants_isa_op;
|
pub mod constants_isa_op;
|
||||||
|
pub mod constants_isa_stub;
|
||||||
pub mod constants_system;
|
pub mod constants_system;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,23 +0,0 @@
|
|||||||
use log::debug;
|
|
||||||
use crate::address_mode::AddressMode::*;
|
|
||||||
use crate::constants::constants_isa_op::*;
|
|
||||||
|
|
||||||
fn join_word(low: u8, high: u8) -> u16 {
|
|
||||||
((high as u16) << 8) | low as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_join_word() {
|
|
||||||
let low: u8 = 0xcd;
|
|
||||||
let high: u8 = 0xab;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
join_word(low, high),
|
|
||||||
0xabcd
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
use crate::address_mode::AddressMode;
|
|
||||||
use crate::address_mode::AddressMode::*;
|
|
||||||
use crate::mos6502flags::Mos6502Flag::*;
|
|
||||||
|
|
||||||
mod from_bytes;
|
|
||||||
mod to_bytes;
|
|
||||||
mod to_string;
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
use crate::address_mode::AddressMode;
|
|
||||||
use crate::address_mode::AddressMode::{Absolute, AbsoluteX, AbsoluteY, Immediate, IndirectX, IndirectY, ZeroPage, ZeroPageX, ZeroPageY};
|
|
||||||
use crate::constants::constants_isa_op::*;
|
|
||||||
|
|
||||||
fn split_word_hl(to_split: u16) -> (u8, u8) {
|
|
||||||
let low = (to_split & 0xff) as u8;
|
|
||||||
let high = ((to_split & 0xff00) >> 8) as u8;
|
|
||||||
(high, low)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn split_word_lh(to_split: u16) -> (u8, u8) {
|
|
||||||
let low = (to_split & 0xff) as u8;
|
|
||||||
let high = ((to_split & 0xff00) >> 8) as u8;
|
|
||||||
(low, high)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn split_le() {
|
|
||||||
let value = 0xabcd;
|
|
||||||
let (high, low) = split_word_hl(value);
|
|
||||||
|
|
||||||
assert_eq!(low, 0xcd);
|
|
||||||
assert_eq!(high, 0xab);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn split_be() {
|
|
||||||
let value = 0xabcd;
|
|
||||||
let (low, high) = split_word_lh(value);
|
|
||||||
|
|
||||||
assert_eq!(low, 0xcd);
|
|
||||||
assert_eq!(high, 0xab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
|
|
||||||
fn format(mode: &AddressMode, prefix: &str) -> String {
|
|
||||||
// let suffix = match mode {
|
|
||||||
// AddressMode::Implied => "",
|
|
||||||
// AddressMode::Accumulator => " A",
|
|
||||||
// AddressMode::Immediate(value) => &*format!(" #${value:02x}"),
|
|
||||||
// AddressMode::ZeroPage(value) => &*format!(" ${value:02x}"),
|
|
||||||
// AddressMode::ZeroPageX(value) => &*format!(" ${value:02x},X"),
|
|
||||||
// AddressMode::Absolute(offset) => &*format!(" ${offset:04x}"),
|
|
||||||
// AddressMode::AbsoluteX(offset) => &*format!(" ${offset:04x},X"),
|
|
||||||
// AddressMode::AbsoluteY(offset) => &*format!(" ${offset:04x},Y"),
|
|
||||||
// AddressMode::IndirectX(value) => &*format!(" (${value:02x},X)"),
|
|
||||||
// AddressMode::IndirectY(value) => &*format!(" (${value:02x}),Y"),
|
|
||||||
// AddressMode::ZeroPageY(value) => &*format!(" ${value:02x},Y")
|
|
||||||
// };
|
|
||||||
// format!("{}{}", prefix, suffix)
|
|
||||||
prefix.to_string()
|
|
||||||
}
|
|
||||||
@ -1,10 +1,36 @@
|
|||||||
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_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::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::*;
|
||||||
|
|
||||||
|
|
||||||
pub fn INSTRUCTION_CYCLES(instruction: u8) -> u8 {
|
pub fn INSTRUCTION_CYCLES(instruction: u8) -> u8 {
|
||||||
INSTRUCTION_TABLE[instruction as usize].unwrap().cycles
|
INSTRUCTION_TABLE[instruction as usize].unwrap().cycles
|
||||||
}
|
}
|
||||||
@ -723,7 +749,7 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
|
|||||||
operation: Operation::ROR,
|
operation: Operation::ROR,
|
||||||
mode: AddressMode::Accumulator,
|
mode: AddressMode::Accumulator,
|
||||||
length: 1,
|
length: 1,
|
||||||
cycles: 2
|
cycles: 2,
|
||||||
});
|
});
|
||||||
table[ISA_OP_ROR_ZP as usize] = Some(OpInfo {
|
table[ISA_OP_ROR_ZP as usize] = Some(OpInfo {
|
||||||
operation: Operation::ROR,
|
operation: Operation::ROR,
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
pub mod periph;
|
pub mod computers;
|
||||||
pub mod address_mode;
|
pub mod address_mode;
|
||||||
pub mod mos6502cpu;
|
|
||||||
pub mod instruction;
|
|
||||||
pub mod mos6502flags;
|
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod operation;
|
pub mod instruction;
|
||||||
|
pub mod instruction_table;
|
||||||
|
pub mod mos6502cpu;
|
||||||
|
pub mod mos6502flags;
|
||||||
pub mod op_info;
|
pub mod op_info;
|
||||||
pub mod operand;
|
pub mod operand;
|
||||||
pub mod instruction_table;
|
pub mod operation;
|
||||||
pub mod computers;
|
pub mod periph;
|
||||||
|
|||||||
@ -1,44 +1,45 @@
|
|||||||
use log::trace;
|
|
||||||
use crate::address_mode::AddressMode;
|
use crate::address_mode::AddressMode;
|
||||||
use crate::constants::constants_isa_op::ISA_OP_NOP;
|
use crate::constants::constants_isa_op::ISA_OP_NOP;
|
||||||
|
use crate::constants::constants_system::*;
|
||||||
use crate::instruction::Instruction;
|
use crate::instruction::Instruction;
|
||||||
use crate::mos6502flags::{Mos6502Flag, Mos6502Flags};
|
use crate::instruction_table::INSTRUCTION_TABLE;
|
||||||
use crate::mos6502flags::Mos6502Flag::*;
|
use crate::mos6502flags::Mos6502Flag::*;
|
||||||
|
use crate::mos6502flags::{Mos6502Flag, Mos6502Flags};
|
||||||
use crate::op_info::OpInfo;
|
use crate::op_info::OpInfo;
|
||||||
use crate::operand::Operand;
|
use crate::operand::Operand;
|
||||||
use crate::operation::Operation;
|
use crate::operation::Operation;
|
||||||
use crate::constants::constants_system::*;
|
use log::trace;
|
||||||
use crate::instruction_table::INSTRUCTION_TABLE;
|
|
||||||
|
|
||||||
pub struct Mos6502Cpu {
|
pub struct Mos6502Cpu {
|
||||||
memory: [u8; SIZE_64KB],
|
pub(crate) memory: [u8; SIZE_64KB],
|
||||||
/// accumulator
|
/// accumulator
|
||||||
a: u8,
|
pub(crate) a: u8,
|
||||||
/// x register
|
/// x register
|
||||||
x: u8,
|
pub(crate) x: u8,
|
||||||
/// y register
|
/// y register
|
||||||
y: u8,
|
pub(crate) y: u8,
|
||||||
/// cpu flags
|
/// cpu flags
|
||||||
flags: Mos6502Flags,
|
pub(crate) flags: Mos6502Flags,
|
||||||
/// program counter
|
/// program counter
|
||||||
pub pc: u16,
|
pub pc: u16,
|
||||||
/// stack offset
|
/// stack offset
|
||||||
s: u8,
|
pub(crate) s: u8,
|
||||||
pub microcode_step: u8,
|
pub microcode_step: u8,
|
||||||
address_bus: u16,
|
pub(crate) address_bus: u16,
|
||||||
data_bus: u8,
|
pub(crate) data_bus: u8,
|
||||||
ir: Instruction, // Instruction Register
|
pub(crate) ir: Instruction, // Instruction Register
|
||||||
oi: OpInfo,
|
pub(crate) oi: OpInfo,
|
||||||
has_reset: bool,
|
pub(crate) has_reset: bool,
|
||||||
iv: u16, // Interrupt Vector
|
pub(crate) iv: u16, // Interrupt Vector
|
||||||
cycle_carry: u16, // Value to hold between microsteps
|
pub(crate) cycle_carry: u16, // Value to hold between microsteps
|
||||||
ir_bytes: [u8; 4],
|
pub(crate) ir_bytes: [u8; 4],
|
||||||
/// CPU Read signal
|
/// CPU Read signal
|
||||||
pub read_signal: bool
|
pub read_signal: bool,
|
||||||
|
pub(crate) reset_vector: u16,
|
||||||
|
pub(crate) int_vector: u16
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mos6502Cpu {
|
impl Mos6502Cpu {
|
||||||
|
|
||||||
/// set_data_bus
|
/// set_data_bus
|
||||||
///
|
///
|
||||||
/// Sets data on the data bus.
|
/// Sets data on the data bus.
|
||||||
@ -71,7 +72,9 @@ impl Default for Mos6502Cpu {
|
|||||||
iv: 0xfffe,
|
iv: 0xfffe,
|
||||||
cycle_carry: 0x0000,
|
cycle_carry: 0x0000,
|
||||||
ir_bytes: [0x00; 4],
|
ir_bytes: [0x00; 4],
|
||||||
read_signal: true
|
read_signal: true,
|
||||||
|
reset_vector: 0x0000,
|
||||||
|
int_vector: 0x0000
|
||||||
};
|
};
|
||||||
working.reset_cpu();
|
working.reset_cpu();
|
||||||
working
|
working
|
||||||
@ -87,46 +90,27 @@ impl Mos6502Cpu {
|
|||||||
self.data_bus
|
self.data_bus
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new() -> Mos6502Cpu {
|
//
|
||||||
let array = [0x00u8; SIZE_64KB];
|
// fn read_word(&self, offset: &u16) -> u16 {
|
||||||
let mut working = Mos6502Cpu {
|
// println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1);
|
||||||
memory: array,
|
// let low = self.memory[*offset as usize];
|
||||||
ir_bytes: [0x00; 4],
|
// let high = self.memory[*offset as usize + 1];
|
||||||
..Default::default()
|
// println!("LOW = 0x{low:02x} HIGH = 0x{high:02x}");
|
||||||
};
|
// let result = (high as u16) << 8 | low as u16;
|
||||||
working.reset_cpu();
|
// // println!("MEMORY: {:?}", self.memory);
|
||||||
working
|
// println!("READ {result:04x}");
|
||||||
}
|
// result
|
||||||
|
// }
|
||||||
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);
|
|
||||||
println!("READ FROM {OFFSET_RESET_VECTOR} AND GOT {}", self.pc);
|
|
||||||
self.iv = self.read_word(&OFFSET_INT_VECTOR);
|
|
||||||
self.address_bus = self.pc;
|
|
||||||
self.read_signal = true;
|
|
||||||
println!("PC and IV are now set from ROM addresses / AB = {:016b}", self.address_bus);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_word(&self, offset: &u16) -> u16 {
|
|
||||||
println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1);
|
|
||||||
let low = self.memory[*offset as usize];
|
|
||||||
let high = self.memory[*offset as usize + 1];
|
|
||||||
println!("LOW = 0x{low:02x} HIGH = 0x{high:02x}");
|
|
||||||
let result = (high as u16) << 8 | low as u16;
|
|
||||||
// println!("MEMORY: {:?}", self.memory);
|
|
||||||
println!("READ {result:04x}");
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn peek_flag(&self, flag_to_read: Mos6502Flag) -> bool {
|
pub fn peek_flag(&self, flag_to_read: Mos6502Flag) -> bool {
|
||||||
self.flags.flag(flag_to_read)
|
self.flags.flag(flag_to_read)
|
||||||
}
|
}
|
||||||
pub fn poke_flag(&mut self, flag_to_set: Mos6502Flag, new_value: bool) {
|
pub fn poke_flag(&mut self, flag_to_set: Mos6502Flag, new_value: bool) {
|
||||||
if new_value { self.flags.set_flag(flag_to_set) } else { self.flags.clear_flag(flag_to_set) }
|
if new_value {
|
||||||
|
self.flags.set_flag(flag_to_set)
|
||||||
|
} else {
|
||||||
|
self.flags.clear_flag(flag_to_set)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek(&self, offset: u16) -> u8 {
|
pub fn peek(&self, offset: u16) -> u8 {
|
||||||
@ -139,16 +123,16 @@ impl Mos6502Cpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek_a(&self) -> u8 {
|
pub fn peek_a(&self) -> u8 {
|
||||||
|
println!("Readding register A => 0x{:02x}", self.a);
|
||||||
self.a
|
self.a
|
||||||
}
|
}
|
||||||
pub fn poke_a(&mut self, new_a: u8) {
|
pub fn poke_a(&mut self, new_a: u8) {
|
||||||
|
|
||||||
println!("Updating register A from [{}] to [{}]", self.a, new_a);
|
println!("Updating register A from [{}] to [{}]", self.a, new_a);
|
||||||
|
|
||||||
self.a = new_a;
|
self.a = new_a;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek_x(&self) -> u8 {
|
pub fn peek_x(&self) -> u8 {
|
||||||
|
println!("Readding register X => 0x{}", self.x);
|
||||||
self.x
|
self.x
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +159,6 @@ impl Mos6502Cpu {
|
|||||||
|
|
||||||
/// Ticks the CPU
|
/// Ticks the CPU
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
|
|
||||||
println!("PREPARiNG TO TICK CPU AT PC 0x{:04x}", self.pc);
|
println!("PREPARiNG TO TICK CPU AT PC 0x{:04x}", self.pc);
|
||||||
if self.microcode_step == 0 {
|
if self.microcode_step == 0 {
|
||||||
println!("OUT OF MICROSTEPS. Decoding the next instruction");
|
println!("OUT OF MICROSTEPS. Decoding the next instruction");
|
||||||
@ -190,12 +173,13 @@ impl Mos6502Cpu {
|
|||||||
// set the counter to the number of steps left
|
// set the counter to the number of steps left
|
||||||
} else {
|
} else {
|
||||||
// run 1 microcode step
|
// run 1 microcode step
|
||||||
println!("Microstep {}/{} for {:?}", self.microcode_step, self.oi.cycles, self.ir.op);
|
println!(
|
||||||
|
"Microstep {}/{} for {:?}",
|
||||||
|
self.microcode_step, self.oi.cycles, self.ir.op
|
||||||
|
);
|
||||||
match self.ir.op {
|
match self.ir.op {
|
||||||
Operation::ADC => {
|
Operation::ADC => match self.microcode_step {
|
||||||
match self.microcode_step {
|
1 => match self.ir.mode {
|
||||||
1 => {
|
|
||||||
match self.ir.mode {
|
|
||||||
AddressMode::Immediate => {}
|
AddressMode::Immediate => {}
|
||||||
AddressMode::ZeroPage => {}
|
AddressMode::ZeroPage => {}
|
||||||
AddressMode::ZeroPageX => {}
|
AddressMode::ZeroPageX => {}
|
||||||
@ -206,12 +190,10 @@ impl Mos6502Cpu {
|
|||||||
AddressMode::IndirectX => {}
|
AddressMode::IndirectX => {}
|
||||||
AddressMode::IndirectY => {}
|
AddressMode::IndirectY => {}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
2 => {},
|
2 => {}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
Operation::AND => {}
|
Operation::AND => {}
|
||||||
Operation::ASL => {}
|
Operation::ASL => {}
|
||||||
Operation::BCC => {}
|
Operation::BCC => {}
|
||||||
@ -247,10 +229,8 @@ impl Mos6502Cpu {
|
|||||||
AddressMode::ZeroPage => {
|
AddressMode::ZeroPage => {
|
||||||
// read from
|
// read from
|
||||||
let offset = match self.ir.operand {
|
let offset = match self.ir.operand {
|
||||||
Operand::Byte(z) => {
|
Operand::Byte(z) => z,
|
||||||
z
|
_ => 0x00,
|
||||||
}
|
|
||||||
_ => { 0x00 }
|
|
||||||
};
|
};
|
||||||
trace!("READING FROM MEMORY AT 0x{offset:04x}");
|
trace!("READING FROM MEMORY AT 0x{offset:04x}");
|
||||||
self.memory[offset as usize]
|
self.memory[offset as usize]
|
||||||
@ -258,37 +238,29 @@ impl Mos6502Cpu {
|
|||||||
}
|
}
|
||||||
AddressMode::ZeroPageX => {
|
AddressMode::ZeroPageX => {
|
||||||
let offset = match self.ir.operand {
|
let offset = match self.ir.operand {
|
||||||
Operand::Byte(z) => {
|
Operand::Byte(z) => z,
|
||||||
z
|
_ => 0x00,
|
||||||
}
|
|
||||||
_ => { 0x00 }
|
|
||||||
};
|
};
|
||||||
// self.memory.peek(offset + self.x);
|
// self.memory.peek(offset + self.x);
|
||||||
self.memory[offset as usize]
|
self.memory[offset as usize]
|
||||||
}
|
}
|
||||||
AddressMode::Absolute => {
|
AddressMode::Absolute => {
|
||||||
let offset = match self.ir.operand {
|
let offset = match self.ir.operand {
|
||||||
Operand::Word(offset) => {
|
Operand::Word(offset) => offset,
|
||||||
offset
|
_ => 0x00,
|
||||||
}
|
|
||||||
_ => { 0x00 }
|
|
||||||
};
|
};
|
||||||
// self.memory.peek(offset)
|
// self.memory.peek(offset)
|
||||||
self.memory[offset as usize]
|
self.memory[offset as usize]
|
||||||
}
|
}
|
||||||
AddressMode::AbsoluteX => {
|
AddressMode::AbsoluteX => {
|
||||||
let offset = match self.ir.operand {
|
let offset = match self.ir.operand {
|
||||||
Operand::Word(offset) => {
|
Operand::Word(offset) => offset,
|
||||||
offset
|
_ => 0x00,
|
||||||
}
|
|
||||||
_ => { 0x00 }
|
|
||||||
};
|
};
|
||||||
// self.memory.peek(offset + self.x);
|
// self.memory.peek(offset + self.x);
|
||||||
self.memory[offset as usize]
|
self.memory[offset as usize]
|
||||||
}
|
}
|
||||||
_ => {
|
_ => 0x00,
|
||||||
0x00
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// DEC write memory
|
// DEC write memory
|
||||||
@ -328,56 +300,47 @@ impl Mos6502Cpu {
|
|||||||
self.poke_flag(Carry, new_carry);
|
self.poke_flag(Carry, new_carry);
|
||||||
self.address_bus = self.pc;
|
self.address_bus = self.pc;
|
||||||
self.data_bus = 0x00;
|
self.data_bus = 0x00;
|
||||||
} }
|
}
|
||||||
Operation::JMP => {
|
}
|
||||||
match self.ir.operand {
|
Operation::JMP => match self.ir.operand {
|
||||||
Operand::Word(offset) => {
|
Operand::Word(offset) => {
|
||||||
self.pc = offset;
|
self.pc = offset;
|
||||||
self.address_bus = self.pc;
|
self.address_bus = self.pc;
|
||||||
self.data_bus = 0x00;
|
self.data_bus = 0x00;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
Operation::JSR => {
|
Operation::JSR => {
|
||||||
// push pc to stack.
|
// push pc to stack.
|
||||||
// jump to the subroutine.
|
// jump to the subroutine.
|
||||||
}
|
}
|
||||||
Operation::LDA => {
|
Operation::LDA => match self.oi.mode {
|
||||||
match self.oi.mode {
|
AddressMode::Immediate => match self.ir.operand {
|
||||||
AddressMode::Immediate => {
|
|
||||||
match self.ir.operand {
|
|
||||||
Operand::Byte(value) => {
|
Operand::Byte(value) => {
|
||||||
println!("Loading 0x{value:02x} ({value}) into A");
|
println!("Loading 0x{value:02x} ({value}) into A");
|
||||||
self.a = value;
|
self.a = value;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
},
|
||||||
}
|
AddressMode::ZeroPage => match self.ir.operand {
|
||||||
AddressMode::ZeroPage => {
|
|
||||||
match self.ir.operand {
|
|
||||||
Operand::Byte(value) => {
|
Operand::Byte(value) => {
|
||||||
println!("Loading from zero page at 0x{value:02x} ({value})");
|
println!("Loading from zero page at 0x{value:02x} ({value})");
|
||||||
self.a = self.memory[value as usize];
|
self.a = self.memory[value as usize];
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
},
|
||||||
}
|
AddressMode::ZeroPageX => match self.ir.operand {
|
||||||
AddressMode::ZeroPageX => {
|
|
||||||
match self.ir.operand {
|
|
||||||
Operand::Byte(value) => {
|
Operand::Byte(value) => {
|
||||||
let x_offset = self.x;
|
let x_offset = self.x;
|
||||||
self.a = self.memory[(value + x_offset) as usize];
|
self.a = self.memory[(value + x_offset) as usize];
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
AddressMode::Absolute => {
|
AddressMode::Absolute => {
|
||||||
if let Operand::Word(offset) = self.ir.operand {
|
if let Operand::Word(offset) = self.ir.operand {
|
||||||
println!("Loading from absolute address 0x{offset:04x}");
|
println!("Loading from absolute address 0x{offset:04x}");
|
||||||
self.a = self.memory[offset as usize];
|
self.a = self.memory[offset as usize];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
AddressMode::AbsoluteX => {
|
AddressMode::AbsoluteX => {
|
||||||
if let Operand::Word(offset) = self.ir.operand {
|
if let Operand::Word(offset) = self.ir.operand {
|
||||||
@ -386,6 +349,8 @@ impl Mos6502Cpu {
|
|||||||
}
|
}
|
||||||
AddressMode::AbsoluteY => {
|
AddressMode::AbsoluteY => {
|
||||||
if let Operand::Word(offset) = self.ir.operand {
|
if let Operand::Word(offset) = self.ir.operand {
|
||||||
|
let real_offset = offset + self.y as u16;
|
||||||
|
println!("offset: {offset:04x} + {:02x}", self.y);
|
||||||
self.a = self.memory[(offset + self.y as u16) as usize];
|
self.a = self.memory[(offset + self.y as u16) as usize];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -395,8 +360,7 @@ impl Mos6502Cpu {
|
|||||||
_ => {
|
_ => {
|
||||||
println!("INVALID ADDRESS MODE FOR LDA");
|
println!("INVALID ADDRESS MODE FOR LDA");
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
Operation::LDX => {}
|
Operation::LDX => {}
|
||||||
Operation::LDY => {}
|
Operation::LDY => {}
|
||||||
Operation::LSR => {}
|
Operation::LSR => {}
|
||||||
@ -501,13 +465,11 @@ impl Mos6502Cpu {
|
|||||||
Operation::TAY => {
|
Operation::TAY => {
|
||||||
self.y = self.a;
|
self.y = self.a;
|
||||||
}
|
}
|
||||||
Operation::TSX => {
|
Operation::TSX => {}
|
||||||
}
|
|
||||||
Operation::TXA => {
|
Operation::TXA => {
|
||||||
self.a = self.x;
|
self.a = self.x;
|
||||||
}
|
}
|
||||||
Operation::TXS => {
|
Operation::TXS => {}
|
||||||
}
|
|
||||||
Operation::TYA => {
|
Operation::TYA => {
|
||||||
self.y = self.a;
|
self.y = self.a;
|
||||||
}
|
}
|
||||||
@ -515,27 +477,13 @@ impl Mos6502Cpu {
|
|||||||
self.microcode_step -= 1;
|
self.microcode_step -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump(&self) {
|
|
||||||
println!("CPU State: PC: {:04x} / A: {:02x} / X: {:02x} / Y: {:02x} / ADDRESS: {:04x} / DATA: {:02x} / MICROSTEPS: {:02x} / S: {}",
|
|
||||||
self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus, self.microcode_step, self.flags.dump());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// dump_data
|
|
||||||
///
|
|
||||||
/// returns
|
|
||||||
/// PC, A, X, Y, Address_Bus, Data_Bus, Microcode_Step
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use super::*;
|
||||||
use crate::constants::constants_isa_op::*;
|
use crate::constants::constants_isa_op::*;
|
||||||
use crate::instruction_table::{INSTRUCTION_CYCLES, INSTRUCTION_TABLE};
|
use crate::instruction_table::{INSTRUCTION_CYCLES, INSTRUCTION_TABLE};
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn clc() {
|
fn clc() {
|
||||||
@ -548,7 +496,9 @@ mod test {
|
|||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
// Tick the CPU through the instruction
|
// Tick the CPU through the instruction
|
||||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_CLC as usize].unwrap().cycles { cpu.tick(); }
|
for _ in 0..INSTRUCTION_CYCLES(ISA_OP_CLC) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
|
|
||||||
assert!(!cpu.peek_flag(Carry));
|
assert!(!cpu.peek_flag(Carry));
|
||||||
}
|
}
|
||||||
@ -560,7 +510,9 @@ mod test {
|
|||||||
cpu.memory[0x6000] = ISA_OP_CLD;
|
cpu.memory[0x6000] = ISA_OP_CLD;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_CLD as usize].unwrap().cycles { cpu.tick(); }
|
for _ in 0..INSTRUCTION_CYCLES(ISA_OP_CLD) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
|
|
||||||
assert!(!cpu.peek_flag(Decimal));
|
assert!(!cpu.peek_flag(Decimal));
|
||||||
}
|
}
|
||||||
@ -572,10 +524,11 @@ mod test {
|
|||||||
cpu.memory[0x6000] = ISA_OP_CLI;
|
cpu.memory[0x6000] = ISA_OP_CLI;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_CLI) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_CLI) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
|
|
||||||
assert!(!cpu.peek_flag(Interrupt));
|
assert!(!cpu.peek_flag(Interrupt));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -585,7 +538,9 @@ mod test {
|
|||||||
cpu.memory[0x6000] = ISA_OP_CLV;
|
cpu.memory[0x6000] = ISA_OP_CLV;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_CLV) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_CLV) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
|
|
||||||
assert!(!cpu.peek_flag(Overflow));
|
assert!(!cpu.peek_flag(Overflow));
|
||||||
}
|
}
|
||||||
@ -597,7 +552,9 @@ mod test {
|
|||||||
cpu.memory[0x6001] = 0xab;
|
cpu.memory[0x6001] = 0xab;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_I) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_I) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(cpu.a, 0xab);
|
assert_eq!(cpu.a, 0xab);
|
||||||
}
|
}
|
||||||
@ -611,7 +568,9 @@ mod test {
|
|||||||
cpu.memory[0x00ac] = 0xbe;
|
cpu.memory[0x00ac] = 0xbe;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ZX) { cpu.tick(); };
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ZX) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
|
|
||||||
// println!("MEMORY AT 0x00aa, ab, ac, ad, ae -> {:02x} {:02x} {:02x} {:02x} {:02x}", cpu.memory[0x00aa], cpu.memory[0x00ab], cpu.memory[0x00ac], cpu.memory[0x00ad], cpu.memory[0x00ae]);
|
// println!("MEMORY AT 0x00aa, ab, ac, ad, ae -> {:02x} {:02x} {:02x} {:02x} {:02x}", cpu.memory[0x00aa], cpu.memory[0x00ab], cpu.memory[0x00ac], cpu.memory[0x00ad], cpu.memory[0x00ae]);
|
||||||
// cpu.dump();
|
// cpu.dump();
|
||||||
@ -630,7 +589,9 @@ mod test {
|
|||||||
cpu.memory[0x00ab] = 0xbe;
|
cpu.memory[0x00ab] = 0xbe;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..INSTRUCTION_CYCLES(ISA_OP_LDA_Z) { cpu.tick(); }
|
for _ in 0..INSTRUCTION_CYCLES(ISA_OP_LDA_Z) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(cpu.a, 0xbe);
|
assert_eq!(cpu.a, 0xbe);
|
||||||
}
|
}
|
||||||
@ -644,7 +605,9 @@ mod test {
|
|||||||
cpu.memory[0x0eef] = 0xab;
|
cpu.memory[0x0eef] = 0xab;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABS) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABS) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(cpu.a, 0xab);
|
assert_eq!(cpu.a, 0xab);
|
||||||
}
|
}
|
||||||
@ -659,7 +622,9 @@ mod test {
|
|||||||
cpu.memory[0x0ef0] = 0xab;
|
cpu.memory[0x0ef0] = 0xab;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSX) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSX) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(cpu.a, 0xab);
|
assert_eq!(cpu.a, 0xab);
|
||||||
}
|
}
|
||||||
@ -669,12 +634,14 @@ mod test {
|
|||||||
let mut cpu = Mos6502Cpu::default();
|
let mut cpu = Mos6502Cpu::default();
|
||||||
cpu.memory[0x6000] = ISA_OP_LDA_ABSY;
|
cpu.memory[0x6000] = ISA_OP_LDA_ABSY;
|
||||||
cpu.memory[0x6001] = 0xef;
|
cpu.memory[0x6001] = 0xef;
|
||||||
cpu.memory[0x6002] = 0xbe;
|
cpu.memory[0x6002] = 0x0e;
|
||||||
cpu.poke_y(0x01);
|
cpu.poke_y(0x01);
|
||||||
cpu.memory[0x0ef0] = 0xab;
|
cpu.memory[0x0ef0] = 0xab;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSY) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_LDA_ABSY) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(cpu.a, 0xab);
|
assert_eq!(cpu.a, 0xab);
|
||||||
}
|
}
|
||||||
@ -687,9 +654,13 @@ mod test {
|
|||||||
cpu.memory[0x6001] = ISA_OP_INX;
|
cpu.memory[0x6001] = ISA_OP_INX;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_DEX) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_DEX) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
assert_eq!(0xaa, cpu.x);
|
assert_eq!(0xaa, cpu.x);
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_INX) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_INX) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
assert_eq!(0xab, cpu.x);
|
assert_eq!(0xab, cpu.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,9 +672,13 @@ mod test {
|
|||||||
cpu.memory[0x6001] = ISA_OP_INY;
|
cpu.memory[0x6001] = ISA_OP_INY;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_DEY) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_DEY) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
assert_eq!(0xaa, cpu.peek_y());
|
assert_eq!(0xaa, cpu.peek_y());
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_INY) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_INY) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
assert_eq!(0xab, cpu.peek_y());
|
assert_eq!(0xab, cpu.peek_y());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -715,9 +690,28 @@ mod test {
|
|||||||
cpu.memory[0x6001] = ISA_OP_ROR_A;
|
cpu.memory[0x6001] = ISA_OP_ROR_A;
|
||||||
cpu.pc = 0x6000;
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_ROL_A) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_ROL_A) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
assert_eq!(cpu.peek_a(), 0b0101_0101);
|
assert_eq!(cpu.peek_a(), 0b0101_0101);
|
||||||
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_ROR_A) { cpu.tick(); }
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_ROR_A) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
assert_eq!(cpu.peek_a(), 0b1010_1010);
|
assert_eq!(cpu.peek_a(), 0b1010_1010);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rol_zp_ror_zp() {
|
||||||
|
let mut cpu = Mos6502Cpu::default();
|
||||||
|
cpu.memory[0x00ab] = 0b0101_0101;
|
||||||
|
cpu.memory[0x6000] = ISA_OP_ROL_ZP;
|
||||||
|
cpu.memory[0x6001] = 0xab;
|
||||||
|
cpu.pc = 0x6000;
|
||||||
|
|
||||||
|
for _ in 0..=INSTRUCTION_CYCLES(ISA_OP_ROL_ZP) {
|
||||||
|
cpu.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(cpu.memory[0xab], 0b1010_1010);;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
35
core/src/mos6502cpu/dbg.rs
Normal file
35
core/src/mos6502cpu/dbg.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use crate::mos6502cpu::cpu::Mos6502Cpu;
|
||||||
|
|
||||||
|
impl Mos6502Cpu {
|
||||||
|
/// dump_data
|
||||||
|
///
|
||||||
|
/// returns
|
||||||
|
/// PC, A, X, Y, Address_Bus, Data_Bus, Microcode_Step
|
||||||
|
pub fn dump_data(&self) -> (u16, u8, u8, u8, u16, u8, u8, u16, u16) {
|
||||||
|
(
|
||||||
|
self.pc,
|
||||||
|
self.a,
|
||||||
|
self.x,
|
||||||
|
self.y,
|
||||||
|
self.address_bus,
|
||||||
|
self.data_bus,
|
||||||
|
self.microcode_step,
|
||||||
|
self.reset_vector,
|
||||||
|
self.int_vector
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dump(&self) {
|
||||||
|
println!(
|
||||||
|
"CPU State: PC: {:04x} / A: {:02x} / X: {:02x} / Y: {:02x} / ADDRESS: {:04x} / DATA: {:02x} / MICROSTEPS: {:02x} / S: {}",
|
||||||
|
self.pc,
|
||||||
|
self.a,
|
||||||
|
self.x,
|
||||||
|
self.y,
|
||||||
|
self.address_bus,
|
||||||
|
self.data_bus,
|
||||||
|
self.microcode_step,
|
||||||
|
self.flags.dump()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
6
core/src/mos6502cpu/mod.rs
Normal file
6
core/src/mos6502cpu/mod.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
pub mod cpu;
|
||||||
|
pub mod new;
|
||||||
|
|
||||||
|
pub mod tick2;
|
||||||
|
mod dbg;
|
||||||
|
mod tick_stages;
|
||||||
26
core/src/mos6502cpu/new.rs
Normal file
26
core/src/mos6502cpu/new.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use crate::constants::constants_system::{OFFSET_RESET_VECTOR, SIZE_64KB};
|
||||||
|
use crate::mos6502cpu::cpu::Mos6502Cpu;
|
||||||
|
|
||||||
|
impl Mos6502Cpu {
|
||||||
|
pub fn new() -> Mos6502Cpu {
|
||||||
|
let array = [0x00u8; SIZE_64KB];
|
||||||
|
let mut working = Mos6502Cpu {
|
||||||
|
memory: array,
|
||||||
|
ir_bytes: [0x00; 4],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
working.reset_cpu();
|
||||||
|
working
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub(crate) fn reset_cpu(&mut self) {
|
||||||
|
self.microcode_step = 7 + 4;
|
||||||
|
// self = &mut Mos6502Cpu::default();
|
||||||
|
println!("Should tick 7 times, then 4 cycles to read the reset and int vectors.");
|
||||||
|
// read the value at 0xfffc 0xfffd for our reset vector.
|
||||||
|
// read the value at 0xfffe 0xffff for our int vector
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
64
core/src/mos6502cpu/tick2.rs
Normal file
64
core/src/mos6502cpu/tick2.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use crate::constants::constants_system::{OFFSET_INT_VECTOR, OFFSET_RESET_VECTOR};
|
||||||
|
use crate::mos6502cpu::cpu::Mos6502Cpu;
|
||||||
|
|
||||||
|
impl Mos6502Cpu {
|
||||||
|
/// AccurateTick
|
||||||
|
///
|
||||||
|
/// In: address_bus > Address of data operationm
|
||||||
|
/// data_bus > Data read or written
|
||||||
|
/// State:
|
||||||
|
/// read_bus > Flag for if cpu is reading or writing the data bus
|
||||||
|
/// cycle_step > Index for what step of the Decode->Load->Execute cycle we are in
|
||||||
|
/// Out: address_bus > address for operation
|
||||||
|
/// data_bus > data for the operation
|
||||||
|
/// 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) {
|
||||||
|
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;
|
||||||
|
} else {
|
||||||
|
// we are writing to the bus.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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 {
|
||||||
|
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;
|
||||||
|
// 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!");
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.microcode_step -= 1;
|
||||||
|
}
|
||||||
|
(self.address_bus, self.data_bus, self.read_signal)
|
||||||
|
}
|
||||||
|
}
|
||||||
19
core/src/mos6502cpu/tick_stages.rs
Normal file
19
core/src/mos6502cpu/tick_stages.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
/// Mos6502TickStates
|
||||||
|
///
|
||||||
|
/// The set of what a tick can be doing
|
||||||
|
///
|
||||||
|
enum Mos6502TickStates {
|
||||||
|
/// Loading the first byte into the IR
|
||||||
|
LoadingInstruction,
|
||||||
|
/// Loading an 8 bit parameter
|
||||||
|
Loading8BitParameter,
|
||||||
|
/// Loading the MSB 8 bits
|
||||||
|
Loading16BitParameter1,
|
||||||
|
/// Loading the LSB 8 bits
|
||||||
|
Loading16BitParameter2,
|
||||||
|
/// Stalling for accurate emulation
|
||||||
|
Stall(u8),
|
||||||
|
/// Completed the instruction
|
||||||
|
Complete
|
||||||
|
}
|
||||||
@ -1,4 +1,6 @@
|
|||||||
use crate::mos6502flags::Mos6502Flag::{Break, Carry, Decimal, Interrupt, Negative, Overflow, Zero};
|
use crate::mos6502flags::Mos6502Flag::{
|
||||||
|
Break, Carry, Decimal, Interrupt, Negative, Overflow, Zero,
|
||||||
|
};
|
||||||
|
|
||||||
pub const BIT_NEGATIVE: u8 = 7;
|
pub const BIT_NEGATIVE: u8 = 7;
|
||||||
pub const BIT_OVERFLOW: u8 = 6;
|
pub const BIT_OVERFLOW: u8 = 6;
|
||||||
@ -59,7 +61,7 @@ impl Mos6502Flag {
|
|||||||
Decimal => BIT_DECIMAL,
|
Decimal => BIT_DECIMAL,
|
||||||
Break => BIT_BREAK,
|
Break => BIT_BREAK,
|
||||||
Overflow => BIT_OVERFLOW,
|
Overflow => BIT_OVERFLOW,
|
||||||
Negative => BIT_NEGATIVE
|
Negative => BIT_NEGATIVE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,7 +79,8 @@ pub struct Mos6502Flags {
|
|||||||
|
|
||||||
impl Mos6502Flags {
|
impl Mos6502Flags {
|
||||||
pub fn dump(&self) -> String {
|
pub fn dump(&self) -> String {
|
||||||
format!("{}{}{}{}{}{}{}",
|
format!(
|
||||||
|
"{}{}{}{}{}{}{}",
|
||||||
if self.carry { 'C' } else { 'c' },
|
if self.carry { 'C' } else { 'c' },
|
||||||
if self.zero { 'Z' } else { 'z' },
|
if self.zero { 'Z' } else { 'z' },
|
||||||
if self.interrupt { 'I' } else { 'i' },
|
if self.interrupt { 'I' } else { 'i' },
|
||||||
@ -113,7 +116,8 @@ impl Mos6502Flags {
|
|||||||
Break => self.break_flag = false,
|
Break => self.break_flag = false,
|
||||||
Overflow => self.overflow = false,
|
Overflow => self.overflow = false,
|
||||||
Negative => self.negative = false,
|
Negative => self.negative = false,
|
||||||
} }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn change_flag(&mut self, flag_to_change: Mos6502Flag, new_value: bool) {
|
fn change_flag(&mut self, flag_to_change: Mos6502Flag, new_value: bool) {
|
||||||
if new_value {
|
if new_value {
|
||||||
@ -139,20 +143,32 @@ impl Mos6502Flags {
|
|||||||
pub fn as_byte(&self) -> u8 {
|
pub fn as_byte(&self) -> u8 {
|
||||||
let mut working = 0x00;
|
let mut working = 0x00;
|
||||||
|
|
||||||
if self.flag(Negative) { working += 1 << Negative.index(); }
|
if self.flag(Negative) {
|
||||||
if self.flag(Overflow) { working += 1 << Overflow.index(); }
|
working += 1 << Negative.index();
|
||||||
|
}
|
||||||
|
if self.flag(Overflow) {
|
||||||
|
working += 1 << Overflow.index();
|
||||||
|
}
|
||||||
working += 1 << 5; // Always Set
|
working += 1 << 5; // Always Set
|
||||||
if self.flag(Break) { working += 1 << Break.index(); }
|
if self.flag(Break) {
|
||||||
if self.flag(Decimal) { working += 1 << Decimal.index(); }
|
working += 1 << Break.index();
|
||||||
if self.flag(Interrupt) { working += 1 << Interrupt.index(); }
|
}
|
||||||
if self.flag(Zero) { working += 1 << Zero.index(); }
|
if self.flag(Decimal) {
|
||||||
if self.flag(Carry) { working += 1 << Carry.index(); }
|
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
|
working
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn from_byte(src: u8) -> Self {
|
pub fn from_byte(src: u8) -> Self {
|
||||||
let mut working = Self::default();
|
let mut working = Self::default();
|
||||||
|
|
||||||
@ -182,14 +198,15 @@ impl Mos6502Flags {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn smoke() { assert!(true); }
|
fn smoke() {
|
||||||
|
assert!(true);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sanity() {
|
fn sanity() {
|
||||||
|
|||||||
@ -356,5 +356,4 @@ pub enum Operation {
|
|||||||
///
|
///
|
||||||
/// Addressing Modes: Implied
|
/// Addressing Modes: Implied
|
||||||
TYA,
|
TYA,
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -6,10 +6,10 @@ impl Default for At28C256 {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let vec = vec![0xea; SIZE_32KB];
|
let vec = vec![0xea; SIZE_32KB];
|
||||||
let boxed_slice: Box<[u8]> = vec.into_boxed_slice();
|
let boxed_slice: Box<[u8]> = vec.into_boxed_slice();
|
||||||
let boxed_array: Box<[u8; SIZE_32KB]> = boxed_slice.try_into().expect("Failed to convert Vec to boxed array");
|
let boxed_array: Box<[u8; SIZE_32KB]> = boxed_slice
|
||||||
At28C256 {
|
.try_into()
|
||||||
data: boxed_array,
|
.expect("Failed to convert Vec to boxed array");
|
||||||
}
|
At28C256 { data: boxed_array }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,5 +18,7 @@ mod test {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn smoke() { assert!(true); }
|
fn smoke() {
|
||||||
|
assert!(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
mod default;
|
pub mod default;
|
||||||
mod rom_chip;
|
pub mod rom_chip;
|
||||||
|
pub mod tick;
|
||||||
|
|
||||||
use std::io::Read;
|
|
||||||
use crate::constants::constants_system::SIZE_32KB;
|
use crate::constants::constants_system::SIZE_32KB;
|
||||||
use crate::periph::rom_chip::RomChip;
|
use crate::periph::rom_chip::RomChip;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
/// At28C256
|
/// At28C256
|
||||||
///
|
///
|
||||||
@ -25,8 +26,8 @@ impl At28C256 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::constants::constants_system::SIZE_1KB;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::constants::constants_system::SIZE_1KB;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn smoke() {
|
fn smoke() {
|
||||||
@ -40,8 +41,7 @@ mod test {
|
|||||||
data.data[i] = 0xea;
|
data.data[i] = 0xea;
|
||||||
}
|
}
|
||||||
for offset in 0..SIZE_32KB {
|
for offset in 0..SIZE_32KB {
|
||||||
if offset.is_multiple_of(SIZE_1KB) {
|
if offset.is_multiple_of(SIZE_1KB) {};
|
||||||
};
|
|
||||||
assert_eq!(0xea, data.read(&(offset as u16)));
|
assert_eq!(0xea, data.read(&(offset as u16)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ use crate::periph::at28c256::At28C256;
|
|||||||
use crate::periph::rom_chip::RomChip;
|
use crate::periph::rom_chip::RomChip;
|
||||||
|
|
||||||
impl RomChip for At28C256 {
|
impl RomChip for At28C256 {
|
||||||
|
|
||||||
fn read(&self, offset: &u16) -> u8 {
|
fn read(&self, offset: &u16) -> u8 {
|
||||||
self.data[*offset as usize]
|
self.data[*offset as usize]
|
||||||
}
|
}
|
||||||
@ -21,7 +20,7 @@ mod test {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn smoke() { assert!(true); }
|
fn smoke() {
|
||||||
|
assert!(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
31
core/src/periph/at28c256/tick.rs
Normal file
31
core/src/periph/at28c256/tick.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use crate::periph::at28c256::At28C256;
|
||||||
|
use crate::periph::hm62256::Hm62256;
|
||||||
|
|
||||||
|
impl At28C256 {
|
||||||
|
fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) {
|
||||||
|
if !read_mode {
|
||||||
|
// has to be read mode. its a rom.
|
||||||
|
return (address_bus, data_bus)
|
||||||
|
}
|
||||||
|
(address_bus, self.data[address_bus as usize])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke() { assert!(true); }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn write_to_memory_read_back_works_at_0() {
|
||||||
|
let mut rom = At28C256::default();
|
||||||
|
|
||||||
|
rom.tick(0x0000, 0xab, false);
|
||||||
|
let (_, new_data) = rom.tick(0x0000, 0x00, true);
|
||||||
|
|
||||||
|
assert_eq!(new_data, 0xab);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,55 +1,40 @@
|
|||||||
// HM62256 Static Ram
|
// HM62256 Static Ram
|
||||||
|
|
||||||
use log::debug;
|
pub mod ramchip;
|
||||||
|
pub mod romchip;
|
||||||
|
pub mod tick;
|
||||||
|
|
||||||
use crate::constants::constants_system::SIZE_32KB;
|
use crate::constants::constants_system::SIZE_32KB;
|
||||||
use crate::periph::ram_chip::RamChip;
|
use crate::periph::ram_chip::RamChip;
|
||||||
use crate::periph::rom_chip::RomChip;
|
use crate::periph::rom_chip::RomChip;
|
||||||
|
use log::debug;
|
||||||
pub struct Hm62256 {
|
pub struct Hm62256 {
|
||||||
pub(crate) base_offset: u16,
|
pub(crate) base_offset: u16,
|
||||||
pub(crate) data: Box<[u8]>
|
pub(crate) data: Box<[u8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Hm62256 {
|
impl Default for Hm62256 {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let vec = vec![0x00; SIZE_32KB];
|
let vec = vec![0x00; SIZE_32KB];
|
||||||
let boxed_slice: Box<[u8]> = vec.into_boxed_slice();
|
let boxed_slice: Box<[u8]> = vec.into_boxed_slice();
|
||||||
let boxed_array: Box<[u8; SIZE_32KB]> = boxed_slice.try_into().expect("Unable to box the ram");
|
let boxed_array: Box<[u8; SIZE_32KB]> =
|
||||||
|
boxed_slice.try_into().expect("Unable to box the ram");
|
||||||
Hm62256 {
|
Hm62256 {
|
||||||
base_offset: 0x0000,
|
base_offset: 0x0000,
|
||||||
data: boxed_array
|
data: boxed_array,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RomChip for Hm62256 {
|
|
||||||
fn read(&self, offset: &u16) -> u8 {
|
|
||||||
// loops memory around past 32k
|
|
||||||
let effective = *offset as i32 % SIZE_32KB as i32;
|
|
||||||
self.data[effective as usize]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn program(_: &[u8; SIZE_32KB]) -> Box<Self> {
|
|
||||||
debug!("Dont program ram.");
|
|
||||||
Hm62256::default().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RamChip for Hm62256 {
|
|
||||||
fn write(&mut self, offset: &u16, value: &u8) {
|
|
||||||
let effective = *offset as i32 % SIZE_32KB as i32;
|
|
||||||
println!("Writing at E[{effective:04x}] / O[{offset:04x}]");
|
|
||||||
self.data[effective as usize] = *value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use rand::random;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use rand::random;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn smoke() { assert!(true) }
|
fn smoke() {
|
||||||
|
assert!(true)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn written_data_comes_back() {
|
fn written_data_comes_back() {
|
||||||
@ -58,7 +43,7 @@ mod test {
|
|||||||
// 100,000 random read/writes to ram that all read back right
|
// 100,000 random read/writes to ram that all read back right
|
||||||
for _ in 0..100_000 {
|
for _ in 0..100_000 {
|
||||||
let mut offset: u16 = random();
|
let mut offset: u16 = random();
|
||||||
println!("SIze = {SIZE_32KB}");
|
println!("Size = {SIZE_32KB}");
|
||||||
let value: u8 = random();
|
let value: u8 = random();
|
||||||
println!("Wrote [{value:02x}] to [{offset:04x}]");
|
println!("Wrote [{value:02x}] to [{offset:04x}]");
|
||||||
ram.write(&offset, &value);
|
ram.write(&offset, &value);
|
||||||
12
core/src/periph/hm62256/ramchip.rs
Normal file
12
core/src/periph/hm62256/ramchip.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use crate::constants::constants_system::SIZE_32KB;
|
||||||
|
use crate::periph::hm62256::Hm62256;
|
||||||
|
use crate::periph::ram_chip::RamChip;
|
||||||
|
|
||||||
|
impl RamChip for Hm62256 {
|
||||||
|
fn write(&mut self, offset: &u16, value: &u8) {
|
||||||
|
let effective = *offset as i32 % SIZE_32KB as i32;
|
||||||
|
println!("Writing at E[{effective:04x}] / O[{offset:04x}]");
|
||||||
|
self.data[effective as usize] = *value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
19
core/src/periph/hm62256/romchip.rs
Normal file
19
core/src/periph/hm62256/romchip.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use log::debug;
|
||||||
|
use crate::constants::constants_system::SIZE_32KB;
|
||||||
|
use crate::periph::hm62256::Hm62256;
|
||||||
|
use crate::periph::rom_chip::RomChip;
|
||||||
|
|
||||||
|
impl RomChip for Hm62256 {
|
||||||
|
|
||||||
|
|
||||||
|
fn read(&self, offset: &u16) -> u8 {
|
||||||
|
// loops memory around past 32k
|
||||||
|
let effective = *offset as i32 % SIZE_32KB as i32;
|
||||||
|
self.data[effective as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn program(_: &[u8; SIZE_32KB]) -> Box<Self> {
|
||||||
|
debug!("Dont program ram.");
|
||||||
|
Hm62256::default().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
33
core/src/periph/hm62256/tick.rs
Normal file
33
core/src/periph/hm62256/tick.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use crate::periph::hm62256::Hm62256;
|
||||||
|
|
||||||
|
impl Hm62256 {
|
||||||
|
fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) {
|
||||||
|
let new_data_bus = if read_mode {
|
||||||
|
// reading from ram
|
||||||
|
self.data[address_bus as usize]
|
||||||
|
} else {
|
||||||
|
// writing to ram
|
||||||
|
self.data[address_bus as usize] = data_bus.into();
|
||||||
|
data_bus
|
||||||
|
};
|
||||||
|
(address_bus, new_data_bus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke() { assert!(true); }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn write_to_memory_read_back_works_at_0() {
|
||||||
|
let mut ram = Hm62256::default();
|
||||||
|
|
||||||
|
ram.tick(0x0000, 0xab, false);
|
||||||
|
let (_, new_data) = ram.tick(0x0000, 0x00, true);
|
||||||
|
|
||||||
|
assert_eq!(new_data, 0xab);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,5 @@
|
|||||||
pub mod rom_chip;
|
pub mod rom_chip;
|
||||||
|
|
||||||
pub mod at28c256;
|
pub mod at28c256;
|
||||||
pub mod ram_chip;
|
|
||||||
pub mod hm62256;
|
pub mod hm62256;
|
||||||
|
pub mod ram_chip;
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
|
||||||
@ -0,0 +1 @@
|
|||||||
|
|
||||||
@ -5,3 +5,4 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
macroquad.workspace = true
|
macroquad.workspace = true
|
||||||
|
core = { path = "../core" }
|
||||||
31
macroquad/src/bin/rom_only.rs
Normal file
31
macroquad/src/bin/rom_only.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use macroquad::prelude::*;
|
||||||
|
use core::computers::rom_only::backplane::Backplane;
|
||||||
|
pub struct UiState {
|
||||||
|
display_offset: u16,
|
||||||
|
current_offset: u16
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macroquad::main("Rom_Only")]
|
||||||
|
async fn main() {
|
||||||
|
|
||||||
|
let mut backplane = Backplane::new();
|
||||||
|
let mut state = UiState { display_offset: 0x00, current_offset: 0x00 };
|
||||||
|
|
||||||
|
loop {
|
||||||
|
clear_background(BLUE);
|
||||||
|
|
||||||
|
draw_text("ROM ONLY", 20.0, 20.0, 30.0, DARKGRAY);
|
||||||
|
|
||||||
|
backplane.tick();
|
||||||
|
|
||||||
|
draw_text(
|
||||||
|
format!("Display Offset: 0x{:04x}", state.display_offset).as_str(), 20.0, 60.0, 30.0, DARKGRAY
|
||||||
|
);
|
||||||
|
|
||||||
|
draw_text(
|
||||||
|
format!("Current Offset: 0x{:04x}", state.current_offset).as_str(), 20.0, 100.0, 30.0, DARKGRAY
|
||||||
|
);
|
||||||
|
|
||||||
|
next_frame().await
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user