crustacean_6502_emulator/src/main.rs

196 lines
7.1 KiB
Rust
Raw Permalink Normal View History

2020-01-13 03:44:09 +00:00
mod error;
use error::ProgErr;
use cairo;
use gio::prelude::*;
use gtk::prelude::*;
use gtk::Builder;
2020-01-28 03:09:05 +00:00
mod emulator;
2020-01-13 03:44:09 +00:00
mod graphic;
2020-01-28 03:09:05 +00:00
mod handler;
2020-01-13 03:44:09 +00:00
use graphic::{Color, Image};
2020-01-28 03:09:05 +00:00
use handler::{Cmd, ThreadedEmulator};
2020-01-13 03:44:09 +00:00
2020-01-28 03:09:05 +00:00
macro_rules! gtk_rs {
($builder:expr=>$name:expr) => {
$builder
.get_object($name)
.unwrap_or_else(|| panic!("Object {} could't be found", $name))
};
2020-01-13 03:44:09 +00:00
}
2020-01-21 23:49:37 +00:00
pub fn init(app: &gtk::Application) -> Result<(), ProgErr> {
2020-01-13 03:44:09 +00:00
use std::sync::{Arc, Mutex};
2020-01-28 03:09:05 +00:00
let img_m = Arc::from(Mutex::from(Image::new()));
let palette: Arc<Mutex<_>> = Arc::from(Mutex::from([Color::default(); 16]));
2020-01-13 03:44:09 +00:00
2020-01-28 03:09:05 +00:00
let emulator = ThreadedEmulator::new();
2020-01-21 23:49:37 +00:00
2020-01-28 03:09:05 +00:00
/*
// 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;
}
}
});
}
*/
2020-01-13 03:44:09 +00:00
let builder: Builder = Builder::new_from_string(include_str!("ui.glade"));
2020-01-28 03:09:05 +00:00
//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);
2020-01-13 03:44:09 +00:00
{
let img_m = img_m.clone();
2020-01-21 23:49:37 +00:00
drawing_area.connect_draw(
move |drawing_area: &gtk::DrawingArea, ctx: &cairo::Context| {
let widget_width = drawing_area.get_allocated_width();
let widget_height = drawing_area.get_allocated_height();
let img: Result<_, _> = img_m.try_lock();
if let Ok(img) = img {
img.draw(&ctx, (widget_width, widget_height));
}
glib::signal::Inhibit(false)
},
);
2020-01-13 03:44:09 +00:00
}
2020-01-21 23:49:37 +00:00
for widget_name in &["Step", "Reset", "Run", "Stop"] {
2020-01-28 03:09:05 +00:00
let tcmd = emulator.tcmd.clone();
let widget: gtk::Button = gtk_rs!(builder=>widget_name); // builder.get_object(widget_name).expect("Not found");
2020-01-13 03:44:09 +00:00
widget.connect_clicked(move |s: &gtk::Button| {
let name = s.get_widget_name().unwrap();
let name = name.as_str();
println!("Sending from {}", name);
2020-01-28 03:09:05 +00:00
tcmd.send(Cmd::from(name)).expect("Couldn't send cmd");
2020-01-21 23:49:37 +00:00
});
}
// Ram Display
2020-01-28 03:09:05 +00:00
/* {
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");
2020-01-21 23:49:37 +00:00
switch.connect_state_set(move |switch: &gtk::Switch, state: bool| {
if state {
ram_display_window.show_all();
} else {
ram_display_window.close();
}
println!("{}", state);
Inhibit(false)
2020-01-13 03:44:09 +00:00
});
2020-01-28 03:09:05 +00:00
let ram_list: gtk::Window = gtk_rs!(builder=>"RamList");
} */
2020-01-13 03:44:09 +00:00
2020-01-28 03:09:05 +00:00
let registers: gtk::Label = gtk_rs!(builder=>"Registers");
2020-01-13 03:44:09 +00:00
2020-01-21 23:49:37 +00:00
// Receive GPU page
2020-01-13 03:44:09 +00:00
{
2020-01-21 23:49:37 +00:00
let drawing_area = drawing_area.clone();
let palette = palette.clone();
2020-01-13 03:44:09 +00:00
let img_m = img_m.clone();
2020-01-28 03:35:23 +00:00
let system = emulator.system.clone();
2020-01-28 03:09:05 +00:00
emulator.rdata.attach(None, move |data: Vec<_>| {
2020-01-13 03:44:09 +00:00
println!("Received page");
for line in data.chunks(16) {
println!(
"{}",
line.iter()
.map(|h| format!("{:02X}", h))
.collect::<String>()
)
}
2020-01-21 23:49:37 +00:00
if let Ok(mut img) = img_m.try_lock() {
2020-01-13 03:44:09 +00:00
let (w, h) = (img.width, img.height);
let pixels: &mut [Color] = &mut img.pixels;
2020-01-21 23:49:37 +00:00
let palette = palette.lock().expect("Couldn't get palette");
for y in 0..h {
for x in 0..w {
2020-01-13 03:44:09 +00:00
let i = y * w + x;
2020-01-21 23:49:37 +00:00
pixels[i] = palette[data[i] as usize & 0x0F];
2020-01-13 03:44:09 +00:00
}
}
}
2020-01-28 03:09:05 +00:00
2020-01-28 03:35:23 +00:00
if let Ok(system) = system.try_lock() {
2020-01-28 03:09:05 +00:00
registers.set_text(&format!("{:#?}", system.registers));
2020-01-13 03:44:09 +00:00
}
2020-01-21 23:49:37 +00:00
drawing_area.queue_draw();
2020-01-13 03:44:09 +00:00
glib::Continue(true)
});
}
2020-01-21 23:49:37 +00:00
// Color palette
{
for i in 0..16 {
let drawing_area = drawing_area.clone();
let palette = palette.clone();
2020-01-28 03:09:05 +00:00
let color_button = &format!("ColorPalette{}", i);
let color_button: gtk::ColorButton = gtk_rs!(builder=>color_button);
2020-01-21 23:49:37 +00:00
color_button.connect_color_set(move |s: &gtk::ColorButton| {
let color = s.get_rgba();
let color = Color::from((color.red, color.green, color.blue));
let mut palette = palette.lock().expect("Couldn't acquire palette lock");
palette[i] = color;
println!("New color: {:?}", color);
drawing_area.queue_draw();
});
color_button.emit("color-set", &[])?;
}
}
2020-01-13 03:44:09 +00:00
window.set_application(Some(app));
window.show_all();
2020-01-28 03:09:05 +00:00
2020-01-21 23:49:37 +00:00
Ok(())
2020-01-13 03:44:09 +00:00
}
fn main() -> Result<(), ProgErr> {
let app: gtk::Application =
gtk::Application::new(Some("com.ducklings_corp.emulator"), Default::default())?;
2020-01-28 03:09:05 +00:00
app.connect_activate(|app| init(app).expect("Init failed"));
2020-01-13 03:44:09 +00:00
app.run(&std::env::args().collect::<Vec<_>>());
Ok(())
}