| 1 | //! Interrupt system: enable, priority and request flag of each source. |
| 2 | |
| 3 | use bench51_core::session::{Session, vector_name}; |
| 4 | use bench51_core::sfr::{IE, IP, SCON, TCON}; |
| 5 | use eframe::egui::{self, Ui}; |
| 6 | |
| 7 | use super::sfr_chip; |
| 8 | use crate::theme::{WARNING, palette}; |
| 9 | use crate::widgets; |
| 10 | |
| 11 | /// (name, vector, IE/IP mask, request flag as (SFR, mask)). |
| 12 | const SOURCES: [(&str, u16, u8, (u8, u8)); 5] = [ |
| 13 | ("INT0", 0x03, 0x01, (TCON, 0x02)), |
| 14 | ("T0", 0x0B, 0x02, (TCON, 0x20)), |
| 15 | ("INT1", 0x13, 0x04, (TCON, 0x08)), |
| 16 | ("T1", 0x1B, 0x08, (TCON, 0x80)), |
| 17 | ("UART", 0x23, 0x10, (SCON, 0x03)), |
| 18 | ]; |
| 19 | |
| 20 | pub fn show(ui: &mut Ui, s: &mut Session) { |
| 21 | let p = palette(ui.ctx()); |
| 22 | egui::ScrollArea::vertical() |
| 23 | .auto_shrink([false; 2]) |
| 24 | .show(ui, |ui| { |
| 25 | ui.horizontal(|ui| { |
| 26 | sfr_chip(ui, s, "EA", IE, 0x80); |
| 27 | ui.add_space(12.0); |
| 28 | let state = if s.sim.power_down { |
| 29 | ("power-down", WARNING) |
| 30 | } else if s.sim.idle { |
| 31 | ("idle", WARNING) |
| 32 | } else { |
| 33 | ("running", p.text_secondary) |
| 34 | }; |
| 35 | ui.label(p.label("CPU")); |
| 36 | ui.label(p.label(state.0).color(state.1)); |
| 37 | }); |
| 38 | ui.add_space(10.0); |
| 39 | egui::Grid::new("irqs") |
| 40 | .num_columns(5) |
| 41 | .spacing([14.0, 6.0]) |
| 42 | .show(ui, |ui| { |
| 43 | for h in ["Source", "Vector", "Enable", "Priority", "Request"] { |
| 44 | ui.label(p.label(h).color(p.text_disabled)); |
| 45 | } |
| 46 | ui.end_row(); |
| 47 | for (name, vector, mask, (flag_sfr, flag_mask)) in SOURCES { |
| 48 | let active = s.sim.last_irq == Some(vector) && !s.sim.in_service.is_empty(); |
| 49 | ui.label(p.label(name).color(if active { |
| 50 | p.text_display |
| 51 | } else { |
| 52 | p.text_primary |
| 53 | })); |
| 54 | ui.label(p.data(format!("{vector:04X}")).color(p.text_secondary)); |
| 55 | sfr_chip(ui, s, "EN", IE, mask); |
| 56 | sfr_chip(ui, s, "HI", IP, mask); |
| 57 | let req = s.sim.sfr(flag_sfr) & flag_mask != 0; |
| 58 | if flag_sfr == SCON { |
| 59 | widgets::bit_chip(ui, "RI|TI", req); |
| 60 | } else { |
| 61 | sfr_chip(ui, s, "REQ", flag_sfr, flag_mask); |
| 62 | } |
| 63 | ui.end_row(); |
| 64 | } |
| 65 | }); |
| 66 | widgets::section(ui, "In service"); |
| 67 | let levels = if s.sim.in_service.is_empty() { |
| 68 | "none".to_string() |
| 69 | } else { |
| 70 | s.sim |
| 71 | .in_service |
| 72 | .iter() |
| 73 | .map(|l| format!("L{l}")) |
| 74 | .collect::<Vec<_>>() |
| 75 | .join(" > ") |
| 76 | }; |
| 77 | widgets::stat_row(ui, "Levels", p.data(levels)); |
| 78 | let last = s.sim.last_irq.map_or("—".to_string(), |v| { |
| 79 | format!("{v:04X}h {}", vector_name(v)) |
| 80 | }); |
| 81 | widgets::stat_row(ui, "Last taken", p.data(last)); |
| 82 | }); |
| 83 | } |