MOS6520 looking mostly there.

This commit is contained in:
2025-07-29 13:12:33 -04:00
parent 8f6f9cb64d
commit 7ac8bd86ba
58 changed files with 742 additions and 422 deletions
Generated
-8
View File
@@ -497,14 +497,6 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "beneater"
version = "0.1.0"
dependencies = [
"core",
"macroquad 0.4.14",
]
[[package]]
name = "bit-set"
version = "0.5.3"
+1 -1
View File
@@ -3,7 +3,7 @@ members = [
"core",
"cli",
"macroquad",
"beneater"
# "beneater"
]
resolver="2"
+1 -1
View File
@@ -1,7 +1,7 @@
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
use crate::parts::via6522::VIA6522;
use core::constants::constants_system::*;
use core::mos6502cpu::cpu::Mos6502Cpu;
use core::mos6502cpu::Mos6502Cpu;
use core::periph::at28c256::At28C256;
use core::traits::rom_chip::RomChip;
use core::constants::constants_via6522::*;
+1 -1
View File
@@ -1,5 +1,5 @@
use core::computers::kim1::Kim1;
use core::constants::constants_system::*;
fn main() {
println!("Taxation is theft.");
+1 -1
View File
@@ -1,4 +1,4 @@
use core::computers::ram_rom::backplane::RamRomComputer;
use core::computers::ram_rom::RamRomComputer;
use core::traits::backplane::Backplane;
use std::fs;
-5
View File
@@ -1,5 +0,0 @@
use core::mos6502cpu::cpu::Mos6502Cpu;
fn main() {
let x = Mos6502Cpu::default();
}
+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)
}
}
+12 -1
View File
@@ -1 +1,12 @@
pub mod beneater;
mod backplane;
use crate::mos6502cpu::Mos6502Cpu;
use crate::periph::mos6522::mos6522::Mos6522;
pub struct BenEater {
cpu: Mos6502Cpu,
via: Mos6522,
data_bus: u8,
address_bus: u16,
read_mode: bool
}
-5
View File
@@ -2,14 +2,9 @@ pub mod new;
pub mod tick;
pub mod reset;
use std::fs;
use std::path::Path;
use crate::constants::constants_system::SIZE_1KB;
use crate::mos6502cpu::Mos6502Cpu;
use crate::periph::at28c256::At28C256;
use crate::periph::hm62256::Hm62256;
use crate::periph::kim1_keypad::Kim1Keypad;
use crate::periph::mos6522::mos6522::Mos6522;
use crate::periph::mos6530::mos6530::Mos6530;
/// Represents a KIM-1
+1
View File
@@ -2,3 +2,4 @@ pub mod beneater;
pub mod rom_only;
pub mod kim1;
pub mod ram_rom;
pub mod tim1;
+11 -8
View File
@@ -1,9 +1,9 @@
use log::debug;
use crate::computers::ram_rom::RamRomComputer;
use crate::periph::at28c256::At28C256;
use crate::traits::backplane::Backplane;
use crate::periph::hm62256::Hm62256;
impl Backplane for RamRomComputer {
fn data_bus(&self) -> u8 {
self.data_bus
@@ -45,7 +45,7 @@ impl Backplane for RamRomComputer {
0x4000..=0x7fff => {
// ROM
println!("ADDRESSING ROM");
let (rom_address_bus, rom_data_bus) = self.rom.tick(self.address_bus, self.data_bus, self.read_mode);
let rom_data_bus = self.rom.signal_tick(self.address_bus, self.data_bus, true, true, true);
self.data_bus = rom_data_bus;
}
_ => {
@@ -54,16 +54,19 @@ impl Backplane for RamRomComputer {
}
}
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) {
todo!()
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, data: u8, cs: bool, oe: bool, we: bool) -> (u8) {
todo!()
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, cs: bool, rw: bool, ce: bool) -> (u8, u8, bool) {
todo!()
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)
}
}
+1 -1
View File
@@ -44,7 +44,7 @@ impl RamRomComputer {
}
_ => {}
};
let (_, rom_data_bus) = self.rom.tick(address, data, control == 1);
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
}
+15 -13
View File
@@ -17,27 +17,29 @@ impl Backplane for RomOnlyComputer {
}
fn tick(&mut self) {
println!("COMPUTER: Preparing to tick.");
// println!("COMPUTER: Preparing to tick.");
// do are we being addressed?
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);
self.set_address_bus(new_addr);
// println!("COMPUTER: BUSSES PRE: 0x{:04x} 0x{:02x} {}", 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);
// tick(self.address_bus, self.data_bus, self.read_mode);
self.set_address_bus(self.address_bus);
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: Done ticking.");
// println!("COMPUTER: BUSSES POST: 0x{:04x} 0x{:02x} {}", self.address_bus, self.data_bus, self.read_mode);
// println!("COMPUTER: Done ticking.");
}
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) {
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
debug!("This system has no ram. ROM only.");
0x00
}
fn tick_rom(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> (u8) {
let (_, data) = self.rom.tick(address, data, true);
data
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, cs: bool, rw: bool, ce: bool) -> (u8, u8, bool) {
debug!("This system has no VIA controllers. ROM only");
(0,0,true)
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)
}
}
+1 -1
View File
@@ -19,7 +19,7 @@ impl RomOnlyComputer {
// tick the parts...
println!("WIDETICK: A:${address:04x} D:${data:02x} C:b{control:08b}");
let (_, new_data) = self.rom.tick(address, data, control == 0x01);
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
+8
View File
@@ -0,0 +1,8 @@
use crate::mos6502cpu::Mos6502Cpu;
use crate::periph::mos6530::mos6530::Mos6530;
pub struct Tim1 {
cpu: Mos6502Cpu,
pia: Mos6530
}
-1
View File
@@ -17,4 +17,3 @@ pub const VIA6522_ACR: u8 = 0b1100;
pub const VIA6522_PCR: u8 = 0b1101;
pub const VIA6522_IFR: u8 = 0b1110;
pub const VIA6522_IER: u8 = 0b1111;
+6 -3
View File
@@ -2,6 +2,12 @@ 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
}
@@ -18,7 +24,4 @@ impl BusDevice for Mos6502Cpu {
self.data_bus = new_value;
}
fn talking_to_me(&self, address: u16) -> bool {
todo!()
}
}
-29
View File
@@ -6,32 +6,3 @@ impl At28C256 {
self.data.chunks(size)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() { assert!(true); }
#[test]
fn full_chunks_come_back_ok() {
let test_data = (0..255).collect();
let mut chip = At28C256::new(0x0000, 0x3fff, test_data);
let chunks = chip.chunks(16);
assert_eq!(chunks.len(), 16);
}
#[test]
fn partial_blocks_come_back_ok() {
let test_data = (0..=3).collect();
let mut chip = At28C256::new(0x0000, 0x3fff, test_data);
let chunks = chip.chunks(16);
assert_eq!(chunks.len(), 1);
for chunk in chunks {
assert_eq!(chunk.len(), 4);
}
}
}
+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
@@ -16,66 +16,3 @@ impl At28C256 {
}
}
#[cfg(test)]
mod test {
use std::fs;
use std::path::Path;
use crate::constants::constants_system::SIZE_1KB;
use crate::traits::memory_chip::MemoryChip;
use crate::traits::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");
}
}
-10
View File
@@ -21,13 +21,3 @@ impl Default for At28C256 {
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() {
assert!(true);
}
}
+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] }
}
}
+151 -3
View File
@@ -1,6 +1,5 @@
pub mod default;
pub mod rom_chip;
pub mod tick;
pub mod new;
pub mod program;
pub mod dump;
@@ -8,9 +7,9 @@ pub mod checksum;
pub mod blocks;
pub mod control;
pub mod signal_tick;
pub mod memory_chip;
pub mod bus_device;
use crate::traits::rom_chip::RomChip;
use std::io::Read;
/// At28C256
///
@@ -31,3 +30,152 @@ pub struct At28C256 {
we: bool,
oe: bool
}
#[cfg(test)]
mod test {
use crate::traits::rom_chip::RomChip;
use std::io::Read;
use std::fs;
use crate::constants::constants_system::*;
use crate::constants::constants_test::*;
use crate::periph::at28c256::At28C256;
use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
#[test]
fn smoke() { assert!(true); }
#[test]
fn checksum_binary_loads() {
let path = format!("{}/{}", TEST_PERIPH_AT28C256_ROOT, "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.");
}
};
let mut rom = At28C256::new(0x0000, 0x3fff, bytes);
assert_eq!(rom.checksum(), 0x58);
}
#[test]
fn full_chunks_come_back_ok() {
let test_data = (0..255).collect();
let mut chip = At28C256::new(0x0000, 0x3fff, test_data);
let chunks = chip.chunks(16);
assert_eq!(chunks.len(), 16);
}
#[test]
fn partial_blocks_come_back_ok() {
let test_data = (0..=3).collect();
let mut chip = At28C256::new(0x0000, 0x3fff, test_data);
let chunks = chip.chunks(16);
assert_eq!(chunks.len(), 1);
for chunk in chunks {
assert_eq!(chunk.len(), 4);
}
}
#[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 - 1) {
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");
}
#[test]
fn address_data_set_reads() {
let mut x = At28C256::new(0x0000, 0x3fff, vec![0xea; SIZE_32KB]);
// set both...
x.set_address_bus(0x3000);
x.set_data_bus(0xab);
assert_eq!(0xab, x.data_bus());
assert_eq!(0x3000, x.address_bus());
// ...set address...
x.set_address_bus(0x2000);
assert_eq!(0x2000, x.address_bus());
assert_eq!(0xab, x.data_bus());
// ...set data.
x.set_data_bus(0xba);
assert_eq!(0xba, x.data_bus());
assert_eq!(0x2000, x.address_bus());
}
fn programming_chip_changes_contents() {
let mut chip = At28C256::new(0x0000, 0x3fff, vec![]);
assert_eq!(0x00, chip.read(&0x0000));
let new_data: Vec<u8> = vec![0xff, 0xff, 0xff, 0xff];
chip.program(new_data.into());
assert_eq!(0xff, chip.read(&0x0000));
assert_eq!(0x00, chip.read(&0x05));
}
#[test]
fn correct_flags_required() {
let mut chip = At28C256::new(0x0000, 0x3fff, vec![0xff]);
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, false, true, true));
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, true, true, false));
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, false, true, false));
assert_eq!(0xff, chip.signal_tick(0x0000, 0xab, true, true, true));
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, true, false, true));
}
}
-21
View File
@@ -9,24 +9,3 @@ impl At28C256 {
}
}
#[cfg(test)]
mod test {
use crate::traits::memory_chip::MemoryChip;
use crate::traits::rom_chip::RomChip;
use super::*;
#[test]
fn smoke() { assert!(true) }
#[test]
fn programming_chip_changes_contents() {
let mut chip = At28C256::new(0x0000, 0x3fff, vec![]);
assert_eq!(0x00, chip.read(&0x0000));
let new_data: Vec<u8> = vec![0xff, 0xff, 0xff, 0xff];
chip.program(new_data.into());
assert_eq!(0xff, chip.read(&0x0000));
assert_eq!(0x00, chip.read(&0x05));
}
}
+2 -31
View File
@@ -1,29 +1,10 @@
use log::debug;
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::at28c256::At28C256;
use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
use crate::traits::rom_chip::RomChip;
impl MemoryChip for At28C256 {
fn read(&self, offset: &u16) -> u8 {
/// read
///
/// Reads a byte from memory.
/// Returns a 0x00 if there is no data at that location but is still in ROM address range
println!("STARTING READ FROM At28C256 ${:04x} | ${:04x} | ${:04x}", self.offset, offset, self.max_offset);
if offset < &self.offset || offset > &self.max_offset {
println!("Unable to read from ${offset:04x} as it it out of range.");
return 0x00;
} else {
println!("OK READ FROM GOOD AREA total len = {}", self.data.len());
}
if *offset >= self.data.len() as u16 {
0x00
} else {
self.data[*offset as usize]
} }
}
impl RomChip for At28C256 {
/// program
///
@@ -35,13 +16,3 @@ impl RomChip for At28C256 {
Box::new(working)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() {
assert!(true);
}
}
-18
View File
@@ -31,21 +31,3 @@ impl At28C256 {
result
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn smoke() { assert!(true) }
#[test]
fn correct_flags_required() {
let mut chip = At28C256::new(0x0000, 0x3fff, vec![0xff]);
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, false, true, true));
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, true, true, false));
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, false, true, false));
assert_eq!(0xff, chip.signal_tick(0x0000, 0xab, true, true, true));
assert_eq!(0xab, chip.signal_tick(0x0000, 0xab, true, false, true));
}
}
-71
View File
@@ -1,71 +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 {
//println!("Checking on {address:04x} in range of {:04x} {:04x}", self.offset, self.max_offset);
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)
}
// print!("At28C256 tick for me.");
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)
}
// print!("At28C256: Read... {:02x}", self.data_bus);
(address_bus, self.data_bus)
}
}
#[cfg(test)]
mod test {
use std::fs;
use crate::traits::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);
}
}
+1
View File
@@ -9,6 +9,7 @@ impl Default for Hm62256 {
boxed_slice.try_into().expect("Unable to box the ram");
Hm62256 {
offset: 0x0000,
max_offset: 0x2000,
data: boxed_array,
address_bus: 0x0000,
data_bus: 0x00,
+1
View File
@@ -18,6 +18,7 @@ use log::debug;
/// 32KByte
pub struct Hm62256 {
pub(crate) offset: u16,
pub(crate) max_offset: u16,
pub(crate) data: Box<[u8]>,
pub(crate) address_bus: u16,
pub(crate) data_bus: u8,
+1
View File
@@ -5,6 +5,7 @@ impl Hm62256 {
pub fn new(base_offset: u16) -> Self {
Self {
offset: base_offset,
max_offset: base_offset + SIZE_32KB as u16,
data: vec![0; SIZE_32KB].into_boxed_slice(),
address_bus: 0x0000,
data_bus: 0x00,
+28
View File
@@ -1,7 +1,35 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::periph::hm62256::Hm62256;
use crate::traits::bus_device::BusDevice;
use crate::traits::ram_chip::RamChip;
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
}
}
impl RamChip for Hm62256 {
fn write(&mut self, offset: &u16, value: &u8) {
let effective = *offset as i32 % SIZE_32KB as i32;
+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
}
}
+34 -48
View File
@@ -1,65 +1,51 @@
mod tod;
mod reset;
pub mod reset;
pub mod bus_device;
pub mod via_chip;
pub mod new;
pub mod tick;
use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
use crate::traits::ram_chip::RamChip;
use crate::traits::rom_chip::RomChip;
use crate::traits::via_chip::ViaChip;
/*
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
port_a: u8,
port_b: u8,
out_a: u8,
in_a: u8,
ddra: u8,
port_b: u8,
out_b: u8,
in_b: u8,
ddrb: u8,
// Timer registers and control
tmr_a: u16,
latch_a: u16,
ctrl_a: u8,
tmr_b: u16,
latch_b: u16,
ctrl_b: u8,
// Interrupt control register
icr: u8,
// TOD clock raw BCD registers
tod_hours: u8,
tod_minutes: u8,
tod_seconds: u8,
tod_tenths: u8,
tod_frozen: bool,
// External Address and Data Bus
address_bus: u16,
data_bus: u8,
// Offsets
offset: u16,
max_offset: u16
}
impl RamChip for Mos6520 {
fn write(&mut self, offset: &u16, value: &u8) {
match offset & 0x0F {
0x0 => { self.port_a = *value; }
0x1 => { self.ddra = *value; }
0x4 => { self.latch_a = (self.latch_a & 0xFF00) | *value as u16; }
0x5 => { self.latch_a = (self.latch_a & 0x00FF) | ((*value as u16) << 8); }
0x8..=0xB => { self.write_tod((offset & 0x03) as u8, *value); }
_ => {}
}
}
}
impl MemoryChip for Mos6520 {
fn read(&self, offset: &u16) -> u8 {
todo!()
}
}
impl RomChip for Mos6520 {
fn program(new_data: &[u8]) -> Box<Self> {
todo!()
}
}
impl ViaChip for Mos6520 {
fn set_port_ddr(&mut self, port_index: u8, value: u8) {
todo!()
}
fn set_port_data(&mut self, port_index: u8, value: u8) {
todo!()
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,
}
}
}
-12
View File
@@ -9,18 +9,6 @@ impl Mos6520 {
self.port_b = 0x00;
self.ddra = 0x00;
self.ddrb = 0x00;
self.tmr_a = 0x00;
self.latch_a = 0x00;
self.ctrl_a = 0x00;
self.tmr_b = 0x00;
self.latch_b = 0x00;
self.ctrl_b = 0x00;
self.icr = 0x00;
self.tod_hours = 0x01;
self.tod_minutes = 0x00;
self.tod_seconds = 0x00;
self.tod_tenths = 0x00;
self.tod_frozen = false;
}
}
+83
View File
@@ -0,0 +1,83 @@
use log::debug;
use crate::periph::mos6520::Mos6520;
use crate::traits::bus_device::BusDevice;
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);
match effective {
0x00 => {
// ddra
// println!("DDRA -> {:02x} -> {:02x}", self.ddra, self.data_bus);
self.ddra = self.data_bus;
}
0x01 => {
// port a
// println!("PORT A -> {:02x} -> {:02x}", self.port_a, self.data_bus);
self.port_a = self.data_bus;
}
0x02 => {
// ddrb
// println!("DDRB -> {:02x}", self.ddrb);
self.ddrb = self.data_bus;
}
0x03 => {
// 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");
}
}
-26
View File
@@ -1,26 +0,0 @@
use crate::periph::mos6520::Mos6520;
impl Mos6520 {
fn read_tod(&mut self, sub: u8) -> u8 {
match sub {
0 => { self.tod_frozen = true; self.tod_hours },
1 => self.tod_minutes,
2 => self.tod_seconds,
3 => {
self.tod_frozen = false;
self.tod_tenths
}
_ => 0
}
}
pub(crate) fn write_tod(&mut self, sub: u8, value: u8) {
match sub {
0 => { self.tod_hours = value; self.tod_frozen = true; }
1 => self.tod_minutes = value,
2 => self.tod_seconds = value,
3 => { self.tod_tenths = value; self.tod_frozen = false; }
_ => {}
}
}
}
+126
View File
@@ -0,0 +1,126 @@
use log::debug;
use crate::periph::mos6520::Mos6520;
use crate::traits::memory_chip::MemoryChip;
use crate::traits::ram_chip::RamChip;
use crate::traits::rom_chip::RomChip;
use crate::traits::via_chip::ViaChip;
impl RomChip for Mos6520 {
fn program(new_data: &[u8]) -> Box<Self> {
debug!("This has no rom. Cant program.");
todo!()
}
}
impl RamChip for Mos6520 {
fn write(&mut self, offset: &u16, value: &u8) {
debug!("This has no ROM / ${offset:04x} ${value:02x}");
}
}
impl MemoryChip for Mos6520 {
fn read(&self, offset: &u16) -> u8 {
debug!("This has no ROM ${offset:04x}");
0
}
}
impl ViaChip for Mos6520 {
fn set_port_ddr(&mut self, port_index: u8, value: u8) {
match port_index {
1 => {
self.ddra = value;
},
2 => {
self.ddrb = value;
}
_ => {
debug!("Invalid Port");
}
}
self.update_ports();
}
fn set_port_data(&mut self, port_index: u8, value: u8) {
match port_index {
1 => {
self.port_a = value;
},
2 => {
self.port_b = value;
}
_ => {
debug!("Invalid Port");
}
}
self.update_ports();
}
}
impl Mos6520 {
fn update_ports(&mut self) {
debug!("PortA: DDR {:08b}", self.port_a);
debug!("PortB: DDR {:08b}", self.port_b);
}
}
#[cfg(test)]
mod test {
use crate::periph::mos6520::Mos6520;
const DDRA_OFFSET: u8 = 0x00;
const PORTA_OFFSET: u8 = 0x01;
const DDRB_OFFSET: u8 = 0x02;
const PORTB_OFFSET: u8 = 0x03;
fn actual(base: u16, offset: u8) -> u16 {
base + offset as u16
}
#[test]
fn ddrb_tests() {
let mut x = Mos6520::new(0x1000);
let params = vec![
// Offset data outa ina ddra porta
(DDRB_OFFSET, 0xff, 0x00, 0x00, 0xff, 0x00),
(PORTB_OFFSET, 0xff, 0xff, 0x00, 0xff, 0xff),
(DDRB_OFFSET, 0xaa, 0xaa, 0x55, 0xaa, 0xff),
(DDRB_OFFSET, 0x55, 0x55, 0xaa, 0x55, 0xff),
(PORTB_OFFSET, 0xf0, 0x50, 0xa0, 0x55, 0xf0),
(PORTB_OFFSET, 0x0f, 0x05, 0x0a, 0x55, 0x0f),
(DDRB_OFFSET, 0xff, 0x0f, 0x00, 0xff, 0x0f)
];
for (offset, data, outb, inb, ddrb, portb) in params {
x.tick(actual(x.offset, offset), data);
assert_eq!(outb, x.out_b);
assert_eq!(inb, x.in_b);
assert_eq!(ddrb, x.ddrb);
assert_eq!(portb, x.port_b);
}
}
#[test]
fn ddra_tests() {
let mut x = Mos6520::new(0x1000);
let params = vec![
// Offset data outa ina ddra porta
(DDRA_OFFSET, 0xff, 0x00, 0x00, 0xff, 0x00),
(PORTA_OFFSET, 0xff, 0xff, 0x00, 0xff, 0xff),
(DDRA_OFFSET, 0xaa, 0xaa, 0x55, 0xaa, 0xff),
(DDRA_OFFSET, 0x55, 0x55, 0xaa, 0x55, 0xff),
(PORTA_OFFSET, 0xf0, 0x50, 0xa0, 0x55, 0xf0),
(PORTA_OFFSET, 0x0f, 0x05, 0x0a, 0x55, 0x0f),
(DDRA_OFFSET, 0xff, 0x0f, 0x00, 0xff, 0x0f)
];
for (offset, data, outa, ina, ddra, porta) in params {
x.tick(actual(x.offset, offset), data);
assert_eq!(outa, x.out_a);
assert_eq!(ina, x.in_a);
assert_eq!(ddra, x.ddra);
assert_eq!(porta, x.port_a);
}
}
}
+3 -3
View File
@@ -1,5 +1,5 @@
pub mod mos6530;
pub mod tick;
mod new;
mod dump;
mod viachip;
pub mod new;
pub mod dump;
pub mod viachip;
+13 -13
View File
@@ -13,19 +13,19 @@ use crate::periph::mos6522::mos6522::Mos6522;
/// IO Ports (A, B)
/// Timer
pub struct Mos6530 {
pub(crate) data: [u8; SIZE_1KB],
pub(crate) ram: [u8; 64],
pub(crate) porta: u8,
pub(crate) portb: u8,
pub(crate) data_bus: u8,
pub(crate) address_bus: u16,
pub(crate) cs1: bool,
pub(crate) cs2: bool,
pub data: [u8; SIZE_1KB],
pub ram: [u8; 64],
pub porta: u8,
pub portb: u8,
pub data_bus: u8,
pub address_bus: u16,
pub cs1: bool,
pub cs2: bool,
// when true, CPU is reading
pub(crate) rw: bool,
pub(crate) reset: bool,
pub(crate) io_offset: u16,
pub(crate) ram_offset: u16,
pub(crate) rom_offset: u16
pub rw: bool,
pub reset: bool,
pub io_offset: u16,
pub ram_offset: u16,
pub rom_offset: u16
}
+28 -1
View File
@@ -1,11 +1,39 @@
use log::debug;
use crate::constants::constants_system::{SIZE_1KB, SIZE_32KB};
use crate::periph::mos6530::mos6530::Mos6530;
use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
use crate::traits::ram_chip::RamChip;
use crate::traits::rom_chip::RomChip;
use crate::traits::via_chip::ViaChip;
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
}
}
impl RamChip for Mos6530 {
fn write(&mut self, offset: &u16, value: &u8) {
debug!("🐙 Writing ${value:02x} to ${offset:04x}");
@@ -49,4 +77,3 @@ impl ViaChip for Mos6530 {
debug!("🐙Setting PORT{port_index} to {value:02x}");
}
}
+5 -4
View File
@@ -16,19 +16,20 @@ pub trait Backplane {
/// Tick a ROM chip
///
/// returns (data_for_databus)
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool);
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8;
/// tick_rom
///
/// Tick a ROM chip
///
/// returns (data_for_databus)
fn tick_rom(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> (u8);
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8;
/// tick_via
///
/// Tick a VIA chip
///
/// returns (portA, portB, interrupt)
fn tick_via(&mut self, address: u16, data: u8, cs: bool, rw: bool, ce: bool) -> (u8, u8, bool);
/// returns (data, irqa, irqb)
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool);
}
+26 -1
View File
@@ -1,8 +1,33 @@
pub trait BusDevice {
fn min_offset(&self) -> u16;
fn max_offset(&self) -> u16;
fn address_bus(&self) -> u16;
fn data_bus(&self) -> u8;
fn set_address_bus(&mut self, new_value: u16);
fn set_data_bus(&mut self, new_value: u8);
fn talking_to_me(&self, address: u16) -> bool;
fn talking_to_me(&self, address: u16) -> bool {
address >= self.min_offset() && address < self.max_offset()
}
/// internal_address
///
/// Converts from a system-wide address to a device specific address
///
/// ex: 0x3000 to a ROM chip with min_offset = 0x2000
/// -> internal_address = 0x1000 <-- read this offset from data array
/// -> external_address = 0x3000
fn internal_address(&self, address: u16) -> u16 {
// println!("MINOFFSET ${:04x}", self.min_offset());
let mo = self.max_offset();
let result= if address > mo {
address - self.max_offset()
} else {
address
};
// println!("RESULT = {:04x}", result - self.min_offset());
result - self.min_offset()
}
}
+3 -1
View File
@@ -1,4 +1,6 @@
pub trait MemoryChip {
use crate::traits::bus_device::BusDevice;
pub trait MemoryChip : BusDevice {
/// Read
///
/// Reads a single byte from the specified address
+1
View File
@@ -5,3 +5,4 @@ pub mod rom_chip;
pub mod ram_chip;
pub mod via_chip;
pub mod backplane;
mod timer_chip;
+2 -1
View File
@@ -1,7 +1,8 @@
use crate::periph::hm62256::Hm62256;
use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
use crate::traits::rom_chip::RomChip;
pub trait RamChip: MemoryChip {
pub trait RamChip: MemoryChip + BusDevice {
fn write(&mut self, offset: &u16, value: &u8);
}
+2 -1
View File
@@ -1,7 +1,8 @@
use crate::constants::constants_system::SIZE_32KB;
use crate::traits::bus_device::BusDevice;
use crate::traits::memory_chip::MemoryChip;
pub trait RomChip: MemoryChip {
pub trait RomChip: MemoryChip + BusDevice {
/// Program
///
/// Replaces all data in the chip
+16
View File
@@ -0,0 +1,16 @@
use crate::traits::bus_device::BusDevice;
pub trait TimerChip: BusDevice {
/// set_timer
///
/// Set current value of timer
fn set_timer(&mut self, timer_index: u8, new_value: u16);
/// get_timer
///
/// Read current value of timer
fn get_timer(&mut self, timer_index: u8) -> u16;
/// Advance Timer circutry 1 cycle
fn tick(&mut self);
}
+9 -3
View File
@@ -1,15 +1,21 @@
use log::debug;
use crate::traits::bus_device::BusDevice;
use crate::traits::ram_chip::RamChip;
use crate::traits::rom_chip::RomChip;
pub trait ViaChip: RamChip + RomChip {
pub trait ViaChip: RamChip + RomChip + BusDevice {
/// set_port_ddr
///
/// Sets the Data Direction Register in the VIA chip for the specified
/// port.
fn set_port_ddr(&mut self, port_index: u8, value: u8);
fn set_port_ddr(&mut self, port_index: u8, value: u8) {
debug!("Please implement this.");
}
/// set_port_data
///
/// Sets the
fn set_port_data(&mut self, port_index: u8, value: u8);
fn set_port_data(&mut self, port_index: u8, value: u8) {
debug!("Please implement this.");
}
}
-6
View File
@@ -1,6 +0,0 @@
use super::*;
#[test]
fn test123() {
}
+4
View File
@@ -0,0 +1,4 @@
#[test]
fn test() {
assert!(true);
}
-1
View File
@@ -1 +0,0 @@
-1
View File
@@ -1 +0,0 @@
Binary file not shown.
-3
View File
@@ -1,3 +0,0 @@
fn main() {
println!("Hello, world!");
}