RamRomComputer now reads from ROM and writes to RAM and reads back from RAM
This commit is contained in:
parent
2939e1cac5
commit
7498489b03
3103
Cargo.lock
generated
3103
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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::backplane::RamRomComputer;
|
||||||
|
use core::periph::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,6 +1,6 @@
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use core::computers::rom_only::backplane::RomOnlyComputer;
|
use core::computers::rom_only::RomOnlyComputer;
|
||||||
use core::periph::backplane::Backplane;
|
use core::periph::backplane::Backplane;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
|
|||||||
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -5,7 +5,7 @@ pub mod reset;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use crate::constants::constants_system::SIZE_1KB;
|
use crate::constants::constants_system::SIZE_1KB;
|
||||||
use crate::mos6502cpu::cpu::Mos6502Cpu;
|
use crate::mos6502cpu::Mos6502Cpu;
|
||||||
use crate::periph::at28c256::At28C256;
|
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;
|
||||||
|
|||||||
@ -24,7 +24,28 @@ impl Backplane for RamRomComputer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn tick(&mut self) {
|
fn tick(&mut self) {
|
||||||
todo!()
|
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_address_bus, rom_data_bus) = self.rom.tick(self.address_bus, self.data_bus, self.read_mode);
|
||||||
|
self.data_bus = rom_data_bus;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Out of range
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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;
|
||||||
@ -41,8 +62,9 @@ impl Backplane for RamRomComputer {
|
|||||||
|
|
||||||
impl RamRomComputer {
|
impl RamRomComputer {
|
||||||
pub fn new() -> RamRomComputer {
|
pub fn new() -> RamRomComputer {
|
||||||
|
let rom = At28C256::new(0x4000, 0x7fff, (0..255).collect());
|
||||||
RamRomComputer {
|
RamRomComputer {
|
||||||
rom: At28C256::default(),
|
rom,
|
||||||
ram: Hm62256::default(),
|
ram: Hm62256::default(),
|
||||||
data_bus: 0x00,
|
data_bus: 0x00,
|
||||||
address_bus: 0x0000,
|
address_bus: 0x0000,
|
||||||
|
|||||||
@ -1,27 +1,16 @@
|
|||||||
use crate::constants::constants_system::{SIZE_32KB, SIZE_64KB};
|
use crate::computers::rom_only::RomOnlyComputer;
|
||||||
use crate::periph::at28c256::At28C256;
|
|
||||||
use crate::periph::backplane::Backplane;
|
use crate::periph::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
|
||||||
}
|
}
|
||||||
@ -38,22 +27,3 @@ impl Backplane for RomOnlyComputer {
|
|||||||
println!("COMPUTER: Done ticking.");
|
println!("COMPUTER: Done ticking.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RomOnlyComputer {
|
|
||||||
pub fn new() -> RomOnlyComputer {
|
|
||||||
let mut working = vec![0x00u8; SIZE_32KB];
|
|
||||||
for index in 0..SIZE_32KB {
|
|
||||||
working[index] = index as u8;
|
|
||||||
}
|
|
||||||
RomOnlyComputer::program(working)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn program(rom: Vec<u8>) -> RomOnlyComputer {
|
|
||||||
RomOnlyComputer {
|
|
||||||
rom: At28C256::new(0x000, 0x3fff, rom),
|
|
||||||
address_bus: 0x0000,
|
|
||||||
data_bus: 0x00,
|
|
||||||
read_mode: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
13
core/src/computers/rom_only/debug_memory.rs
Normal file
13
core/src/computers/rom_only/debug_memory.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
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,14 @@
|
|||||||
|
use crate::periph::at28c256::At28C256;
|
||||||
|
|
||||||
pub mod backplane;
|
pub mod backplane;
|
||||||
|
pub mod new;
|
||||||
|
pub mod program;
|
||||||
|
pub mod debug_memory;
|
||||||
|
mod rom_chunks;
|
||||||
|
|
||||||
|
pub struct RomOnlyComputer {
|
||||||
|
pub(crate) rom: At28C256,
|
||||||
|
pub(crate) data_bus: u8,
|
||||||
|
pub(crate) address_bus: u16,
|
||||||
|
pub(crate) read_mode: bool,
|
||||||
|
}
|
||||||
13
core/src/computers/rom_only/new.rs
Normal file
13
core/src/computers/rom_only/new.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
use crate::computers::rom_only::RomOnlyComputer;
|
||||||
|
use crate::constants::constants_system::SIZE_32KB;
|
||||||
|
|
||||||
|
impl RomOnlyComputer {
|
||||||
|
pub fn new() -> RomOnlyComputer {
|
||||||
|
let mut working = vec![0x00u8; SIZE_32KB];
|
||||||
|
for index in 0..SIZE_32KB {
|
||||||
|
working[index] = index as u8;
|
||||||
|
}
|
||||||
|
RomOnlyComputer::program(working)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
14
core/src/computers/rom_only/program.rs
Normal file
14
core/src/computers/rom_only/program.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use crate::computers::rom_only::RomOnlyComputer;
|
||||||
|
use crate::constants::constants_system::SIZE_32KB;
|
||||||
|
use crate::periph::at28c256::At28C256;
|
||||||
|
|
||||||
|
impl RomOnlyComputer {
|
||||||
|
pub fn program(rom: Vec<u8>) -> RomOnlyComputer {
|
||||||
|
RomOnlyComputer {
|
||||||
|
rom: At28C256::new(0x000, 0x3fff, rom),
|
||||||
|
address_bus: 0x0000,
|
||||||
|
data_bus: 0x00,
|
||||||
|
read_mode: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
core/src/computers/rom_only/rom_chunks.rs
Normal file
8
core/src/computers/rom_only/rom_chunks.rs
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
20
core/src/mos6502cpu/bus_device.rs
Normal file
20
core/src/mos6502cpu/bus_device.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use crate::mos6502cpu::Mos6502Cpu;
|
||||||
|
use crate::traits::bus_device::BusDevice;
|
||||||
|
|
||||||
|
impl BusDevice for Mos6502Cpu {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
|||||||
43
core/src/mos6502cpu/default.rs
Normal file
43
core/src/mos6502cpu/default.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use crate::address_mode::AddressMode;
|
||||||
|
use crate::constants::constants_isa_op::ISA_OP_NOP;
|
||||||
|
use crate::constants::constants_system::SIZE_64KB;
|
||||||
|
use crate::instruction::Instruction;
|
||||||
|
use crate::instruction_table::INSTRUCTION_TABLE;
|
||||||
|
use crate::mos6502cpu::Mos6502Cpu;
|
||||||
|
use crate::mos6502cpu::tick_stages::Mos6502TickStates::LoadingInstruction;
|
||||||
|
use crate::operand::Operand;
|
||||||
|
use crate::operation::Operation;
|
||||||
|
|
||||||
|
impl Default for Mos6502Cpu {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut working = Mos6502Cpu {
|
||||||
|
memory: [0x00; SIZE_64KB],
|
||||||
|
a: 0x00,
|
||||||
|
x: 0x00,
|
||||||
|
y: 0x00,
|
||||||
|
flags: Default::default(),
|
||||||
|
pc: 0xfffd,
|
||||||
|
s: 0x00,
|
||||||
|
microcode_step: 0x00,
|
||||||
|
address_bus: 0x00,
|
||||||
|
data_bus: 0x00,
|
||||||
|
ir: Instruction {
|
||||||
|
op: Operation::NOP,
|
||||||
|
mode: AddressMode::Implied,
|
||||||
|
operand: Operand::None,
|
||||||
|
},
|
||||||
|
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].clone().unwrap(),
|
||||||
|
has_reset: false,
|
||||||
|
iv: 0xfffe,
|
||||||
|
cycle_carry: 0x0000,
|
||||||
|
ir_bytes: [0x00; 4],
|
||||||
|
read_signal: true,
|
||||||
|
reset_vector: 0x0000,
|
||||||
|
int_vector: 0x0000,
|
||||||
|
nmi_vector: 0x0000,
|
||||||
|
tick_stage: LoadingInstruction
|
||||||
|
};
|
||||||
|
working.reset_cpu();
|
||||||
|
working
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
37
core/src/periph/at28c256/blocks.rs
Normal file
37
core/src/periph/at28c256/blocks.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use std::slice::Chunks;
|
||||||
|
use crate::periph::at28c256::At28C256;
|
||||||
|
|
||||||
|
impl At28C256 {
|
||||||
|
pub fn chunks(&self, size: usize) -> Chunks<u8> {
|
||||||
|
self.data.chunks(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke() { assert!(true); }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn full_chunks_come_back_ok() {
|
||||||
|
let test_data = (0..255).collect();
|
||||||
|
let mut chip = At28C256::new(0x0000, 0x3fff, test_data);
|
||||||
|
|
||||||
|
let chunks = chip.chunks(16);
|
||||||
|
assert_eq!(chunks.len(), 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn partial_blocks_come_back_ok() {
|
||||||
|
let test_data = (0..=3).collect();
|
||||||
|
let mut chip = At28C256::new(0x0000, 0x3fff, test_data);
|
||||||
|
|
||||||
|
let chunks = chip.chunks(16);
|
||||||
|
assert_eq!(chunks.len(), 1);
|
||||||
|
for chunk in chunks {
|
||||||
|
assert_eq!(chunk.len(), 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
pub mod default;
|
pub mod default;
|
||||||
pub mod rom_chip;
|
pub mod rom_chip;
|
||||||
pub mod tick;
|
pub mod tick;
|
||||||
mod new;
|
pub mod new;
|
||||||
mod program;
|
pub mod program;
|
||||||
mod dump;
|
pub mod dump;
|
||||||
mod checksum;
|
pub mod checksum;
|
||||||
|
pub mod blocks;
|
||||||
|
|
||||||
use crate::constants::constants_system::SIZE_32KB;
|
use crate::constants::constants_system::SIZE_32KB;
|
||||||
use crate::periph::rom_chip::RomChip;
|
use crate::periph::rom_chip::RomChip;
|
||||||
|
|||||||
@ -4,11 +4,12 @@ use crate::periph::hm62256::Hm62256;
|
|||||||
|
|
||||||
impl At28C256 {
|
impl At28C256 {
|
||||||
fn talking_to_me(&self, address: u16) -> bool {
|
fn talking_to_me(&self, address: u16) -> bool {
|
||||||
|
//println!("Checking on {address:04x} in range of {:04x} {:04x}", self.offset, self.max_offset);
|
||||||
address >= self.offset && address < self.max_offset
|
address >= self.offset && address < self.max_offset
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, address_bus: u16, data_bus: u8, read_mode: bool) -> (u16, u8) {
|
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}");
|
print!("At28C256: Tick starting for A${address_bus:04x} D${data_bus:02x} R{read_mode}");
|
||||||
|
|
||||||
// we aren't being addressed
|
// we aren't being addressed
|
||||||
// OR
|
// OR
|
||||||
@ -16,9 +17,11 @@ impl At28C256 {
|
|||||||
if !self.talking_to_me(address_bus) ||
|
if !self.talking_to_me(address_bus) ||
|
||||||
!read_mode {
|
!read_mode {
|
||||||
// ...go away.
|
// ...go away.
|
||||||
|
// println!("At28C256 Tick not for me.");
|
||||||
return (address_bus, data_bus)
|
return (address_bus, data_bus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// print!("At28C256 tick for me.");
|
||||||
let effective = address_bus - self.offset;
|
let effective = address_bus - self.offset;
|
||||||
if effective < self.max_offset {
|
if effective < self.max_offset {
|
||||||
if effective < self.data.len() as u16 {
|
if effective < self.data.len() as u16 {
|
||||||
@ -31,8 +34,7 @@ impl At28C256 {
|
|||||||
return (address_bus, data_bus)
|
return (address_bus, data_bus)
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("At28C256: Read... {:02x}", self.data_bus);
|
// print!("At28C256: Read... {:02x}", self.data_bus);
|
||||||
println!("At28C256: Done with ticking the AtC256");
|
|
||||||
(address_bus, self.data_bus)
|
(address_bus, self.data_bus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,3 +7,4 @@ pub trait Backplane {
|
|||||||
fn set_address_bus(&mut self, new_value: u16);
|
fn set_address_bus(&mut self, new_value: u16);
|
||||||
fn tick(&mut self);
|
fn tick(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,8 @@ impl Hm62256 {
|
|||||||
|
|
||||||
// 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();
|
||||||
|
|||||||
8
core/src/traits/bus_device.rs
Normal file
8
core/src/traits/bus_device.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
pub trait BusDevice {
|
||||||
|
fn address_bus(&self) -> u16;
|
||||||
|
fn data_bus(&self) -> u8;
|
||||||
|
|
||||||
|
fn set_address_bus(&mut self, new_value: u16);
|
||||||
|
fn set_data_bus(&mut self, new_value: u8);
|
||||||
|
|
||||||
|
}
|
||||||
1
core/src/traits/mod.rs
Normal file
1
core/src/traits/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod bus_device;
|
||||||
@ -6,4 +6,6 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
macroquad.workspace = true
|
macroquad.workspace = true
|
||||||
core = { path = "../core" }
|
core = { path = "../core" }
|
||||||
egui-macroquad = "0.17"
|
egui_extras = "0.32"
|
||||||
|
egui = "0.27"
|
||||||
|
eframe = "0.27"
|
||||||
@ -1,92 +1,88 @@
|
|||||||
use core::periph::backplane::Backplane;
|
use eframe::egui;
|
||||||
use core::computers::rom_only::backplane::RomOnlyComputer;
|
use core::computers::rom_only::RomOnlyComputer;
|
||||||
use egui_macroquad::egui::TextBuffer;
|
struct MyApp {
|
||||||
use macroquad::prelude::*;
|
address: String,
|
||||||
|
data: String,
|
||||||
struct UIState {
|
cpu_read: bool,
|
||||||
address: u16,
|
computer: RomOnlyComputer
|
||||||
data: u8,
|
|
||||||
new_address_input: String,
|
|
||||||
new_data_input: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macroquad::main("Tick Interface")]
|
impl Default for MyApp {
|
||||||
async fn main() {
|
fn default() -> Self {
|
||||||
let mut ui = UIState {
|
let rom_data = vec![0x01, 0x02, 0x03, 0x04];
|
||||||
address: 0x1234,
|
Self {
|
||||||
data: 0xAB,
|
address: String::new(),
|
||||||
new_address_input: String::new(),
|
data: String::new(),
|
||||||
new_data_input: String::new(),
|
cpu_read: false,
|
||||||
};
|
computer: RomOnlyComputer::program(rom_data), // Example memory: 0x00 to 0xFF
|
||||||
|
|
||||||
let rom_program = vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07];
|
|
||||||
|
|
||||||
let mut rom_only_pc = RomOnlyComputer::program(rom_program);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
clear_background(BLACK);
|
|
||||||
|
|
||||||
// Labels
|
|
||||||
draw_text("Address:", 20.0, 40.0, 30.0, WHITE);
|
|
||||||
draw_text(&format!("0x{:04X}", ui.address), 150.0, 40.0, 30.0, YELLOW);
|
|
||||||
|
|
||||||
draw_text("Data:", 20.0, 80.0, 30.0, WHITE);
|
|
||||||
draw_text(&format!("0x{:02X}", ui.data), 150.0, 80.0, 30.0, YELLOW);
|
|
||||||
|
|
||||||
// Input: New Address
|
|
||||||
draw_text("New Address:", 20.0, 140.0, 25.0, WHITE);
|
|
||||||
ui.new_address_input = draw_textbox(&ui.new_address_input, 200.0, 120.0, 150.0);
|
|
||||||
|
|
||||||
// Input: New Data
|
|
||||||
draw_text("New Data:", 20.0, 190.0, 25.0, WHITE);
|
|
||||||
ui.new_data_input = draw_textbox(&ui.new_data_input, 200.0, 170.0, 150.0);
|
|
||||||
|
|
||||||
// Tick Button
|
|
||||||
if is_mouse_button_pressed(MouseButton::Left) {
|
|
||||||
let (mx, my) = mouse_position();
|
|
||||||
if mx >= 20.0 && mx <= 120.0 && my >= 220.0 && my <= 260.0 {
|
|
||||||
if let Ok(addr) = u16::from_str_radix(&ui.new_address_input.trim_start_matches("0x"), 16) {
|
|
||||||
rom_only_pc.set_address_bus(addr);
|
|
||||||
}
|
}
|
||||||
if let Ok(dat) = u8::from_str_radix(&ui.new_data_input.trim_start_matches("0x"), 16) {
|
|
||||||
rom_only_pc.set_data_bus(dat);
|
|
||||||
}
|
|
||||||
println!("Tick: addr=0x{:04X} data=0x{:02X}", ui.address, ui.data);
|
|
||||||
rom_only_pc.tick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw button
|
|
||||||
draw_rectangle(20.0, 220.0, 100.0, 40.0, DARKGRAY);
|
|
||||||
draw_text("Tick", 40.0, 250.0, 30.0, WHITE);
|
|
||||||
|
|
||||||
ui.address = rom_only_pc.address_bus();
|
|
||||||
ui.data = rom_only_pc.data_bus();
|
|
||||||
|
|
||||||
next_frame().await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_textbox(input: &str, x: f32, y: f32, width: f32) -> String {
|
impl eframe::App for MyApp {
|
||||||
let mut new_input = input.to_string();
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
|
ui.heading("Memory Inspector");
|
||||||
|
|
||||||
draw_rectangle_lines(x - 5.0, y - 5.0, width + 10.0, 40.0, 2.0, WHITE);
|
ui.horizontal(|ui| {
|
||||||
draw_text(input, x, y + 25.0, 30.0, WHITE);
|
ui.label("Address:");
|
||||||
|
ui.text_edit_singleline(&mut self.address);
|
||||||
|
});
|
||||||
|
|
||||||
if is_mouse_button_pressed(MouseButton::Left) {
|
ui.horizontal(|ui| {
|
||||||
let (mx, my) = mouse_position();
|
ui.label("Data:");
|
||||||
if mx >= x && mx <= x + width && my >= y && my <= y + 40.0 {
|
ui.text_edit_singleline(&mut self.data);
|
||||||
new_input = String::new(); // reset input on click
|
});
|
||||||
}
|
|
||||||
|
ui.checkbox(&mut self.cpu_read, "CPU Read");
|
||||||
|
|
||||||
|
if ui.button("Tick").clicked() {
|
||||||
|
println!(
|
||||||
|
"Ticked with Address: {}, Data: {}, CPU Read: {}",
|
||||||
|
self.address, self.data, self.cpu_read
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for c in get_char_pressed() {
|
ui.horizontal(|ui| {
|
||||||
if c == '\u{8}' {
|
ui.label(format!("Address Bus ${:?}", self.address).as_str());
|
||||||
new_input.pop(); // backspace
|
ui.label(format!("Data Bus ${:?}", self.data).as_str());
|
||||||
} else if c.is_ascii_hexdigit() {
|
});
|
||||||
new_input.push(c.to_ascii_uppercase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new_input
|
ui.separator();
|
||||||
|
ui.label("Memory View (Hex Dump):");
|
||||||
|
|
||||||
|
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||||
|
let bytes_per_row = 16;
|
||||||
|
for (i, chunk) in self.computer.rom_chunks(bytes_per_row).enumerate() {
|
||||||
|
let address = i * bytes_per_row;
|
||||||
|
let hex_values: String = chunk
|
||||||
|
.iter()
|
||||||
|
.map(|b| format!("{:02X} ", b))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let ascii_values: String = chunk
|
||||||
|
.iter()
|
||||||
|
.map(|b| {
|
||||||
|
if b.is_ascii_graphic() {
|
||||||
|
*b as char
|
||||||
|
} else {
|
||||||
|
'.'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
ui.monospace(format!("{:08X}: {:<48} {}", address, hex_values, ascii_values));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> eframe::Result<()> {
|
||||||
|
let options = eframe::NativeOptions::default();
|
||||||
|
eframe::run_native(
|
||||||
|
"Memory Inspector",
|
||||||
|
options,
|
||||||
|
Box::new(|_cc| Box::new(MyApp::default())),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user