💻💾

This commit is contained in:
PeronTheDuck 2020-01-28 00:09:05 -03:00
parent 22fac611d8
commit e5f67a01f5
12 changed files with 289 additions and 160 deletions

View File

@ -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 { pub fn get_size(addr_mode: AddressingMode) -> usize {
OP_SIZES[addr_mode as usize] OP_SIZES[addr_mode as usize]
} }

27
src/emulator/error.rs Normal file
View File

@ -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 {}

View File

@ -1,9 +1,10 @@
pub mod error; mod error;
pub use error::CpuError;
mod addressing_modes; mod addressing_modes;
use addressing_modes::AddressingMode; use addressing_modes::AddressingMode;
mod opcodes; mod opcodes;
use opcodes::OpcodeType; use opcodes::OpcodeType;
mod cpu; mod registers;
mod emulator; mod system;
pub use emulator::Emulator; pub use system::System;

View File

@ -11,14 +11,14 @@ pub enum Flags {
Carry = 1, Carry = 1,
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub struct Cpu { pub struct Registers {
pub A: u8, pub A: u8,
pub X: u8, pub X: u8,
pub Y: u8, pub Y: u8,
pub PC: u16, pub PC: u16,
pub flags: u8, pub flags: u8,
} }
impl Cpu { impl Registers {
pub fn test(&self, flag: Flags) -> bool { pub fn test(&self, flag: Flags) -> bool {
(self.flags & flag as u8) != 0 (self.flags & flag as u8) != 0
} }
@ -46,7 +46,7 @@ impl Cpu {
self.A = value; self.A = value;
} }
} }
impl std::default::Default for Cpu { impl std::default::Default for Registers {
fn default() -> Self { fn default() -> Self {
Self { Self {
A: 0x00, 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> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!( write!(
f, f,

View File

@ -1,6 +1,6 @@
use super::cpu::{Cpu, Flags};
use super::error; use super::error;
use super::opcodes; use super::opcodes;
use super::registers::{Flags, Registers};
use super::OpcodeType; use super::OpcodeType;
use super::{addressing_modes::get_size, AddressingMode}; use super::{addressing_modes::get_size, AddressingMode};
@ -12,7 +12,7 @@ static RESET_VEC_ADDR: usize = 0xFFFC;
macro_rules! fetch { macro_rules! fetch {
($self:ident PC+$off:expr) => { ($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:ident $addr:expr) => {
$self.ram[$addr as usize] $self.ram[$addr as usize]
@ -23,48 +23,48 @@ macro_rules! fetch {
} }
macro_rules! operation { macro_rules! operation {
($self:ident A+$b:expr) => { ($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: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) => { (unwrap $arg:ident $addr:ident) => {
$arg.unwrap_or_else(|| invalid_mode($addr.addr_mode)) $arg.unwrap_or_else(|| invalid_mode($addr.addr_mode))
}; };
} }
pub struct Emulator { pub struct System {
pub cycles: usize, pub cycles: usize,
pub ram: [u8; 0x10000], pub ram: [u8; 0x10000],
pub cpu: Cpu, pub registers: Registers,
} }
impl Emulator { impl System {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
cycles: 0, cycles: 0,
ram: [0x00; 0x10000], 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 lo: u16 = self.ram[RESET_VEC_ADDR] as u16;
let hi: u16 = self.ram[RESET_VEC_ADDR + 1] as u16; let hi: u16 = self.ram[RESET_VEC_ADDR + 1] as u16;
let addr = hi << 8 | lo; let addr = hi << 8 | lo;
self.cpu.PC = addr; self.registers.PC = addr;
Ok(()) Ok(())
} }
pub fn step(&mut self) -> Result<(), error::EmulatorError> { pub fn step(&mut self) -> Result<(), error::CpuError> {
if self.cycles == 0 { if self.cycles == 0 {
println!("Initializing"); println!("Initializing");
self.init()?; self.init()?;
} }
if self.cpu.test(Flags::Break) { /* if self.registers.test(Flags::Break) {
return Err(error::EmulatorError::Break); return Err(error::EmulatorError::Break);
} } */
println!("Step on {:04X}", self.cpu.PC); println!("Step on {:04X}", self.registers.PC);
let code = self.ram[self.cpu.PC as usize]; let code = self.ram[self.registers.PC as usize];
let code = match opcodes::from_code(code) { let code = match opcodes::from_code(code) {
None => return Err(error::EmulatorError::UnknownOp(code)), None => return Err(error::CpuError::UnknownOp(code)),
Some(v) => v, Some(v) => v,
}; };
println!(" Opcode {:?}", code.name); println!(" Opcode {:?}", code.name);
@ -78,12 +78,12 @@ impl Emulator {
} }
AddressingMode::ABS => { AddressingMode::ABS => {
// Next 2 bytes are an address from where to fetch the real argument // 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) Some(fetch!(self D addr) as u16)
} }
AddressingMode::ZPG => { AddressingMode::ZPG => {
// Next byte is an address from the range 0x0000-0x00FF // 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) Some(fetch!(self addr) as u16)
} }
AddressingMode::INDX => { AddressingMode::INDX => {
@ -99,7 +99,7 @@ impl Emulator {
AddressingMode::REL => { AddressingMode::REL => {
// Add PC with the next byte // Add PC with the next byte
let arg = fetch!(self PC+1) as u8 as i8 as isize; 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; let new_pc = (arg + pc) & 0xFFFF;
Some(new_pc as u16) Some(new_pc as u16)
} }
@ -112,39 +112,49 @@ impl Emulator {
match code.name { match code.name {
OpcodeType::BRK => { OpcodeType::BRK => {
println!("Stepped on break. Ending"); println!("Stepped on break. Ending");
println!("{:#?}", self.cpu); println!("{:#?}", self.registers);
return Err(error::EmulatorError::Break); /* return Err(error::EmulatorError::Break); */
} }
OpcodeType::NOP => {} OpcodeType::NOP => {}
OpcodeType::LDA => match code.addr_mode { OpcodeType::LDA => match code.addr_mode {
AddressingMode::IMM => self.cpu.set_a(operation!(unwrap arg code) as u8), AddressingMode::IMM => self.registers.set_a(operation!(unwrap arg code) as u8),
AddressingMode::ABS => self.cpu.set_a(fetch!(self operation!(unwrap arg code))), AddressingMode::ABS => self
AddressingMode::ZPG => self.cpu.set_a(fetch!(self operation!(unwrap arg code))), .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), _ => panic!("Invalid addressing mode for {:?}", code.name),
}, },
OpcodeType::STA => match code.addr_mode { OpcodeType::STA => match code.addr_mode {
AddressingMode::ABS => self.ram[operation!(unwrap arg code) as usize] = self.cpu.A, AddressingMode::ABS => {
AddressingMode::ZPG => self.ram[operation!(unwrap arg code) as usize] = self.cpu.A, self.ram[operation!(unwrap arg code) as usize] = self.registers.A
AddressingMode::INDX => self.ram[operation!(unwrap arg code) as usize] = self.cpu.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), _ => panic!("Invalid addressing mode for {:?}", code.name),
}, },
OpcodeType::ADC => match code.addr_mode { 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), _ => panic!("Invalid addressing mode for {:?}", code.name),
}, },
OpcodeType::JMP => match code.addr_mode { 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), _ => panic!("Invalid addressing mode for {:?}", code.name),
}, },
OpcodeType::BEQ if code.addr_mode == AddressingMode::REL => { OpcodeType::BEQ if code.addr_mode == AddressingMode::REL => {
if self.cpu.test(Flags::Zero) { if self.registers.test(Flags::Zero) {
self.cpu.PC = operation!(unwrap arg code); self.registers.PC = operation!(unwrap arg code);
branch_taken = true; branch_taken = true;
} }
} }
OpcodeType::BNE if code.addr_mode == AddressingMode::REL => { OpcodeType::BNE if code.addr_mode == AddressingMode::REL => {
if !self.cpu.test(Flags::Zero) { if !self.registers.test(Flags::Zero) {
self.cpu.PC = operation!(unwrap arg code); self.registers.PC = operation!(unwrap arg code);
branch_taken = true; branch_taken = true;
} }
} }
@ -159,7 +169,7 @@ impl Emulator {
if branch_taken || code.name == OpcodeType::JMP { if branch_taken || code.name == OpcodeType::JMP {
println!("Don't increment PC"); println!("Don't increment PC");
} else { } else {
self.cpu.PC += get_size(code.addr_mode) as u16; self.registers.PC += get_size(code.addr_mode) as u16;
} }
self.cycles += 1; self.cycles += 1;
Ok(()) Ok(())
@ -167,15 +177,15 @@ impl Emulator {
pub fn restart(&mut self) { pub fn restart(&mut self) {
self.cycles = 0; self.cycles = 0;
self.ram = [0x00; 0x10000]; self.ram = [0x00; 0x10000];
self.cpu = Cpu::default(); self.registers = Registers::default();
} }
} }
mod test { mod test {
#[test] #[test]
fn test_flags() { fn test_flags() {
use super::{Cpu, Flags}; use super::{Flags, Registers};
let mut cpu: Cpu = Cpu::default(); let mut cpu: Registers = Registers::default();
cpu.set_flag(Flags::Zero, true); cpu.set_flag(Flags::Zero, true);
assert_eq!(cpu.test(Flags::Zero), true); assert_eq!(cpu.test(Flags::Zero), true);
cpu.set_flag(Flags::Zero, false); cpu.set_flag(Flags::Zero, false);

View File

@ -21,4 +21,4 @@ macro_rules! prog_err {
}; };
} }
prog_err!(glib::BoolError, crate::sixty_five::error::EmulatorError); prog_err!(glib::BoolError);

107
src/handler.rs Normal file
View File

@ -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");
}
},
_ => {}
};
}
}
}
}

View File

@ -6,87 +6,81 @@ use gio::prelude::*;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::Builder; use gtk::Builder;
mod sixty_five; mod emulator;
use sixty_five::Emulator;
mod graphic; mod graphic;
mod handler;
use graphic::{Color, Image}; use graphic::{Color, Image};
use handler::{Cmd, ThreadedEmulator};
#[derive(Copy, Clone, Debug, PartialEq)] macro_rules! gtk_rs {
enum Cmd { ($builder:expr=>$name:expr) => {
Step, $builder
Run, .get_object($name)
Stop, .unwrap_or_else(|| panic!("Object {} could't be found", $name))
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!("???"),
}
}
} }
pub fn init(app: &gtk::Application) -> Result<(), ProgErr> { pub fn init(app: &gtk::Application) -> Result<(), ProgErr> {
let img = Image::new();
let (img_width, img_height) = (img.width, img.height);
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
let img_m = Arc::from(Mutex::from(img)); let img_m = Arc::from(Mutex::from(Image::new()));
let palette = Arc::from(Mutex::from([Color::default(); 16])); let palette: Arc<Mutex<_>> = Arc::from(Mutex::from([Color::default(); 16]));
// Handle emulator CMDs let emulator = ThreadedEmulator::new();
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);
}
});
}
/*
// 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 builder: Builder = Builder::new_from_string(include_str!("ui.glade"));
let window: gtk::ApplicationWindow = builder.get_object("Window").unwrap(); //let window: Option<gtk::ApplicationWindow> = builder.get_object("Window");
let drawing_area: gtk::DrawingArea = builder.get_object("Display").unwrap(); let window: gtk::ApplicationWindow = gtk_rs!(builder=>"Window");
let drawing_area = Arc::from(drawing_area); 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(); let img_m = img_m.clone();
drawing_area.connect_draw( drawing_area.connect_draw(
move |drawing_area: &gtk::DrawingArea, ctx: &cairo::Context| { move |drawing_area: &gtk::DrawingArea, ctx: &cairo::Context| {
@ -102,20 +96,20 @@ pub fn init(app: &gtk::Application) -> Result<(), ProgErr> {
} }
for widget_name in &["Step", "Reset", "Run", "Stop"] { for widget_name in &["Step", "Reset", "Run", "Stop"] {
let tcmd_clone = tcmd.clone(); let tcmd = emulator.tcmd.clone();
let widget: gtk::Button = builder.get_object(widget_name).expect("Not found"); let widget: gtk::Button = gtk_rs!(builder=>widget_name); // builder.get_object(widget_name).expect("Not found");
widget.connect_clicked(move |s: &gtk::Button| { widget.connect_clicked(move |s: &gtk::Button| {
let name = s.get_widget_name().unwrap(); let name = s.get_widget_name().unwrap();
let name = name.as_str(); let name = name.as_str();
println!("Sending from {}", name); 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 // Ram Display
{ /* {
let ram_display_window: gtk::Window = builder.get_object("RamDisplayWindow").unwrap(); let ram_display_window: gtk::Window = gtk_rs!(builder=>"RamDisplayWindow"); // builder.get_object().unwrap();
let switch: gtk::Switch = builder.get_object("RamDisplay").expect("Not Found"); let switch: gtk::Switch = gtk_rs!(builder=>"RamDisplay"); // builder.get_object().expect("Not Found");
switch.connect_state_set(move |switch: &gtk::Switch, state: bool| { switch.connect_state_set(move |switch: &gtk::Switch, state: bool| {
if state { if state {
ram_display_window.show_all(); ram_display_window.show_all();
@ -126,19 +120,17 @@ pub fn init(app: &gtk::Application) -> Result<(), ProgErr> {
Inhibit(false) 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: gtk::Label = gtk_rs!(builder=>"Registers");
let registers = Mutex::from(registers);
// Receive GPU page // Receive GPU page
{ {
let drawing_area = drawing_area.clone(); let drawing_area = drawing_area.clone();
let palette = palette.clone(); let palette = palette.clone();
let emulator = emulator.clone();
let img_m = img_m.clone(); let img_m = img_m.clone();
rdata.attach(None, move |data: Vec<_>| { emulator.rdata.attach(None, move |data: Vec<_>| {
println!("Received page"); println!("Received page");
for line in data.chunks(16) { for line in data.chunks(16) {
println!( println!(
@ -159,10 +151,9 @@ pub fn init(app: &gtk::Application) -> Result<(), ProgErr> {
} }
} }
} }
if let Ok(registers) = registers.try_lock() {
if let Ok(emulator) = emulator.try_lock() { if let Ok(system) = emulator.system.try_lock() {
registers.set_text(&format!("{:#?}", emulator.cpu)); registers.set_text(&format!("{:#?}", system.registers));
}
} }
drawing_area.queue_draw(); drawing_area.queue_draw();
glib::Continue(true) glib::Continue(true)
@ -174,8 +165,8 @@ pub fn init(app: &gtk::Application) -> Result<(), ProgErr> {
for i in 0..16 { for i in 0..16 {
let drawing_area = drawing_area.clone(); let drawing_area = drawing_area.clone();
let palette = palette.clone(); let palette = palette.clone();
let color_button: gtk::ColorButton = let color_button = &format!("ColorPalette{}", i);
builder.get_object(&format!("ColorPalette{}", i)).unwrap(); let color_button: gtk::ColorButton = gtk_rs!(builder=>color_button);
color_button.connect_color_set(move |s: &gtk::ColorButton| { color_button.connect_color_set(move |s: &gtk::ColorButton| {
let color = s.get_rgba(); let color = s.get_rgba();
let color = Color::from((color.red, color.green, color.blue)); let color = Color::from((color.red, color.green, color.blue));
@ -190,13 +181,14 @@ pub fn init(app: &gtk::Application) -> Result<(), ProgErr> {
window.set_application(Some(app)); window.set_application(Some(app));
window.show_all(); window.show_all();
Ok(()) Ok(())
} }
fn main() -> Result<(), ProgErr> { fn main() -> Result<(), ProgErr> {
let app: gtk::Application = let app: gtk::Application =
gtk::Application::new(Some("com.ducklings_corp.emulator"), Default::default())?; 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<_>>()); app.run(&std::env::args().collect::<Vec<_>>());
Ok(()) Ok(())
} }

View File

@ -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 {}