Finish binary file loading
This commit is contained in:
parent
9a2e02e1ee
commit
189fd790c1
126
src/load_bin_window.rs
Normal file
126
src/load_bin_window.rs
Normal file
@ -0,0 +1,126 @@
|
||||
use std::{fmt::Display, path::PathBuf};
|
||||
|
||||
use eframe::egui::{self, DragValue};
|
||||
use egui_modal::Modal;
|
||||
use rfd::FileDialog;
|
||||
|
||||
use crate::{state::EmuState, window::Window};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum BinaryType {
|
||||
Raw,
|
||||
IntelHex,
|
||||
}
|
||||
|
||||
impl Display for BinaryType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Raw => f.write_str("Raw"),
|
||||
Self::IntelHex => f.write_str("Intel HEX"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LoadBinWindow {
|
||||
path: Option<PathBuf>,
|
||||
ftype: BinaryType,
|
||||
start_addr: u16,
|
||||
}
|
||||
|
||||
impl LoadBinWindow {
|
||||
pub fn new(ctx: &egui::Context) -> Self {
|
||||
Modal::new(ctx, "load_bin_modal").open();
|
||||
Self {
|
||||
path: None,
|
||||
ftype: BinaryType::Raw,
|
||||
start_addr: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn choose_file(&mut self) {
|
||||
let ihex_exts = ["hex", "mcs", "int", "ihex", "ihe", "ihx"];
|
||||
let file = FileDialog::new()
|
||||
.add_filter(
|
||||
"Binary files",
|
||||
&["bin", "img", "hex", "mcs", "int", "ihex", "ihe", "ihx"],
|
||||
)
|
||||
.add_filter("All files", &["*"])
|
||||
.pick_file();
|
||||
let Some(file) = file else {
|
||||
return;
|
||||
};
|
||||
if file
|
||||
.extension()
|
||||
.map_or(false, |ext| ihex_exts.contains(&ext.to_str().unwrap_or("")))
|
||||
{
|
||||
self.ftype = BinaryType::IntelHex;
|
||||
} else {
|
||||
self.ftype = BinaryType::Raw;
|
||||
}
|
||||
self.path = Some(file);
|
||||
}
|
||||
|
||||
fn load_file(&self, state: &mut EmuState) {
|
||||
let path = self.path.as_ref().unwrap();
|
||||
match self.ftype {
|
||||
BinaryType::Raw => {
|
||||
let bin = std::fs::read(path).unwrap();
|
||||
state.write_binary(self.start_addr as usize, bin);
|
||||
}
|
||||
BinaryType::IntelHex => {
|
||||
let data = std::fs::read_to_string(path).unwrap();
|
||||
for record in ihex::Reader::new(&data) {
|
||||
let record = record.unwrap();
|
||||
match record {
|
||||
ihex::Record::Data { offset, value } => {
|
||||
state.write_binary(offset as usize, value);
|
||||
}
|
||||
ihex::Record::StartLinearAddress(_) => todo!(),
|
||||
ihex::Record::EndOfFile => (),
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Window for LoadBinWindow {
|
||||
fn draw(&mut self, ctx: &egui::Context, state: &mut EmuState) -> bool {
|
||||
let modal = Modal::new(ctx, "load_bin_modal");
|
||||
modal.show(|ui| {
|
||||
modal.title(ui, "Load binary");
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Choose file").clicked() {
|
||||
self.choose_file();
|
||||
}
|
||||
ui.label(format!(
|
||||
"{}",
|
||||
self.path.as_ref().map_or("".into(), |x| x
|
||||
.file_name()
|
||||
.map_or("".into(), |x| x.to_string_lossy().to_string()))
|
||||
));
|
||||
});
|
||||
egui::ComboBox::from_label("File type")
|
||||
.selected_text(format!("{}", self.ftype))
|
||||
.show_ui(ui, |ui| {
|
||||
ui.selectable_value(&mut self.ftype, BinaryType::Raw, "Raw");
|
||||
ui.selectable_value(&mut self.ftype, BinaryType::IntelHex, "Intel HEX");
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.set_enabled(self.ftype != BinaryType::IntelHex);
|
||||
ui.add(DragValue::new(&mut self.start_addr).clamp_range(0..=65535));
|
||||
ui.label("Start address");
|
||||
});
|
||||
modal.buttons(ui, |ui| {
|
||||
modal.caution_button(ui, "Cancel");
|
||||
ui.add_enabled_ui(self.path.is_some(), |ui| {
|
||||
if modal.suggested_button(ui, "Load").clicked() {
|
||||
self.load_file(state);
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
!modal.is_open()
|
||||
}
|
||||
}
|
42
src/main.rs
42
src/main.rs
@ -2,10 +2,11 @@ mod audio;
|
||||
mod card;
|
||||
mod cpu;
|
||||
mod frontpanel;
|
||||
mod ram;
|
||||
mod window;
|
||||
mod state;
|
||||
mod load_bin_window;
|
||||
mod option_window;
|
||||
mod ram;
|
||||
mod state;
|
||||
mod window;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
@ -15,6 +16,7 @@ use eframe::{
|
||||
NativeOptions,
|
||||
};
|
||||
use frontpanel::Textures;
|
||||
use load_bin_window::LoadBinWindow;
|
||||
use option_window::OptionWindow;
|
||||
use rfd::FileDialog;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -56,7 +58,6 @@ struct AltairEmulator {
|
||||
windows: HashMap<&'static str, Box<dyn Window>>,
|
||||
}
|
||||
|
||||
|
||||
impl AltairEmulator {
|
||||
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||
let audio_tx = AudioThread::init();
|
||||
@ -89,37 +90,8 @@ impl AltairEmulator {
|
||||
ui.close_menu();
|
||||
}
|
||||
if ui.button("Load binary file").clicked() {
|
||||
let ihex_exts = ["hex", "mcs", "int", "ihex", "ihe", "ihx"];
|
||||
let file = FileDialog::new()
|
||||
.add_filter(
|
||||
"Binary files",
|
||||
&["bin", "img", "hex", "mcs", "int", "ihex", "ihe", "ihx"],
|
||||
)
|
||||
.add_filter("All files", &["*"])
|
||||
.pick_file();
|
||||
if let Some(file) = file {
|
||||
if file
|
||||
.extension()
|
||||
.map_or(false, |ext| ihex_exts.contains(&ext.to_str().unwrap_or("")))
|
||||
{
|
||||
let data = std::fs::read_to_string(file).unwrap();
|
||||
for record in ihex::Reader::new(&data) {
|
||||
let record = record.unwrap();
|
||||
match record {
|
||||
ihex::Record::Data { offset, value } => {
|
||||
self.state.write_binary(offset as usize, value);
|
||||
}
|
||||
ihex::Record::StartLinearAddress(_) => todo!(),
|
||||
ihex::Record::EndOfFile => (),
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// Raw binary
|
||||
todo!();
|
||||
}
|
||||
self.state.update_fp();
|
||||
}
|
||||
self.windows
|
||||
.insert("load_bin_window", Box::new(LoadBinWindow::new(ui.ctx())));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
use eframe::egui::{self, Slider};
|
||||
use egui_modal::Modal;
|
||||
|
||||
use crate::{Options, state::EmuState, window::Window};
|
||||
use crate::{state::EmuState, window::Window, Options};
|
||||
|
||||
pub struct OptionWindow {
|
||||
options: Options,
|
||||
|
@ -2,7 +2,12 @@ use std::sync::mpsc::Sender;
|
||||
|
||||
use rand::RngCore;
|
||||
|
||||
use crate::{cpu::{I8080, Status, MemCycle}, audio::AudioMessage, Options, frontpanel::{FrontpanelState, FrontpanelInteraction, ActionSwitch, switch::SwitchState}};
|
||||
use crate::{
|
||||
audio::AudioMessage,
|
||||
cpu::{MemCycle, Status, I8080},
|
||||
frontpanel::{switch::SwitchState, ActionSwitch, FrontpanelInteraction, FrontpanelState},
|
||||
Options,
|
||||
};
|
||||
|
||||
pub struct EmuState {
|
||||
mem: [u8; 65536],
|
||||
@ -23,7 +28,7 @@ impl EmuState {
|
||||
running: false,
|
||||
audio_tx,
|
||||
options,
|
||||
fp_state: FrontpanelState::new()
|
||||
fp_state: FrontpanelState::new(),
|
||||
};
|
||||
slf.apply_options();
|
||||
slf
|
||||
|
Loading…
Reference in New Issue
Block a user