Compare commits
3 Commits
d89fc1cd2b
...
8ed93fc90e
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ed93fc90e | |||
| 0c475127f6 | |||
| e5c2319803 |
5
.bad/.gitignore
vendored
Normal file
5
.bad/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
8
.bad/modules.xml
Normal file
8
.bad/modules.xml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?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>
|
||||||
13
.bad/mos6502.iml
Normal file
13
.bad/mos6502.iml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?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>
|
||||||
6
.bad/vcs.xml
Normal file
6
.bad/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@ -1,5 +1,2 @@
|
|||||||
[alias]
|
[alias]
|
||||||
coverage = "tarpaulin --out Html --skip-clean --output-dir coverage"
|
coverage = "tarpaulin --out Html --skip-clean --output-dir coverage"
|
||||||
|
|
||||||
[build]
|
|
||||||
rustc-wrapper = "sccache"
|
|
||||||
|
|||||||
2
.idea/mos6502.iml
generated
2
.idea/mos6502.iml
generated
@ -6,6 +6,8 @@
|
|||||||
<sourceFolder url="file://$MODULE_DIR$/core/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/core/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/macroquad/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/macroquad/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/beneater/src" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/core/tests" isTestSource="true" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|||||||
63
Cargo.lock
generated
63
Cargo.lock
generated
@ -75,9 +75,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.4.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "beneater"
|
name = "beneater"
|
||||||
@ -185,6 +185,7 @@ name = "core"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -474,6 +475,15 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pretty_env_logger"
|
name = "pretty_env_logger"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -514,6 +524,35 @@ version = "5.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||||
|
dependencies = [
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.9.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.11.1"
|
version = "1.11.1"
|
||||||
@ -823,3 +862,23 @@ checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.8.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.8.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
// This is the GUI for the BenEater PC
|
// This is the GUI for the BenEater PC
|
||||||
|
use beneater::parts::cpu_display::CpuDisplay;
|
||||||
use macroquad::prelude::*;
|
use macroquad::prelude::*;
|
||||||
|
use macroquad::telemetry::frame;
|
||||||
|
use beneater::parts::ben_eater_pc::BenEaterPC;
|
||||||
|
use beneater::parts::display_matrix::DisplayMatrix;
|
||||||
|
|
||||||
|
|
||||||
#[macroquad::main("Ben Eaters PC")]
|
#[macroquad::main("Ben Eaters PC")]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
@ -7,10 +12,32 @@ async fn main() {
|
|||||||
|
|
||||||
let computer = BenEaterPC::new();
|
let computer = BenEaterPC::new();
|
||||||
|
|
||||||
|
|
||||||
|
let mut dm = DisplayMatrix::new(200.0, 50.0);
|
||||||
|
let message_to_show = "Taxation is theft";
|
||||||
|
let mut message_index = 0;
|
||||||
|
|
||||||
|
dm.push_letter('T');
|
||||||
|
let mut frame_number: u32 = 0x00;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
clear_background(BLUE);
|
clear_background(BLUE);
|
||||||
|
|
||||||
draw_text("Ben Eater", 20.0, 20.0, 30.0, BLACK);
|
draw_text("Ben Eater", 20.0, 20.0, 30.0, BLACK);
|
||||||
|
dm.render(20.0, 40.0);
|
||||||
|
CpuDisplay::render(&computer.cpu, 20.0, 120.0);
|
||||||
|
|
||||||
|
frame_number += 1;
|
||||||
|
|
||||||
|
if frame_number.is_multiple_of(60) {
|
||||||
|
dm.push_letter('X');
|
||||||
|
}
|
||||||
|
|
||||||
|
if frame_number.is_multiple_of(60 * 6) {
|
||||||
|
dm.clear_display()
|
||||||
|
}
|
||||||
|
|
||||||
next_frame().await
|
next_frame().await
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
beneater/src/parts/address_bus.rs
Normal file
9
beneater/src/parts/address_bus.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
pub struct AddressBus {
|
||||||
|
pub address: u16
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddressBus {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
AddressBus { address: 0x0000 }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,13 +1,17 @@
|
|||||||
use crate::parts::clock::Clock;
|
use crate::parts::clock::Clock;
|
||||||
use core::mos6502cpu::Mos6502Cpu;
|
use core::mos6502cpu::Mos6502Cpu;
|
||||||
|
|
||||||
struct BenEaterPC {
|
pub struct BenEaterPC {
|
||||||
clock: Clock,
|
clock: Clock,
|
||||||
cpu: Mos6502Cpu,
|
// pub because i am rendering it.
|
||||||
|
// there should be a proper interface to get the data
|
||||||
|
// for ui out of this.
|
||||||
|
pub cpu: Mos6502Cpu,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BenEaterPC {
|
impl BenEaterPC {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
println!("New BENEATERPC");
|
||||||
BenEaterPC {
|
BenEaterPC {
|
||||||
clock: Clock::new(),
|
clock: Clock::new(),
|
||||||
cpu: Mos6502Cpu::default()
|
cpu: Mos6502Cpu::default()
|
||||||
@ -20,6 +24,8 @@ impl BenEaterPC {
|
|||||||
// tick the clock.
|
// tick the clock.
|
||||||
// tick the memory
|
// tick the memory
|
||||||
// tick the VIA
|
// tick the VIA
|
||||||
|
} else {
|
||||||
|
self.cpu.tick();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
beneater/src/parts/cpu_display.rs
Normal file
28
beneater/src/parts/cpu_display.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
use macroquad::color::{BLACK, Color};
|
||||||
|
use macroquad::prelude::*;
|
||||||
|
use macroquad::text::draw_text;
|
||||||
|
use core::mos6502cpu::Mos6502Cpu;
|
||||||
|
|
||||||
|
pub struct CpuDisplay {}
|
||||||
|
impl CpuDisplay {
|
||||||
|
pub fn render(cpu: &Mos6502Cpu, x_offset: f32, y_offset: f32) {
|
||||||
|
// get the data to display...
|
||||||
|
let (pc, a, x, y, address_bus, data_bus) = cpu.dump_data();
|
||||||
|
|
||||||
|
// ...build the interface
|
||||||
|
Self::draw_square(x_offset, y_offset, x_offset + 300.0, y_offset + 85.0, BLACK);
|
||||||
|
|
||||||
|
draw_text(format!("PC: 0x{:04x} / {}", pc, pc).as_str(), x_offset + 5.0, y_offset + 18.0, 15.0, BLACK);
|
||||||
|
draw_text(format!("A: 0x{:02x} X: 0x{:02x} Y: 0x{:02x}", a, x, y).as_str(), x_offset + 5.0, y_offset + 35.0, 15.0, BLACK);
|
||||||
|
draw_text(format!("Address: {:016b} | {:04x}", address_bus, address_bus).as_str(), x_offset + 5.0, y_offset + 55.0, 15.0, BLACK);
|
||||||
|
draw_text(format!("Data: {:08b} | {:02x}", data_bus, data_bus).as_str(), x_offset + 5.0, y_offset + 75.0, 15.0, BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_square(x1: f32, y1: f32, x2: f32, y2: f32, color: Color) {
|
||||||
|
// println!("Square from {x1:2.0}x{y1:2.0} to {x2:2.0}x{y2:2.0} with {:?}", color);
|
||||||
|
draw_line(x1, y1, x2, y1, 1.0, color);
|
||||||
|
draw_line(x1, y1, x1, y2, 1.0, color);
|
||||||
|
draw_line(x1, y2, x2, y2, 1.0, color);
|
||||||
|
draw_line(x2, y1, x2, y2, 1.0, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
beneater/src/parts/data_bus.rs
Normal file
9
beneater/src/parts/data_bus.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
pub struct DataBus {
|
||||||
|
pub data: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataBus {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
DataBus { data: 0x00 }
|
||||||
|
}
|
||||||
|
}
|
||||||
79
beneater/src/parts/display_matrix.rs
Normal file
79
beneater/src/parts/display_matrix.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
use macroquad::prelude::*;
|
||||||
|
use crate::parts::address_bus::AddressBus;
|
||||||
|
use crate::parts::data_bus::DataBus;
|
||||||
|
|
||||||
|
pub struct DisplayMatrix {
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
text_buffer: String,
|
||||||
|
data_bus: DataBus,
|
||||||
|
rs: bool,
|
||||||
|
rw: bool,
|
||||||
|
cursor_position: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisplayMatrix {
|
||||||
|
pub fn new(width: f32, height: f32) -> DisplayMatrix {
|
||||||
|
DisplayMatrix {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
text_buffer: String::from(""),
|
||||||
|
data_bus: DataBus::new(),
|
||||||
|
rs: false,
|
||||||
|
rw: false,
|
||||||
|
cursor_position: 0x00
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tick
|
||||||
|
///
|
||||||
|
/// Checks the data bus and sees what the setup is.
|
||||||
|
///
|
||||||
|
/// 0 0 0 0 0 0 0 1 -> Clear Display
|
||||||
|
/// 0 0 0 0 0 0 1 - -> Return Home
|
||||||
|
/// 0 0 0 0 0 0 A B -> Sets cursor move direction and shift
|
||||||
|
/// A -> 0 = Insert, 1 = Delete
|
||||||
|
/// B -> Scroll bool
|
||||||
|
/// 0 0 0 0 1 D C B -> Sets display mode
|
||||||
|
/// D -> Display On/Off
|
||||||
|
/// C -> Cursor On/Off
|
||||||
|
/// B -> Blink
|
||||||
|
pub fn tick(&mut self) {
|
||||||
|
// parse whats on the data bus.
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_busses(&mut self, address_bus: &mut AddressBus, data_bus: &mut DataBus) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_letter(&mut self, letter_to_push: char) {
|
||||||
|
self.cursor_position += 1;
|
||||||
|
self.text_buffer.push(letter_to_push)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_display(&mut self) {
|
||||||
|
self.cursor_position = 0;
|
||||||
|
self.text_buffer.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, x_offset: f32, y_offset: f32) {
|
||||||
|
DisplayMatrix::draw_square(x_offset,
|
||||||
|
y_offset,
|
||||||
|
x_offset + self.width ,
|
||||||
|
y_offset + self.height,
|
||||||
|
BLACK);
|
||||||
|
|
||||||
|
let mut tmp = self.text_buffer.clone();
|
||||||
|
tmp.push('#');
|
||||||
|
draw_text(&*tmp, x_offset + 5.0, y_offset + 20.0, 20.0, BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_square(x1: f32, y1: f32, x2: f32, y2: f32, color: Color) {
|
||||||
|
// println!("Square from {x1:2.0}x{y1:2.0} to {x2:2.0}x{y2:2.0} with {:?}", color);
|
||||||
|
draw_line(x1, y1, x2, y1, 1.0, color);
|
||||||
|
draw_line(x1, y1, x1, y2, 1.0, color);
|
||||||
|
draw_line(x1, y2, x2, y2, 1.0, color);
|
||||||
|
draw_line(x2, y1, x2, y2, 1.0, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,8 @@
|
|||||||
pub mod clock;
|
pub mod clock;
|
||||||
mod ben_eater_pc;
|
pub mod ben_eater_pc;
|
||||||
mod via6522;
|
pub mod via6522;
|
||||||
|
pub mod display_matrix;
|
||||||
|
pub mod address_bus;
|
||||||
|
pub mod data_bus;
|
||||||
|
pub mod cpu_display;
|
||||||
|
mod ram_display;
|
||||||
|
|||||||
20
beneater/src/parts/ram_display.rs
Normal file
20
beneater/src/parts/ram_display.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use macroquad::prelude::*;
|
||||||
|
|
||||||
|
pub struct RamDisplay {}
|
||||||
|
|
||||||
|
impl RamDisplay {
|
||||||
|
pub fn render(ram: &Box<[u8]>, x_offset: f32, y_offset: f32) {
|
||||||
|
Self::draw_square(x_offset, y_offset, x_offset + 200.0, y_offset + 300.0, BLACK);
|
||||||
|
|
||||||
|
draw_text("RAM", x_offset + 5.0, y_offset + 5.0, 15.0, BLACK);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_square(x1: f32, y1: f32, x2: f32, y2: f32, color: Color) {
|
||||||
|
// println!("Square from {x1:2.0}x{y1:2.0} to {x2:2.0}x{y2:2.0} with {:?}", color);
|
||||||
|
draw_line(x1, y1, x2, y1, 1.0, color);
|
||||||
|
draw_line(x1, y1, x1, y2, 1.0, color);
|
||||||
|
draw_line(x1, y2, x2, y2, 1.0, color);
|
||||||
|
draw_line(x2, y1, x2, y2, 1.0, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,12 @@
|
|||||||
|
pub enum Via6522Port {
|
||||||
|
A(u8),
|
||||||
|
B(u8)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Via6522 {
|
pub struct Via6522 {
|
||||||
|
data_bus: u8,
|
||||||
|
address_bus: u16,
|
||||||
port_a_state: u8,
|
port_a_state: u8,
|
||||||
port_b_data: u8,
|
port_b_data: u8,
|
||||||
port_a_direction: u8,
|
port_a_direction: u8,
|
||||||
@ -15,16 +22,23 @@ impl Via6522 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_a_direction(&mut self, new_direction: u8) {
|
pub fn set_port_direction(&mut self, port: Via6522Port) {
|
||||||
|
match port {
|
||||||
|
Via6522Port::A(x) => {
|
||||||
|
self.port_a_direction = x;
|
||||||
|
},
|
||||||
|
Via6522Port::B(x) => {
|
||||||
|
self.port_b_direction = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for output pins and see what they say
|
/// check for output pins and see what they say
|
||||||
pub fn update_pins(&mut self) {
|
pub fn update_pins(&mut self) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for input mode pins and see what they say
|
/// check for input mode pins and see what they say
|
||||||
pub fn read_pins(&self) {
|
pub fn read_pins(&self) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,22 @@
|
|||||||
use core::instruction::Instruction;
|
use core::instruction::Instruction;
|
||||||
use core::address_mode::AddressMode;
|
use core::address_mode::AddressMode;
|
||||||
|
use core::operand::Operand;
|
||||||
|
use core::operation::Operation;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Taxation is Theft");
|
println!("Taxation is Theft");
|
||||||
|
|
||||||
// Instruction::from_bytes(vec![0b11100011]);
|
let instructions = vec![(
|
||||||
|
Instruction {
|
||||||
|
op: Operation::NOP,
|
||||||
|
mode: AddressMode::Implied,
|
||||||
|
operand: Operand::None,
|
||||||
|
}, &[0xea]
|
||||||
|
)];
|
||||||
|
|
||||||
// let instruction = Instruction::ADC(AddressMode::Immediate);
|
for (op, bytes) in instructions {
|
||||||
// println!("Instruction = {:?}", instruction.to_string());
|
assert_eq!(Instruction::decode(bytes), Some(op));
|
||||||
|
}
|
||||||
|
// let instruction = Instruction::decode(&[0xea]);
|
||||||
|
// println!("NOP Decoded -> {:?}", instruction);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,4 +3,5 @@ name = "core"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
rand = "0.9.0"
|
||||||
@ -1,4 +1,3 @@
|
|||||||
use std::fmt::{Display};
|
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||||
pub enum AddressMode {
|
pub enum AddressMode {
|
||||||
|
|||||||
@ -15,6 +15,7 @@ pub struct Instruction {
|
|||||||
|
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
pub fn decode(bytes: &[u8]) -> Option<Instruction> {
|
pub fn decode(bytes: &[u8]) -> Option<Instruction> {
|
||||||
|
println!("DECODING : {bytes:?}");
|
||||||
let opcode = bytes.get(0).copied()?;
|
let opcode = bytes.get(0).copied()?;
|
||||||
let info = INSTRUCTION_TABLE[opcode as usize]?;
|
let info = INSTRUCTION_TABLE[opcode as usize]?;
|
||||||
|
|
||||||
@ -25,14 +26,18 @@ impl Instruction {
|
|||||||
let hi = *bytes.get(2)?;
|
let hi = *bytes.get(2)?;
|
||||||
Operand::Word(u16::from_le_bytes([lo, hi]))
|
Operand::Word(u16::from_le_bytes([lo, hi]))
|
||||||
}
|
}
|
||||||
_ => return None,
|
_ => Operand::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(Instruction {
|
let return_value = Some(Instruction {
|
||||||
op: info.operation,
|
op: info.operation,
|
||||||
mode: info.mode,
|
mode: info.mode,
|
||||||
operand,
|
operand,
|
||||||
})
|
});
|
||||||
|
|
||||||
|
println!("RETURNING: {:?}", return_value);
|
||||||
|
|
||||||
|
return_value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +46,7 @@ impl Instruction {
|
|||||||
mod test {
|
mod test {
|
||||||
use crate::address_mode::AddressMode::*;
|
use crate::address_mode::AddressMode::*;
|
||||||
use crate::instruction::Instruction;
|
use crate::instruction::Instruction;
|
||||||
use crate::operation::Operation::ADC;
|
use crate::operation::Operation::{ADC, INY, LSR};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -75,14 +80,14 @@ mod test {
|
|||||||
(vec![0x24, 0xab], Instruction { op: BIT, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
(vec![0x24, 0xab], Instruction { op: BIT, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x2c, 0xcd, 0xab], Instruction { op: BIT, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
(vec![0x2c, 0xcd, 0xab], Instruction { op: BIT, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
||||||
// BCC, BCS, BEQ, BMI, BNE, BPL, BVC, BVS
|
// BCC, BCS, BEQ, BMI, BNE, BPL, BVC, BVS
|
||||||
(vec![0x10, 0xab], Instruction { op: BPL, mode: Immediate, operand: Operand::Byte(0xab) }),
|
(vec![0x10, 0xab], Instruction { op: BPL, mode: Implied, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x30, 0xab], Instruction { op: BMI, mode: Immediate, operand: Operand::Byte(0xab) }),
|
(vec![0x30, 0xab], Instruction { op: BMI, mode: Implied, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x50, 0xab], Instruction { op: BVC, mode: Immediate, operand: Operand::Byte(0xab) }),
|
(vec![0x50, 0xab], Instruction { op: BVC, mode: Implied, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x70, 0xab], Instruction { op: BVS, mode: Immediate, operand: Operand::Byte(0xab) }),
|
(vec![0x70, 0xab], Instruction { op: BVS, mode: Implied, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x90, 0xab], Instruction { op: BCC, mode: Immediate, operand: Operand::Byte(0xab) }),
|
(vec![0x90, 0xab], Instruction { op: BCC, mode: Implied, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0xb0, 0xab], Instruction { op: BCS, mode: Immediate, operand: Operand::Byte(0xab) }),
|
(vec![0xb0, 0xab], Instruction { op: BCS, mode: Implied, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0xd0, 0xab], Instruction { op: BNE, mode: Immediate, operand: Operand::Byte(0xab) }),
|
(vec![0xd0, 0xab], Instruction { op: BNE, mode: Implied, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0xf0, 0xab], Instruction { op: BEQ, mode: Immediate, operand: Operand::Byte(0xab) }),
|
(vec![0xf0, 0xab], Instruction { op: BEQ, mode: Implied, operand: Operand::Byte(0xab) }),
|
||||||
// BRK
|
// BRK
|
||||||
(vec![0x00], Instruction { op: BRK, mode: Implied, operand: Operand::None }),
|
(vec![0x00], Instruction { op: BRK, mode: Implied, operand: Operand::None }),
|
||||||
// CLC, CLD, CLI, CLV
|
// CLC, CLD, CLI, CLV
|
||||||
@ -129,7 +134,7 @@ mod test {
|
|||||||
(vec![0xee, 0xcd, 0xab], Instruction { op: INC, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
(vec![0xee, 0xcd, 0xab], Instruction { op: INC, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
||||||
(vec![0xfe, 0xcd, 0xab], Instruction { op: INC, mode: AbsoluteX, operand: Operand::Word(0xabcd) }),
|
(vec![0xfe, 0xcd, 0xab], Instruction { op: INC, mode: AbsoluteX, operand: Operand::Word(0xabcd) }),
|
||||||
(vec![0xe8], Instruction { op: INX, mode: Implied, operand: Operand::None }),
|
(vec![0xe8], Instruction { op: INX, mode: Implied, operand: Operand::None }),
|
||||||
(vec![0xc8], Instruction { op: INX, mode: Implied, operand: Operand::None }),
|
(vec![0xc8], Instruction { op: INY, mode: Implied, operand: Operand::None }),
|
||||||
// JMP, JSR
|
// JMP, JSR
|
||||||
(vec![0x4c, 0xcd, 0xab], Instruction { op: JMP, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
(vec![0x4c, 0xcd, 0xab], Instruction { op: JMP, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
||||||
(vec![0x6c, 0xcd, 0xab], Instruction { op: JMP, mode: Indirect, operand: Operand::Word(0xabcd) }),
|
(vec![0x6c, 0xcd, 0xab], Instruction { op: JMP, mode: Indirect, operand: Operand::Word(0xabcd) }),
|
||||||
@ -146,21 +151,21 @@ mod test {
|
|||||||
// LDX
|
// LDX
|
||||||
(vec![0xa2, 0xab], Instruction { op: LDX, mode: Immediate, operand: Operand::Byte(0xab) }),
|
(vec![0xa2, 0xab], Instruction { op: LDX, mode: Immediate, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0xa6, 0xab], Instruction { op: LDX, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
(vec![0xa6, 0xab], Instruction { op: LDX, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0xb6, 0xab], Instruction { op: LDX, mode: ZeroPageX, operand: Operand::Byte(0xab) }),
|
(vec![0xb6, 0xab], Instruction { op: LDX, mode: ZeroPageY, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0xae, 0xcd, 0xab], Instruction { op: LDX, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
(vec![0xae, 0xcd, 0xab], Instruction { op: LDX, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
||||||
(vec![0xbe, 0xcd, 0xab], Instruction { op: LDX, mode: AbsoluteX, operand: Operand::Word(0xabcd) }),
|
(vec![0xbe, 0xcd, 0xab], Instruction { op: LDX, mode: AbsoluteY, operand: Operand::Word(0xabcd) }),
|
||||||
// LDY
|
// LDY
|
||||||
(vec![0xa2, 0xab], Instruction { op: LDY, mode: Immediate, operand: Operand::Byte(0xab) }),
|
(vec![0xa0, 0xab], Instruction { op: LDY, mode: Immediate, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0xa6, 0xab], Instruction { op: LDY, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
(vec![0xa4, 0xab], Instruction { op: LDY, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0xb6, 0xab], Instruction { op: LDY, mode: ZeroPageX, operand: Operand::Byte(0xab) }),
|
(vec![0xb4, 0xab], Instruction { op: LDY, mode: ZeroPageX, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0xae, 0xcd, 0xab], Instruction { op: LDY, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
(vec![0xac, 0xcd, 0xab], Instruction { op: LDY, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
||||||
(vec![0xbe, 0xcd, 0xab], Instruction { op: LDY, mode: AbsoluteX, operand: Operand::Word(0xabcd) }),
|
(vec![0xbc, 0xcd, 0xab], Instruction { op: LDY, mode: AbsoluteX, operand: Operand::Word(0xabcd) }),
|
||||||
// LSR
|
// LSR
|
||||||
(vec![0x4a, 0xab], Instruction { op: LDY, mode: Accumulator, operand: Operand::Byte(0xab) }),
|
(vec![0x4a], Instruction { op: LSR, mode: Accumulator, operand: Operand::None }),
|
||||||
(vec![0x46, 0xab], Instruction { op: LDY, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
(vec![0x46, 0xab], Instruction { op: LSR, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x56, 0xab], Instruction { op: LDY, mode: ZeroPageX, operand: Operand::Byte(0xab) }),
|
(vec![0x56, 0xab], Instruction { op: LSR, mode: ZeroPageX, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x4e, 0xcd, 0xab], Instruction { op: LDY, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
(vec![0x4e, 0xcd, 0xab], Instruction { op: LSR, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
||||||
(vec![0x5e, 0xcd, 0xab], Instruction { op: LDY, mode: AbsoluteX, operand: Operand::Word(0xabcd) }),
|
(vec![0x5e, 0xcd, 0xab], Instruction { op: LSR, mode: AbsoluteX, operand: Operand::Word(0xabcd) }),
|
||||||
// NOP
|
// NOP
|
||||||
(vec![0xea], Instruction { op: NOP, mode: Implied, operand: Operand::None }),
|
(vec![0xea], Instruction { op: NOP, mode: Implied, operand: Operand::None }),
|
||||||
// ORA
|
// ORA
|
||||||
@ -178,13 +183,13 @@ mod test {
|
|||||||
(vec![0x68], Instruction { op: PLA, mode: Implied, operand: Operand::None }),
|
(vec![0x68], Instruction { op: PLA, mode: Implied, operand: Operand::None }),
|
||||||
(vec![0x28], Instruction { op: PLP, mode: Implied, operand: Operand::None }),
|
(vec![0x28], Instruction { op: PLP, mode: Implied, operand: Operand::None }),
|
||||||
// ROL
|
// ROL
|
||||||
(vec![0x2a, 0xab], Instruction { op: ROL, mode: Accumulator, operand: Operand::Byte(0xab) }),
|
(vec![0x2a], Instruction { op: ROL, mode: Accumulator, operand: Operand::None }),
|
||||||
(vec![0x26, 0xab], Instruction { op: ROL, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
(vec![0x26, 0xab], Instruction { op: ROL, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x36, 0xab], Instruction { op: ROL, mode: ZeroPageX, operand: Operand::Byte(0xab) }),
|
(vec![0x36, 0xab], Instruction { op: ROL, mode: ZeroPageX, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x2e, 0xcd, 0xab], Instruction { op: ROL, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
(vec![0x2e, 0xcd, 0xab], Instruction { op: ROL, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
||||||
(vec![0x3e, 0xcd, 0xab], Instruction { op: ROL, mode: AbsoluteX, operand: Operand::Word(0xabcd) }),
|
(vec![0x3e, 0xcd, 0xab], Instruction { op: ROL, mode: AbsoluteX, operand: Operand::Word(0xabcd) }),
|
||||||
// ROR
|
// ROR
|
||||||
(vec![0x6a, 0xab], Instruction { op: ROR, mode: Accumulator, operand: Operand::Byte(0xab) }),
|
(vec![0x6a], Instruction { op: ROR, mode: Accumulator, operand: Operand::None }),
|
||||||
(vec![0x66, 0xab], Instruction { op: ROR, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
(vec![0x66, 0xab], Instruction { op: ROR, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x76, 0xab], Instruction { op: ROR, mode: ZeroPageX, operand: Operand::Byte(0xab) }),
|
(vec![0x76, 0xab], Instruction { op: ROR, mode: ZeroPageX, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x6e, 0xcd, 0xab], Instruction { op: ROR, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
(vec![0x6e, 0xcd, 0xab], Instruction { op: ROR, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
||||||
@ -215,7 +220,7 @@ mod test {
|
|||||||
(vec![0x91, 0xab], Instruction { op: STA, mode: IndirectY, operand: Operand::Byte(0xab) }),
|
(vec![0x91, 0xab], Instruction { op: STA, mode: IndirectY, operand: Operand::Byte(0xab) }),
|
||||||
// STX
|
// STX
|
||||||
(vec![0x86, 0xab], Instruction { op: STX, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
(vec![0x86, 0xab], Instruction { op: STX, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x96, 0xab], Instruction { op: STX, mode: ZeroPageX, operand: Operand::Byte(0xab) }),
|
(vec![0x96, 0xab], Instruction { op: STX, mode: ZeroPageY, operand: Operand::Byte(0xab) }),
|
||||||
(vec![0x8e, 0xcd, 0xab], Instruction { op: STX, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
(vec![0x8e, 0xcd, 0xab], Instruction { op: STX, mode: Absolute, operand: Operand::Word(0xabcd) }),
|
||||||
// STY
|
// STY
|
||||||
(vec![0x84, 0xab], Instruction { op: STY, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
(vec![0x84, 0xab], Instruction { op: STY, mode: ZeroPage, operand: Operand::Byte(0xab) }),
|
||||||
@ -230,13 +235,12 @@ mod test {
|
|||||||
(vec![0x98], Instruction { op: TYA, mode: Implied, operand: Operand::None })
|
(vec![0x98], Instruction { op: TYA, mode: Implied, operand: Operand::None })
|
||||||
];
|
];
|
||||||
for (bytes, instruction) in params {
|
for (bytes, instruction) in params {
|
||||||
let result = Instruction::decode(&bytes);
|
let result1 = Instruction::decode(&bytes);
|
||||||
if let Some(instruction) = result {
|
if let Some(instruction1) = result1 {
|
||||||
assert_eq!(Instruction::decode(&bytes).unwrap(), instruction)
|
assert_eq!(instruction, instruction1)
|
||||||
} else {
|
} else {
|
||||||
println!("Failed to decode {:?}", bytes);
|
println!("Failed to decode {:?}", bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -256,13 +256,13 @@ pub const INSTRUCTION_TABLE: [Option<OpInfo>; 256] = {
|
|||||||
table[ISA_OP_CMP_ABSX as usize] = Some(OpInfo {
|
table[ISA_OP_CMP_ABSX as usize] = Some(OpInfo {
|
||||||
operation: CMP,
|
operation: CMP,
|
||||||
mode: AddressMode::AbsoluteX,
|
mode: AddressMode::AbsoluteX,
|
||||||
length: 2,
|
length: 3,
|
||||||
cycles: 4,
|
cycles: 4,
|
||||||
});
|
});
|
||||||
table[ISA_OP_CMP_ABSY as usize] = Some(OpInfo {
|
table[ISA_OP_CMP_ABSY as usize] = Some(OpInfo {
|
||||||
operation: CMP,
|
operation: CMP,
|
||||||
mode: AddressMode::AbsoluteY,
|
mode: AddressMode::AbsoluteY,
|
||||||
length: 2,
|
length: 3,
|
||||||
cycles: 4,
|
cycles: 4,
|
||||||
});
|
});
|
||||||
table[ISA_OP_CMP_INDX as usize] = Some(OpInfo {
|
table[ISA_OP_CMP_INDX as usize] = Some(OpInfo {
|
||||||
|
|||||||
@ -1,11 +1,17 @@
|
|||||||
|
use crate::address_mode::AddressMode;
|
||||||
|
use crate::instruction::Instruction;
|
||||||
use crate::mos6502flags::{Mos6502Flag, Mos6502Flags};
|
use crate::mos6502flags::{Mos6502Flag, Mos6502Flags};
|
||||||
|
use crate::operand::Operand;
|
||||||
|
use crate::operation::Operation;
|
||||||
|
use crate::operation::Operation::NOP;
|
||||||
|
|
||||||
pub const SIZE_1KB: usize = 1024 * 1024;
|
pub const SIZE_1KB: usize = 1024 * 1024;
|
||||||
pub const SIZE_32KB: usize = SIZE_1KB * 32;
|
pub const SIZE_32KB: usize = SIZE_1KB * 32;
|
||||||
pub const SIZE_64KB: usize = SIZE_1KB * 64;
|
pub const SIZE_64KB: usize = SIZE_1KB * 64;
|
||||||
|
|
||||||
pub struct Mos6502Cpu {
|
pub struct Mos6502Cpu {
|
||||||
memory: [u8; SIZE_64KB],
|
// this is public for rendering quickly.
|
||||||
|
pub memory: Box<[u8]>,
|
||||||
a: u8,
|
a: u8,
|
||||||
x: u8,
|
x: u8,
|
||||||
y: u8,
|
y: u8,
|
||||||
@ -13,33 +19,44 @@ pub struct Mos6502Cpu {
|
|||||||
pc: u16,
|
pc: u16,
|
||||||
s: u8,
|
s: u8,
|
||||||
pub microcode_step: u8,
|
pub microcode_step: u8,
|
||||||
address_bus: u16,
|
pub address_bus: u16,
|
||||||
data_bus: u8,
|
pub data_bus: u8,
|
||||||
ir: u8 // Instruction Register
|
ir: Instruction // Instruction Register
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Mos6502Cpu {
|
impl Default for Mos6502Cpu {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let vec = vec![0x00; SIZE_64KB];
|
||||||
|
let boxed_slize: Box<[u8]> = vec.into_boxed_slice();
|
||||||
|
let boxed_array: Box<[u8; SIZE_64KB]> = boxed_slize.try_into().expect("Failed to allocate system memory");
|
||||||
|
|
||||||
Mos6502Cpu {
|
Mos6502Cpu {
|
||||||
memory: [0x00; SIZE_64KB],
|
memory: boxed_array,
|
||||||
a: 0,
|
a: 0,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
flags: Default::default(),
|
flags: Default::default(),
|
||||||
pc: 0,
|
pc: 0xfffd,
|
||||||
s: 0,
|
s: 0,
|
||||||
microcode_step: 0,
|
microcode_step: 0,
|
||||||
address_bus: 0,
|
address_bus: 0,
|
||||||
data_bus: 0,
|
data_bus: 0,
|
||||||
ir: 0x00
|
ir: Instruction {
|
||||||
|
op: Operation::NOP,
|
||||||
|
mode: AddressMode::Implied,
|
||||||
|
operand: Operand::None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mos6502Cpu {
|
impl Mos6502Cpu {
|
||||||
pub fn new() -> Mos6502Cpu {
|
pub fn new() -> Mos6502Cpu {
|
||||||
|
let vec = vec![0x00; SIZE_64KB];
|
||||||
|
let boxed_slize: Box<[u8]> = vec.into_boxed_slice();
|
||||||
|
let boxed_array: Box<[u8; SIZE_64KB]> = boxed_slize.try_into().expect("Failed to allocate system memory");
|
||||||
Mos6502Cpu {
|
Mos6502Cpu {
|
||||||
memory: [0; SIZE_64KB],
|
memory: boxed_array,
|
||||||
a: 0,
|
a: 0,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
@ -49,7 +66,11 @@ impl Mos6502Cpu {
|
|||||||
microcode_step: 0,
|
microcode_step: 0,
|
||||||
address_bus: 0x0000,
|
address_bus: 0x0000,
|
||||||
data_bus: 0x00,
|
data_bus: 0x00,
|
||||||
ir: 0x00
|
ir: Instruction {
|
||||||
|
op: Operation::NOP,
|
||||||
|
mode: AddressMode::Implied,
|
||||||
|
operand: Operand::None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +116,21 @@ impl Mos6502Cpu {
|
|||||||
/// Returns
|
/// Returns
|
||||||
/// AddressBus, DataBus, RW flag
|
/// AddressBus, DataBus, RW flag
|
||||||
pub fn tick(&mut self) -> (u16, u8, bool) {
|
pub fn tick(&mut self) -> (u16, u8, bool) {
|
||||||
|
|
||||||
|
println!("PREPARiNG TO TICK CPU AT {:04x}", self.pc);
|
||||||
|
|
||||||
|
let mut num_microsteps_left = 0;
|
||||||
|
|
||||||
|
if num_microsteps_left == 0 {
|
||||||
|
println!("OUT OF MICROSTEPS. Time To do something that isnt microstep.");
|
||||||
|
// load the microstep buffer with what steps to run
|
||||||
|
// set the counter to the number of steps left
|
||||||
|
} else {
|
||||||
|
// run 1 microcode step
|
||||||
|
println!("Microstep {num_microsteps_left}");
|
||||||
|
num_microsteps_left -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
(0,0,false)
|
(0,0,false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,5 +139,11 @@ impl Mos6502Cpu {
|
|||||||
self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus);
|
self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dump_data(&self) -> ( u16, u8, u8, u8, u16, u8) {
|
||||||
|
(self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_microstep(&self, instruction: Instruction, step: u8) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::mos6502cpu::SIZE_32KB;
|
use crate::mos6502cpu::{SIZE_32KB};
|
||||||
use crate::periph::rom_chip::RomChip;
|
use crate::periph::rom_chip::RomChip;
|
||||||
|
|
||||||
/// At28C256
|
/// At28C256
|
||||||
@ -8,24 +8,37 @@ use crate::periph::rom_chip::RomChip;
|
|||||||
/// 256kbit storage
|
/// 256kbit storage
|
||||||
/// 32kbyte storage
|
/// 32kbyte storage
|
||||||
pub struct At28C256 {
|
pub struct At28C256 {
|
||||||
data: [u8; SIZE_32KB]
|
data: Box<[u8; SIZE_32KB]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for At28C256 {
|
||||||
|
fn default() -> Self {
|
||||||
|
let vec = vec![0x00; SIZE_32KB];
|
||||||
|
let boxed_slice: Box<[u8]> = vec.into_boxed_slice();
|
||||||
|
let boxed_array: Box<[u8; SIZE_32KB]> = boxed_slice.try_into().expect("Failed to convert Vec to boxed array");
|
||||||
|
At28C256 {
|
||||||
|
data: boxed_array,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RomChip for At28C256 {
|
impl RomChip for At28C256 {
|
||||||
|
|
||||||
fn read(&self, offset: &u16) -> u8 {
|
fn read(&self, offset: &u16) -> u8 {
|
||||||
self.data[*offset as usize]
|
self.data[*offset as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn program(new_data: &[u8; SIZE_32KB]) -> Self {
|
fn program(new_data: Box<[u8; 33554432]>) -> Box<At28C256> {
|
||||||
println!("Writing new chip.");
|
println!("Writing new chip.");
|
||||||
At28C256 {
|
let mut working = At28C256::default();
|
||||||
data: *new_data
|
working.data = Box::new(*new_data);
|
||||||
}
|
working.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use crate::mos6502cpu::SIZE_1KB;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -35,18 +48,14 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn programmed_data_reads_back_same() {
|
fn programmed_data_reads_back_same() {
|
||||||
print!("Starting test...");
|
let mut data = At28C256::default();
|
||||||
let data_to_write = [0xea; SIZE_32KB];
|
for i in 0..SIZE_32KB {
|
||||||
print!("allocated data for rom...");
|
data.data[i] = 0xea;
|
||||||
let chip: At28C256 = At28C256::program(&data_to_write);
|
}
|
||||||
println!("programmed chip...");
|
for offset in 0..SIZE_32KB {
|
||||||
print!("testing");
|
if offset.is_multiple_of(SIZE_1KB) {
|
||||||
for offset in 0..SIZE_32KB {
|
};
|
||||||
if offset.is_multiple_of(1000) {
|
assert_eq!(0xea, data.read(&(offset as u16)));
|
||||||
print!(".");
|
|
||||||
};
|
|
||||||
assert_eq!(0xea, chip.read(&(offset as u16)));
|
|
||||||
}
|
}
|
||||||
println!("passed!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
88
core/src/periph/hm62256.rs
Normal file
88
core/src/periph/hm62256.rs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// HM62256 Static Ram
|
||||||
|
|
||||||
|
use log::debug;
|
||||||
|
use crate::mos6502cpu::SIZE_32KB;
|
||||||
|
use crate::periph::ram_chip::RamChip;
|
||||||
|
use crate::periph::rom_chip::RomChip;
|
||||||
|
|
||||||
|
struct Hm62256 {
|
||||||
|
base_offset: u16,
|
||||||
|
data: Box<[u8]>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Hm62256 {
|
||||||
|
fn default() -> Self {
|
||||||
|
let vec = vec![0x00; SIZE_32KB];
|
||||||
|
let boxed_slice: Box<[u8]> = vec.into_boxed_slice();
|
||||||
|
let boxed_array: Box<[u8; SIZE_32KB]> = boxed_slice.try_into().expect("Unable to box the ram");
|
||||||
|
Hm62256 {
|
||||||
|
base_offset: 0x0000,
|
||||||
|
data: boxed_array
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RomChip for Hm62256 {
|
||||||
|
fn read(&self, offset: &u16) -> u8 {
|
||||||
|
//println!("READING FROM RAM AT [{offset:04x}]");
|
||||||
|
self.data[*offset as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn program(_: Box<[u8; SIZE_32KB]>) -> Box<Self> {
|
||||||
|
debug!("Dont program ram.");
|
||||||
|
Hm62256::default().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RamChip for Hm62256 {
|
||||||
|
fn write(&mut self, offset: &u16, value: &u8) {
|
||||||
|
let effective = *offset as i32 % SIZE_32KB as i32;
|
||||||
|
println!("Writing at E[{effective:04x}] / O[{offset:04x}]");
|
||||||
|
self.data[effective as usize] = *value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use rand::random;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,6 @@
|
|||||||
pub mod rom_chip;
|
pub mod rom_chip;
|
||||||
|
|
||||||
pub mod at28c256;
|
pub mod at28c256;
|
||||||
|
pub mod ram_chip;
|
||||||
|
mod hm62256;
|
||||||
|
|
||||||
|
|||||||
5
core/src/periph/ram_chip.rs
Normal file
5
core/src/periph/ram_chip.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
use crate::periph::rom_chip::RomChip;
|
||||||
|
|
||||||
|
pub trait RamChip: RomChip {
|
||||||
|
fn write(&mut self, offset: &u16, value: &u8);
|
||||||
|
}
|
||||||
@ -8,10 +8,5 @@ pub trait RomChip {
|
|||||||
/// Program
|
/// Program
|
||||||
///
|
///
|
||||||
/// Replaces all data in the ROM chip
|
/// Replaces all data in the ROM chip
|
||||||
fn program(new_data: &[u8; SIZE_32KB]) -> Self;
|
fn program(new_data: Box<[u8; SIZE_32KB]>) -> Box<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RamChip: RomChip {
|
|
||||||
fn write(&mut self, offset: &u16, value: &u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user