VIP inspection tooling #4
|
@ -1,9 +1,10 @@
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::{Display, UpperHex},
|
||||||
ops::{Bound, RangeBounds},
|
ops::{Bound, RangeBounds},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use atoi::FromRadix16;
|
||||||
use egui::{
|
use egui::{
|
||||||
ecolor::HexColor, Align, Color32, CursorIcon, Event, Frame, Key, Layout, Margin, Rect,
|
ecolor::HexColor, Align, Color32, CursorIcon, Event, Frame, Key, Layout, Margin, Rect,
|
||||||
Response, RichText, Rounding, Sense, Shape, Stroke, TextEdit, Ui, UiBuilder, Vec2, Widget,
|
Response, RichText, Rounding, Sense, Shape, Stroke, TextEdit, Ui, UiBuilder, Vec2, Widget,
|
||||||
|
@ -38,7 +39,12 @@ impl UiExt for Ui {
|
||||||
let mut frame = Frame::group(self.style());
|
let mut frame = Frame::group(self.style());
|
||||||
frame.outer_margin.top += 10.0;
|
frame.outer_margin.top += 10.0;
|
||||||
frame.inner_margin.top += 2.0;
|
frame.inner_margin.top += 2.0;
|
||||||
let res = self.push_id(&title, |ui| frame.show(ui, add_contents));
|
let res = self.push_id(&title, |ui| {
|
||||||
|
frame.show(ui, |ui| {
|
||||||
|
ui.set_min_width(ui.available_width());
|
||||||
|
add_contents(ui);
|
||||||
|
})
|
||||||
|
});
|
||||||
let text = RichText::new(title).background_color(self.style().visuals.panel_fill);
|
let text = RichText::new(title).background_color(self.style().visuals.panel_fill);
|
||||||
let old_rect = res.response.rect;
|
let old_rect = res.response.rect;
|
||||||
let mut text_rect = old_rect;
|
let mut text_rect = old_rect;
|
||||||
|
@ -98,11 +104,35 @@ enum Direction {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Number:
|
pub trait Number:
|
||||||
Copy + One + CheckedAdd + CheckedSub + Eq + Ord + Display + FromStr + Send + Sync + 'static
|
Copy
|
||||||
|
+ One
|
||||||
|
+ CheckedAdd
|
||||||
|
+ CheckedSub
|
||||||
|
+ Eq
|
||||||
|
+ Ord
|
||||||
|
+ Display
|
||||||
|
+ FromStr
|
||||||
|
+ FromRadix16
|
||||||
|
+ UpperHex
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
impl<
|
impl<
|
||||||
T: Copy + One + CheckedAdd + CheckedSub + Eq + Ord + Display + FromStr + Send + Sync + 'static,
|
T: Copy
|
||||||
|
+ One
|
||||||
|
+ CheckedAdd
|
||||||
|
+ CheckedSub
|
||||||
|
+ Eq
|
||||||
|
+ Ord
|
||||||
|
+ Display
|
||||||
|
+ FromStr
|
||||||
|
+ FromRadix16
|
||||||
|
+ UpperHex
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
> Number for T
|
> Number for T
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -113,6 +143,8 @@ pub struct NumberEdit<'a, T: Number> {
|
||||||
precision: usize,
|
precision: usize,
|
||||||
min: Option<T>,
|
min: Option<T>,
|
||||||
max: Option<T>,
|
max: Option<T>,
|
||||||
|
arrows: bool,
|
||||||
|
hex: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Number> NumberEdit<'a, T> {
|
impl<'a, T: Number> NumberEdit<'a, T> {
|
||||||
|
@ -123,6 +155,8 @@ impl<'a, T: Number> NumberEdit<'a, T> {
|
||||||
precision: 3,
|
precision: 3,
|
||||||
min: None,
|
min: None,
|
||||||
max: None,
|
max: None,
|
||||||
|
arrows: true,
|
||||||
|
hex: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,12 +177,35 @@ impl<'a, T: Number> NumberEdit<'a, T> {
|
||||||
};
|
};
|
||||||
Self { min, max, ..self }
|
Self { min, max, ..self }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn arrows(self, arrows: bool) -> Self {
|
||||||
|
Self { arrows, ..self }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hex(self, hex: bool) -> Self {
|
||||||
|
Self { hex, ..self }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Number> Widget for NumberEdit<'_, T> {
|
impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||||
fn ui(self, ui: &mut Ui) -> Response {
|
fn ui(self, ui: &mut Ui) -> Response {
|
||||||
let id = ui.id();
|
let id = ui.id();
|
||||||
let to_string = |val: &T| format!("{val:.0$}", self.precision);
|
let to_string = |val: &T| {
|
||||||
|
if self.hex {
|
||||||
|
format!("{val:.0$X}", self.precision)
|
||||||
|
} else {
|
||||||
|
format!("{val:.0$}", self.precision)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let from_string = |val: &str| {
|
||||||
|
if self.hex {
|
||||||
|
let bytes = val.as_bytes();
|
||||||
|
let (result, consumed) = T::from_radix_16(bytes);
|
||||||
|
(consumed == bytes.len()).then_some(result)
|
||||||
|
} else {
|
||||||
|
val.parse::<T>().ok()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (last_value, mut str, focus) = ui.memory(|m| {
|
let (last_value, mut str, focus) = ui.memory(|m| {
|
||||||
let (lv, s) = m
|
let (lv, s) = m
|
||||||
|
@ -163,7 +220,7 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||||
str = to_string(self.value);
|
str = to_string(self.value);
|
||||||
stale = true;
|
stale = true;
|
||||||
}
|
}
|
||||||
let valid = str.parse().is_ok_and(|v: T| v == *self.value);
|
let valid = from_string(&str).is_some_and(|v: T| v == *self.value);
|
||||||
let mut up_pressed = false;
|
let mut up_pressed = false;
|
||||||
let mut down_pressed = false;
|
let mut down_pressed = false;
|
||||||
if focus {
|
if focus {
|
||||||
|
@ -194,17 +251,25 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||||
.id(id)
|
.id(id)
|
||||||
.margin(Margin {
|
.margin(Margin {
|
||||||
left: 4.0,
|
left: 4.0,
|
||||||
right: 20.0,
|
right: if self.arrows { 20.0 } else { 4.0 },
|
||||||
top: 2.0,
|
top: 2.0,
|
||||||
bottom: 2.0,
|
bottom: 2.0,
|
||||||
});
|
});
|
||||||
let res = if valid {
|
let mut res = if valid {
|
||||||
ui.add(text)
|
ui.add(text)
|
||||||
} else {
|
} else {
|
||||||
let message = match (self.min, self.max) {
|
let message = match (self.min, self.max) {
|
||||||
(Some(min), Some(max)) => format!("Please enter a number between {min} and {max}."),
|
(Some(min), Some(max)) => format!(
|
||||||
(Some(min), None) => format!("Please enter a number greater than {min}."),
|
"Please enter a number between {} and {}.",
|
||||||
(None, Some(max)) => format!("Please enter a number less than {max}."),
|
to_string(&min),
|
||||||
|
to_string(&max)
|
||||||
|
),
|
||||||
|
(Some(min), None) => {
|
||||||
|
format!("Please enter a number greater than {}.", to_string(&min))
|
||||||
|
}
|
||||||
|
(None, Some(max)) => {
|
||||||
|
format!("Please enter a number less than {}.", to_string(&max))
|
||||||
|
}
|
||||||
(None, None) => "Please enter a number.".to_string(),
|
(None, None) => "Please enter a number.".to_string(),
|
||||||
};
|
};
|
||||||
ui.scope(|ui| {
|
ui.scope(|ui| {
|
||||||
|
@ -218,26 +283,28 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||||
.on_hover_text(message)
|
.on_hover_text(message)
|
||||||
};
|
};
|
||||||
|
|
||||||
let arrow_left = res.rect.max.x + 4.0;
|
|
||||||
let arrow_right = res.rect.max.x + 20.0;
|
|
||||||
let arrow_top = res.rect.min.y - 2.0;
|
|
||||||
let arrow_middle = (res.rect.min.y + res.rect.max.y) / 2.0;
|
|
||||||
let arrow_bottom = res.rect.max.y + 2.0;
|
|
||||||
|
|
||||||
let mut delta = None;
|
let mut delta = None;
|
||||||
let top_arrow_rect = Rect {
|
if self.arrows {
|
||||||
min: (arrow_left, arrow_top).into(),
|
let arrow_left = res.rect.max.x + 4.0;
|
||||||
max: (arrow_right, arrow_middle).into(),
|
let arrow_right = res.rect.max.x + 20.0;
|
||||||
};
|
let arrow_top = res.rect.min.y - 2.0;
|
||||||
if draw_arrow(ui, top_arrow_rect, true).clicked_or_dragged() || up_pressed {
|
let arrow_middle = (res.rect.min.y + res.rect.max.y) / 2.0;
|
||||||
delta = Some(Direction::Up);
|
let arrow_bottom = res.rect.max.y + 2.0;
|
||||||
}
|
|
||||||
let bottom_arrow_rect = Rect {
|
let top_arrow_rect = Rect {
|
||||||
min: (arrow_left, arrow_middle).into(),
|
min: (arrow_left, arrow_top).into(),
|
||||||
max: (arrow_right, arrow_bottom).into(),
|
max: (arrow_right, arrow_middle).into(),
|
||||||
};
|
};
|
||||||
if draw_arrow(ui, bottom_arrow_rect, false).clicked_or_dragged() || down_pressed {
|
if draw_arrow(ui, top_arrow_rect, true).clicked_or_dragged() || up_pressed {
|
||||||
delta = Some(Direction::Down);
|
delta = Some(Direction::Up);
|
||||||
|
}
|
||||||
|
let bottom_arrow_rect = Rect {
|
||||||
|
min: (arrow_left, arrow_middle).into(),
|
||||||
|
max: (arrow_right, arrow_bottom).into(),
|
||||||
|
};
|
||||||
|
if draw_arrow(ui, bottom_arrow_rect, false).clicked_or_dragged() || down_pressed {
|
||||||
|
delta = Some(Direction::Down);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let in_range =
|
let in_range =
|
||||||
|
@ -248,12 +315,18 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||||
Direction::Down => self.value.checked_sub(&self.increment),
|
Direction::Down => self.value.checked_sub(&self.increment),
|
||||||
};
|
};
|
||||||
if let Some(new_value) = value.filter(in_range) {
|
if let Some(new_value) = value.filter(in_range) {
|
||||||
|
if *self.value != new_value {
|
||||||
|
res.mark_changed();
|
||||||
|
}
|
||||||
*self.value = new_value;
|
*self.value = new_value;
|
||||||
}
|
}
|
||||||
str = to_string(self.value);
|
str = to_string(self.value);
|
||||||
stale = true;
|
stale = true;
|
||||||
} else if res.changed {
|
} else if res.changed {
|
||||||
if let Some(new_value) = str.parse().ok().filter(in_range) {
|
if let Some(new_value) = from_string(&str).filter(in_range) {
|
||||||
|
if *self.value != new_value {
|
||||||
|
res.mark_changed();
|
||||||
|
}
|
||||||
*self.value = new_value;
|
*self.value = new_value;
|
||||||
}
|
}
|
||||||
stale = true;
|
stale = true;
|
||||||
|
|
|
@ -1,20 +1,22 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use egui::{
|
use egui::{
|
||||||
Align, Button, CentralPanel, Checkbox, Context, Label, Layout, ScrollArea, TextEdit, Ui,
|
Align, Button, CentralPanel, Checkbox, Color32, Context, Direction, Label, Layout, ScrollArea,
|
||||||
ViewportBuilder, ViewportId,
|
TextEdit, Ui, ViewportBuilder, ViewportId,
|
||||||
};
|
};
|
||||||
use egui_extras::{Column, Size, StripBuilder, TableBuilder};
|
use egui_extras::{Column, Size, StripBuilder, TableBuilder};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
emulator::SimId,
|
emulator::SimId,
|
||||||
memory::{MemoryClient, MemoryValue, MemoryView},
|
memory::{MemoryClient, MemoryRef, MemoryValue, MemoryView},
|
||||||
window::{
|
window::{
|
||||||
utils::{NumberEdit, UiExt},
|
utils::{NumberEdit, UiExt},
|
||||||
AppWindow,
|
AppWindow,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::utils;
|
||||||
|
|
||||||
pub struct RegisterWindow {
|
pub struct RegisterWindow {
|
||||||
sim_id: SimId,
|
sim_id: SimId,
|
||||||
memory: Arc<MemoryClient>,
|
memory: Arc<MemoryClient>,
|
||||||
|
@ -26,7 +28,7 @@ impl RegisterWindow {
|
||||||
Self {
|
Self {
|
||||||
sim_id,
|
sim_id,
|
||||||
memory: memory.clone(),
|
memory: memory.clone(),
|
||||||
registers: memory.watch(sim_id, 0x0005f800, 0x70),
|
registers: memory.watch(sim_id, 0x0005f800, 0x72),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,21 +38,21 @@ impl RegisterWindow {
|
||||||
let mut intenb = InterruptReg::parse(raw_intenb);
|
let mut intenb = InterruptReg::parse(raw_intenb);
|
||||||
let mut intpnd = InterruptReg::parse(raw_intpnd);
|
let mut intpnd = InterruptReg::parse(raw_intpnd);
|
||||||
ui.section("Interrupt", |ui| {
|
ui.section("Interrupt", |ui| {
|
||||||
ui.vertical(|ui| {
|
let width = ui.available_width();
|
||||||
|
ui.with_layout(Layout::top_down_justified(Align::Center), |ui| {
|
||||||
TableBuilder::new(ui)
|
TableBuilder::new(ui)
|
||||||
.id_salt("raw_values")
|
.id_salt("raw_values")
|
||||||
.column(Column::auto())
|
.columns(Column::exact(width * 0.5), 2)
|
||||||
.column(Column::remainder())
|
|
||||||
.cell_layout(Layout::left_to_right(Align::Max))
|
.cell_layout(Layout::left_to_right(Align::Max))
|
||||||
.body(|mut body| {
|
.body(|mut body| {
|
||||||
body.row(row_height, |mut row| {
|
body.row(row_height, |mut row| {
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.label("INTENB");
|
ui.add_sized(ui.available_size(), Label::new("INTENB"));
|
||||||
});
|
});
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
let mut text = format!("{raw_intenb:04x}");
|
let mut text = format!("{raw_intenb:04x}");
|
||||||
ui.add_enabled(
|
ui.add_sized(
|
||||||
false,
|
ui.available_size(),
|
||||||
TextEdit::singleline(&mut text).horizontal_align(Align::Max),
|
TextEdit::singleline(&mut text).horizontal_align(Align::Max),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -71,17 +73,17 @@ impl RegisterWindow {
|
||||||
ui.add_space(8.0);
|
ui.add_space(8.0);
|
||||||
TableBuilder::new(ui)
|
TableBuilder::new(ui)
|
||||||
.id_salt("flags")
|
.id_salt("flags")
|
||||||
.column(Column::auto())
|
.column(Column::exact(width * 0.5))
|
||||||
.columns(Column::remainder(), 2)
|
.columns(Column::exact(width * 0.25), 2)
|
||||||
.cell_layout(Layout::left_to_right(Align::Center).with_main_align(Align::RIGHT))
|
.cell_layout(Layout::left_to_right(Align::Center).with_main_align(Align::RIGHT))
|
||||||
.body(|mut body| {
|
.body(|mut body| {
|
||||||
body.row(row_height, |mut row| {
|
body.row(row_height, |mut row| {
|
||||||
row.col(|_ui| {});
|
row.col(|_ui| {});
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.add_sized([ui.available_width(), 0.0], Label::new("ENB"));
|
ui.add_sized(ui.available_size(), Label::new("ENB"));
|
||||||
});
|
});
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.add_sized([ui.available_width(), 0.0], Label::new("PND"));
|
ui.add_sized(ui.available_size(), Label::new("PND"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
let mut add_row = |label: &str, enb: &mut bool, pnd: &mut bool| {
|
let mut add_row = |label: &str, enb: &mut bool, pnd: &mut bool| {
|
||||||
|
@ -112,7 +114,7 @@ impl RegisterWindow {
|
||||||
add_row("LFBEND", &mut intenb.lfbend, &mut intpnd.lfbend);
|
add_row("LFBEND", &mut intenb.lfbend, &mut intpnd.lfbend);
|
||||||
add_row("SCANERR", &mut intenb.scanerr, &mut intpnd.scanerr);
|
add_row("SCANERR", &mut intenb.scanerr, &mut intpnd.scanerr);
|
||||||
});
|
});
|
||||||
ui.add_space(ui.available_height());
|
ui.allocate_space(ui.available_size());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if intpnd.update(&mut raw_intpnd) {
|
if intpnd.update(&mut raw_intpnd) {
|
||||||
|
@ -128,9 +130,10 @@ impl RegisterWindow {
|
||||||
let mut raw_dpstts = self.read_address(0x0005f820);
|
let mut raw_dpstts = self.read_address(0x0005f820);
|
||||||
let mut dpstts = DisplayReg::parse(raw_dpstts);
|
let mut dpstts = DisplayReg::parse(raw_dpstts);
|
||||||
ui.section("Display", |ui| {
|
ui.section("Display", |ui| {
|
||||||
|
let width = ui.available_width();
|
||||||
TableBuilder::new(ui)
|
TableBuilder::new(ui)
|
||||||
.column(Column::auto())
|
.column(Column::exact(width * 0.5))
|
||||||
.column(Column::remainder())
|
.column(Column::exact(width * 0.5))
|
||||||
.cell_layout(Layout::left_to_right(Align::Max))
|
.cell_layout(Layout::left_to_right(Align::Max))
|
||||||
.body(|mut body| {
|
.body(|mut body| {
|
||||||
body.row(row_height, |mut row| {
|
body.row(row_height, |mut row| {
|
||||||
|
@ -197,7 +200,7 @@ impl RegisterWindow {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ui.vertical(|ui| ui.add_space((ui.available_height() - row_height).max(0.0)));
|
ui.allocate_space(ui.available_size());
|
||||||
});
|
});
|
||||||
if dpstts.update(&mut raw_dpstts) {
|
if dpstts.update(&mut raw_dpstts) {
|
||||||
self.memory.write(self.sim_id, 0x0005f822, &raw_dpstts);
|
self.memory.write(self.sim_id, 0x0005f822, &raw_dpstts);
|
||||||
|
@ -209,9 +212,10 @@ impl RegisterWindow {
|
||||||
let [mut raw_xpstts, raw_xpctrl] = self.read_address(0x0005f840);
|
let [mut raw_xpstts, raw_xpctrl] = self.read_address(0x0005f840);
|
||||||
let mut xpstts = DrawingReg::parse(raw_xpstts);
|
let mut xpstts = DrawingReg::parse(raw_xpstts);
|
||||||
ui.section("Drawing", |ui| {
|
ui.section("Drawing", |ui| {
|
||||||
|
let width = ui.available_width();
|
||||||
TableBuilder::new(ui)
|
TableBuilder::new(ui)
|
||||||
.column(Column::auto())
|
.column(Column::exact(width * 0.5))
|
||||||
.column(Column::remainder())
|
.column(Column::exact(width * 0.5))
|
||||||
.cell_layout(Layout::left_to_right(Align::Max))
|
.cell_layout(Layout::left_to_right(Align::Max))
|
||||||
.body(|mut body| {
|
.body(|mut body| {
|
||||||
body.row(row_height, |mut row| {
|
body.row(row_height, |mut row| {
|
||||||
|
@ -257,7 +261,9 @@ impl RegisterWindow {
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.add_enabled(
|
ui.add_enabled(
|
||||||
false,
|
false,
|
||||||
NumberEdit::new(&mut xpstts.sbcount).range(0..32),
|
NumberEdit::new(&mut xpstts.sbcount)
|
||||||
|
.arrows(false)
|
||||||
|
.range(0..32),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -291,7 +297,7 @@ impl RegisterWindow {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ui.vertical(|ui| ui.add_space(ui.available_height()));
|
ui.allocate_space(ui.available_size());
|
||||||
});
|
});
|
||||||
if xpstts.update(&mut raw_xpstts) {
|
if xpstts.update(&mut raw_xpstts) {
|
||||||
xpstts.update(&mut raw_xpstts);
|
xpstts.update(&mut raw_xpstts);
|
||||||
|
@ -299,10 +305,185 @@ impl RegisterWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_address<T: MemoryValue>(&self, address: usize) -> T {
|
fn show_colors(&mut self, ui: &mut Ui) {
|
||||||
let index = (address - 0x0005f800) / size_of::<T>();
|
let row_height = ui.spacing().interact_size.y;
|
||||||
self.registers.borrow().read(index)
|
let registers = self.registers.borrow();
|
||||||
|
ui.section("Colors", |ui| {
|
||||||
|
TableBuilder::new(ui)
|
||||||
|
.column(Column::auto())
|
||||||
|
.columns(Column::remainder(), 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)
|
||||||
|
.arrows(false)
|
||||||
|
.hex(true),
|
||||||
|
)
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
stale = true;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
if ui
|
||||||
|
.add(NumberEdit::new(&mut c1).range(0..4).arrows(false))
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
*value = (*value & 0xfff3) | (c1 << 2);
|
||||||
|
stale = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
if ui
|
||||||
|
.add(NumberEdit::new(&mut c2).range(0..4).arrows(false))
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
*value = (*value & 0xffcf) | (c2 << 4);
|
||||||
|
stale = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
if ui
|
||||||
|
.add(NumberEdit::new(&mut c3).range(0..4).arrows(false))
|
||||||
|
.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).arrows(false))
|
||||||
|
.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 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 {
|
impl AppWindow for RegisterWindow {
|
||||||
|
@ -317,15 +498,19 @@ impl AppWindow for RegisterWindow {
|
||||||
fn initial_viewport(&self) -> ViewportBuilder {
|
fn initial_viewport(&self) -> ViewportBuilder {
|
||||||
ViewportBuilder::default()
|
ViewportBuilder::default()
|
||||||
.with_title(format!("Registers ({})", self.sim_id))
|
.with_title(format!("Registers ({})", self.sim_id))
|
||||||
.with_inner_size((640.0, 480.0))
|
.with_inner_size((800.0, 480.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show(&mut self, ctx: &Context) {
|
fn show(&mut self, ctx: &Context) {
|
||||||
CentralPanel::default().show(ctx, |ui| {
|
CentralPanel::default().show(ctx, |ui| {
|
||||||
ScrollArea::vertical().show(ui, |ui| {
|
ScrollArea::vertical().show(ui, |ui| {
|
||||||
ui.horizontal_top(|ui| {
|
ui.horizontal_top(|ui| {
|
||||||
|
let width = ui.available_width() - (ui.spacing().item_spacing.x * 6.0);
|
||||||
StripBuilder::new(ui)
|
StripBuilder::new(ui)
|
||||||
.sizes(Size::remainder(), 4)
|
.size(Size::exact(width * 0.2))
|
||||||
|
.size(Size::exact(width * 0.2))
|
||||||
|
.size(Size::exact(width * 0.3))
|
||||||
|
.size(Size::exact(width * 0.2))
|
||||||
.horizontal(|mut strip| {
|
.horizontal(|mut strip| {
|
||||||
strip.cell(|ui| {
|
strip.cell(|ui| {
|
||||||
self.show_interrupts(ui);
|
self.show_interrupts(ui);
|
||||||
|
@ -340,6 +525,9 @@ impl AppWindow for RegisterWindow {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
strip.cell(|ui| {
|
||||||
|
self.show_colors(ui);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -28,6 +28,15 @@ pub const fn parse_shades(brts: &[u8; 8]) -> [u8; 4] {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse_brts(brts: &[u16; 3], color: Color32) -> [Color32; 4] {
|
||||||
|
[
|
||||||
|
Color32::BLACK,
|
||||||
|
shade(brts[0] as u8, color),
|
||||||
|
shade(brts[1] as u8, color),
|
||||||
|
shade((brts[0] + brts[1] + brts[2]) as u8, color),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
pub fn palette_colors(palette: u8, brts: &[u8; 8], color: Color32) -> [Color32; 4] {
|
pub fn palette_colors(palette: u8, brts: &[u8; 8], color: Color32) -> [Color32; 4] {
|
||||||
let colors = parse_shades(brts).map(|s| shade(s, color));
|
let colors = parse_shades(brts).map(|s| shade(s, color));
|
||||||
parse_palette(palette).map(|p| colors[p as usize])
|
parse_palette(palette).map(|p| colors[p as usize])
|
||||||
|
|
Loading…
Reference in New Issue