Skip to content

Commit

Permalink
tui: Refactor some tui code to their own modules
Browse files Browse the repository at this point in the history
  • Loading branch information
Granddave committed Jan 6, 2024
1 parent cf8b645 commit aa483d2
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 134 deletions.
93 changes: 15 additions & 78 deletions src/emulator/tui/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,74 +6,13 @@ use crate::{
},
};

use super::ui::AppWidget;
use self::{state::EmulationState, widget::AppWidget};

#[derive(Debug, Default, Clone)]
pub struct StateValue<T> {
value: T,
did_change: bool,
}
pub mod state;
pub mod widget;

impl<T: PartialEq> StateValue<T> {
pub fn set(&mut self, value: T) {
if self.value == value {
return;
}
self.value = value;
self.did_change = true;
}

pub fn get(&self) -> T
where
T: Copy,
{
self.value
}

pub fn has_changed(&self) -> bool {
self.did_change
}

pub fn invalidate(&mut self) {
self.did_change = false;
}
}

#[derive(Debug, Default, Clone)]
pub struct EmulationState {
pub a: StateValue<u8>,
pub x: StateValue<u8>,
pub y: StateValue<u8>,
pub pc: StateValue<u16>,
pub sp: StateValue<u8>,

// Status register
pub carry: StateValue<bool>,
pub zero: StateValue<bool>,
pub interrupt_disable: StateValue<bool>,
pub decimal: StateValue<bool>,
pub break_command: StateValue<bool>,
pub overflow: StateValue<bool>,
pub negative: StateValue<bool>,
}

impl EmulationState {
fn invalidate(&mut self) {
self.a.invalidate();
self.x.invalidate();
self.y.invalidate();
self.pc.invalidate();
self.sp.invalidate();

self.carry.invalidate();
self.zero.invalidate();
self.interrupt_disable.invalidate();
self.decimal.invalidate();
self.break_command.invalidate();
self.overflow.invalidate();
self.negative.invalidate();
}
}
const MEMORY_SCROLL_PAGE: usize = 0x10;
const MEMORY_SCROLL_MAX: usize = 0xff;

