Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c4e1f233ae | |||
| 7ac8bd86ba | |||
| 8f6f9cb64d | |||
| b40c3c503f | |||
| d5efabdd36 |
Generated
+8
-8
@@ -497,14 +497,6 @@ version = "1.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "beneater"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"core",
|
|
||||||
"macroquad 0.4.14",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@@ -1110,6 +1102,14 @@ dependencies = [
|
|||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "egui"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"core",
|
||||||
|
"eframe",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "egui"
|
name = "egui"
|
||||||
version = "0.27.2"
|
version = "0.27.2"
|
||||||
|
|||||||
+2
-1
@@ -3,7 +3,8 @@ members = [
|
|||||||
"core",
|
"core",
|
||||||
"cli",
|
"cli",
|
||||||
"macroquad",
|
"macroquad",
|
||||||
"beneater"
|
# "beneater"
|
||||||
|
"egui"
|
||||||
]
|
]
|
||||||
resolver="2"
|
resolver="2"
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
+1
-1
@@ -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.");
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use core::computers::ram_rom::backplane::RamRomComputer;
|
use core::computers::ram_rom::RamRomComputer;
|
||||||
use core::periph::backplane::Backplane;
|
use core::traits::backplane::Backplane;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
use std::fs;
|
|
||||||
use clap::Parser;
|
|
||||||
use core::computers::rom_only::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!("----");
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
use core::computers::single_breadboard::SingleBreadboard;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let sb = SingleBreadboard::new();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
use core::mos6502cpu::cpu::Mos6502Cpu;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let x = Mos6502Cpu::default();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod ram_rom_tests;
|
||||||
|
mod rom_only_test;
|
||||||
@@ -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());
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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,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,15 +2,10 @@ pub mod new;
|
|||||||
pub mod tick;
|
pub mod tick;
|
||||||
pub mod reset;
|
pub mod reset;
|
||||||
|
|
||||||
use std::fs;
|
|
||||||
use std::path::Path;
|
|
||||||
use crate::constants::constants_system::SIZE_1KB;
|
|
||||||
use crate::mos6502cpu::Mos6502Cpu;
|
use crate::mos6502cpu::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
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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,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;
|
||||||
|
|||||||
@@ -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,6 +17,18 @@ impl Backplane for RamRomComputer {
|
|||||||
self.read_mode
|
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) {
|
fn tick(&mut self) {
|
||||||
println!("Preparing to tick the backplane. - ${:04x} ${:02x} {}", self.address_bus, self.data_bus, self.read_mode);
|
println!("Preparing to tick the backplane. - ${:04x} ${:02x} {}", self.address_bus, self.data_bus, self.read_mode);
|
||||||
|
|
||||||
@@ -39,7 +45,7 @@ impl Backplane for RamRomComputer {
|
|||||||
0x4000..=0x7fff => {
|
0x4000..=0x7fff => {
|
||||||
// ROM
|
// ROM
|
||||||
println!("ADDRESSING 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;
|
self.data_bus = rom_data_bus;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -47,29 +53,19 @@ impl Backplane for RamRomComputer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn set_read_mode(&mut self, new_mode: bool) {
|
|
||||||
self.read_mode = new_mode;
|
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 set_address_bus(&mut self, new_value: u16) {
|
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
|
||||||
self.address_bus = new_value;
|
debug!("Ticking rom with A${address:04x} CS:{cs} OE:{oe}");
|
||||||
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_data_bus(&mut self, new_value: u8) {
|
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
|
||||||
self.data_bus = new_value;
|
debug!("Ticking Via with A${address:04x} D${data:02x} cs0:{cs0} cs1:{cs1} rw:{rw} rs0:{rs0} rs1:{rs1}");
|
||||||
}
|
(0, false, false)
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
|
use log::debug;
|
||||||
use crate::computers::rom_only::RomOnlyComputer;
|
use crate::computers::rom_only::RomOnlyComputer;
|
||||||
use crate::periph::backplane::Backplane;
|
use crate::traits::backplane::Backplane;
|
||||||
|
|
||||||
impl Backplane for RomOnlyComputer {
|
impl Backplane for RomOnlyComputer {
|
||||||
fn data_bus(&self) -> u8 { self.data_bus }
|
fn data_bus(&self) -> u8 { self.data_bus }
|
||||||
@@ -16,14 +17,29 @@ impl Backplane for RomOnlyComputer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ impl RomOnlyComputer {
|
|||||||
for index in 0..size {
|
for index in 0..size {
|
||||||
println!("Index {index} for {}", index + start_offset);
|
println!("Index {index} for {}", index + start_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::periph::at28c256::At28C256;
|
use crate::periph::at28c256::At28C256;
|
||||||
|
use crate::traits::backplane::Backplane;
|
||||||
|
|
||||||
pub mod backplane;
|
pub mod backplane;
|
||||||
pub mod new;
|
pub mod new;
|
||||||
@@ -7,8 +8,22 @@ pub mod debug_memory;
|
|||||||
mod rom_chunks;
|
mod rom_chunks;
|
||||||
|
|
||||||
pub struct RomOnlyComputer {
|
pub struct RomOnlyComputer {
|
||||||
pub(crate) rom: At28C256,
|
pub rom: At28C256,
|
||||||
pub(crate) data_bus: u8,
|
pub data_bus: u8,
|
||||||
pub(crate) address_bus: u16,
|
pub address_bus: u16,
|
||||||
pub(crate) read_mode: bool,
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -9,5 +9,4 @@ impl RomOnlyComputer {
|
|||||||
}
|
}
|
||||||
RomOnlyComputer::program(working)
|
RomOnlyComputer::program(working)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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 {
|
||||||
@@ -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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,6 +2,12 @@ use crate::mos6502cpu::Mos6502Cpu;
|
|||||||
use crate::traits::bus_device::BusDevice;
|
use crate::traits::bus_device::BusDevice;
|
||||||
|
|
||||||
impl BusDevice for Mos6502Cpu {
|
impl BusDevice for Mos6502Cpu {
|
||||||
|
fn min_offset(&self) -> u16 { 0 }
|
||||||
|
|
||||||
|
fn max_offset(&self) -> u16 {
|
||||||
|
0x7fff
|
||||||
|
}
|
||||||
|
|
||||||
fn address_bus(&self) -> u16 {
|
fn address_bus(&self) -> u16 {
|
||||||
self.address_bus
|
self.address_bus
|
||||||
}
|
}
|
||||||
@@ -17,4 +23,5 @@ impl BusDevice for Mos6502Cpu {
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
@@ -6,32 +6,3 @@ impl At28C256 {
|
|||||||
self.data.chunks(size)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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 {}
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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,15 +1,14 @@
|
|||||||
pub mod default;
|
pub mod default;
|
||||||
pub mod rom_chip;
|
pub mod rom_chip;
|
||||||
pub mod tick;
|
|
||||||
pub mod new;
|
pub mod new;
|
||||||
pub mod program;
|
pub mod program;
|
||||||
pub mod dump;
|
pub mod dump;
|
||||||
pub mod checksum;
|
pub mod checksum;
|
||||||
pub mod blocks;
|
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
|
||||||
///
|
///
|
||||||
@@ -18,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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,22 +9,3 @@ impl At28C256 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use crate::periph::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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,46 +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 {
|
||||||
/// 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 {
|
|
||||||
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]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// program
|
/// program
|
||||||
///
|
///
|
||||||
/// Writes new data to the memory chip
|
/// Writes new data to the memory chip
|
||||||
fn program(new_data: &[u8; SIZE_32KB]) -> Box<At28C256> {
|
fn program(new_data: &[u8]) -> 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,70 +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) {
|
|
||||||
print!("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.
|
|
||||||
// println!("At28C256 Tick not for me.");
|
|
||||||
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::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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
pub trait BusDevice {
|
|
||||||
fn talking_to_me(&self, address: u16) -> bool;
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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!()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
mod backplane;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Mos6526 {}
|
||||||
@@ -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,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) {
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use log::debug;
|
||||||
|
use crate::periph::mos6530::Mos6530;
|
||||||
|
use crate::traits::memory_chip::MemoryChip;
|
||||||
|
|
||||||
|
impl MemoryChip for Mos6530 {
|
||||||
|
fn read(&self, offset: &u16) -> u8 {
|
||||||
|
debug!("🐙 Reading from ${offset:04x}");
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,45 @@
|
|||||||
pub mod mos6530;
|
use crate::constants::constants_system::SIZE_1KB;
|
||||||
|
|
||||||
pub mod tick;
|
pub mod tick;
|
||||||
mod new;
|
pub mod new;
|
||||||
mod dump;
|
pub mod dump;
|
||||||
|
pub mod viachip;
|
||||||
|
pub mod bus_device;
|
||||||
|
pub mod ram_chip;
|
||||||
|
pub mod rom_chip;
|
||||||
|
pub mod memory_chip;
|
||||||
|
|
||||||
|
/// Mos6530 RRIOT
|
||||||
|
/// Ram/Rom/IO/Timer
|
||||||
|
///
|
||||||
|
/// Represents a single Mos6530 RRIOT Chip
|
||||||
|
///
|
||||||
|
/// Used in the TIM-1, KIM-1
|
||||||
|
///
|
||||||
|
/// 1kb Rom
|
||||||
|
/// 64 bytes RAM
|
||||||
|
/// IO Ports (A, B)
|
||||||
|
/// Timer
|
||||||
|
pub struct Mos6530 {
|
||||||
|
pub data: [u8; SIZE_1KB],
|
||||||
|
pub ram: [u8; 64],
|
||||||
|
pub port_a: u8,
|
||||||
|
pub ddra: u8,
|
||||||
|
pub in_a: u8,
|
||||||
|
pub out_a: u8,
|
||||||
|
pub port_b: u8,
|
||||||
|
pub ddrb: u8,
|
||||||
|
pub in_b: u8,
|
||||||
|
pub out_b: u8,
|
||||||
|
pub data_bus: u8,
|
||||||
|
pub address_bus: u16,
|
||||||
|
pub cs1: bool,
|
||||||
|
pub cs2: bool,
|
||||||
|
// when true, CPU is reading
|
||||||
|
pub rw: bool,
|
||||||
|
pub reset: bool,
|
||||||
|
pub io_offset: u16,
|
||||||
|
pub ram_offset: u16,
|
||||||
|
pub rom_offset: u16
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
use crate::constants::constants_system::*;
|
|
||||||
use crate::periph::mos6522::mos6522::Mos6522;
|
|
||||||
|
|
||||||
/// Mos6530 RRIOT
|
|
||||||
/// Ram/Rom/IO/Timer
|
|
||||||
///
|
|
||||||
/// Represents a single Mos6530 RRIOT Chip
|
|
||||||
///
|
|
||||||
/// Used in the TIM-1, KIM-1
|
|
||||||
///
|
|
||||||
/// 1kb Rom
|
|
||||||
/// 64 bytes RAM
|
|
||||||
/// 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,
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::constants::constants_system::SIZE_1KB;
|
use crate::constants::constants_system::SIZE_1KB;
|
||||||
use crate::periph::mos6530::mos6530::Mos6530;
|
use crate::periph::mos6530::Mos6530;
|
||||||
|
|
||||||
impl Mos6530 {
|
impl Mos6530 {
|
||||||
pub fn new(io_offset: u16,
|
pub fn new(io_offset: u16,
|
||||||
@@ -9,8 +9,14 @@ impl Mos6530 {
|
|||||||
Mos6530 {
|
Mos6530 {
|
||||||
data: *data,
|
data: *data,
|
||||||
ram: [0x00; 64],
|
ram: [0x00; 64],
|
||||||
porta: 0,
|
port_a: 0,
|
||||||
portb: 0,
|
ddra: 0,
|
||||||
|
in_a: 0,
|
||||||
|
out_a: 0,
|
||||||
|
port_b: 0,
|
||||||
|
ddrb: 0,
|
||||||
|
in_b: 0,
|
||||||
|
out_b: 0,
|
||||||
data_bus: 0,
|
data_bus: 0,
|
||||||
address_bus: 0,
|
address_bus: 0,
|
||||||
cs1: false,
|
cs1: false,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
use log::debug;
|
||||||
|
use crate::periph::mos6530::Mos6530;
|
||||||
|
use crate::traits::ram_chip::RamChip;
|
||||||
|
|
||||||
|
impl RamChip for Mos6530 {
|
||||||
|
fn write(&mut self, offset: &u16, value: &u8) {
|
||||||
|
debug!("🐙 Writing ${value:02x} to ${offset:04x}");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
use log::debug;
|
||||||
|
use crate::periph::mos6530::Mos6530;
|
||||||
|
use crate::traits::rom_chip::RomChip;
|
||||||
|
|
||||||
|
impl RomChip for Mos6530 {
|
||||||
|
fn program(new_data: &[u8]) -> Box<Self> {
|
||||||
|
debug!("🐙 programming {}b to ROM", new_data.len());
|
||||||
|
Box::new(Mos6530 {
|
||||||
|
data: new_data.to_vec().try_into().unwrap(),
|
||||||
|
ram: [0x00; 64],
|
||||||
|
port_a: 0,
|
||||||
|
ddra: 0,
|
||||||
|
in_a: 0,
|
||||||
|
out_a: 0,
|
||||||
|
port_b: 0,
|
||||||
|
ddrb: 0,
|
||||||
|
in_b: 0,
|
||||||
|
out_b: 0,
|
||||||
|
data_bus: 0,
|
||||||
|
address_bus: 0,
|
||||||
|
cs1: false,
|
||||||
|
cs2: false,
|
||||||
|
rw: false,
|
||||||
|
reset: false,
|
||||||
|
io_offset: 0,
|
||||||
|
ram_offset: 0,
|
||||||
|
rom_offset: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
use log::debug;
|
use log::debug;
|
||||||
use crate::periph::mos6530::mos6530::Mos6530;
|
use crate::periph::mos6530::Mos6530;
|
||||||
|
|
||||||
impl Mos6530 {
|
impl Mos6530 {
|
||||||
pub fn tick(&mut self, address_bus: u16, data_bus: u8, reset: bool, rw: bool) {
|
pub fn tick(&mut self, address_bus: u16, data_bus: u8, reset: bool, rw: bool) {
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
use log::debug;
|
||||||
|
use crate::constants::constants_system::{SIZE_1KB, SIZE_32KB};
|
||||||
|
use crate::periph::mos6520::Mos6520;
|
||||||
|
use crate::periph::mos6530::Mos6530;
|
||||||
|
use crate::traits::bus_device::BusDevice;
|
||||||
|
use crate::traits::gpio_chip::{GpioChip, GpioChipPorts};
|
||||||
|
use crate::traits::memory_chip::MemoryChip;
|
||||||
|
use crate::traits::pia_chip::PiaChip;
|
||||||
|
use crate::traits::ram_chip::RamChip;
|
||||||
|
use crate::traits::rom_chip::RomChip;
|
||||||
|
|
||||||
|
impl GpioChip for Mos6530 {
|
||||||
|
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 Mos6530 {
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
use crate::periph::mos6532::Mos6532;
|
||||||
|
use crate::traits::bus_device::BusDevice;
|
||||||
|
|
||||||
|
impl BusDevice for Mos6532 {
|
||||||
|
fn min_offset(&self) -> u16 {
|
||||||
|
self.ram_offset.min(self.io_offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_offset(&self) -> u16 { self.min_offset() + 0x40 }
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
mod bus_device;
|
||||||
|
mod new;
|
||||||
|
|
||||||
|
use log::debug;
|
||||||
|
use crate::traits::backplane::Backplane;
|
||||||
|
use crate::traits::bus_device::BusDevice;
|
||||||
|
|
||||||
|
pub struct Mos6532 {
|
||||||
|
// R
|
||||||
|
ram: Box<[u8; 64]>,
|
||||||
|
// IO
|
||||||
|
ddra: u8,
|
||||||
|
porta: u8,
|
||||||
|
in_a: u8,
|
||||||
|
out_a: u8,
|
||||||
|
ddrb: u8,
|
||||||
|
portb: u8,
|
||||||
|
in_b: u8,
|
||||||
|
out_b: u8,
|
||||||
|
// T
|
||||||
|
|
||||||
|
// Generic 6502 stuff
|
||||||
|
read_mode: bool,
|
||||||
|
data_bus: u8,
|
||||||
|
address_bus: u16,
|
||||||
|
|
||||||
|
// Part Specific
|
||||||
|
ram_offset: u16,
|
||||||
|
io_offset: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
const MOS6532_DDRA_OFFSET: u8 = 0x00;
|
||||||
|
const MOS6532_DDRB_OFFSET: u8 = 0x02;
|
||||||
|
const MOS6532_PRTA_OFFSET: u8 = 0x01;
|
||||||
|
const MOS6532_PRTB_OFFSET: u8 = 0x03;
|
||||||
|
|
||||||
|
impl Mos6532 {
|
||||||
|
fn targets_ram(&self, offset: u16) -> bool {
|
||||||
|
// we are at or above the offset AND we are under the end of ram
|
||||||
|
offset >= self.ram_offset && offset <= self.ram_offset + 64
|
||||||
|
}
|
||||||
|
|
||||||
|
fn targets_io(&self, offset: u16) -> bool {
|
||||||
|
offset >= self.io_offset && offset <= self.io_offset + 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn targetting_parts() {
|
||||||
|
// RAM from 0x0000 -> 0x0040
|
||||||
|
// IO from 0x1000 -> 0x1004
|
||||||
|
let via = Mos6532::new(0x0000, 0x1000);
|
||||||
|
|
||||||
|
assert!(via.targets_io(0x1000));
|
||||||
|
assert!(!via.targets_ram(0x1000));
|
||||||
|
|
||||||
|
assert!(!via.targets_io(0x0000));
|
||||||
|
assert!(via.targets_ram(0x0000));
|
||||||
|
|
||||||
|
assert!(!via.targets_io(0x4000));
|
||||||
|
assert!(!via.targets_ram(0x4000));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
use crate::periph::mos6532::Mos6532;
|
||||||
|
|
||||||
|
impl Mos6532 {
|
||||||
|
pub fn new(ram_offset: u16, io_offset: u16) -> Self {
|
||||||
|
Mos6532 {
|
||||||
|
ram: Box::new([0x00; 64]),
|
||||||
|
ddra: 0,
|
||||||
|
porta: 0,
|
||||||
|
in_a: 0,
|
||||||
|
out_a: 0,
|
||||||
|
ddrb: 0,
|
||||||
|
portb: 0,
|
||||||
|
in_b: 0,
|
||||||
|
out_b: 0,
|
||||||
|
read_mode: true,
|
||||||
|
data_bus: 0x00,
|
||||||
|
address_bus: 0x0000,
|
||||||
|
ram_offset,
|
||||||
|
io_offset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
use crate::periph::mos6540::Mos6540;
|
||||||
|
use crate::traits::bus_device::BusDevice;
|
||||||
|
use crate::traits::memory_chip::MemoryChip;
|
||||||
|
|
||||||
|
impl BusDevice for Mos6540 {
|
||||||
|
fn min_offset(&self) -> u16 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_offset(&self) -> u16 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn address_bus(&self) -> u16 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Mos6540 {
|
||||||
|
fn read(&self, offset: &u16) -> u8 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// MOS6540
|
||||||
|
// 2KByte 16kbit ROM
|
||||||
|
|
||||||
|
mod memory_chip;
|
||||||
|
|
||||||
|
struct Mos6540 {
|
||||||
|
data_bus: u8,
|
||||||
|
address_bus: u16,
|
||||||
|
pub data: Box<u8>,
|
||||||
|
offset: u16,
|
||||||
|
max_offset: u16
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
use crate::periph::rom_chip::RomChip;
|
|
||||||
|
|
||||||
pub trait RamChip: RomChip {
|
|
||||||
fn write(&mut self, offset: &u16, value: &u8);
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
use crate::constants::constants_system::SIZE_32KB;
|
|
||||||
|
|
||||||
pub trait RomChip {
|
|
||||||
/// Read
|
|
||||||
///
|
|
||||||
/// Reads a single byte from the specified address
|
|
||||||
fn read(&self, offset: &u16) -> u8;
|
|
||||||
/// Program
|
|
||||||
///
|
|
||||||
/// Replaces all data in the ROM chip
|
|
||||||
fn program(new_data: &[u8; SIZE_32KB]) -> Box<Self>;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
use log::debug;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/// Tick
|
||||||
|
///
|
||||||
|
/// Master tick method to handle ticking all subsystems.
|
||||||
|
fn tick(&mut self);
|
||||||
|
|
||||||
|
/// tick_rom
|
||||||
|
///
|
||||||
|
/// Tick a ROM chip
|
||||||
|
///
|
||||||
|
/// returns (data_for_databus)
|
||||||
|
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, cs: bool, oe: bool) -> u8;
|
||||||
|
|
||||||
|
/// tick_via
|
||||||
|
///
|
||||||
|
/// Tick a VIA chip
|
||||||
|
///
|
||||||
|
/// 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);
|
||||||
|
|
||||||
|
/// tick_tod
|
||||||
|
///
|
||||||
|
/// Tick the TOD circutry
|
||||||
|
///
|
||||||
|
/// returns (time_irq)
|
||||||
|
fn tick_tod(&mut self) -> bool;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
use crate::traits::bus_device::BusDevice;
|
||||||
|
|
||||||
|
/// BusControlByte
|
||||||
|
///
|
||||||
|
/// Used to allow passing of a component specific set of
|
||||||
|
/// properties to be used with the universal tick
|
||||||
|
pub trait BusControlByte<T: BusDevice> {
|
||||||
|
fn from_byte(source: u8) -> T;
|
||||||
|
}
|
||||||
@@ -1,8 +1,31 @@
|
|||||||
|
|
||||||
pub trait BusDevice {
|
pub trait BusDevice {
|
||||||
fn address_bus(&self) -> u16;
|
fn min_offset(&self) -> u16;
|
||||||
|
fn max_offset(&self) -> u16;
|
||||||
fn data_bus(&self) -> u8;
|
fn data_bus(&self) -> u8;
|
||||||
|
|
||||||
fn set_address_bus(&mut self, new_value: u16);
|
|
||||||
fn set_data_bus(&mut self, new_value: u8);
|
fn set_data_bus(&mut self, new_value: u8);
|
||||||
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
use crate::traits::bus_device::BusDevice;
|
||||||
|
use crate::traits::gpio_chip::GpioChip;
|
||||||
|
use crate::traits::timer_chip::TimerChip;
|
||||||
|
|
||||||
|
pub trait CiaChip: BusDevice + GpioChip + TimerChip {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
pub enum GpioChipPorts {
|
||||||
|
PORT_A,
|
||||||
|
PORT_B
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GpioChip {
|
||||||
|
fn set_port(&mut self, new_a_value: u8, port: GpioChipPorts);
|
||||||
|
fn set_ddr(&mut self, new_ddra_value: u8, port: GpioChipPorts);
|
||||||
|
fn get_port(&self, port: GpioChipPorts) -> u8;
|
||||||
|
fn get_ddr(&self, port: GpioChipPorts) -> u8;
|
||||||
|
fn get_in(&self, port: GpioChipPorts) -> u8;
|
||||||
|
fn get_out(&self, port: GpioChipPorts) -> u8;
|
||||||
|
fn update_ports(&mut self);
|
||||||
|
|
||||||
|
fn split_port(value: u8, ddr: u8) -> (u8, u8) {
|
||||||
|
let mut in_val = 0x00;
|
||||||
|
let mut out_val = 0x00;
|
||||||
|
|
||||||
|
for bit in 0..8 {
|
||||||
|
let mask = 1 << bit;
|
||||||
|
let is_output = (ddr & mask) != 0;
|
||||||
|
let is_set = (value & mask) != 0;
|
||||||
|
|
||||||
|
match (is_output, is_set) {
|
||||||
|
(true, true) => out_val |= mask,
|
||||||
|
(false, true) => in_val |= mask,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(in_val, out_val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::periph::mos6520::Mos6520;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_split() {
|
||||||
|
let params = vec![
|
||||||
|
(0xf0, 0xff, 0xf0, 0x0f),
|
||||||
|
(0x0f, 0xff, 0x0f, 0xf0),
|
||||||
|
(0xff, 0xff, 0xff, 0x00),
|
||||||
|
(0x00, 0xff, 0x00, 0xff),
|
||||||
|
(0x55, 0xff, 0x55, 0xaa)
|
||||||
|
];
|
||||||
|
|
||||||
|
for (ddr, port, output, input) in params {
|
||||||
|
|
||||||
|
let (calc_ina, calc_oua) = Mos6520::split_port(port, ddr);
|
||||||
|
|
||||||
|
assert_eq!(calc_oua, output);
|
||||||
|
assert_eq!(calc_ina, input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user