MOS6520 looking mostly there.
This commit is contained in:
Generated
-8
@@ -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
@@ -3,7 +3,7 @@ members = [
|
||||
"core",
|
||||
"cli",
|
||||
"macroquad",
|
||||
"beneater"
|
||||
# "beneater"
|
||||
]
|
||||
resolver="2"
|
||||
|
||||
|
||||
@@ -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
@@ -1,5 +1,5 @@
|
||||
use core::computers::kim1::Kim1;
|
||||
|
||||
use core::constants::constants_system::*;
|
||||
fn main() {
|
||||
println!("Taxation is theft.");
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
use core::mos6502cpu::cpu::Mos6502Cpu;
|
||||
|
||||
fn main() {
|
||||
let x = Mos6502Cpu::default();
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,3 +2,4 @@ pub mod beneater;
|
||||
pub mod rom_only;
|
||||
pub mod kim1;
|
||||
pub mod ram_rom;
|
||||
pub mod tim1;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
use crate::mos6502cpu::Mos6502Cpu;
|
||||
use crate::periph::mos6530::mos6530::Mos6530;
|
||||
|
||||
pub struct Tim1 {
|
||||
cpu: Mos6502Cpu,
|
||||
pia: Mos6530
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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!()
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,3 @@ impl Default for At28C256 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn smoke() {
|
||||
assert!(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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] }
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,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
|
||||
}
|
||||
|
||||
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,3 +5,4 @@ pub mod rom_chip;
|
||||
pub mod ram_chip;
|
||||
pub mod via_chip;
|
||||
pub mod backplane;
|
||||
mod timer_chip;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test123() {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#[test]
|
||||
fn test() {
|
||||
assert!(true);
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
Binary file not shown.
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
Reference in New Issue
Block a user