Skip to content

Commit

Permalink
tui: Improve on disasm scroll functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Granddave committed Jan 4, 2024
1 parent 1190b9f commit 11fe3db
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 57 deletions.
47 changes: 40 additions & 7 deletions src/emulator/tui/app.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::{
ast::ASTInstructionNode,
disassembler::disassemble_code,
disassembler::{disassemble_code, listing},
emulator::{
cpu::{self, Cpu, RunOption},
memory::{Bus, Memory},
Expand Down Expand Up @@ -87,8 +86,9 @@ pub struct App {
pub program_start: u16,
/// A cached disassembled AST of the loaded program
/// with memory addresses as keys.
pub disassembled_program: Vec<(usize, ASTInstructionNode)>,
pub disassembly_scroll: u16,
pub disassembled_program: Vec<(usize, String)>,
pub disassembly_scroll: usize,
pub disassembly_frame_height: usize,

/// State of the CPU
state: EmulationState,
Expand All @@ -99,16 +99,20 @@ pub struct App {

impl App {
pub fn new(program: &[u8], program_start: u16) -> Self {
// turn a Vec<ASTInstructionNode> into a Vec<(usize, ASTInstructionNode)>
// turn a Vec<ASTInstructionNode> into a Vec<(usize, String)>
// where the usize is the memory address of the instruction.
let instructions = disassemble_code(program);
let disassembly: Vec<(usize, ASTInstructionNode)> = instructions
let disassembly: Vec<(usize, String)> = disassemble_code(program)
.iter()
.scan(0, |acc, ins| {
let addr = *acc;
*acc += ins.size();
Some((addr, ins.clone()))
})
.map(|(addr, node)| {
let memory_addr = program_start as usize + addr;
let line = listing::generate_line(memory_addr, &node);
(memory_addr, line)
})
.collect();

let mut app = Self {
Expand Down Expand Up @@ -179,4 +183,33 @@ impl App {
pub fn memory_slice(&self, start: u16, end: u16) -> &[u8] {
self.memory.slice(start, end)
}

pub fn scroll_up(&mut self) {
if self.disassembly_scroll > 0 {
self.disassembly_scroll -= 1;
}
}

pub fn scroll_up_page(&mut self) {
if self.disassembly_scroll > self.disassembly_frame_height {
self.disassembly_scroll -= self.disassembly_frame_height;
} else {
self.disassembly_scroll = 0;
}
}

pub fn scroll_down(&mut self) {
if self.disassembly_scroll < self.disassembled_program.len() - 1 {
self.disassembly_scroll += 1;
}
}

pub fn scroll_down_page(&mut self) {
let max = self.disassembled_program.len() - 1;
if self.disassembly_scroll < max - self.disassembly_frame_height {
self.disassembly_scroll += self.disassembly_frame_height;
} else {
self.disassembly_scroll = max;
}
}
}
67 changes: 25 additions & 42 deletions src/emulator/tui/ui.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use ratatui::{prelude::*, widgets::*};

use crate::{
disassembler::listing,
emulator::cpu::{STACK_BASE, STACK_PAGE},
};
use crate::emulator::cpu::{STACK_BASE, STACK_PAGE};

use super::app::{App, StateValue};

Expand Down Expand Up @@ -121,37 +118,20 @@ fn stack_view(app: &mut App) -> Paragraph {
)
}

fn disassembly(app: &mut App) -> (Paragraph, usize) {
let mut lines: Vec<Line<'_>> = vec![];

fn disassembly_lines(app: &mut App) -> Vec<Line> {
// TODO: Center around program counter.
// Would be possible to disassemble the memory instead of the loaded program
let pc = app.state().pc.get() as usize;
let start_addr = app.program_start as usize;
for (offset, node) in app.disassembled_program.iter() {
let memory_addr = start_addr + offset;

let line = listing::generate_line(memory_addr, node);
if memory_addr == pc {
lines.push(Line::styled(line, Style::default().light_yellow().bold()));
} else {
lines.push(Line::raw(line));
}
}

let len = lines.len();
(
Paragraph::new(lines)
.scroll((app.disassembly_scroll, 0))
.block(
Block::default()
.title("Disassembly")
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.style(Style::default().fg(Color::Yellow)),
),
len,
)
app.disassembled_program
.iter()
.map(|(memory_addr, line)| {
if *memory_addr == pc as usize {
Line::styled(line, Style::default().light_yellow().bold())
} else {
Line::raw(line)
}
})
.collect()
}

fn top_bar() -> Paragraph<'static> {
Expand Down Expand Up @@ -196,19 +176,22 @@ pub fn render(app: &mut App, frame: &mut Frame) {
frame.render_widget(stack_view(app), app_layout[1]);

// Disassembly view
let scroll_amount = app.disassembly_scroll as usize;
let (disassembly, num_instructions) = disassembly(app);
let scrollbar = Scrollbar::default()
.orientation(ScrollbarOrientation::VerticalRight)
.begin_symbol(Some("↑"))
.end_symbol(Some("↓"));
let mut scrollbar_state = ScrollbarState::new(num_instructions).position(scroll_amount);
frame.render_widget(disassembly, app_layout[2]);
app.disassembly_frame_height = app_layout[2].height as usize - 2;
let scroll_pos = app.disassembly_scroll;
let lines = disassembly_lines(app);
let mut scrollbar_state = ScrollbarState::new(lines.len()).position(scroll_pos);
frame.render_stateful_widget(
scrollbar,
Scrollbar::default().orientation(ScrollbarOrientation::VerticalRight),
app_layout[2].inner(&Margin::new(1, 0)),
&mut scrollbar_state,
);

let disassembly = Paragraph::new(lines).scroll((scroll_pos as u16, 0)).block(
Block::default()
.title("Disassembly")
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.style(Style::default().fg(Color::Yellow)),
);
frame.render_widget(disassembly, app_layout[2]);
frame.render_widget(bottom_bar(), main_layout[2]);
}
12 changes: 4 additions & 8 deletions src/emulator/tui/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,10 @@ pub fn update(app: &mut App, key_event: KeyEvent) {
}
KeyCode::Char('s') => app.step_cpu(),
KeyCode::Char('r') => app.reset(),
KeyCode::Up => {
if app.disassembly_scroll > 0 {
app.disassembly_scroll -= 1;
}
}
KeyCode::Down => {
app.disassembly_scroll += 1;
}
KeyCode::Up => app.scroll_up(),
KeyCode::Down => app.scroll_down(),
KeyCode::PageUp => app.scroll_up_page(),
KeyCode::PageDown => app.scroll_down_page(),
_ => {}
};
}

0 comments on commit 11fe3db

Please sign in to comment.