Compare commits

7 Commits

Author SHA1 Message Date
tmerritt c4e1f233ae more chips
more docs
2025-08-02 11:17:23 -04:00
tmerritt 7ac8bd86ba MOS6520 looking mostly there. 2025-07-29 13:12:33 -04:00
tmerritt 8f6f9cb64d adds docs
working on widetick
2025-07-26 11:02:36 -04:00
tmerritt b40c3c503f box swap 2025-07-22 15:51:21 -04:00
tmerritt d5efabdd36 prep to do big tick method 2025-07-21 13:41:17 -04:00
tmerritt 7498489b03 RamRomComputer now reads from ROM and writes to RAM and reads back from RAM 2025-07-18 16:09:41 -04:00
tmerritt 2939e1cac5 Lots of stuff. 2025-07-17 11:51:05 -04:00
159 changed files with 6853 additions and 2475 deletions
-5
View File
@@ -1,5 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/mos6502.iml" filepath="$PROJECT_DIR$/.idea/mos6502.iml" />
</modules>
</component>
</project>
-13
View File
@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="EMPTY_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/cli/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/core/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/macroquad/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
Generated
+2894 -217
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -3,7 +3,8 @@ members = [
"core", "core",
"cli", "cli",
"macroquad", "macroquad",
"beneater" # "beneater"
"egui"
] ]
resolver="2" resolver="2"
+5 -1
View File
@@ -8,6 +8,10 @@ fn main() {
let mut backplane = Backplane::new(); let mut backplane = Backplane::new();
for i in 0..12 {
backplane.tick();
}
//backplane.load_rom(); //backplane.load_rom();
println!("Backplane is live."); println!("Backplane is live.");
@@ -16,7 +20,7 @@ fn main() {
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!( println!(
"VALUE AT OFFSET_RESET_VECTOR = 0x{:02x} ", "VALUE AT OFFSET_RESET_VECTOR = 0x{:04x} ",
new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize] new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize]
); );
// println!("{:?}", new_program); // println!("{:?}", new_program);
+4 -4
View File
@@ -1,9 +1,9 @@
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::cpu::Mos6502Cpu; use core::mos6502cpu::Mos6502Cpu;
use core::periph::at28c256::At28C256; use core::periph::at28c256::At28C256;
use core::periph::rom_chip::RomChip; use core::traits::rom_chip::RomChip;
use core::constants::constants_via6522::*; use core::constants::constants_via6522::*;
/// Backplane /// Backplane
@@ -19,7 +19,7 @@ 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_32KB]>, pub memory: Box<[u8]>,
pub rom: At28C256, pub rom: At28C256,
data_bus: u8, data_bus: u8,
address_bus: u16 address_bus: u16
@@ -38,7 +38,7 @@ impl Backplane {
} }
pub fn load_rom(&mut self, to_load: &[u8; SIZE_32KB]) { pub fn load_rom(&mut self, to_load: &[u8; SIZE_32KB]) {
self.rom.program(to_load); self.rom.program((*to_load).into());
} }
pub fn tick(&mut self) { pub fn tick(&mut self) {
+1
View File
@@ -201,6 +201,7 @@ mod tests {
} }
#[test] #[test]
#[ignore]
fn test_write_data() { fn test_write_data() {
let mut lcd = HD44780::new(); let mut lcd = HD44780::new();
lcd.set_data_bus(0x41); // 'A' lcd.set_data_bus(0x41); // 'A'
+4
View File
@@ -162,6 +162,7 @@ mod tests {
} }
#[test] #[test]
#[ignore]
fn test_timer1_write_and_tick() { fn test_timer1_write_and_tick() {
let mut via = VIA6522::new(); let mut via = VIA6522::new();
@@ -180,6 +181,7 @@ mod tests {
} }
#[test] #[test]
#[ignore]
fn test_timer2_write_and_tick() { fn test_timer2_write_and_tick() {
let mut via = VIA6522::new(); let mut via = VIA6522::new();
via.t2_enabled = true; via.t2_enabled = true;
@@ -194,6 +196,7 @@ mod tests {
} }
#[test] #[test]
#[ignore]
fn test_interrupt_enable_disable() { fn test_interrupt_enable_disable() {
let mut via = VIA6522::new(); let mut via = VIA6522::new();
@@ -205,6 +208,7 @@ mod tests {
} }
#[test] #[test]
#[ignore]
fn test_clear_interrupt_flags() { fn test_clear_interrupt_flags() {
let mut via = VIA6522::new(); let mut via = VIA6522::new();
via.ifr = 0xFF; via.ifr = 0xFF;
-2
View File
@@ -18,6 +18,4 @@ fn main() {
for (op, bytes) in instructions { for (op, bytes) in instructions {
assert_eq!(Instruction::decode(bytes), Some(op)); assert_eq!(Instruction::decode(bytes), Some(op));
} }
// let instruction = Instruction::decode(&[0xea]);
// println!("NOP Decoded -> {:?}", instruction);
} }
+2 -2
View File
@@ -1,5 +1,5 @@
use core::computers::kim1::Kim1; use core::computers::kim1::Kim1;
use core::constants::constants_system::*;
fn main() { fn main() {
println!("Taxation is theft."); println!("Taxation is theft.");
@@ -12,7 +12,7 @@ fn main() {
kim.tick(); kim.tick();
num_ticks += 1; num_ticks += 1;
if num_ticks == 11 { if num_ticks == MOS6502_RESET_CYCLE_COUNT {
println!("Got our 11 ticks. time to hotwire this pc."); println!("Got our 11 ticks. time to hotwire this pc.");
kim.running = true; kim.running = true;
kim.dump(); kim.dump();
+27
View File
@@ -1,3 +1,5 @@
use core::computers::ram_rom::RamRomComputer;
use core::traits::backplane::Backplane;
use std::fs; use std::fs;
fn main() { fn main() {
@@ -18,4 +20,29 @@ fn main() {
}; };
let mut computer = RamRomComputer::new();
// Read byte from ROM 0x4000
println!("-- ");
computer.set_read_mode(true);
computer.set_address_bus(0x4020);
computer.tick();
println!("-- ");
// Data Bus contains value from ROM
let read_from_rom = computer.data_bus();
// Write byte to RAM 0x0000
computer.set_read_mode(false);
computer.set_address_bus(0x0001);
computer.tick();
println!("-- ");
// Read byte from RAM
computer.set_read_mode(true);
computer.set_address_bus(0x0001);
computer.tick();
println!("-- ");
let read_from_ram = computer.data_bus();
assert_eq!(read_from_rom, read_from_ram);
println!("Test passed. We read the same from ROM as we did from RAM - {} == {}", read_from_rom, read_from_ram);
} }
-47
View File
@@ -1,47 +0,0 @@
use std::fs;
use clap::Parser;
use core::computers::rom_only::backplane::RomOnlyComputer;
use core::periph::backplane::Backplane;
#[derive(Parser)]
struct CliOptions {
offset: u16,
bytes: u16,
filename: String
}
fn main() {
println!("Taxation is theft");
// let opts = CliOptions::parse();
let path = "/home/tmerritt/Projects/mos6502/resources/test/periph/at28c256/checksum.bin";
let bytes = match fs::read(path) {
Ok(bytes) => {
println!("Read {} bytes.", bytes.len());
bytes
},
Err(e) => {
eprintln!("FAIL to read rom.");
panic!("No rom no run.");
vec![]
}
};
let mut rom_only = RomOnlyComputer::program((&bytes[..]).to_vec());
rom_only.set_read_mode(true);
rom_only.set_address_bus(0x05);
rom_only.tick();
println!("COMPUTER: Read {:02x} from ROM", rom_only.data_bus()) ;
println!("COMPUTER: Read {:04x} from Address Bus", rom_only.address_bus());
println!("----");
rom_only.set_read_mode(true);
rom_only.set_address_bus(0x07);
rom_only.tick();
println!("COMPUTER: Read {:02x} from ROM", rom_only.data_bus()) ;
println!("COMPUTER: Read {:04x} from Address Bus", rom_only.address_bus());
println!("----");
}
+6
View File
@@ -0,0 +1,6 @@
use core::computers::single_breadboard::SingleBreadboard;
fn main() {
let sb = SingleBreadboard::new();
}
-5
View File
@@ -1,5 +0,0 @@
use core::mos6502cpu::cpu::Mos6502Cpu;
fn main() {
let x = Mos6502Cpu::default();
}
+2
View File
@@ -0,0 +1,2 @@
mod ram_rom_tests;
mod rom_only_test;
+16
View File
@@ -0,0 +1,16 @@
use core::computers::ram_rom::RamRomComputer;
use core::traits::backplane::Backplane;
const RAM_START: u16 = 0x4000;
const ROM_START: u16 = 0x0000;
#[test]
fn ram_rom_thintick() {
let mut ramrom = RamRomComputer::new();
ramrom.tick2(0x0001, 1, 0x00);
println!("DataBus: {}", ramrom.data_bus());
ramrom.tick2(0x4001, 1,0xab);
println!("DataBus: {}", ramrom.data_bus());
ramrom.tick2(0x4001, 1,0x00);
println!("DataBus: {}", ramrom.data_bus());
}
+42
View File
@@ -0,0 +1,42 @@
use core::computers::rom_only::RomOnlyComputer;
use core::traits::backplane::Backplane;
#[test]
fn rom_only_widetick_test() {
let bytes = include_bytes!("/home/tmerritt/Projects/mos6502/resources/test/periph/at28c256/checksum.bin");
let mut rom_only = RomOnlyComputer::program((&bytes[..]).to_vec());
rom_only.tick2(0x05, 0x00, 0x00);
assert_eq!(rom_only.data_bus(), 0x05);
assert_eq!(rom_only.address_bus(), 0x05);
rom_only.tick2(0x07, 0x00, 0x00);
assert_eq!(rom_only.data_bus(), 0x07);
assert_eq!(rom_only.address_bus(), 0x07);
rom_only.tick2(0x09, 0x00, 0x00);
assert_eq!(rom_only.data_bus(), 0x09);
assert_eq!(rom_only.address_bus(), 0x09);
}
#[test]
fn rom_only_thintick_test() {
let bytes = include_bytes!("/home/tmerritt/Projects/mos6502/resources/test/periph/at28c256/checksum.bin");
let mut rom_only = RomOnlyComputer::program((&bytes[..]).to_vec());
rom_only.set_read_mode(true);
rom_only.set_address_bus(0x05);
rom_only.tick();
assert_eq!(rom_only.data_bus(), 0x05);
assert_eq!(rom_only.address_bus(), 0x05);
rom_only.set_read_mode(true);
rom_only.set_address_bus(0x07);
rom_only.tick();
assert_eq!(rom_only.data_bus(), 0x07);
assert_eq!(rom_only.address_bus(), 0x07);
}
-25
View File
@@ -1,25 +0,0 @@
use crate::mos6502cpu::cpu::Mos6502Cpu;
use crate::periph::ram_chip::RamChip;
/// BackplaneBuilder
///
/// Builds a Backplane for a 6502 Emulated PC
struct BackplaneBuilder {
cpu: Mos6502Cpu,
// ram_modules: Vec<dyn RamChip>
}
impl BackplaneBuilder {
pub fn add_cpu(mut self, new_cpu: Mos6502Cpu) -> Self {
self.cpu = new_cpu;
self
}
pub fn add_ram(mut self, new_ram: impl RamChip) -> Self {
// self.ram_modules.push(new_ram);
self
}
}
+52
View File
@@ -0,0 +1,52 @@
use crate::computers::beneater::BenEater;
use crate::traits::backplane::Backplane;
impl Backplane for BenEater {
fn data_bus(&self) -> u8 {
self.data_bus
}
fn address_bus(&self) -> u16 {
self.address_bus
}
fn read_mode(&self) -> bool {
self.read_mode
}
fn set_read_mode(&mut self, new_mode: bool) {
self.read_mode = new_mode
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
fn tick(&mut self) {
println!("Tick the system.");
self.tick_ram(self.address_bus, self.data_bus, true, true, true);
self.tick_rom(self.address_bus, true, true);
self.tick_via(self.address_bus, self.data_bus, true, true, self.read_mode, true, true);
}
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
println!("Ticking RAM");
0x00
}
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
println!("Ticking ROM");
0x00
}
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
println!("Ticking VIA 6522");
let (new_address, new_data) = self.via.tick(self.address_bus, self.data_bus, false, self.read_mode);
(new_data, false, false)
}
}
+22 -1
View File
@@ -1 +1,22 @@
pub mod beneater; mod backplane;
use crate::mos6502cpu::Mos6502Cpu;
use crate::periph::mos6522::Mos6522;
/*
SBC Designed by Ben Eater
0x0000 -> 0x3fff -> RAM (16KB)
0x4000 -> 0x5fff -> UNUSED
0x6000 -> 0x600f -> VIA
0x6010 -> 0x7fff -> UNUSED
0x8000 -> 0xffff -> ROM (32KB)
*/
pub struct BenEater {
cpu: Mos6502Cpu,
via: Mos6522,
data_bus: u8,
address_bus: u16,
read_mode: bool
}
+2 -7
View File
@@ -2,15 +2,10 @@ pub mod new;
pub mod tick; pub mod tick;
pub mod reset; pub mod reset;
use std::fs; use crate::mos6502cpu::Mos6502Cpu;
use std::path::Path;
use crate::constants::constants_system::SIZE_1KB;
use crate::mos6502cpu::cpu::Mos6502Cpu;
use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256; use crate::periph::hm62256::Hm62256;
use crate::periph::kim1_keypad::Kim1Keypad; use crate::periph::kim1_keypad::Kim1Keypad;
use crate::periph::mos6522::mos6522::Mos6522; use crate::periph::mos6530::Mos6530;
use crate::periph::mos6530::mos6530::Mos6530;
/// Represents a KIM-1 /// Represents a KIM-1
/// ///
+3 -3
View File
@@ -1,7 +1,7 @@
use crate::computers::kim1::Kim1; use crate::computers::kim1::Kim1;
use crate::periph::hm62256::Hm62256; use crate::periph::hm62256::Hm62256;
use crate::periph::kim1_keypad::Kim1Keypad; use crate::periph::kim1_keypad::Kim1Keypad;
use crate::periph::mos6530::mos6530::Mos6530; use crate::periph::mos6530::Mos6530;
impl Kim1 { impl Kim1 {
pub fn dump(&self) { pub fn dump(&self) {
@@ -13,8 +13,8 @@ impl Kim1 {
} }
pub fn new() -> Self { pub fn new() -> Self {
let rriot1_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/kim1/6530-002_fillerbyte00-0x1c00.bin"); let rriot1_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/pia/6530-002_fillerbyte00-0x1c00.bin");
let rriot2_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/kim1/6530-003_fillerbyte00-0x1800.bin"); let rriot2_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/pia/6530-003_fillerbyte00-0x1800.bin");
Self { Self {
cpu: Default::default(), cpu: Default::default(),
+3 -3
View File
@@ -1,11 +1,11 @@
use crate::computers::kim1::Kim1; use crate::computers::kim1::Kim1;
use crate::periph::hm62256::Hm62256; use crate::periph::hm62256::Hm62256;
use crate::periph::mos6530::mos6530::Mos6530; use crate::periph::mos6530::Mos6530;
impl Kim1 { impl Kim1 {
pub fn reset(&mut self) { pub fn reset(&mut self) {
let rriot1_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/kim1/6530-002_fillerbyte00-0x1c00.bin"); let rriot1_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/pia/6530-002_fillerbyte00-0x1c00.bin");
let rriot2_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/kim1/6530-003_fillerbyte00-0x1800.bin"); let rriot2_rom = include_bytes!("/home/tmerritt/Projects/mos6502/resources/pia/6530-003_fillerbyte00-0x1800.bin");
self.cpu = Default::default(); self.cpu = Default::default();
self.rriot1 = Mos6530::new(0x1700, 0x1780, 0x1800, rriot1_rom.as_array().unwrap()); self.rriot1 = Mos6530::new(0x1700, 0x1780, 0x1800, rriot1_rom.as_array().unwrap());
self.rriot2 = Mos6530::new(0x1740, 0x17c0, 0x1c00, rriot2_rom.as_array().unwrap()); self.rriot2 = Mos6530::new(0x1740, 0x17c0, 0x1c00, rriot2_rom.as_array().unwrap());
+2
View File
@@ -2,3 +2,5 @@ pub mod beneater;
pub mod rom_only; pub mod rom_only;
pub mod kim1; pub mod kim1;
pub mod ram_rom; pub mod ram_rom;
pub mod tim1;
pub mod single_breadboard;
+43 -25
View File
@@ -1,15 +1,9 @@
use log::debug;
use crate::computers::ram_rom::RamRomComputer;
use crate::periph::at28c256::At28C256; use crate::periph::at28c256::At28C256;
use crate::periph::backplane::Backplane; use crate::traits::backplane::Backplane;
use crate::periph::hm62256::Hm62256; use crate::periph::hm62256::Hm62256;
pub struct RamRomComputer {
rom: At28C256,
ram: Hm62256,
data_bus: u8,
address_bus: u16,
read_mode: bool,
}
impl Backplane for RamRomComputer { impl Backplane for RamRomComputer {
fn data_bus(&self) -> u8 { fn data_bus(&self) -> u8 {
self.data_bus self.data_bus
@@ -23,31 +17,55 @@ impl Backplane for RamRomComputer {
self.read_mode self.read_mode
} }
fn tick(&mut self) {
todo!()
}
fn set_read_mode(&mut self, new_mode: bool) { fn set_read_mode(&mut self, new_mode: bool) {
self.read_mode = new_mode; self.read_mode = new_mode;
} }
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value;
}
fn set_address_bus(&mut self, new_value: u16) { fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value; self.address_bus = new_value;
} }
fn set_data_bus(&mut self, new_value: u8) { fn tick(&mut self) {
self.data_bus = new_value; println!("Preparing to tick the backplane. - ${:04x} ${:02x} {}", self.address_bus, self.data_bus, self.read_mode);
}
}
impl RamRomComputer { // who are we talking to?
pub fn new() -> RamRomComputer { match self.address_bus {
RamRomComputer { 0x0000..=0x3fff => {
rom: At28C256::default(), // RAM
ram: Hm62256::default(), println!("ADDRESSING RAM");
data_bus: 0x00, let (ram_address_bus, ram_data_bus) = self.ram.tick(self.address_bus, self.data_bus, self.read_mode, true);
address_bus: 0x0000, if self.read_mode {
/// is the CPU reading from the 'other' device? self.data_bus = ram_data_bus;
read_mode: true }
},
0x4000..=0x7fff => {
// ROM
println!("ADDRESSING ROM");
let rom_data_bus = self.rom.signal_tick(self.address_bus, self.data_bus, true, true, true);
self.data_bus = rom_data_bus;
}
_ => {
// Out of range
}
} }
} }
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
debug!("Ticking ram with A${address:04x} D${data:02x} CS:{cs} OE:{oe} WE:{we}");
0
}
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
debug!("Ticking rom with A${address:04x} CS:{cs} OE:{oe}");
0
}
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
debug!("Ticking Via with A${address:04x} D${data:02x} cs0:{cs0} cs1:{cs1} rw:{rw} rs0:{rs0} rs1:{rs1}");
(0, false, false)
}
} }
+14
View File
@@ -1 +1,15 @@
use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256;
pub mod backplane; pub mod backplane;
pub mod program_rom;
pub mod new;
pub mod tick2;
pub struct RamRomComputer {
pub(crate) rom: At28C256,
pub(crate) ram: Hm62256,
pub(crate) data_bus: u8,
pub(crate) address_bus: u16,
pub(crate) read_mode: bool,
}
+17
View File
@@ -0,0 +1,17 @@
use crate::computers::ram_rom::RamRomComputer;
use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256;
impl RamRomComputer {
pub fn new() -> RamRomComputer {
let rom = At28C256::new(0x4000, 0x7fff, (0..255).collect());
RamRomComputer {
rom,
ram: Hm62256::default(),
data_bus: 0x00,
address_bus: 0x0000,
/// is the CPU reading from the 'other' device?
read_mode: true
}
}
}
+16
View File
@@ -0,0 +1,16 @@
use crate::computers::ram_rom::RamRomComputer;
use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256;
impl RamRomComputer {
pub fn program_rom(rom: Vec<u8>) -> RamRomComputer {
let new_rom = At28C256::new(0x0000, 0x3fff, rom);
RamRomComputer {
rom: new_rom,
ram: Hm62256::new(0x3fff),
data_bus: 0x00,
address_bus: 0x00,
read_mode: false,
}
}
}
+43
View File
@@ -0,0 +1,43 @@
use crate::computers::ram_rom::RamRomComputer;
use crate::traits::backplane::Backplane;
struct ChipSignals {
cs: bool,
oe: bool,
we: bool
}
enum RomRamChips {
At28C256,
Hm62256
}
impl RamRomComputer {
pub fn tick2(&mut self, address: u16, control: u8, data: u8) -> (u8) {
println!("⏲RAM ROM Computer tick starting / {address:04x} {control:08b} {data:02x}");
// tick the parts
// map of memory
// 0x0000 -> 0x3fff -> RAM (HM62256)
// 0x4000 -> 0x7fff -> ROM (At28C256)
match address {
0x0000..=0x3fff => {
if self.read_mode {
println!("⏲__ROM BEING READ FROM");
let new_data = self.rom.signal_tick(address, data, true, true, true);
self.set_data_bus(new_data);
} else {
panic!("UNABLE TO WRITE TO ROM");
}
}
0x4000 ..=0x7fff => {
println!("⏲__DATA TARGETTING RRAAMM GETTING STORED ON DATA BUS");
}
_ => {}
};
let rom_data_bus = self.rom.signal_tick(self.address_bus ,self.data_bus, true ,true , true);
let (_, ram_data_bus) = self.ram.tick(address, data, control == 1, true);
0
}
}
+23 -37
View File
@@ -1,59 +1,45 @@
use crate::constants::constants_system::{SIZE_32KB, SIZE_64KB}; use log::debug;
use crate::periph::at28c256::At28C256; use crate::computers::rom_only::RomOnlyComputer;
use crate::periph::backplane::Backplane; use crate::traits::backplane::Backplane;
use crate::periph::rom_chip::RomChip;
pub struct RomOnlyComputer {
rom: At28C256,
data_bus: u8,
address_bus: u16,
read_mode: bool,
}
impl Backplane for RomOnlyComputer { impl Backplane for RomOnlyComputer {
fn data_bus(&self) -> u8 { self.data_bus } fn data_bus(&self) -> u8 { self.data_bus }
fn address_bus(&self) -> u16 { self.address_bus } fn address_bus(&self) -> u16 { self.address_bus }
fn read_mode(&self) -> bool { self.read_mode } fn read_mode(&self) -> bool { self.read_mode }
fn set_read_mode(&mut self, new_mode: bool) { fn set_read_mode(&mut self, new_mode: bool) {
self.read_mode = new_mode self.read_mode = new_mode
} }
fn set_data_bus(&mut self, new_value: u8) { fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value self.data_bus = new_value
} }
fn set_address_bus(&mut self, new_value: u16) { fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value self.address_bus = new_value
} }
fn tick(&mut self) { fn tick(&mut self) {
println!("COMPUTER: Preparing to tick."); // println!("COMPUTER: Preparing to tick.");
// do are we being addressed? // do are we being addressed?
println!("COMPUTER: BUSSES PRE: 0x{:04x} 0x{:02x} {}", self.address_bus, self.data_bus, self.read_mode); // println!("COMPUTER: BUSSES PRE: 0x{:04x} 0x{:02x} {}", self.address_bus, self.data_bus, self.read_mode);
let (new_addr, new_data) = self.rom.tick(self.address_bus, self.data_bus, self.read_mode); let new_data = self.rom.signal_tick(self.address_bus, self.data_bus, true, true, true);
self.set_address_bus(new_addr); // tick(self.address_bus, self.data_bus, self.read_mode);
self.set_address_bus(self.address_bus);
self.set_data_bus(new_data); self.set_data_bus(new_data);
println!("COMPUTER: BUSSES POST: 0x{:04x} 0x{:02x} {}", self.address_bus, self.data_bus, self.read_mode); // println!("COMPUTER: BUSSES POST: 0x{:04x} 0x{:02x} {}", self.address_bus, self.data_bus, self.read_mode);
println!("COMPUTER: Done ticking."); // println!("COMPUTER: Done ticking.");
}
}
impl RomOnlyComputer {
pub fn new() -> RomOnlyComputer {
let mut working = vec![0x00u8; SIZE_32KB];
for index in 0..SIZE_32KB {
working[index] = index as u8;
}
RomOnlyComputer::program(working)
} }
pub fn program(rom: Vec<u8>) -> RomOnlyComputer { fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
RomOnlyComputer { debug!("This system has no ram. ROM only.");
rom: At28C256::new(0x000, 0x3fff, rom), 0x00
address_bus: 0x0000, }
data_bus: 0x00,
read_mode: true, fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
} let data = self.rom.signal_tick(address, self.data_bus, cs, oe, true);
data
}
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
debug!("This system has no VIA controllers. ROM only");
(0,false,false)
} }
} }
@@ -0,0 +1,12 @@
use crate::computers::rom_only::RomOnlyComputer;
impl RomOnlyComputer {
pub fn debug_memory(&self, start_offset: u16, end_offset: u16) -> Vec<u8> {
let mut data = vec![];
let size = end_offset - start_offset;
for index in 0..size {
println!("Index {index} for {}", index + start_offset);
}
data
}
}
+28
View File
@@ -1 +1,29 @@
use crate::periph::at28c256::At28C256;
use crate::traits::backplane::Backplane;
pub mod backplane; pub mod backplane;
pub mod new;
pub mod program;
pub mod debug_memory;
mod rom_chunks;
pub struct RomOnlyComputer {
pub rom: At28C256,
pub data_bus: u8,
pub address_bus: u16,
pub read_mode: bool,
}
impl RomOnlyComputer {
pub fn tick2(&mut self, address: u16, control: u8, data: u8) -> (u8) {
// tick the parts...
println!("WIDETICK: A:${address:04x} D:${data:02x} C:b{control:08b}");
self.address_bus = address;
self.data_bus = data;
let new_data = self.rom.signal_tick(self.address_bus, self.data_bus, true, true, true);
println!("\nNew Data : {new_data:02x}");
self.set_data_bus(new_data);
new_data
}
}
+12
View File
@@ -0,0 +1,12 @@
use crate::computers::rom_only::RomOnlyComputer;
use crate::constants::constants_system::SIZE_32KB;
impl RomOnlyComputer {
pub fn new() -> RomOnlyComputer {
let mut working = vec![0x00u8; SIZE_32KB];
for index in 0..SIZE_32KB {
working[index] = index as u8;
}
RomOnlyComputer::program(working)
}
}
+14
View File
@@ -0,0 +1,14 @@
use crate::computers::rom_only::RomOnlyComputer;
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
impl RomOnlyComputer {
pub fn program(rom: Vec<u8>) -> RomOnlyComputer {
RomOnlyComputer {
rom: At28C256::new(0x000, 0x3fff, rom),
address_bus: 0x0000,
data_bus: 0x00,
read_mode: true,
}
}
}
@@ -0,0 +1,8 @@
use std::slice::Chunks;
use crate::computers::rom_only::RomOnlyComputer;
impl RomOnlyComputer {
pub fn rom_chunks(&self, size: usize) -> Chunks<u8> {
self.rom.chunks(size)
}
}
@@ -0,0 +1,3 @@
Computer at
https://www.youtube.com/watch?v=s3t2QMukBRs
https://github.com/AndersBNielsen/6507SBC
@@ -0,0 +1,20 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::mos6502cpu::Mos6502Cpu;
use crate::periph::at28c256::At28C256;
use crate::periph::mos6532::Mos6532;
pub struct SingleBreadboard {
pub cpu: Mos6502Cpu,
pub ram: At28C256,
pub via: Mos6532
}
impl SingleBreadboard {
pub fn new() -> Self {
SingleBreadboard {
cpu: Mos6502Cpu::default(),
ram: At28C256::new(0xf000, 0xffff, vec![0x00; SIZE_32KB]),
via: Mos6532::new(0x0000, 0x0080)
}
}
}
+46
View File
@@ -0,0 +1,46 @@
use std::net::IpAddr::V4;
use log::debug;
use crate::computers::tim1::Tim1;
use crate::traits::backplane::Backplane;
impl Backplane for Tim1 {
fn data_bus(&self) -> u8 { self.data_bus }
fn address_bus(&self) -> u16 { self.address_bus }
fn read_mode(&self) -> bool { self.read_mode }
fn set_read_mode(&mut self, new_mode: bool) {
self.read_mode = new_mode
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
fn tick(&mut self) {
println!("Starting tick for TIM-1");
}
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
debug!("No dedicated RAM. Its in the VIA");
0x00
}
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
debug!("No dedicated ROM. Its in the VIA");
0x00
}
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
debug!("Starting VIA Tick");
self.pia.tick(address, data, false, self.read_mode);
// is this for the ROM?
// is this for the RAM?
// is this for the Interrupts?
// is this for the Timers?
(0x00, false, false)
}
}
+13
View File
@@ -0,0 +1,13 @@
mod backplane;
use crate::mos6502cpu::Mos6502Cpu;
use crate::periph::mos6530::Mos6530;
pub struct Tim1 {
cpu: Mos6502Cpu,
pia: Mos6530,
read_mode: bool,
data_bus: u8,
address_bus: u16
}
+5
View File
@@ -9,3 +9,8 @@ pub const OFFSET_RESET_VECTOR: u16 = 0xfffc;
pub const OFFSET_RESET_VECTORS: usize = 0xffff; pub const OFFSET_RESET_VECTORS: usize = 0xffff;
pub const OFFSET_INT_VECTOR: u16 = 0xfffe; pub const OFFSET_INT_VECTOR: u16 = 0xfffe;
pub const OFFSET_INT_VECTORS: usize = 0xfffe; pub const OFFSET_INT_VECTORS: usize = 0xfffe;
// 7 cycles for internal reset
// 6 to read the vectors from RAM
pub const MOS6502_RESET_CYCLE_COUNT: u16 = 8;
-1
View File
@@ -17,4 +17,3 @@ pub const VIA6522_ACR: u8 = 0b1100;
pub const VIA6522_PCR: u8 = 0b1101; pub const VIA6522_PCR: u8 = 0b1101;
pub const VIA6522_IFR: u8 = 0b1110; pub const VIA6522_IFR: u8 = 0b1110;
pub const VIA6522_IER: u8 = 0b1111; pub const VIA6522_IER: u8 = 0b1111;
+2 -1263
View File
File diff suppressed because it is too large Load Diff
+2 -76
View File
@@ -1,32 +1,5 @@
use crate::address_mode::AddressMode; use crate::address_mode::AddressMode;
use crate::constants::constants_isa_op::{ 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::*;
@@ -39,7 +12,6 @@ pub fn instruction_length(instruction: u8) -> u8 {
INSTRUCTION_TABLE[instruction as usize].clone().unwrap().length INSTRUCTION_TABLE[instruction as usize].clone().unwrap().length
} }
pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = { pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
let mut table: [Option<OpInfo>; 256] = [const { None }; 256]; let mut table: [Option<OpInfo>; 256] = [const { None }; 256];
table[ISA_OP_ADC_I as usize] = Some(OpInfo { table[ISA_OP_ADC_I as usize] = Some(OpInfo {
@@ -215,7 +187,7 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
table[ISA_OP_BCC as usize] = Some(OpInfo { table[ISA_OP_BCC as usize] = Some(OpInfo {
operation: BCC, operation: BCC,
mode: AddressMode::Implied, mode: AddressMode::Immediate,
length: 2, length: 2,
cycles: 2, cycles: 2,
format_prefix: "BCC $", format_prefix: "BCC $",
@@ -1307,49 +1279,3 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
table table
}; };
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_instruction_table_completeness() {
use INSTRUCTION_TABLE; // Adjust to your actual path
let mut defined_count = 0;
let mut defined_opcodes = vec![];
for (i, entry) in INSTRUCTION_TABLE.iter().enumerate() {
if let Some(info) = entry {
defined_count += 1;
defined_opcodes.push(i);
// Optional: sanity check
assert!(
info.length > 0 && info.cycles > 0,
"Invalid OpInfo at opcode {:#04x?}",
i
);
}
}
println!("Defined opcodes: {}", defined_count);
for i in 0..256 {
if defined_opcodes.contains(&i) {
print!("{:02x} ", i);
}
}
println!("\nMissing opcodes:");
for i in 0..256 {
if !defined_opcodes.contains(&i) {
print!("{:02X} ", i);
}
}
println!();
// The standard 6502 has 151 documented opcodes
assert_eq!(
defined_count, 151,
"Expected 151 opcodes, found {}",
defined_count
);
}
}
+1 -1
View File
@@ -11,4 +11,4 @@ pub mod op_info;
pub mod operand; pub mod operand;
pub mod operation; pub mod operation;
pub mod periph; pub mod periph;
mod backplane; pub mod traits;
+27
View File
@@ -0,0 +1,27 @@
use crate::mos6502cpu::Mos6502Cpu;
use crate::traits::bus_device::BusDevice;
impl BusDevice for Mos6502Cpu {
fn min_offset(&self) -> u16 { 0 }
fn max_offset(&self) -> u16 {
0x7fff
}
fn address_bus(&self) -> u16 {
self.address_bus
}
fn data_bus(&self) -> u8 {
self.data_bus
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value;
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value;
}
}
+26 -114
View File
@@ -9,93 +9,17 @@ use crate::op_info::OpInfo;
use crate::operand::Operand; use crate::operand::Operand;
use crate::operation::Operation; use crate::operation::Operation;
use log::trace; use log::trace;
use crate::mos6502cpu::Mos6502Cpu;
use crate::mos6502cpu::tick_stages::Mos6502TickStates; use crate::mos6502cpu::tick_stages::Mos6502TickStates;
use crate::mos6502cpu::tick_stages::Mos6502TickStates::*; use crate::mos6502cpu::tick_stages::Mos6502TickStates::*;
pub struct Mos6502Cpu { enum Mos6502Registers {
pub(crate) memory: [u8; SIZE_64KB], A,
/// accumulator X,
pub(crate) a: u8, Y
/// x register
pub(crate) x: u8,
/// y register
pub(crate) y: u8,
/// cpu flags
pub(crate) flags: Mos6502Flags,
/// program counter
pub pc: u16,
/// stack offset
pub(crate) s: u8,
pub microcode_step: u8,
pub(crate) address_bus: u16,
pub(crate) data_bus: u8,
pub(crate) ir: Instruction, // Instruction Register
pub(crate) oi: OpInfo,
pub(crate) has_reset: bool,
pub(crate) iv: u16, // Interrupt Vector
pub(crate) cycle_carry: u16, // Value to hold between microsteps
pub(crate) ir_bytes: [u8; 4],
/// CPU Read signal
pub read_signal: bool,
pub(crate) reset_vector: u16,
pub(crate) int_vector: u16,
pub(crate) nmi_vector: u16,
pub tick_stage: Mos6502TickStates
} }
impl Mos6502Cpu { 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 mut working = Mos6502Cpu {
memory: [0x00; SIZE_64KB],
a: 0x00,
x: 0x00,
y: 0x00,
flags: Default::default(),
pc: 0xfffd,
s: 0x00,
microcode_step: 0x00,
address_bus: 0x00,
data_bus: 0x00,
ir: Instruction {
op: Operation::NOP,
mode: AddressMode::Implied,
operand: Operand::None,
},
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].clone().unwrap(),
has_reset: false,
iv: 0xfffe,
cycle_carry: 0x0000,
ir_bytes: [0x00; 4],
read_signal: true,
reset_vector: 0x0000,
int_vector: 0x0000,
nmi_vector: 0x0000,
tick_stage: LoadingInstruction
};
working.reset_cpu();
working
}
}
impl Mos6502Cpu {
pub fn address_bus(&self) -> u16 {
self.address_bus
}
pub fn data_bus(&self) -> u8 {
self.data_bus
}
// //
// fn read_word(&self, offset: &u16) -> u16 { // fn read_word(&self, offset: &u16) -> u16 {
// println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1); // println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1);
@@ -108,6 +32,22 @@ impl Mos6502Cpu {
// result // result
// } // }
pub fn peek_register(&self, register_to_peek: Mos6502Registers) -> u8 {
match register_to_peek {
Mos6502Registers::A => self.a,
Mos6502Registers::X => self.x,
Mos6502Registers::Y => self.y
}
}
pub fn poke_register(&mut self, register_to_poke: Mos6502Registers, new_value: u8) {
match register_to_poke {
Mos6502Registers::A => self.a = new_value,
Mos6502Registers::X => self.x = new_value,
Mos6502Registers::Y => self.y = new_value
}
}
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)
} }
@@ -119,42 +59,15 @@ impl Mos6502Cpu {
} }
} }
pub fn peek(&self, offset: u16) -> u8 { pub fn peek_memory(&self, offset: u16) -> u8 {
self.memory[offset as usize] self.memory[offset as usize]
} }
pub fn poke(&mut self, offset: u16, value: u8) { pub fn poke_memory(&mut self, offset: u16, value: u8) {
println!("Setting memory at {offset:04x} to {value:02x}"); println!("Setting memory at {offset:04x} to {value:02x}");
self.memory[offset as usize] = value self.memory[offset as usize] = value
} }
pub fn peek_a(&self) -> u8 {
println!("Readding register A => 0x{:02x}", self.a);
self.a
}
pub fn poke_a(&mut self, new_a: u8) {
println!("Updating register A from [{}] to [{}]", self.a, new_a);
self.a = new_a;
}
pub fn peek_x(&self) -> u8 {
println!("Readding register X => 0x{}", self.x);
self.x
}
pub fn poke_x(&mut self, new_x: u8) {
println!("Updating register X from [{}] to [{}]", self.x, new_x);
self.x = new_x
}
pub fn peek_y(&self) -> u8 {
self.y
}
pub fn poke_y(&mut self, new_y: u8) {
self.y = new_y
}
fn advance_pc(&mut self, how_far: u16) { fn advance_pc(&mut self, how_far: u16) {
self.pc += how_far; self.pc += how_far;
} }
@@ -207,7 +120,6 @@ impl Mos6502Cpu {
} }
} }
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");
let offset = self.pc as usize; let offset = self.pc as usize;
@@ -321,7 +233,7 @@ impl Mos6502Cpu {
Operation::DEX => { Operation::DEX => {
if self.microcode_step == 1 { if self.microcode_step == 1 {
let (new_x, new_carry) = self.x.overflowing_sub(1); let (new_x, new_carry) = self.x.overflowing_sub(1);
self.poke_x(new_x); self.poke_register(Mos6502Registers::X, new_x);
self.poke_flag(Carry, new_carry); self.poke_flag(Carry, new_carry);
} }
} }
@@ -335,7 +247,7 @@ impl Mos6502Cpu {
Operation::INX => { Operation::INX => {
if self.microcode_step == 1 { if self.microcode_step == 1 {
let (new_x, new_carry) = self.x.overflowing_add(1); let (new_x, new_carry) = self.x.overflowing_add(1);
self.poke_x(new_x); self.poke_register(Mos6502Registers::X, new_x);
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;
@@ -344,7 +256,7 @@ impl Mos6502Cpu {
Operation::INY => { Operation::INY => {
if self.microcode_step == 1 { if self.microcode_step == 1 {
let (new_y, new_carry) = self.y.overflowing_add(1); let (new_y, new_carry) = self.y.overflowing_add(1);
self.poke_y(new_y); self.poke_register(Mos6502Registers::Y, new_y);
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;
+1 -1
View File
@@ -1,4 +1,4 @@
use crate::mos6502cpu::cpu::Mos6502Cpu; use crate::mos6502cpu::Mos6502Cpu;
impl Mos6502Cpu { impl Mos6502Cpu {
/// dump_data /// dump_data
+43
View File
@@ -0,0 +1,43 @@
use crate::address_mode::AddressMode;
use crate::constants::constants_isa_op::ISA_OP_NOP;
use crate::constants::constants_system::SIZE_64KB;
use crate::instruction::Instruction;
use crate::instruction_table::INSTRUCTION_TABLE;
use crate::mos6502cpu::Mos6502Cpu;
use crate::mos6502cpu::tick_stages::Mos6502TickStates::LoadingInstruction;
use crate::operand::Operand;
use crate::operation::Operation;
impl Default for Mos6502Cpu {
fn default() -> Self {
let mut working = Mos6502Cpu {
memory: [0x00; SIZE_64KB],
a: 0x00,
x: 0x00,
y: 0x00,
flags: Default::default(),
pc: 0xfffd,
s: 0x00,
microcode_step: 0x00,
address_bus: 0x00,
data_bus: 0x00,
ir: Instruction {
op: Operation::NOP,
mode: AddressMode::Implied,
operand: Operand::None,
},
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].clone().unwrap(),
has_reset: false,
iv: 0xfffe,
cycle_carry: 0x0000,
ir_bytes: [0x00; 4],
read_signal: true,
reset_vector: 0x0000,
int_vector: 0x0000,
nmi_vector: 0x0000,
tick_stage: LoadingInstruction
};
working.reset_cpu();
working
}
}
+39 -1
View File
@@ -1,6 +1,44 @@
use crate::constants::constants_system::SIZE_64KB;
use crate::instruction::Instruction;
use crate::mos6502cpu::tick_stages::Mos6502TickStates;
use crate::mos6502flags::Mos6502Flags;
use crate::op_info::OpInfo;
pub mod cpu; pub mod cpu;
pub mod new; pub mod new;
pub mod tick2; pub mod tick2;
pub mod dbg; pub mod dbg;
pub mod tick_stages; pub mod tick_stages;
pub mod default;
pub mod bus_device;
pub struct Mos6502Cpu {
pub(crate) memory: [u8; SIZE_64KB],
/// accumulator
pub(crate) a: u8,
/// x register
pub(crate) x: u8,
/// y register
pub(crate) y: u8,
/// cpu flags
pub(crate) flags: Mos6502Flags,
/// program counter
pub pc: u16,
/// stack offset
pub(crate) s: u8,
pub microcode_step: u8,
pub(crate) address_bus: u16,
pub(crate) data_bus: u8,
pub(crate) ir: Instruction, // Instruction Register
pub(crate) oi: OpInfo,
pub(crate) has_reset: bool,
pub(crate) iv: u16, // Interrupt Vector
pub(crate) cycle_carry: u16, // Value to hold between microsteps
pub(crate) ir_bytes: [u8; 4],
/// CPU Read signal
pub read_signal: bool,
pub(crate) reset_vector: u16,
pub(crate) int_vector: u16,
pub(crate) nmi_vector: u16,
pub tick_stage: Mos6502TickStates
}
+3 -3
View File
@@ -1,5 +1,5 @@
use crate::constants::constants_system::{OFFSET_RESET_VECTOR, SIZE_64KB}; use crate::constants::constants_system::{MOS6502_RESET_CYCLE_COUNT, OFFSET_RESET_VECTOR, SIZE_64KB};
use crate::mos6502cpu::cpu::Mos6502Cpu; use crate::mos6502cpu::Mos6502Cpu;
impl Mos6502Cpu { impl Mos6502Cpu {
pub fn new() -> Mos6502Cpu { pub fn new() -> Mos6502Cpu {
@@ -14,7 +14,7 @@ impl Mos6502Cpu {
} }
pub(crate) fn reset_cpu(&mut self) { pub(crate) fn reset_cpu(&mut self) {
self.microcode_step = 7 + 6; self.microcode_step = MOS6502_RESET_CYCLE_COUNT as u8;
// self = &mut Mos6502Cpu::default(); // self = &mut Mos6502Cpu::default();
println!("Should tick 7 times, then 6 cycles to read the reset and int vectors."); println!("Should tick 7 times, then 6 cycles to read the reset and int vectors.");
// read the value at 0xfffa 0xfffb for our NMI vector. // read the value at 0xfffa 0xfffb for our NMI vector.
+71 -61
View File
@@ -1,9 +1,69 @@
use crate::constants::constants_system::{OFFSET_INT_VECTOR, OFFSET_RESET_VECTOR}; use crate::constants::constants_system::{OFFSET_INT_VECTOR, OFFSET_RESET_VECTOR};
use crate::mos6502cpu::cpu::Mos6502Cpu; use crate::mos6502cpu::Mos6502Cpu;
enum Mos6502ResetSteps {
/// there are 6 of these
DummyRead(u8),
ReadRstVectorLow,
ReadRstVectorHigh,
ReadPcLow,
ReadPcHigh
}
impl Mos6502Cpu { impl Mos6502Cpu {
fn reset_step(&mut self, address_bus: u16, data_bus: u8, read: bool) -> (u16, u8, bool) {
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 {
6 => {
// NMI High byte
}
5 => {
// NMI low byte
}
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;
println!("Loaded reset vector of 0x{:04x}", self.reset_vector);
// 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!");
println!("START HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK");
// the KIM-1 uses 0x0000 for its initial PC
self.pc = 0x0000;
println!("END HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK");
self.has_reset = true;
}
_ => {
}
}
if self.microcode_step > 0 {
self.microcode_step -= 1;
}
(address_bus, data_bus, read)
}
/// AccurateTick /// AccurateTick
/// ///
/// In: address_bus > Address of data operationm /// In: address_bus > Address of data operationm
@@ -16,66 +76,16 @@ impl Mos6502Cpu {
/// read_bus > lets rest of the computer know if the CPU is reading from the address /// 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 /// provided or if we are writing to the address
pub fn tick2(&mut self, address_bus: u16, data_bus: u8) -> (u16, u8, bool) { pub fn tick2(&mut self, address_bus: u16, data_bus: u8) -> (u16, u8, bool) {
if self.has_reset { println!("STARTING TICK2");
// we have completed the reset cycle if !self.has_reset { return self.reset_step(address_bus, data_bus, self.read_signal) }
if self.read_signal { // we have completed the reset cycle
// we should see new data in the data_bus for us if self.read_signal {
let read_data = data_bus; // we should see new data in the data_bus for us
println!("READ 0x{read_data:02x} from data bus."); let read_data = data_bus;
self.data_bus = read_data; println!("READ 0x{read_data:02x} from data bus.");
} else { self.data_bus = read_data;
// we are writing to the bus.
}
} else { } else {
println!("Reset microstep {}", self.microcode_step); // we are writing to the bus.
// we need to do the reset steps
// reduce the number of remaining microsteps
self.read_signal = true;
match self.microcode_step {
6 => {
// NMI High byte
}
5 => {
// NMI low byte
}
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;
println!("Loaded reset vector of 0x{:04x}", self.reset_vector);
// 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!");
println!("START HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK");
// the KIM-1 uses 0x0000 for its initial PC
self.pc = 0x0000;
println!("END HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK");
self.has_reset = true;
}
_ => {
}
}
if self.microcode_step > 0 {
self.microcode_step -= 1;
}
} }
(self.address_bus, self.data_bus, self.read_signal) (self.address_bus, self.data_bus, self.read_signal)
} }
+9 -38
View File
@@ -1,6 +1,4 @@
use crate::mos6502flags::Mos6502Flag::{ 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;
@@ -68,13 +66,14 @@ impl Mos6502Flag {
#[derive(Default, PartialEq, Debug)] #[derive(Default, PartialEq, Debug)]
pub struct Mos6502Flags { pub struct Mos6502Flags {
carry: bool, // TODO: This is pub for tests. shouldn't be that way
zero: bool, pub carry: bool,
interrupt: bool, pub zero: bool,
decimal: bool, pub interrupt: bool,
break_flag: bool, pub decimal: bool,
overflow: bool, pub break_flag: bool,
negative: bool, pub overflow: bool,
pub negative: bool,
} }
impl Mos6502Flags { impl Mos6502Flags {
@@ -197,31 +196,3 @@ impl Mos6502Flags {
(src >> pos) & 1 != 0 (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));
}
}
+9
View File
@@ -0,0 +1,9 @@
Peripherals
At28C256 - 256 byte static ram
Hm682256 - 256 byte ROM
Kim1_Keypad - Keypad for KIM-1 Computer
mos6520 - Peripheral Adapter
mos6522 - Versatile Interface Adapter (6520++)
mos6530 - RRIOT (Ram, Rom, Input, Output, Timers)
+8
View File
@@ -0,0 +1,8 @@
use std::slice::Chunks;
use crate::periph::at28c256::At28C256;
impl At28C256 {
pub fn chunks(&self, size: usize) -> Chunks<u8> {
self.data.chunks(size)
}
}
+28
View File
@@ -0,0 +1,28 @@
use crate::periph::at28c256::At28C256;
use crate::traits::bus_device::BusDevice;
impl BusDevice for At28C256 {
fn min_offset(&self) -> u16 {
self.offset
}
fn max_offset(&self) -> u16 {
self.max_offset
}
fn address_bus(&self) -> u16 {
self.address_bus
}
fn data_bus(&self) -> u8 {
self.data_bus
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
}
-63
View File
@@ -15,66 +15,3 @@ impl At28C256 {
data.iter().fold(0u8, |acc, &b| acc.wrapping_add(b)) data.iter().fold(0u8, |acc, &b| acc.wrapping_add(b))
} }
} }
#[cfg(test)]
mod test {
use std::fs;
use std::path::Path;
use crate::constants::constants_system::SIZE_1KB;
use crate::periph::rom_chip::RomChip;
use super::*;
#[test]
fn smoke() { assert!(true); }
#[test]
fn programmed_data_reads_back_same() {
let mut data = At28C256::default();
for i in 0..SIZE_32KB {
data.data[i] = 0xeau8;
}
for offset in 0..SIZE_32KB {
if offset.is_multiple_of(SIZE_1KB) {};
assert_eq!(0xea, data.read(&(offset as u16)));
}
}
#[test]
fn checksums_calculate_correctly_for_zero() {
let data1 = [0x00u8; SIZE_32KB];
assert_eq!(0x00, At28C256::checksum_static(&data1));
}
#[test]
fn checksums_calculate_for_1_byte() {
let data = [0xff; 1];
assert_eq!(0xff, At28C256::checksum_static(&data));
}
#[test]
fn checksums_calculate_for_2_bytes() {
let data = [0xff; 2];
// 0xff + 0xff = 0x1fe
assert_eq!(0xfe, At28C256::checksum_static(&data));
}
#[test]
fn checksums_calculate_for_first_80_bytes() {
println!("STARTING TEST");
let mut checksum = 0x00;
let path = format!("{}{}", TEST_PERIPH_AT28C256_ROOT, "/checksum.bin");
println!("READING [{path}]");
let data = fs::read(path);
match data {
Ok(bytes) => {
println!("Read {} bytes", bytes.len());
checksum = At28C256::checksum_static(&bytes);
println!("Checksum: 0x{:02x}", checksum);
}
Err(e) => eprintln!("Failed to read file: {}", e),
}
assert_eq!(0x58, checksum);
println!("TEST COMPLETE");
}
}
+8
View File
@@ -0,0 +1,8 @@
use crate::periph::at28c256::At28C256;
use crate::traits::bus_control_byte::BusControlByte;
const CTRL_CS: u8 = 0b0000_0001;
const CTRL_WE: u8 = 0b0000_0010;
const CTRL_OE: u8 = 0b0000_0100;
pub struct At28c256Control {}
+3 -10
View File
@@ -15,16 +15,9 @@ impl Default for At28C256 {
data_bus: 0x00, data_bus: 0x00,
offset: 0x0000, offset: 0x0000,
max_offset: 0x3fff, max_offset: 0x3fff,
cs: false,
oe: false,
we: false
} }
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() {
assert!(true);
}
}
+4 -2
View File
@@ -1,13 +1,15 @@
use crate::periph::at28c256::At28C256; use crate::periph::at28c256::At28C256;
pub struct At28C256State { pub struct At28C256State {
offset: u16 offset: u16,
max_offset: u16
} }
impl At28C256 { impl At28C256 {
pub fn dump(&self) -> At28C256State { pub fn dump(&self) -> At28C256State {
At28C256State { At28C256State {
offset: self.offset offset: self.offset,
max_offset: self.max_offset
} }
} }
} }
+16
View File
@@ -0,0 +1,16 @@
use log::debug;
use crate::periph::at28c256::At28C256;
use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
impl MemoryChip for At28C256 {
/// read
///
/// Reads a byte from memory.
/// Returns a 0x00 if there is no data at that location but is still in ROM address range
fn read(&self, offset: &u16) -> u8 {
let effective = self.internal_address(*offset);
debug!("STARTING READ FROM At28C256 ${:04x} | ${:04x} / ${effective:04x} | ${:04x}", self.offset, offset, self.max_offset);
if effective >= self.data.len() as u16 { 0x00 } else { self.data[effective as usize] }
}
}
+16 -11
View File
@@ -1,14 +1,14 @@
pub mod default; pub mod default;
pub mod rom_chip; pub mod rom_chip;
pub mod tick; pub mod new;
mod new; pub mod program;
mod program; pub mod dump;
mod dump; pub mod checksum;
mod checksum; pub mod blocks;
pub mod control;
use crate::constants::constants_system::SIZE_32KB; pub mod signal_tick;
use crate::periph::rom_chip::RomChip; pub mod memory_chip;
use std::io::Read; pub mod bus_device;
/// At28C256 /// At28C256
/// ///
@@ -17,10 +17,15 @@ use std::io::Read;
/// 256kbit storage /// 256kbit storage
/// 32kbyte storage /// 32kbyte storage
pub struct At28C256 { pub struct At28C256 {
// Logical parts
data_bus: u8, data_bus: u8,
address_bus: u16, address_bus: u16,
data: Box<[u8]>, pub data: Box<[u8]>,
// where in the computer memory map do we live? // where in the computer memory map do we live?
offset: u16, offset: u16,
max_offset: u16 max_offset: u16,
// Physical Parts
cs: bool,
we: bool,
oe: bool
} }
+4 -1
View File
@@ -10,7 +10,10 @@ impl At28C256 {
address_bus: 0x0000, address_bus: 0x0000,
data_bus: 0x00, data_bus: 0x00,
offset, offset,
max_offset max_offset,
cs: false,
oe: false,
we: false
} }
} }
} }
+3 -2
View File
@@ -2,9 +2,10 @@ use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256; use crate::periph::at28c256::At28C256;
impl At28C256 { impl At28C256 {
pub fn program(&mut self, new_program: &[u8; SIZE_32KB]) { pub fn program(&mut self, new_program: Box<[u8]>) {
// panic!("FAIL. Cant program the chip."); // panic!("FAIL. Cant program the chip.");
// println!("PROGRAMMING {:?}", new_program); // println!("PROGRAMMING {:?}", new_program);
self.data = Box::new(*new_program); self.data = new_program;
} }
} }
+10 -18
View File
@@ -1,26 +1,18 @@
use log::debug;
use crate::constants::constants_system::SIZE_32KB; use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256; use crate::periph::at28c256::At28C256;
use crate::periph::rom_chip::RomChip; use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
use crate::traits::rom_chip::RomChip;
impl RomChip for At28C256 { impl RomChip for At28C256 {
fn read(&self, offset: &u16) -> u8 { /// program
self.data[*offset as usize] ///
} /// Writes new data to the memory chip
fn program(new_data: &[u8]) -> Box<At28C256> {
fn program(new_data: &[u8; SIZE_32KB]) -> Box<At28C256> {
println!("Writing new chip."); println!("Writing new chip.");
let mut working = At28C256::default(); let mut working = At28C256::default();
working.data = Box::new(*new_data); working.data = new_data.to_vec().into_boxed_slice();
working.into() Box::new(working)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() {
assert!(true);
} }
} }
+33
View File
@@ -0,0 +1,33 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
const CHIP_SIZE: usize = SIZE_32KB ;
impl At28C256 {
/// Tick the ROM
/// address_bus
/// data_bus
/// CS -> Chip Select
/// OE -> Output Enable
/// WE -> Write Enable
pub fn signal_tick(&mut self, address_bus: u16, data_bus: u8, cs: bool, oe: bool, we: bool) -> (u8) {
// if we aren't selected and we aren't able to write to the bus...
if !cs || !we || !oe { return data_bus };
// if we aren't being addressed directly
if !(address_bus <= self.max_offset && address_bus >= self.offset) {
return data_bus
};
let internal_address = address_bus - self.offset;
let result = if internal_address < CHIP_SIZE as u16 {
self.data[internal_address as usize]
} else {
data_bus
};
println!("At28C256 EADDR: ${address_bus:04x} IADDR: ${internal_address:04x} = {result:02x}");
result
}
}
-68
View File
@@ -1,68 +0,0 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256;
impl At28C256 {
fn talking_to_me(&self, address: u16) -> bool {
address >= self.offset && address < self.max_offset
}
pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) {
println!("At28C256: Tick starting for A${address_bus:04x} D${data_bus:02x} R{read_mode}");
// we aren't being addressed
// OR
// we arent reading from the ROM...
if !self.talking_to_me(address_bus) ||
!read_mode {
// ...go away.
return (address_bus, data_bus)
}
let effective = address_bus - self.offset;
if effective < self.max_offset {
if effective < self.data.len() as u16 {
self.data_bus = self.data[effective as usize];
} else {
self.data_bus = 0x00;
}
} else {
println!("At28C256: OUTSIDE RANGE. :(");
return (address_bus, data_bus)
}
println!("At28C256: Read... {:02x}", self.data_bus);
println!("At28C256: Done with ticking the AtC256");
(address_bus, self.data_bus)
}
}
#[cfg(test)]
mod test {
use std::fs;
use crate::periph::rom_chip::RomChip;
use super::*;
#[test]
fn smoke() { assert!(true); }
#[test]
fn checksum_binary_loads() {
let path = "/home/tmerritt/Projects/mos6502/resources/test/periph/at28c256/checksum.bin";
let bytes = match fs::read(path) {
Ok(bytes) => {
println!("Read {} bytes.", bytes.len());
bytes
},
Err(e) => {
eprintln!("FAIL to read rom.");
panic!("No rom no run.");
vec![]
}
};
let mut rom = At28C256::new(0x0000, 0x3fff, bytes);
assert_eq!(rom.checksum(), 0x58);
}
}
-9
View File
@@ -1,9 +0,0 @@
pub trait Backplane {
fn data_bus(&self) -> u8;
fn address_bus(&self) -> u16;
fn read_mode(&self) -> bool;
fn set_read_mode(&mut self, new_mode: bool);
fn set_data_bus(&mut self, new_value: u8);
fn set_address_bus(&mut self, new_value: u16);
fn tick(&mut self);
}
-3
View File
@@ -1,3 +0,0 @@
pub trait BusDevice {
fn talking_to_me(&self, address: u16) -> bool;
}
+29
View File
@@ -0,0 +1,29 @@
use crate::periph::hm62256::Hm62256;
use crate::traits::bus_device::BusDevice;
impl BusDevice for Hm62256 {
fn min_offset(&self) -> u16 {
self.offset
}
fn max_offset(&self) -> u16 {
self.max_offset
}
fn address_bus(&self) -> u16 {
self.address_bus
}
fn data_bus(&self) -> u8 {
self.data_bus
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
}
+8
View File
@@ -0,0 +1,8 @@
use crate::periph::hm62256::Hm62256;
use crate::traits::bus_control_byte::BusControlByte;
const CTRL_CS: u8 = 0b0000_0001;
const CTRL_WE: u8 = 0b0000_0010;
const CTRL_OE: u8 = 0b0000_0100;
pub struct Hm62256Control;
+5 -1
View File
@@ -9,9 +9,13 @@ impl Default for Hm62256 {
boxed_slice.try_into().expect("Unable to box the ram"); boxed_slice.try_into().expect("Unable to box the ram");
Hm62256 { Hm62256 {
offset: 0x0000, offset: 0x0000,
max_offset: 0x2000,
data: boxed_array, data: boxed_array,
address_bus: 0x0000, address_bus: 0x0000,
data_bus: 0x00 data_bus: 0x00,
cs: false,
oe: false,
we: false
} }
} }
} }
+11
View File
@@ -0,0 +1,11 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::hm62256::Hm62256;
use crate::traits::memory_chip::MemoryChip;
impl MemoryChip 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]
}
}
+13 -50
View File
@@ -6,10 +6,13 @@ pub mod tick;
pub mod default; pub mod default;
pub mod new; pub mod new;
pub mod dump; pub mod dump;
mod control;
mod bus_device;
mod memory_chip;
use crate::constants::constants_system::SIZE_32KB; use crate::constants::constants_system::SIZE_32KB;
use crate::periph::ram_chip::RamChip; use crate::traits::ram_chip::RamChip;
use crate::periph::rom_chip::RomChip; use crate::traits::rom_chip::RomChip;
use log::debug; use log::debug;
/// Hitachi Semiconductor /// Hitachi Semiconductor
@@ -17,54 +20,14 @@ use log::debug;
/// 32KByte /// 32KByte
pub struct Hm62256 { pub struct Hm62256 {
pub(crate) offset: u16, pub(crate) offset: u16,
pub(crate) max_offset: u16,
pub(crate) data: Box<[u8]>, pub(crate) data: Box<[u8]>,
pub(crate) address_bus: u16, pub(crate) address_bus: u16,
pub(crate) data_bus: u8 pub(crate) data_bus: u8,
} // Chip Select
pub(crate) cs: bool,
#[cfg(test)] // Write Enable
mod test { pub(crate) we: bool,
use super::*; // Output Enable
use rand::random; pub(crate) oe: bool
#[test]
fn smoke() {
assert!(true)
}
#[test]
fn written_data_comes_back() {
let mut ram = Hm62256::default();
// 100,000 random read/writes to ram that all read back right
for _ in 0..100_000 {
let mut offset: u16 = random();
println!("Size = {SIZE_32KB}");
let value: u8 = random();
println!("Wrote [{value:02x}] to [{offset:04x}]");
ram.write(&offset, &value);
assert_eq!(ram.read(&offset), value)
}
}
#[test]
fn address_space_is_round() {
// addresses written past the last address 'loop' back to 0+(offset - MAX_SIZE)
let max_offset = SIZE_32KB;
let test_offset = max_offset;
// all zero
let mut ram = Hm62256::default();
// write FF to the addresss after the last
ram.write(&(test_offset as u16), &0xff);
// check all the ram for anything that isn't 0x00
assert_eq!(ram.read(&(0x0000)), 0xff);
for offset in 1..SIZE_32KB {
println!("Testing offset {offset:04x} for 0x00");
assert_eq!(ram.read(&(offset as u16)), 0x00);
}
}
} }
+5 -1
View File
@@ -5,9 +5,13 @@ impl Hm62256 {
pub fn new(base_offset: u16) -> Self { pub fn new(base_offset: u16) -> Self {
Self { Self {
offset: base_offset, offset: base_offset,
max_offset: base_offset + SIZE_32KB as u16,
data: vec![0; SIZE_32KB].into_boxed_slice(), data: vec![0; SIZE_32KB].into_boxed_slice(),
address_bus: 0x0000, address_bus: 0x0000,
data_bus: 0x00 data_bus: 0x00,
cs: false,
oe: false,
we: false
} }
} }
} }
+2 -1
View File
@@ -1,6 +1,7 @@
use crate::constants::constants_system::SIZE_32KB; use crate::constants::constants_system::SIZE_32KB;
use crate::periph::hm62256::Hm62256; use crate::periph::hm62256::Hm62256;
use crate::periph::ram_chip::RamChip; use crate::traits::bus_device::BusDevice;
use crate::traits::ram_chip::RamChip;
impl RamChip for Hm62256 { impl RamChip for Hm62256 {
fn write(&mut self, offset: &u16, value: &u8) { fn write(&mut self, offset: &u16, value: &u8) {
+4 -10
View File
@@ -1,18 +1,12 @@
use log::debug; use log::debug;
use crate::constants::constants_system::SIZE_32KB; use crate::constants::constants_system::SIZE_32KB;
use crate::periph::hm62256::Hm62256; use crate::periph::hm62256::Hm62256;
use crate::periph::rom_chip::RomChip; use crate::traits::memory_chip::MemoryChip;
use crate::traits::rom_chip::RomChip;
impl RomChip for Hm62256 { impl RomChip for Hm62256 {
fn program(_: &[u8]) -> Box<Self> {
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."); debug!("Dont program ram.");
Hm62256::default().into() Hm62256::default().into()
} }
+5 -23
View File
@@ -8,7 +8,7 @@ impl Hm62256 {
pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool, cs: bool) -> (u16, u8) { pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool, cs: bool) -> (u16, u8) {
println!("HM62256RAM TICK START -> 0x{address_bus:04x} 0x{data_bus:02x} {read_mode} {cs}"); println!("HM62256RAM TICK START -> 0x{address_bus:04x} 0x{data_bus:02x} {read_mode} {cs}");
if !(address_bus.gt( &self.offset) && address_bus.le(&self.max_address())) { if !(address_bus >= self.offset && address_bus < self.max_address()) {
return (address_bus, data_bus); return (address_bus, data_bus);
} }
@@ -17,7 +17,7 @@ impl Hm62256 {
let addr = address_bus.wrapping_sub(self.offset) + self.offset; let addr = address_bus.wrapping_sub(self.offset) + self.offset;
// did we want to talk to the chip... // did we want to talk to the chip...
if !cs { if !cs {
return (address_bus, data_bus); return (address_bus, data_bus);
} }
@@ -26,9 +26,11 @@ impl Hm62256 {
return (address_bus, data_bus); return (address_bus, data_bus);
} }
// ok. lets see what we are dealing with // ok. lets see what we are dealing with
self.data_bus = if read_mode { self.data_bus = if read_mode {
self.data[addr as usize] let new_value = self.data[addr as usize];
new_value
} else { } else {
// writing to ram // writing to ram
self.data[addr as usize] = data_bus.into(); self.data[addr as usize] = data_bus.into();
@@ -37,23 +39,3 @@ impl Hm62256 {
(self.address_bus, self.data_bus) (self.address_bus, self.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();
// load the data to ram
ram.tick(0x0000, 0xab, false, true);
// read the data back
let (_, new_data) = ram.tick(0x0000, 0x00, true, true);
assert_eq!(new_data, 0xab);
}
}
+2 -53
View File
@@ -11,8 +11,8 @@
*/ */
pub struct Kim1Keypad { pub struct Kim1Keypad {
keys: [bool; 23], pub keys: [bool; 23],
stepping: bool pub stepping: bool
} }
impl Kim1Keypad { impl Kim1Keypad {
@@ -52,54 +52,3 @@ impl Kim1Keypad {
self.keys[Self::keyid(key)] self.keys[Self::keyid(key)]
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() { assert!(true); }
#[test]
fn keys_are_pressed() {
let mut kb = Kim1Keypad::new();
for index in 0..23 {
assert!(!kb.is_pressed(index));
kb.press_key(index);
assert!(kb.is_pressed(index));
kb.release_key(index);
assert!(!kb.is_pressed(index));
}
}
#[test]
fn stepping_changes() {
let mut kb = Kim1Keypad::new();
kb.set_stepping(false);
assert!(!kb.stepping);
kb.toggle_stepping();
assert!(kb.stepping);
kb.toggle_stepping();
kb.toggle_stepping();
kb.toggle_stepping();
kb.toggle_stepping();
kb.toggle_stepping();
assert!(!kb.stepping);
}
#[test]
fn out_of_range() {
let mut kb = Kim1Keypad::new();
kb.press_key(24);
assert!(kb.is_pressed(1));
}
}
+12 -8
View File
@@ -1,9 +1,13 @@
pub mod rom_chip;
pub mod at28c256;
pub mod hm62256;
pub mod ram_chip;
pub mod mos6522;
pub mod mos6530;
pub mod kim1_keypad; pub mod kim1_keypad;
mod bus_device;
pub mod backplane; pub mod at28c256; // EEPROM with 32KB/256Kbit
pub mod hm62256; // RAM with 32KBit/256Kbit
pub mod mos6520; // PIA
pub mod mos6522; // PIA
pub mod mos6530; // RRIOT ROM, RAM, IO, Timer
pub mod mos6532; // PIA RAM, IO, Timer
pub mod mos6526;
mod mos6540;
mod mos6111;
// CIA Parallel, Serial, Interval Timers, Time Of Day
+50
View File
@@ -0,0 +1,50 @@
use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
// MOS6111
// AKA MCS6111
// 128B/1024b RAM
pub struct Mos6111 {
data: Box<[u8]>,
offset: u16,
max_offset: u16
}
impl Mos6111 {
pub fn new(min_offset: u16, max_offset: u16) -> Self {
Mos6111 {
data: Box::new([0x00u8; 64]),
offset: min_offset,
max_offset
}
}
}
impl BusDevice for Mos6111 {
fn min_offset(&self) -> u16 {
self.offset
}
fn max_offset(&self) -> u16 {
self.max_offset
}
fn data_bus(&self) -> u8 {
todo!()
}
fn set_address_bus(&mut self, new_value: u16) {
todo!()
}
fn set_data_bus(&mut self, new_value: u8) {
todo!()
}
}
impl MemoryChip for Mos6111 {
fn read(&self, offset: &u16) -> u8 {
println!("IA = {}", self.internal_address(*offset));
0x00
}
}
+26
View File
@@ -0,0 +1,26 @@
use crate::periph::mos6520::Mos6520;
use crate::traits::bus_device::BusDevice;
impl BusDevice for Mos6520 {
fn min_offset(&self) -> u16 {
self.offset
}
fn max_offset(&self) -> u16 { self.max_offset }
fn address_bus(&self) -> u16 {
self.address_bus
}
fn data_bus(&self) -> u8 {
self.data_bus
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
}
+10
View File
@@ -0,0 +1,10 @@
use log::debug;
use crate::periph::mos6520::Mos6520;
use crate::traits::memory_chip::MemoryChip;
impl MemoryChip for Mos6520 {
fn read(&self, offset: &u16) -> u8 {
debug!("This has no ROM ${offset:04x}");
0
}
}
+54
View File
@@ -0,0 +1,54 @@
pub mod reset;
pub mod bus_device;
pub mod new;
pub mod tick;
pub mod rom_chip;
pub mod ram_chip;
pub mod memory_chip;
pub mod pia_chip;
use crate::traits::bus_device::BusDevice;
use crate::traits::gpio_chip::GpioChip;
use crate::traits::memory_chip::MemoryChip;
use crate::traits::ram_chip::RamChip;
use crate::traits::rom_chip::RomChip;
/*
The MCS6520 Peripheral Adapter is designed to solve a broad range of peripheral
control problems in the implementation of microcomputer systems. This device allows
a very effective trade-off between software and hardware by providing significant
capability and flexibility in a low cost chip. When coupled with the power and
speed of the MCS6500 family of microprocessors, the MCS6S20 allows implementation
of very complex systems at a minimum overall cost.
Control of peripheral devices is handled primarily through two 8-bit bi-directional ports.
Each of these lines can be programmed to act as either an input or
an output. In addition, four peripheral control/interrupt input lines are provided.
These lines can be used to interrupt the processor or for "hand-shaking" data
be tween the processor and a peripheral device.
*/
pub struct Mos6520 {
// Parallel ports A & B data registers
pub port_a: u8,
pub out_a: u8,
pub in_a: u8,
pub ddra: u8,
pub port_b: u8,
pub out_b: u8,
pub in_b: u8,
pub ddrb: u8,
// Interrupt control register
pub icr: u8,
// External Address and Data Bus
pub address_bus: u16,
pub data_bus: u8,
// Offsets
pub offset: u16,
pub max_offset: u16
}
impl Mos6520 {
pub fn debug_dump(&self) {
println!("DUMPING STATE: \nPORT_A:\t{:08b}\nIN_A:\t{:08b}\nOUT_A:\t{:08b}\nDDRA:\t{:08b}", self.port_a, self.in_a, self.out_a, self.ddra);
}
}
+21
View File
@@ -0,0 +1,21 @@
use crate::periph::mos6520::Mos6520;
impl Mos6520 {
pub fn new(start_offset: u16) -> Self {
Self {
port_a: 0,
out_a: 0,
port_b: 0,
out_b: 0,
ddra: 0,
ddrb: 0,
icr: 0,
address_bus: 0,
data_bus: 0,
offset: start_offset,
max_offset: start_offset + 4,
in_a: 0,
in_b: 0,
}
}
}
+101
View File
@@ -0,0 +1,101 @@
use crate::periph::mos6520::Mos6520;
use crate::traits::gpio_chip::{GpioChip, GpioChipPorts};
use crate::traits::pia_chip::PiaChip;
impl GpioChip for Mos6520 {
fn set_port(&mut self, new_value: u8, port: GpioChipPorts) {
match port {
GpioChipPorts::PORT_A => {
self.port_a = new_value
}
GpioChipPorts::PORT_B => {
self.port_b = new_value
}
}
}
fn set_ddr(&mut self, new_ddr_value: u8, port: GpioChipPorts) {
match port {
GpioChipPorts::PORT_A => {
self.ddra = new_ddr_value
}
GpioChipPorts::PORT_B => {
self.ddrb = new_ddr_value
}
}
}
fn get_port(&self, port: GpioChipPorts) -> u8 {
match port {
GpioChipPorts::PORT_A => {
self.port_a
}
GpioChipPorts::PORT_B => {
self.port_b
}
}
}
fn get_ddr(&self, port: GpioChipPorts) -> u8 {
match port {
GpioChipPorts::PORT_A => {
self.ddra
}
GpioChipPorts::PORT_B => {
self.ddrb
}
}
}
fn get_in(&self, port: GpioChipPorts) -> u8 {
match port {
GpioChipPorts::PORT_A => {
self.in_a
}
GpioChipPorts::PORT_B => {
self.in_b
}
}
}
fn get_out(&self, port: GpioChipPorts) -> u8 {
match port {
GpioChipPorts::PORT_A => {
self.port_a
}
GpioChipPorts::PORT_B => {
self.port_b
}
}
}
fn update_ports(&mut self) {
let (in_a, out_a) = Mos6520::split_port(self.port_a, self.ddra);
self.in_a = in_a;
self.out_a = out_a;
// Port B
let (in_b, out_b) = Mos6520::split_port(self.port_b, self.ddrb);
self.in_b = in_b;
self.out_b = out_b;
}
}
impl PiaChip for Mos6520 { }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn check_gpio_ports() {
let mut x = Mos6520::new(0x1000);
// offsets from 0x1000 -> 0x1004
}
}
+9
View File
@@ -0,0 +1,9 @@
use log::debug;
use crate::periph::mos6520::Mos6520;
use crate::traits::ram_chip::RamChip;
impl RamChip for Mos6520 {
fn write(&mut self, offset: &u16, value: &u8) {
debug!("This has no ROM / ${offset:04x} ${value:02x}");
}
}
+16
View File
@@ -0,0 +1,16 @@
use crate::periph::mos6520::Mos6520;
impl Mos6520 {
/// reset
///
/// Simulates holding Reset pin low
pub fn reset(&mut self) {
self.port_a = 0x00;
self.port_b = 0x00;
self.ddra = 0x00;
self.ddrb = 0x00;
self.icr = 0x00;
self.address_bus = 0x0000;
self.data_bus = 0x00;
}
}
+10
View File
@@ -0,0 +1,10 @@
use log::debug;
use crate::periph::mos6520::Mos6520;
use crate::traits::rom_chip::RomChip;
impl RomChip for Mos6520 {
fn program(new_data: &[u8]) -> Box<Self> {
debug!("This has no rom. Cant program.");
todo!()
}
}
+88
View File
@@ -0,0 +1,88 @@
use log::debug;
use crate::periph::mos6520::Mos6520;
use crate::traits::bus_device::BusDevice;
const MOS6520_DDRA_OFFSET: u8 = 0x00;
const MOS6520_DDRB_OFFSET: u8 = 0x02;
const MOS6520_PRTA_OFFSET: u8 = 0x01;
const MOS6520_PRTB_OFFSET: u8 = 0x03;
impl Mos6520 {
pub fn tick(&mut self, address_bus: u16, data_bus: u8) -> u8 {
self.address_bus = address_bus;
self.data_bus = data_bus;
println!("Preparing to tick MOS6520");
// are we changing our state?
let effective = self.internal_address(self.address_bus) as u8;
match effective {
MOS6520_DDRA_OFFSET => {
// ddra
// println!("DDRA -> {:02x} -> {:02x}", self.ddra, self.data_bus);
self.ddra = self.data_bus;
}
MOS6520_PRTA_OFFSET => {
// port a
// println!("PORT A -> {:02x} -> {:02x}", self.port_a, self.data_bus);
self.port_a = self.data_bus;
}
MOS6520_DDRB_OFFSET => {
// ddrb
// println!("DDRB -> {:02x}", self.ddrb);
self.ddrb = self.data_bus;
}
MOS6520_PRTB_OFFSET => {
// port b
// println!("PORT B -> {:02x}", self.port_b);
self.port_b = self.data_bus;
}
_ => {
panic!("Unable to access via 6520 at offset ${effective}")
}
}
self.tick_port_a();
self.tick_port_b();
self.data_bus
}
fn tick_port_a(&mut self) {
self.out_a = 0x00;
self.in_a = 0x00;
for current_bit in 0..8 {
let bit_mask = 1 << current_bit;
let is_output = (self.ddra & bit_mask) != 0;
let is_set = (self.port_a & bit_mask) != 0;
match (is_output, is_set) {
(true, true) => self.out_a |= bit_mask,
(false, true) => self.in_a |= bit_mask,
_ => {}
}
}
println!("Time to tick the device on port a");
}
fn tick_port_b(&mut self) {
self.out_b = 0x00;
self.in_b = 0x00;
for current_bit in 0..8 {
let bit_mask = 1 << current_bit;
let is_output = (self.ddrb & bit_mask) != 0;
let is_set = (self.port_b & bit_mask) != 0;
match (is_output, is_set) {
(true, true) => self.out_b |= bit_mask,
(false, true) => self.in_b |= bit_mask,
_ => {}
}
}
println!("Time to tick the device on port b");
}
}
+46 -3
View File
@@ -1,4 +1,47 @@
pub mod mos6522; pub mod mos6522;
mod registers; pub mod registers;
mod new; pub mod new;
mod tick; pub mod tick;
#[derive(Default)]
pub struct Mos6522 {
/// data direction
pub dda: u8,
pub ddb: u8,
/// bottom 4 address bits
pub rs0: u8,
pub rs1: u8,
pub rs2: u8,
pub rs3: u8,
/// external data bus
pub data_bus: u8,
pub cs1: bool,
pub cs2: bool,
// when true CPU is reading
pub rw: bool,
/// reset circuit - true when reset inited
pub reset: bool,
/// IRQ - true when interrupt waiting
pub irq: bool,
pub ira: u8,
pub ora: u8,
pub porta: u8,
pub irb: u8,
pub orb: u8,
pub portb: u8,
pub ca1: bool,
pub ca2: bool,
pub cb1: bool,
pub cb2: bool,
// memory offset for where in the computers memory map this fits
pub offset: u16,
pub address_bus: u16,
}
+1 -92
View File
@@ -1,49 +1,6 @@
use std::time::Instant; use std::time::Instant;
use log::debug;
use crate::constants::constants_via6522::*; use crate::constants::constants_via6522::*;
use crate::periph::mos6522::Mos6522;
#[derive(Default)]
pub struct Mos6522 {
/// data direction
pub(crate) dda: u8,
pub(crate) ddb: u8,
/// bottom 4 address bits
pub(crate) rs0: u8,
pub(crate) rs1: u8,
pub(crate) rs2: u8,
pub(crate) rs3: u8,
/// external data bus
pub(crate) data_bus: u8,
pub(crate) cs1: bool,
pub(crate) cs2: bool,
// when true CPU is reading
pub(crate) rw: bool,
/// reset circuit - true when reset inited
pub(crate) reset: bool,
/// IRQ - true when interrupt waiting
pub(crate) irq: bool,
pub(crate) ira: u8,
pub(crate) ora: u8,
pub(crate) porta: u8,
pub(crate) irb: u8,
pub(crate) orb: u8,
pub(crate) portb: u8,
pub(crate) ca1: bool,
pub(crate) ca2: bool,
pub(crate) cb1: bool,
pub(crate) cb2: bool,
// memory offset for where in the computers memory map this fits
pub(crate) offset: u16,
pub(crate) address_bus: u16,
}
impl Mos6522 { impl Mos6522 {
pub fn max_offset(&self) -> u16 { pub fn max_offset(&self) -> u16 {
@@ -59,51 +16,3 @@ impl Mos6522 {
} }
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() { assert!(true); }
#[test]
fn registers() {
let mut x = Mos6522::new();
x.tick(VIA6522_DDRA as u16, 0b0000_0000, false, true);
assert_eq!(x.dda, 0b0000_0000);
x.tick(VIA6522_DDRA as u16, 0b1111_1111, false, true);
assert_eq!(x.dda, 0b1111_1111);
x.tick(VIA6522_DDRB as u16, 0b0000_0000, false, true);
assert_eq!(x.ddb, 0b0000_0000);
x.tick(VIA6522_DDRB as u16, 0b1111_1111, false, true);
assert_eq!(x.ddb, 0b1111_1111);
x.tick(VIA6522_ORA as u16, 0b0000_0000, false, true);
assert_eq!(x.ora, 0b0000_0000);
x.tick(VIA6522_ORA as u16, 0b1111_1111, false, true);
assert_eq!(x.ora, 0b1111_1111);
x.tick(VIA6522_ORB as u16, 0b0000_0000, false, true);
assert_eq!(x.orb, 0b0000_0000);
x.tick(VIA6522_ORB as u16, 0b1111_1111, false, true);
assert_eq!(x.orb, 0b1111_1111);
}
#[test]
fn partial_output_porta() {
let mut x = Mos6522::new();
x.tick(VIA6522_DDRA as u16, 0b1010_1010, false, true);
x.tick(VIA6522_ORA as u16,0b1111_1111, false, true);
assert_eq!(x.porta, 0b1010_1010);
}
#[test]
fn partial_output_portb() {
let mut x = Mos6522::new();
x.tick(VIA6522_DDRB as u16, 0b0101_0101, false, true);
x.tick(VIA6522_ORB as u16, 0b1111_1111, false, true);
assert_eq!(x.portb, 0b0101_0101);
}
}
+28 -3
View File
@@ -1,7 +1,32 @@
use crate::periph::mos6522::mos6522::Mos6522; use crate::periph::mos6522::Mos6522;
impl Mos6522 { impl Mos6522 {
pub fn new() -> Self { pub fn new(offset: u16) -> Self {
Mos6522::default() Mos6522 {
dda: 0,
ddb: 0,
rs0: 0,
rs1: 0,
rs2: 0,
rs3: 0,
data_bus: 0,
cs1: false,
cs2: false,
rw: false,
reset: false,
irq: false,
ira: 0,
ora: 0,
porta: 0,
irb: 0,
orb: 0,
portb: 0,
ca1: false,
ca2: false,
cb1: false,
cb2: false,
offset,
address_bus: 0,
}
} }
} }
+3 -5
View File
@@ -1,18 +1,16 @@
use log::debug; use log::debug;
use crate::constants::constants_system::SIZE_32KB; use crate::constants::constants_system::SIZE_32KB;
use crate::constants::constants_via6522::{VIA6522_DDRA, VIA6522_DDRB, VIA6522_ORA, VIA6522_ORB}; use crate::constants::constants_via6522::{VIA6522_DDRA, VIA6522_DDRB, VIA6522_ORA, VIA6522_ORB};
use crate::periph::mos6522::mos6522::Mos6522; use crate::periph::mos6522::Mos6522;
impl Mos6522 { impl Mos6522 {
fn max_address(&self) -> u16 {
self.offset + SIZE_32KB as u16
}
/// tick /// tick
/// ///
/// data_bus -> 8 bits from the data bus /// data_bus -> 8 bits from the data bus
/// control -> 4 bits to identify which register to control /// control -> 4 bits to identify which register to control
pub fn tick(&mut self, address_bus: u16, data_bus: u8,reset: bool, rw: bool) -> (u16, u8) { pub fn tick(&mut self, address_bus: u16, data_bus: u8,reset: bool, rw: bool) -> (u16, u8) {
if !(address_bus >= self.offset && address_bus.le(&self.max_address())) { if !(address_bus >= self.offset && address_bus.le(&self.max_offset())) {
return (address_bus, data_bus); return (address_bus, data_bus);
} }
+44
View File
@@ -0,0 +1,44 @@
use crate::periph::mos6526::Mos6526;
use crate::traits::backplane::Backplane;
impl Backplane for Mos6526 {
fn data_bus(&self) -> u8 {
todo!()
}
fn address_bus(&self) -> u16 {
todo!()
}
fn read_mode(&self) -> bool {
todo!()
}
fn set_read_mode(&mut self, new_mode: bool) {
todo!()
}
fn set_data_bus(&mut self, new_value: u8) {
todo!()
}
fn set_address_bus(&mut self, new_value: u16) {
todo!()
}
fn tick(&mut self) {
todo!()
}
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
todo!()
}
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
todo!()
}
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
todo!()
}
}
+4
View File
@@ -0,0 +1,4 @@
mod backplane;
pub struct Mos6526 {}
+30
View File
@@ -0,0 +1,30 @@
use crate::constants::constants_system::SIZE_1KB;
use crate::periph::mos6530::Mos6530;
use crate::traits::bus_device::BusDevice;
impl BusDevice for Mos6530 {
fn min_offset(&self) -> u16 {
self.ram_offset
}
fn max_offset(&self) -> u16 {
self.min_offset() + SIZE_1KB as u16
}
fn address_bus(&self) -> u16 {
self.address_bus
}
fn data_bus(&self) -> u8 {
self.data_bus
}
fn set_address_bus(&mut self, new_value: u16) {
self.address_bus = new_value
}
fn set_data_bus(&mut self, new_value: u8) {
self.data_bus = new_value
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
use crate::periph::mos6530::mos6530::Mos6530; use crate::periph::mos6530::Mos6530;
impl Mos6530 { impl Mos6530 {
pub fn dump(&self) { pub fn dump(&self) {

Some files were not shown because too many files have changed in this diff Show More