Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c4e1f233ae | |||
| 7ac8bd86ba | |||
| 8f6f9cb64d | |||
| b40c3c503f | |||
| d5efabdd36 | |||
| 7498489b03 | |||
| 2939e1cac5 |
@@ -1,5 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/mos6502.iml" filepath="$PROJECT_DIR$/.idea/mos6502.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="EMPTY_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/cli/src" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/core/src" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/macroquad/src" isTestSource="false" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
Generated
+2894
-217
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -3,7 +3,8 @@ members = [
|
|||||||
"core",
|
"core",
|
||||||
"cli",
|
"cli",
|
||||||
"macroquad",
|
"macroquad",
|
||||||
"beneater"
|
# "beneater"
|
||||||
|
"egui"
|
||||||
]
|
]
|
||||||
resolver="2"
|
resolver="2"
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ fn main() {
|
|||||||
|
|
||||||
let mut backplane = Backplane::new();
|
let mut backplane = Backplane::new();
|
||||||
|
|
||||||
|
for i in 0..12 {
|
||||||
|
backplane.tick();
|
||||||
|
}
|
||||||
|
|
||||||
//backplane.load_rom();
|
//backplane.load_rom();
|
||||||
println!("Backplane is live.");
|
println!("Backplane is live.");
|
||||||
|
|
||||||
@@ -16,7 +20,7 @@ fn main() {
|
|||||||
new_program[(OFFSET_RESET_VECTOR + 1 - SIZE_32KB as u16) as usize] = 0x60;
|
new_program[(OFFSET_RESET_VECTOR + 1 - SIZE_32KB as u16) as usize] = 0x60;
|
||||||
println!("Set offset in rom...");
|
println!("Set offset in rom...");
|
||||||
println!(
|
println!(
|
||||||
"VALUE AT OFFSET_RESET_VECTOR = 0x{:02x} ",
|
"VALUE AT OFFSET_RESET_VECTOR = 0x{:04x} ",
|
||||||
new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize]
|
new_program[(OFFSET_RESET_VECTOR - SIZE_32KB as u16) as usize]
|
||||||
);
|
);
|
||||||
// println!("{:?}", new_program);
|
// println!("{:?}", new_program);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
|
use crate::parts::mos6522_peripheral::Mos6522Peripheral;
|
||||||
use crate::parts::via6522::VIA6522;
|
use crate::parts::via6522::VIA6522;
|
||||||
use core::constants::constants_system::*;
|
use core::constants::constants_system::*;
|
||||||
use core::mos6502cpu::cpu::Mos6502Cpu;
|
use core::mos6502cpu::Mos6502Cpu;
|
||||||
use core::periph::at28c256::At28C256;
|
use core::periph::at28c256::At28C256;
|
||||||
use core::periph::rom_chip::RomChip;
|
use core::traits::rom_chip::RomChip;
|
||||||
use core::constants::constants_via6522::*;
|
use core::constants::constants_via6522::*;
|
||||||
|
|
||||||
/// Backplane
|
/// Backplane
|
||||||
@@ -19,7 +19,7 @@ pub struct Backplane {
|
|||||||
// pub for dev
|
// pub for dev
|
||||||
pub cpu: Mos6502Cpu,
|
pub cpu: Mos6502Cpu,
|
||||||
pub via: VIA6522,
|
pub via: VIA6522,
|
||||||
pub memory: Box<[u8; SIZE_32KB]>,
|
pub memory: Box<[u8]>,
|
||||||
pub rom: At28C256,
|
pub rom: At28C256,
|
||||||
data_bus: u8,
|
data_bus: u8,
|
||||||
address_bus: u16
|
address_bus: u16
|
||||||
@@ -38,7 +38,7 @@ impl Backplane {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_rom(&mut self, to_load: &[u8; SIZE_32KB]) {
|
pub fn load_rom(&mut self, to_load: &[u8; SIZE_32KB]) {
|
||||||
self.rom.program(to_load);
|
self.rom.program((*to_load).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_write_data() {
|
fn test_write_data() {
|
||||||
let mut lcd = HD44780::new();
|
let mut lcd = HD44780::new();
|
||||||
lcd.set_data_bus(0x41); // 'A'
|
lcd.set_data_bus(0x41); // 'A'
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_timer1_write_and_tick() {
|
fn test_timer1_write_and_tick() {
|
||||||
let mut via = VIA6522::new();
|
let mut via = VIA6522::new();
|
||||||
|
|
||||||
@@ -180,6 +181,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_timer2_write_and_tick() {
|
fn test_timer2_write_and_tick() {
|
||||||
let mut via = VIA6522::new();
|
let mut via = VIA6522::new();
|
||||||
via.t2_enabled = true;
|
via.t2_enabled = true;
|
||||||
@@ -194,6 +196,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_interrupt_enable_disable() {
|
fn test_interrupt_enable_disable() {
|
||||||
let mut via = VIA6522::new();
|
let mut via = VIA6522::new();
|
||||||
|
|
||||||
@@ -205,6 +208,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_clear_interrupt_flags() {
|
fn test_clear_interrupt_flags() {
|
||||||
let mut via = VIA6522::new();
|
let mut via = VIA6522::new();
|
||||||
via.ifr = 0xFF;
|
via.ifr = 0xFF;
|
||||||
|
|||||||
@@ -18,6 +18,4 @@ fn main() {
|
|||||||
for (op, bytes) in instructions {
|
for (op, bytes) in instructions {
|
||||||
assert_eq!(Instruction::decode(bytes), Some(op));
|
assert_eq!(Instruction::decode(bytes), Some(op));
|
||||||
}
|
}
|
||||||
// let instruction = Instruction::decode(&[0xea]);
|
|
||||||
// println!("NOP Decoded -> {:?}", instruction);
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
use core::computers::kim1::Kim1;
|
use core::computers::kim1::Kim1;
|
||||||
|
use core::constants::constants_system::*;
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Taxation is theft.");
|
println!("Taxation is theft.");
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ fn main() {
|
|||||||
kim.tick();
|
kim.tick();
|
||||||
num_ticks += 1;
|
num_ticks += 1;
|
||||||
|
|
||||||
if num_ticks == 11 {
|
if num_ticks == MOS6502_RESET_CYCLE_COUNT {
|
||||||
println!("Got our 11 ticks. time to hotwire this pc.");
|
println!("Got our 11 ticks. time to hotwire this pc.");
|
||||||
kim.running = true;
|
kim.running = true;
|
||||||
kim.dump();
|
kim.dump();
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use core::computers::ram_rom::RamRomComputer;
|
||||||
|
use core::traits::backplane::Backplane;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -18,4 +20,29 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let mut computer = RamRomComputer::new();
|
||||||
|
|
||||||
|
// Read byte from ROM 0x4000
|
||||||
|
println!("-- ");
|
||||||
|
computer.set_read_mode(true);
|
||||||
|
computer.set_address_bus(0x4020);
|
||||||
|
computer.tick();
|
||||||
|
println!("-- ");
|
||||||
|
// Data Bus contains value from ROM
|
||||||
|
|
||||||
|
let read_from_rom = computer.data_bus();
|
||||||
|
// Write byte to RAM 0x0000
|
||||||
|
computer.set_read_mode(false);
|
||||||
|
computer.set_address_bus(0x0001);
|
||||||
|
computer.tick();
|
||||||
|
println!("-- ");
|
||||||
|
// Read byte from RAM
|
||||||
|
computer.set_read_mode(true);
|
||||||
|
computer.set_address_bus(0x0001);
|
||||||
|
computer.tick();
|
||||||
|
println!("-- ");
|
||||||
|
let read_from_ram = computer.data_bus();
|
||||||
|
|
||||||
|
assert_eq!(read_from_rom, read_from_ram);
|
||||||
|
println!("Test passed. We read the same from ROM as we did from RAM - {} == {}", read_from_rom, read_from_ram);
|
||||||
}
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
use std::fs;
|
|
||||||
use clap::Parser;
|
|
||||||
use core::computers::rom_only::backplane::RomOnlyComputer;
|
|
||||||
use core::periph::backplane::Backplane;
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
|
||||||
struct CliOptions {
|
|
||||||
offset: u16,
|
|
||||||
bytes: u16,
|
|
||||||
filename: String
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
println!("Taxation is theft");
|
|
||||||
|
|
||||||
// let opts = CliOptions::parse();
|
|
||||||
let path = "/home/tmerritt/Projects/mos6502/resources/test/periph/at28c256/checksum.bin";
|
|
||||||
let bytes = match fs::read(path) {
|
|
||||||
Ok(bytes) => {
|
|
||||||
println!("Read {} bytes.", bytes.len());
|
|
||||||
bytes
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("FAIL to read rom.");
|
|
||||||
panic!("No rom no run.");
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut rom_only = RomOnlyComputer::program((&bytes[..]).to_vec());
|
|
||||||
|
|
||||||
rom_only.set_read_mode(true);
|
|
||||||
rom_only.set_address_bus(0x05);
|
|
||||||
rom_only.tick();
|
|
||||||
|
|
||||||
println!("COMPUTER: Read {:02x} from ROM", rom_only.data_bus()) ;
|
|
||||||
println!("COMPUTER: Read {:04x} from Address Bus", rom_only.address_bus());
|
|
||||||
|
|
||||||
println!("----");
|
|
||||||
rom_only.set_read_mode(true);
|
|
||||||
rom_only.set_address_bus(0x07);
|
|
||||||
rom_only.tick();
|
|
||||||
|
|
||||||
println!("COMPUTER: Read {:02x} from ROM", rom_only.data_bus()) ;
|
|
||||||
println!("COMPUTER: Read {:04x} from Address Bus", rom_only.address_bus());
|
|
||||||
println!("----");
|
|
||||||
}
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
use crate::mos6502cpu::cpu::Mos6502Cpu;
|
|
||||||
use crate::periph::ram_chip::RamChip;
|
|
||||||
|
|
||||||
/// BackplaneBuilder
|
|
||||||
///
|
|
||||||
/// Builds a Backplane for a 6502 Emulated PC
|
|
||||||
struct BackplaneBuilder {
|
|
||||||
cpu: Mos6502Cpu,
|
|
||||||
// ram_modules: Vec<dyn RamChip>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BackplaneBuilder {
|
|
||||||
pub fn add_cpu(mut self, new_cpu: Mos6502Cpu) -> Self {
|
|
||||||
self.cpu = new_cpu;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_ram(mut self, new_ram: impl RamChip) -> Self {
|
|
||||||
// self.ram_modules.push(new_ram);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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 crate::mos6502cpu::Mos6502Cpu;
|
||||||
use std::path::Path;
|
|
||||||
use crate::constants::constants_system::SIZE_1KB;
|
|
||||||
use crate::mos6502cpu::cpu::Mos6502Cpu;
|
|
||||||
use crate::periph::at28c256::At28C256;
|
|
||||||
use crate::periph::hm62256::Hm62256;
|
use crate::periph::hm62256::Hm62256;
|
||||||
use crate::periph::kim1_keypad::Kim1Keypad;
|
use crate::periph::kim1_keypad::Kim1Keypad;
|
||||||
use crate::periph::mos6522::mos6522::Mos6522;
|
use crate::periph::mos6530::Mos6530;
|
||||||
use crate::periph::mos6530::mos6530::Mos6530;
|
|
||||||
|
|
||||||
/// Represents a KIM-1
|
/// Represents a KIM-1
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -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,31 +17,55 @@ impl Backplane for RamRomComputer {
|
|||||||
self.read_mode
|
self.read_mode
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
fn set_read_mode(&mut self, new_mode: bool) {
|
fn set_read_mode(&mut self, new_mode: bool) {
|
||||||
self.read_mode = new_mode;
|
self.read_mode = new_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_data_bus(&mut self, new_value: u8) {
|
||||||
|
self.data_bus = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
fn set_address_bus(&mut self, new_value: u16) {
|
fn set_address_bus(&mut self, new_value: u16) {
|
||||||
self.address_bus = new_value;
|
self.address_bus = new_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_data_bus(&mut self, new_value: u8) {
|
fn tick(&mut self) {
|
||||||
self.data_bus = new_value;
|
println!("Preparing to tick the backplane. - ${:04x} ${:02x} {}", self.address_bus, self.data_bus, self.read_mode);
|
||||||
|
|
||||||
|
// who are we talking to?
|
||||||
|
match self.address_bus {
|
||||||
|
0x0000..=0x3fff => {
|
||||||
|
// RAM
|
||||||
|
println!("ADDRESSING RAM");
|
||||||
|
let (ram_address_bus, ram_data_bus) = self.ram.tick(self.address_bus, self.data_bus, self.read_mode, true);
|
||||||
|
if self.read_mode {
|
||||||
|
self.data_bus = ram_data_bus;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
0x4000..=0x7fff => {
|
||||||
|
// ROM
|
||||||
|
println!("ADDRESSING ROM");
|
||||||
|
let rom_data_bus = self.rom.signal_tick(self.address_bus, self.data_bus, true, true, true);
|
||||||
|
self.data_bus = rom_data_bus;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Out of range
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RamRomComputer {
|
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
|
||||||
pub fn new() -> RamRomComputer {
|
debug!("Ticking ram with A${address:04x} D${data:02x} CS:{cs} OE:{oe} WE:{we}");
|
||||||
RamRomComputer {
|
0
|
||||||
rom: At28C256::default(),
|
}
|
||||||
ram: Hm62256::default(),
|
|
||||||
data_bus: 0x00,
|
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
|
||||||
address_bus: 0x0000,
|
debug!("Ticking rom with A${address:04x} CS:{cs} OE:{oe}");
|
||||||
/// is the CPU reading from the 'other' device?
|
0
|
||||||
read_mode: true
|
}
|
||||||
}
|
|
||||||
|
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
|
||||||
|
debug!("Ticking Via with A${address:04x} D${data:02x} cs0:{cs0} cs1:{cs1} rw:{rw} rs0:{rs0} rs1:{rs1}");
|
||||||
|
(0, false, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1 +1,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,59 +1,45 @@
|
|||||||
use crate::constants::constants_system::{SIZE_32KB, SIZE_64KB};
|
use log::debug;
|
||||||
use crate::periph::at28c256::At28C256;
|
use crate::computers::rom_only::RomOnlyComputer;
|
||||||
use crate::periph::backplane::Backplane;
|
use crate::traits::backplane::Backplane;
|
||||||
use crate::periph::rom_chip::RomChip;
|
|
||||||
pub struct RomOnlyComputer {
|
|
||||||
rom: At28C256,
|
|
||||||
data_bus: u8,
|
|
||||||
address_bus: u16,
|
|
||||||
read_mode: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Backplane for RomOnlyComputer {
|
impl Backplane for RomOnlyComputer {
|
||||||
fn data_bus(&self) -> u8 { self.data_bus }
|
fn data_bus(&self) -> u8 { self.data_bus }
|
||||||
fn address_bus(&self) -> u16 { self.address_bus }
|
fn address_bus(&self) -> u16 { self.address_bus }
|
||||||
fn read_mode(&self) -> bool { self.read_mode }
|
fn read_mode(&self) -> bool { self.read_mode }
|
||||||
|
|
||||||
fn set_read_mode(&mut self, new_mode: bool) {
|
fn set_read_mode(&mut self, new_mode: bool) {
|
||||||
self.read_mode = new_mode
|
self.read_mode = new_mode
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_data_bus(&mut self, new_value: u8) {
|
fn set_data_bus(&mut self, new_value: u8) {
|
||||||
self.data_bus = new_value
|
self.data_bus = new_value
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_address_bus(&mut self, new_value: u16) {
|
fn set_address_bus(&mut self, new_value: u16) {
|
||||||
self.address_bus = new_value
|
self.address_bus = new_value
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self) {
|
fn tick(&mut self) {
|
||||||
println!("COMPUTER: Preparing to tick.");
|
// println!("COMPUTER: Preparing to tick.");
|
||||||
|
|
||||||
// do are we being addressed?
|
// do are we being addressed?
|
||||||
println!("COMPUTER: BUSSES PRE: 0x{:04x} 0x{:02x} {}", self.address_bus, self.data_bus, self.read_mode);
|
// println!("COMPUTER: BUSSES PRE: 0x{:04x} 0x{:02x} {}", self.address_bus, self.data_bus, self.read_mode);
|
||||||
let (new_addr, new_data) = self.rom.tick(self.address_bus, self.data_bus, self.read_mode);
|
let new_data = self.rom.signal_tick(self.address_bus, self.data_bus, true, true, true);
|
||||||
self.set_address_bus(new_addr);
|
// tick(self.address_bus, self.data_bus, self.read_mode);
|
||||||
|
self.set_address_bus(self.address_bus);
|
||||||
self.set_data_bus(new_data);
|
self.set_data_bus(new_data);
|
||||||
println!("COMPUTER: BUSSES POST: 0x{:04x} 0x{:02x} {}", self.address_bus, self.data_bus, self.read_mode);
|
// println!("COMPUTER: BUSSES POST: 0x{:04x} 0x{:02x} {}", self.address_bus, self.data_bus, self.read_mode);
|
||||||
println!("COMPUTER: Done ticking.");
|
// println!("COMPUTER: Done ticking.");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RomOnlyComputer {
|
fn tick_ram(&mut self, address: u16, data: u8, cs: bool, oe: bool, we: bool) -> u8 {
|
||||||
pub fn new() -> RomOnlyComputer {
|
debug!("This system has no ram. ROM only.");
|
||||||
let mut working = vec![0x00u8; SIZE_32KB];
|
0x00
|
||||||
for index in 0..SIZE_32KB {
|
|
||||||
working[index] = index as u8;
|
|
||||||
}
|
|
||||||
RomOnlyComputer::program(working)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn program(rom: Vec<u8>) -> RomOnlyComputer {
|
fn tick_rom(&mut self, address: u16, cs: bool, oe: bool) -> u8 {
|
||||||
RomOnlyComputer {
|
let data = self.rom.signal_tick(address, self.data_bus, cs, oe, true);
|
||||||
rom: At28C256::new(0x000, 0x3fff, rom),
|
data
|
||||||
address_bus: 0x0000,
|
}
|
||||||
data_bus: 0x00,
|
|
||||||
read_mode: true,
|
fn tick_via(&mut self, address: u16, data: u8, cs0: bool, cs1: bool, rw: bool, rs0: bool, rs1: bool) -> (u8, bool, bool) {
|
||||||
}
|
debug!("This system has no VIA controllers. ROM only");
|
||||||
|
(0,false,false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
use crate::computers::rom_only::RomOnlyComputer;
|
||||||
|
|
||||||
|
impl RomOnlyComputer {
|
||||||
|
pub fn debug_memory(&self, start_offset: u16, end_offset: u16) -> Vec<u8> {
|
||||||
|
let mut data = vec![];
|
||||||
|
let size = end_offset - start_offset;
|
||||||
|
for index in 0..size {
|
||||||
|
println!("Index {index} for {}", index + start_offset);
|
||||||
|
}
|
||||||
|
data
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,29 @@
|
|||||||
|
use crate::periph::at28c256::At28C256;
|
||||||
|
use crate::traits::backplane::Backplane;
|
||||||
|
|
||||||
pub mod backplane;
|
pub mod backplane;
|
||||||
|
pub mod new;
|
||||||
|
pub mod program;
|
||||||
|
pub mod debug_memory;
|
||||||
|
mod rom_chunks;
|
||||||
|
|
||||||
|
pub struct RomOnlyComputer {
|
||||||
|
pub rom: At28C256,
|
||||||
|
pub data_bus: u8,
|
||||||
|
pub address_bus: u16,
|
||||||
|
pub read_mode: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RomOnlyComputer {
|
||||||
|
pub fn tick2(&mut self, address: u16, control: u8, data: u8) -> (u8) {
|
||||||
|
// tick the parts...
|
||||||
|
println!("WIDETICK: A:${address:04x} D:${data:02x} C:b{control:08b}");
|
||||||
|
self.address_bus = address;
|
||||||
|
self.data_bus = data;
|
||||||
|
|
||||||
|
let new_data = self.rom.signal_tick(self.address_bus, self.data_bus, true, true, true);
|
||||||
|
println!("\nNew Data : {new_data:02x}");
|
||||||
|
self.set_data_bus(new_data);
|
||||||
|
new_data
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
use crate::computers::rom_only::RomOnlyComputer;
|
||||||
|
use crate::constants::constants_system::SIZE_32KB;
|
||||||
|
|
||||||
|
impl RomOnlyComputer {
|
||||||
|
pub fn new() -> RomOnlyComputer {
|
||||||
|
let mut working = vec![0x00u8; SIZE_32KB];
|
||||||
|
for index in 0..SIZE_32KB {
|
||||||
|
working[index] = index as u8;
|
||||||
|
}
|
||||||
|
RomOnlyComputer::program(working)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
use crate::computers::rom_only::RomOnlyComputer;
|
||||||
|
use crate::constants::constants_system::SIZE_32KB;
|
||||||
|
use crate::periph::at28c256::At28C256;
|
||||||
|
|
||||||
|
impl RomOnlyComputer {
|
||||||
|
pub fn program(rom: Vec<u8>) -> RomOnlyComputer {
|
||||||
|
RomOnlyComputer {
|
||||||
|
rom: At28C256::new(0x000, 0x3fff, rom),
|
||||||
|
address_bus: 0x0000,
|
||||||
|
data_bus: 0x00,
|
||||||
|
read_mode: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
use std::slice::Chunks;
|
||||||
|
use crate::computers::rom_only::RomOnlyComputer;
|
||||||
|
|
||||||
|
impl RomOnlyComputer {
|
||||||
|
pub fn rom_chunks(&self, size: usize) -> Chunks<u8> {
|
||||||
|
self.rom.chunks(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Computer at
|
||||||
|
https://www.youtube.com/watch?v=s3t2QMukBRs
|
||||||
|
https://github.com/AndersBNielsen/6507SBC
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
use crate::constants::constants_system::SIZE_32KB;
|
||||||
|
use crate::mos6502cpu::Mos6502Cpu;
|
||||||
|
use crate::periph::at28c256::At28C256;
|
||||||
|
use crate::periph::mos6532::Mos6532;
|
||||||
|
|
||||||
|
pub struct SingleBreadboard {
|
||||||
|
pub cpu: Mos6502Cpu,
|
||||||
|
pub ram: At28C256,
|
||||||
|
pub via: Mos6532
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SingleBreadboard {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
SingleBreadboard {
|
||||||
|
cpu: Mos6502Cpu::default(),
|
||||||
|
ram: At28C256::new(0xf000, 0xffff, vec![0x00; SIZE_32KB]),
|
||||||
|
via: Mos6532::new(0x0000, 0x0080)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
@@ -9,3 +9,8 @@ pub const OFFSET_RESET_VECTOR: u16 = 0xfffc;
|
|||||||
pub const OFFSET_RESET_VECTORS: usize = 0xffff;
|
pub const OFFSET_RESET_VECTORS: usize = 0xffff;
|
||||||
pub const OFFSET_INT_VECTOR: u16 = 0xfffe;
|
pub const OFFSET_INT_VECTOR: u16 = 0xfffe;
|
||||||
pub const OFFSET_INT_VECTORS: usize = 0xfffe;
|
pub const OFFSET_INT_VECTORS: usize = 0xfffe;
|
||||||
|
|
||||||
|
// 7 cycles for internal reset
|
||||||
|
// 6 to read the vectors from RAM
|
||||||
|
pub const MOS6502_RESET_CYCLE_COUNT: u16 = 8;
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
@@ -215,7 +187,7 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
|
|||||||
|
|
||||||
table[ISA_OP_BCC as usize] = Some(OpInfo {
|
table[ISA_OP_BCC as usize] = Some(OpInfo {
|
||||||
operation: BCC,
|
operation: BCC,
|
||||||
mode: AddressMode::Implied,
|
mode: AddressMode::Immediate,
|
||||||
length: 2,
|
length: 2,
|
||||||
cycles: 2,
|
cycles: 2,
|
||||||
format_prefix: "BCC $",
|
format_prefix: "BCC $",
|
||||||
@@ -1307,49 +1279,3 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
|
|||||||
|
|
||||||
table
|
table
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
#[test]
|
|
||||||
fn test_instruction_table_completeness() {
|
|
||||||
use INSTRUCTION_TABLE; // Adjust to your actual path
|
|
||||||
|
|
||||||
let mut defined_count = 0;
|
|
||||||
let mut defined_opcodes = vec![];
|
|
||||||
|
|
||||||
for (i, entry) in INSTRUCTION_TABLE.iter().enumerate() {
|
|
||||||
if let Some(info) = entry {
|
|
||||||
defined_count += 1;
|
|
||||||
defined_opcodes.push(i);
|
|
||||||
// Optional: sanity check
|
|
||||||
assert!(
|
|
||||||
info.length > 0 && info.cycles > 0,
|
|
||||||
"Invalid OpInfo at opcode {:#04x?}",
|
|
||||||
i
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Defined opcodes: {}", defined_count);
|
|
||||||
for i in 0..256 {
|
|
||||||
if defined_opcodes.contains(&i) {
|
|
||||||
print!("{:02x} ", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!("\nMissing opcodes:");
|
|
||||||
for i in 0..256 {
|
|
||||||
if !defined_opcodes.contains(&i) {
|
|
||||||
print!("{:02X} ", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!();
|
|
||||||
|
|
||||||
// The standard 6502 has 151 documented opcodes
|
|
||||||
assert_eq!(
|
|
||||||
defined_count, 151,
|
|
||||||
"Expected 151 opcodes, found {}",
|
|
||||||
defined_count
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+1
-1
@@ -11,4 +11,4 @@ pub mod op_info;
|
|||||||
pub mod operand;
|
pub mod operand;
|
||||||
pub mod operation;
|
pub mod operation;
|
||||||
pub mod periph;
|
pub mod periph;
|
||||||
mod backplane;
|
pub mod traits;
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
use crate::mos6502cpu::Mos6502Cpu;
|
||||||
|
use crate::traits::bus_device::BusDevice;
|
||||||
|
|
||||||
|
impl BusDevice for Mos6502Cpu {
|
||||||
|
fn min_offset(&self) -> u16 { 0 }
|
||||||
|
|
||||||
|
fn max_offset(&self) -> u16 {
|
||||||
|
0x7fff
|
||||||
|
}
|
||||||
|
|
||||||
|
fn address_bus(&self) -> u16 {
|
||||||
|
self.address_bus
|
||||||
|
}
|
||||||
|
|
||||||
|
fn data_bus(&self) -> u8 {
|
||||||
|
self.data_bus
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_address_bus(&mut self, new_value: u16) {
|
||||||
|
self.address_bus = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_data_bus(&mut self, new_value: u8) {
|
||||||
|
self.data_bus = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+26
-114
@@ -9,93 +9,17 @@ use crate::op_info::OpInfo;
|
|||||||
use crate::operand::Operand;
|
use crate::operand::Operand;
|
||||||
use crate::operation::Operation;
|
use crate::operation::Operation;
|
||||||
use log::trace;
|
use log::trace;
|
||||||
|
use crate::mos6502cpu::Mos6502Cpu;
|
||||||
use crate::mos6502cpu::tick_stages::Mos6502TickStates;
|
use crate::mos6502cpu::tick_stages::Mos6502TickStates;
|
||||||
use crate::mos6502cpu::tick_stages::Mos6502TickStates::*;
|
use crate::mos6502cpu::tick_stages::Mos6502TickStates::*;
|
||||||
|
|
||||||
pub struct Mos6502Cpu {
|
enum Mos6502Registers {
|
||||||
pub(crate) memory: [u8; SIZE_64KB],
|
A,
|
||||||
/// accumulator
|
X,
|
||||||
pub(crate) a: u8,
|
Y
|
||||||
/// x register
|
|
||||||
pub(crate) x: u8,
|
|
||||||
/// y register
|
|
||||||
pub(crate) y: u8,
|
|
||||||
/// cpu flags
|
|
||||||
pub(crate) flags: Mos6502Flags,
|
|
||||||
/// program counter
|
|
||||||
pub pc: u16,
|
|
||||||
/// stack offset
|
|
||||||
pub(crate) s: u8,
|
|
||||||
pub microcode_step: u8,
|
|
||||||
pub(crate) address_bus: u16,
|
|
||||||
pub(crate) data_bus: u8,
|
|
||||||
pub(crate) ir: Instruction, // Instruction Register
|
|
||||||
pub(crate) oi: OpInfo,
|
|
||||||
pub(crate) has_reset: bool,
|
|
||||||
pub(crate) iv: u16, // Interrupt Vector
|
|
||||||
pub(crate) cycle_carry: u16, // Value to hold between microsteps
|
|
||||||
pub(crate) ir_bytes: [u8; 4],
|
|
||||||
/// CPU Read signal
|
|
||||||
pub read_signal: bool,
|
|
||||||
pub(crate) reset_vector: u16,
|
|
||||||
pub(crate) int_vector: u16,
|
|
||||||
pub(crate) nmi_vector: u16,
|
|
||||||
pub tick_stage: Mos6502TickStates
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mos6502Cpu {
|
impl Mos6502Cpu {
|
||||||
/// set_data_bus
|
|
||||||
///
|
|
||||||
/// Sets data on the data bus.
|
|
||||||
/// Used when CPU is in "R" mode
|
|
||||||
pub fn set_data_bus(&mut self, to_set: u8) {
|
|
||||||
self.data_bus = to_set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Mos6502Cpu {
|
|
||||||
fn default() -> Self {
|
|
||||||
let mut working = Mos6502Cpu {
|
|
||||||
memory: [0x00; SIZE_64KB],
|
|
||||||
a: 0x00,
|
|
||||||
x: 0x00,
|
|
||||||
y: 0x00,
|
|
||||||
flags: Default::default(),
|
|
||||||
pc: 0xfffd,
|
|
||||||
s: 0x00,
|
|
||||||
microcode_step: 0x00,
|
|
||||||
address_bus: 0x00,
|
|
||||||
data_bus: 0x00,
|
|
||||||
ir: Instruction {
|
|
||||||
op: Operation::NOP,
|
|
||||||
mode: AddressMode::Implied,
|
|
||||||
operand: Operand::None,
|
|
||||||
},
|
|
||||||
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].clone().unwrap(),
|
|
||||||
has_reset: false,
|
|
||||||
iv: 0xfffe,
|
|
||||||
cycle_carry: 0x0000,
|
|
||||||
ir_bytes: [0x00; 4],
|
|
||||||
read_signal: true,
|
|
||||||
reset_vector: 0x0000,
|
|
||||||
int_vector: 0x0000,
|
|
||||||
nmi_vector: 0x0000,
|
|
||||||
tick_stage: LoadingInstruction
|
|
||||||
};
|
|
||||||
working.reset_cpu();
|
|
||||||
working
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Mos6502Cpu {
|
|
||||||
pub fn address_bus(&self) -> u16 {
|
|
||||||
self.address_bus
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn data_bus(&self) -> u8 {
|
|
||||||
self.data_bus
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// fn read_word(&self, offset: &u16) -> u16 {
|
// fn read_word(&self, offset: &u16) -> u16 {
|
||||||
// println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1);
|
// println!("READING OFFSET 0x{offset:04x} and 0x{:04x}", offset + 1);
|
||||||
@@ -108,6 +32,22 @@ impl Mos6502Cpu {
|
|||||||
// result
|
// result
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
pub fn peek_register(&self, register_to_peek: Mos6502Registers) -> u8 {
|
||||||
|
match register_to_peek {
|
||||||
|
Mos6502Registers::A => self.a,
|
||||||
|
Mos6502Registers::X => self.x,
|
||||||
|
Mos6502Registers::Y => self.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn poke_register(&mut self, register_to_poke: Mos6502Registers, new_value: u8) {
|
||||||
|
match register_to_poke {
|
||||||
|
Mos6502Registers::A => self.a = new_value,
|
||||||
|
Mos6502Registers::X => self.x = new_value,
|
||||||
|
Mos6502Registers::Y => self.y = new_value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn peek_flag(&self, flag_to_read: Mos6502Flag) -> bool {
|
pub fn peek_flag(&self, flag_to_read: Mos6502Flag) -> bool {
|
||||||
self.flags.flag(flag_to_read)
|
self.flags.flag(flag_to_read)
|
||||||
}
|
}
|
||||||
@@ -119,42 +59,15 @@ impl Mos6502Cpu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek(&self, offset: u16) -> u8 {
|
pub fn peek_memory(&self, offset: u16) -> u8 {
|
||||||
self.memory[offset as usize]
|
self.memory[offset as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poke(&mut self, offset: u16, value: u8) {
|
pub fn poke_memory(&mut self, offset: u16, value: u8) {
|
||||||
println!("Setting memory at {offset:04x} to {value:02x}");
|
println!("Setting memory at {offset:04x} to {value:02x}");
|
||||||
self.memory[offset as usize] = value
|
self.memory[offset as usize] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek_a(&self) -> u8 {
|
|
||||||
println!("Readding register A => 0x{:02x}", self.a);
|
|
||||||
self.a
|
|
||||||
}
|
|
||||||
pub fn poke_a(&mut self, new_a: u8) {
|
|
||||||
println!("Updating register A from [{}] to [{}]", self.a, new_a);
|
|
||||||
self.a = new_a;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn peek_x(&self) -> u8 {
|
|
||||||
println!("Readding register X => 0x{}", self.x);
|
|
||||||
self.x
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poke_x(&mut self, new_x: u8) {
|
|
||||||
println!("Updating register X from [{}] to [{}]", self.x, new_x);
|
|
||||||
self.x = new_x
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn peek_y(&self) -> u8 {
|
|
||||||
self.y
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poke_y(&mut self, new_y: u8) {
|
|
||||||
self.y = new_y
|
|
||||||
}
|
|
||||||
|
|
||||||
fn advance_pc(&mut self, how_far: u16) {
|
fn advance_pc(&mut self, how_far: u16) {
|
||||||
self.pc += how_far;
|
self.pc += how_far;
|
||||||
}
|
}
|
||||||
@@ -207,7 +120,6 @@ impl Mos6502Cpu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if self.microcode_step == 0 {
|
if self.microcode_step == 0 {
|
||||||
println!("OUT OF MICROSTEPS. Decoding the next instruction");
|
println!("OUT OF MICROSTEPS. Decoding the next instruction");
|
||||||
let offset = self.pc as usize;
|
let offset = self.pc as usize;
|
||||||
@@ -321,7 +233,7 @@ impl Mos6502Cpu {
|
|||||||
Operation::DEX => {
|
Operation::DEX => {
|
||||||
if self.microcode_step == 1 {
|
if self.microcode_step == 1 {
|
||||||
let (new_x, new_carry) = self.x.overflowing_sub(1);
|
let (new_x, new_carry) = self.x.overflowing_sub(1);
|
||||||
self.poke_x(new_x);
|
self.poke_register(Mos6502Registers::X, new_x);
|
||||||
self.poke_flag(Carry, new_carry);
|
self.poke_flag(Carry, new_carry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -335,7 +247,7 @@ impl Mos6502Cpu {
|
|||||||
Operation::INX => {
|
Operation::INX => {
|
||||||
if self.microcode_step == 1 {
|
if self.microcode_step == 1 {
|
||||||
let (new_x, new_carry) = self.x.overflowing_add(1);
|
let (new_x, new_carry) = self.x.overflowing_add(1);
|
||||||
self.poke_x(new_x);
|
self.poke_register(Mos6502Registers::X, new_x);
|
||||||
self.poke_flag(Carry, new_carry);
|
self.poke_flag(Carry, new_carry);
|
||||||
self.address_bus = self.pc;
|
self.address_bus = self.pc;
|
||||||
self.data_bus = 0x00;
|
self.data_bus = 0x00;
|
||||||
@@ -344,7 +256,7 @@ impl Mos6502Cpu {
|
|||||||
Operation::INY => {
|
Operation::INY => {
|
||||||
if self.microcode_step == 1 {
|
if self.microcode_step == 1 {
|
||||||
let (new_y, new_carry) = self.y.overflowing_add(1);
|
let (new_y, new_carry) = self.y.overflowing_add(1);
|
||||||
self.poke_y(new_y);
|
self.poke_register(Mos6502Registers::Y, new_y);
|
||||||
self.poke_flag(Carry, new_carry);
|
self.poke_flag(Carry, new_carry);
|
||||||
self.address_bus = self.pc;
|
self.address_bus = self.pc;
|
||||||
self.data_bus = 0x00;
|
self.data_bus = 0x00;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::mos6502cpu::cpu::Mos6502Cpu;
|
use crate::mos6502cpu::Mos6502Cpu;
|
||||||
|
|
||||||
impl Mos6502Cpu {
|
impl Mos6502Cpu {
|
||||||
/// dump_data
|
/// dump_data
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
use crate::address_mode::AddressMode;
|
||||||
|
use crate::constants::constants_isa_op::ISA_OP_NOP;
|
||||||
|
use crate::constants::constants_system::SIZE_64KB;
|
||||||
|
use crate::instruction::Instruction;
|
||||||
|
use crate::instruction_table::INSTRUCTION_TABLE;
|
||||||
|
use crate::mos6502cpu::Mos6502Cpu;
|
||||||
|
use crate::mos6502cpu::tick_stages::Mos6502TickStates::LoadingInstruction;
|
||||||
|
use crate::operand::Operand;
|
||||||
|
use crate::operation::Operation;
|
||||||
|
|
||||||
|
impl Default for Mos6502Cpu {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut working = Mos6502Cpu {
|
||||||
|
memory: [0x00; SIZE_64KB],
|
||||||
|
a: 0x00,
|
||||||
|
x: 0x00,
|
||||||
|
y: 0x00,
|
||||||
|
flags: Default::default(),
|
||||||
|
pc: 0xfffd,
|
||||||
|
s: 0x00,
|
||||||
|
microcode_step: 0x00,
|
||||||
|
address_bus: 0x00,
|
||||||
|
data_bus: 0x00,
|
||||||
|
ir: Instruction {
|
||||||
|
op: Operation::NOP,
|
||||||
|
mode: AddressMode::Implied,
|
||||||
|
operand: Operand::None,
|
||||||
|
},
|
||||||
|
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].clone().unwrap(),
|
||||||
|
has_reset: false,
|
||||||
|
iv: 0xfffe,
|
||||||
|
cycle_carry: 0x0000,
|
||||||
|
ir_bytes: [0x00; 4],
|
||||||
|
read_signal: true,
|
||||||
|
reset_vector: 0x0000,
|
||||||
|
int_vector: 0x0000,
|
||||||
|
nmi_vector: 0x0000,
|
||||||
|
tick_stage: LoadingInstruction
|
||||||
|
};
|
||||||
|
working.reset_cpu();
|
||||||
|
working
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,44 @@
|
|||||||
|
use crate::constants::constants_system::SIZE_64KB;
|
||||||
|
use crate::instruction::Instruction;
|
||||||
|
use crate::mos6502cpu::tick_stages::Mos6502TickStates;
|
||||||
|
use crate::mos6502flags::Mos6502Flags;
|
||||||
|
use crate::op_info::OpInfo;
|
||||||
|
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
pub mod new;
|
pub mod new;
|
||||||
|
|
||||||
pub mod tick2;
|
pub mod tick2;
|
||||||
pub mod dbg;
|
pub mod dbg;
|
||||||
pub mod tick_stages;
|
pub mod tick_stages;
|
||||||
|
pub mod default;
|
||||||
|
pub mod bus_device;
|
||||||
|
|
||||||
|
pub struct Mos6502Cpu {
|
||||||
|
pub(crate) memory: [u8; SIZE_64KB],
|
||||||
|
/// accumulator
|
||||||
|
pub(crate) a: u8,
|
||||||
|
/// x register
|
||||||
|
pub(crate) x: u8,
|
||||||
|
/// y register
|
||||||
|
pub(crate) y: u8,
|
||||||
|
/// cpu flags
|
||||||
|
pub(crate) flags: Mos6502Flags,
|
||||||
|
/// program counter
|
||||||
|
pub pc: u16,
|
||||||
|
/// stack offset
|
||||||
|
pub(crate) s: u8,
|
||||||
|
pub microcode_step: u8,
|
||||||
|
pub(crate) address_bus: u16,
|
||||||
|
pub(crate) data_bus: u8,
|
||||||
|
pub(crate) ir: Instruction, // Instruction Register
|
||||||
|
pub(crate) oi: OpInfo,
|
||||||
|
pub(crate) has_reset: bool,
|
||||||
|
pub(crate) iv: u16, // Interrupt Vector
|
||||||
|
pub(crate) cycle_carry: u16, // Value to hold between microsteps
|
||||||
|
pub(crate) ir_bytes: [u8; 4],
|
||||||
|
/// CPU Read signal
|
||||||
|
pub read_signal: bool,
|
||||||
|
pub(crate) reset_vector: u16,
|
||||||
|
pub(crate) int_vector: u16,
|
||||||
|
pub(crate) nmi_vector: u16,
|
||||||
|
pub tick_stage: Mos6502TickStates
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::constants::constants_system::{OFFSET_RESET_VECTOR, SIZE_64KB};
|
use crate::constants::constants_system::{MOS6502_RESET_CYCLE_COUNT, OFFSET_RESET_VECTOR, SIZE_64KB};
|
||||||
use crate::mos6502cpu::cpu::Mos6502Cpu;
|
use crate::mos6502cpu::Mos6502Cpu;
|
||||||
|
|
||||||
impl Mos6502Cpu {
|
impl Mos6502Cpu {
|
||||||
pub fn new() -> Mos6502Cpu {
|
pub fn new() -> Mos6502Cpu {
|
||||||
@@ -14,7 +14,7 @@ impl Mos6502Cpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reset_cpu(&mut self) {
|
pub(crate) fn reset_cpu(&mut self) {
|
||||||
self.microcode_step = 7 + 6;
|
self.microcode_step = MOS6502_RESET_CYCLE_COUNT as u8;
|
||||||
// self = &mut Mos6502Cpu::default();
|
// self = &mut Mos6502Cpu::default();
|
||||||
println!("Should tick 7 times, then 6 cycles to read the reset and int vectors.");
|
println!("Should tick 7 times, then 6 cycles to read the reset and int vectors.");
|
||||||
// read the value at 0xfffa 0xfffb for our NMI vector.
|
// read the value at 0xfffa 0xfffb for our NMI vector.
|
||||||
|
|||||||
@@ -1,32 +1,17 @@
|
|||||||
use crate::constants::constants_system::{OFFSET_INT_VECTOR, OFFSET_RESET_VECTOR};
|
use crate::constants::constants_system::{OFFSET_INT_VECTOR, OFFSET_RESET_VECTOR};
|
||||||
use crate::mos6502cpu::cpu::Mos6502Cpu;
|
use crate::mos6502cpu::Mos6502Cpu;
|
||||||
|
|
||||||
|
|
||||||
|
enum Mos6502ResetSteps {
|
||||||
|
/// there are 6 of these
|
||||||
|
DummyRead(u8),
|
||||||
|
ReadRstVectorLow,
|
||||||
|
ReadRstVectorHigh,
|
||||||
|
ReadPcLow,
|
||||||
|
ReadPcHigh
|
||||||
|
}
|
||||||
|
|
||||||
impl Mos6502Cpu {
|
impl Mos6502Cpu {
|
||||||
/// AccurateTick
|
fn reset_step(&mut self, address_bus: u16, data_bus: u8, read: bool) -> (u16, u8, bool) {
|
||||||
///
|
|
||||||
/// In: address_bus > Address of data operationm
|
|
||||||
/// data_bus > Data read or written
|
|
||||||
/// State:
|
|
||||||
/// read_bus > Flag for if cpu is reading or writing the data bus
|
|
||||||
/// cycle_step > Index for what step of the Decode->Load->Execute cycle we are in
|
|
||||||
/// Out: address_bus > address for operation
|
|
||||||
/// data_bus > data for the operation
|
|
||||||
/// read_bus > lets rest of the computer know if the CPU is reading from the address
|
|
||||||
/// provided or if we are writing to the address
|
|
||||||
pub fn tick2(&mut self, address_bus: u16, data_bus: u8) -> (u16, u8, bool) {
|
|
||||||
if self.has_reset {
|
|
||||||
// we have completed the reset cycle
|
|
||||||
if self.read_signal {
|
|
||||||
// we should see new data in the data_bus for us
|
|
||||||
let read_data = data_bus;
|
|
||||||
println!("READ 0x{read_data:02x} from data bus.");
|
|
||||||
self.data_bus = read_data;
|
|
||||||
} else {
|
|
||||||
// we are writing to the bus.
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("Reset microstep {}", self.microcode_step);
|
println!("Reset microstep {}", self.microcode_step);
|
||||||
// we need to do the reset steps
|
// we need to do the reset steps
|
||||||
// reduce the number of remaining microsteps
|
// reduce the number of remaining microsteps
|
||||||
@@ -76,6 +61,31 @@ impl Mos6502Cpu {
|
|||||||
if self.microcode_step > 0 {
|
if self.microcode_step > 0 {
|
||||||
self.microcode_step -= 1;
|
self.microcode_step -= 1;
|
||||||
}
|
}
|
||||||
|
(address_bus, data_bus, read)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// AccurateTick
|
||||||
|
///
|
||||||
|
/// In: address_bus > Address of data operationm
|
||||||
|
/// data_bus > Data read or written
|
||||||
|
/// State:
|
||||||
|
/// read_bus > Flag for if cpu is reading or writing the data bus
|
||||||
|
/// cycle_step > Index for what step of the Decode->Load->Execute cycle we are in
|
||||||
|
/// Out: address_bus > address for operation
|
||||||
|
/// data_bus > data for the operation
|
||||||
|
/// read_bus > lets rest of the computer know if the CPU is reading from the address
|
||||||
|
/// provided or if we are writing to the address
|
||||||
|
pub fn tick2(&mut self, address_bus: u16, data_bus: u8) -> (u16, u8, bool) {
|
||||||
|
println!("STARTING TICK2");
|
||||||
|
if !self.has_reset { return self.reset_step(address_bus, data_bus, self.read_signal) }
|
||||||
|
// we have completed the reset cycle
|
||||||
|
if self.read_signal {
|
||||||
|
// we should see new data in the data_bus for us
|
||||||
|
let read_data = data_bus;
|
||||||
|
println!("READ 0x{read_data:02x} from data bus.");
|
||||||
|
self.data_bus = read_data;
|
||||||
|
} else {
|
||||||
|
// we are writing to the bus.
|
||||||
}
|
}
|
||||||
(self.address_bus, self.data_bus, self.read_signal)
|
(self.address_bus, self.data_bus, self.read_signal)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
use std::slice::Chunks;
|
||||||
|
use crate::periph::at28c256::At28C256;
|
||||||
|
|
||||||
|
impl At28C256 {
|
||||||
|
pub fn chunks(&self, size: usize) -> Chunks<u8> {
|
||||||
|
self.data.chunks(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
use crate::periph::at28c256::At28C256;
|
use crate::periph::at28c256::At28C256;
|
||||||
|
|
||||||
pub struct At28C256State {
|
pub struct At28C256State {
|
||||||
offset: u16
|
offset: u16,
|
||||||
|
max_offset: u16
|
||||||
}
|
}
|
||||||
|
|
||||||
impl At28C256 {
|
impl At28C256 {
|
||||||
pub fn dump(&self) -> At28C256State {
|
pub fn dump(&self) -> At28C256State {
|
||||||
At28C256State {
|
At28C256State {
|
||||||
offset: self.offset
|
offset: self.offset,
|
||||||
|
max_offset: self.max_offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,14 +1,14 @@
|
|||||||
pub mod default;
|
pub mod default;
|
||||||
pub mod rom_chip;
|
pub mod rom_chip;
|
||||||
pub mod tick;
|
pub mod new;
|
||||||
mod new;
|
pub mod program;
|
||||||
mod program;
|
pub mod dump;
|
||||||
mod dump;
|
pub mod checksum;
|
||||||
mod checksum;
|
pub mod blocks;
|
||||||
|
pub mod control;
|
||||||
use crate::constants::constants_system::SIZE_32KB;
|
pub mod signal_tick;
|
||||||
use crate::periph::rom_chip::RomChip;
|
pub mod memory_chip;
|
||||||
use std::io::Read;
|
pub mod bus_device;
|
||||||
|
|
||||||
/// At28C256
|
/// At28C256
|
||||||
///
|
///
|
||||||
@@ -17,10 +17,15 @@ use std::io::Read;
|
|||||||
/// 256kbit storage
|
/// 256kbit storage
|
||||||
/// 32kbyte storage
|
/// 32kbyte storage
|
||||||
pub struct At28C256 {
|
pub struct At28C256 {
|
||||||
|
// Logical parts
|
||||||
data_bus: u8,
|
data_bus: u8,
|
||||||
address_bus: u16,
|
address_bus: u16,
|
||||||
data: Box<[u8]>,
|
pub data: Box<[u8]>,
|
||||||
// where in the computer memory map do we live?
|
// where in the computer memory map do we live?
|
||||||
offset: u16,
|
offset: u16,
|
||||||
max_offset: u16
|
max_offset: u16,
|
||||||
|
// Physical Parts
|
||||||
|
cs: bool,
|
||||||
|
we: bool,
|
||||||
|
oe: bool
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ use crate::constants::constants_system::SIZE_32KB;
|
|||||||
use crate::periph::at28c256::At28C256;
|
use crate::periph::at28c256::At28C256;
|
||||||
|
|
||||||
impl At28C256 {
|
impl At28C256 {
|
||||||
pub fn program(&mut self, new_program: &[u8; SIZE_32KB]) {
|
pub fn program(&mut self, new_program: Box<[u8]>) {
|
||||||
// panic!("FAIL. Cant program the chip.");
|
// panic!("FAIL. Cant program the chip.");
|
||||||
// println!("PROGRAMMING {:?}", new_program);
|
// println!("PROGRAMMING {:?}", new_program);
|
||||||
self.data = Box::new(*new_program);
|
self.data = new_program;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,18 @@
|
|||||||
|
use log::debug;
|
||||||
use crate::constants::constants_system::SIZE_32KB;
|
use crate::constants::constants_system::SIZE_32KB;
|
||||||
use crate::periph::at28c256::At28C256;
|
use crate::periph::at28c256::At28C256;
|
||||||
use crate::periph::rom_chip::RomChip;
|
use crate::traits::bus_device::BusDevice;
|
||||||
|
use crate::traits::memory_chip::MemoryChip;
|
||||||
|
use crate::traits::rom_chip::RomChip;
|
||||||
|
|
||||||
impl RomChip for At28C256 {
|
impl RomChip for At28C256 {
|
||||||
fn read(&self, offset: &u16) -> u8 {
|
/// program
|
||||||
self.data[*offset as usize]
|
///
|
||||||
}
|
/// Writes new data to the memory chip
|
||||||
|
fn program(new_data: &[u8]) -> Box<At28C256> {
|
||||||
fn program(new_data: &[u8; SIZE_32KB]) -> Box<At28C256> {
|
|
||||||
println!("Writing new chip.");
|
println!("Writing new chip.");
|
||||||
let mut working = At28C256::default();
|
let mut working = At28C256::default();
|
||||||
working.data = Box::new(*new_data);
|
working.data = new_data.to_vec().into_boxed_slice();
|
||||||
working.into()
|
Box::new(working)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn smoke() {
|
|
||||||
assert!(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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,68 +0,0 @@
|
|||||||
use crate::constants::constants_system::SIZE_32KB;
|
|
||||||
use crate::periph::at28c256::At28C256;
|
|
||||||
use crate::periph::hm62256::Hm62256;
|
|
||||||
|
|
||||||
impl At28C256 {
|
|
||||||
fn talking_to_me(&self, address: u16) -> bool {
|
|
||||||
address >= self.offset && address < self.max_offset
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) {
|
|
||||||
println!("At28C256: Tick starting for A${address_bus:04x} D${data_bus:02x} R{read_mode}");
|
|
||||||
|
|
||||||
// we aren't being addressed
|
|
||||||
// OR
|
|
||||||
// we arent reading from the ROM...
|
|
||||||
if !self.talking_to_me(address_bus) ||
|
|
||||||
!read_mode {
|
|
||||||
// ...go away.
|
|
||||||
return (address_bus, data_bus)
|
|
||||||
}
|
|
||||||
|
|
||||||
let effective = address_bus - self.offset;
|
|
||||||
if effective < self.max_offset {
|
|
||||||
if effective < self.data.len() as u16 {
|
|
||||||
self.data_bus = self.data[effective as usize];
|
|
||||||
} else {
|
|
||||||
self.data_bus = 0x00;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println!("At28C256: OUTSIDE RANGE. :(");
|
|
||||||
return (address_bus, data_bus)
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("At28C256: Read... {:02x}", self.data_bus);
|
|
||||||
println!("At28C256: Done with ticking the AtC256");
|
|
||||||
(address_bus, self.data_bus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use std::fs;
|
|
||||||
use crate::periph::rom_chip::RomChip;
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn smoke() { assert!(true); }
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn checksum_binary_loads() {
|
|
||||||
let path = "/home/tmerritt/Projects/mos6502/resources/test/periph/at28c256/checksum.bin";
|
|
||||||
let bytes = match fs::read(path) {
|
|
||||||
Ok(bytes) => {
|
|
||||||
println!("Read {} bytes.", bytes.len());
|
|
||||||
bytes
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("FAIL to read rom.");
|
|
||||||
panic!("No rom no run.");
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut rom = At28C256::new(0x0000, 0x3fff, bytes);
|
|
||||||
|
|
||||||
assert_eq!(rom.checksum(), 0x58);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
pub trait Backplane {
|
|
||||||
fn data_bus(&self) -> u8;
|
|
||||||
fn address_bus(&self) -> u16;
|
|
||||||
fn read_mode(&self) -> bool;
|
|
||||||
fn set_read_mode(&mut self, new_mode: bool);
|
|
||||||
fn set_data_bus(&mut self, new_value: u8);
|
|
||||||
fn set_address_bus(&mut self, new_value: u16);
|
|
||||||
fn tick(&mut self);
|
|
||||||
}
|
|
||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ impl Hm62256 {
|
|||||||
|
|
||||||
pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool, cs: bool) -> (u16, u8) {
|
pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool, cs: bool) -> (u16, u8) {
|
||||||
println!("HM62256RAM TICK START -> 0x{address_bus:04x} 0x{data_bus:02x} {read_mode} {cs}");
|
println!("HM62256RAM TICK START -> 0x{address_bus:04x} 0x{data_bus:02x} {read_mode} {cs}");
|
||||||
if !(address_bus.gt( &self.offset) && address_bus.le(&self.max_address())) {
|
if !(address_bus >= self.offset && address_bus < self.max_address()) {
|
||||||
return (address_bus, data_bus);
|
return (address_bus, data_bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,9 +26,11 @@ impl Hm62256 {
|
|||||||
return (address_bus, data_bus);
|
return (address_bus, data_bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ok. lets see what we are dealing with
|
// ok. lets see what we are dealing with
|
||||||
self.data_bus = if read_mode {
|
self.data_bus = if read_mode {
|
||||||
self.data[addr as usize]
|
let new_value = self.data[addr as usize];
|
||||||
|
new_value
|
||||||
} else {
|
} else {
|
||||||
// writing to ram
|
// writing to ram
|
||||||
self.data[addr as usize] = data_bus.into();
|
self.data[addr as usize] = data_bus.into();
|
||||||
@@ -37,23 +39,3 @@ impl Hm62256 {
|
|||||||
(self.address_bus, self.data_bus)
|
(self.address_bus, self.data_bus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn smoke() { assert!(true); }
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn write_to_memory_read_back_works_at_0() {
|
|
||||||
let mut ram = Hm62256::default();
|
|
||||||
|
|
||||||
// load the data to ram
|
|
||||||
ram.tick(0x0000, 0xab, false, true);
|
|
||||||
// read the data back
|
|
||||||
let (_, new_data) = ram.tick(0x0000, 0x00, true, true);
|
|
||||||
|
|
||||||
assert_eq!(new_data, 0xab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user