💻✏💾
This commit is contained in:
parent
22fac611d8
commit
e5f67a01f5
|
@ -1,3 +1,20 @@
|
|||
use std::convert::{From, Into};
|
||||
|
||||
struct Address(usize);
|
||||
impl From<usize> for Address {
|
||||
fn from(v: usize) -> Self {
|
||||
if v > 0xFFFF {
|
||||
panic!("Address is bigger than 0x10000 (Got 0x{:04X})", v);
|
||||
}
|
||||
Self(v)
|
||||
}
|
||||
}
|
||||
impl From<u16> for Address {
|
||||
fn from(v: u16) -> Self {
|
||||
Self(v as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_size(addr_mode: AddressingMode) -> usize {
|
||||
OP_SIZES[addr_mode as usize]
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
use std::boxed::Box;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display, Error as FmtError, Formatter};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CpuError {
|
||||
UnknownOp(u8),
|
||||
Break,
|
||||
Suberror(Box<dyn Error>),
|
||||
}
|
||||
|
||||
impl Display for CpuError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
write!(
|
||||
f,
|
||||
"Emulator Error: {}",
|
||||
match self {
|
||||
CpuError::Suberror(e) => e.description().to_string(),
|
||||
CpuError::Break => "Emulator Terminated".to_string(),
|
||||
CpuError::UnknownOp(code) => format!("Unknown OP with code {:02X}", code),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
impl Error for CpuError {}
|
||||
unsafe impl std::marker::Send for CpuError {}
|
||||
unsafe impl std::marker::Sync for CpuError {}
|
|
@ -1,9 +1,10 @@
|
|||
pub mod error;
|
||||
mod error;
|
||||
pub use error::CpuError;
|
||||
|
||||
mod addressing_modes;
|
||||
use addressing_modes::AddressingMode;
|
||||
mod opcodes;
|
||||
use opcodes::OpcodeType;
|
||||
mod cpu;
|
||||
mod emulator;
|
||||
pub use emulator::Emulator;
|
||||
mod registers;
|
||||
mod system;
|
||||
pub use system::System;
|
|
@ -11,14 +11,14 @@ pub enum Flags {
|
|||
Carry = 1,
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
pub struct Cpu {
|
||||
pub struct Registers {
|
||||
pub A: u8,
|
||||
pub X: u8,
|
||||
pub Y: u8,
|
||||
pub PC: u16,
|
||||
pub flags: u8,
|
||||
}
|
||||
impl Cpu {
|
||||
impl Registers {
|
||||
pub fn test(&self, flag: Flags) -> bool {
|
||||
(self.flags & flag as u8) != 0
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ impl Cpu {
|
|||
self.A = value;
|
||||
}
|
||||
}
|
||||
impl std::default::Default for Cpu {
|
||||
impl std::default::Default for Registers {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
A: 0x00,
|
||||
|
@ -57,7 +57,7 @@ impl std::default::Default for Cpu {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for Cpu {
|
||||
impl std::fmt::Debug for Registers {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(
|
||||
f,
|
|
@ -1,6 +1,6 @@
|
|||
use super::cpu::{Cpu, Flags};
|
||||
use super::error;
|
||||
use super::opcodes;
|
||||
use super::registers::{Flags, Registers};
|
||||
use super::OpcodeType;
|
||||
use super::{addressing_modes::get_size, AddressingMode};
|
||||
|
||||
|
@ -12,7 +12,7 @@ static RESET_VEC_ADDR: usize = 0xFFFC;
|
|||
|
||||
macro_rules! fetch {
|
||||
($self:ident PC+$off:expr) => {
|
||||
$self.ram[$self.cpu.PC as usize + $off]
|
||||
$self.ram[$self.registers.PC as usize + $off]
|
||||
};
|
||||
($self:ident $addr:expr) => {
|
||||
$self.ram[$addr as usize]
|
||||
|
@ -23,48 +23,48 @@ macro_rules! fetch {
|
|||
}
|
||||
macro_rules! operation {
|
||||
($self:ident A+$b:expr) => {
|
||||
$self.cpu.A.wrapping_add($b as u8)
|
||||
$self.registers.A.wrapping_add($b as u8)
|
||||
};
|
||||
($self:ident X+$b:expr) => {
|
||||
$self.cpu.X.wrapping_add($b as u8)
|
||||
$self.registers.X.wrapping_add($b as u8)
|
||||
};
|
||||
(unwrap $arg:ident $addr:ident) => {
|
||||
$arg.unwrap_or_else(|| invalid_mode($addr.addr_mode))
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Emulator {
|
||||
pub struct System {
|
||||
pub cycles: usize,
|
||||
pub ram: [u8; 0x10000],
|
||||
pub cpu: Cpu,
|
||||
pub registers: Registers,
|
||||
}
|
||||
impl Emulator {
|
||||
impl System {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
cycles: 0,
|
||||
ram: [0x00; 0x10000],
|
||||
cpu: Cpu::default(),
|
||||
registers: Registers::default(),
|
||||
}
|
||||
}
|
||||
pub fn init(&mut self) -> Result<(), error::EmulatorError> {
|
||||
pub fn init(&mut self) -> Result<(), error::CpuError> {
|
||||
let lo: u16 = self.ram[RESET_VEC_ADDR] as u16;
|
||||
let hi: u16 = self.ram[RESET_VEC_ADDR + 1] as u16;
|
||||
let addr = hi << 8 | lo;
|
||||
self.cpu.PC = addr;
|
||||
self.registers.PC = addr;
|
||||
Ok(())
|
||||
}
|
||||
pub fn step(&mut self) -> Result<(), error::EmulatorError> {
|
||||
pub fn step(&mut self) -> Result<(), error::CpuError> {
|
||||
if self.cycles == 0 {
|
||||
println!("Initializing");
|
||||
self.init()?;
|
||||
}
|
||||
if self.cpu.test(Flags::Break) {
|
||||
/* if self.registers.test(Flags::Break) {
|
||||
return Err(error::EmulatorError::Break);
|
||||
}
|
||||
println!("Step on {:04X}", self.cpu.PC);
|
||||
let code = self.ram[self.cpu.PC as usize];
|
||||
} */
|
||||
println!("Step on {:04X}", self.registers.PC);
|
||||
let code = self.ram[self.registers.PC as usize];
|
||||
let code = match opcodes::from_code(code) {
|
||||
None => return Err(error::EmulatorError::UnknownOp(code)),
|
||||
None => return Err(error::CpuError::UnknownOp(code)),
|
||||
Some(v) => v,
|
||||
};
|
||||
println!(" Opcode {:?}", code.name);
|
||||
|
@ -78,12 +78,12 @@ impl Emulator {
|
|||
}
|
||||
AddressingMode::ABS => {
|
||||
// Next 2 bytes are an address from where to fetch the real argument
|
||||
let addr = self.cpu.PC as usize + 1;
|
||||
let addr = self.registers.PC as usize + 1;
|
||||
Some(fetch!(self D addr) as u16)
|
||||
}
|
||||
AddressingMode::ZPG => {
|
||||
// Next byte is an address from the range 0x0000-0x00FF
|
||||
let addr = self.cpu.PC as usize + 1;
|
||||
let addr = self.registers.PC as usize + 1;
|
||||
Some(fetch!(self addr) as u16)
|
||||
}
|
||||
AddressingMode::INDX => {
|
||||
|
@ -99,7 +99,7 @@ impl Emulator {
|
|||
AddressingMode::REL => {
|
||||
// Add PC with the next byte
|
||||
let arg = fetch!(self PC+1) as u8 as i8 as isize;
|
||||
let pc = self.cpu.PC as usize as isize;
|
||||
let pc = self.registers.PC as usize as isize;
|
||||
let new_pc = (arg + pc) & 0xFFFF;
|
||||
Some(new_pc as u16)
|
||||
}
|
||||
|
@ -112,39 +112,49 @@ impl Emulator {
|
|||
match code.name {
|
||||
OpcodeType::BRK => {
|
||||
println!("Stepped on break. Ending");
|
||||
println!("{:#?}", self.cpu);
|
||||
return Err(error::EmulatorError::Break);
|
||||
println!("{:#?}", self.registers);
|
||||
/* return Err(error::EmulatorError::Break); */
|
||||
}
|
||||
OpcodeType::NOP => {}
|
||||
OpcodeType::LDA => match code.addr_mode {
|
||||
AddressingMode::IMM => self.cpu.set_a(operation!(unwrap arg code) as u8),
|
||||
AddressingMode::ABS => self.cpu.set_a(fetch!(self operation!(unwrap arg code))),
|
||||
AddressingMode::ZPG => self.cpu.set_a(fetch!(self operation!(unwrap arg code))),
|
||||
AddressingMode::IMM => self.registers.set_a(operation!(unwrap arg code) as u8),
|
||||
AddressingMode::ABS => self
|
||||
.registers
|
||||
.set_a(fetch!(self operation!(unwrap arg code))),
|
||||
AddressingMode::ZPG => self
|
||||
.registers
|
||||
.set_a(fetch!(self operation!(unwrap arg code))),
|
||||
_ => panic!("Invalid addressing mode for {:?}", code.name),
|
||||
},
|
||||
OpcodeType::STA => match code.addr_mode {
|
||||
AddressingMode::ABS => self.ram[operation!(unwrap arg code) as usize] = self.cpu.A,
|
||||
AddressingMode::ZPG => self.ram[operation!(unwrap arg code) as usize] = self.cpu.A,
|
||||
AddressingMode::INDX => self.ram[operation!(unwrap arg code) as usize] = self.cpu.A,
|
||||
AddressingMode::ABS => {
|
||||
self.ram[operation!(unwrap arg code) as usize] = self.registers.A
|
||||
}
|
||||
AddressingMode::ZPG => {
|
||||
self.ram[operation!(unwrap arg code) as usize] = self.registers.A
|
||||
}
|
||||
AddressingMode::INDX => {
|
||||
self.ram[operation!(unwrap arg code) as usize] = self.registers.A
|
||||
}
|
||||
_ => panic!("Invalid addressing mode for {:?}", code.name),
|
||||
},
|
||||
OpcodeType::ADC => match code.addr_mode {
|
||||
AddressingMode::IMM => self.cpu.add_a(operation!(unwrap arg code) as u8),
|
||||
AddressingMode::IMM => self.registers.add_a(operation!(unwrap arg code) as u8),
|
||||
_ => panic!("Invalid addressing mode for {:?}", code.name),
|
||||
},
|
||||
OpcodeType::JMP => match code.addr_mode {
|
||||
AddressingMode::ABS => self.cpu.PC = operation!(unwrap arg code) as u16,
|
||||
AddressingMode::ABS => self.registers.PC = operation!(unwrap arg code) as u16,
|
||||
_ => panic!("Invalid addressing mode for {:?}", code.name),
|
||||
},
|
||||
OpcodeType::BEQ if code.addr_mode == AddressingMode::REL => {
|
||||
if self.cpu.test(Flags::Zero) {
|
||||
self.cpu.PC = operation!(unwrap arg code);
|
||||
if self.registers.test(Flags::Zero) {
|
||||
self.registers.PC = operation!(unwrap arg code);
|
||||
branch_taken = true;
|
||||
}
|
||||
}
|
||||
OpcodeType::BNE if code.addr_mode == AddressingMode::REL => {
|
||||
if !self.cpu.test(Flags::Zero) {
|
||||
self.cpu.PC = operation!(unwrap arg code);
|
||||
if !self.registers.test(Flags::Zero) {
|
||||
self.registers.PC = operation!(unwrap arg code);
|
||||
branch_taken = true;
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +169,7 @@ impl Emulator {
|
|||
if branch_taken || code.name == OpcodeType::JMP {
|
||||
println!("Don't increment PC");
|
||||
} else {
|
||||
self.cpu.PC += get_size(code.addr_mode) as u16;
|
||||
self.registers.PC += get_size(code.addr_mode) as u16;
|
||||
}
|
||||
self.cycles += 1;
|
||||
Ok(())
|
||||
|
@ -167,15 +177,15 @@ impl Emulator {
|
|||
pub fn restart(&mut self) {
|
||||
self.cycles = 0;
|
||||
self.ram = [0x00; 0x10000];
|
||||
self.cpu = Cpu::default();
|
||||
self.registers = Registers::default();
|
||||
}
|
||||
}
|
||||
|
||||
mod test {
|
||||
#[test]
|
||||
fn test_flags() {
|
||||
use super::{Cpu, Flags};
|
||||
let mut cpu: Cpu = Cpu::default();
|
||||
use super::{Flags, Registers};
|
||||
let mut cpu: Registers = Registers::default();
|
||||
cpu.set_flag(Flags::Zero, true);
|
||||
assert_eq!(cpu.test(Flags::Zero), true);
|
||||
cpu.set_flag(Flags::Zero, false);
|
|
@ -21,4 +21,4 @@ macro_rules! prog_err {
|
|||
};
|
||||
}
|
||||
|
||||
prog_err!(glib::BoolError, crate::sixty_five::error::EmulatorError);
|
||||
prog_err!(glib::BoolError);
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
use crate::emulator::{CpuError, System};
|
||||
use std::sync::mpsc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
|
||||
static TEST_CODE: &'static [u8; 0x10000] = include_bytes!("color.hex");
|
||||
|
||||
/* #region Commands */
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum Cmd {
|
||||
Step,
|
||||
Run,
|
||||
Stop,
|
||||
Get(GetType),
|
||||
Reset,
|
||||
}
|
||||
impl std::convert::From<&str> for Cmd {
|
||||
fn from(text: &str) -> Self {
|
||||
match text {
|
||||
"Step" => Self::Step,
|
||||
"Run" => Self::Run,
|
||||
"Stop" => Self::Stop,
|
||||
"Reset" => Self::Reset,
|
||||
_ => panic!("???"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum GetType {
|
||||
Range(usize, usize),
|
||||
Value(usize),
|
||||
Flags,
|
||||
}
|
||||
/* #endregion */
|
||||
|
||||
pub struct ThreadedEmulator {
|
||||
pub tcmd: mpsc::Sender<Cmd>,
|
||||
pub rdata: glib::Receiver<Vec<u8>>,
|
||||
pub system: Arc<Mutex<System>>,
|
||||
pub thread: thread::JoinHandle<Result<(), CpuError>>,
|
||||
}
|
||||
impl ThreadedEmulator {
|
||||
pub fn new() -> Self {
|
||||
let (tcmd, rcmd) = mpsc::channel::<Cmd>();
|
||||
let (tdata, rdata) = glib::MainContext::channel(glib::source::Priority::default());
|
||||
let system = Arc::from(Mutex::from(System::new()));
|
||||
let thread = {
|
||||
let system = system.clone();
|
||||
thread::spawn(move || Self::thread(rcmd, tdata, system))
|
||||
};
|
||||
Self {
|
||||
tcmd,
|
||||
rdata,
|
||||
system,
|
||||
thread,
|
||||
}
|
||||
}
|
||||
|
||||
fn thread(
|
||||
rcmd: mpsc::Receiver<Cmd>,
|
||||
tdata: glib::Sender<Vec<u8>>,
|
||||
system: Arc<Mutex<System>>,
|
||||
) -> Result<(), CpuError> {
|
||||
loop {
|
||||
if let Ok(cmd) = rcmd.recv() {
|
||||
let mut system = system.lock().unwrap_or_else(|e| {
|
||||
panic!("Error acquiring lock for the system. Error: {}", e)
|
||||
});
|
||||
println!("Cmd: {:?}", cmd);
|
||||
match cmd {
|
||||
Cmd::Step => system.step()?,
|
||||
Cmd::Reset => {
|
||||
system.restart();
|
||||
system.ram = *TEST_CODE;
|
||||
}
|
||||
Cmd::Run => loop {
|
||||
if let Err(e) = rcmd.recv_timeout(std::time::Duration::from_millis(1)) {
|
||||
if e == std::sync::mpsc::RecvTimeoutError::Timeout {
|
||||
system.step()?;
|
||||
} else {
|
||||
panic!("Controller mpsc disconnected: {}", e)
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
},
|
||||
Cmd::Get(what) => match what {
|
||||
GetType::Flags => {}
|
||||
GetType::Range(start, end) => {
|
||||
let data = &system.ram[start..end];
|
||||
tdata
|
||||
.send(Vec::from(data))
|
||||
.expect("Couldn't send requested value");
|
||||
}
|
||||
GetType::Value(addr) => {
|
||||
tdata
|
||||
.send(vec![system.ram[addr]])
|
||||
.expect("Couldn't send requested value");
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
170
src/main.rs
170
src/main.rs
|
@ -6,87 +6,81 @@ use gio::prelude::*;
|
|||
use gtk::prelude::*;
|
||||
use gtk::Builder;
|
||||
|
||||
mod sixty_five;
|
||||
use sixty_five::Emulator;
|
||||
mod emulator;
|
||||
mod graphic;
|
||||
mod handler;
|
||||
use graphic::{Color, Image};
|
||||
use handler::{Cmd, ThreadedEmulator};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
enum Cmd {
|
||||
Step,
|
||||
Run,
|
||||
Stop,
|
||||
Reset,
|
||||
}
|
||||
impl std::convert::From<&str> for Cmd {
|
||||
fn from(text: &str) -> Self {
|
||||
match text {
|
||||
"Step" => Self::Step,
|
||||
"Run" => Self::Run,
|
||||
"Stop" => Self::Stop,
|
||||
"Reset" => Self::Reset,
|
||||
_ => panic!("???"),
|
||||
}
|
||||
}
|
||||
macro_rules! gtk_rs {
|
||||
($builder:expr=>$name:expr) => {
|
||||
$builder
|
||||
.get_object($name)
|
||||
.unwrap_or_else(|| panic!("Object {} could't be found", $name))
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init(app: >k::Application) -> Result<(), ProgErr> {
|
||||
let img = Image::new();
|
||||
let (img_width, img_height) = (img.width, img.height);
|
||||
use std::sync::{Arc, Mutex};
|
||||
let img_m = Arc::from(Mutex::from(img));
|
||||
let palette = Arc::from(Mutex::from([Color::default(); 16]));
|
||||
let img_m = Arc::from(Mutex::from(Image::new()));
|
||||
let palette: Arc<Mutex<_>> = Arc::from(Mutex::from([Color::default(); 16]));
|
||||
|
||||
// Handle emulator CMDs
|
||||
let (tcmd, rcmd) = std::sync::mpsc::channel::<Cmd>();
|
||||
let (tdata, rdata) = glib::MainContext::channel(glib::source::Priority::default());
|
||||
let emulator = Arc::from(Mutex::from(Emulator::new()));
|
||||
{
|
||||
let emulator = emulator.clone();
|
||||
std::thread::spawn(move || loop {
|
||||
if let Ok(cmd) = rcmd.recv() {
|
||||
let mut emulator = match emulator.try_lock() {
|
||||
Err(_) => continue,
|
||||
Ok(v) => v,
|
||||
};
|
||||
match cmd {
|
||||
Cmd::Step => {
|
||||
if let Err(e) = emulator.step() {
|
||||
println!("{:#?}", e);
|
||||
}
|
||||
}
|
||||
Cmd::Reset => {
|
||||
emulator.restart();
|
||||
emulator.ram = *include_bytes!("color.hex");
|
||||
}
|
||||
Cmd::Run => loop {
|
||||
if let Ok(_) = rcmd.recv_timeout(std::time::Duration::from_millis(1)) {
|
||||
break;
|
||||
} else {
|
||||
if let Err(e) = emulator.step() {
|
||||
println!("Emulator error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
println!("Tick {}", emulator.cycles);
|
||||
let page_02 = Vec::from(&emulator.ram[0x200..0x300]);
|
||||
tdata.send(page_02);
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
println!("Tick {}", emulator.cycles);
|
||||
let page_02 = Vec::from(&emulator.ram[0x200..0x300]);
|
||||
tdata.send(page_02);
|
||||
}
|
||||
});
|
||||
}
|
||||
let emulator = ThreadedEmulator::new();
|
||||
|
||||
/*
|
||||
// Handle emulator CMDs
|
||||
let (tcmd, rcmd) = std::sync::mpsc::channel::<Cmd>();
|
||||
let (tdata, rdata) = glib::MainContext::channel(glib::source::Priority::default());
|
||||
let emulator = Arc::from(Mutex::from(System::new()));
|
||||
{
|
||||
let emulator = emulator.clone();
|
||||
std::thread::spawn(move || loop {
|
||||
if let Ok(cmd) = rcmd.recv() {
|
||||
if let Ok(mut emulator) = emulator.try_lock() {
|
||||
match cmd {
|
||||
Cmd::Step => {
|
||||
if let Err(e) = emulator.step() {
|
||||
println!("{:#?}", e);
|
||||
}
|
||||
}
|
||||
Cmd::Reset => {
|
||||
emulator.restart();
|
||||
emulator.ram = *include_bytes!("color.hex");
|
||||
}
|
||||
Cmd::Run => loop {
|
||||
if let Ok(_) = rcmd.recv_timeout(std::time::Duration::from_millis(1)) {
|
||||
break;
|
||||
} else {
|
||||
if let Err(e) = emulator.step() {
|
||||
println!("Emulator error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
println!("Tick {}", emulator.cycles);
|
||||
let page_02 = Vec::from(&emulator.ram[0x200..0x300]);
|
||||
tdata.send(page_02);
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
println!("Tick {}", emulator.cycles);
|
||||
let page_02 = Vec::from(&emulator.ram[0x200..0x300]);
|
||||
tdata.send(page_02);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
*/
|
||||
let builder: Builder = Builder::new_from_string(include_str!("ui.glade"));
|
||||
let window: gtk::ApplicationWindow = builder.get_object("Window").unwrap();
|
||||
let drawing_area: gtk::DrawingArea = builder.get_object("Display").unwrap();
|
||||
let drawing_area = Arc::from(drawing_area);
|
||||
//let window: Option<gtk::ApplicationWindow> = builder.get_object("Window");
|
||||
let window: gtk::ApplicationWindow = gtk_rs!(builder=>"Window");
|
||||
let drawing_area: gtk::DrawingArea = gtk_rs!(builder=>"Display");
|
||||
//let drawing_area = Arc::from(drawing_area);
|
||||
{
|
||||
drawing_area.set_size_request(img_width as i32, img_height as i32);
|
||||
let img_m = img_m.clone();
|
||||
drawing_area.connect_draw(
|
||||
move |drawing_area: >k::DrawingArea, ctx: &cairo::Context| {
|
||||
|
@ -102,20 +96,20 @@ pub fn init(app: >k::Application) -> Result<(), ProgErr> {
|
|||
}
|
||||
|
||||
for widget_name in &["Step", "Reset", "Run", "Stop"] {
|
||||
let tcmd_clone = tcmd.clone();
|
||||
let widget: gtk::Button = builder.get_object(widget_name).expect("Not found");
|
||||
let tcmd = emulator.tcmd.clone();
|
||||
let widget: gtk::Button = gtk_rs!(builder=>widget_name); // builder.get_object(widget_name).expect("Not found");
|
||||
widget.connect_clicked(move |s: >k::Button| {
|
||||
let name = s.get_widget_name().unwrap();
|
||||
let name = name.as_str();
|
||||
println!("Sending from {}", name);
|
||||
tcmd_clone.send(Cmd::from(name)).expect("Couldn't send cmd");
|
||||
tcmd.send(Cmd::from(name)).expect("Couldn't send cmd");
|
||||
});
|
||||
}
|
||||
|
||||
// Ram Display
|
||||
{
|
||||
let ram_display_window: gtk::Window = builder.get_object("RamDisplayWindow").unwrap();
|
||||
let switch: gtk::Switch = builder.get_object("RamDisplay").expect("Not Found");
|
||||
/* {
|
||||
let ram_display_window: gtk::Window = gtk_rs!(builder=>"RamDisplayWindow"); // builder.get_object().unwrap();
|
||||
let switch: gtk::Switch = gtk_rs!(builder=>"RamDisplay"); // builder.get_object().expect("Not Found");
|
||||
switch.connect_state_set(move |switch: >k::Switch, state: bool| {
|
||||
if state {
|
||||
ram_display_window.show_all();
|
||||
|
@ -126,19 +120,17 @@ pub fn init(app: >k::Application) -> Result<(), ProgErr> {
|
|||
|
||||
Inhibit(false)
|
||||
});
|
||||
let ram_list: gtk::Window = builder.get_object("RamList").unwrap();
|
||||
}
|
||||
let ram_list: gtk::Window = gtk_rs!(builder=>"RamList");
|
||||
} */
|
||||
|
||||
let registers: gtk::Label = builder.get_object("Registers").unwrap();
|
||||
let registers = Mutex::from(registers);
|
||||
let registers: gtk::Label = gtk_rs!(builder=>"Registers");
|
||||
|
||||
// Receive GPU page
|
||||
{
|
||||
let drawing_area = drawing_area.clone();
|
||||
let palette = palette.clone();
|
||||
let emulator = emulator.clone();
|
||||
let img_m = img_m.clone();
|
||||
rdata.attach(None, move |data: Vec<_>| {
|
||||
emulator.rdata.attach(None, move |data: Vec<_>| {
|
||||
println!("Received page");
|
||||
for line in data.chunks(16) {
|
||||
println!(
|
||||
|
@ -159,10 +151,9 @@ pub fn init(app: >k::Application) -> Result<(), ProgErr> {
|
|||
}
|
||||
}
|
||||
}
|
||||
if let Ok(registers) = registers.try_lock() {
|
||||
if let Ok(emulator) = emulator.try_lock() {
|
||||
registers.set_text(&format!("{:#?}", emulator.cpu));
|
||||
}
|
||||
|
||||
if let Ok(system) = emulator.system.try_lock() {
|
||||
registers.set_text(&format!("{:#?}", system.registers));
|
||||
}
|
||||
drawing_area.queue_draw();
|
||||
glib::Continue(true)
|
||||
|
@ -174,8 +165,8 @@ pub fn init(app: >k::Application) -> Result<(), ProgErr> {
|
|||
for i in 0..16 {
|
||||
let drawing_area = drawing_area.clone();
|
||||
let palette = palette.clone();
|
||||
let color_button: gtk::ColorButton =
|
||||
builder.get_object(&format!("ColorPalette{}", i)).unwrap();
|
||||
let color_button = &format!("ColorPalette{}", i);
|
||||
let color_button: gtk::ColorButton = gtk_rs!(builder=>color_button);
|
||||
color_button.connect_color_set(move |s: >k::ColorButton| {
|
||||
let color = s.get_rgba();
|
||||
let color = Color::from((color.red, color.green, color.blue));
|
||||
|
@ -190,13 +181,14 @@ pub fn init(app: >k::Application) -> Result<(), ProgErr> {
|
|||
|
||||
window.set_application(Some(app));
|
||||
window.show_all();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<(), ProgErr> {
|
||||
let app: gtk::Application =
|
||||
gtk::Application::new(Some("com.ducklings_corp.emulator"), Default::default())?;
|
||||
app.connect_activate(move |app| init(app).expect("Init failed"));
|
||||
app.connect_activate(|app| init(app).expect("Init failed"));
|
||||
app.run(&std::env::args().collect::<Vec<_>>());
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
use std::boxed::Box;
|
||||
use std::error::Error;
|
||||
use std::fmt::{Display, Error as FmtError, Formatter};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EmulatorError {
|
||||
UnknownOp(u8),
|
||||
Break,
|
||||
Suberror(Box<dyn Error>),
|
||||
}
|
||||
|
||||
impl Display for EmulatorError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
write!(
|
||||
f,
|
||||
"Emulator Error: {}",
|
||||
match self {
|
||||
EmulatorError::Suberror(e) => e.description().to_string(),
|
||||
EmulatorError::Break => "Emulator Terminated".to_string(),
|
||||
EmulatorError::UnknownOp(code) => format!("Unknown OP with code {:02X}", code),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
impl Error for EmulatorError {}
|
Loading…
Reference in New Issue