perilus

RISC-V processor built with Chisel
git clone https://git.bradleygannon.com/perilus.git
Log | Files | Refs | Submodules | README

memory.rs (8676B)


      1 use eframe::egui;
      2 use egui::{Align2, FontId, Key, Rect, Sense, Stroke, TextEdit, Ui, pos2, vec2};
      3 use perilus_core::perilus::Perilus;
      4 
      5 use crate::app::{
      6     ADDR_W, BYTES_PER_ROW, DIVIDER_GAP, FONT_SIZE, GROUP_GAP, PC_COLOR, ROW_H, SimApp,
      7     WORDS_PER_ROW, char_width,
      8 };
      9 use crate::state::{Focus, ViewMode, hex_char, printable, row_digits};
     10 
     11 fn divider(ui: &mut Ui) {
     12     let (rect, _) = ui.allocate_exact_size(vec2(DIVIDER_GAP * 2.0, ROW_H), Sense::hover());
     13     let color = ui.visuals().weak_text_color();
     14     let spacing = ui.spacing().item_spacing.y;
     15     ui.painter().line_segment(
     16         [
     17             pos2(rect.center().x, rect.top() - spacing * 0.5),
     18             pos2(rect.center().x, rect.bottom() + spacing * 0.5),
     19         ],
     20         Stroke::new(1.0, color),
     21     );
     22 }
     23 
     24 impl SimApp {
     25     pub(crate) fn memory_ui(&mut self, ui: &mut Ui) {
     26         let font = FontId::monospace(FONT_SIZE);
     27         let nib_w = char_width(ui, &font);
     28 
     29         ui.horizontal_wrapped(|ui| {
     30             ui.strong("Memory");
     31             ui.toggle_value(&mut self.show_aliases, "ABI names [x]");
     32             let mut byte_view = self.view == ViewMode::Byte;
     33             if ui.toggle_value(&mut byte_view, "Byte view [v]").changed() {
     34                 self.view = if byte_view {
     35                     ViewMode::Byte
     36                 } else {
     37                     ViewMode::Word
     38                 };
     39             }
     40             let mut follow = self.follow_pc;
     41             if ui
     42                 .toggle_value(&mut follow, "Follow PC [shift+p]")
     43                 .changed()
     44             {
     45                 self.follow_pc = follow;
     46                 self.follow_pc_last = self.current_pc;
     47                 self.status = format!("Follow PC {}", if follow { "on" } else { "off" });
     48             }
     49             ui.separator();
     50             ui.label("addr");
     51             let response = ui.add(
     52                 TextEdit::singleline(&mut self.address_input)
     53                     .desired_width(90.0)
     54                     .hint_text("hex"),
     55             );
     56             if std::mem::take(&mut self.focus_address) {
     57                 response.request_focus();
     58             }
     59             if response.lost_focus() && ui.input(|i| i.key_pressed(Key::Enter)) {
     60                 self.jump_to_address();
     61             }
     62             if ui.button("Go [g]").clicked() {
     63                 self.jump_to_address();
     64             }
     65             ui.separator();
     66             ui.label(format!("selected 0x{:08x}", self.mem_addr));
     67         });
     68         ui.separator();
     69 
     70         if self.follow_pc && self.current_pc != self.follow_pc_last {
     71             self.follow_pc_last = self.current_pc;
     72             let pc_row = self.current_pc as usize / BYTES_PER_ROW;
     73             if !self.mem_viewport.contains(&pc_row) {
     74                 self.scroll_to_row = Some(pc_row);
     75             }
     76         }
     77 
     78         let row_pitch = ROW_H + ui.spacing().item_spacing.y;
     79         let mut area = egui::ScrollArea::both().auto_shrink([false, false]);
     80         if let Some(row) = self.scroll_to_row.take() {
     81             area = area.vertical_scroll_offset(row as f32 * row_pitch);
     82         }
     83         let total_rows = Perilus::MEMORY_SIZE_WORDS / WORDS_PER_ROW;
     84         area.show_rows(ui, ROW_H, total_rows, |ui, rows| {
     85             self.mem_viewport = rows.clone();
     86             for row in rows {
     87                 self.memory_row(ui, row, nib_w, &font);
     88             }
     89         });
     90     }
     91 
     92     fn memory_row(&mut self, ui: &mut Ui, row: usize, nib_w: f32, font: &FontId) {
     93         let row_addr = (row * BYTES_PER_ROW) as u32;
     94         ui.horizontal(|ui| {
     95             let text_color = ui.visuals().text_color();
     96             let background = ui.visuals().panel_fill;
     97             let pc = self.current_pc;
     98             let focus_memory = self.focus == Focus::Memory;
     99             let cursor_in_row =
    100                 focus_memory && (self.mem_addr / BYTES_PER_ROW as u32) as usize == row;
    101             let cursor_index = (self.mem_addr % BYTES_PER_ROW as u32) as usize;
    102 
    103             let (addr_rect, _) = ui.allocate_exact_size(vec2(ADDR_W, ROW_H), Sense::hover());
    104             ui.painter().text(
    105                 addr_rect.left_center(),
    106                 Align2::LEFT_CENTER,
    107                 format!("{row_addr:08x}"),
    108                 font.clone(),
    109                 text_color,
    110             );
    111             divider(ui);
    112 
    113             let group = match self.view {
    114                 ViewMode::Word => 8,
    115                 ViewMode::Byte => 2,
    116             };
    117             let gaps = (64 / group - 1) as f32;
    118             let digit_w = 64.0 * nib_w + gaps * GROUP_GAP;
    119             let (digits_rect, digits_response) =
    120                 ui.allocate_exact_size(vec2(digit_w, ROW_H), Sense::click());
    121 
    122             let order = row_digits(self.view);
    123             let cursor = (self.mem_addr, self.mem_nib);
    124             let mut cells: Vec<(Rect, u32, u8)> = Vec::with_capacity(64);
    125             let mut x = digits_rect.left();
    126             for (i, &(offset, nib)) in order.iter().enumerate() {
    127                 if i > 0 && i % group == 0 {
    128                     x += GROUP_GAP;
    129                 }
    130                 let cell = Rect::from_min_size(pos2(x, digits_rect.top()), vec2(nib_w, ROW_H));
    131                 let addr = row_addr + offset;
    132                 let byte = self.perilus.get_memory_byte(addr);
    133                 let digit = if nib == 0 { byte >> 4 } else { byte & 0xf };
    134                 if focus_memory && (addr, nib) == cursor {
    135                     ui.painter().rect_filled(cell, 0.0, text_color);
    136                     ui.painter().text(
    137                         cell.center(),
    138                         Align2::CENTER_CENTER,
    139                         hex_char(digit),
    140                         font.clone(),
    141                         background,
    142                     );
    143                 } else {
    144                     let color = if (addr & !3) == (pc & !3) {
    145                         PC_COLOR
    146                     } else {
    147                         text_color
    148                     };
    149                     ui.painter().text(
    150                         cell.center(),
    151                         Align2::CENTER_CENTER,
    152                         hex_char(digit),
    153                         font.clone(),
    154                         color,
    155                     );
    156                 }
    157                 cells.push((cell, addr, nib));
    158                 x += nib_w;
    159             }
    160 
    161             if let Some(pos) = digits_response.interact_pointer_pos()
    162                 && (digits_response.clicked() || digits_response.double_clicked())
    163                 && let Some(&(_, addr, nib)) = cells.iter().find(|(rect, _, _)| rect.contains(pos))
    164             {
    165                 self.mem_addr = addr;
    166                 self.mem_nib = nib;
    167                 self.focus = Focus::Memory;
    168                 if digits_response.double_clicked() {
    169                     self.set_pc_to_cursor();
    170                 }
    171             }
    172 
    173             divider(ui);
    174 
    175             let ascii: Vec<char> = match self.view {
    176                 ViewMode::Word => (0..WORDS_PER_ROW)
    177                     .flat_map(|word| {
    178                         self.perilus.get_memory()[row * WORDS_PER_ROW + word].to_le_bytes()
    179                     })
    180                     .map(printable)
    181                     .collect(),
    182                 ViewMode::Byte => (0..BYTES_PER_ROW)
    183                     .map(|i| printable(self.perilus.get_memory_byte(row_addr + i as u32)))
    184                     .collect(),
    185             };
    186             let ascii_width = ascii.len() as f32 * nib_w;
    187             let (ascii_rect, _) = ui.allocate_exact_size(vec2(ascii_width, ROW_H), Sense::hover());
    188             let painter = ui.painter();
    189             for (i, ch) in ascii.iter().enumerate() {
    190                 let cell = Rect::from_min_size(
    191                     pos2(ascii_rect.left() + i as f32 * nib_w, ascii_rect.top()),
    192                     vec2(nib_w, ROW_H),
    193                 );
    194                 if cursor_in_row && i == cursor_index {
    195                     painter.rect_filled(cell, 0.0, text_color);
    196                     painter.text(
    197                         cell.center(),
    198                         Align2::CENTER_CENTER,
    199                         *ch,
    200                         font.clone(),
    201                         background,
    202                     );
    203                 } else {
    204                     let color = if (row_addr + i as u32) & !3 == pc & !3 {
    205                         PC_COLOR
    206                     } else {
    207                         text_color
    208                     };
    209                     painter.text(
    210                         cell.center(),
    211                         Align2::CENTER_CENTER,
    212                         *ch,
    213                         font.clone(),
    214                         color,
    215                     );
    216                 }
    217             }
    218         });
    219     }
    220 }