#[derive(Default)]
pub struct App {
Expand Down Expand Up @@ -108,6 +47,7 @@ impl App {
pub fn new(program: &[u8], program_start: u16) -> Self {
// turn a Vec<ASTInstructionNode> into a Vec<(usize, String)>
// where the usize is the memory address of the instruction.
// TODO: Refactor this into a function
let disassembly: Vec<(usize, String)> = disassemble_code(program)
.iter()
.scan(0, |acc, ins| {
Expand Down Expand Up @@ -223,8 +163,8 @@ impl App {
}
}
AppWidget::Memory => {
if self.memory_page_to_display > 0x10 {
self.memory_page_to_display -= 0x10;
if self.memory_page_to_display > MEMORY_SCROLL_PAGE {
self.memory_page_to_display -= MEMORY_SCROLL_PAGE;
} else {
self.memory_page_to_display = 0;
}
Expand All @@ -241,9 +181,8 @@ impl App {
}
}
AppWidget::Memory => {
if self.memory_page_to_display < 0xff {
if self.memory_page_to_display < MEMORY_SCROLL_MAX {
self.memory_page_to_display += 1;
self.memory_slice(0xfff0, 0xffff);
}
}
_ => {}
Expand All @@ -253,20 +192,18 @@ impl App {
pub fn scroll_down_page(&mut self) {
match self.selected_widget {
AppWidget::Disassembly => {
let max = self.disassembled_program.len() - 1;
if self.disassembly_widget_scroll < max - self.disassembly_frame_height {
let max_scroll = self.disassembled_program.len() - 1;
if self.disassembly_widget_scroll < max_scroll - self.disassembly_frame_height {
self.disassembly_widget_scroll += self.disassembly_frame_height;
} else {
self.disassembly_widget_scroll = max;
self.disassembly_widget_scroll = max_scroll;
}
}
AppWidget::Memory => {
let max = 0xff;
let step = 0x10;
if self.memory_page_to_display < max - step {
self.memory_page_to_display += step;
if self.memory_page_to_display < MEMORY_SCROLL_MAX - MEMORY_SCROLL_PAGE {
self.memory_page_to_display += MEMORY_SCROLL_PAGE;
} else {
self.memory_page_to_display = max;
self.memory_page_to_display = MEMORY_SCROLL_MAX;
}
}
_ => {}
Expand Down
66 changes: 66 additions & 0 deletions src/emulator/tui/app/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#[derive(Debug, Default, Clone)]
pub struct StateValue<T> {
value: T,
did_change: bool,
}

impl<T: PartialEq> StateValue<T> {
pub fn set(&mut self, value: T) {
if self.value == value {
return;
}
self.value = value;
self.did_change = true;
}

pub fn get(&self) -> T
where
T: Copy,
{
self.value
}

pub fn has_changed(&self) -> bool {
self.did_change
}

pub fn invalidate(&mut self) {
self.did_change = false;
}
}

#[derive(Debug, Default, Clone)]
pub struct EmulationState {
pub a: StateValue<u8>,
pub x: StateValue<u8>,
pub y: StateValue<u8>,
pub pc: StateValue<u16>,
pub sp: StateValue<u8>,

// Status register
pub carry: StateValue<bool>,
pub zero: StateValue<bool>,
pub interrupt_disable: StateValue<bool>,
pub decimal: StateValue<bool>,
pub break_command: StateValue<bool>,
pub overflow: StateValue<bool>,
pub negative: StateValue<bool>,
}

impl EmulationState {
pub fn invalidate(&mut self) {
self.a.invalidate();
self.x.invalidate();
self.y.invalidate();
self.pc.invalidate();
self.sp.invalidate();

self.carry.invalidate();
self.zero.invalidate();
self.interrupt_disable.invalidate();
self.decimal.invalidate();
self.break_command.invalidate();
self.overflow.invalidate();
self.negative.invalidate();
}
}
53 changes: 53 additions & 0 deletions src/emulator/tui/app/widget.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#[derive(Debug, Default, Copy, Clone, PartialEq)]
pub enum AppWidget {
Registers,
Stack,
#[default]
Disassembly,
Memory,
}

impl AppWidget {
pub fn next(&self) -> AppWidget {
match self {
AppWidget::Registers => AppWidget::Stack,
AppWidget::Stack => AppWidget::Disassembly,
AppWidget::Disassembly => AppWidget::Memory,
AppWidget::Memory => AppWidget::Memory, // Don't wrap
}
}

pub fn prev(&self) -> AppWidget {
match self {
AppWidget::Registers => AppWidget::Registers, // Don't wrap
AppWidget::Stack => AppWidget::Registers,
AppWidget::Disassembly => AppWidget::Stack,
AppWidget::Memory => AppWidget::Disassembly,
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_widget_cycle() {
let mut w = AppWidget::default();
assert_eq!(w, AppWidget::Disassembly);
w = w.next();
assert_eq!(w, AppWidget::Memory);
w = w.next();
assert_eq!(w, AppWidget::Memory);
w = w.prev();
assert_eq!(w, AppWidget::Disassembly);
w = w.prev();
assert_eq!(w, AppWidget::Stack);
w = w.prev();
assert_eq!(w, AppWidget::Registers);
w = w.prev();
assert_eq!(w, AppWidget::Registers);
w = w.next();
assert_eq!(w, AppWidget::Stack);
}
}
58 changes: 2 additions & 56 deletions src/emulator/tui/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,7 @@ use ratatui::{prelude::*, widgets::*};

use crate::emulator::cpu::STACK_BASE;

use super::app::App;

#[derive(Debug, Default, Copy, Clone, PartialEq)]
pub enum AppWidget {
Registers,
Stack,
#[default]
Disassembly,
Memory,
}

impl AppWidget {
pub fn next(&self) -> AppWidget {
match self {
AppWidget::Registers => AppWidget::Stack,
AppWidget::Stack => AppWidget::Disassembly,
AppWidget::Disassembly => AppWidget::Memory,
AppWidget::Memory => AppWidget::Memory, // Don't wrap
}
}

pub fn prev(&self) -> AppWidget {
match self {
AppWidget::Registers => AppWidget::Registers, // Don't wrap
AppWidget::Stack => AppWidget::Registers,
AppWidget::Disassembly => AppWidget::Stack,
AppWidget::Memory => AppWidget::Disassembly,
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_widget_cycle() {
let mut w = AppWidget::default();
assert_eq!(w, AppWidget::Disassembly);
w = w.next();
assert_eq!(w, AppWidget::Memory);
w = w.next();
assert_eq!(w, AppWidget::Memory);
w = w.prev();
assert_eq!(w, AppWidget::Disassembly);
w = w.prev();
assert_eq!(w, AppWidget::Stack);
w = w.prev();
assert_eq!(w, AppWidget::Registers);
w = w.prev();
assert_eq!(w, AppWidget::Registers);
w = w.next();
assert_eq!(w, AppWidget::Stack);
}
}
use super::app::{widget::AppWidget, App};

fn is_selected_style(selected: AppWidget, current_widget: AppWidget) -> Style {
if selected == current_widget {
Expand Down Expand Up @@ -254,7 +200,7 @@ fn render_memory_widget(app: &mut App, frame: &mut Frame, layout: Rect) {
let mut curr_line: Vec<Span> = vec![];
curr_line.push(Span::raw(format!(
"0x{:0width$x}",
(page as usize * 0x0100) + stride * stride_ix,
(page * 0x0100) + stride * stride_ix,
width = addr_width
)));
for bytes in stride_slice.chunks(2) {
Expand Down

0 comments on commit aa483d2

Please sign in to comment.