Initial commit
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
3290
Cargo.lock
generated
Normal file
21
Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "altair_emu"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bitflags = "2.3.3"
|
||||
device_query = "1.1.3"
|
||||
eframe = { version = "0.22.0", features = ["ron", "persistence"] }
|
||||
egui-modal = "0.2.4"
|
||||
enum_dispatch = "0.3.12"
|
||||
env_logger = "0.10.0"
|
||||
image = "0.24.6"
|
||||
log = "0.4.19"
|
||||
parking_lot = "0.12.1"
|
||||
rand = "0.8.5"
|
||||
ron = "0.8.0"
|
||||
serde = { version = "1.0.171", features = ["derive"] }
|
||||
soloud = "1.0.2"
|
BIN
resources/Altair.png
Normal file
After Width: | Height: | Size: 480 B |
BIN
resources/Diskdrive.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
resources/Led_off.png
Normal file
After Width: | Height: | Size: 479 B |
BIN
resources/Led_on.png
Normal file
After Width: | Height: | Size: 474 B |
BIN
resources/Togdown.png
Normal file
After Width: | Height: | Size: 436 B |
BIN
resources/Togneut.png
Normal file
After Width: | Height: | Size: 397 B |
BIN
resources/Togup.png
Normal file
After Width: | Height: | Size: 423 B |
BIN
resources/altair800.png
Normal file
After Width: | Height: | Size: 196 KiB |
BIN
resources/blk_dn.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
resources/blk_up.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
resources/bot.png
Normal file
After Width: | Height: | Size: 362 B |
BIN
resources/cass_40.png
Normal file
After Width: | Height: | Size: 235 KiB |
BIN
resources/click.wav
Normal file
BIN
resources/click2.wav
Normal file
BIN
resources/digits.png
Normal file
After Width: | Height: | Size: 926 B |
BIN
resources/ding.wav
Normal file
BIN
resources/disk_ins.png
Normal file
After Width: | Height: | Size: 409 B |
BIN
resources/disk_rmv.png
Normal file
After Width: | Height: | Size: 502 B |
BIN
resources/doorCLOSE.wav
Normal file
BIN
resources/doorOPEN.wav
Normal file
BIN
resources/doorclosed.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
resources/dooropen.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
resources/fan.wav
Normal file
BIN
resources/fan1.wav
Normal file
BIN
resources/fan2.wav
Normal file
BIN
resources/fan3.wav
Normal file
BIN
resources/ff.png
Normal file
After Width: | Height: | Size: 368 B |
BIN
resources/greenbar.png
Normal file
After Width: | Height: | Size: 108 KiB |
BIN
resources/head_step.wav
Normal file
BIN
resources/lpplaten.png
Normal file
After Width: | Height: | Size: 165 KiB |
BIN
resources/play.png
Normal file
After Width: | Height: | Size: 354 B |
BIN
resources/rec.png
Normal file
After Width: | Height: | Size: 355 B |
BIN
resources/red_dn.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
resources/red_up.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
resources/rew.png
Normal file
After Width: | Height: | Size: 364 B |
BIN
resources/rled_off.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
resources/rled_on.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
resources/stop.png
Normal file
After Width: | Height: | Size: 373 B |
32
src/card.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use eframe::egui;
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use crate::ram::RamCard;
|
||||
|
||||
#[enum_dispatch(CardEnum)]
|
||||
pub enum CardEnum {
|
||||
RamCard
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[enum_dispatch]
|
||||
pub trait Card {
|
||||
fn new(_settings: ron::Value) -> CardEnum;
|
||||
|
||||
fn read_mem(&mut self, _address: u16) -> Option<u8> {
|
||||
None
|
||||
}
|
||||
fn write_mem(&mut self, _address: u16, _data: u8) -> Option<()> {
|
||||
None
|
||||
}
|
||||
fn read_io(&mut self, _address: u8) -> Option<u8> {
|
||||
None
|
||||
}
|
||||
fn write_io(&mut self, _address: u8, _data: u8) -> Option<()> {
|
||||
None
|
||||
}
|
||||
fn draw_settings_ui(&mut self, _ui: egui::Ui) {}
|
||||
fn serialize_settings(&self) -> String;
|
||||
}
|
||||
|
||||
|
602
src/cpu.rs
Normal file
@ -0,0 +1,602 @@
|
||||
mod opcode;
|
||||
mod opcode_table;
|
||||
|
||||
use std::{
|
||||
fmt::Display,
|
||||
ops::{Index, IndexMut},
|
||||
};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use opcode_table::OPCODE_TABLE;
|
||||
|
||||
use self::opcode::{Opcode, Register, RegisterPair};
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Status: u8 {
|
||||
const INTA = 0x1;
|
||||
const WO = 0x2;
|
||||
const STACK = 0x4;
|
||||
const HLTA = 0x8;
|
||||
const OUT = 0x10;
|
||||
const M1 = 0x20;
|
||||
const INP = 0x40;
|
||||
const MEMR = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum MemCycle {
|
||||
Fetch(u16),
|
||||
Read(u16),
|
||||
Write(u16, u8),
|
||||
StackRead(u16),
|
||||
StackWrite(u16, u8),
|
||||
In(u16),
|
||||
Out(u16, u8),
|
||||
#[allow(unused)]
|
||||
Inta(u16),
|
||||
Hlta(u16),
|
||||
#[allow(unused)]
|
||||
IntaHlt(u16),
|
||||
}
|
||||
|
||||
impl MemCycle {
|
||||
pub fn get_status(self) -> Status {
|
||||
match self {
|
||||
Self::Fetch(_) => Status::WO | Status::M1 | Status::MEMR,
|
||||
Self::Read(_) => Status::WO | Status::MEMR,
|
||||
Self::Write(_, _) => Status::empty(),
|
||||
Self::StackRead(_) => Status::WO | Status::MEMR | Status::STACK,
|
||||
Self::StackWrite(_, _) => Status::STACK,
|
||||
Self::In(_) => Status::WO | Status::INP,
|
||||
Self::Out(_, _) => Status::OUT,
|
||||
Self::Inta(_) => Status::INTA | Status::WO | Status::M1,
|
||||
Self::Hlta(_) => Status::HLTA | Status::WO | Status::M1,
|
||||
Self::IntaHlt(_) => Status::INTA | Status::HLTA | Status::WO | Status::M1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn address(self) -> u16 {
|
||||
match self {
|
||||
Self::Fetch(a) => a,
|
||||
Self::Read(a) => a,
|
||||
Self::Write(a, _) => a,
|
||||
Self::StackRead(a) => a,
|
||||
Self::StackWrite(a, _) => a,
|
||||
Self::In(a) => a,
|
||||
Self::Out(a, _) => a,
|
||||
Self::Inta(a) => a,
|
||||
Self::Hlta(a) => a,
|
||||
Self::IntaHlt(a) => a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum MCycle {
|
||||
M1,
|
||||
M2,
|
||||
M3,
|
||||
M4,
|
||||
M5,
|
||||
}
|
||||
|
||||
impl MCycle {
|
||||
fn next(self) -> Self {
|
||||
match self {
|
||||
Self::M1 => Self::M2,
|
||||
Self::M2 => Self::M3,
|
||||
Self::M3 => Self::M4,
|
||||
Self::M4 => Self::M5,
|
||||
Self::M5 => panic!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for MCycle {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::M1 => f.write_str("M1"),
|
||||
Self::M2 => f.write_str("M2"),
|
||||
Self::M3 => f.write_str("M3"),
|
||||
Self::M4 => f.write_str("M4"),
|
||||
Self::M5 => f.write_str("M5"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct RegisterFile {
|
||||
b: u8,
|
||||
c: u8,
|
||||
d: u8,
|
||||
e: u8,
|
||||
h: u8,
|
||||
l: u8,
|
||||
a: u8,
|
||||
}
|
||||
|
||||
impl RegisterFile {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
b: rand::random(),
|
||||
c: rand::random(),
|
||||
d: rand::random(),
|
||||
e: rand::random(),
|
||||
h: rand::random(),
|
||||
l: rand::random(),
|
||||
a: rand::random(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<Register> for RegisterFile {
|
||||
type Output = u8;
|
||||
|
||||
fn index(&self, index: Register) -> &Self::Output {
|
||||
match index {
|
||||
Register::B => &self.b,
|
||||
Register::C => &self.c,
|
||||
Register::D => &self.d,
|
||||
Register::E => &self.e,
|
||||
Register::H => &self.h,
|
||||
Register::L => &self.l,
|
||||
Register::A => &self.a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<Register> for RegisterFile {
|
||||
fn index_mut(&mut self, index: Register) -> &mut Self::Output {
|
||||
match index {
|
||||
Register::B => &mut self.b,
|
||||
Register::C => &mut self.c,
|
||||
Register::D => &mut self.d,
|
||||
Register::E => &mut self.e,
|
||||
Register::H => &mut self.h,
|
||||
Register::L => &mut self.l,
|
||||
Register::A => &mut self.a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RegisterFile {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct I8080 {
|
||||
pc: u16,
|
||||
regs: RegisterFile,
|
||||
sp: u16,
|
||||
#[allow(unused)]
|
||||
sign: bool,
|
||||
#[allow(unused)]
|
||||
zero: bool,
|
||||
#[allow(unused)]
|
||||
parity: bool,
|
||||
#[allow(unused)]
|
||||
carry: bool,
|
||||
#[allow(unused)]
|
||||
aux_carry: bool,
|
||||
cycle: MCycle,
|
||||
opcode: Opcode,
|
||||
w: u8,
|
||||
z: u8,
|
||||
tmp: u8,
|
||||
halted: bool,
|
||||
}
|
||||
|
||||
impl Display for I8080 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!(
|
||||
"PC: {:#x} A: {:#x}, B: {:#x}, C: {:#x}, D: {:#x}, E: {:#x}, H: {:#x}, L: {:#x}, SP: {:#x}",
|
||||
self.pc,
|
||||
self.regs.a,
|
||||
self.regs.b,
|
||||
self.regs.c,
|
||||
self.regs.d,
|
||||
self.regs.e,
|
||||
self.regs.h,
|
||||
self.regs.l,
|
||||
self.sp
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl I8080 {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
pc: rand::random(),
|
||||
regs: RegisterFile::new(),
|
||||
sp: rand::random(),
|
||||
sign: rand::random(),
|
||||
zero: rand::random(),
|
||||
parity: rand::random(),
|
||||
carry: rand::random(),
|
||||
aux_carry: rand::random(),
|
||||
cycle: MCycle::M1,
|
||||
opcode: Opcode::Nop,
|
||||
w: rand::random(),
|
||||
z: rand::random(),
|
||||
tmp: rand::random(),
|
||||
halted: rand::random(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.pc = 0;
|
||||
self.halted = false;
|
||||
}
|
||||
|
||||
pub fn get_mem_cycle(&self) -> MemCycle {
|
||||
if self.halted {
|
||||
return MemCycle::Hlta(self.pc);
|
||||
};
|
||||
match self.cycle {
|
||||
MCycle::M1 => MemCycle::Fetch(self.pc),
|
||||
MCycle::M2 => match self.opcode {
|
||||
Opcode::MovMR(src) => {
|
||||
MemCycle::Write(self.get_pair(RegisterPair::HL), self.regs[src])
|
||||
}
|
||||
Opcode::MovRM(_) => MemCycle::Read(self.get_pair(RegisterPair::HL)),
|
||||
Opcode::Mvi(_) => MemCycle::Read(self.pc),
|
||||
Opcode::Lxi(_) => MemCycle::Read(self.pc),
|
||||
Opcode::Lda => MemCycle::Read(self.pc),
|
||||
Opcode::Sta => MemCycle::Read(self.pc),
|
||||
Opcode::Lhld => MemCycle::Read(self.pc),
|
||||
Opcode::Shld => MemCycle::Read(self.pc),
|
||||
Opcode::Ldax(rp) => MemCycle::Read(self.get_pair(rp)),
|
||||
Opcode::Stax(rp) => MemCycle::Read(self.get_pair(rp)),
|
||||
Opcode::Add(_) => MemCycle::Read(self.get_pair(RegisterPair::HL)),
|
||||
Opcode::Adi => MemCycle::Read(self.pc),
|
||||
Opcode::Adc(_) => MemCycle::Read(self.get_pair(RegisterPair::HL)),
|
||||
Opcode::Aci => MemCycle::Read(self.pc),
|
||||
Opcode::Sub(_) => MemCycle::Read(self.get_pair(RegisterPair::HL)),
|
||||
Opcode::Sui => MemCycle::Read(self.pc),
|
||||
Opcode::Sbb(_) => MemCycle::Read(self.get_pair(RegisterPair::HL)),
|
||||
Opcode::Sbi => MemCycle::Read(self.pc),
|
||||
Opcode::Inr(_) => MemCycle::Read(self.get_pair(RegisterPair::HL)),
|
||||
Opcode::Dcr(_) => MemCycle::Read(self.get_pair(RegisterPair::HL)),
|
||||
Opcode::Ana(_) => MemCycle::Read(self.get_pair(RegisterPair::HL)),
|
||||
Opcode::Ani => MemCycle::Read(self.pc),
|
||||
Opcode::Xra(_) => MemCycle::Read(self.get_pair(RegisterPair::HL)),
|
||||
Opcode::Xri => MemCycle::Read(self.pc),
|
||||
Opcode::Ora(_) => MemCycle::Read(self.get_pair(RegisterPair::HL)),
|
||||
Opcode::Ori => MemCycle::Read(self.pc),
|
||||
Opcode::Cmp(_) => MemCycle::Read(self.get_pair(RegisterPair::HL)),
|
||||
Opcode::Cpi => MemCycle::Read(self.pc),
|
||||
Opcode::Jmp => MemCycle::Read(self.pc),
|
||||
Opcode::Jcc(_) => MemCycle::Read(self.pc),
|
||||
Opcode::Call => MemCycle::Read(self.pc),
|
||||
Opcode::Ccc(_) => MemCycle::Read(self.pc),
|
||||
Opcode::Ret => MemCycle::Read(self.sp),
|
||||
Opcode::Rcc(_) => MemCycle::StackRead(self.sp),
|
||||
Opcode::Rst(_) => MemCycle::StackWrite(self.sp, (self.pc >> 8) as u8),
|
||||
Opcode::Push(_) => MemCycle::StackRead(self.sp),
|
||||
Opcode::Pop(_) => MemCycle::StackRead(self.sp),
|
||||
Opcode::Xthl => MemCycle::StackRead(self.sp),
|
||||
Opcode::In => MemCycle::Read(self.pc),
|
||||
Opcode::Out => MemCycle::Read(self.pc),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
MCycle::M3 => match self.opcode {
|
||||
Opcode::Mvi(_) => MemCycle::Write(self.get_pair(RegisterPair::HL), self.tmp),
|
||||
Opcode::Lxi(_) => MemCycle::Read(self.pc),
|
||||
Opcode::Lda => MemCycle::Read(self.pc),
|
||||
Opcode::Sta => MemCycle::Read(self.pc),
|
||||
Opcode::Lhld => MemCycle::Read(self.pc),
|
||||
Opcode::Shld => MemCycle::Read(self.pc),
|
||||
Opcode::Inr(_) => MemCycle::Write(self.get_pair(RegisterPair::HL), self.tmp),
|
||||
Opcode::Dcr(_) => MemCycle::Write(self.get_pair(RegisterPair::HL), self.tmp),
|
||||
Opcode::Jmp => MemCycle::Read(self.pc),
|
||||
Opcode::Jcc(_) => MemCycle::Read(self.pc),
|
||||
Opcode::Call => MemCycle::Read(self.pc),
|
||||
Opcode::Ccc(_) => MemCycle::Read(self.pc),
|
||||
Opcode::Ret => MemCycle::StackRead(self.sp),
|
||||
Opcode::Rcc(_) => MemCycle::StackRead(self.sp),
|
||||
Opcode::Rst(_) => MemCycle::StackWrite(self.sp, 0),
|
||||
Opcode::Xthl => MemCycle::StackRead(self.sp),
|
||||
Opcode::In => MemCycle::In(self.get_wz()),
|
||||
Opcode::Out => MemCycle::Out(self.get_wz(), self.regs.a),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
MCycle::M4 => match self.opcode {
|
||||
Opcode::Lda => MemCycle::Read(self.get_wz()),
|
||||
Opcode::Sta => MemCycle::Write(self.get_wz(), self.regs.a),
|
||||
Opcode::Lhld => MemCycle::Read(self.get_wz()),
|
||||
Opcode::Shld => MemCycle::Write(self.get_wz(), self.regs.l),
|
||||
Opcode::Call => MemCycle::StackWrite(self.sp, (self.pc >> 8) as u8),
|
||||
Opcode::Ccc(_) => MemCycle::StackWrite(self.sp, (self.pc >> 8) as u8),
|
||||
Opcode::Xthl => MemCycle::StackWrite(self.sp, self.regs.h),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
MCycle::M5 => match self.opcode {
|
||||
Opcode::Lhld => MemCycle::Read(self.get_wz()),
|
||||
Opcode::Shld => MemCycle::Write(self.get_wz(), self.regs.h),
|
||||
Opcode::Call => MemCycle::StackWrite(self.sp, self.pc as u8),
|
||||
Opcode::Ccc(_) => MemCycle::StackWrite(self.sp, self.pc as u8),
|
||||
Opcode::Xthl => MemCycle::StackWrite(self.sp, self.regs.l),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn finish_m_cycle(&mut self, data: u8) {
|
||||
if self.halted {
|
||||
return;
|
||||
}
|
||||
println!(
|
||||
"Finish {} ({:?}), got data {}",
|
||||
self.cycle,
|
||||
self.get_mem_cycle(),
|
||||
data
|
||||
);
|
||||
match self.cycle {
|
||||
MCycle::M1 => {
|
||||
self.pc += 1;
|
||||
self.opcode = OPCODE_TABLE[data as usize];
|
||||
dbg!(self.opcode);
|
||||
match self.opcode {
|
||||
Opcode::MovMR(_) => (),
|
||||
Opcode::MovRM(_) => (),
|
||||
Opcode::Mov(dst, src) => {
|
||||
self.regs[dst] = self.regs[src];
|
||||
}
|
||||
Opcode::Sphl => {
|
||||
self.sp = ((self.regs.h as u16) << 8) | (self.regs.l as u16);
|
||||
}
|
||||
Opcode::MviM => (),
|
||||
Opcode::Mvi(_) => (),
|
||||
Opcode::Lxi(_) => (),
|
||||
Opcode::Lda => (),
|
||||
Opcode::Sta => (),
|
||||
Opcode::Lhld => (),
|
||||
Opcode::Shld => (),
|
||||
Opcode::Ldax(_) => (),
|
||||
Opcode::Stax(_) => (),
|
||||
Opcode::Xchg => {
|
||||
(self.regs.d, self.regs.e, self.regs.h, self.regs.l) =
|
||||
(self.regs.h, self.regs.l, self.regs.d, self.regs.e);
|
||||
}
|
||||
Opcode::AddM => (),
|
||||
Opcode::Add(src) => {
|
||||
let a = self.regs.a;
|
||||
let b = self.regs[src];
|
||||
let res = (a as u16) + (b as u16);
|
||||
self.sign = ((res as u8) & 0x80) > 0;
|
||||
self.zero = (res as u8) == 0;
|
||||
self.aux_carry = (a & 0x0f) + (b & 0x0f) > 0x0f;
|
||||
self.parity = (res as u8).count_ones() % 2 == 0;
|
||||
self.carry = res > 0xff;
|
||||
self.regs.a = res as u8;
|
||||
}
|
||||
Opcode::Adi => (),
|
||||
Opcode::AdcM => (),
|
||||
Opcode::Adc(_) => todo!(),
|
||||
Opcode::Aci => (),
|
||||
Opcode::SubM => (),
|
||||
Opcode::Sub(_) => todo!(),
|
||||
Opcode::Sui => (),
|
||||
Opcode::SbbM => (),
|
||||
Opcode::Sbb(_) => todo!(),
|
||||
Opcode::Sbi => (),
|
||||
Opcode::InrM => (),
|
||||
Opcode::Inr(_) => todo!(),
|
||||
Opcode::DcrM => (),
|
||||
Opcode::Dcr(_) => todo!(),
|
||||
Opcode::Inx(dst) => self.set_pair(dst, self.get_pair(dst) + 1),
|
||||
Opcode::Dcx(dst) => self.set_pair(dst, self.get_pair(dst) + 2),
|
||||
Opcode::Dad(src) => {
|
||||
let a = self.get_pair(RegisterPair::HL) as u32;
|
||||
let b = self.get_pair(src) as u32;
|
||||
let res = a + b;
|
||||
self.carry = res > 0xffff;
|
||||
self.set_pair(RegisterPair::HL, res as u16);
|
||||
}
|
||||
Opcode::Daa => todo!(),
|
||||
Opcode::AnaM => (),
|
||||
Opcode::Ana(_) => todo!(),
|
||||
Opcode::Ani => (),
|
||||
Opcode::XraM => (),
|
||||
Opcode::Xra(_) => todo!(),
|
||||
Opcode::Xri => (),
|
||||
Opcode::OraM => (),
|
||||
Opcode::Ora(_) => todo!(),
|
||||
Opcode::Ori => (),
|
||||
Opcode::CmpM => (),
|
||||
Opcode::Cmp(_) => todo!(),
|
||||
Opcode::Cpi => (),
|
||||
Opcode::Rlc => todo!(),
|
||||
Opcode::Rrc => todo!(),
|
||||
Opcode::Ral => todo!(),
|
||||
Opcode::Rar => todo!(),
|
||||
Opcode::Cma => todo!(),
|
||||
Opcode::Cmc => todo!(),
|
||||
Opcode::Stc => todo!(),
|
||||
Opcode::Jmp => (),
|
||||
Opcode::Jcc(_) => todo!(),
|
||||
Opcode::Call => todo!(),
|
||||
Opcode::Ccc(_) => todo!(),
|
||||
Opcode::Ret => (),
|
||||
Opcode::Rcc(_) => todo!(),
|
||||
Opcode::Rst(_) => todo!(),
|
||||
Opcode::Pchl => todo!(),
|
||||
Opcode::Push(_) => todo!(),
|
||||
Opcode::Pop(_) => (),
|
||||
Opcode::Xthl => (),
|
||||
Opcode::In => (),
|
||||
Opcode::Out => (),
|
||||
Opcode::Ei => todo!(),
|
||||
Opcode::Di => todo!(),
|
||||
Opcode::Hlt => self.halted = true,
|
||||
Opcode::Nop => (),
|
||||
}
|
||||
}
|
||||
MCycle::M2 => match self.opcode {
|
||||
Opcode::MovMR(_) => (),
|
||||
Opcode::MovRM(dst) => self.regs[dst] = data,
|
||||
Opcode::MviM => {
|
||||
self.pc += 1;
|
||||
self.tmp = data;
|
||||
}
|
||||
Opcode::Mvi(dst) => {
|
||||
self.regs[dst] = data;
|
||||
}
|
||||
Opcode::Lxi(_) => todo!(),
|
||||
Opcode::Lda => {
|
||||
self.z = data;
|
||||
self.pc += 1;
|
||||
}
|
||||
Opcode::Sta => {
|
||||
self.z = data;
|
||||
self.pc += 1;
|
||||
}
|
||||
Opcode::Lhld => todo!(),
|
||||
Opcode::Shld => todo!(),
|
||||
Opcode::Ldax(_) => todo!(),
|
||||
Opcode::Stax(_) => todo!(),
|
||||
Opcode::AddM => {
|
||||
let a = self.regs.a;
|
||||
let b = data;
|
||||
let res = (a as u16) + (b as u16);
|
||||
self.sign = ((res as u8) & 0x80) > 0;
|
||||
self.zero = (res as u8) == 0;
|
||||
self.aux_carry = (a & 0x0f) + (b & 0x0f) > 0x0f;
|
||||
self.parity = (res as u8).count_ones() % 2 == 0;
|
||||
self.carry = res > 0xff;
|
||||
self.regs.a = res as u8;
|
||||
}
|
||||
Opcode::Adi => todo!(),
|
||||
Opcode::AdcM => todo!(),
|
||||
Opcode::Aci => todo!(),
|
||||
Opcode::SubM => todo!(),
|
||||
Opcode::Sui => todo!(),
|
||||
Opcode::SbbM => todo!(),
|
||||
Opcode::Sbi => todo!(),
|
||||
Opcode::InrM => todo!(),
|
||||
Opcode::DcrM => todo!(),
|
||||
Opcode::AnaM => todo!(),
|
||||
Opcode::Ani => todo!(),
|
||||
Opcode::XraM => todo!(),
|
||||
Opcode::Xri => todo!(),
|
||||
Opcode::OraM => todo!(),
|
||||
Opcode::Ori => todo!(),
|
||||
Opcode::CmpM => todo!(),
|
||||
Opcode::Cpi => todo!(),
|
||||
Opcode::Jmp => {
|
||||
self.z = data;
|
||||
self.pc += 1;
|
||||
}
|
||||
Opcode::Jcc(_) => todo!(),
|
||||
Opcode::Call => todo!(),
|
||||
Opcode::Ccc(_) => todo!(),
|
||||
Opcode::Ret => todo!(),
|
||||
Opcode::Rcc(_) => todo!(),
|
||||
Opcode::Rst(_) => todo!(),
|
||||
Opcode::Push(_) => todo!(),
|
||||
Opcode::Pop(_) => todo!(),
|
||||
Opcode::Xthl => {
|
||||
self.sp += 1;
|
||||
self.z = data;
|
||||
}
|
||||
Opcode::In => todo!(),
|
||||
Opcode::Out => todo!(),
|
||||
Opcode::Hlt => todo!(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
MCycle::M3 => match self.opcode {
|
||||
Opcode::MviM => (),
|
||||
Opcode::Lxi(_) => todo!(),
|
||||
Opcode::Lda => {
|
||||
self.w = data;
|
||||
self.pc += 1;
|
||||
}
|
||||
Opcode::Sta => {
|
||||
self.w = data;
|
||||
self.pc += 1;
|
||||
}
|
||||
Opcode::Lhld => todo!(),
|
||||
Opcode::Shld => {
|
||||
self.set_wz(self.get_wz() + 1);
|
||||
}
|
||||
Opcode::Inr(_) => todo!(),
|
||||
Opcode::Dcr(_) => todo!(),
|
||||
Opcode::Jmp => {
|
||||
self.w = data;
|
||||
self.pc = self.get_wz();
|
||||
}
|
||||
Opcode::Jcc(_) => todo!(),
|
||||
Opcode::Call => todo!(),
|
||||
Opcode::Ccc(_) => todo!(),
|
||||
Opcode::Ret => todo!(),
|
||||
Opcode::Rcc(_) => todo!(),
|
||||
Opcode::Rst(_) => todo!(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
MCycle::M4 => match self.opcode {
|
||||
Opcode::Lda => {
|
||||
self.regs.a = data;
|
||||
}
|
||||
Opcode::Sta => (),
|
||||
Opcode::Lhld => todo!(),
|
||||
Opcode::Shld => todo!(),
|
||||
Opcode::Call => todo!(),
|
||||
Opcode::Ccc(_) => todo!(),
|
||||
Opcode::Xthl => (),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
MCycle::M5 => match self.opcode {
|
||||
Opcode::Call => todo!(),
|
||||
Opcode::Ccc(_) => todo!(),
|
||||
Opcode::Xthl => (),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
}
|
||||
if self.cycle == self.opcode.max_m_cycle() {
|
||||
println!("Instruction done");
|
||||
self.cycle = MCycle::M1;
|
||||
} else {
|
||||
self.cycle = self.cycle.next();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_pair(&self, pair: RegisterPair) -> u16 {
|
||||
match pair {
|
||||
RegisterPair::BC => ((self.regs.b as u16) << 8) | (self.regs.c as u16),
|
||||
RegisterPair::DE => ((self.regs.d as u16) << 8) | (self.regs.e as u16),
|
||||
RegisterPair::HL => ((self.regs.h as u16) << 8) | (self.regs.l as u16),
|
||||
RegisterPair::SP => self.sp,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_wz(&self) -> u16 {
|
||||
((self.w as u16) << 8) | (self.z as u16)
|
||||
}
|
||||
|
||||
fn set_pair(&mut self, pair: RegisterPair, val: u16) {
|
||||
match pair {
|
||||
RegisterPair::BC => {
|
||||
self.regs.b = (val >> 8) as u8;
|
||||
self.regs.c = val as u8;
|
||||
}
|
||||
RegisterPair::DE => {
|
||||
self.regs.d = (val >> 8) as u8;
|
||||
self.regs.e = val as u8;
|
||||
}
|
||||
RegisterPair::HL => {
|
||||
self.regs.h = (val >> 8) as u8;
|
||||
self.regs.l = val as u8;
|
||||
}
|
||||
RegisterPair::SP => self.sp = val,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_wz(&mut self, val: u16) {
|
||||
self.w = (val >> 8) as u8;
|
||||
self.z = val as u8;
|
||||
}
|
||||
}
|
182
src/cpu/opcode.rs
Normal file
@ -0,0 +1,182 @@
|
||||
use super::MCycle;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(super) enum RegisterPair {
|
||||
BC,
|
||||
DE,
|
||||
HL,
|
||||
SP, // PSW for push/pop
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(super) enum Register {
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
E,
|
||||
H,
|
||||
L,
|
||||
A,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(super) enum Condition {
|
||||
NZ,
|
||||
Z,
|
||||
NC,
|
||||
C,
|
||||
PO,
|
||||
PE,
|
||||
P,
|
||||
M,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(super) enum Opcode {
|
||||
MovMR(Register),
|
||||
MovRM(Register),
|
||||
Mov(Register, Register),
|
||||
Sphl,
|
||||
MviM,
|
||||
Mvi(Register),
|
||||
Lxi(RegisterPair),
|
||||
Lda,
|
||||
Sta,
|
||||
Lhld,
|
||||
Shld,
|
||||
Ldax(RegisterPair),
|
||||
Stax(RegisterPair),
|
||||
Xchg,
|
||||
AddM,
|
||||
Add(Register),
|
||||
Adi,
|
||||
AdcM,
|
||||
Adc(Register),
|
||||
Aci,
|
||||
SubM,
|
||||
Sub(Register),
|
||||
Sui,
|
||||
SbbM,
|
||||
Sbb(Register),
|
||||
Sbi,
|
||||
InrM,
|
||||
Inr(Register),
|
||||
DcrM,
|
||||
Dcr(Register),
|
||||
Inx(RegisterPair),
|
||||
Dcx(RegisterPair),
|
||||
Dad(RegisterPair),
|
||||
Daa,
|
||||
AnaM,
|
||||
Ana(Register),
|
||||
Ani,
|
||||
XraM,
|
||||
Xra(Register),
|
||||
Xri,
|
||||
OraM,
|
||||
Ora(Register),
|
||||
Ori,
|
||||
CmpM,
|
||||
Cmp(Register),
|
||||
Cpi,
|
||||
Rlc,
|
||||
Rrc,
|
||||
Ral,
|
||||
Rar,
|
||||
Cma,
|
||||
Cmc,
|
||||
Stc,
|
||||
Jmp,
|
||||
Jcc(Condition),
|
||||
Call,
|
||||
Ccc(Condition),
|
||||
Ret,
|
||||
Rcc(Condition),
|
||||
Rst(u8),
|
||||
Pchl,
|
||||
Push(RegisterPair),
|
||||
Pop(RegisterPair),
|
||||
Xthl,
|
||||
In,
|
||||
Out,
|
||||
Ei,
|
||||
Di,
|
||||
Hlt,
|
||||
Nop,
|
||||
}
|
||||
|
||||
impl Opcode {
|
||||
pub fn max_m_cycle(self) -> MCycle {
|
||||
match self {
|
||||
Self::MovMR(_) | Self::MovRM(_) => MCycle::M2,
|
||||
Self::Mov(_, _) => MCycle::M1,
|
||||
Self::Sphl => MCycle::M1,
|
||||
Self::MviM => MCycle::M3,
|
||||
Self::Mvi(_) => MCycle::M2,
|
||||
Self::Lxi(_) => MCycle::M3,
|
||||
Self::Lda => MCycle::M4,
|
||||
Self::Sta => MCycle::M4,
|
||||
Self::Lhld => MCycle::M5,
|
||||
Self::Shld => MCycle::M5,
|
||||
Self::Ldax(_) => MCycle::M2,
|
||||
Self::Stax(_) => MCycle::M2,
|
||||
Self::Xchg => MCycle::M1,
|
||||
Self::AddM => MCycle::M2,
|
||||
Self::Add(_) => MCycle::M1,
|
||||
Self::Adi => MCycle::M2,
|
||||
Self::AdcM => MCycle::M2,
|
||||
Self::Adc(_) => MCycle::M1,
|
||||
Self::Aci => MCycle::M2,
|
||||
Self::SubM => MCycle::M2,
|
||||
Self::Sub(_) => MCycle::M1,
|
||||
Self::Sui => MCycle::M2,
|
||||
Self::SbbM => MCycle::M2,
|
||||
Self::Sbb(_) => MCycle::M1,
|
||||
Self::Sbi => MCycle::M2,
|
||||
Self::InrM => MCycle::M3,
|
||||
Self::Inr(_) => MCycle::M1,
|
||||
Self::DcrM => MCycle::M3,
|
||||
Self::Dcr(_) => MCycle::M1,
|
||||
Self::Inx(_) => MCycle::M1,
|
||||
Self::Dcx(_) => MCycle::M1,
|
||||
Self::Dad(_) => MCycle::M1,
|
||||
Self::Daa => MCycle::M1,
|
||||
Self::AnaM => MCycle::M2,
|
||||
Self::Ana(_) => MCycle::M1,
|
||||
Self::Ani => MCycle::M2,
|
||||
Self::XraM => MCycle::M2,
|
||||
Self::Xra(_) => MCycle::M1,
|
||||
Self::Xri => MCycle::M2,
|
||||
Self::OraM => MCycle::M2,
|
||||
Self::Ora(_) => MCycle::M1,
|
||||
Self::Ori => MCycle::M2,
|
||||
Self::CmpM => MCycle::M2,
|
||||
Self::Cmp(_) => MCycle::M1,
|
||||
Self::Cpi => MCycle::M2,
|
||||
Self::Rlc => MCycle::M1,
|
||||
Self::Rrc => MCycle::M1,
|
||||
Self::Ral => MCycle::M1,
|
||||
Self::Rar => MCycle::M1,
|
||||
Self::Cma => MCycle::M1,
|
||||
Self::Cmc => MCycle::M1,
|
||||
Self::Stc => MCycle::M1,
|
||||
Self::Jmp => MCycle::M3,
|
||||
Self::Jcc(_) => MCycle::M3,
|
||||
Self::Call => MCycle::M5,
|
||||
Self::Ccc(_) => MCycle::M5,
|
||||
Self::Ret => MCycle::M3,
|
||||
Self::Rcc(_) => MCycle::M3,
|
||||
Self::Rst(_) => MCycle::M3,
|
||||
Self::Pchl => MCycle::M1,
|
||||
Self::Push(_) => MCycle::M3,
|
||||
Self::Pop(_) => MCycle::M3,
|
||||
Self::Xthl => MCycle::M5,
|
||||
Self::In => MCycle::M3,
|
||||
Self::Out => MCycle::M3,
|
||||
Self::Ei => MCycle::M1,
|
||||
Self::Di => MCycle::M1,
|
||||
Self::Hlt => MCycle::M1,
|
||||
Self::Nop => MCycle::M1,
|
||||
}
|
||||
}
|
||||
}
|
263
src/cpu/opcode_table.rs
Normal file
@ -0,0 +1,263 @@
|
||||
use super::opcode::{
|
||||
Condition,
|
||||
Opcode::{self, *},
|
||||
Register, RegisterPair,
|
||||
};
|
||||
pub(super) static OPCODE_TABLE: [Opcode; 256] = [
|
||||
Nop,
|
||||
Lxi(RegisterPair::BC),
|
||||
Stax(RegisterPair::BC),
|
||||
Inx(RegisterPair::BC),
|
||||
Inr(Register::B),
|
||||
Dcr(Register::B),
|
||||
Mvi(Register::B),
|
||||
Rlc,
|
||||
Nop,
|
||||
Dad(RegisterPair::BC),
|
||||
Ldax(RegisterPair::BC),
|
||||
Dcx(RegisterPair::BC),
|
||||
Inr(Register::C),
|
||||
Dcr(Register::C),
|
||||
Mvi(Register::C),
|
||||
Rrc,
|
||||
Nop,
|
||||
Lxi(RegisterPair::DE),
|
||||
Stax(RegisterPair::DE),
|
||||
Inx(RegisterPair::DE),
|
||||
Inr(Register::D),
|
||||
Dcr(Register::D),
|
||||
Mvi(Register::D),
|
||||
Ral,
|
||||
Nop,
|
||||
Dad(RegisterPair::DE),
|
||||
Ldax(RegisterPair::DE),
|
||||
Dcx(RegisterPair::DE),
|
||||
Inr(Register::E),
|
||||
Dcr(Register::E),
|
||||
Mvi(Register::E),
|
||||
Rar,
|
||||
Nop,
|
||||
Lxi(RegisterPair::HL),
|
||||
Shld,
|
||||
Inx(RegisterPair::HL),
|
||||
Inr(Register::H),
|
||||
Dcr(Register::H),
|
||||
Mvi(Register::H),
|
||||
Daa,
|
||||
Nop,
|
||||
Dad(RegisterPair::HL),
|
||||
Lhld,
|
||||
Dcx(RegisterPair::HL),
|
||||
Inr(Register::L),
|
||||
Dcr(Register::L),
|
||||
Mvi(Register::L),
|
||||
Cma,
|
||||
Nop,
|
||||
Lxi(RegisterPair::SP),
|
||||
Sta,
|
||||
Inx(RegisterPair::SP),
|
||||
InrM,
|
||||
DcrM,
|
||||
MviM,
|
||||
Stc,
|
||||
Nop,
|
||||
Dad(RegisterPair::SP),
|
||||
Lda,
|
||||
Dcx(RegisterPair::SP),
|
||||
Inr(Register::A),
|
||||
Dcr(Register::A),
|
||||
Mvi(Register::A),
|
||||
Cmc,
|
||||
Mov(Register::B, Register::B),
|
||||
Mov(Register::B, Register::C),
|
||||
Mov(Register::B, Register::D),
|
||||
Mov(Register::B, Register::E),
|
||||
Mov(Register::B, Register::H),
|
||||
Mov(Register::B, Register::L),
|
||||
MovRM(Register::B),
|
||||
Mov(Register::B, Register::A),
|
||||
Mov(Register::C, Register::B),
|
||||
Mov(Register::C, Register::C),
|
||||
Mov(Register::C, Register::D),
|
||||
Mov(Register::C, Register::E),
|
||||
Mov(Register::C, Register::H),
|
||||
Mov(Register::C, Register::L),
|
||||
MovRM(Register::C),
|
||||
Mov(Register::C, Register::A),
|
||||
Mov(Register::D, Register::B),
|
||||
Mov(Register::D, Register::C),
|
||||
Mov(Register::D, Register::D),
|
||||
Mov(Register::D, Register::E),
|
||||
Mov(Register::D, Register::H),
|
||||
Mov(Register::D, Register::L),
|
||||
MovRM(Register::D),
|
||||
Mov(Register::D, Register::A),
|
||||
Mov(Register::E, Register::B),
|
||||
Mov(Register::E, Register::C),
|
||||
Mov(Register::E, Register::D),
|
||||
Mov(Register::E, Register::E),
|
||||
Mov(Register::E, Register::H),
|
||||
Mov(Register::E, Register::L),
|
||||
MovRM(Register::E),
|
||||
Mov(Register::E, Register::A),
|
||||
Mov(Register::H, Register::B),
|
||||
Mov(Register::H, Register::C),
|
||||
Mov(Register::H, Register::D),
|
||||
Mov(Register::H, Register::E),
|
||||
Mov(Register::H, Register::H),
|
||||
Mov(Register::H, Register::L),
|
||||
MovRM(Register::H),
|
||||
Mov(Register::H, Register::A),
|
||||
Mov(Register::L, Register::B),
|
||||
Mov(Register::L, Register::C),
|
||||
Mov(Register::L, Register::D),
|
||||
Mov(Register::L, Register::E),
|
||||
Mov(Register::L, Register::H),
|
||||
Mov(Register::L, Register::L),
|
||||
MovRM(Register::L),
|
||||
Mov(Register::L, Register::A),
|
||||
MovMR(Register::B),
|
||||
MovMR(Register::C),
|
||||
MovMR(Register::D),
|
||||
MovMR(Register::E),
|
||||
MovMR(Register::H),
|
||||
MovMR(Register::L),
|
||||
Hlt,
|
||||
MovMR(Register::A),
|
||||
Mov(Register::A, Register::B),
|
||||
Mov(Register::A, Register::C),
|
||||
Mov(Register::A, Register::D),
|
||||
Mov(Register::A, Register::E),
|
||||
Mov(Register::A, Register::H),
|
||||
Mov(Register::A, Register::L),
|
||||
MovRM(Register::A),
|
||||
Mov(Register::A, Register::A),
|
||||
Add(Register::B),
|
||||
Add(Register::C),
|
||||
Add(Register::D),
|
||||
Add(Register::E),
|
||||
Add(Register::H),
|
||||
Add(Register::L),
|
||||
AddM,
|
||||
Add(Register::A),
|
||||
Adc(Register::B),
|
||||
Adc(Register::C),
|
||||
Adc(Register::D),
|
||||
Adc(Register::E),
|
||||
Adc(Register::H),
|
||||
Adc(Register::L),
|
||||
AdcM,
|
||||
Adc(Register::A),
|
||||
Sub(Register::B),
|
||||
Sub(Register::C),
|
||||
Sub(Register::D),
|
||||
Sub(Register::E),
|
||||
Sub(Register::H),
|
||||
Sub(Register::L),
|
||||
SubM,
|
||||
Sub(Register::A),
|
||||
Sbb(Register::B),
|
||||
Sbb(Register::C),
|
||||
Sbb(Register::D),
|
||||
Sbb(Register::E),
|
||||
Sbb(Register::H),
|
||||
Sbb(Register::L),
|
||||
SbbM,
|
||||
Sbb(Register::A),
|
||||
Ana(Register::B),
|
||||
Ana(Register::C),
|
||||
Ana(Register::D),
|
||||
Ana(Register::E),
|
||||
Ana(Register::H),
|
||||
Ana(Register::L),
|
||||
AnaM,
|
||||
Ana(Register::A),
|
||||
Xra(Register::B),
|
||||
Xra(Register::C),
|
||||
Xra(Register::D),
|
||||
Xra(Register::E),
|
||||
Xra(Register::H),
|
||||
Xra(Register::L),
|
||||
XraM,
|
||||
Xra(Register::A),
|
||||
Ora(Register::B),
|
||||
Ora(Register::C),
|
||||
Ora(Register::D),
|
||||
Ora(Register::E),
|
||||
Ora(Register::H),
|
||||
Ora(Register::L),
|
||||
OraM,
|
||||
Ora(Register::A),
|
||||
Cmp(Register::B),
|
||||
Cmp(Register::C),
|
||||
Cmp(Register::D),
|
||||
Cmp(Register::E),
|
||||
Cmp(Register::H),
|
||||
Cmp(Register::L),
|
||||
CmpM,
|
||||
Cmp(Register::A),
|
||||
Rcc(Condition::NZ),
|
||||
Pop(RegisterPair::BC),
|
||||
Jcc(Condition::NZ),
|
||||
Jmp,
|
||||
Ccc(Condition::NZ),
|
||||
Push(RegisterPair::BC),
|
||||
Adi,
|
||||
Rst(0),
|
||||
Rcc(Condition::Z),
|
||||
Ret,
|
||||
Jcc(Condition::Z),
|
||||
Jmp,
|
||||
Ccc(Condition::Z),
|
||||
Call,
|
||||
Aci,
|
||||
Rst(1),
|
||||
Rcc(Condition::NC),
|
||||
Pop(RegisterPair::DE),
|
||||
Jcc(Condition::NC),
|
||||
Out,
|
||||
Ccc(Condition::NC),
|
||||
Push(RegisterPair::DE),
|
||||
Sui,
|
||||
Rst(2),
|
||||
Rcc(Condition::C),
|
||||
Ret,
|
||||
Jcc(Condition::C),
|
||||
In,
|
||||
Ccc(Condition::C),
|
||||
Call,
|
||||
Sbi,
|
||||
Rst(3),
|
||||
Rcc(Condition::PO),
|
||||
Pop(RegisterPair::HL),
|
||||
Jcc(Condition::PO),
|
||||
Xthl,
|
||||
Ccc(Condition::PO),
|
||||
Push(RegisterPair::HL),
|
||||
Ani,
|
||||
Rst(4),
|
||||
Rcc(Condition::PE),
|
||||
Pchl,
|
||||
Jcc(Condition::PE),
|
||||
Xchg,
|
||||
Ccc(Condition::PE),
|
||||
Call,
|
||||
Xri,
|
||||
Rst(5),
|
||||
Rcc(Condition::P),
|
||||
Pop(RegisterPair::SP), // Actually PSW
|
||||
Jcc(Condition::P),
|
||||
Di,
|
||||
Ccc(Condition::P),
|
||||
Push(RegisterPair::SP), // Actually PSW
|
||||
Ori,
|
||||
Rst(6),
|
||||
Rcc(Condition::M),
|
||||
Sphl,
|
||||
Jcc(Condition::M),
|
||||
Ei,
|
||||
Ccc(Condition::M),
|
||||
Call,
|
||||
Cpi,
|
||||
Rst(7),
|
||||
];
|
1075
src/main.rs
Normal file
32
src/ram.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::card::{Card, CardEnum};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct RamCardSettings {
|
||||
size: u16,
|
||||
start_addr: u16,
|
||||
}
|
||||
pub struct RamCard {
|
||||
ram: Vec<u8>,
|
||||
start_addr: u16,
|
||||
}
|
||||
|
||||
impl Card for RamCard {
|
||||
fn new(settings: ron::Value) -> CardEnum {
|
||||
let settings: RamCardSettings = settings.into_rust().unwrap();
|
||||
let mut ram = Vec::with_capacity(settings.size as usize);
|
||||
ram.resize(settings.size as usize, 0);
|
||||
CardEnum::RamCard(Self {
|
||||
ram,
|
||||
start_addr: settings.start_addr
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_settings(&self) -> String {
|
||||
ron::to_string(&RamCardSettings {
|
||||
size: self.ram.len() as u16,
|
||||
start_addr: self.start_addr,
|
||||
}).unwrap()
|
||||
}
|
||||
}
|