From 892d48e321eee2d424437cb98904b7c8574e3b3b Mon Sep 17 00:00:00 2001 From: Simon Gellis Date: Wed, 19 Feb 2025 19:52:31 -0500 Subject: [PATCH] Add dpctrl+xpctrl to register view --- src/window/vram/registers.rs | 296 ++++++++++++++++++++++++++++++++++- 1 file changed, 289 insertions(+), 7 deletions(-) diff --git a/src/window/vram/registers.rs b/src/window/vram/registers.rs index e001dc4..882b2b5 100644 --- a/src/window/vram/registers.rs +++ b/src/window/vram/registers.rs @@ -1,15 +1,18 @@ use std::sync::Arc; use egui::{ - Align, CentralPanel, Context, Label, Layout, ScrollArea, TextEdit, Ui, ViewportBuilder, - ViewportId, + Align, Button, CentralPanel, Checkbox, Context, Label, Layout, ScrollArea, TextEdit, Ui, + ViewportBuilder, ViewportId, }; use egui_extras::{Column, Size, StripBuilder, TableBuilder}; use crate::{ emulator::SimId, - memory::{MemoryClient, MemoryView}, - window::{utils::UiExt, AppWindow}, + memory::{MemoryClient, MemoryValue, MemoryView}, + window::{ + utils::{NumberEdit, UiExt}, + AppWindow, + }, }; pub struct RegisterWindow { @@ -29,8 +32,7 @@ impl RegisterWindow { fn show_interrupts(&mut self, ui: &mut Ui) { let row_height = ui.spacing().interact_size.y; - let registers = self.registers.borrow(); - let [mut raw_intpnd, mut raw_intenb] = registers.read::<[u16; 2]>(0); + 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| { @@ -110,6 +112,7 @@ impl RegisterWindow { add_row("LFBEND", &mut intenb.lfbend, &mut intpnd.lfbend); add_row("SCANERR", &mut intenb.scanerr, &mut intpnd.scanerr); }); + ui.add_space(ui.available_height()); }); }); if intpnd.update(&mut raw_intpnd) { @@ -119,6 +122,187 @@ impl RegisterWindow { self.memory.write(self.sim_id, 0x0005f802, &raw_intenb); } } + + fn show_display_status(&mut self, ui: &mut Ui) { + let row_height = ui.spacing().interact_size.y; + let mut raw_dpstts = self.read_address(0x0005f820); + let mut dpstts = DisplayReg::parse(raw_dpstts); + ui.section("Display", |ui| { + TableBuilder::new(ui) + .column(Column::auto()) + .column(Column::remainder()) + .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.vertical(|ui| ui.add_space((ui.available_height() - row_height).max(0.0))); + }); + 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 = ui.spacing().interact_size.y; + let [mut raw_xpstts, raw_xpctrl] = self.read_address(0x0005f840); + let mut xpstts = DrawingReg::parse(raw_xpstts); + ui.section("Drawing", |ui| { + TableBuilder::new(ui) + .column(Column::auto()) + .column(Column::remainder()) + .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).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.vertical(|ui| ui.add_space(ui.available_height())); + }); + if xpstts.update(&mut raw_xpstts) { + xpstts.update(&mut raw_xpstts); + self.memory.write(self.sim_id, 0x0005f842, &raw_xpstts); + } + } + + fn read_address(&self, address: usize) -> T { + let index = (address - 0x0005f800) / size_of::(); + self.registers.borrow().read(index) + } } impl AppWindow for RegisterWindow { @@ -145,7 +329,17 @@ impl AppWindow for RegisterWindow { .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); + }); + }); + }); }); }); }); @@ -193,3 +387,91 @@ impl InterruptReg { 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 + } +}