820 lines
34 KiB
Rust
820 lines
34 KiB
Rust
use std::sync::Arc;
|
|
|
|
use egui::{
|
|
Align, Button, CentralPanel, Checkbox, Color32, Context, Direction, Label, Layout, ScrollArea,
|
|
TextEdit, Ui, ViewportBuilder, ViewportId,
|
|
};
|
|
use egui_extras::{Column, Size, StripBuilder, TableBuilder};
|
|
|
|
use crate::{
|
|
emulator::SimId,
|
|
memory::{MemoryClient, MemoryRef, MemoryValue, MemoryView},
|
|
window::{
|
|
AppWindow,
|
|
utils::{NumberEdit, UiExt},
|
|
},
|
|
};
|
|
|
|
use super::utils;
|
|
|
|
pub struct RegisterWindow {
|
|
sim_id: SimId,
|
|
memory: Arc<MemoryClient>,
|
|
registers: MemoryView,
|
|
}
|
|
|
|
impl RegisterWindow {
|
|
pub fn new(sim_id: SimId, memory: &Arc<MemoryClient>) -> Self {
|
|
Self {
|
|
sim_id,
|
|
memory: memory.clone(),
|
|
registers: memory.watch(sim_id, 0x0005f800, 0x72),
|
|
}
|
|
}
|
|
|
|
fn show_interrupts(&mut self, ui: &mut Ui) {
|
|
let row_height = self.row_height(ui);
|
|
let [mut raw_intpnd, mut raw_intenb] = self.read_address(0x0005f800);
|
|
let mut intenb = InterruptReg::parse(raw_intenb);
|
|
let mut intpnd = InterruptReg::parse(raw_intpnd);
|
|
ui.section("Interrupt", |ui| {
|
|
let width = ui.available_width();
|
|
let xspace = ui.spacing().item_spacing.x;
|
|
ui.with_layout(Layout::top_down_justified(Align::Center), |ui| {
|
|
TableBuilder::new(ui)
|
|
.id_salt("raw_values")
|
|
.columns(Column::exact(width * 0.5 - xspace), 2)
|
|
.cell_layout(Layout::left_to_right(Align::Max))
|
|
.body(|mut body| {
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("INTENB");
|
|
});
|
|
row.col(|ui| {
|
|
let mut text = format!("{raw_intenb:04x}");
|
|
ui.add_sized(
|
|
ui.available_size(),
|
|
TextEdit::singleline(&mut text).horizontal_align(Align::Max),
|
|
);
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("INTPND");
|
|
});
|
|
row.col(|ui| {
|
|
let mut text = format!("{raw_intpnd:04x}");
|
|
ui.add_enabled(
|
|
false,
|
|
TextEdit::singleline(&mut text).horizontal_align(Align::Max),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
ui.add_space(8.0);
|
|
TableBuilder::new(ui)
|
|
.id_salt("flags")
|
|
.column(Column::exact(width * 0.5 - xspace))
|
|
.columns(Column::exact(width * 0.25 - xspace), 2)
|
|
.cell_layout(Layout::left_to_right(Align::Center).with_main_align(Align::RIGHT))
|
|
.body(|mut body| {
|
|
body.row(row_height, |mut row| {
|
|
row.col(|_ui| {});
|
|
row.col(|ui| {
|
|
ui.add_sized(ui.available_size(), Label::new("ENB"));
|
|
});
|
|
row.col(|ui| {
|
|
ui.add_sized(ui.available_size(), Label::new("PND"));
|
|
});
|
|
});
|
|
let mut add_row = |label: &str, enb: &mut bool, pnd: &mut bool| {
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label(label);
|
|
});
|
|
row.col(|ui| {
|
|
let space =
|
|
(ui.available_width() - ui.spacing().icon_width) / 2.0;
|
|
ui.add_space(space);
|
|
ui.checkbox(enb, "");
|
|
});
|
|
row.col(|ui| {
|
|
let space =
|
|
(ui.available_width() - ui.spacing().icon_width) / 2.0;
|
|
ui.add_space(space);
|
|
ui.checkbox(pnd, "");
|
|
});
|
|
});
|
|
};
|
|
add_row("TIMEERR", &mut intenb.timeerr, &mut intpnd.timeerr);
|
|
add_row("XPEND", &mut intenb.xpend, &mut intpnd.xpend);
|
|
add_row("SBHIT", &mut intenb.sbhit, &mut intpnd.sbhit);
|
|
add_row("FRAMESTART", &mut intenb.framestart, &mut intpnd.framestart);
|
|
add_row("GAMESTART", &mut intenb.gamestart, &mut intpnd.gamestart);
|
|
add_row("RFBEND", &mut intenb.rfbend, &mut intpnd.rfbend);
|
|
add_row("LFBEND", &mut intenb.lfbend, &mut intpnd.lfbend);
|
|
add_row("SCANERR", &mut intenb.scanerr, &mut intpnd.scanerr);
|
|
});
|
|
});
|
|
ui.allocate_space(ui.available_size());
|
|
});
|
|
if intpnd.update(&mut raw_intpnd) {
|
|
self.memory.write(self.sim_id, 0x0005f800, &raw_intpnd);
|
|
}
|
|
if intenb.update(&mut raw_intenb) {
|
|
self.memory.write(self.sim_id, 0x0005f802, &raw_intenb);
|
|
}
|
|
}
|
|
|
|
fn show_display_status(&mut self, ui: &mut Ui) {
|
|
let row_height = self.row_height(ui);
|
|
let mut raw_dpstts = self.read_address(0x0005f820);
|
|
let mut dpstts = DisplayReg::parse(raw_dpstts);
|
|
ui.section("Display", |ui| {
|
|
let width = ui.available_width();
|
|
TableBuilder::new(ui)
|
|
.column(Column::exact(width * 0.5))
|
|
.column(Column::exact(width * 0.5))
|
|
.cell_layout(Layout::left_to_right(Align::Max))
|
|
.body(|mut body| {
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("DPSTTS");
|
|
});
|
|
row.col(|ui| {
|
|
let mut value_str = format!("{raw_dpstts:04x}");
|
|
ui.add_enabled(
|
|
false,
|
|
TextEdit::singleline(&mut value_str).horizontal_align(Align::Max),
|
|
);
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.add_enabled(true, Checkbox::new(&mut dpstts.lock, "LOCK"));
|
|
});
|
|
row.col(|ui| {
|
|
ui.add_enabled(false, Checkbox::new(&mut dpstts.r1bsy, "R1BSY"));
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.add_enabled(true, Checkbox::new(&mut dpstts.synce, "SYNCE"));
|
|
});
|
|
row.col(|ui| {
|
|
ui.add_enabled(false, Checkbox::new(&mut dpstts.l1bsy, "L1BSY"));
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.add_enabled(true, Checkbox::new(&mut dpstts.re, "RE"));
|
|
});
|
|
row.col(|ui| {
|
|
ui.add_enabled(false, Checkbox::new(&mut dpstts.r0bsy, "R0BSY"));
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.add_enabled(false, Checkbox::new(&mut dpstts.fclk, "FCLK"));
|
|
});
|
|
row.col(|ui| {
|
|
ui.add_enabled(false, Checkbox::new(&mut dpstts.l0bsy, "L0BSY"));
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.add_enabled(false, Checkbox::new(&mut dpstts.scanrdy, "SCANRDY"));
|
|
});
|
|
row.col(|ui| {
|
|
ui.add_enabled(true, Checkbox::new(&mut dpstts.disp, "DISP"));
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|_ui| {});
|
|
row.col(|ui| {
|
|
if ui
|
|
.add(Button::new("DPRST").min_size(ui.available_size()))
|
|
.clicked()
|
|
{
|
|
dpstts.dprst = true;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
ui.allocate_space(ui.available_size());
|
|
});
|
|
if dpstts.update(&mut raw_dpstts) {
|
|
self.memory.write(self.sim_id, 0x0005f822, &raw_dpstts);
|
|
}
|
|
}
|
|
|
|
fn show_drawing_status(&mut self, ui: &mut Ui) {
|
|
let row_height = self.row_height(ui);
|
|
let [mut raw_xpstts, raw_xpctrl] = self.read_address(0x0005f840);
|
|
let mut xpstts = DrawingReg::parse(raw_xpstts);
|
|
ui.section("Drawing", |ui| {
|
|
let width = ui.available_width();
|
|
TableBuilder::new(ui)
|
|
.column(Column::exact(width * 0.5))
|
|
.column(Column::exact(width * 0.5))
|
|
.cell_layout(Layout::left_to_right(Align::Max))
|
|
.body(|mut body| {
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("XPCTRL");
|
|
});
|
|
row.col(|ui| {
|
|
let mut value_str = format!("{raw_xpctrl:04x}");
|
|
ui.add_enabled(
|
|
false,
|
|
TextEdit::singleline(&mut value_str).horizontal_align(Align::Max),
|
|
);
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("XPSTTS");
|
|
});
|
|
row.col(|ui| {
|
|
let mut value_str = format!("{raw_xpstts:04x}");
|
|
ui.add_enabled(
|
|
false,
|
|
TextEdit::singleline(&mut value_str).horizontal_align(Align::Max),
|
|
);
|
|
});
|
|
});
|
|
/*
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("SBCMP");
|
|
});
|
|
row.col(|ui| {
|
|
let old_value = xpctrl.sbcmp;
|
|
ui.add_enabled(true, NumberEdit::new(&mut xpctrl.sbcmp).range(0..32));
|
|
cmp_changed = xpctrl.sbcmp != old_value;
|
|
});
|
|
});
|
|
*/
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("SBCOUNT");
|
|
});
|
|
row.col(|ui| {
|
|
ui.add_enabled(
|
|
false,
|
|
NumberEdit::new(&mut xpstts.sbcount)
|
|
.arrows(false)
|
|
.range(0..32),
|
|
);
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.add_enabled(false, Checkbox::new(&mut xpstts.sbout, "SBOUT"));
|
|
});
|
|
row.col(|ui| {
|
|
ui.add_enabled(false, Checkbox::new(&mut xpstts.f1bsy, "F1BSY"));
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.add_enabled(false, Checkbox::new(&mut xpstts.f0bsy, "F0BSY"));
|
|
});
|
|
row.col(|ui| {
|
|
ui.add_enabled(false, Checkbox::new(&mut xpstts.overtime, "OVERTIME"));
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.add_enabled(true, Checkbox::new(&mut xpstts.xpen, "XPEN"));
|
|
});
|
|
row.col(|ui| {
|
|
if ui
|
|
.add(Button::new("XPRST").min_size(ui.available_size()))
|
|
.clicked()
|
|
{
|
|
xpstts.xprst = true;
|
|
}
|
|
});
|
|
});
|
|
});
|
|
ui.allocate_space(ui.available_size());
|
|
});
|
|
if xpstts.update(&mut raw_xpstts) {
|
|
xpstts.update(&mut raw_xpstts);
|
|
self.memory.write(self.sim_id, 0x0005f842, &raw_xpstts);
|
|
}
|
|
}
|
|
|
|
fn show_colors(&mut self, ui: &mut Ui) {
|
|
let row_height = self.row_height(ui);
|
|
let registers = self.registers.borrow();
|
|
ui.section("Colors", |ui| {
|
|
let width = ui.available_width();
|
|
let xspace = ui.spacing().item_spacing.x;
|
|
TableBuilder::new(ui)
|
|
.column(Column::exact(width * 0.2 - xspace))
|
|
.columns(Column::exact(width * 0.20 - xspace), 4)
|
|
.cell_layout(Layout::left_to_right(Align::Max))
|
|
.body(|mut body| {
|
|
body.row(row_height, |mut row| {
|
|
row.col(|_ui| {});
|
|
row.col(|_ui| {});
|
|
row.col(|ui| {
|
|
ui.with_layout(
|
|
Layout::centered_and_justified(Direction::LeftToRight),
|
|
|ui| ui.label("1"),
|
|
);
|
|
});
|
|
row.col(|ui| {
|
|
ui.with_layout(
|
|
Layout::centered_and_justified(Direction::LeftToRight),
|
|
|ui| ui.label("2"),
|
|
);
|
|
});
|
|
row.col(|ui| {
|
|
ui.with_layout(
|
|
Layout::centered_and_justified(Direction::LeftToRight),
|
|
|ui| ui.label("3"),
|
|
);
|
|
});
|
|
});
|
|
let mut brts: [u16; 3] = [
|
|
read_address(®isters, 0x0005f824),
|
|
read_address(®isters, 0x0005f826),
|
|
read_address(®isters, 0x0005f828),
|
|
];
|
|
body.row(row_height, |mut row| {
|
|
let mut stale = false;
|
|
row.col(|ui| {
|
|
ui.label("BRT");
|
|
});
|
|
row.col(|_ui| {});
|
|
for brt in brts.iter_mut() {
|
|
row.col(|ui| {
|
|
if ui
|
|
.add(NumberEdit::new(brt).range(0..256).arrows(false).hex(true))
|
|
.changed()
|
|
{
|
|
stale = true;
|
|
}
|
|
});
|
|
}
|
|
if stale {
|
|
self.memory.write(self.sim_id, 0x0005f824, &brts);
|
|
}
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|_ui| {});
|
|
for shade in utils::parse_brts(&brts, Color32::RED) {
|
|
row.col(|ui| {
|
|
ui.painter().rect_filled(
|
|
ui.available_rect_before_wrap(),
|
|
0.0,
|
|
shade,
|
|
);
|
|
});
|
|
}
|
|
});
|
|
let mut palettes = read_address::<[u16; 8]>(®isters, 0x0005f860);
|
|
let mut add_row = |name: &str, address: u32, value: &mut u16| {
|
|
let mut c1 = (*value >> 2) & 0x03;
|
|
let mut c2 = (*value >> 4) & 0x03;
|
|
let mut c3 = (*value >> 6) & 0x03;
|
|
let mut stale = false;
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label(name);
|
|
});
|
|
row.col(|ui| {
|
|
if ui
|
|
.add(
|
|
NumberEdit::new(value)
|
|
.range(0..256)
|
|
.desired_width(width * 0.2)
|
|
.arrows(false)
|
|
.hex(true),
|
|
)
|
|
.changed()
|
|
{
|
|
stale = true;
|
|
};
|
|
});
|
|
row.col(|ui| {
|
|
if ui
|
|
.add(
|
|
NumberEdit::new(&mut c1)
|
|
.range(0..4)
|
|
.desired_width(ui.available_width() - xspace),
|
|
)
|
|
.changed()
|
|
{
|
|
*value = (*value & 0xfff3) | (c1 << 2);
|
|
stale = true;
|
|
}
|
|
});
|
|
row.col(|ui| {
|
|
if ui
|
|
.add(
|
|
NumberEdit::new(&mut c2)
|
|
.range(0..4)
|
|
.desired_width(ui.available_width() - xspace),
|
|
)
|
|
.changed()
|
|
{
|
|
*value = (*value & 0xffcf) | (c2 << 4);
|
|
stale = true;
|
|
}
|
|
});
|
|
row.col(|ui| {
|
|
if ui
|
|
.add(
|
|
NumberEdit::new(&mut c3)
|
|
.range(0..4)
|
|
.desired_width(ui.available_width() - xspace),
|
|
)
|
|
.changed()
|
|
{
|
|
*value = (*value & 0xff3f) | (c3 << 6);
|
|
stale = true;
|
|
}
|
|
});
|
|
});
|
|
if stale {
|
|
self.memory.write(self.sim_id, address, value);
|
|
}
|
|
};
|
|
|
|
add_row("GPLT0", 0x0005f860, &mut palettes[0]);
|
|
add_row("GPLT1", 0x0005f862, &mut palettes[1]);
|
|
add_row("GPLT2", 0x0005f864, &mut palettes[2]);
|
|
add_row("GPLT3", 0x0005f866, &mut palettes[3]);
|
|
add_row("JPLT0", 0x0005f868, &mut palettes[4]);
|
|
add_row("JPLT1", 0x0005f86a, &mut palettes[5]);
|
|
add_row("JPLT2", 0x0005f86c, &mut palettes[6]);
|
|
add_row("JPLT3", 0x0005f86e, &mut palettes[7]);
|
|
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("BKCOL");
|
|
});
|
|
row.col(|ui| {
|
|
let mut bkcol: u16 = read_address(®isters, 0x0005f870);
|
|
if ui
|
|
.add(
|
|
NumberEdit::new(&mut bkcol)
|
|
.range(0..4)
|
|
.desired_width(ui.available_width() - xspace),
|
|
)
|
|
.changed()
|
|
{
|
|
self.memory.write(self.sim_id, 0x0005f870, &bkcol);
|
|
}
|
|
});
|
|
row.col(|_ui| {});
|
|
row.col(|ui| {
|
|
ui.label("REST");
|
|
});
|
|
row.col(|ui| {
|
|
let mut rest: u16 = read_address(®isters, 0x0005f82a);
|
|
if ui
|
|
.add(
|
|
NumberEdit::new(&mut rest)
|
|
.range(0..256)
|
|
.arrows(false)
|
|
.hex(true),
|
|
)
|
|
.changed()
|
|
{
|
|
self.memory.write(self.sim_id, 0x0005f82a, &rest);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
ui.allocate_space(ui.available_size_before_wrap());
|
|
});
|
|
}
|
|
|
|
fn show_objects(&mut self, ui: &mut Ui) {
|
|
let row_height = self.row_height(ui);
|
|
ui.section("Objects", |ui| {
|
|
let width = ui.available_width();
|
|
let xspace = ui.spacing().item_spacing.x;
|
|
TableBuilder::new(ui)
|
|
.column(Column::exact(width * 0.3 - xspace))
|
|
.column(Column::exact(width * 0.3 - xspace))
|
|
.column(Column::exact(width * 0.4 - xspace))
|
|
.cell_layout(Layout::left_to_right(Align::Center).with_main_align(Align::RIGHT))
|
|
.body(|mut body| {
|
|
body.row(row_height, |mut row| {
|
|
row.col(|_ui| {});
|
|
row.col(|ui| {
|
|
ui.add_sized(ui.available_size(), Label::new("Start"));
|
|
});
|
|
row.col(|ui| {
|
|
ui.add_sized(ui.available_size(), Label::new("End"));
|
|
});
|
|
});
|
|
let mut spts = self.read_address::<[u16; 4]>(0x0005f848);
|
|
let prevs = std::iter::once(0u16).chain(spts.map(|i| (i + 1) & 0x03ff));
|
|
let mut changed = false;
|
|
for (index, (spt, prev)) in spts.iter_mut().zip(prevs).enumerate() {
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label(format!("SPT{index}"));
|
|
});
|
|
row.col(|ui| {
|
|
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
|
ui.label(prev.to_string());
|
|
});
|
|
});
|
|
row.col(|ui| {
|
|
if ui.add(NumberEdit::new(spt).range(0..1024)).changed() {
|
|
changed = true;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
if changed {
|
|
self.memory.write(self.sim_id, 0x0005f848, &spts);
|
|
}
|
|
});
|
|
ui.allocate_space(ui.available_size_before_wrap());
|
|
});
|
|
}
|
|
|
|
fn show_misc(&mut self, ui: &mut Ui) {
|
|
let row_height = self.row_height(ui);
|
|
let registers = self.registers.borrow();
|
|
ui.section("Misc.", |ui| {
|
|
let width = ui.available_width();
|
|
let xspace = ui.spacing().item_spacing.x;
|
|
TableBuilder::new(ui)
|
|
.column(Column::exact(width * 0.5 - xspace))
|
|
.column(Column::exact(width * 0.5 - xspace))
|
|
.cell_layout(Layout::left_to_right(Align::Center).with_main_align(Align::RIGHT))
|
|
.body(|mut body| {
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("FRMCYC");
|
|
});
|
|
row.col(|ui| {
|
|
let mut frmcyc = read_address::<u16>(®isters, 0x0005f82e);
|
|
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
|
if ui.add(NumberEdit::new(&mut frmcyc).range(0..32)).changed() {
|
|
self.memory.write(self.sim_id, 0x0005f82e, &frmcyc);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
let mut cta = read_address::<u16>(®isters, 0x0005f830);
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("CTA");
|
|
});
|
|
row.col(|ui| {
|
|
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
|
ui.add_enabled(
|
|
false,
|
|
NumberEdit::new(&mut cta).arrows(false).hex(true),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("CTA_L");
|
|
});
|
|
row.col(|ui| {
|
|
let mut cta_l = cta & 0xff;
|
|
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
|
ui.add_enabled(
|
|
false,
|
|
NumberEdit::new(&mut cta_l).arrows(false).hex(true),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
body.row(row_height, |mut row| {
|
|
row.col(|ui| {
|
|
ui.label("CTA_R");
|
|
});
|
|
row.col(|ui| {
|
|
let mut cta_r = (cta >> 8) & 0xff;
|
|
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
|
|
ui.add_enabled(
|
|
false,
|
|
NumberEdit::new(&mut cta_r).arrows(false).hex(true),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
ui.allocate_space(ui.available_size_before_wrap());
|
|
});
|
|
}
|
|
|
|
fn row_height(&self, ui: &mut Ui) -> f32 {
|
|
ui.spacing().interact_size.y + ui.style().visuals.selection.stroke.width
|
|
}
|
|
|
|
fn read_address<T: MemoryValue>(&self, address: usize) -> T {
|
|
read_address(&self.registers.borrow(), address)
|
|
}
|
|
}
|
|
|
|
fn read_address<T: MemoryValue>(registers: &MemoryRef, address: usize) -> T {
|
|
let index = (address - 0x0005f800) / size_of::<T>();
|
|
registers.read(index)
|
|
}
|
|
|
|
impl AppWindow for RegisterWindow {
|
|
fn viewport_id(&self) -> ViewportId {
|
|
ViewportId::from_hash_of(format!("registers-{}", self.sim_id))
|
|
}
|
|
|
|
fn sim_id(&self) -> SimId {
|
|
self.sim_id
|
|
}
|
|
|
|
fn initial_viewport(&self) -> ViewportBuilder {
|
|
ViewportBuilder::default()
|
|
.with_title(format!("Registers ({})", self.sim_id))
|
|
.with_inner_size((800.0, 480.0))
|
|
}
|
|
|
|
fn show(&mut self, ctx: &Context) {
|
|
CentralPanel::default().show(ctx, |ui| {
|
|
ScrollArea::vertical().show(ui, |ui| {
|
|
ui.horizontal_top(|ui| {
|
|
let width = ui.available_width();
|
|
let xspace = ui.spacing().item_spacing.x;
|
|
StripBuilder::new(ui)
|
|
.size(Size::exact(width * 0.25 - xspace))
|
|
.size(Size::exact(width * 0.225 - xspace))
|
|
.size(Size::exact(width * 0.325 - xspace))
|
|
.size(Size::exact(width * 0.2 - xspace))
|
|
.horizontal(|mut strip| {
|
|
strip.cell(|ui| {
|
|
self.show_interrupts(ui);
|
|
});
|
|
strip.strip(|nested| {
|
|
nested.sizes(Size::remainder(), 2).vertical(|mut strip| {
|
|
strip.cell(|ui| {
|
|
self.show_display_status(ui);
|
|
});
|
|
strip.cell(|ui| {
|
|
self.show_drawing_status(ui);
|
|
});
|
|
});
|
|
});
|
|
strip.cell(|ui| {
|
|
self.show_colors(ui);
|
|
});
|
|
strip.strip(|nested| {
|
|
nested.sizes(Size::remainder(), 2).vertical(|mut strip| {
|
|
strip.cell(|ui| {
|
|
self.show_objects(ui);
|
|
});
|
|
strip.cell(|ui| {
|
|
self.show_misc(ui);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
struct InterruptReg {
|
|
timeerr: bool,
|
|
xpend: bool,
|
|
sbhit: bool,
|
|
framestart: bool,
|
|
gamestart: bool,
|
|
rfbend: bool,
|
|
lfbend: bool,
|
|
scanerr: bool,
|
|
}
|
|
|
|
impl InterruptReg {
|
|
fn parse(value: u16) -> Self {
|
|
Self {
|
|
timeerr: value & 0x8000 != 0,
|
|
xpend: value & 0x4000 != 0,
|
|
sbhit: value & 0x2000 != 0,
|
|
framestart: value & 0x0010 != 0,
|
|
gamestart: value & 0x0008 != 0,
|
|
rfbend: value & 0x0004 != 0,
|
|
lfbend: value & 0x0002 != 0,
|
|
scanerr: value & 0x0001 != 0,
|
|
}
|
|
}
|
|
|
|
fn update(&self, value: &mut u16) -> bool {
|
|
let new_value = (*value & 0x1fe0)
|
|
| if self.timeerr { 0x8000 } else { 0x0000 }
|
|
| if self.xpend { 0x4000 } else { 0x0000 }
|
|
| if self.sbhit { 0x2000 } else { 0x0000 }
|
|
| if self.framestart { 0x0010 } else { 0x0000 }
|
|
| if self.gamestart { 0x0008 } else { 0x0000 }
|
|
| if self.rfbend { 0x0004 } else { 0x0000 }
|
|
| if self.lfbend { 0x0002 } else { 0x0000 }
|
|
| if self.scanerr { 0x0001 } else { 0x0000 };
|
|
let changed = *value != new_value;
|
|
*value = new_value;
|
|
changed
|
|
}
|
|
}
|
|
|
|
struct DisplayReg {
|
|
lock: bool,
|
|
synce: bool,
|
|
re: bool,
|
|
fclk: bool,
|
|
scanrdy: bool,
|
|
r1bsy: bool,
|
|
l1bsy: bool,
|
|
r0bsy: bool,
|
|
l0bsy: bool,
|
|
disp: bool,
|
|
dprst: bool,
|
|
}
|
|
|
|
impl DisplayReg {
|
|
fn parse(value: u16) -> Self {
|
|
Self {
|
|
lock: value & 0x0400 != 0,
|
|
synce: value & 0x0200 != 0,
|
|
re: value & 0x0100 != 0,
|
|
fclk: value & 0x0080 != 0,
|
|
scanrdy: value & 0x0040 != 0,
|
|
r1bsy: value & 0x0020 != 0,
|
|
l1bsy: value & 0x0010 != 0,
|
|
r0bsy: value & 0x0008 != 0,
|
|
l0bsy: value & 0x0004 != 0,
|
|
disp: value & 0x0002 != 0,
|
|
dprst: value & 0x0001 != 0,
|
|
}
|
|
}
|
|
|
|
fn update(&self, value: &mut u16) -> bool {
|
|
let new_value = (*value & 0xf800)
|
|
| if self.lock { 0x0400 } else { 0x0000 }
|
|
| if self.synce { 0x0200 } else { 0x0000 }
|
|
| if self.re { 0x0100 } else { 0x0000 }
|
|
| if self.fclk { 0x0080 } else { 0x0000 }
|
|
| if self.scanrdy { 0x0040 } else { 0x0000 }
|
|
| if self.r1bsy { 0x0020 } else { 0x0000 }
|
|
| if self.l1bsy { 0x0010 } else { 0x0000 }
|
|
| if self.r0bsy { 0x0008 } else { 0x0000 }
|
|
| if self.l0bsy { 0x0004 } else { 0x0000 }
|
|
| if self.disp { 0x0002 } else { 0x0000 }
|
|
| if self.dprst { 0x0001 } else { 0x0000 };
|
|
let changed = *value != new_value;
|
|
*value = new_value;
|
|
changed
|
|
}
|
|
}
|
|
|
|
struct DrawingReg {
|
|
sbout: bool,
|
|
sbcount: u8,
|
|
overtime: bool,
|
|
f1bsy: bool,
|
|
f0bsy: bool,
|
|
xpen: bool,
|
|
xprst: bool,
|
|
}
|
|
|
|
impl DrawingReg {
|
|
fn parse(value: u16) -> Self {
|
|
Self {
|
|
sbout: value & 0x8000 != 0,
|
|
sbcount: (value >> 8) as u8 & 0x1f,
|
|
overtime: value & 0x0010 != 0,
|
|
f1bsy: value & 0x0008 != 0,
|
|
f0bsy: value & 0x0004 != 0,
|
|
xpen: value & 0x0002 != 0,
|
|
xprst: value & 0x0001 != 0,
|
|
}
|
|
}
|
|
|
|
fn update(&self, value: &mut u16) -> bool {
|
|
let new_value = (*value & 0x60e0)
|
|
| if self.sbout { 0x8000 } else { 0x0000 }
|
|
| (((self.sbcount & 0x1f) as u16) << 8)
|
|
| if self.overtime { 0x0010 } else { 0x0000 }
|
|
| if self.f1bsy { 0x0008 } else { 0x0000 }
|
|
| if self.f0bsy { 0x0004 } else { 0x0000 }
|
|
| if self.xpen { 0x0002 } else { 0x0000 }
|
|
| if self.xprst { 0x0001 } else { 0x0000 };
|
|
let changed = *value != new_value;
|
|
*value = new_value;
|
|
changed
|
|
}
|
|
}
|