From f3a9bef0a4578e9e2dfac9640d5668098485c71b Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:43 +0100
Subject: [PATCH 01/34] Add first mockup of `tapasco-debug` in Rust
This is the first commit for a work-in-progress effort on Issue #264.
Since `tapasco-debug` was removed in the v2020.10 release because the
ncurses-based UI was "quite flaky" you had to use two different Tapasco
workspaces to have the debugger still around while using the recent
Tapasco version.
This reimplementation of `tapasco-debug` is written in Rust and
uses the `libtui-rs` and `crossterm` crates for the terminal user
interface along with the new Tapasco runtime.
For the moment it provides a list of PEs which can be selected to see
the first 16 argument registers along with some generic bitstream and
platform information.
Writing to argument registers, starting PEs, dumping Local Memory is not
possible yet.
To integrate it into the build process of this repository it uses the
same mechanism to build using Cargo from CMake as PR #285.
---
runtime/examples/CMakeLists.txt | 1 +
.../examples/Rust/tapasco-debug/.gitignore | 1 +
.../Rust/tapasco-debug/CMakeLists.txt | 49 +++
.../examples/Rust/tapasco-debug/Cargo.toml | 15 +
.../Rust/tapasco-debug/src/app/mod.rs | 336 ++++++++++++++++++
.../examples/Rust/tapasco-debug/src/main.rs | 26 ++
.../examples/Rust/tapasco-debug/src/ui/mod.rs | 329 +++++++++++++++++
7 files changed, 757 insertions(+)
create mode 100644 runtime/examples/Rust/tapasco-debug/.gitignore
create mode 100644 runtime/examples/Rust/tapasco-debug/CMakeLists.txt
create mode 100644 runtime/examples/Rust/tapasco-debug/Cargo.toml
create mode 100644 runtime/examples/Rust/tapasco-debug/src/app/mod.rs
create mode 100644 runtime/examples/Rust/tapasco-debug/src/main.rs
create mode 100644 runtime/examples/Rust/tapasco-debug/src/ui/mod.rs
diff --git a/runtime/examples/CMakeLists.txt b/runtime/examples/CMakeLists.txt
index 09c6aa7f..ec59ab6c 100644
--- a/runtime/examples/CMakeLists.txt
+++ b/runtime/examples/CMakeLists.txt
@@ -37,3 +37,4 @@ add_subdirectory(C++/svm)
add_subdirectory(Rust/libtapasco_tests)
add_subdirectory(Rust/libtapasco_svm)
+add_subdirectory(Rust/tapasco-debug)
diff --git a/runtime/examples/Rust/tapasco-debug/.gitignore b/runtime/examples/Rust/tapasco-debug/.gitignore
new file mode 100644
index 00000000..ea8c4bf7
--- /dev/null
+++ b/runtime/examples/Rust/tapasco-debug/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/runtime/examples/Rust/tapasco-debug/CMakeLists.txt b/runtime/examples/Rust/tapasco-debug/CMakeLists.txt
new file mode 100644
index 00000000..6f7ae564
--- /dev/null
+++ b/runtime/examples/Rust/tapasco-debug/CMakeLists.txt
@@ -0,0 +1,49 @@
+# Copyright (c) 2014-2021 Embedded Systems and Applications, TU Darmstadt.
+#
+# This file is part of TaPaSCo
+# (see https://github.com/esa-tu-darmstadt/tapasco).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see .
+
+cmake_minimum_required(VERSION 3.5.1 FATAL_ERROR)
+project(tapasco-debug)
+
+# Add a Rust/Cargo project to CMake watching all files in the current directory because Cargo already doesn't do anything if nothing has changed.
+add_executable(tapasco-debug .)
+
+# Use Cargo to build this project in debug mode by defining a custom target running after the tapasco target has been built.
+add_custom_target(tapasco_debug_cargo_build_debug COMMAND CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} cargo build -q --debug WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} DEPENDS tapasco COMMENT "Building tapasco-debug with Cargo")
+
+# Use Cargo to build this project in release mode by defining a custom target running after the tapasco target has been built.
+add_custom_target(tapasco_debug_cargo_build_release COMMAND CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} cargo build -q --release WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} DEPENDS tapasco COMMENT "Building tapasco-debug with Cargo")
+
+# Check if building should be in Debug or Release mode
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(TARGET_DIR "debug")
+ add_dependencies(tapasco-debug tapasco_debug_cargo_build_debug)
+else()
+ set(TARGET_DIR "release")
+ add_dependencies(tapasco-debug tapasco_debug_cargo_build_release)
+endif()
+
+
+# This tells CMake that this is a C++ executable (but it's Rust) because CMake really wants to know how to link this executable
+set_target_properties(tapasco-debug PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON LINKER_LANGUAGE CXX)
+# but it has already been linked by Cargo, so we then tell CMake to use the most failure-proof linker available (none, it's just /usr/bin/true).
+# You can't tell CMake not to link this at all, so this is the dirty workaround:
+set(CMAKE_CXX_LINK_EXECUTABLE "true")
+
+# Install the executable in the TaPaSCo PATH
+install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_DIR}/tapasco-debug
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/Tapasco/bin)
diff --git a/runtime/examples/Rust/tapasco-debug/Cargo.toml b/runtime/examples/Rust/tapasco-debug/Cargo.toml
new file mode 100644
index 00000000..56a2e127
--- /dev/null
+++ b/runtime/examples/Rust/tapasco-debug/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "tapasco-debug"
+version = "0.1.0"
+authors = ["zyno42 <83068959+zyno42@users.noreply.github.com>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+tui = { version = "0.15", default-features = false, features = ['crossterm'] }
+crossterm = "0.20"
+tapasco = { path = "../../../libtapasco" }
+
+snafu = "0.6"
+chrono = "0.4"
diff --git a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
new file mode 100644
index 00000000..dc7b293f
--- /dev/null
+++ b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
@@ -0,0 +1,336 @@
+use std::{
+ collections::HashMap,
+};
+
+use tapasco::{
+ tlkm::*,
+ device::status::Interrupt,
+ pe::PE,
+ device::PEParameter,
+};
+
+use chrono::{TimeZone, Utc};
+
+use snafu::{ResultExt, Snafu};
+
+#[derive(Debug, Snafu)]
+pub enum Error {
+ #[snafu(display("Failed to initialize TLKM object: {}", source))]
+ TLKMInit { source: tapasco::tlkm::Error },
+
+ #[snafu(display("Failed to decode/acquire TLKM device or one of its PEs: {}", source))]
+ DeviceInit { source: tapasco::device::Error },
+}
+
+type Result = std::result::Result;
+
+
+// TODO: Right now I'm just handling the first FPGA device because I assume most will have
+// only one FPGA but switching devices should be possible e.g. by passing the device as cli
+// argument or with an extra key binding?
+// TODO: It would be nice to see when/how many interrupts were triggered.
+
+
+pub struct App<'a> {
+ bitstream_info: String,
+ platform_info: String,
+ pub title: &'a str,
+ pub tabs: TabsState<'a>,
+ pub pe_infos: StatefulList,
+ pub pes: Vec<(usize, PE)>, // Plural of Processing Element (PEs)
+}
+
+impl<'a> App<'a> {
+ pub fn new() -> Result> {
+ // Get Tapasco Loadable Linux Kernel Module
+ let tlkm = TLKM::new().context(TLKMInit {})?;
+ //let tlkm_device = tlkm.device_enum(&HashMap::new()).context(TLKMInit {})?;
+ // Allocate the first device with ID 0 (because most devices will only have one FPGA)
+ let mut tlkm_device = tlkm.device_alloc(0, &HashMap::new()).context(TLKMInit {})?;
+ // Change device access to excluse to be able to acquire PEs
+ tlkm_device.change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive).context(DeviceInit {})?;
+
+ let tlkm_version = tlkm.version().context(TLKMInit {})?;
+ let platform_base = tlkm_device.status().platform_base.clone().expect("Could not get platform_base!");
+ let arch_base = tlkm_device.status().arch_base.clone().expect("Could not get arch_base!");
+
+ // Now d is shorthand for tlkm_device
+ let d = &tlkm_device;
+
+ // Parse info about PEs from the status core
+ let mut pe_infos = Vec::new();
+ // Preallocate this vector to set the acquired PE at the right position later
+ let mut pes: Vec<(usize, PE)> = Vec::with_capacity(d.status().pe.len());
+
+ for (index, pe) in d.status().pe.iter().enumerate() {
+ // Calculate the "real" address using arch base address plus PE offset
+ let address = &arch_base.base + pe.offset;
+ pe_infos.push(
+ // TODO: How wide is this address? 32 or 64 (48) bits?
+ format!("Slot {}: {} (ID: {}) Address: 0x{:012x} ({}), Size: 0x{:x} ({} Bytes)",
+ index, pe.name, pe.id, address, address, pe.size, pe.size));
+
+ // Acquire the PE to be able to show its registers etc.
+ // Warning: casting to usize can panic! On a <32-bit system..
+ let pe = d.acquire_pe_without_job(pe.id as usize).context(DeviceInit {})?;
+ // TODO: There is no way to check that you really got the PE that you wanted
+ // so I have to use this workaround to set it at the ID of the PE struct which
+ // confusingly is NOT the pe.id from above which is stored at type_id inside the PE.
+ let pe_real_id = *pe.id();
+ //pes[pe_real_id] = pe;
+ pes.push((pe_real_id, pe));
+ }
+
+ // Preselect the first element if the device's bitstream contains at least one PE
+ let pe_infos = if pe_infos.len() > 0 {
+ StatefulList::with_items_selected(pe_infos, 0)
+ } else {
+ StatefulList::with_items(pe_infos)
+ };
+
+ // Parse bitstream info from the Status core
+ let mut bitstream_info = String::new();
+ // TODO: decode vendor and product IDs
+ bitstream_info += &format!(" Device ID: {} ({}),\n Vendor: {}, Product: {},\n\n",
+ d.id(), d.name(), d.vendor(), d.product());
+
+ // Warning: casting to i64 can panic! If the timestamp is bigger than 63 bit..
+ bitstream_info += &format!(" Bitstream generated at:\n {} ({})\n\n",
+ Utc.timestamp(d.status().timestamp as i64, 0),
+ d.status().timestamp);
+
+ for v in &d.status().versions {
+ bitstream_info += &format!(" {} Version: {}.{}{}\n",
+ v.software, v.year, v.release, v.extra_version);
+ }
+ bitstream_info += &format!(" TLKM Version: {}\n\n", tlkm_version);
+
+ for c in &d.status().clocks {
+ bitstream_info += &format!(" {} Clock Frequency: {} MHz\n",
+ c.name, c.frequency_mhz);
+ }
+
+ // Parse platform info from the Status core
+ let mut platform_info = String::new();
+
+ platform_info += &format!(" Platform Base: 0x{:012x} (Size: 0x{:x} ({} Bytes))\n\n",
+ platform_base.base, platform_base.size, platform_base.size);
+
+ for p in &d.status().platform {
+ // TODO: is this correct? PEs use arch_base, platform components use platform_base?
+ let address = &platform_base.base + p.offset;
+ platform_info +=
+ &format!(" {}:\n Address: 0x{:012x} ({}), Size: 0x{:x} ({} Bytes)\n Interrupts: {}\n\n",
+ p.name.trim_start_matches("PLATFORM_COMPONENT_"), address, address,
+ p.size, p.size, parse_interrupts(&p.interrupts));
+ }
+
+
+ Ok(App {
+ bitstream_info,
+ platform_info,
+ title: "TaPaSCo Debugger",
+ tabs: TabsState::new(vec!["Peek & Poke", "DMAEngine Statistics"]),
+ pe_infos,
+ pes,
+ })
+ }
+
+ pub fn next_tab(&mut self) {
+ self.tabs.next();
+ }
+
+ pub fn previous_tab(&mut self) {
+ self.tabs.previous();
+ }
+
+ pub fn on_up(&mut self) {
+ self.pe_infos.previous();
+ }
+
+ pub fn on_down(&mut self) {
+ self.pe_infos.next();
+ }
+
+ pub fn on_escape(&mut self) {
+ self.pe_infos.unselect();
+ }
+
+ pub fn on_return(&mut self) {
+ match self.pe_infos.state.selected() {
+ // TODO: Implement changing the focused widget
+ Some(_n) => {},
+ _ => {},
+ }
+ }
+
+ pub fn get_bitstream_info(&mut self) -> &str {
+ &self.bitstream_info
+ }
+
+ pub fn get_platform_info(&mut self) -> &str {
+ &self.platform_info
+ }
+
+ pub fn read_pe_registers(&mut self, pe_slot: Option) -> String {
+ let pe_slot = match pe_slot {
+ Some(n) => n,
+ _ => return "\n No PE selected.".to_string(),
+ };
+
+ // Get the PE with the real ID of the given Slot
+ let (_, pe) = self.pes.iter()
+ .filter(|(id, _)| *id == pe_slot)
+ .take(1)
+ .collect::>()
+ .get(0)
+ .expect("There should be a PE with the selected ID. This is a bug.");
+
+ let (global_interrupt, local_interrupt) = pe.interrupt_status().expect("Expected to get PE interrupt status.");
+ let return_value = pe.return_value();
+ let argument_registers = (0..16)
+ .map(|i| match pe.read_arg(i, 8).expect("Expected to be able to read PE registers!") {
+ PEParameter::Single64(u) => u,
+ _ => 0
+ })
+ .collect::>();
+
+ // TODO: From where can I get those?
+ let is_running = false;
+ let interrupt_pending = false;
+
+ let mut result = String::new();
+ result += &format!(concat!(" PE is running: {}\n Local Interrupt Enabled: {}\n",
+ " Global Interrupt Enabled: {}\n Interrupt pending: {}\n\n",
+ " Return Value: 0x{:16x}\n\n"),
+ is_running, local_interrupt, global_interrupt, interrupt_pending,
+ return_value);
+ for (i, a) in argument_registers.iter().enumerate() {
+ result += &format!(" A#{:02}: 0x{:16x} ({})\n", i, a, a);
+ }
+
+ result
+ }
+}
+
+fn parse_interrupts(interrupts: &Vec) -> String {
+ let mut result = String::new();
+
+ if interrupts.len() == 0 {
+ result += "None";
+ }
+ else {
+ result += "[ ";
+
+ for (index, interrupt) in interrupts.iter().enumerate() {
+ if index > 0 {
+ result += ", ";
+ }
+
+ result += &format!("{}:{}", interrupt.mapping, interrupt.name);
+ }
+
+ result += " ]";
+ }
+
+ result
+}
+
+
+// The following code is taken from libtui-rs demo:
+// https://github.com/fdehau/tui-rs/blob/v0.15.0/examples/util/mod.rs
+// licensed under MIT License by Florian Dehau, see:
+// https://spdx.org/licenses/MIT.html
+pub struct TabsState<'a> {
+ pub titles: Vec<&'a str>,
+ pub index: usize,
+}
+
+impl<'a> TabsState<'a> {
+ pub fn new(titles: Vec<&'a str>) -> TabsState {
+ TabsState {
+ titles,
+ index: 0,
+ }
+ }
+
+ pub fn next(&mut self) {
+ self.index = (self.index + 1) % self.titles.len();
+ }
+
+ pub fn previous(&mut self) {
+ self.index = if self.index == 0 {
+ self.titles.len() - 1
+ } else {
+ self.index - 1
+ }
+ }
+}
+
+
+use tui::widgets::ListState;
+
+pub struct StatefulList {
+ pub state: ListState,
+ pub items: Vec,
+}
+
+impl StatefulList {
+ pub fn new() -> StatefulList {
+ StatefulList {
+ state: ListState::default(),
+ items: Vec::new(),
+ }
+ }
+
+ pub fn with_items(items: Vec) -> StatefulList {
+ StatefulList {
+ state: ListState::default(),
+ items,
+ }
+ }
+
+ pub fn with_items_selected(items: Vec, selected: usize) -> StatefulList {
+ let mut list = StatefulList {
+ state: ListState::default(),
+ items,
+ };
+ list.state.select(Some(selected));
+
+ list
+ }
+
+ pub fn next(&mut self) {
+ let n = match self.state.selected() {
+ Some(m) => {
+ if m >= self.items.len() - 1 {
+ 0
+ } else {
+ m + 1
+ }
+ },
+ None => 0,
+ };
+
+ self.state.select(Some(n));
+ }
+
+ pub fn previous(&mut self) {
+ let n = match self.state.selected() {
+ Some(m) => {
+ if m == 0 {
+ self.items.len() - 1
+ } else {
+ m - 1
+ }
+ },
+ None => self.items.len() - 1,
+ };
+
+ self.state.select(Some(n));
+ }
+
+ pub fn unselect(&mut self) {
+ self.state.select(None);
+ }
+}
diff --git a/runtime/examples/Rust/tapasco-debug/src/main.rs b/runtime/examples/Rust/tapasco-debug/src/main.rs
new file mode 100644
index 00000000..e4ff946d
--- /dev/null
+++ b/runtime/examples/Rust/tapasco-debug/src/main.rs
@@ -0,0 +1,26 @@
+mod app;
+mod ui;
+use app::App;
+use ui::setup;
+
+use snafu::{ResultExt, Snafu};
+
+#[derive(Debug, Snafu)]
+#[snafu(visibility(pub))]
+pub enum Error {
+ #[snafu(display("Failed to initialize TLKM object: {}. Have you loaded the kernel module?", source))]
+ TLKMInit { source: tapasco::tlkm::Error },
+
+ #[snafu(display("Failed to initialize App: {}. Have you loaded the kernel module?", source))]
+ AppError { source: app::Error },
+
+ #[snafu(display("Failed to initialize UI: {}. Have you checked your Terminal?", source))]
+ UIError { source: ui::Error },
+}
+
+type Result = std::result::Result;
+
+
+fn main() -> Result<()> {
+ setup(&mut App::new().context(AppError {})?).context(UIError {})
+}
diff --git a/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs b/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs
new file mode 100644
index 00000000..19b66fdd
--- /dev/null
+++ b/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs
@@ -0,0 +1,329 @@
+use std::{
+ io::stdout,
+ sync::mpsc,
+ thread,
+ time::Duration,
+};
+
+use tui::{
+ Terminal,
+ Frame,
+ backend::{Backend, CrosstermBackend},
+ widgets::{Tabs, Block, Borders, Paragraph, Wrap, BorderType, ListItem, List},
+ layout::{Layout, Constraint, Direction, Rect},
+ text::{Span, Spans, Text},
+ style::{Style, Color, Modifier},
+ symbols::DOT,
+};
+
+use crossterm::{
+ execute,
+ event::{self, EnableMouseCapture, DisableMouseCapture, Event as CEvent, KeyEvent, KeyCode, KeyModifiers},
+ terminal::{enable_raw_mode, disable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
+};
+
+use snafu::{ResultExt, Snafu};
+
+#[derive(Debug, Snafu)]
+pub enum Error {
+ #[snafu(display("Failure in Crossterm Terminal Backend: {}", source))]
+ CrosstermError { source: std::io::Error },
+
+ #[snafu(display("Failed to receive Input event: {}", source))]
+ ReceiveInput { source: std::sync::mpsc::RecvError },
+
+ #[snafu(display("Failed to handle Input event: {}", source))]
+ HandleInput { source: std::io::Error },
+
+ //#[snafu(display("Failed to send Input event!"))]
+ //SendInput { source: std::sync::mpsc::SendError },
+}
+
+pub type Result = std::result::Result;
+
+use crate::app::App;
+
+
+// Define Instructions (see key press in event loop for reference)
+//const INSTRUCTIONS: &str = r#"'q' Quit 'r' Peek/Redraw UI"#;
+
+// Define an Event which can consist of a pressed key or a Tick which occurs when the UI should be
+// updated while no key got pressed
+enum Event {
+ Input(I),
+ Resize(H, H),
+ //Tick, // Maybe update app for Ticks?
+}
+
+
+pub fn setup(app: &mut App) -> Result<()> {
+ // Raw mode disables some common terminal functions that are unnecessary in the TUI environment
+ enable_raw_mode().context(CrosstermError {})?;
+
+ // Enter the Alternate Screen, so we don't break terminal history (it's like opening vim)
+ let mut stdout = stdout();
+ execute!(stdout, EnterAlternateScreen, EnableMouseCapture).context(CrosstermError {})?;
+
+ // Initialize Crossterm backend
+ let backend = CrosstermBackend::new(stdout);
+ let mut terminal = Terminal::new(backend).context(CrosstermError {})?;
+
+ // Clear the Alternate Screen if someone left it dirty
+ terminal.clear().context(CrosstermError {})?;
+
+ // Save the result of the main loop to return it after tearing down the backend
+ let result = run_event_loop(app, &mut terminal);
+
+ // Leave Alternate Screen to shut down cleanly regardless of the result
+ disable_raw_mode().context(CrosstermError {})?;
+ execute!(terminal.backend_mut(), DisableMouseCapture, LeaveAlternateScreen).context(CrosstermError {})?;
+ terminal.show_cursor().context(CrosstermError {})?;
+
+ // Return the result of the main loop after restoring the previous terminal state in order to
+ // not be stuck in the Alternate Screen / or Raw Mode which would make a `reset` of the shell
+ // necessary
+ result
+}
+
+fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) -> Result<()> {
+ // Setup input handling as in the crossterm demo with a multi producer single consumer (mpsc) channel
+ let (tx, rx) = mpsc::channel();
+ thread::spawn(move || {
+ loop {
+ if event::poll(Duration::from_millis(250)).expect("Event loop: could not poll for events!") {
+ if let CEvent::Key(key) = event::read().expect("Event loop: could not read a key event!") {
+ tx.send(Event::Input(key)).expect("Event loop: could not send an input event!");
+ } else if let CEvent::Resize(w, h) = event::read().expect("Event loop: could not read a resize event!") {
+ tx.send(Event::Resize(w, h)).expect("Event loop: could not send a resize event!");
+ }
+ }
+ }
+ });
+
+ // Event loop
+ loop {
+ // Update UI
+ draw(app, &mut terminal)?;
+
+ // Handle events
+ match rx.recv().context(ReceiveInput {})? {
+ // Match key pressed events
+ Event::Input(event) => match event {
+ // with Shift modifier
+ KeyEvent {
+ modifiers: KeyModifiers::SHIFT,
+ code,
+ } => match code {
+ // Press 'Shift+Tab' to switch backward between tabs
+ // TODO: This doesn't work! Why?
+ KeyCode::Tab => app.previous_tab(),
+ _ => {},
+ },
+ // without any modifiers
+ KeyEvent {
+ modifiers: KeyModifiers::NONE,
+ code,
+ } => match code {
+ // Press 'q' to quit application
+ KeyCode::Char('q') => return Ok(()),
+ // Press 'r' to redraw the UI
+ KeyCode::Char('r') => continue,
+ // Press 'Tab' to switch forward between tabs
+ KeyCode::Tab => app.next_tab(),
+ // Press ↑ or 'k' to go up in the list of PEs/Registers
+ KeyCode::Up | KeyCode::Char('k') => app.on_up(),
+ // Press ↓ or 'j' to go down in the list of PEs/Registers
+ KeyCode::Down | KeyCode::Char('j') => app.on_down(),
+ // Press Escape or 'h' to return back to the list of PEs
+ KeyCode::Esc | KeyCode::Char('h') => app.on_escape(),
+ // Press Enter or 'l' to select a PE/Register
+ KeyCode::Enter | KeyCode::Char('l') => app.on_return(),
+ _ => {},
+ },
+ _ => {},
+ },
+ Event::Resize(_, _) => continue,
+ }
+ }
+}
+
+fn draw(app: &mut App, terminal: &mut Terminal) -> Result<()> {
+ terminal.draw(|f| {
+ // Create a layout with fixed space for the Tab bar and a flexible space where each tab can
+ // draw itself
+ let tabs_chunks = Layout::default()
+ .direction(Direction::Vertical)
+ .margin(1)
+ .constraints(
+ [
+ Constraint::Length(3),
+ Constraint::Min(0),
+ ].as_ref()
+ )
+ .split(f.size());
+
+ // Map the titles of the Tabs into Spans to be able to highlight the title of the
+ // selected Tab
+ let titles = app.tabs.titles
+ .iter()
+ .map(|t| Spans::from(Span::styled(*t, Style::default())))
+ .collect();
+ let tabs = Tabs::new(titles)
+ .block(Block::default()
+ .title(Span::styled(app.title,
+ Style::default().add_modifier(Modifier::DIM)))
+ .border_type(BorderType::Rounded)
+ .border_style(Style::default().add_modifier(Modifier::DIM))
+ .borders(Borders::ALL))
+ .style(Style::default()
+ .fg(Color::White))
+ .highlight_style(
+ Style::default()
+ .fg(Color::Blue)
+ .add_modifier(Modifier::BOLD)
+ )
+ .divider(DOT)
+ .select(app.tabs.index);
+
+ f.render_widget(tabs, tabs_chunks[0]);
+
+ // Call the specific draw function for the selected Tab
+ match app.tabs.index {
+ 0 => draw_first_tab(f, app, tabs_chunks[1]),
+ 1 => draw_second_tab(f, app, tabs_chunks[1]),
+ _ => {},
+ }
+ }).context(CrosstermError {})?;
+
+ Ok(())
+}
+
+fn draw_first_tab(f: &mut Frame, app: &mut App, chunk: Rect) {
+ // Create a vertical layout (top to bottom) first to split the Tab into 3 rows
+ let vertical_chunks = Layout::default()
+ .direction(Direction::Vertical)
+ .margin(1)
+ .constraints(
+ [
+ Constraint::Percentage(65),
+ Constraint::Percentage(30),
+ Constraint::Length(3),
+ ].as_ref()
+ )
+ .split(chunk);
+
+ // Split the first row into half (okay golden ratio) vertically again
+ let inner_vertical_chunks = Layout::default()
+ //.direction(Direction::Horizontal)
+ .direction(Direction::Vertical)
+ .margin(0)
+ .constraints(
+ [
+ Constraint::Percentage(35),
+ Constraint::Percentage(65),
+ ].as_ref()
+ )
+ .split(vertical_chunks[0]);
+
+ // Split the first row's second row into half (okay golden ratio) horizontally
+ let first_horizontal_chunks = Layout::default()
+ .direction(Direction::Horizontal)
+ //.direction(Direction::Vertical)
+ .margin(0)
+ .constraints(
+ [
+ Constraint::Percentage(65),
+ Constraint::Percentage(35),
+ ].as_ref()
+ )
+ .split(inner_vertical_chunks[1]);
+
+ let triple_vertical_chunks = Layout::default()
+ .direction(Direction::Vertical)
+ .margin(0)
+ .constraints(
+ [
+ Constraint::Percentage(33),
+ Constraint::Percentage(33),
+ Constraint::Percentage(33),
+ ].as_ref()
+ )
+ .split(first_horizontal_chunks[1]);
+
+ // Split the second row into half (okay golden ratio)
+ let second_horizontal_chunks = Layout::default()
+ .direction(Direction::Horizontal)
+ .margin(0)
+ .constraints(
+ [
+ Constraint::Percentage(35),
+ Constraint::Percentage(65),
+ ].as_ref()
+ )
+ .split(vertical_chunks[1]);
+
+ // Draw the PEs as stateful list to be able to select one
+ let pes: Vec = app.pe_infos.items.iter()
+ .map(|i| ListItem::new(vec![Spans::from(Span::raw(i))]))
+ .collect();
+ let pes = List::new(pes)
+ .block(new_dim_block("PE List: ↓,j/↑,k/Enter,l to switch to PE Registers"))
+ .highlight_style(Style::default().add_modifier(Modifier::BOLD))
+ .highlight_symbol("> ");
+ f.render_stateful_widget(pes, inner_vertical_chunks[0], &mut app.pe_infos.state);
+
+ draw_block_with_paragraph(f, "Register List: ↓,j/↑,k/Enter,l to set Register",
+ app.read_pe_registers(app.pe_infos.state.selected()),
+ first_horizontal_chunks[0]);
+
+ // Also show info about Local Memory, Debug Cores and Interrupts
+ draw_block_with_paragraph(f, "Local Memory",
+ "No info about Local Memory yet.",
+ triple_vertical_chunks[0]);
+ draw_block_with_paragraph(f, "Debug Cores",
+ "No info about Debug Cores yet.",
+ triple_vertical_chunks[1]);
+ draw_block_with_paragraph(f, "Interrupts",
+ "No info about Interrupts yet.",
+ triple_vertical_chunks[2]);
+
+ draw_block_with_paragraph(f, "Bitstream & Device Info", app.get_bitstream_info(), second_horizontal_chunks[0]);
+ draw_block_with_paragraph(f, "Platform Components", app.get_platform_info(), second_horizontal_chunks[1]);
+
+ // Define Instructions (see key press in event loop for reference)
+ let instructions = Spans::from(vec![
+ Span::raw(" "),
+ Span::styled("q", Style::default().add_modifier(Modifier::BOLD)),
+ Span::from(" Quit"),
+ Span::raw(" "),
+ Span::styled("r", Style::default().add_modifier(Modifier::BOLD)),
+ Span::from(" Peek/Redraw"),
+ Span::raw(" "),
+ Span::styled("Remember to quit before reprogramming the FPGA or reloading the kernel module!",
+ Style::default().add_modifier(Modifier::ITALIC)),
+ ]);
+ draw_block_with_paragraph(f, "Instructions", instructions, vertical_chunks[2]);
+}
+
+fn draw_second_tab(f: &mut Frame, _app: &App, chunk: Rect) {
+ draw_block_with_paragraph(f, "Nothing to see here", "This still needs to be implemented.. Sorry!", chunk);
+}
+
+/// Draw a block with some text in it into the rectangular space given by chunk
+//fn draw_block_with_paragraph(f: &mut Frame, block_title: &str, paragraph_text: &str, chunk: Rect) {
+fn draw_block_with_paragraph<'a, B: Backend, T>(f: &mut Frame, block_title: &str, text: T, chunk: Rect) where Text<'a>: From {
+ let block = new_dim_block(block_title);
+ let paragraph = Paragraph::new(text)
+ .block(block)
+ .wrap(Wrap { trim: false });
+ f.render_widget(paragraph, chunk);
+}
+
+/// Create a new Block with round corners in dim colors and the given title
+fn new_dim_block(title: &str) -> Block {
+ Block::default()
+ .title(Span::styled(title, Style::default().add_modifier(Modifier::DIM)))
+ .border_type(BorderType::Rounded)
+ .border_style(Style::default().add_modifier(Modifier::DIM))
+ .borders(Borders::ALL)
+}
From 097d8d143baad0684e7cb926ec4f68e496f225eb Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:48 +0100
Subject: [PATCH 02/34] Modify `libtapasco` to acquire a PE without a job
This is a necessary change for `tapasco-debug` to be able to acquire a
PE in order to call its methods instead of directly starting a job on
that PE as it is usually the case.
---
runtime/libtapasco/src/device.rs | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/runtime/libtapasco/src/device.rs b/runtime/libtapasco/src/device.rs
index 21af184c..08bad53a 100644
--- a/runtime/libtapasco/src/device.rs
+++ b/runtime/libtapasco/src/device.rs
@@ -23,7 +23,7 @@ use crate::debug::DebugGenerator;
use crate::dma::{DMAControl, DirectDMA, DriverDMA, VfioDMA, SVMDMA};
use crate::dma_user_space::UserSpaceDMA;
use crate::job::Job;
-use crate::pe::PEId;
+use crate::pe::{PE, PEId};
use crate::scheduler::Scheduler;
use crate::tlkm::{tlkm_access, tlkm_ioctl_svm_launch, tlkm_svm_init_cmd};
use crate::tlkm::tlkm_ioctl_create;
@@ -498,6 +498,20 @@ impl Device {
Ok(Job::new(pe, &self.scheduler))
}
+ /// Request a PE from the device but don't create a Job for it. Usually [`acquire_pe`] is used
+ /// if you don't want to do things manually.
+ ///
+ /// # Arguments
+ /// * id: The ID of the desired PE.
+ ///
+ pub fn acquire_pe_without_job(&self, id: PEId) -> Result {
+ self.check_exclusive_access()?;
+ trace!("Trying to acquire PE of type {}.", id);
+ let pe = self.scheduler.acquire_pe(id).context(SchedulerError)?;
+ trace!("Successfully acquired PE of type {}.", id);
+ Ok(pe)
+ }
+
fn check_exclusive_access(&self) -> Result<()> {
if self.access == tlkm_access::TlkmAccessExclusive {
Ok(())
From 3e4574420b3b3c87115e5799b9dece2f731274a5 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:49 +0100
Subject: [PATCH 03/34] Add `env_logger` crate for logging
---
runtime/examples/Rust/tapasco-debug/Cargo.toml | 3 +++
runtime/examples/Rust/tapasco-debug/src/main.rs | 3 +++
2 files changed, 6 insertions(+)
diff --git a/runtime/examples/Rust/tapasco-debug/Cargo.toml b/runtime/examples/Rust/tapasco-debug/Cargo.toml
index 56a2e127..4683acd8 100644
--- a/runtime/examples/Rust/tapasco-debug/Cargo.toml
+++ b/runtime/examples/Rust/tapasco-debug/Cargo.toml
@@ -13,3 +13,6 @@ tapasco = { path = "../../../libtapasco" }
snafu = "0.6"
chrono = "0.4"
+
+log = "0.4"
+env_logger = "0.8"
diff --git a/runtime/examples/Rust/tapasco-debug/src/main.rs b/runtime/examples/Rust/tapasco-debug/src/main.rs
index e4ff946d..bc73b132 100644
--- a/runtime/examples/Rust/tapasco-debug/src/main.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/main.rs
@@ -20,7 +20,10 @@ pub enum Error {
type Result = std::result::Result;
+use env_logger;
fn main() -> Result<()> {
+ env_logger::init();
+
setup(&mut App::new().context(AppError {})?).context(UIError {})
}
From af8cc0747bf3b44f73c0569c5502ffd410a8473e Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:49 +0100
Subject: [PATCH 04/34] Print snafu's backtrace in Display format
---
runtime/examples/Rust/tapasco-debug/src/main.rs | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/main.rs b/runtime/examples/Rust/tapasco-debug/src/main.rs
index bc73b132..1cbc6bb0 100644
--- a/runtime/examples/Rust/tapasco-debug/src/main.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/main.rs
@@ -22,8 +22,20 @@ type Result = std::result::Result;
use env_logger;
-fn main() -> Result<()> {
- env_logger::init();
+fn init() -> Result<()> {
setup(&mut App::new().context(AppError {})?).context(UIError {})
}
+fn main() {
+ env_logger::init();
+
+ match init() {
+ Ok(_) => {},
+ Err(e) => {
+ eprintln!("An error occurred: {}", e);
+ if let Some(backtrace) = snafu::ErrorCompat::backtrace(&e) {
+ println!("{}", backtrace);
+ }
+ },
+ };
+}
From 4d79685442710df18879e598d3ab981bd89250aa Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:50 +0100
Subject: [PATCH 05/34] Restructure module imports in `main.rs`
---
runtime/examples/Rust/tapasco-debug/src/main.rs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/main.rs b/runtime/examples/Rust/tapasco-debug/src/main.rs
index 1cbc6bb0..a7009bfb 100644
--- a/runtime/examples/Rust/tapasco-debug/src/main.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/main.rs
@@ -1,6 +1,7 @@
mod app;
-mod ui;
use app::App;
+
+mod ui;
use ui::setup;
use snafu::{ResultExt, Snafu};
From ebf946a8c1c4ae466e6cec612a4a404d14b7571e Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:50 +0100
Subject: [PATCH 06/34] Modify `libtapasco` to acquire a PE read-only
In order to implement a Monitor Mode where values can only be observed
in `tapasco-debug` the function in `libtapasco` which is used to acquire
PEs is modified to return non-mutable PE structs which do not need
exclusive access to the device.
---
runtime/examples/Rust/tapasco-debug/src/app/mod.rs | 8 +++++---
runtime/libtapasco/src/device.rs | 5 ++---
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
index dc7b293f..ef0871ef 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
@@ -46,9 +46,11 @@ impl<'a> App<'a> {
let tlkm = TLKM::new().context(TLKMInit {})?;
//let tlkm_device = tlkm.device_enum(&HashMap::new()).context(TLKMInit {})?;
// Allocate the first device with ID 0 (because most devices will only have one FPGA)
- let mut tlkm_device = tlkm.device_alloc(0, &HashMap::new()).context(TLKMInit {})?;
- // Change device access to excluse to be able to acquire PEs
- tlkm_device.change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive).context(DeviceInit {})?;
+ let tlkm_device = tlkm.device_alloc(0, &HashMap::new()).context(TLKMInit {})?;
+ // Monitor Mode: In order to observe other Tapasco Host applications which need exclusive
+ // access we implement a monitor mode where registers cannot be modified.
+ // Change device access to exclusive to be able to acquire PEs
+ //tlkm_device.change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive).context(DeviceInit {})?;
let tlkm_version = tlkm.version().context(TLKMInit {})?;
let platform_base = tlkm_device.status().platform_base.clone().expect("Could not get platform_base!");
diff --git a/runtime/libtapasco/src/device.rs b/runtime/libtapasco/src/device.rs
index 08bad53a..c324ed23 100644
--- a/runtime/libtapasco/src/device.rs
+++ b/runtime/libtapasco/src/device.rs
@@ -505,10 +505,9 @@ impl Device {
/// * id: The ID of the desired PE.
///
pub fn acquire_pe_without_job(&self, id: PEId) -> Result {
- self.check_exclusive_access()?;
- trace!("Trying to acquire PE of type {}.", id);
+ trace!("Trying to acquire PE of type {} without exclusive access.", id);
let pe = self.scheduler.acquire_pe(id).context(SchedulerError)?;
- trace!("Successfully acquired PE of type {}.", id);
+ trace!("Successfully acquired PE of type {} without exclusive access.", id);
Ok(pe)
}
From ce6854926d567c8ddc9a4c0b540228f2839567b4 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:51 +0100
Subject: [PATCH 07/34] Fix `CMakeLists` for `tapasco-debug` in debug mode
See commit 59110746aa4f5aa5f2c5ea7ced8df2e4d2f4f956.
---
runtime/examples/Rust/tapasco-debug/CMakeLists.txt | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/CMakeLists.txt b/runtime/examples/Rust/tapasco-debug/CMakeLists.txt
index 6f7ae564..37b338ac 100644
--- a/runtime/examples/Rust/tapasco-debug/CMakeLists.txt
+++ b/runtime/examples/Rust/tapasco-debug/CMakeLists.txt
@@ -23,10 +23,18 @@ project(tapasco-debug)
add_executable(tapasco-debug .)
# Use Cargo to build this project in debug mode by defining a custom target running after the tapasco target has been built.
-add_custom_target(tapasco_debug_cargo_build_debug COMMAND CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} cargo build -q --debug WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} DEPENDS tapasco COMMENT "Building tapasco-debug with Cargo")
+add_custom_target(tapasco_debug_cargo_build_debug
+ COMMAND CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} cargo build -q
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+ DEPENDS tapasco
+ COMMENT "Building tapasco-debug with Cargo")
# Use Cargo to build this project in release mode by defining a custom target running after the tapasco target has been built.
-add_custom_target(tapasco_debug_cargo_build_release COMMAND CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} cargo build -q --release WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} DEPENDS tapasco COMMENT "Building tapasco-debug with Cargo")
+add_custom_target(tapasco_debug_cargo_build_release
+ COMMAND CARGO_TARGET_DIR=${CMAKE_CURRENT_BINARY_DIR} cargo build -q --release
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
+ DEPENDS tapasco
+ COMMENT "Building tapasco-debug with Cargo")
# Check if building should be in Debug or Release mode
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
From 67433889cfbd774bfa057c5777a0275fe6f86d39 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:51 +0100
Subject: [PATCH 08/34] Implement Monitor, Debug and Unsafe Mode
As discussed in the respective PR #290
(https://github.com/esa-tu-darmstadt/tapasco/pull/290)
there are now three differenct access modes: Monitor, Debug, Unsafe.
This commit introduces command-line subcommands to choose the mode in
which to operate.
In `Monitor` mode nothing can be modified only another runtime
can be monitored.
In `Debug` Mode the argument registers can also be set interactively.
In `Unsafe` Mode the only difference to `Debug` Mode is that the driver
is released, so another host application can run in parallel.
---
.../examples/Rust/tapasco-debug/Cargo.toml | 5 +-
.../Rust/tapasco-debug/src/app/mod.rs | 458 ++++++++++++++----
.../examples/Rust/tapasco-debug/src/main.rs | 35 +-
.../examples/Rust/tapasco-debug/src/ui/mod.rs | 332 +++++++------
4 files changed, 592 insertions(+), 238 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/Cargo.toml b/runtime/examples/Rust/tapasco-debug/Cargo.toml
index 4683acd8..f5da7d40 100644
--- a/runtime/examples/Rust/tapasco-debug/Cargo.toml
+++ b/runtime/examples/Rust/tapasco-debug/Cargo.toml
@@ -10,9 +10,10 @@ edition = "2018"
tui = { version = "0.15", default-features = false, features = ['crossterm'] }
crossterm = "0.20"
tapasco = { path = "../../../libtapasco" }
-
snafu = "0.6"
chrono = "0.4"
-
log = "0.4"
env_logger = "0.8"
+structopt = "0.3"
+memmap = "0.7"
+unicode-width = "0.1.8"
diff --git a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
index ef0871ef..665c5422 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
@@ -1,11 +1,17 @@
use std::{
collections::HashMap,
+ sync::Arc,
};
+use log::{trace, warn, error};
+
use tapasco::{
tlkm::*,
- device::status::Interrupt,
- pe::PE,
+ device::{
+ Device,
+ status::Interrupt,
+ },
+ pe::PE,
device::PEParameter,
};
@@ -24,57 +30,106 @@ pub enum Error {
type Result = std::result::Result;
+// Import the Subcommand enum from super module as AccessMode to clarify intent
+pub use super::Command as AccessMode;
+
-// TODO: Right now I'm just handling the first FPGA device because I assume most will have
-// only one FPGA but switching devices should be possible e.g. by passing the device as cli
-// argument or with an extra key binding?
// TODO: It would be nice to see when/how many interrupts were triggered.
+#[derive(Debug,PartialEq)]
+pub enum InputMode { Normal, Edit }
+
+#[derive(Debug,PartialEq)]
+pub enum InputFrame { PEList, RegisterList }
+
pub struct App<'a> {
+ _tlkm_option: Option,
+ _device_option: Option,
bitstream_info: String,
platform_info: String,
- pub title: &'a str,
+ platform: Arc,
+ dmaengine_offset: Option,
+ pub access_mode: AccessMode,
+ pub input: String,
+ pub input_mode: InputMode,
+ pub focus: InputFrame,
+ pub title: String,
pub tabs: TabsState<'a>,
pub pe_infos: StatefulList,
pub pes: Vec<(usize, PE)>, // Plural of Processing Element (PEs)
+ pub register_list: StatefulList,
+ pub local_memory_list: StatefulList,
}
impl<'a> App<'a> {
- pub fn new() -> Result> {
+ pub fn new(device_id: u32, access_mode: AccessMode) -> Result> {
+ trace!("Creating new App for Tapasco state");
+
// Get Tapasco Loadable Linux Kernel Module
let tlkm = TLKM::new().context(TLKMInit {})?;
- //let tlkm_device = tlkm.device_enum(&HashMap::new()).context(TLKMInit {})?;
- // Allocate the first device with ID 0 (because most devices will only have one FPGA)
- let tlkm_device = tlkm.device_alloc(0, &HashMap::new()).context(TLKMInit {})?;
- // Monitor Mode: In order to observe other Tapasco Host applications which need exclusive
- // access we implement a monitor mode where registers cannot be modified.
- // Change device access to exclusive to be able to acquire PEs
- //tlkm_device.change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive).context(DeviceInit {})?;
+ // Allocate the device with the given ID
+ let mut tlkm_device = tlkm.device_alloc(device_id, &HashMap::new()).context(TLKMInit {})?;
+
+ // For some access modes we need to take some special care to use them
+ let access_mode_str = match access_mode {
+ AccessMode::Monitor {} => {
+ // Monitor Mode: In order to observe other Tapasco Host applications which need exclusive
+ // access we implement a monitor mode where registers cannot be modified. For this
+ // no special access is necessary. This is a no-op.
+ "Monitor"
+ },
+ AccessMode::Debug {} => {
+ // Change device access to exclusive to be able to acquire PEs
+ tlkm_device.change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive).context(DeviceInit {})?;
+ "Debug"
+ },
+ AccessMode::Unsafe {} => {
+ // Change device access to exclusive to be able to acquire PEs
+ tlkm_device.change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive).context(DeviceInit {})?;
+ warn!("Running in Unsafe Mode");
+ "Unsafe"
+ },
+ };
+ trace!("Access Mode is: {}", access_mode_str);
+
+ // Empty string where input is stored
+ let input = String::new();
+ // Initialize App in Normal mode
+ let input_mode = InputMode::Normal;
+ // Initialize UI with focus on the PE list
+ let focus = InputFrame::PEList;
+
+ let tabs = TabsState::new(vec!["Peek & Poke PEs", "Platform Components", "Bitstream & Device Info"]);
+ let title = format!("TaPaSCo Debugger - {} Mode", access_mode_str);
let tlkm_version = tlkm.version().context(TLKMInit {})?;
let platform_base = tlkm_device.status().platform_base.clone().expect("Could not get platform_base!");
let arch_base = tlkm_device.status().arch_base.clone().expect("Could not get arch_base!");
+ let platform = tlkm_device.platform().clone();
- // Now d is shorthand for tlkm_device
- let d = &tlkm_device;
+ // Hold the TLKM if we are running in Debug mode, so it is not free'd after this method
+ let _tlkm_option = if (access_mode == AccessMode::Debug {}) {
+ Some(tlkm)
+ } else {
+ None
+ };
// Parse info about PEs from the status core
- let mut pe_infos = Vec::new();
- // Preallocate this vector to set the acquired PE at the right position later
- let mut pes: Vec<(usize, PE)> = Vec::with_capacity(d.status().pe.len());
+ // Preallocate these vectors to set the acquired PE at the right position later
+ let mut pe_infos = Vec::with_capacity(tlkm_device.status().pe.len());
+ let mut pes: Vec<(usize, PE)> = Vec::with_capacity(tlkm_device.status().pe.len());
- for (index, pe) in d.status().pe.iter().enumerate() {
+ for (index, pe) in tlkm_device.status().pe.iter().enumerate() {
// Calculate the "real" address using arch base address plus PE offset
let address = &arch_base.base + pe.offset;
pe_infos.push(
- // TODO: How wide is this address? 32 or 64 (48) bits?
- format!("Slot {}: {} (ID: {}) Address: 0x{:012x} ({}), Size: 0x{:x} ({} Bytes)",
- index, pe.name, pe.id, address, address, pe.size, pe.size));
+ format!("Slot {}: {} (ID: {}) Address: 0x{:016x} ({}), Size: 0x{:x} ({} Bytes), Interrupts: {}, Debug: {:?}",
+ index, pe.name, pe.id, address, address, pe.size, pe.size, App::parse_interrupts(&pe.interrupts), pe.debug));
// Acquire the PE to be able to show its registers etc.
// Warning: casting to usize can panic! On a <32-bit system..
- let pe = d.acquire_pe_without_job(pe.id as usize).context(DeviceInit {})?;
+ let pe = tlkm_device.acquire_pe_without_job(pe.id as usize).context(DeviceInit {})?;
// TODO: There is no way to check that you really got the PE that you wanted
// so I have to use this workaround to set it at the ID of the PE struct which
// confusingly is NOT the pe.id from above which is stored at type_id inside the PE.
@@ -90,51 +145,77 @@ impl<'a> App<'a> {
StatefulList::with_items(pe_infos)
};
+ // There are theoretically endless registers. 100 seems to be a good value.
+ let register_list = StatefulList::with_items(vec!["".to_string(); 100]);
+ let local_memory_list = StatefulList::new();
+
// Parse bitstream info from the Status core
let mut bitstream_info = String::new();
// TODO: decode vendor and product IDs
- bitstream_info += &format!(" Device ID: {} ({}),\n Vendor: {}, Product: {},\n\n",
- d.id(), d.name(), d.vendor(), d.product());
+ bitstream_info += &format!("Device ID: {} ({}),\nVendor: {}, Product: {},\n\n",
+ tlkm_device.id(), tlkm_device.name(), tlkm_device.vendor(), tlkm_device.product());
// Warning: casting to i64 can panic! If the timestamp is bigger than 63 bit..
- bitstream_info += &format!(" Bitstream generated at:\n {} ({})\n\n",
- Utc.timestamp(d.status().timestamp as i64, 0),
- d.status().timestamp);
+ bitstream_info += &format!("Bitstream generated at: {} ({})\n\n",
+ Utc.timestamp(tlkm_device.status().timestamp as i64, 0).format("%Y-%m-%d"),
+ tlkm_device.status().timestamp);
- for v in &d.status().versions {
- bitstream_info += &format!(" {} Version: {}.{}{}\n",
+ for v in &tlkm_device.status().versions {
+ bitstream_info += &format!("{} Version: {}.{}{}\n",
v.software, v.year, v.release, v.extra_version);
}
- bitstream_info += &format!(" TLKM Version: {}\n\n", tlkm_version);
+ bitstream_info += &format!("TLKM Version: {}\n\n", tlkm_version);
- for c in &d.status().clocks {
- bitstream_info += &format!(" {} Clock Frequency: {} MHz\n",
+ for c in &tlkm_device.status().clocks {
+ bitstream_info += &format!("{} Clock Frequency: {} MHz\n",
c.name, c.frequency_mhz);
}
// Parse platform info from the Status core
let mut platform_info = String::new();
- platform_info += &format!(" Platform Base: 0x{:012x} (Size: 0x{:x} ({} Bytes))\n\n",
- platform_base.base, platform_base.size, platform_base.size);
+ let mut dmaengine_offset = None;
+ platform_info += &format!("Platform Base: 0x{:012x} (Size: 0x{:x} ({} Bytes))\n\n",
+ platform_base.base, platform_base.size, platform_base.size);
- for p in &d.status().platform {
- // TODO: is this correct? PEs use arch_base, platform components use platform_base?
+ for p in &tlkm_device.status().platform {
let address = &platform_base.base + p.offset;
platform_info +=
- &format!(" {}:\n Address: 0x{:012x} ({}), Size: 0x{:x} ({} Bytes)\n Interrupts: {}\n\n",
+ &format!("{}:\n Address: 0x{:012x} ({}), Size: 0x{:x} ({} Bytes)\n Interrupts: {}\n\n",
p.name.trim_start_matches("PLATFORM_COMPONENT_"), address, address,
- p.size, p.size, parse_interrupts(&p.interrupts));
+ p.size, p.size, App::parse_interrupts(&p.interrupts));
+
+ if p.name == "PLATFORM_COMPONENT_DMA0" {
+ dmaengine_offset = Some(p.offset as isize);
+ }
}
+ // Hold the TLKM Device if we are running in Debug mode, so it is not free'd after this method
+ let _device_option = if (access_mode == AccessMode::Debug {}) {
+ Some(tlkm_device)
+ } else {
+ None
+ };
+
+ trace!("Constructed App");
Ok(App {
+ _tlkm_option,
+ _device_option,
bitstream_info,
platform_info,
- title: "TaPaSCo Debugger",
- tabs: TabsState::new(vec!["Peek & Poke", "DMAEngine Statistics"]),
+ platform,
+ dmaengine_offset,
+ access_mode,
+ input,
+ input_mode,
+ focus,
+ title,
+ tabs,
pe_infos,
pes,
+ register_list,
+ local_memory_list,
})
}
@@ -147,40 +228,122 @@ impl<'a> App<'a> {
}
pub fn on_up(&mut self) {
- self.pe_infos.previous();
+ match self.tabs.index {
+ 0 => {
+ match self.focus {
+ InputFrame::PEList => self.pe_infos.previous(),
+ InputFrame::RegisterList => self.register_list.previous(),
+ };
+ },
+ _ => {},
+ };
}
pub fn on_down(&mut self) {
- self.pe_infos.next();
+ match self.tabs.index {
+ 0 => {
+ match self.focus {
+ InputFrame::PEList => self.pe_infos.next(),
+ InputFrame::RegisterList => self.register_list.next(),
+ };
+ },
+ _ => {},
+ };
}
pub fn on_escape(&mut self) {
- self.pe_infos.unselect();
+ match self.tabs.index {
+ 0 => {
+ match self.input_mode {
+ InputMode::Normal => {
+ match self.focus {
+ InputFrame::PEList => self.pe_infos.unselect(),
+ InputFrame::RegisterList => {
+ self.register_list.unselect();
+ self.focus = InputFrame::PEList;
+ },
+ };
+ },
+ InputMode::Edit => {
+ self.input_mode = InputMode::Normal;
+ self.input.clear();
+ },
+ };
+ },
+ _ => {},
+ };
}
- pub fn on_return(&mut self) {
- match self.pe_infos.state.selected() {
- // TODO: Implement changing the focused widget
- Some(_n) => {},
+ pub fn on_enter(&mut self) {
+ match self.tabs.index {
+ 0 => {
+ match self.access_mode {
+ AccessMode::Monitor {} => {},
+ AccessMode::Debug {} | AccessMode::Unsafe {} => {
+ match self.input_mode {
+ InputMode::Normal => {
+ match self.focus {
+ // Change the focused component to the register list of the selected PE
+ InputFrame::PEList => match self.pe_infos.state.selected() {
+ Some(_) => {
+ self.focus = InputFrame::RegisterList;
+ self.register_list.next();
+ },
+ _ => self.pe_infos.next(),
+ },
+ // Enter Edit Mode for a new register value
+ InputFrame::RegisterList => {
+ self.input_mode = InputMode::Edit;
+ },
+ };
+ },
+ InputMode::Edit => {
+ // If the input cannot be parsed correctly, simply do nothing until
+ // we either hit Escape or enter a valid decimal integer.
+ if let Ok(new_value) = self.input.parse::() {
+ self.input.clear();
+
+ // Ignore the error because unless the code changes, there will
+ // be no error returned by this function.
+ if let Err(e) = self.pes
+ .get_mut(self.pe_infos.state.selected()
+ .expect("There should have been a selected PE. This is a bug."))
+ .expect("There should have been a PE for the selection. This is a bug.")
+ .1 // ignore the index, select the PE from the tuple
+ .set_arg(self.register_list.state.selected().unwrap(),
+ PEParameter::Single64(new_value as u64)) {
+ // but log this error in case the code changes
+ error!("Error setting argument: {}.
+ This is probably due to libtapasco having changed something
+ important. You should fix this app.", e);
+ }
+
+ self.input_mode = InputMode::Normal;
+ }
+ },
+ };
+ },
+ };
+ },
_ => {},
- }
+ };
}
- pub fn get_bitstream_info(&mut self) -> &str {
+ pub fn get_bitstream_info(&self) -> &str {
&self.bitstream_info
}
- pub fn get_platform_info(&mut self) -> &str {
+ pub fn get_platform_info(&self) -> &str {
&self.platform_info
}
- pub fn read_pe_registers(&mut self, pe_slot: Option) -> String {
- let pe_slot = match pe_slot {
+ fn get_current_pe(&self) -> Option<&PE> {
+ let pe_slot = match self.pe_infos.state.selected() {
Some(n) => n,
- _ => return "\n No PE selected.".to_string(),
+ _ => return None,
};
- // Get the PE with the real ID of the given Slot
+ // Get the PE with the real ID of the selected Slot
let (_, pe) = self.pes.iter()
.filter(|(id, _)| *id == pe_slot)
.take(1)
@@ -188,54 +351,171 @@ impl<'a> App<'a> {
.get(0)
.expect("There should be a PE with the selected ID. This is a bug.");
- let (global_interrupt, local_interrupt) = pe.interrupt_status().expect("Expected to get PE interrupt status.");
- let return_value = pe.return_value();
- let argument_registers = (0..16)
- .map(|i| match pe.read_arg(i, 8).expect("Expected to be able to read PE registers!") {
- PEParameter::Single64(u) => u,
- _ => 0
- })
- .collect::>();
+ Some(pe)
+ }
- // TODO: From where can I get those?
- let is_running = false;
- let interrupt_pending = false;
+ //pub fn start_current_pe(&self) {
+ // if (self.access_mode != AccessMode::Debug {}) {
+ // return;
+ // }
+
+ // if let Some(pe) = self.get_current_pe() {
+ // if let Some(device) = &self._device_option {
+ // // TODO: This might not be the correct PE when there are multiple PEs with the same
+ // // TypeID.
+ // match device.acquire_pe(*pe.type_id()) {
+ // Ok(mut pe) => {
+ // trace!("Acquired PE: {:?}", pe);
+ // if let Ok(_) = pe.start(vec![]) {
+ // trace!("Started PE: {:?}", pe);
+ // if let Ok(_) = pe.release(true, true) {
+ // trace!("Starting PE: {:?}", pe);
+ // }
+ // }
+ // },
+ // Err(e) => error!("Could not acquire PE: {}", e),
+ // }
+ // }
+ // }
+ //}
+
+ pub fn get_status_registers(&mut self) -> String {
+ if let Some(pe) = self.get_current_pe() {
+ let (global_interrupt, local_interrupt) = pe.interrupt_status().expect("Expected to get PE interrupt status.");
+ let return_value = pe.return_value();
+
+ // TODO: I have to get these from the runtime because there are no registers for that.
+ //let is_running = false;
+ //let interrupt_pending = false;
+
+ let mut result = String::new();
+ //result += &format!("PE is running: {}", is_running);
+ result += &format!("Local Interrupt Enabled: {}\n", local_interrupt);
+ result += &format!("Global Interrupt Enabled: {}\n", global_interrupt);
+ //result += &format!("Interrupt pending: {}", interrupt_pending);
+ result += &format!("Return: 0x{:16x} (i32: {:10})\n", return_value, return_value as i32);
+
+ result
+ } else {
+ "No PE selected.".to_string()
+ }
+ }
+
+ pub fn get_argument_registers(&mut self) -> Vec {
+ if let Some(pe) = self.get_current_pe() {
+ let argument_registers = (0..self.register_list.items.len())
+ .map(|i| match pe.read_arg(i, 8).expect("Expected to be able to read PE registers!") {
+ PEParameter::Single64(u) => u,
+ _ => unreachable!()
+ })
+ .collect::>();
+
+ let mut result = Vec::new();
+ for (i, a) in argument_registers.iter().enumerate() {
+ result.push(format!("Arg#{:02}: 0x{:16x} ({:20})\n", i, a, a));
+ }
+
+ result
+ } else {
+ vec!["No PE selected.".to_string()]
+ }
+ }
+
+ pub fn dump_current_pe_local_memory(&self) -> Vec {
+ if let Some(pe) = self.get_current_pe() {
+ let local_memory = match pe.local_memory() {
+ Some(m) => m,
+ _ => return vec!["No local memory for this PE.".to_string()],
+ };
+
+ let mut memory_cells: Box<[u8]> = Box::new([0u8; 16*100]);
+ match local_memory.dma().copy_from(0, &mut memory_cells) {
+ Ok(_) => {},
+ _ => return vec!["Could not read PE Local Memory!".to_string()],
+ }
+
+ let mut result: Vec = Vec::new();
+ for (i, s) in memory_cells.chunks_exact(16).enumerate() {
+ // format bytes like hexdump
+ result.push(format!("{:08x}: {}\n", 16 * i,
+ s.iter()
+ .map(|x| format!("{:02x}", x))
+ .collect::>()
+ .join(" ")));
+ }
+
+ result
+ } else {
+ vec!["No PE selected.".to_string()]
+ }
+ }
+ fn parse_interrupts(interrupts: &Vec) -> String {
let mut result = String::new();
- result += &format!(concat!(" PE is running: {}\n Local Interrupt Enabled: {}\n",
- " Global Interrupt Enabled: {}\n Interrupt pending: {}\n\n",
- " Return Value: 0x{:16x}\n\n"),
- is_running, local_interrupt, global_interrupt, interrupt_pending,
- return_value);
- for (i, a) in argument_registers.iter().enumerate() {
- result += &format!(" A#{:02}: 0x{:16x} ({})\n", i, a, a);
+
+ if interrupts.len() == 0 {
+ result += "None";
+ }
+ else {
+ result += "[ ";
+
+ for (index, interrupt) in interrupts.iter().enumerate() {
+ if index > 0 {
+ result += ", ";
+ }
+
+ result += &format!("{}:{}", interrupt.mapping, interrupt.name);
+ }
+
+ result += " ]";
}
result
}
-}
-fn parse_interrupts(interrupts: &Vec) -> String {
- let mut result = String::new();
+ pub fn get_dmaengine_statistics(&self) -> String {
+ let dmaengine_offset = match self.dmaengine_offset {
+ Some(s) => s,
+ _ => return "No DMAEngine found!".to_string(),
+ };
- if interrupts.len() == 0 {
- result += "None";
- }
- else {
- result += "[ ";
+ let status_registers: Vec<(&str, isize)> = vec![
+ ("Number of Read Requests ", 48),
+ ("Number of Write Requests ", 56),
+ ("Cycles since last Read Request ", 64),
+ ("Cycles between Read Requests ", 72),
+ ("Cycles since last Write Request", 88),
+ ("Cycles between Write Requests ", 96),
+ ];
- for (index, interrupt) in interrupts.iter().enumerate() {
- if index > 0 {
- result += ", ";
+ let mut result = String::new();
+ for (index, r) in status_registers.iter().enumerate() {
+ unsafe {
+ // Create a const pointer to the u64 register at the offset in the platform address
+ // space of the DMAEngine
+ let dmaengine_register_ptr = self.platform.as_ptr().offset(dmaengine_offset + r.1) as *const u64;
+ // Read IO register with volatile, see:
+ // https://doc.rust-lang.org/std/ptr/fn.read_volatile.html
+ let dmaengine_register = dmaengine_register_ptr.read_volatile();
+
+ if index < 2 {
+ // Calculating ms doesn't make sense for the number of Reads/Writes
+ result += &format!("{} {:016x} ({:20})\n", r.0, dmaengine_register, dmaengine_register);
+ } else {
+ // Warning: This assumes the host frequency to be 250MHz which should be the case
+ // everywhere.
+ result += &format!("{} {:016x} ({:20} = {:9} ns)\n", r.0, dmaengine_register, dmaengine_register, dmaengine_register * 4);
+ }
}
- result += &format!("{}:{}", interrupt.mapping, interrupt.name);
+ // Add a newline every second line
+ if index % 2 == 1 {
+ result += "\n";
+ }
}
- result += " ]";
+ result
}
-
- result
}
diff --git a/runtime/examples/Rust/tapasco-debug/src/main.rs b/runtime/examples/Rust/tapasco-debug/src/main.rs
index a7009bfb..5f8e2ddf 100644
--- a/runtime/examples/Rust/tapasco-debug/src/main.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/main.rs
@@ -1,14 +1,10 @@
mod app;
-use app::App;
-
mod ui;
-use ui::setup;
use snafu::{ResultExt, Snafu};
#[derive(Debug, Snafu)]
-#[snafu(visibility(pub))]
-pub enum Error {
+enum Error {
#[snafu(display("Failed to initialize TLKM object: {}. Have you loaded the kernel module?", source))]
TLKMInit { source: tapasco::tlkm::Error },
@@ -22,11 +18,38 @@ pub enum Error {
type Result = std::result::Result;
use env_logger;
+use structopt::StructOpt;
+
+/// The interactive TaPaSCo Debugger can be used to retrieve information about the loaded
+/// bitstream, monitor other TaPaSCo runtimes and write values to the registers of your PEs
+#[derive(StructOpt, Debug)]
+#[structopt(rename_all = "kebab-case")]
+struct Opt {
+ /// The Device ID of the FPGA you want to use if you got more than one
+ #[structopt(short = "d", long = "device", default_value = "0")]
+ device_id: u32,
+
+ /// Specify the Access Mode as subcommand
+ #[structopt(subcommand)]
+ pub subcommand: Command,
+}
+#[derive(StructOpt, Debug, PartialEq)]
+pub enum Command {
+ /// Enter Monitor Mode where values cannot be modified, e.g. to monitor another runtime
+ Monitor {},
+ /// Enter Debug Mode where values can only be modified interactively in this debugger
+ Debug {},
+ /// Enter Unsafe Mode where values can be modified by this debugger and another runtime
+ Unsafe {},
+}
fn init() -> Result<()> {
- setup(&mut App::new().context(AppError {})?).context(UIError {})
+ let Opt { device_id, subcommand, } = Opt::from_args();
+ // Specify the Access Mode as subcommand
+ ui::setup(&mut app::App::new(device_id, subcommand).context(AppError {})?).context(UIError {})
}
+
fn main() {
env_logger::init();
diff --git a/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs b/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs
index 19b66fdd..11830bd3 100644
--- a/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs
@@ -18,10 +18,12 @@ use tui::{
use crossterm::{
execute,
- event::{self, EnableMouseCapture, DisableMouseCapture, Event as CEvent, KeyEvent, KeyCode, KeyModifiers},
+ event::{self, Event as CEvent, KeyEvent, KeyCode, KeyModifiers},
terminal::{enable_raw_mode, disable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
+use unicode_width::UnicodeWidthStr;
+
use snafu::{ResultExt, Snafu};
#[derive(Debug, Snafu)]
@@ -34,25 +36,18 @@ pub enum Error {
#[snafu(display("Failed to handle Input event: {}", source))]
HandleInput { source: std::io::Error },
-
- //#[snafu(display("Failed to send Input event!"))]
- //SendInput { source: std::sync::mpsc::SendError },
}
pub type Result = std::result::Result;
-use crate::app::App;
+use crate::app::{App, AccessMode, InputMode, InputFrame};
-// Define Instructions (see key press in event loop for reference)
-//const INSTRUCTIONS: &str = r#"'q' Quit 'r' Peek/Redraw UI"#;
-
// Define an Event which can consist of a pressed key or a Tick which occurs when the UI should be
// updated while no key got pressed
enum Event {
Input(I),
Resize(H, H),
- //Tick, // Maybe update app for Ticks?
}
@@ -62,7 +57,7 @@ pub fn setup(app: &mut App) -> Result<()> {
// Enter the Alternate Screen, so we don't break terminal history (it's like opening vim)
let mut stdout = stdout();
- execute!(stdout, EnterAlternateScreen, EnableMouseCapture).context(CrosstermError {})?;
+ execute!(stdout, EnterAlternateScreen).context(CrosstermError {})?;
// Initialize Crossterm backend
let backend = CrosstermBackend::new(stdout);
@@ -76,7 +71,7 @@ pub fn setup(app: &mut App) -> Result<()> {
// Leave Alternate Screen to shut down cleanly regardless of the result
disable_raw_mode().context(CrosstermError {})?;
- execute!(terminal.backend_mut(), DisableMouseCapture, LeaveAlternateScreen).context(CrosstermError {})?;
+ execute!(terminal.backend_mut(), LeaveAlternateScreen).context(CrosstermError {})?;
terminal.show_cursor().context(CrosstermError {})?;
// Return the result of the main loop after restoring the previous terminal state in order to
@@ -108,40 +103,53 @@ fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) ->
// Handle events
match rx.recv().context(ReceiveInput {})? {
// Match key pressed events
- Event::Input(event) => match event {
- // with Shift modifier
- KeyEvent {
- modifiers: KeyModifiers::SHIFT,
- code,
- } => match code {
- // Press 'Shift+Tab' to switch backward between tabs
- // TODO: This doesn't work! Why?
- KeyCode::Tab => app.previous_tab(),
- _ => {},
- },
- // without any modifiers
- KeyEvent {
- modifiers: KeyModifiers::NONE,
- code,
- } => match code {
- // Press 'q' to quit application
- KeyCode::Char('q') => return Ok(()),
- // Press 'r' to redraw the UI
- KeyCode::Char('r') => continue,
- // Press 'Tab' to switch forward between tabs
- KeyCode::Tab => app.next_tab(),
- // Press ↑ or 'k' to go up in the list of PEs/Registers
- KeyCode::Up | KeyCode::Char('k') => app.on_up(),
- // Press ↓ or 'j' to go down in the list of PEs/Registers
- KeyCode::Down | KeyCode::Char('j') => app.on_down(),
- // Press Escape or 'h' to return back to the list of PEs
- KeyCode::Esc | KeyCode::Char('h') => app.on_escape(),
- // Press Enter or 'l' to select a PE/Register
- KeyCode::Enter | KeyCode::Char('l') => app.on_return(),
- _ => {},
- },
- _ => {},
+ Event::Input(event) => {
+ match app.input_mode {
+ InputMode::Edit => match event.code {
+ KeyCode::Char(c) => app.input.push(c),
+ KeyCode::Backspace => if let None = app.input.pop() { app.input_mode = InputMode::Normal },
+ KeyCode::Enter => app.on_enter(),
+ KeyCode::Esc => app.on_escape(),
+ _ => {}
+ },
+ InputMode::Normal => match event {
+ // with Shift modifier
+ KeyEvent {
+ modifiers: KeyModifiers::SHIFT,
+ code,
+ } => match code {
+ // Press 'Shift+Tab' to switch backward through tabs
+ KeyCode::BackTab => app.previous_tab(),
+ _ => {},
+ },
+ // without any modifiers
+ KeyEvent {
+ modifiers: KeyModifiers::NONE,
+ code,
+ } => match code {
+ // Press 'q' to quit application
+ KeyCode::Char('q') => return Ok(()),
+ // Press 'r' to redraw the UI
+ KeyCode::Char('r') => continue,
+ // Press 'Tab' to switch forward through tabs
+ KeyCode::Tab => app.next_tab(),
+ // Press ↑ or 'k' to go up in the list of PEs/Registers
+ KeyCode::Up | KeyCode::Char('k') => app.on_up(),
+ // Press ↓ or 'j' to go down in the list of PEs/Registers
+ KeyCode::Down | KeyCode::Char('j') => app.on_down(),
+ // Press Escape or 'h' to return back to the list of PEs
+ KeyCode::Esc | KeyCode::Left | KeyCode::Char('h') => app.on_escape(),
+ // Press Enter or 'l' to select a PE/Register
+ KeyCode::Enter | KeyCode::Right | KeyCode::Char('l') => app.on_enter(),
+ // Press 's' on a selected PE to start a job
+ //KeyCode::Char('s') => app.start_current_pe(),
+ _ => {},
+ },
+ _ => {},
+ },
+ }
},
+ // TODO: When opening a new pane in Tmux this app is not redrawn.
Event::Resize(_, _) => continue,
}
}
@@ -153,15 +161,27 @@ fn draw(app: &mut App, terminal: &mut Terminal) -> Result<()> {
// draw itself
let tabs_chunks = Layout::default()
.direction(Direction::Vertical)
- .margin(1)
+ .margin(0)
.constraints(
[
+ Constraint::Length(2),
Constraint::Length(3),
Constraint::Min(0),
].as_ref()
)
.split(f.size());
+ // Render title and general user instructions
+ f.render_widget(
+ Paragraph::new(
+ Spans::from(vec![
+ Span::raw(&app.title),
+ Span::raw(" (q: Quit. "),
+ Span::styled("Remember to quit before reprogramming the FPGA or reloading the kernel module!",
+ Style::default().add_modifier(Modifier::ITALIC)),
+ Span::raw(")"),
+ ])), tabs_chunks[0]);
+
// Map the titles of the Tabs into Spans to be able to highlight the title of the
// selected Tab
let titles = app.tabs.titles
@@ -170,27 +190,24 @@ fn draw(app: &mut App, terminal: &mut Terminal) -> Result<()> {
.collect();
let tabs = Tabs::new(titles)
.block(Block::default()
- .title(Span::styled(app.title,
+ .title(Span::styled("Tabs (Shift+Tab: ←, Tab: →)",
Style::default().add_modifier(Modifier::DIM)))
.border_type(BorderType::Rounded)
.border_style(Style::default().add_modifier(Modifier::DIM))
.borders(Borders::ALL))
.style(Style::default()
.fg(Color::White))
- .highlight_style(
- Style::default()
- .fg(Color::Blue)
- .add_modifier(Modifier::BOLD)
- )
+ .highlight_style(Style::default().add_modifier(Modifier::BOLD))
.divider(DOT)
.select(app.tabs.index);
- f.render_widget(tabs, tabs_chunks[0]);
+ f.render_widget(tabs, tabs_chunks[1]);
// Call the specific draw function for the selected Tab
match app.tabs.index {
- 0 => draw_first_tab(f, app, tabs_chunks[1]),
- 1 => draw_second_tab(f, app, tabs_chunks[1]),
+ 0 => draw_tab_peek_and_poke_pes(f, app, tabs_chunks[2]),
+ 1 => draw_tab_platform_components(f, app, tabs_chunks[2]),
+ 2 => draw_tab_bitstream_and_device_info(f, app, tabs_chunks[2]),
_ => {},
}
}).context(CrosstermError {})?;
@@ -198,132 +215,165 @@ fn draw(app: &mut App, terminal: &mut Terminal) -> Result<()> {
Ok(())
}
-fn draw_first_tab(f: &mut Frame, app: &mut App, chunk: Rect) {
- // Create a vertical layout (top to bottom) first to split the Tab into 3 rows
+fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk: Rect) {
+ // Create a vertical layout (top to bottom) first to split the Tab into 2 rows with a
+ // bottom line for keyboard input that is only shown when in Edit Mode
let vertical_chunks = Layout::default()
.direction(Direction::Vertical)
- .margin(1)
- .constraints(
- [
- Constraint::Percentage(65),
- Constraint::Percentage(30),
+ .margin(0)
+ .constraints(match app.input_mode {
+ InputMode::Edit => [
+ Constraint::Length(15),
+ Constraint::Min(30),
Constraint::Length(3),
- ].as_ref()
- )
+ ].as_ref(),
+ _ => [
+ Constraint::Length(15),
+ Constraint::Min(30),
+ ].as_ref(),
+ })
.split(chunk);
- // Split the first row into half (okay golden ratio) vertically again
- let inner_vertical_chunks = Layout::default()
- //.direction(Direction::Horizontal)
- .direction(Direction::Vertical)
- .margin(0)
- .constraints(
- [
- Constraint::Percentage(35),
- Constraint::Percentage(65),
- ].as_ref()
- )
- .split(vertical_chunks[0]);
-
- // Split the first row's second row into half (okay golden ratio) horizontally
- let first_horizontal_chunks = Layout::default()
+ // Split the second row into half horizontally
+ let horizontal_chunks = Layout::default()
.direction(Direction::Horizontal)
- //.direction(Direction::Vertical)
.margin(0)
.constraints(
[
- Constraint::Percentage(65),
- Constraint::Percentage(35),
+ Constraint::Percentage(50),
+ Constraint::Percentage(50),
].as_ref()
)
- .split(inner_vertical_chunks[1]);
+ .split(vertical_chunks[1]);
+
+ // Draw the PEs as stateful list to be able to select one
+ let pes_title = if (app.access_mode == AccessMode::Monitor {}) {
+ "PE List (j:↓, k:↑)"
+ } else {
+ "PE List (j:↓, k:↑, Enter/l: switch to Register List)"
+ };
+ let pes: Vec = app.pe_infos.items.iter()
+ .map(|i| ListItem::new(vec![Spans::from(Span::raw(i))]))
+ .collect();
+ let pes = List::new(pes)
+ .block(focusable_block(pes_title, app.focus == InputFrame::PEList {}))
+ .highlight_style(Style::default().add_modifier(Modifier::BOLD))
+ .highlight_symbol("> ");
+ f.render_stateful_widget(pes, vertical_chunks[0], &mut app.pe_infos.state);
- let triple_vertical_chunks = Layout::default()
+ // Split the PE's registers into status plus return value and arguments
+ let register_chunks = Layout::default()
.direction(Direction::Vertical)
.margin(0)
.constraints(
[
- Constraint::Percentage(33),
- Constraint::Percentage(33),
- Constraint::Percentage(33),
+ Constraint::Length(5),
+ Constraint::Min(10),
].as_ref()
)
- .split(first_horizontal_chunks[1]);
+ .split(horizontal_chunks[0]);
+
+ // Status registers
+ draw_block_with_paragraph(f, "Status Registers", app.get_status_registers(), register_chunks[0]);
+
+ // Argument Register List (also stateful list for editing)
+ let registers_title = if (app.access_mode == AccessMode::Monitor {}) {
+ "Register List (r: Refresh)"
+ //} else if (app.access_mode == AccessMode::Debug {}) {
+ // "Register List (r: Refresh, Escape: back, j:↓, k:↑, Enter/l: set Register, s: Start PE)"
+ } else {
+ "Register List (r: Refresh, Escape: back, j:↓, k:↑, Enter/l: set Register)"
+ };
+ let registers = app.get_argument_registers();
+ let registers: Vec = registers.iter()
+ .map(|i| ListItem::new(vec![Spans::from(Span::raw(i))]))
+ .collect();
+ let registers = List::new(registers)
+ .block(focusable_block(registers_title, app.focus == InputFrame::RegisterList))
+ .highlight_style(Style::default().add_modifier(Modifier::BOLD))
+ .highlight_symbol("> ");
+ f.render_stateful_widget(registers, register_chunks[1], &mut app.register_list.state);
- // Split the second row into half (okay golden ratio)
- let second_horizontal_chunks = Layout::default()
- .direction(Direction::Horizontal)
+ // Local Memory (also a stateful list for editing TODO?)
+ let local_memory = app.dump_current_pe_local_memory();
+ let local_memory: Vec = local_memory.iter()
+ .map(|i| ListItem::new(vec![Spans::from(Span::raw(i))]))
+ .collect();
+ let local_memory = List::new(local_memory)
+ .block(focusable_block("Local Memory (r: Refresh)", false))
+ .highlight_style(Style::default().add_modifier(Modifier::BOLD))
+ .highlight_symbol("> ");
+ f.render_stateful_widget(local_memory, horizontal_chunks[1], &mut app.local_memory_list.state);
+
+ // Draw an input line if in Edit Mode
+ if app.input_mode == InputMode::Edit {
+ let input = Paragraph::new(app.input.as_ref())
+ .block(Block::default()
+ .borders(Borders::ALL)
+ .border_type(BorderType::Rounded)
+ .title("Input (Escape: abort, Enter: try to parse input as signed decimal i64)")
+ .style(Style::default().fg(Color::Yellow)));
+ let input_chunks = vertical_chunks[2];
+ f.render_widget(input, input_chunks);
+
+ // Make the cursor visible and ask tui-rs to put it at the specified coordinates after rendering
+ f.set_cursor(
+ // Put cursor past the end of the input text
+ input_chunks.x + app.input.width() as u16 + 1,
+ // Move one line down, from the border to the input line
+ input_chunks.y + 1,)
+ }
+}
+
+fn draw_tab_platform_components(f: &mut Frame, app: &App, chunk: Rect) {
+ // Create a vertical layout (top to bottom) first to split the Tab into 2 rows
+ let vertical_chunks = Layout::default()
+ .direction(Direction::Vertical)
.margin(0)
.constraints(
[
- Constraint::Percentage(35),
- Constraint::Percentage(65),
+ Constraint::Min(15),
+ Constraint::Length(10),
].as_ref()
)
- .split(vertical_chunks[1]);
+ .split(chunk);
- // Draw the PEs as stateful list to be able to select one
- let pes: Vec = app.pe_infos.items.iter()
- .map(|i| ListItem::new(vec![Spans::from(Span::raw(i))]))
- .collect();
- let pes = List::new(pes)
- .block(new_dim_block("PE List: ↓,j/↑,k/Enter,l to switch to PE Registers"))
- .highlight_style(Style::default().add_modifier(Modifier::BOLD))
- .highlight_symbol("> ");
- f.render_stateful_widget(pes, inner_vertical_chunks[0], &mut app.pe_infos.state);
-
- draw_block_with_paragraph(f, "Register List: ↓,j/↑,k/Enter,l to set Register",
- app.read_pe_registers(app.pe_infos.state.selected()),
- first_horizontal_chunks[0]);
-
- // Also show info about Local Memory, Debug Cores and Interrupts
- draw_block_with_paragraph(f, "Local Memory",
- "No info about Local Memory yet.",
- triple_vertical_chunks[0]);
- draw_block_with_paragraph(f, "Debug Cores",
- "No info about Debug Cores yet.",
- triple_vertical_chunks[1]);
- draw_block_with_paragraph(f, "Interrupts",
- "No info about Interrupts yet.",
- triple_vertical_chunks[2]);
-
- draw_block_with_paragraph(f, "Bitstream & Device Info", app.get_bitstream_info(), second_horizontal_chunks[0]);
- draw_block_with_paragraph(f, "Platform Components", app.get_platform_info(), second_horizontal_chunks[1]);
-
- // Define Instructions (see key press in event loop for reference)
- let instructions = Spans::from(vec![
- Span::raw(" "),
- Span::styled("q", Style::default().add_modifier(Modifier::BOLD)),
- Span::from(" Quit"),
- Span::raw(" "),
- Span::styled("r", Style::default().add_modifier(Modifier::BOLD)),
- Span::from(" Peek/Redraw"),
- Span::raw(" "),
- Span::styled("Remember to quit before reprogramming the FPGA or reloading the kernel module!",
- Style::default().add_modifier(Modifier::ITALIC)),
- ]);
- draw_block_with_paragraph(f, "Instructions", instructions, vertical_chunks[2]);
+ // Show general info about platform components
+ draw_block_with_paragraph(f, "Overview", app.get_platform_info(), vertical_chunks[0]);
+
+ // and DMAEngine Statistics
+ draw_block_with_paragraph(f, "DMAEngine Statistics (r: Refresh)", app.get_dmaengine_statistics(), vertical_chunks[1]);
}
-fn draw_second_tab(f: &mut Frame, _app: &App, chunk: Rect) {
- draw_block_with_paragraph(f, "Nothing to see here", "This still needs to be implemented.. Sorry!", chunk);
+fn draw_tab_bitstream_and_device_info(f: &mut Frame, app: &App, chunk: Rect) {
+ draw_block_with_paragraph(f, "", app.get_bitstream_info(), chunk);
}
/// Draw a block with some text in it into the rectangular space given by chunk
//fn draw_block_with_paragraph(f: &mut Frame, block_title: &str, paragraph_text: &str, chunk: Rect) {
fn draw_block_with_paragraph<'a, B: Backend, T>(f: &mut Frame, block_title: &str, text: T, chunk: Rect) where Text<'a>: From {
- let block = new_dim_block(block_title);
+ let block = dim_block(block_title);
let paragraph = Paragraph::new(text)
.block(block)
.wrap(Wrap { trim: false });
f.render_widget(paragraph, chunk);
}
-/// Create a new Block with round corners in dim colors and the given title
-fn new_dim_block(title: &str) -> Block {
+/// Create a new Block with round corners and the given title and choose the border style
+fn block_with_border_style(title: &str, style: Modifier) -> Block {
Block::default()
- .title(Span::styled(title, Style::default().add_modifier(Modifier::DIM)))
+ .title(Span::styled(title, Style::default().add_modifier(style)))
.border_type(BorderType::Rounded)
- .border_style(Style::default().add_modifier(Modifier::DIM))
+ .border_style(Style::default().add_modifier(style))
.borders(Borders::ALL)
}
+
+/// Create a new Block with round corners in dim colors and the given title
+fn dim_block(title: &str) -> Block {
+ block_with_border_style(title, Modifier::DIM)
+}
+
+/// Create a new Block with round corners which takes a boolean if it is focused
+fn focusable_block(title: &str, focused: bool) -> Block {
+ block_with_border_style(title, if focused { Modifier::BOLD } else { Modifier::DIM })
+}
From 9aa8082f13092ff82750bf37a3c761bfea103f0f Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:51 +0100
Subject: [PATCH 09/34] Apply clippy lints and ruftfmt
---
.../Rust/tapasco-debug/src/app/mod.rs | 374 ++++++++++--------
.../examples/Rust/tapasco-debug/src/main.rs | 30 +-
.../examples/Rust/tapasco-debug/src/ui/mod.rs | 205 +++++-----
3 files changed, 340 insertions(+), 269 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
index 665c5422..f68509bc 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
@@ -1,18 +1,12 @@
-use std::{
- collections::HashMap,
- sync::Arc,
-};
+use std::{collections::HashMap, sync::Arc};
-use log::{trace, warn, error};
+use log::{error, trace, warn};
use tapasco::{
- tlkm::*,
- device::{
- Device,
- status::Interrupt,
- },
- pe::PE,
device::PEParameter,
+ device::{status::Interrupt, Device},
+ pe::PE,
+ tlkm::TLKM,
};
use chrono::{TimeZone, Utc};
@@ -33,15 +27,19 @@ type Result = std::result::Result;
// Import the Subcommand enum from super module as AccessMode to clarify intent
pub use super::Command as AccessMode;
-
// TODO: It would be nice to see when/how many interrupts were triggered.
+#[derive(Debug, PartialEq)]
+pub enum InputMode {
+ Normal,
+ Edit,
+}
-#[derive(Debug,PartialEq)]
-pub enum InputMode { Normal, Edit }
-
-#[derive(Debug,PartialEq)]
-pub enum InputFrame { PEList, RegisterList }
+#[derive(Debug, PartialEq)]
+pub enum InputFrame {
+ PEList,
+ RegisterList,
+}
pub struct App<'a> {
_tlkm_option: Option,
@@ -69,7 +67,9 @@ impl<'a> App<'a> {
// Get Tapasco Loadable Linux Kernel Module
let tlkm = TLKM::new().context(TLKMInit {})?;
// Allocate the device with the given ID
- let mut tlkm_device = tlkm.device_alloc(device_id, &HashMap::new()).context(TLKMInit {})?;
+ let mut tlkm_device = tlkm
+ .device_alloc(device_id, &HashMap::new())
+ .context(TLKMInit {})?;
// For some access modes we need to take some special care to use them
let access_mode_str = match access_mode {
@@ -78,18 +78,22 @@ impl<'a> App<'a> {
// access we implement a monitor mode where registers cannot be modified. For this
// no special access is necessary. This is a no-op.
"Monitor"
- },
+ }
AccessMode::Debug {} => {
// Change device access to exclusive to be able to acquire PEs
- tlkm_device.change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive).context(DeviceInit {})?;
+ tlkm_device
+ .change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive)
+ .context(DeviceInit {})?;
"Debug"
- },
+ }
AccessMode::Unsafe {} => {
// Change device access to exclusive to be able to acquire PEs
- tlkm_device.change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive).context(DeviceInit {})?;
+ tlkm_device
+ .change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive)
+ .context(DeviceInit {})?;
warn!("Running in Unsafe Mode");
"Unsafe"
- },
+ }
};
trace!("Access Mode is: {}", access_mode_str);
@@ -100,12 +104,24 @@ impl<'a> App<'a> {
// Initialize UI with focus on the PE list
let focus = InputFrame::PEList;
- let tabs = TabsState::new(vec!["Peek & Poke PEs", "Platform Components", "Bitstream & Device Info"]);
+ let tabs = TabsState::new(vec![
+ "Peek & Poke PEs",
+ "Platform Components",
+ "Bitstream & Device Info",
+ ]);
let title = format!("TaPaSCo Debugger - {} Mode", access_mode_str);
let tlkm_version = tlkm.version().context(TLKMInit {})?;
- let platform_base = tlkm_device.status().platform_base.clone().expect("Could not get platform_base!");
- let arch_base = tlkm_device.status().arch_base.clone().expect("Could not get arch_base!");
+ let platform_base = tlkm_device
+ .status()
+ .platform_base
+ .clone()
+ .expect("Could not get platform_base!");
+ let arch_base = tlkm_device
+ .status()
+ .arch_base
+ .clone()
+ .expect("Could not get arch_base!");
let platform = tlkm_device.platform().clone();
// Hold the TLKM if we are running in Debug mode, so it is not free'd after this method
@@ -122,14 +138,16 @@ impl<'a> App<'a> {
for (index, pe) in tlkm_device.status().pe.iter().enumerate() {
// Calculate the "real" address using arch base address plus PE offset
- let address = &arch_base.base + pe.offset;
+ let address = arch_base.base + pe.offset;
pe_infos.push(
format!("Slot {}: {} (ID: {}) Address: 0x{:016x} ({}), Size: 0x{:x} ({} Bytes), Interrupts: {}, Debug: {:?}",
index, pe.name, pe.id, address, address, pe.size, pe.size, App::parse_interrupts(&pe.interrupts), pe.debug));
// Acquire the PE to be able to show its registers etc.
// Warning: casting to usize can panic! On a <32-bit system..
- let pe = tlkm_device.acquire_pe_without_job(pe.id as usize).context(DeviceInit {})?;
+ let pe = tlkm_device
+ .acquire_pe_without_job(pe.id as usize)
+ .context(DeviceInit {})?;
// TODO: There is no way to check that you really got the PE that you wanted
// so I have to use this workaround to set it at the ID of the PE struct which
// confusingly is NOT the pe.id from above which is stored at type_id inside the PE.
@@ -139,10 +157,10 @@ impl<'a> App<'a> {
}
// Preselect the first element if the device's bitstream contains at least one PE
- let pe_infos = if pe_infos.len() > 0 {
- StatefulList::with_items_selected(pe_infos, 0)
- } else {
+ let pe_infos = if pe_infos.is_empty() {
StatefulList::with_items(pe_infos)
+ } else {
+ StatefulList::with_items_selected(pe_infos, 0)
};
// There are theoretically endless registers. 100 seems to be a good value.
@@ -152,38 +170,54 @@ impl<'a> App<'a> {
// Parse bitstream info from the Status core
let mut bitstream_info = String::new();
// TODO: decode vendor and product IDs
- bitstream_info += &format!("Device ID: {} ({}),\nVendor: {}, Product: {},\n\n",
- tlkm_device.id(), tlkm_device.name(), tlkm_device.vendor(), tlkm_device.product());
+ bitstream_info += &format!(
+ "Device ID: {} ({}),\nVendor: {}, Product: {},\n\n",
+ tlkm_device.id(),
+ tlkm_device.name(),
+ tlkm_device.vendor(),
+ tlkm_device.product()
+ );
// Warning: casting to i64 can panic! If the timestamp is bigger than 63 bit..
- bitstream_info += &format!("Bitstream generated at: {} ({})\n\n",
- Utc.timestamp(tlkm_device.status().timestamp as i64, 0).format("%Y-%m-%d"),
- tlkm_device.status().timestamp);
+ bitstream_info += &format!(
+ "Bitstream generated at: {} ({})\n\n",
+ Utc.timestamp(tlkm_device.status().timestamp as i64, 0)
+ .format("%Y-%m-%d"),
+ tlkm_device.status().timestamp
+ );
for v in &tlkm_device.status().versions {
- bitstream_info += &format!("{} Version: {}.{}{}\n",
- v.software, v.year, v.release, v.extra_version);
+ bitstream_info += &format!(
+ "{} Version: {}.{}{}\n",
+ v.software, v.year, v.release, v.extra_version
+ );
}
bitstream_info += &format!("TLKM Version: {}\n\n", tlkm_version);
for c in &tlkm_device.status().clocks {
- bitstream_info += &format!("{} Clock Frequency: {} MHz\n",
- c.name, c.frequency_mhz);
+ bitstream_info += &format!("{} Clock Frequency: {} MHz\n", c.name, c.frequency_mhz);
}
// Parse platform info from the Status core
let mut platform_info = String::new();
let mut dmaengine_offset = None;
- platform_info += &format!("Platform Base: 0x{:012x} (Size: 0x{:x} ({} Bytes))\n\n",
- platform_base.base, platform_base.size, platform_base.size);
+ platform_info += &format!(
+ "Platform Base: 0x{:012x} (Size: 0x{:x} ({} Bytes))\n\n",
+ platform_base.base, platform_base.size, platform_base.size
+ );
for p in &tlkm_device.status().platform {
- let address = &platform_base.base + p.offset;
- platform_info +=
- &format!("{}:\n Address: 0x{:012x} ({}), Size: 0x{:x} ({} Bytes)\n Interrupts: {}\n\n",
- p.name.trim_start_matches("PLATFORM_COMPONENT_"), address, address,
- p.size, p.size, App::parse_interrupts(&p.interrupts));
+ let address = platform_base.base + p.offset;
+ platform_info += &format!(
+ "{}:\n Address: 0x{:012x} ({}), Size: 0x{:x} ({} Bytes)\n Interrupts: {}\n\n",
+ p.name.trim_start_matches("PLATFORM_COMPONENT_"),
+ address,
+ address,
+ p.size,
+ p.size,
+ App::parse_interrupts(&p.interrupts)
+ );
if p.name == "PLATFORM_COMPONENT_DMA0" {
dmaengine_offset = Some(p.offset as isize);
@@ -228,104 +262,92 @@ impl<'a> App<'a> {
}
pub fn on_up(&mut self) {
- match self.tabs.index {
- 0 => {
- match self.focus {
- InputFrame::PEList => self.pe_infos.previous(),
- InputFrame::RegisterList => self.register_list.previous(),
- };
- },
- _ => {},
+ if self.tabs.index == 0 {
+ match self.focus {
+ InputFrame::PEList => self.pe_infos.previous(),
+ InputFrame::RegisterList => self.register_list.previous(),
+ };
};
}
pub fn on_down(&mut self) {
- match self.tabs.index {
- 0 => {
- match self.focus {
- InputFrame::PEList => self.pe_infos.next(),
- InputFrame::RegisterList => self.register_list.next(),
- };
- },
- _ => {},
+ if self.tabs.index == 0 {
+ match self.focus {
+ InputFrame::PEList => self.pe_infos.next(),
+ InputFrame::RegisterList => self.register_list.next(),
+ };
};
}
pub fn on_escape(&mut self) {
- match self.tabs.index {
- 0 => {
- match self.input_mode {
- InputMode::Normal => {
- match self.focus {
- InputFrame::PEList => self.pe_infos.unselect(),
- InputFrame::RegisterList => {
- self.register_list.unselect();
- self.focus = InputFrame::PEList;
- },
- };
- },
- InputMode::Edit => {
- self.input_mode = InputMode::Normal;
- self.input.clear();
- },
- };
- },
- _ => {},
+ if self.tabs.index == 0 {
+ match self.input_mode {
+ InputMode::Normal => {
+ match self.focus {
+ InputFrame::PEList => self.pe_infos.unselect(),
+ InputFrame::RegisterList => {
+ self.register_list.unselect();
+ self.focus = InputFrame::PEList;
+ }
+ };
+ }
+ InputMode::Edit => {
+ self.input_mode = InputMode::Normal;
+ self.input.clear();
+ }
+ };
};
}
pub fn on_enter(&mut self) {
- match self.tabs.index {
- 0 => {
- match self.access_mode {
- AccessMode::Monitor {} => {},
- AccessMode::Debug {} | AccessMode::Unsafe {} => {
- match self.input_mode {
- InputMode::Normal => {
- match self.focus {
- // Change the focused component to the register list of the selected PE
- InputFrame::PEList => match self.pe_infos.state.selected() {
- Some(_) => {
- self.focus = InputFrame::RegisterList;
- self.register_list.next();
- },
- _ => self.pe_infos.next(),
- },
- // Enter Edit Mode for a new register value
- InputFrame::RegisterList => {
- self.input_mode = InputMode::Edit;
- },
- };
- },
- InputMode::Edit => {
- // If the input cannot be parsed correctly, simply do nothing until
- // we either hit Escape or enter a valid decimal integer.
- if let Ok(new_value) = self.input.parse::() {
- self.input.clear();
-
- // Ignore the error because unless the code changes, there will
- // be no error returned by this function.
- if let Err(e) = self.pes
- .get_mut(self.pe_infos.state.selected()
- .expect("There should have been a selected PE. This is a bug."))
- .expect("There should have been a PE for the selection. This is a bug.")
- .1 // ignore the index, select the PE from the tuple
- .set_arg(self.register_list.state.selected().unwrap(),
- PEParameter::Single64(new_value as u64)) {
- // but log this error in case the code changes
- error!("Error setting argument: {}.
- This is probably due to libtapasco having changed something
- important. You should fix this app.", e);
+ if self.tabs.index == 0 {
+ match self.access_mode {
+ AccessMode::Monitor {} => {}
+ AccessMode::Debug {} | AccessMode::Unsafe {} => {
+ match self.input_mode {
+ InputMode::Normal => {
+ match self.focus {
+ // Change the focused component to the register list of the selected PE
+ InputFrame::PEList => match self.pe_infos.state.selected() {
+ Some(_) => {
+ self.focus = InputFrame::RegisterList;
+ self.register_list.next();
}
-
- self.input_mode = InputMode::Normal;
+ _ => self.pe_infos.next(),
+ },
+ // Enter Edit Mode for a new register value
+ InputFrame::RegisterList => {
+ self.input_mode = InputMode::Edit;
}
- },
- };
- },
- };
- },
- _ => {},
+ };
+ }
+ InputMode::Edit => {
+ // If the input cannot be parsed correctly, simply do nothing until
+ // we either hit Escape or enter a valid decimal integer.
+ if let Ok(new_value) = self.input.parse::() {
+ self.input.clear();
+
+ // Ignore the error because unless the code changes, there will
+ // be no error returned by this function.
+ if let Err(e) = self.pes
+ .get_mut(self.pe_infos.state.selected()
+ .expect("There should have been a selected PE. This is a bug."))
+ .expect("There should have been a PE for the selection. This is a bug.")
+ .1 // ignore the index, select the PE from the tuple
+ .set_arg(self.register_list.state.selected().unwrap(),
+ PEParameter::Single64(new_value as u64)) {
+ // but log this error in case the code changes
+ error!("Error setting argument: {}.
+ This is probably due to libtapasco having changed something
+ important. You should fix this app.", e);
+ }
+
+ self.input_mode = InputMode::Normal;
+ }
+ }
+ };
+ }
+ };
};
}
@@ -344,7 +366,9 @@ impl<'a> App<'a> {
};
// Get the PE with the real ID of the selected Slot
- let (_, pe) = self.pes.iter()
+ let (_, pe) = self
+ .pes
+ .iter()
.filter(|(id, _)| *id == pe_slot)
.take(1)
.collect::>()
@@ -381,7 +405,9 @@ impl<'a> App<'a> {
pub fn get_status_registers(&mut self) -> String {
if let Some(pe) = self.get_current_pe() {
- let (global_interrupt, local_interrupt) = pe.interrupt_status().expect("Expected to get PE interrupt status.");
+ let (global_interrupt, local_interrupt) = pe
+ .interrupt_status()
+ .expect("Expected to get PE interrupt status.");
let return_value = pe.return_value();
// TODO: I have to get these from the runtime because there are no registers for that.
@@ -393,7 +419,10 @@ impl<'a> App<'a> {
result += &format!("Local Interrupt Enabled: {}\n", local_interrupt);
result += &format!("Global Interrupt Enabled: {}\n", global_interrupt);
//result += &format!("Interrupt pending: {}", interrupt_pending);
- result += &format!("Return: 0x{:16x} (i32: {:10})\n", return_value, return_value as i32);
+ result += &format!(
+ "Return: 0x{:16x} (i32: {:10})\n",
+ return_value, return_value as i32
+ );
result
} else {
@@ -404,9 +433,14 @@ impl<'a> App<'a> {
pub fn get_argument_registers(&mut self) -> Vec {
if let Some(pe) = self.get_current_pe() {
let argument_registers = (0..self.register_list.items.len())
- .map(|i| match pe.read_arg(i, 8).expect("Expected to be able to read PE registers!") {
- PEParameter::Single64(u) => u,
- _ => unreachable!()
+ .map(|i| {
+ match pe
+ .read_arg(i, 8)
+ .expect("Expected to be able to read PE registers!")
+ {
+ PEParameter::Single64(u) => u,
+ _ => unreachable!(),
+ }
})
.collect::>();
@@ -428,20 +462,23 @@ impl<'a> App<'a> {
_ => return vec!["No local memory for this PE.".to_string()],
};
- let mut memory_cells: Box<[u8]> = Box::new([0u8; 16*100]);
+ let mut memory_cells: Box<[u8]> = Box::new([0_u8; 16 * 100]);
match local_memory.dma().copy_from(0, &mut memory_cells) {
- Ok(_) => {},
+ Ok(_) => {}
_ => return vec!["Could not read PE Local Memory!".to_string()],
}
let mut result: Vec = Vec::new();
for (i, s) in memory_cells.chunks_exact(16).enumerate() {
// format bytes like hexdump
- result.push(format!("{:08x}: {}\n", 16 * i,
- s.iter()
- .map(|x| format!("{:02x}", x))
- .collect::>()
- .join(" ")));
+ result.push(format!(
+ "{:08x}: {}\n",
+ 16 * i,
+ s.iter()
+ .map(|x| format!("{:02x}", x))
+ .collect::>()
+ .join(" ")
+ ));
}
result
@@ -450,13 +487,12 @@ impl<'a> App<'a> {
}
}
- fn parse_interrupts(interrupts: &Vec) -> String {
+ fn parse_interrupts(interrupts: &[Interrupt]) -> String {
let mut result = String::new();
- if interrupts.len() == 0 {
+ if interrupts.is_empty() {
result += "None";
- }
- else {
+ } else {
result += "[ ";
for (index, interrupt) in interrupts.iter().enumerate() {
@@ -493,18 +529,31 @@ impl<'a> App<'a> {
unsafe {
// Create a const pointer to the u64 register at the offset in the platform address
// space of the DMAEngine
- let dmaengine_register_ptr = self.platform.as_ptr().offset(dmaengine_offset + r.1) as *const u64;
+ let dmaengine_register_ptr = self
+ .platform
+ .as_ptr()
+ .offset(dmaengine_offset + r.1)
+ .cast::();
// Read IO register with volatile, see:
// https://doc.rust-lang.org/std/ptr/fn.read_volatile.html
let dmaengine_register = dmaengine_register_ptr.read_volatile();
if index < 2 {
// Calculating ms doesn't make sense for the number of Reads/Writes
- result += &format!("{} {:016x} ({:20})\n", r.0, dmaengine_register, dmaengine_register);
+ result += &format!(
+ "{} {:016x} ({:20})\n",
+ r.0, dmaengine_register, dmaengine_register
+ );
} else {
// Warning: This assumes the host frequency to be 250MHz which should be the case
// everywhere.
- result += &format!("{} {:016x} ({:20} = {:9} ns)\n", r.0, dmaengine_register, dmaengine_register, dmaengine_register * 4);
+ result += &format!(
+ "{} {:016x} ({:20} = {:9} ns)\n",
+ r.0,
+ dmaengine_register,
+ dmaengine_register,
+ dmaengine_register * 4
+ );
}
}
@@ -518,7 +567,6 @@ impl<'a> App<'a> {
}
}
-
// The following code is taken from libtui-rs demo:
// https://github.com/fdehau/tui-rs/blob/v0.15.0/examples/util/mod.rs
// licensed under MIT License by Florian Dehau, see:
@@ -530,10 +578,7 @@ pub struct TabsState<'a> {
impl<'a> TabsState<'a> {
pub fn new(titles: Vec<&'a str>) -> TabsState {
- TabsState {
- titles,
- index: 0,
- }
+ TabsState { titles, index: 0 }
}
pub fn next(&mut self) {
@@ -549,7 +594,6 @@ impl<'a> TabsState<'a> {
}
}
-
use tui::widgets::ListState;
pub struct StatefulList {
@@ -558,22 +602,22 @@ pub struct StatefulList {
}
impl StatefulList {
- pub fn new() -> StatefulList {
- StatefulList {
+ pub fn new() -> Self {
+ Self {
state: ListState::default(),
items: Vec::new(),
}
}
- pub fn with_items(items: Vec) -> StatefulList {
- StatefulList {
+ pub fn with_items(items: Vec) -> Self {
+ Self {
state: ListState::default(),
items,
}
}
- pub fn with_items_selected(items: Vec, selected: usize) -> StatefulList {
- let mut list = StatefulList {
+ pub fn with_items_selected(items: Vec, selected: usize) -> Self {
+ let mut list = Self {
state: ListState::default(),
items,
};
@@ -590,7 +634,7 @@ impl StatefulList {
} else {
m + 1
}
- },
+ }
None => 0,
};
@@ -605,7 +649,7 @@ impl StatefulList {
} else {
m - 1
}
- },
+ }
None => self.items.len() - 1,
};
diff --git a/runtime/examples/Rust/tapasco-debug/src/main.rs b/runtime/examples/Rust/tapasco-debug/src/main.rs
index 5f8e2ddf..b66fc902 100644
--- a/runtime/examples/Rust/tapasco-debug/src/main.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/main.rs
@@ -5,23 +5,28 @@ use snafu::{ResultExt, Snafu};
#[derive(Debug, Snafu)]
enum Error {
- #[snafu(display("Failed to initialize TLKM object: {}. Have you loaded the kernel module?", source))]
+ #[snafu(display(
+ "Failed to initialize TLKM object: {}. Have you loaded the kernel module?",
+ source
+ ))]
TLKMInit { source: tapasco::tlkm::Error },
- #[snafu(display("Failed to initialize App: {}. Have you loaded the kernel module?", source))]
- AppError { source: app::Error },
+ #[snafu(display(
+ "Failed to initialize App: {}. Have you loaded the kernel module?",
+ source
+ ))]
+ App { source: app::Error },
#[snafu(display("Failed to initialize UI: {}. Have you checked your Terminal?", source))]
- UIError { source: ui::Error },
+ UI { source: ui::Error },
}
type Result = std::result::Result;
-use env_logger;
use structopt::StructOpt;
-/// The interactive TaPaSCo Debugger can be used to retrieve information about the loaded
-/// bitstream, monitor other TaPaSCo runtimes and write values to the registers of your PEs
+/// The interactive `TaPaSCo` Debugger can be used to retrieve information about the loaded
+/// bitstream, monitor other `TaPaSCo` runtimes and write values to the registers of your PEs
#[derive(StructOpt, Debug)]
#[structopt(rename_all = "kebab-case")]
struct Opt {
@@ -45,21 +50,24 @@ pub enum Command {
}
fn init() -> Result<()> {
- let Opt { device_id, subcommand, } = Opt::from_args();
+ let Opt {
+ device_id,
+ subcommand,
+ } = Opt::from_args();
// Specify the Access Mode as subcommand
- ui::setup(&mut app::App::new(device_id, subcommand).context(AppError {})?).context(UIError {})
+ ui::setup(&mut app::App::new(device_id, subcommand).context(App {})?).context(UI {})
}
fn main() {
env_logger::init();
match init() {
- Ok(_) => {},
+ Ok(_) => {}
Err(e) => {
eprintln!("An error occurred: {}", e);
if let Some(backtrace) = snafu::ErrorCompat::backtrace(&e) {
println!("{}", backtrace);
}
- },
+ }
};
}
diff --git a/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs b/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs
index 11830bd3..9ca064e8 100644
--- a/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs
@@ -1,25 +1,19 @@
-use std::{
- io::stdout,
- sync::mpsc,
- thread,
- time::Duration,
-};
+use std::{io::stdout, sync::mpsc, thread, time::Duration};
use tui::{
- Terminal,
- Frame,
backend::{Backend, CrosstermBackend},
- widgets::{Tabs, Block, Borders, Paragraph, Wrap, BorderType, ListItem, List},
- layout::{Layout, Constraint, Direction, Rect},
- text::{Span, Spans, Text},
- style::{Style, Color, Modifier},
+ layout::{Constraint, Direction, Layout, Rect},
+ style::{Color, Modifier, Style},
symbols::DOT,
+ text::{Span, Spans, Text},
+ widgets::{Block, BorderType, Borders, List, ListItem, Paragraph, Tabs, Wrap},
+ Frame, Terminal,
};
use crossterm::{
+ event::{self, Event as CEvent, KeyCode, KeyEvent, KeyModifiers},
execute,
- event::{self, Event as CEvent, KeyEvent, KeyCode, KeyModifiers},
- terminal::{enable_raw_mode, disable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
+ terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use unicode_width::UnicodeWidthStr;
@@ -29,7 +23,7 @@ use snafu::{ResultExt, Snafu};
#[derive(Debug, Snafu)]
pub enum Error {
#[snafu(display("Failure in Crossterm Terminal Backend: {}", source))]
- CrosstermError { source: std::io::Error },
+ Crossterm { source: std::io::Error },
#[snafu(display("Failed to receive Input event: {}", source))]
ReceiveInput { source: std::sync::mpsc::RecvError },
@@ -40,8 +34,7 @@ pub enum Error {
pub type Result = std::result::Result;
-use crate::app::{App, AccessMode, InputMode, InputFrame};
-
+use crate::app::{AccessMode, App, InputFrame, InputMode};
// Define an Event which can consist of a pressed key or a Tick which occurs when the UI should be
// updated while no key got pressed
@@ -50,29 +43,28 @@ enum Event {
Resize(H, H),
}
-
pub fn setup(app: &mut App) -> Result<()> {
// Raw mode disables some common terminal functions that are unnecessary in the TUI environment
- enable_raw_mode().context(CrosstermError {})?;
+ enable_raw_mode().context(Crossterm {})?;
// Enter the Alternate Screen, so we don't break terminal history (it's like opening vim)
let mut stdout = stdout();
- execute!(stdout, EnterAlternateScreen).context(CrosstermError {})?;
+ execute!(stdout, EnterAlternateScreen).context(Crossterm {})?;
// Initialize Crossterm backend
let backend = CrosstermBackend::new(stdout);
- let mut terminal = Terminal::new(backend).context(CrosstermError {})?;
+ let mut terminal = Terminal::new(backend).context(Crossterm {})?;
// Clear the Alternate Screen if someone left it dirty
- terminal.clear().context(CrosstermError {})?;
+ terminal.clear().context(Crossterm {})?;
// Save the result of the main loop to return it after tearing down the backend
let result = run_event_loop(app, &mut terminal);
// Leave Alternate Screen to shut down cleanly regardless of the result
- disable_raw_mode().context(CrosstermError {})?;
- execute!(terminal.backend_mut(), LeaveAlternateScreen).context(CrosstermError {})?;
- terminal.show_cursor().context(CrosstermError {})?;
+ disable_raw_mode().context(Crossterm {})?;
+ execute!(terminal.backend_mut(), LeaveAlternateScreen).context(Crossterm {})?;
+ terminal.show_cursor().context(Crossterm {})?;
// Return the result of the main loop after restoring the previous terminal state in order to
// not be stuck in the Alternate Screen / or Raw Mode which would make a `reset` of the shell
@@ -83,14 +75,19 @@ pub fn setup(app: &mut App) -> Result<()> {
fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) -> Result<()> {
// Setup input handling as in the crossterm demo with a multi producer single consumer (mpsc) channel
let (tx, rx) = mpsc::channel();
- thread::spawn(move || {
- loop {
- if event::poll(Duration::from_millis(250)).expect("Event loop: could not poll for events!") {
- if let CEvent::Key(key) = event::read().expect("Event loop: could not read a key event!") {
- tx.send(Event::Input(key)).expect("Event loop: could not send an input event!");
- } else if let CEvent::Resize(w, h) = event::read().expect("Event loop: could not read a resize event!") {
- tx.send(Event::Resize(w, h)).expect("Event loop: could not send a resize event!");
- }
+ thread::spawn(move || loop {
+ if event::poll(Duration::from_millis(250)).expect("Event loop: could not poll for events!")
+ {
+ if let CEvent::Key(key) =
+ event::read().expect("Event loop: could not read a key event!")
+ {
+ tx.send(Event::Input(key))
+ .expect("Event loop: could not send an input event!");
+ } else if let CEvent::Resize(w, h) =
+ event::read().expect("Event loop: could not read a resize event!")
+ {
+ tx.send(Event::Resize(w, h))
+ .expect("Event loop: could not send a resize event!");
}
}
});
@@ -107,21 +104,21 @@ fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) ->
match app.input_mode {
InputMode::Edit => match event.code {
KeyCode::Char(c) => app.input.push(c),
- KeyCode::Backspace => if let None = app.input.pop() { app.input_mode = InputMode::Normal },
+ KeyCode::Backspace => {
+ if app.input.pop().is_none() {
+ app.input_mode = InputMode::Normal;
+ }
+ }
KeyCode::Enter => app.on_enter(),
KeyCode::Esc => app.on_escape(),
_ => {}
},
InputMode::Normal => match event {
- // with Shift modifier
+ // Press 'Shift+Tab' to switch backward through tabs
KeyEvent {
modifiers: KeyModifiers::SHIFT,
- code,
- } => match code {
- // Press 'Shift+Tab' to switch backward through tabs
- KeyCode::BackTab => app.previous_tab(),
- _ => {},
- },
+ code: KeyCode::BackTab,
+ } => app.previous_tab(),
// without any modifiers
KeyEvent {
modifiers: KeyModifiers::NONE,
@@ -143,12 +140,12 @@ fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) ->
KeyCode::Enter | KeyCode::Right | KeyCode::Char('l') => app.on_enter(),
// Press 's' on a selected PE to start a job
//KeyCode::Char('s') => app.start_current_pe(),
- _ => {},
+ _ => {}
},
- _ => {},
+ _ => {}
},
}
- },
+ }
// TODO: When opening a new pane in Tmux this app is not redrawn.
Event::Resize(_, _) => continue,
}
@@ -190,7 +187,7 @@ fn draw(app: &mut App, terminal: &mut Terminal) -> Result<()> {
.collect();
let tabs = Tabs::new(titles)
.block(Block::default()
- .title(Span::styled("Tabs (Shift+Tab: ←, Tab: →)",
+ .title(Span::styled("Tabs (Shift+Tab: \u{2190}, Tab: \u{2192})",
Style::default().add_modifier(Modifier::DIM)))
.border_type(BorderType::Rounded)
.border_style(Style::default().add_modifier(Modifier::DIM))
@@ -210,7 +207,7 @@ fn draw(app: &mut App, terminal: &mut Terminal) -> Result<()> {
2 => draw_tab_bitstream_and_device_info(f, app, tabs_chunks[2]),
_ => {},
}
- }).context(CrosstermError {})?;
+ }).context(Crossterm {})?;
Ok(())
}
@@ -226,11 +223,9 @@ fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk
Constraint::Length(15),
Constraint::Min(30),
Constraint::Length(3),
- ].as_ref(),
- _ => [
- Constraint::Length(15),
- Constraint::Min(30),
- ].as_ref(),
+ ]
+ .as_ref(),
+ InputMode::Normal => [Constraint::Length(15), Constraint::Min(30)].as_ref(),
})
.split(chunk);
@@ -238,25 +233,26 @@ fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk
let horizontal_chunks = Layout::default()
.direction(Direction::Horizontal)
.margin(0)
- .constraints(
- [
- Constraint::Percentage(50),
- Constraint::Percentage(50),
- ].as_ref()
- )
+ .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
.split(vertical_chunks[1]);
// Draw the PEs as stateful list to be able to select one
let pes_title = if (app.access_mode == AccessMode::Monitor {}) {
- "PE List (j:↓, k:↑)"
+ "PE List (j:\u{2193}, k:\u{2191})"
} else {
- "PE List (j:↓, k:↑, Enter/l: switch to Register List)"
+ "PE List (j:\u{2193}, k:\u{2191}, Enter/l: switch to Register List)"
};
- let pes: Vec = app.pe_infos.items.iter()
+ let pes: Vec = app
+ .pe_infos
+ .items
+ .iter()
.map(|i| ListItem::new(vec![Spans::from(Span::raw(i))]))
.collect();
let pes = List::new(pes)
- .block(focusable_block(pes_title, app.focus == InputFrame::PEList {}))
+ .block(focusable_block(
+ pes_title,
+ app.focus == InputFrame::PEList {},
+ ))
.highlight_style(Style::default().add_modifier(Modifier::BOLD))
.highlight_symbol("> ");
f.render_stateful_widget(pes, vertical_chunks[0], &mut app.pe_infos.state);
@@ -265,54 +261,64 @@ fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk
let register_chunks = Layout::default()
.direction(Direction::Vertical)
.margin(0)
- .constraints(
- [
- Constraint::Length(5),
- Constraint::Min(10),
- ].as_ref()
- )
+ .constraints([Constraint::Length(5), Constraint::Min(10)].as_ref())
.split(horizontal_chunks[0]);
// Status registers
- draw_block_with_paragraph(f, "Status Registers", app.get_status_registers(), register_chunks[0]);
+ draw_block_with_paragraph(
+ f,
+ "Status Registers",
+ app.get_status_registers(),
+ register_chunks[0],
+ );
// Argument Register List (also stateful list for editing)
let registers_title = if (app.access_mode == AccessMode::Monitor {}) {
"Register List (r: Refresh)"
//} else if (app.access_mode == AccessMode::Debug {}) {
- // "Register List (r: Refresh, Escape: back, j:↓, k:↑, Enter/l: set Register, s: Start PE)"
+ // "Register List (r: Refresh, Escape: back, j:\u{2193}, k:\u{2191}, Enter/l: set Register, s: Start PE)"
} else {
- "Register List (r: Refresh, Escape: back, j:↓, k:↑, Enter/l: set Register)"
+ "Register List (r: Refresh, Escape: back, j:\u{2193}, k:\u{2191}, Enter/l: set Register)"
};
let registers = app.get_argument_registers();
- let registers: Vec = registers.iter()
+ let registers: Vec = registers
+ .iter()
.map(|i| ListItem::new(vec![Spans::from(Span::raw(i))]))
.collect();
let registers = List::new(registers)
- .block(focusable_block(registers_title, app.focus == InputFrame::RegisterList))
+ .block(focusable_block(
+ registers_title,
+ app.focus == InputFrame::RegisterList,
+ ))
.highlight_style(Style::default().add_modifier(Modifier::BOLD))
.highlight_symbol("> ");
f.render_stateful_widget(registers, register_chunks[1], &mut app.register_list.state);
// Local Memory (also a stateful list for editing TODO?)
let local_memory = app.dump_current_pe_local_memory();
- let local_memory: Vec = local_memory.iter()
+ let local_memory: Vec = local_memory
+ .iter()
.map(|i| ListItem::new(vec![Spans::from(Span::raw(i))]))
.collect();
let local_memory = List::new(local_memory)
.block(focusable_block("Local Memory (r: Refresh)", false))
.highlight_style(Style::default().add_modifier(Modifier::BOLD))
.highlight_symbol("> ");
- f.render_stateful_widget(local_memory, horizontal_chunks[1], &mut app.local_memory_list.state);
+ f.render_stateful_widget(
+ local_memory,
+ horizontal_chunks[1],
+ &mut app.local_memory_list.state,
+ );
// Draw an input line if in Edit Mode
if app.input_mode == InputMode::Edit {
- let input = Paragraph::new(app.input.as_ref())
- .block(Block::default()
- .borders(Borders::ALL)
- .border_type(BorderType::Rounded)
- .title("Input (Escape: abort, Enter: try to parse input as signed decimal i64)")
- .style(Style::default().fg(Color::Yellow)));
+ let input = Paragraph::new(app.input.as_ref()).block(
+ Block::default()
+ .borders(Borders::ALL)
+ .border_type(BorderType::Rounded)
+ .title("Input (Escape: abort, Enter: try to parse input as signed decimal i64)")
+ .style(Style::default().fg(Color::Yellow)),
+ );
let input_chunks = vertical_chunks[2];
f.render_widget(input, input_chunks);
@@ -321,7 +327,8 @@ fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk
// Put cursor past the end of the input text
input_chunks.x + app.input.width() as u16 + 1,
// Move one line down, from the border to the input line
- input_chunks.y + 1,)
+ input_chunks.y + 1,
+ );
}
}
@@ -330,19 +337,19 @@ fn draw_tab_platform_components(f: &mut Frame, app: &App, chunk:
let vertical_chunks = Layout::default()
.direction(Direction::Vertical)
.margin(0)
- .constraints(
- [
- Constraint::Min(15),
- Constraint::Length(10),
- ].as_ref()
- )
+ .constraints([Constraint::Min(15), Constraint::Length(10)].as_ref())
.split(chunk);
// Show general info about platform components
draw_block_with_paragraph(f, "Overview", app.get_platform_info(), vertical_chunks[0]);
// and DMAEngine Statistics
- draw_block_with_paragraph(f, "DMAEngine Statistics (r: Refresh)", app.get_dmaengine_statistics(), vertical_chunks[1]);
+ draw_block_with_paragraph(
+ f,
+ "DMAEngine Statistics (r: Refresh)",
+ app.get_dmaengine_statistics(),
+ vertical_chunks[1],
+ );
}
fn draw_tab_bitstream_and_device_info(f: &mut Frame, app: &App, chunk: Rect) {
@@ -351,11 +358,16 @@ fn draw_tab_bitstream_and_device_info(f: &mut Frame, app: &App, c
/// Draw a block with some text in it into the rectangular space given by chunk
//fn draw_block_with_paragraph(f: &mut Frame, block_title: &str, paragraph_text: &str, chunk: Rect) {
-fn draw_block_with_paragraph<'a, B: Backend, T>(f: &mut Frame, block_title: &str, text: T, chunk: Rect) where Text<'a>: From {
+fn draw_block_with_paragraph<'a, B: Backend, T>(
+ f: &mut Frame,
+ block_title: &str,
+ text: T,
+ chunk: Rect,
+) where
+ Text<'a>: From,
+{
let block = dim_block(block_title);
- let paragraph = Paragraph::new(text)
- .block(block)
- .wrap(Wrap { trim: false });
+ let paragraph = Paragraph::new(text).block(block).wrap(Wrap { trim: false });
f.render_widget(paragraph, chunk);
}
@@ -375,5 +387,12 @@ fn dim_block(title: &str) -> Block {
/// Create a new Block with round corners which takes a boolean if it is focused
fn focusable_block(title: &str, focused: bool) -> Block {
- block_with_border_style(title, if focused { Modifier::BOLD } else { Modifier::DIM })
+ block_with_border_style(
+ title,
+ if focused {
+ Modifier::BOLD
+ } else {
+ Modifier::DIM
+ },
+ )
}
From a26a6bc7474a3e8c361d8d455ab97cc648ff1c73 Mon Sep 17 00:00:00 2001
From: Jaco Hofmann
Date: Mon, 14 Mar 2022 17:53:52 +0100
Subject: [PATCH 10/34] Adds the option to treat a platform component as PE
- Adds unsafe method to directly access platform component memory
- Simplifies usage of platform components with interrupts
if they follow the TaPaSCo PE conventions
- NOTE: Does not return a Job as most operations such as memory
copy does not make sense for most platform components
---
.gitignore | 2 +
runtime/libtapasco/src/device.rs | 108 +++++++++++++++++++++++++++++--
2 files changed, 106 insertions(+), 4 deletions(-)
diff --git a/.gitignore b/.gitignore
index 412648eb..7f28aaaf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,3 +63,5 @@ Cargo.lock
*.sublime-project
*.sublime-workspace
+
+.vscode/
diff --git a/runtime/libtapasco/src/device.rs b/runtime/libtapasco/src/device.rs
index c324ed23..d3312532 100644
--- a/runtime/libtapasco/src/device.rs
+++ b/runtime/libtapasco/src/device.rs
@@ -19,11 +19,12 @@
*/
use crate::allocator::{Allocator, DriverAllocator, DummyAllocator, GenericAllocator, VfioAllocator};
-use crate::debug::DebugGenerator;
+use crate::debug::DebugGenerator, NonDebugGenerator};
use crate::dma::{DMAControl, DirectDMA, DriverDMA, VfioDMA, SVMDMA};
use crate::dma_user_space::UserSpaceDMA;
use crate::job::Job;
-use crate::pe::{PE, PEId};
+use crate::pe::PEId;
+use crate::pe::PE;
use crate::scheduler::Scheduler;
use crate::tlkm::{tlkm_access, tlkm_ioctl_svm_launch, tlkm_svm_init_cmd};
use crate::tlkm::tlkm_ioctl_create;
@@ -106,6 +107,21 @@ pub enum Error {
#[snafu(display("Could not launch SVM support in the TLKM"))]
SVMInitError { source: nix::Error },
+
+ #[snafu(display("Could not find component {}.", name))]
+ ComponentNotFound { name: String },
+
+ #[snafu(display(
+ "Component {} has no associated interrupt. Cannot be used as PE.",
+ name
+ ))]
+ MissingInterrupt { name: String },
+
+ #[snafu(display("PE Error: {}", source))]
+ PEError { source: crate::pe::Error },
+
+ #[snafu(display("Debug Error: {}", source))]
+ DebugError { source: crate::debug::Error },
}
type Result = std::result::Result;
@@ -505,9 +521,15 @@ impl Device {
/// * id: The ID of the desired PE.
///
pub fn acquire_pe_without_job(&self, id: PEId) -> Result {
- trace!("Trying to acquire PE of type {} without exclusive access.", id);
+ trace!(
+ "Trying to acquire PE of type {} without exclusive access.",
+ id
+ );
let pe = self.scheduler.acquire_pe(id).context(SchedulerError)?;
- trace!("Successfully acquired PE of type {} without exclusive access.", id);
+ trace!(
+ "Successfully acquired PE of type {} without exclusive access.",
+ id
+ );
Ok(pe)
}
@@ -638,4 +660,82 @@ impl Device {
pub fn get_pe_id(&self, name: &str) -> Result {
self.scheduler.get_pe_id(name).context(SchedulerError)
}
+
+ /// Get a list of platform components names available on this device
+ pub fn get_available_platform_components(&self) -> Vec {
+ let mut platform_components = Vec::new();
+
+ for p in &self.status.platform {
+ trace!("Found platform component {}.", p.name);
+ platform_components.push(p.name.clone());
+ }
+
+ platform_components
+ }
+
+ /// Get memory of a platform component
+ /// Treated unsafe as a user can change anything about the memory without any checks
+ /// and might try using the memory after the device has been released.
+ pub unsafe fn get_platform_component_memory(&self, name: &str) -> Result<&mut [u8]> {
+ for p in &self.status.platform {
+ if p.name == name {
+ trace!(
+ "Found platform component {} at {:X} (Size {}).",
+ p.name,
+ p.offset,
+ p.size
+ );
+
+ let ptr = self.platform.as_ptr().offset(p.offset as isize) as *mut u8;
+ let s = std::slice::from_raw_parts_mut(ptr, p.size as usize);
+ return Ok(s);
+ }
+ }
+ Err(Error::ComponentNotFound {
+ name: name.to_string(),
+ })
+ }
+
+ /// Returns a PE interface to the platform component
+ /// Can be used like any other PE but is not integrated
+ /// into the scheduling and job mechanisms
+ pub fn get_platform_component_as_pe(&self, name: &str) -> Result {
+ for p in &self.status.platform {
+ if p.name == name {
+ trace!(
+ "Found platform component {} at {:X} (Size {}).",
+ p.name,
+ p.offset,
+ p.size
+ );
+
+ let d = NonDebugGenerator {};
+ let debug = d
+ .new(&self.platform, "Unused".to_string(), 0, 0)
+ .context(DebugError)?;
+
+ if p.interrupts.len() > 0 {
+ return Ok(PE::new(
+ 42,
+ 42 as PEId,
+ p.offset,
+ p.size,
+ p.name.to_string(),
+ self.platform.clone(),
+ &self.tlkm_device_file,
+ p.interrupts[0].mapping as usize,
+ debug,
+ )
+ .context(PEError)?);
+ } else {
+ return Err(Error::MissingInterrupt {
+ name: name.to_string(),
+ });
+ }
+ }
+ }
+ Err(Error::ComponentNotFound {
+ name: name.to_string(),
+ })
+ }
}
From 9024d6f47fdbd4fbcc75a0cad719968efa16ebd0 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:52 +0100
Subject: [PATCH 11/34] Update DMAEngine Statistics to use the new API
from the cherry-picked commit from PR #279:
03d717e9a1f65c1d4a9d8124d7d692229ed5fc3b
This requires the App state to hold the device for the reference which
makes unsafe mode effectively debug mode. But this is not a problem
because debug mode is in reality unsafe mode as long as the exclusive
access is not working correctly.
---
.../Rust/tapasco-debug/src/app/mod.rs | 72 ++++++-------------
1 file changed, 21 insertions(+), 51 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
index f68509bc..844cbbdf 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
@@ -1,4 +1,4 @@
-use std::{collections::HashMap, sync::Arc};
+use std::collections::HashMap;
use log::{error, trace, warn};
@@ -42,12 +42,9 @@ pub enum InputFrame {
}
pub struct App<'a> {
- _tlkm_option: Option,
- _device_option: Option,
+ tlkm_device: Device,
bitstream_info: String,
platform_info: String,
- platform: Arc,
- dmaengine_offset: Option,
pub access_mode: AccessMode,
pub input: String,
pub input_mode: InputMode,
@@ -122,14 +119,6 @@ impl<'a> App<'a> {
.arch_base
.clone()
.expect("Could not get arch_base!");
- let platform = tlkm_device.platform().clone();
-
- // Hold the TLKM if we are running in Debug mode, so it is not free'd after this method
- let _tlkm_option = if (access_mode == AccessMode::Debug {}) {
- Some(tlkm)
- } else {
- None
- };
// Parse info about PEs from the status core
// Preallocate these vectors to set the acquired PE at the right position later
@@ -201,7 +190,6 @@ impl<'a> App<'a> {
// Parse platform info from the Status core
let mut platform_info = String::new();
- let mut dmaengine_offset = None;
platform_info += &format!(
"Platform Base: 0x{:012x} (Size: 0x{:x} ({} Bytes))\n\n",
platform_base.base, platform_base.size, platform_base.size
@@ -218,28 +206,14 @@ impl<'a> App<'a> {
p.size,
App::parse_interrupts(&p.interrupts)
);
-
- if p.name == "PLATFORM_COMPONENT_DMA0" {
- dmaengine_offset = Some(p.offset as isize);
- }
}
- // Hold the TLKM Device if we are running in Debug mode, so it is not free'd after this method
- let _device_option = if (access_mode == AccessMode::Debug {}) {
- Some(tlkm_device)
- } else {
- None
- };
-
trace!("Constructed App");
Ok(App {
- _tlkm_option,
- _device_option,
+ tlkm_device,
bitstream_info,
platform_info,
- platform,
- dmaengine_offset,
access_mode,
input,
input_mode,
@@ -384,21 +358,19 @@ impl<'a> App<'a> {
// }
// if let Some(pe) = self.get_current_pe() {
- // if let Some(device) = &self._device_option {
- // // TODO: This might not be the correct PE when there are multiple PEs with the same
- // // TypeID.
- // match device.acquire_pe(*pe.type_id()) {
- // Ok(mut pe) => {
- // trace!("Acquired PE: {:?}", pe);
- // if let Ok(_) = pe.start(vec![]) {
- // trace!("Started PE: {:?}", pe);
- // if let Ok(_) = pe.release(true, true) {
- // trace!("Starting PE: {:?}", pe);
- // }
+ // // TODO: This might not be the correct PE when there are multiple PEs with the same
+ // // TypeID.
+ // match self.tlkm_device.acquire_pe(*pe.type_id()) {
+ // Ok(mut pe) => {
+ // trace!("Acquired PE: {:?}", pe);
+ // if let Ok(_) = pe.start(vec![]) {
+ // trace!("Started PE: {:?}", pe);
+ // if let Ok(_) = pe.release(true, true) {
+ // trace!("Starting PE: {:?}", pe);
// }
- // },
- // Err(e) => error!("Could not acquire PE: {}", e),
- // }
+ // }
+ // },
+ // Err(e) => error!("Could not acquire PE: {}", e),
// }
// }
//}
@@ -510,9 +482,11 @@ impl<'a> App<'a> {
}
pub fn get_dmaengine_statistics(&self) -> String {
- let dmaengine_offset = match self.dmaengine_offset {
- Some(s) => s,
- _ => return "No DMAEngine found!".to_string(),
+ let dmaengine_memory = unsafe {
+ match self.tlkm_device.get_platform_component_memory("PLATFORM_COMPONENT_DMA0") {
+ Ok(m) => m,
+ Err(_) => return "No DMAEngine found!".to_string(),
+ }
};
let status_registers: Vec<(&str, isize)> = vec![
@@ -529,11 +503,7 @@ impl<'a> App<'a> {
unsafe {
// Create a const pointer to the u64 register at the offset in the platform address
// space of the DMAEngine
- let dmaengine_register_ptr = self
- .platform
- .as_ptr()
- .offset(dmaengine_offset + r.1)
- .cast::();
+ let dmaengine_register_ptr = dmaengine_memory.as_ptr().offset(r.1).cast::();
// Read IO register with volatile, see:
// https://doc.rust-lang.org/std/ptr/fn.read_volatile.html
let dmaengine_register = dmaengine_register_ptr.read_volatile();
From 6b6ebadfd27712c817b65693bcf6c3ccd9f70e7b Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:53 +0100
Subject: [PATCH 12/34] Remove a cast that can panic
when parsing the timestamp of the bitstream generation.
---
runtime/examples/Rust/tapasco-debug/src/app/mod.rs | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
index 844cbbdf..8320546c 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
@@ -1,4 +1,5 @@
use std::collections::HashMap;
+use std::convert::TryInto;
use log::{error, trace, warn};
@@ -167,11 +168,13 @@ impl<'a> App<'a> {
tlkm_device.product()
);
- // Warning: casting to i64 can panic! If the timestamp is bigger than 63 bit..
bitstream_info += &format!(
"Bitstream generated at: {} ({})\n\n",
- Utc.timestamp(tlkm_device.status().timestamp as i64, 0)
- .format("%Y-%m-%d"),
+ if let Ok(i) = tlkm_device.status().timestamp.try_into() {
+ format!("{}", Utc.timestamp(i, 0).format("%Y-%m-%d"))
+ } else {
+ "the future".to_string()
+ },
tlkm_device.status().timestamp
);
From 2d7ffd9e043b11f6fbd6d1f2793459128bdf2796 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:53 +0100
Subject: [PATCH 13/34] Remove exclusive access from Unsafe Mode
to make it unsafe again.
---
runtime/examples/Rust/tapasco-debug/src/app/mod.rs | 3 ---
1 file changed, 3 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
index 8320546c..47caddae 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app/mod.rs
@@ -86,9 +86,6 @@ impl<'a> App<'a> {
}
AccessMode::Unsafe {} => {
// Change device access to exclusive to be able to acquire PEs
- tlkm_device
- .change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive)
- .context(DeviceInit {})?;
warn!("Running in Unsafe Mode");
"Unsafe"
}
From 335d715ff966f31110864b5a7f042a441bec4fc1 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:53 +0100
Subject: [PATCH 14/34] Simplify `tapasco-debug` directory layout
by removing unnecessary folders.
---
runtime/examples/Rust/tapasco-debug/src/{app/mod.rs => app.rs} | 0
runtime/examples/Rust/tapasco-debug/src/{ui/mod.rs => ui.rs} | 0
2 files changed, 0 insertions(+), 0 deletions(-)
rename runtime/examples/Rust/tapasco-debug/src/{app/mod.rs => app.rs} (100%)
rename runtime/examples/Rust/tapasco-debug/src/{ui/mod.rs => ui.rs} (100%)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app/mod.rs b/runtime/examples/Rust/tapasco-debug/src/app.rs
similarity index 100%
rename from runtime/examples/Rust/tapasco-debug/src/app/mod.rs
rename to runtime/examples/Rust/tapasco-debug/src/app.rs
diff --git a/runtime/examples/Rust/tapasco-debug/src/ui/mod.rs b/runtime/examples/Rust/tapasco-debug/src/ui.rs
similarity index 100%
rename from runtime/examples/Rust/tapasco-debug/src/ui/mod.rs
rename to runtime/examples/Rust/tapasco-debug/src/ui.rs
From 51612127ff96e480f32976894219d40cba2a4187 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:54 +0100
Subject: [PATCH 15/34] Disable debug mode and add comment for Issue #296
Also leave some instructions on how to enable it again.
Debug mode is currently the same as unsafe mode due to libtapasco
not handling this case of access mode.
Additionally, the DMA Buffers, Interrupts, etc. are also allocated in
Monitor Mode which leads to the problem that you have to start your
other runtime twice. For this case I've added a comment in the help
section of `tapasco-debug`.
---
.../examples/Rust/tapasco-debug/src/app.rs | 21 +++++++++++--------
.../examples/Rust/tapasco-debug/src/main.rs | 8 +++++--
2 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app.rs b/runtime/examples/Rust/tapasco-debug/src/app.rs
index 47caddae..b2fd9cd7 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app.rs
@@ -65,7 +65,7 @@ impl<'a> App<'a> {
// Get Tapasco Loadable Linux Kernel Module
let tlkm = TLKM::new().context(TLKMInit {})?;
// Allocate the device with the given ID
- let mut tlkm_device = tlkm
+ let tlkm_device = tlkm
.device_alloc(device_id, &HashMap::new())
.context(TLKMInit {})?;
@@ -77,13 +77,14 @@ impl<'a> App<'a> {
// no special access is necessary. This is a no-op.
"Monitor"
}
- AccessMode::Debug {} => {
- // Change device access to exclusive to be able to acquire PEs
- tlkm_device
- .change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive)
- .context(DeviceInit {})?;
- "Debug"
- }
+ // TODO: 3. When Issue #296 is fixed, enable debug mode here again, too.
+ //AccessMode::Debug {} => {
+ // // Change device access to exclusive to be able to acquire PEs
+ // tlkm_device
+ // .change_access(tapasco::tlkm::tlkm_access::TlkmAccessExclusive)
+ // .context(DeviceInit {})?;
+ // "Debug"
+ //}
AccessMode::Unsafe {} => {
// Change device access to exclusive to be able to acquire PEs
warn!("Running in Unsafe Mode");
@@ -277,7 +278,9 @@ impl<'a> App<'a> {
if self.tabs.index == 0 {
match self.access_mode {
AccessMode::Monitor {} => {}
- AccessMode::Debug {} | AccessMode::Unsafe {} => {
+ // TODO: 4. Replace the second next line with the next line:
+ // AccessMode::Debug {} | AccessMode::Unsafe {} => {
+ AccessMode::Unsafe {} => {
match self.input_mode {
InputMode::Normal => {
match self.focus {
diff --git a/runtime/examples/Rust/tapasco-debug/src/main.rs b/runtime/examples/Rust/tapasco-debug/src/main.rs
index b66fc902..a36a91a2 100644
--- a/runtime/examples/Rust/tapasco-debug/src/main.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/main.rs
@@ -25,8 +25,11 @@ type Result = std::result::Result;
use structopt::StructOpt;
+// TODO: 1. When issue #296 is fixed, remove the paragraph about the `EMFILE` error.
/// The interactive `TaPaSCo` Debugger can be used to retrieve information about the loaded
/// bitstream, monitor other `TaPaSCo` runtimes and write values to the registers of your PEs
+///
+/// Currently due to a `libtapasco` bug where DMA Buffers, Interrupts, etc. are allocated even in monitor mode, you will have to start your other runtime twice, where the first time the `EMFILE` error is to be expected.
#[derive(StructOpt, Debug)]
#[structopt(rename_all = "kebab-case")]
struct Opt {
@@ -43,8 +46,9 @@ struct Opt {
pub enum Command {
/// Enter Monitor Mode where values cannot be modified, e.g. to monitor another runtime
Monitor {},
- /// Enter Debug Mode where values can only be modified interactively in this debugger
- Debug {},
+ // TODO: 2. When issue #296 is fixed, enable debug mode again.
+ // /// Enter Debug Mode where values can only be modified interactively in this debugger
+ // Debug {},
/// Enter Unsafe Mode where values can be modified by this debugger and another runtime
Unsafe {},
}
From 774fdf3dcd11fc3598d299dbde1d33592fc43593 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:54 +0100
Subject: [PATCH 16/34] Update `tapasco-debug` dependencies, add lock file
---
.../examples/Rust/tapasco-debug/Cargo.lock | 1125 +++++++++++++++++
.../examples/Rust/tapasco-debug/Cargo.toml | 18 +-
2 files changed, 1134 insertions(+), 9 deletions(-)
create mode 100644 runtime/examples/Rust/tapasco-debug/Cargo.lock
diff --git a/runtime/examples/Rust/tapasco-debug/Cargo.lock b/runtime/examples/Rust/tapasco-debug/Cargo.lock
new file mode 100644
index 00000000..1ec3d6b8
--- /dev/null
+++ b/runtime/examples/Rust/tapasco-debug/Cargo.lock
@@ -0,0 +1,1125 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
+
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "bytes"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
+
+[[package]]
+name = "cassowary"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
+
+[[package]]
+name = "cbindgen"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51e3973b165dc0f435831a9e426de67e894de532754ff7a3f307c03ee5dec7dc"
+dependencies = [
+ "clap",
+ "heck",
+ "indexmap",
+ "log",
+ "proc-macro2",
+ "quote",
+ "serde 1.0.130",
+ "serde_json",
+ "syn",
+ "tempfile",
+ "toml",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
+dependencies = [
+ "libc",
+ "num-integer",
+ "num-traits 0.2.14",
+ "time",
+ "winapi",
+]
+
+[[package]]
+name = "clap"
+version = "2.33.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
+name = "config"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b1b9d958c2b1368a663f05538fc1b5975adce1e19f435acceae987aceeeb369"
+dependencies = [
+ "lazy_static",
+ "nom",
+ "rust-ini",
+ "serde 1.0.130",
+ "serde-hjson",
+ "serde_json",
+ "toml",
+ "yaml-rust",
+]
+
+[[package]]
+name = "crossbeam"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845"
+dependencies = [
+ "cfg-if",
+ "crossbeam-channel",
+ "crossbeam-deque",
+ "crossbeam-epoch",
+ "crossbeam-queue",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
+dependencies = [
+ "cfg-if",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+ "lazy_static",
+ "memoffset",
+ "scopeguard",
+]
+
+[[package]]
+name = "crossbeam-queue"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
+dependencies = [
+ "cfg-if",
+ "lazy_static",
+]
+
+[[package]]
+name = "crossterm"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ebde6a9dd5e331cd6c6f48253254d117642c31653baa475e394657c59c1f7d"
+dependencies = [
+ "bitflags",
+ "crossterm_winapi",
+ "libc",
+ "mio",
+ "parking_lot",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
+]
+
+[[package]]
+name = "crossterm"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "486d44227f71a1ef39554c0dc47e44b9f4139927c75043312690c3f476d1d788"
+dependencies = [
+ "bitflags",
+ "crossterm_winapi",
+ "libc",
+ "mio",
+ "parking_lot",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
+]
+
+[[package]]
+name = "crossterm_winapi"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a6966607622438301997d3dac0d2f6e9a90c68bb6bc1785ea98456ab93c0507"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "doc-comment"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
+
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "env_logger"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
+dependencies = [
+ "atty",
+ "humantime",
+ "log",
+ "regex",
+ "termcolor",
+]
+
+[[package]]
+name = "fixedbitset"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
+
+[[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "getset"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24b328c01a4d71d2d8173daa93562a73ab0fe85616876f02500f53d82948c504"
+dependencies = [
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "indexmap"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "lexical-core"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
+dependencies = [
+ "arrayvec",
+ "bitflags",
+ "cfg-if",
+ "ryu",
+ "static_assertions",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
+
+[[package]]
+name = "lock_api"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "lockfree"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74ee94b5ad113c7cb98c5a040f783d0952ee4fe100993881d1673c2cb002dd23"
+dependencies = [
+ "owned-alloc",
+]
+
+[[package]]
+name = "log"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "memmap"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "mio"
+version = "0.7.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
+dependencies = [
+ "libc",
+ "log",
+ "miow",
+ "ntapi",
+ "winapi",
+]
+
+[[package]]
+name = "miow"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "multimap"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
+
+[[package]]
+name = "nix"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7555d6c7164cc913be1ce7f95cbecdabda61eb2ccd89008524af306fb7f5031"
+dependencies = [
+ "bitflags",
+ "cc",
+ "cfg-if",
+ "libc",
+ "memoffset",
+]
+
+[[package]]
+name = "nom"
+version = "5.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
+dependencies = [
+ "lexical-core",
+ "memchr",
+ "version_check",
+]
+
+[[package]]
+name = "ntapi"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+dependencies = [
+ "autocfg",
+ "num-traits 0.2.14",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.1.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
+dependencies = [
+ "num-traits 0.2.14",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "owned-alloc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30fceb411f9a12ff9222c5f824026be368ff15dc2f13468d850c7d3f502205d6"
+
+[[package]]
+name = "parking_lot"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
+dependencies = [
+ "instant",
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
+dependencies = [
+ "cfg-if",
+ "instant",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "winapi",
+]
+
+[[package]]
+name = "petgraph"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
+dependencies = [
+ "fixedbitset",
+ "indexmap",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "prost"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020"
+dependencies = [
+ "bytes",
+ "prost-derive",
+]
+
+[[package]]
+name = "prost-build"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603"
+dependencies = [
+ "bytes",
+ "heck",
+ "itertools",
+ "log",
+ "multimap",
+ "petgraph",
+ "prost",
+ "prost-types",
+ "tempfile",
+ "which",
+]
+
+[[package]]
+name = "prost-derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba"
+dependencies = [
+ "anyhow",
+ "itertools",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "prost-types"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b"
+dependencies = [
+ "bytes",
+ "prost",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "rust-ini"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
+
+[[package]]
+name = "ryu"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "serde"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
+
+[[package]]
+name = "serde"
+version = "1.0.130"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde-hjson"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8"
+dependencies = [
+ "lazy_static",
+ "num-traits 0.1.43",
+ "regex",
+ "serde 0.8.23",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.130"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde 1.0.130",
+]
+
+[[package]]
+name = "signal-hook"
+version = "0.3.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-mio"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4"
+dependencies = [
+ "libc",
+ "mio",
+ "signal-hook",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
+
+[[package]]
+name = "snafu"
+version = "0.6.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7"
+dependencies = [
+ "doc-comment",
+ "snafu-derive",
+]
+
+[[package]]
+name = "snafu-derive"
+version = "0.6.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "structopt"
+version = "0.3.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa"
+dependencies = [
+ "clap",
+ "lazy_static",
+ "structopt-derive",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.4.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba"
+dependencies = [
+ "heck",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "tapasco"
+version = "1.0.0"
+dependencies = [
+ "bytes",
+ "cbindgen",
+ "chrono",
+ "config",
+ "crossbeam",
+ "env_logger",
+ "getset",
+ "libc",
+ "lockfree",
+ "log",
+ "memmap",
+ "nix",
+ "prost",
+ "prost-build",
+ "serde 1.0.130",
+ "snafu",
+ "vfio-bindings",
+]
+
+[[package]]
+name = "tapasco-debug"
+version = "0.1.0"
+dependencies = [
+ "chrono",
+ "crossterm 0.21.0",
+ "env_logger",
+ "log",
+ "memmap",
+ "snafu",
+ "structopt",
+ "tapasco",
+ "tui",
+ "unicode-width",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "rand",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "time"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
+dependencies = [
+ "libc",
+ "wasi",
+ "winapi",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
+dependencies = [
+ "serde 1.0.130",
+]
+
+[[package]]
+name = "tui"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39c8ce4e27049eed97cfa363a5048b09d995e209994634a0efc26a14ab6c0c23"
+dependencies = [
+ "bitflags",
+ "cassowary",
+ "crossterm 0.20.0",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "version_check"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+
+[[package]]
+name = "vfio-bindings"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a21f546f2bda37f5a8cfb138c87f95b8e34d2d78d6a7a92ba3785f4e08604a7"
+
+[[package]]
+name = "wasi"
+version = "0.10.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+
+[[package]]
+name = "which"
+version = "4.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9"
+dependencies = [
+ "either",
+ "lazy_static",
+ "libc",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "yaml-rust"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
+dependencies = [
+ "linked-hash-map",
+]
diff --git a/runtime/examples/Rust/tapasco-debug/Cargo.toml b/runtime/examples/Rust/tapasco-debug/Cargo.toml
index f5da7d40..36a458b9 100644
--- a/runtime/examples/Rust/tapasco-debug/Cargo.toml
+++ b/runtime/examples/Rust/tapasco-debug/Cargo.toml
@@ -7,13 +7,13 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-tui = { version = "0.15", default-features = false, features = ['crossterm'] }
-crossterm = "0.20"
+tui = { version = "0.16.0", default-features = false, features = ['crossterm'] }
+crossterm = "0.21.0"
tapasco = { path = "../../../libtapasco" }
-snafu = "0.6"
-chrono = "0.4"
-log = "0.4"
-env_logger = "0.8"
-structopt = "0.3"
-memmap = "0.7"
-unicode-width = "0.1.8"
+snafu = "0.6.10"
+chrono = "0.4.19"
+log = "0.4.14"
+env_logger = "0.9.0"
+structopt = "0.3.23"
+memmap = "0.7.0"
+unicode-width = "0.1.9"
From 19e0d2a0b870979920f13bf2a8178a4ffdcc52e7 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:55 +0100
Subject: [PATCH 17/34] Apply rustfmt again
---
runtime/examples/Rust/tapasco-debug/src/app.rs | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app.rs b/runtime/examples/Rust/tapasco-debug/src/app.rs
index b2fd9cd7..077cfafa 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app.rs
@@ -486,7 +486,10 @@ impl<'a> App<'a> {
pub fn get_dmaengine_statistics(&self) -> String {
let dmaengine_memory = unsafe {
- match self.tlkm_device.get_platform_component_memory("PLATFORM_COMPONENT_DMA0") {
+ match self
+ .tlkm_device
+ .get_platform_component_memory("PLATFORM_COMPONENT_DMA0")
+ {
Ok(m) => m,
Err(_) => return "No DMAEngine found!".to_string(),
}
From 5701fdb5a44aa0046c33b06e1ca9389244449a7e Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:55 +0100
Subject: [PATCH 18/34] Improve input handling to accept hex values
---
runtime/examples/Rust/tapasco-debug/src/app.rs | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app.rs b/runtime/examples/Rust/tapasco-debug/src/app.rs
index 077cfafa..cce57f59 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app.rs
@@ -301,7 +301,17 @@ impl<'a> App<'a> {
InputMode::Edit => {
// If the input cannot be parsed correctly, simply do nothing until
// we either hit Escape or enter a valid decimal integer.
- if let Ok(new_value) = self.input.parse::() {
+ let new_value: Option = if let Some(hex_string) = self.input.strip_prefix("0x") {
+ u64::from_str_radix(hex_string, 16).ok()
+ } else if let Ok(new_value) = self.input.parse::() {
+ Some(new_value)
+ } else if let Ok(new_value) = self.input.parse::() {
+ Some(new_value as u64)
+ } else {
+ None
+ };
+
+ if let Some(new_value) = new_value {
self.input.clear();
// Ignore the error because unless the code changes, there will
@@ -312,7 +322,7 @@ impl<'a> App<'a> {
.expect("There should have been a PE for the selection. This is a bug.")
.1 // ignore the index, select the PE from the tuple
.set_arg(self.register_list.state.selected().unwrap(),
- PEParameter::Single64(new_value as u64)) {
+ PEParameter::Single64(new_value)) {
// but log this error in case the code changes
error!("Error setting argument: {}.
This is probably due to libtapasco having changed something
From 9dcaaafbcc2667116008e7e77eccc4f7f1c81321 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:56 +0100
Subject: [PATCH 19/34] Rename Normal mode to Navigation mode
---
runtime/examples/Rust/tapasco-debug/src/app.rs | 14 +++++++-------
runtime/examples/Rust/tapasco-debug/src/ui.rs | 6 +++---
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app.rs b/runtime/examples/Rust/tapasco-debug/src/app.rs
index cce57f59..a8ac4605 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app.rs
@@ -32,7 +32,7 @@ pub use super::Command as AccessMode;
#[derive(Debug, PartialEq)]
pub enum InputMode {
- Normal,
+ Navigation,
Edit,
}
@@ -95,8 +95,8 @@ impl<'a> App<'a> {
// Empty string where input is stored
let input = String::new();
- // Initialize App in Normal mode
- let input_mode = InputMode::Normal;
+ // Initialize App in Navigation mode
+ let input_mode = InputMode::Navigation;
// Initialize UI with focus on the PE list
let focus = InputFrame::PEList;
@@ -257,7 +257,7 @@ impl<'a> App<'a> {
pub fn on_escape(&mut self) {
if self.tabs.index == 0 {
match self.input_mode {
- InputMode::Normal => {
+ InputMode::Navigation => {
match self.focus {
InputFrame::PEList => self.pe_infos.unselect(),
InputFrame::RegisterList => {
@@ -267,7 +267,7 @@ impl<'a> App<'a> {
};
}
InputMode::Edit => {
- self.input_mode = InputMode::Normal;
+ self.input_mode = InputMode::Navigation;
self.input.clear();
}
};
@@ -282,7 +282,7 @@ impl<'a> App<'a> {
// AccessMode::Debug {} | AccessMode::Unsafe {} => {
AccessMode::Unsafe {} => {
match self.input_mode {
- InputMode::Normal => {
+ InputMode::Navigation => {
match self.focus {
// Change the focused component to the register list of the selected PE
InputFrame::PEList => match self.pe_infos.state.selected() {
@@ -329,7 +329,7 @@ impl<'a> App<'a> {
important. You should fix this app.", e);
}
- self.input_mode = InputMode::Normal;
+ self.input_mode = InputMode::Navigation;
}
}
};
diff --git a/runtime/examples/Rust/tapasco-debug/src/ui.rs b/runtime/examples/Rust/tapasco-debug/src/ui.rs
index 9ca064e8..b665f338 100644
--- a/runtime/examples/Rust/tapasco-debug/src/ui.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/ui.rs
@@ -106,14 +106,14 @@ fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) ->
KeyCode::Char(c) => app.input.push(c),
KeyCode::Backspace => {
if app.input.pop().is_none() {
- app.input_mode = InputMode::Normal;
+ app.input_mode = InputMode::Navigation;
}
}
KeyCode::Enter => app.on_enter(),
KeyCode::Esc => app.on_escape(),
_ => {}
},
- InputMode::Normal => match event {
+ InputMode::Navigation => match event {
// Press 'Shift+Tab' to switch backward through tabs
KeyEvent {
modifiers: KeyModifiers::SHIFT,
@@ -225,7 +225,7 @@ fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk
Constraint::Length(3),
]
.as_ref(),
- InputMode::Normal => [Constraint::Length(15), Constraint::Min(30)].as_ref(),
+ InputMode::Navigation => [Constraint::Length(15), Constraint::Min(30)].as_ref(),
})
.split(chunk);
From e1041110816fcac61ad1f391c564902e368f948b Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:56 +0100
Subject: [PATCH 20/34] Implement starting PEs just like `libtapasco`
Write the 1 to start the PE directly to the appropriate address in
the mapped memory. Using `libtapasco`'s API function to start a PE
is not possible because ownership of the `PE` struct has already
been taken and cannot be stolen back in the starting function.
---
.../examples/Rust/tapasco-debug/src/app.rs | 65 ++++++++++++-------
runtime/examples/Rust/tapasco-debug/src/ui.rs | 13 +++-
2 files changed, 55 insertions(+), 23 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app.rs b/runtime/examples/Rust/tapasco-debug/src/app.rs
index a8ac4605..99d9800b 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app.rs
@@ -365,28 +365,49 @@ impl<'a> App<'a> {
Some(pe)
}
- //pub fn start_current_pe(&self) {
- // if (self.access_mode != AccessMode::Debug {}) {
- // return;
- // }
-
- // if let Some(pe) = self.get_current_pe() {
- // // TODO: This might not be the correct PE when there are multiple PEs with the same
- // // TypeID.
- // match self.tlkm_device.acquire_pe(*pe.type_id()) {
- // Ok(mut pe) => {
- // trace!("Acquired PE: {:?}", pe);
- // if let Ok(_) = pe.start(vec![]) {
- // trace!("Started PE: {:?}", pe);
- // if let Ok(_) = pe.release(true, true) {
- // trace!("Starting PE: {:?}", pe);
- // }
- // }
- // },
- // Err(e) => error!("Could not acquire PE: {}", e),
- // }
- // }
- //}
+ pub fn start_current_pe(&self) -> Result<()> {
+ if (self.access_mode != AccessMode::Unsafe {}) {
+ panic!("Unsafe access mode necessary to start a PE! This function should not have been callable. This is a bug.");
+ }
+
+ if let Some(pe) = self.get_current_pe() {
+ // This does not work because `libtapasco` does a really god job of protecting its PEs
+ // and access to them with Rust's ownership rules.
+ //
+ // Besides, this might not be the correct PE when there are multiple PEs with the same
+ // TypeID.
+ //match self.tlkm_device.acquire_pe(*pe.type_id()) {
+ // Ok(mut pe) => {
+ // trace!("Acquired PE: {:?}", pe);
+ // if let Ok(_) = pe.start(vec![]) {
+ // trace!("Started PE: {:?}", pe);
+ // if let Ok(_) = pe.release(true, true) {
+ // trace!("Starting PE: {:?}", pe);
+ // }
+ // }
+ // },
+ // Err(e) => error!("Could not acquire PE: {}", e),
+ //}
+ //
+ trace!("Starting PE with ID: {}.", pe.id());
+
+ let offset = *pe.offset() as isize;
+
+ unsafe {
+ // Access PE memory just like in `libtapasco`:
+ //use volatile::Volatile;
+ //let ptr = pe.memory().as_ptr().offset(offset);
+ //let volatile_ptr: *mut Volatile = ptr as *mut Volatile;
+ //(*volatile_ptr).write(1);
+ //
+ // but instead of the `volatile` crate use std::ptr:
+ let ptr = pe.memory().as_ptr().offset(offset);
+ (ptr as *mut u32).write_volatile(1);
+ }
+ }
+
+ Ok(())
+ }
pub fn get_status_registers(&mut self) -> String {
if let Some(pe) = self.get_current_pe() {
diff --git a/runtime/examples/Rust/tapasco-debug/src/ui.rs b/runtime/examples/Rust/tapasco-debug/src/ui.rs
index b665f338..9976aeb3 100644
--- a/runtime/examples/Rust/tapasco-debug/src/ui.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/ui.rs
@@ -139,7 +139,18 @@ fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) ->
// Press Enter or 'l' to select a PE/Register
KeyCode::Enter | KeyCode::Right | KeyCode::Char('l') => app.on_enter(),
// Press 's' on a selected PE to start a job
- //KeyCode::Char('s') => app.start_current_pe(),
+ KeyCode::Char('s') => match app.access_mode {
+ AccessMode::Unsafe {} => match app.start_current_pe() {
+ // TODO: let the UI show something like started or error..
+ Ok(_) => {
+ info!("Started PE.");
+ },
+ Err(e) => {
+ error!("{}", e);
+ }
+ },
+ AccessMode::Monitor {} => warn!("Unsafe access mode necessary to start a PE. Restart the app with `unsafe` parameter.")
+ },
_ => {}
},
_ => {}
From 0ae916e98c8f8973beff58cb9573972b6b7cf7f4 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:57 +0100
Subject: [PATCH 21/34] Add `tapasco-debug` feature to `libtapasco` to make
getters pub
that are necessary for `tapasco-debug` but break up the usually wanted
encapsulation of `libtapasco`, so they are guarded behind conditional
compilation if the non-default feature is activated.
---
runtime/examples/Rust/tapasco-debug/Cargo.toml | 2 +-
runtime/libtapasco/Cargo.toml | 6 ++++++
runtime/libtapasco/src/pe.rs | 4 ++++
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/runtime/examples/Rust/tapasco-debug/Cargo.toml b/runtime/examples/Rust/tapasco-debug/Cargo.toml
index 36a458b9..e4b509f4 100644
--- a/runtime/examples/Rust/tapasco-debug/Cargo.toml
+++ b/runtime/examples/Rust/tapasco-debug/Cargo.toml
@@ -9,7 +9,7 @@ edition = "2018"
[dependencies]
tui = { version = "0.16.0", default-features = false, features = ['crossterm'] }
crossterm = "0.21.0"
-tapasco = { path = "../../../libtapasco" }
+tapasco = { path = "../../../libtapasco", features = ["tapasco-debug"] }
snafu = "0.6.10"
chrono = "0.4.19"
log = "0.4.14"
diff --git a/runtime/libtapasco/Cargo.toml b/runtime/libtapasco/Cargo.toml
index ac073d27..4d654cf2 100644
--- a/runtime/libtapasco/Cargo.toml
+++ b/runtime/libtapasco/Cargo.toml
@@ -12,6 +12,12 @@ opt-level = 3
codegen-units = 1
lto = "fat"
+[features]
+# There are no default features:
+default = []
+# Necessary when building `tapasco-debug` to make some things accessible that are usually hidden away:
+tapasco-debug = []
+
[dependencies]
log = "0.4.8"
chrono = "0.4.11"
diff --git a/runtime/libtapasco/src/pe.rs b/runtime/libtapasco/src/pe.rs
index 73c069f1..74c56997 100644
--- a/runtime/libtapasco/src/pe.rs
+++ b/runtime/libtapasco/src/pe.rs
@@ -95,10 +95,14 @@ pub struct PE {
id: usize,
#[get = "pub"]
type_id: PEId,
+ // This public getter is guarded behind conditional compilation for `tapasco-debug`:
+ #[cfg_attr(feature = "tapasco-debug", get = "pub")]
offset: DeviceAddress,
#[get = "pub"]
active: bool,
copy_back: Option>,
+ // This public getter is guarded behind conditional compilation for `tapasco-debug`:
+ #[cfg_attr(feature = "tapasco-debug", get = "pub")]
memory: Arc,
#[set = "pub"]
From b020de2df69c05ed3a1b88b13afd9c63ae37a4f5 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:57 +0100
Subject: [PATCH 22/34] Update `Cargo.lock`
---
.../examples/Rust/tapasco-debug/Cargo.lock | 184 ++++++++++++------
1 file changed, 129 insertions(+), 55 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/Cargo.lock b/runtime/examples/Rust/tapasco-debug/Cargo.lock
index 1ec3d6b8..9026af31 100644
--- a/runtime/examples/Rust/tapasco-debug/Cargo.lock
+++ b/runtime/examples/Rust/tapasco-debug/Cargo.lock
@@ -57,9 +57,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bytes"
-version = "1.1.0"
+version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8"
+checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
[[package]]
name = "cassowary"
@@ -69,13 +69,12 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]]
name = "cbindgen"
-version = "0.20.0"
+version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51e3973b165dc0f435831a9e426de67e894de532754ff7a3f307c03ee5dec7dc"
+checksum = "e6e03a705df2e735cc5486f104a48e25a8f72ae06eaea5b7753a81270ed00859"
dependencies = [
"clap",
"heck",
- "indexmap",
"log",
"proc-macro2",
"quote",
@@ -92,6 +91,12 @@ version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -128,9 +133,9 @@ dependencies = [
[[package]]
name = "config"
-version = "0.11.0"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b1b9d958c2b1368a663f05538fc1b5975adce1e19f435acceae987aceeeb369"
+checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3"
dependencies = [
"lazy_static",
"nom",
@@ -144,11 +149,11 @@ dependencies = [
[[package]]
name = "crossbeam"
-version = "0.8.1"
+version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845"
+checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e"
dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-epoch",
@@ -158,55 +163,59 @@ dependencies = [
[[package]]
name = "crossbeam-channel"
-version = "0.5.1"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
+checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
dependencies = [
- "cfg-if",
"crossbeam-utils",
+ "maybe-uninit",
]
[[package]]
name = "crossbeam-deque"
-version = "0.8.1"
+version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
+checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed"
dependencies = [
- "cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
+ "maybe-uninit",
]
[[package]]
name = "crossbeam-epoch"
-version = "0.9.5"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
+checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
dependencies = [
- "cfg-if",
+ "autocfg",
+ "cfg-if 0.1.10",
"crossbeam-utils",
"lazy_static",
+ "maybe-uninit",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-queue"
-version = "0.3.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9"
+checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
"crossbeam-utils",
+ "maybe-uninit",
]
[[package]]
name = "crossbeam-utils"
-version = "0.8.5"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
+checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
- "cfg-if",
+ "autocfg",
+ "cfg-if 0.1.10",
"lazy_static",
]
@@ -263,6 +272,19 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+[[package]]
+name = "env_logger"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
+dependencies = [
+ "atty",
+ "humantime 1.3.0",
+ "log",
+ "regex",
+ "termcolor",
+]
+
[[package]]
name = "env_logger"
version = "0.9.0"
@@ -270,7 +292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"atty",
- "humantime",
+ "humantime 2.1.0",
"log",
"regex",
"termcolor",
@@ -288,7 +310,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"libc",
"wasi",
]
@@ -329,6 +351,15 @@ dependencies = [
"libc",
]
+[[package]]
+name = "humantime"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
+dependencies = [
+ "quick-error",
+]
+
[[package]]
name = "humantime"
version = "2.1.0"
@@ -351,14 +382,14 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
]
[[package]]
name = "itertools"
-version = "0.10.1"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
+checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
dependencies = [
"either",
]
@@ -383,7 +414,7 @@ checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe"
dependencies = [
"arrayvec",
"bitflags",
- "cfg-if",
+ "cfg-if 1.0.0",
"ryu",
"static_assertions",
]
@@ -394,6 +425,16 @@ version = "0.2.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
+[[package]]
+name = "linked-hash-map"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
+dependencies = [
+ "serde 0.8.23",
+ "serde_test",
+]
+
[[package]]
name = "linked-hash-map"
version = "0.5.4"
@@ -424,9 +465,15 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
]
+[[package]]
+name = "maybe-uninit"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
+
[[package]]
name = "memchr"
version = "2.4.1"
@@ -445,9 +492,9 @@ dependencies = [
[[package]]
name = "memoffset"
-version = "0.6.4"
+version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
+checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
dependencies = [
"autocfg",
]
@@ -482,15 +529,15 @@ checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a"
[[package]]
name = "nix"
-version = "0.22.1"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7555d6c7164cc913be1ce7f95cbecdabda61eb2ccd89008524af306fb7f5031"
+checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363"
dependencies = [
"bitflags",
"cc",
- "cfg-if",
+ "cfg-if 0.1.10",
"libc",
- "memoffset",
+ "void",
]
[[package]]
@@ -564,7 +611,7 @@ version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"instant",
"libc",
"redox_syscall",
@@ -623,9 +670,9 @@ dependencies = [
[[package]]
name = "prost"
-version = "0.8.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de5e2533f59d08fcf364fd374ebda0692a70bd6d7e66ef97f306f45c6c5d8020"
+checksum = "ce49aefe0a6144a45de32927c77bd2859a5f7677b55f220ae5b744e87389c212"
dependencies = [
"bytes",
"prost-derive",
@@ -633,9 +680,9 @@ dependencies = [
[[package]]
name = "prost-build"
-version = "0.8.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "355f634b43cdd80724ee7848f95770e7e70eefa6dcf14fea676216573b8fd603"
+checksum = "02b10678c913ecbd69350e8535c3aef91a8676c0773fc1d7b95cdd196d7f2f26"
dependencies = [
"bytes",
"heck",
@@ -651,9 +698,9 @@ dependencies = [
[[package]]
name = "prost-derive"
-version = "0.8.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "600d2f334aa05acb02a755e217ef1ab6dea4d51b58b7846588b747edec04efba"
+checksum = "537aa19b95acde10a12fec4301466386f757403de4cd4e5b4fa78fb5ecb18f72"
dependencies = [
"anyhow",
"itertools",
@@ -664,14 +711,20 @@ dependencies = [
[[package]]
name = "prost-types"
-version = "0.8.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "603bbd6394701d13f3f25aada59c7de9d35a6a5887cfc156181234a44002771b"
+checksum = "1834f67c0697c001304b75be76f67add9c89742eda3a085ad8ee0bb38c3417aa"
dependencies = [
"bytes",
"prost",
]
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+
[[package]]
name = "quote"
version = "1.0.9"
@@ -796,6 +849,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8"
dependencies = [
"lazy_static",
+ "linked-hash-map 0.3.0",
"num-traits 0.1.43",
"regex",
"serde 0.8.23",
@@ -823,6 +877,15 @@ dependencies = [
"serde 1.0.130",
]
+[[package]]
+name = "serde_test"
+version = "0.8.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5"
+dependencies = [
+ "serde 0.8.23",
+]
+
[[package]]
name = "signal-hook"
version = "0.3.10"
@@ -936,7 +999,7 @@ dependencies = [
"chrono",
"config",
"crossbeam",
- "env_logger",
+ "env_logger 0.7.1",
"getset",
"libc",
"lockfree",
@@ -948,6 +1011,7 @@ dependencies = [
"serde 1.0.130",
"snafu",
"vfio-bindings",
+ "volatile",
]
[[package]]
@@ -956,7 +1020,7 @@ version = "0.1.0"
dependencies = [
"chrono",
"crossterm 0.21.0",
- "env_logger",
+ "env_logger 0.9.0",
"log",
"memmap",
"snafu",
@@ -972,7 +1036,7 @@ version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [
- "cfg-if",
+ "cfg-if 1.0.0",
"libc",
"rand",
"redox_syscall",
@@ -1067,6 +1131,18 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a21f546f2bda37f5a8cfb138c87f95b8e34d2d78d6a7a92ba3785f4e08604a7"
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
+[[package]]
+name = "volatile"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6b06ad3ed06fef1713569d547cdbdb439eafed76341820fb0e0344f29a41945"
+
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
@@ -1075,12 +1151,10 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "which"
-version = "4.2.2"
+version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9"
+checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
dependencies = [
- "either",
- "lazy_static",
"libc",
]
@@ -1121,5 +1195,5 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
- "linked-hash-map",
+ "linked-hash-map 0.5.4",
]
From a29d975eafe1400fc8e20ba53fbf90e9c7602c5b Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:57 +0100
Subject: [PATCH 23/34] Improve logging in `src/ui.rs`
---
runtime/examples/Rust/tapasco-debug/src/ui.rs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/runtime/examples/Rust/tapasco-debug/src/ui.rs b/runtime/examples/Rust/tapasco-debug/src/ui.rs
index 9976aeb3..4d90d4ff 100644
--- a/runtime/examples/Rust/tapasco-debug/src/ui.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/ui.rs
@@ -1,5 +1,7 @@
use std::{io::stdout, sync::mpsc, thread, time::Duration};
+use log::{error, info, trace, warn};
+
use tui::{
backend::{Backend, CrosstermBackend},
layout::{Constraint, Direction, Layout, Rect},
@@ -101,6 +103,10 @@ fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) ->
match rx.recv().context(ReceiveInput {})? {
// Match key pressed events
Event::Input(event) => {
+ trace!("Input event: {:?}", event);
+
+ // Match the input mode, either you're in line input mode where you enter new
+ // values for registers or you're in the default navigation mode.
match app.input_mode {
InputMode::Edit => match event.code {
KeyCode::Char(c) => app.input.push(c),
From 287a5d7b15b0a220d9d07036cdb32697da6addcf Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:58 +0100
Subject: [PATCH 24/34] Implement `tapasco-debug` message view
---
.../examples/Rust/tapasco-debug/src/app.rs | 14 +++++++++++--
runtime/examples/Rust/tapasco-debug/src/ui.rs | 20 ++++++++++++++-----
2 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app.rs b/runtime/examples/Rust/tapasco-debug/src/app.rs
index 99d9800b..18e16c72 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app.rs
@@ -56,6 +56,7 @@ pub struct App<'a> {
pub pes: Vec<(usize, PE)>, // Plural of Processing Element (PEs)
pub register_list: StatefulList,
pub local_memory_list: StatefulList,
+ pub messages: Vec,
}
impl<'a> App<'a> {
@@ -209,6 +210,12 @@ impl<'a> App<'a> {
);
}
+ // Setup a new Vector to store (event) messages. It's kind of like logging but as there
+ // already is a real logger and we cannot add another logging implementation, we have to
+ // provide something a little bit different and simpler to inform users about things like
+ // started PEs.
+ let messages: Vec = Vec::new();
+
trace!("Constructed App");
Ok(App {
@@ -225,6 +232,7 @@ impl<'a> App<'a> {
pes,
register_list,
local_memory_list,
+ messages,
})
}
@@ -365,7 +373,7 @@ impl<'a> App<'a> {
Some(pe)
}
- pub fn start_current_pe(&self) -> Result<()> {
+ pub fn start_current_pe(&self) -> Result {
if (self.access_mode != AccessMode::Unsafe {}) {
panic!("Unsafe access mode necessary to start a PE! This function should not have been callable. This is a bug.");
}
@@ -404,9 +412,11 @@ impl<'a> App<'a> {
let ptr = pe.memory().as_ptr().offset(offset);
(ptr as *mut u32).write_volatile(1);
}
+
+ return Ok(format!("Started PE with ID: {}.", pe.id()).to_string())
}
- Ok(())
+ Ok("No PE selected.".to_string())
}
pub fn get_status_registers(&mut self) -> String {
diff --git a/runtime/examples/Rust/tapasco-debug/src/ui.rs b/runtime/examples/Rust/tapasco-debug/src/ui.rs
index 4d90d4ff..246e9973 100644
--- a/runtime/examples/Rust/tapasco-debug/src/ui.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/ui.rs
@@ -147,12 +147,13 @@ fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) ->
// Press 's' on a selected PE to start a job
KeyCode::Char('s') => match app.access_mode {
AccessMode::Unsafe {} => match app.start_current_pe() {
- // TODO: let the UI show something like started or error..
- Ok(_) => {
+ Ok(s) => {
info!("Started PE.");
+ app.messages.push(s);
},
Err(e) => {
error!("{}", e);
+ app.messages.push(e.to_string());
}
},
AccessMode::Monitor {} => warn!("Unsafe access mode necessary to start a PE. Restart the app with `unsafe` parameter.")
@@ -230,8 +231,9 @@ fn draw(app: &mut App, terminal: &mut Terminal) -> Result<()> {
}
fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk: Rect) {
- // Create a vertical layout (top to bottom) first to split the Tab into 2 rows with a
- // bottom line for keyboard input that is only shown when in Edit Mode
+ // Create a vertical layout (top to bottom) first to split the Tab into 3 rows with a
+ // bottom line for keyboard input that is only shown when in Edit Mode (that replaces the
+ // messages view):
let vertical_chunks = Layout::default()
.direction(Direction::Vertical)
.margin(0)
@@ -242,7 +244,7 @@ fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk
Constraint::Length(3),
]
.as_ref(),
- InputMode::Navigation => [Constraint::Length(15), Constraint::Min(30)].as_ref(),
+ InputMode::Navigation => [Constraint::Length(15), Constraint::Min(30), Constraint::Length(15)].as_ref(),
})
.split(chunk);
@@ -346,6 +348,14 @@ fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk
// Move one line down, from the border to the input line
input_chunks.y + 1,
);
+ // Or the messages view when not in Edit Mode
+ } else {
+ draw_block_with_paragraph(
+ f,
+ "Messages",
+ app.messages.iter().rev().take((f.size().height - 2).into()).rev().cloned().collect::>().join("\n"),
+ vertical_chunks[2],
+ );
}
}
From 4370005348079ece957a704e5ffcee9ca203acbb Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:58 +0100
Subject: [PATCH 25/34] Update `Cargo.lock`
---
.../examples/Rust/tapasco-debug/Cargo.lock | 202 +++++++-----------
1 file changed, 77 insertions(+), 125 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/Cargo.lock b/runtime/examples/Rust/tapasco-debug/Cargo.lock
index 9026af31..2b0ea4dc 100644
--- a/runtime/examples/Rust/tapasco-debug/Cargo.lock
+++ b/runtime/examples/Rust/tapasco-debug/Cargo.lock
@@ -13,18 +13,18 @@ dependencies = [
[[package]]
name = "ansi_term"
-version = "0.11.0"
+version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "anyhow"
-version = "1.0.44"
+version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1"
+checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
[[package]]
name = "arrayvec"
@@ -45,15 +45,15 @@ dependencies = [
[[package]]
name = "autocfg"
-version = "1.0.1"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
-version = "1.2.1"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bytes"
@@ -78,7 +78,7 @@ dependencies = [
"log",
"proc-macro2",
"quote",
- "serde 1.0.130",
+ "serde 1.0.136",
"serde_json",
"syn",
"tempfile",
@@ -87,9 +87,9 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.0.70"
+version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
+checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
@@ -118,9 +118,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "2.33.3"
+version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"ansi_term",
"atty",
@@ -140,7 +140,7 @@ dependencies = [
"lazy_static",
"nom",
"rust-ini",
- "serde 1.0.130",
+ "serde 1.0.136",
"serde-hjson",
"serde_json",
"toml",
@@ -299,27 +299,25 @@ dependencies = [
]
[[package]]
-name = "fixedbitset"
-version = "0.2.0"
+name = "fastrand"
+version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
+checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
+dependencies = [
+ "instant",
+]
[[package]]
-name = "getrandom"
-version = "0.2.3"
+name = "fixedbitset"
+version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
-dependencies = [
- "cfg-if 1.0.0",
- "libc",
- "wasi",
-]
+checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d"
[[package]]
name = "getset"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24b328c01a4d71d2d8173daa93562a73ab0fe85616876f02500f53d82948c504"
+checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9"
dependencies = [
"proc-macro-error",
"proc-macro2",
@@ -368,9 +366,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "indexmap"
-version = "1.7.0"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
@@ -378,9 +376,9 @@ dependencies = [
[[package]]
name = "instant"
-version = "0.1.10"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if 1.0.0",
]
@@ -396,9 +394,9 @@ dependencies = [
[[package]]
name = "itoa"
-version = "0.4.8"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
+checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "lazy_static"
@@ -421,9 +419,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.102"
+version = "0.2.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
+checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
[[package]]
name = "linked-hash-map"
@@ -443,9 +441,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "lock_api"
-version = "0.4.5"
+version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
+checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
dependencies = [
"scopeguard",
]
@@ -501,9 +499,9 @@ dependencies = [
[[package]]
name = "mio"
-version = "0.7.13"
+version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
+checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
dependencies = [
"libc",
"log",
@@ -553,9 +551,9 @@ dependencies = [
[[package]]
name = "ntapi"
-version = "0.3.6"
+version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
+checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
dependencies = [
"winapi",
]
@@ -629,12 +627,6 @@ dependencies = [
"indexmap",
]
-[[package]]
-name = "ppv-lite86"
-version = "0.2.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
-
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@@ -661,9 +653,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.29"
+version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
+checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
@@ -727,67 +719,27 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
-version = "1.0.9"
+version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
]
-[[package]]
-name = "rand"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
- "rand_hc",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
-dependencies = [
- "getrandom",
-]
-
-[[package]]
-name = "rand_hc"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
-dependencies = [
- "rand_core",
-]
-
[[package]]
name = "redox_syscall"
-version = "0.2.10"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
-version = "1.5.4"
+version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [
"aho-corasick",
"memchr",
@@ -817,9 +769,9 @@ checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
[[package]]
name = "ryu"
-version = "1.0.5"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "scopeguard"
@@ -835,9 +787,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
[[package]]
name = "serde"
-version = "1.0.130"
+version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
+checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
@@ -857,9 +809,9 @@ dependencies = [
[[package]]
name = "serde_derive"
-version = "1.0.130"
+version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
+checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
@@ -868,13 +820,13 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.68"
+version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
+checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [
"itoa",
"ryu",
- "serde 1.0.130",
+ "serde 1.0.136",
]
[[package]]
@@ -888,9 +840,9 @@ dependencies = [
[[package]]
name = "signal-hook"
-version = "0.3.10"
+version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
+checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
dependencies = [
"libc",
"signal-hook-registry",
@@ -918,9 +870,9 @@ dependencies = [
[[package]]
name = "smallvec"
-version = "1.6.1"
+version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
+checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
[[package]]
name = "snafu"
@@ -957,9 +909,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "structopt"
-version = "0.3.23"
+version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa"
+checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"
dependencies = [
"clap",
"lazy_static",
@@ -968,9 +920,9 @@ dependencies = [
[[package]]
name = "structopt-derive"
-version = "0.4.16"
+version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba"
+checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [
"heck",
"proc-macro-error",
@@ -981,9 +933,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.76"
+version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
+checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
@@ -1008,7 +960,7 @@ dependencies = [
"nix",
"prost",
"prost-build",
- "serde 1.0.130",
+ "serde 1.0.136",
"snafu",
"vfio-bindings",
"volatile",
@@ -1032,13 +984,13 @@ dependencies = [
[[package]]
name = "tempfile"
-version = "3.2.0"
+version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if 1.0.0",
+ "fastrand",
"libc",
- "rand",
"redox_syscall",
"remove_dir_all",
"winapi",
@@ -1046,9 +998,9 @@ dependencies = [
[[package]]
name = "termcolor"
-version = "1.1.2"
+version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
@@ -1079,7 +1031,7 @@ version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
dependencies = [
- "serde 1.0.130",
+ "serde 1.0.136",
]
[[package]]
@@ -1097,9 +1049,9 @@ dependencies = [
[[package]]
name = "unicode-segmentation"
-version = "1.8.0"
+version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
[[package]]
name = "unicode-width"
@@ -1121,9 +1073,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
-version = "0.9.3"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vfio-bindings"
From 22b195c056f0617f2e4532fda6e377fdb832abb4 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:59 +0100
Subject: [PATCH 26/34] Update Rust edition from 2018 to 2021
---
runtime/examples/Rust/tapasco-debug/Cargo.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/runtime/examples/Rust/tapasco-debug/Cargo.toml b/runtime/examples/Rust/tapasco-debug/Cargo.toml
index e4b509f4..62eb034c 100644
--- a/runtime/examples/Rust/tapasco-debug/Cargo.toml
+++ b/runtime/examples/Rust/tapasco-debug/Cargo.toml
@@ -2,7 +2,7 @@
name = "tapasco-debug"
version = "0.1.0"
authors = ["zyno42 <83068959+zyno42@users.noreply.github.com>"]
-edition = "2018"
+edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
From 40fdcb209fd8e6b1097b0da3f16e00a559976ef1 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:53:59 +0100
Subject: [PATCH 27/34] Remove unnecessary import
TryInto is now in the prelude of the 2021 edition.
---
runtime/examples/Rust/tapasco-debug/src/app.rs | 1 -
1 file changed, 1 deletion(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app.rs b/runtime/examples/Rust/tapasco-debug/src/app.rs
index 18e16c72..9c5d401a 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app.rs
@@ -1,5 +1,4 @@
use std::collections::HashMap;
-use std::convert::TryInto;
use log::{error, trace, warn};
From 9e4df7df039849395b46dffbdc38470fbb047015 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:54:00 +0100
Subject: [PATCH 28/34] Improve inline comments and TODOs
---
runtime/examples/Rust/tapasco-debug/src/app.rs | 2 ++
runtime/examples/Rust/tapasco-debug/src/main.rs | 8 +++++++-
runtime/examples/Rust/tapasco-debug/src/ui.rs | 12 ++++++++----
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app.rs b/runtime/examples/Rust/tapasco-debug/src/app.rs
index 9c5d401a..b3acee33 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app.rs
@@ -445,6 +445,8 @@ impl<'a> App<'a> {
}
}
+ // TODO: add a function parameter for the number of registers that should be read to make it
+ // dependent on the size of the UI frame.
pub fn get_argument_registers(&mut self) -> Vec {
if let Some(pe) = self.get_current_pe() {
let argument_registers = (0..self.register_list.items.len())
diff --git a/runtime/examples/Rust/tapasco-debug/src/main.rs b/runtime/examples/Rust/tapasco-debug/src/main.rs
index a36a91a2..96abb8e8 100644
--- a/runtime/examples/Rust/tapasco-debug/src/main.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/main.rs
@@ -1,4 +1,6 @@
+// The app module holds all state (of TaPaSCo) and interacts with PEs
mod app;
+// The ui module handles (key press) events and displaying the app in the TUI
mod ui;
use snafu::{ResultExt, Snafu};
@@ -54,17 +56,21 @@ pub enum Command {
}
fn init() -> Result<()> {
+ // Parse command line arguments:
let Opt {
device_id,
subcommand,
} = Opt::from_args();
- // Specify the Access Mode as subcommand
+
+ // Specify the Access Mode as subcommand and setup the App and UI
ui::setup(&mut app::App::new(device_id, subcommand).context(App {})?).context(UI {})
}
fn main() {
+ // Initialize the env logger. Export `RUST_LOG=debug` to see logs on stderr.
env_logger::init();
+ // Initialize app and error reporting with Snafu:
match init() {
Ok(_) => {}
Err(e) => {
diff --git a/runtime/examples/Rust/tapasco-debug/src/ui.rs b/runtime/examples/Rust/tapasco-debug/src/ui.rs
index 246e9973..01e2d962 100644
--- a/runtime/examples/Rust/tapasco-debug/src/ui.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/ui.rs
@@ -38,11 +38,11 @@ pub type Result = std::result::Result;
use crate::app::{AccessMode, App, InputFrame, InputMode};
-// Define an Event which can consist of a pressed key or a Tick which occurs when the UI should be
-// updated while no key got pressed
+// Define an Event which can consist of a pressed key or the terminal got resized.
enum Event {
Input(I),
Resize(H, H),
+ // TODO: Maybe add a tick event which occurs when the UI should be updated while no key got pressed?
}
pub fn setup(app: &mut App) -> Result<()> {
@@ -107,6 +107,7 @@ fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) ->
// Match the input mode, either you're in line input mode where you enter new
// values for registers or you're in the default navigation mode.
+ // TODO: refactor app.on_enter and app.on_* into this match
match app.input_mode {
InputMode::Edit => match event.code {
KeyCode::Char(c) => app.input.push(c),
@@ -232,8 +233,8 @@ fn draw(app: &mut App, terminal: &mut Terminal) -> Result<()> {
fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk: Rect) {
// Create a vertical layout (top to bottom) first to split the Tab into 3 rows with a
- // bottom line for keyboard input that is only shown when in Edit Mode (that replaces the
- // messages view):
+ // bottom line for keyboard input that is only shown when in Edit Mode (that then replaces
+ // the messages view):
let vertical_chunks = Layout::default()
.direction(Direction::Vertical)
.margin(0)
@@ -292,6 +293,7 @@ fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk
);
// Argument Register List (also stateful list for editing)
+ // TODO: query and draw only as many registers as there is space in the frame
let registers_title = if (app.access_mode == AccessMode::Monitor {}) {
"Register List (r: Refresh)"
//} else if (app.access_mode == AccessMode::Debug {}) {
@@ -314,6 +316,7 @@ fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk
f.render_stateful_widget(registers, register_chunks[1], &mut app.register_list.state);
// Local Memory (also a stateful list for editing TODO?)
+ // TODO: query and draw only as many addresses as there is space in the frame
let local_memory = app.dump_current_pe_local_memory();
let local_memory: Vec = local_memory
.iter()
@@ -349,6 +352,7 @@ fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk
input_chunks.y + 1,
);
// Or the messages view when not in Edit Mode
+ // TODO: show more messages e.g. when some register/address is changed
} else {
draw_block_with_paragraph(
f,
From 3bad6ea4912ea90ecf7e406cb1297679df732495 Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:54:00 +0100
Subject: [PATCH 29/34] Improve code quality and UI
---
.../examples/Rust/tapasco-debug/src/app.rs | 16 ++++++--------
runtime/examples/Rust/tapasco-debug/src/ui.rs | 22 +++++--------------
2 files changed, 13 insertions(+), 25 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app.rs b/runtime/examples/Rust/tapasco-debug/src/app.rs
index b3acee33..0dab2c9c 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app.rs
@@ -372,10 +372,8 @@ impl<'a> App<'a> {
Some(pe)
}
- pub fn start_current_pe(&self) -> Result {
- if (self.access_mode != AccessMode::Unsafe {}) {
- panic!("Unsafe access mode necessary to start a PE! This function should not have been callable. This is a bug.");
- }
+ pub fn start_current_pe(&self) -> String {
+ assert!(self.access_mode == AccessMode::Unsafe {}, "Unsafe access mode necessary to start a PE! This function should not have been callable. This is a bug.");
if let Some(pe) = self.get_current_pe() {
// This does not work because `libtapasco` does a really god job of protecting its PEs
@@ -412,10 +410,10 @@ impl<'a> App<'a> {
(ptr as *mut u32).write_volatile(1);
}
- return Ok(format!("Started PE with ID: {}.", pe.id()).to_string())
+ return format!("Started PE with ID: {}.", pe.id())
}
- Ok("No PE selected.".to_string())
+ "No PE selected.".to_string()
}
pub fn get_status_registers(&mut self) -> String {
@@ -439,10 +437,10 @@ impl<'a> App<'a> {
return_value, return_value as i32
);
- result
- } else {
- "No PE selected.".to_string()
+ return result
}
+
+ "No PE selected.".to_string()
}
// TODO: add a function parameter for the number of registers that should be read to make it
diff --git a/runtime/examples/Rust/tapasco-debug/src/ui.rs b/runtime/examples/Rust/tapasco-debug/src/ui.rs
index 01e2d962..6dcc4f13 100644
--- a/runtime/examples/Rust/tapasco-debug/src/ui.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/ui.rs
@@ -1,6 +1,6 @@
use std::{io::stdout, sync::mpsc, thread, time::Duration};
-use log::{error, info, trace, warn};
+use log::trace;
use tui::{
backend::{Backend, CrosstermBackend},
@@ -74,7 +74,7 @@ pub fn setup(app: &mut App) -> Result<()> {
result
}
-fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) -> Result<()> {
+fn run_event_loop(app: &mut App, terminal: &mut Terminal) -> Result<()> {
// Setup input handling as in the crossterm demo with a multi producer single consumer (mpsc) channel
let (tx, rx) = mpsc::channel();
thread::spawn(move || loop {
@@ -97,7 +97,7 @@ fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) ->
// Event loop
loop {
// Update UI
- draw(app, &mut terminal)?;
+ draw(app, terminal)?;
// Handle events
match rx.recv().context(ReceiveInput {})? {
@@ -147,17 +147,8 @@ fn run_event_loop(app: &mut App, mut terminal: &mut Terminal) ->
KeyCode::Enter | KeyCode::Right | KeyCode::Char('l') => app.on_enter(),
// Press 's' on a selected PE to start a job
KeyCode::Char('s') => match app.access_mode {
- AccessMode::Unsafe {} => match app.start_current_pe() {
- Ok(s) => {
- info!("Started PE.");
- app.messages.push(s);
- },
- Err(e) => {
- error!("{}", e);
- app.messages.push(e.to_string());
- }
- },
- AccessMode::Monitor {} => warn!("Unsafe access mode necessary to start a PE. Restart the app with `unsafe` parameter.")
+ AccessMode::Unsafe {} => app.messages.push(app.start_current_pe()),
+ AccessMode::Monitor {} => app.messages.push("Unsafe access mode necessary to start a PE. Restart the app with `unsafe` parameter.".to_string())
},
_ => {}
},
@@ -260,7 +251,7 @@ fn draw_tab_peek_and_poke_pes(f: &mut Frame, app: &mut App, chunk
let pes_title = if (app.access_mode == AccessMode::Monitor {}) {
"PE List (j:\u{2193}, k:\u{2191})"
} else {
- "PE List (j:\u{2193}, k:\u{2191}, Enter/l: switch to Register List)"
+ "PE List (j:\u{2193}, k:\u{2191}, s: start the selected PE, Enter/l: switch to Register List)"
};
let pes: Vec = app
.pe_infos
@@ -388,7 +379,6 @@ fn draw_tab_bitstream_and_device_info(f: &mut Frame, app: &App, c
}
/// Draw a block with some text in it into the rectangular space given by chunk
-//fn draw_block_with_paragraph(f: &mut Frame, block_title: &str, paragraph_text: &str, chunk: Rect) {
fn draw_block_with_paragraph<'a, B: Backend, T>(
f: &mut Frame,
block_title: &str,
From f5f24ef8d0c02a913292a7d0b786295181a4dbfc Mon Sep 17 00:00:00 2001
From: zyno42 <83068959+zyno42@users.noreply.github.com>
Date: Mon, 14 Mar 2022 17:54:00 +0100
Subject: [PATCH 30/34] Improve code for Registers and Local Memory panes
Replace unnecessary `StatefulList`s with `ListStates`.
Make the number of registers and the size of local memory endless.
---
.../examples/Rust/tapasco-debug/src/app.rs | 86 +++++++++++++++----
runtime/examples/Rust/tapasco-debug/src/ui.rs | 11 ++-
2 files changed, 72 insertions(+), 25 deletions(-)
diff --git a/runtime/examples/Rust/tapasco-debug/src/app.rs b/runtime/examples/Rust/tapasco-debug/src/app.rs
index 0dab2c9c..8a73f807 100644
--- a/runtime/examples/Rust/tapasco-debug/src/app.rs
+++ b/runtime/examples/Rust/tapasco-debug/src/app.rs
@@ -1,5 +1,7 @@
use std::collections::HashMap;
+use tui::widgets::ListState;
+
use log::{error, trace, warn};
use tapasco::{
@@ -53,8 +55,8 @@ pub struct App<'a> {
pub tabs: TabsState<'a>,
pub pe_infos: StatefulList,
pub pes: Vec<(usize, PE)>, // Plural of Processing Element (PEs)
- pub register_list: StatefulList,
- pub local_memory_list: StatefulList,
+ pub register_list: ListState,
+ pub local_memory_list: ListState,
pub messages: Vec,
}
@@ -151,9 +153,9 @@ impl<'a> App<'a> {
StatefulList::with_items_selected(pe_infos, 0)
};
- // There are theoretically endless registers. 100 seems to be a good value.
- let register_list = StatefulList::with_items(vec!["".to_string(); 100]);
- let local_memory_list = StatefulList::new();
+ // There are theoretically endless registers and local memory
+ let register_list = ListState::default();
+ let local_memory_list = ListState::default();
// Parse bitstream info from the Status core
let mut bitstream_info = String::new();
@@ -328,7 +330,7 @@ impl<'a> App<'a> {
.expect("There should have been a selected PE. This is a bug."))
.expect("There should have been a PE for the selection. This is a bug.")
.1 // ignore the index, select the PE from the tuple
- .set_arg(self.register_list.state.selected().unwrap(),
+ .set_arg(self.register_list.selected().unwrap(),
PEParameter::Single64(new_value)) {
// but log this error in case the code changes
error!("Error setting argument: {}.
@@ -336,6 +338,11 @@ impl<'a> App<'a> {
important. You should fix this app.", e);
}
+ self.messages.push(format!("In slot {} set argument register {} to new value: {}.",
+ self.pe_infos.state.selected().unwrap(),
+ self.register_list.selected().unwrap(),
+ new_value));
+
self.input_mode = InputMode::Navigation;
}
}
@@ -359,7 +366,7 @@ impl<'a> App<'a> {
_ => return None,
};
- // Get the PE with the real ID of the selected Slot
+ // Get the PE with the real ID of the selected slot
let (_, pe) = self
.pes
.iter()
@@ -410,7 +417,7 @@ impl<'a> App<'a> {
(ptr as *mut u32).write_volatile(1);
}
- return format!("Started PE with ID: {}.", pe.id())
+ return format!("Send start signal to PE in slot: {}.", self.pe_infos.state.selected().expect("There needs to be a selected PE. This is a bug."))
}
"No PE selected.".to_string()
@@ -445,9 +452,11 @@ impl<'a> App<'a> {
// TODO: add a function parameter for the number of registers that should be read to make it
// dependent on the size of the UI frame.
- pub fn get_argument_registers(&mut self) -> Vec {
+ pub fn get_argument_registers(&mut self, number_of_lines: usize) -> Vec {
+ let number_of_registers = self.register_list.selected().unwrap_or(0) + number_of_lines;
+
if let Some(pe) = self.get_current_pe() {
- let argument_registers = (0..self.register_list.items.len())
+ let argument_registers = (0..number_of_registers)
.map(|i| {
match pe
.read_arg(i, 8)
@@ -470,14 +479,14 @@ impl<'a> App<'a> {
}
}
- pub fn dump_current_pe_local_memory(&self) -> Vec {
+ pub fn dump_current_pe_local_memory(&self, number_of_lines: usize) -> Vec {
if let Some(pe) = self.get_current_pe() {
let local_memory = match pe.local_memory() {
Some(m) => m,
_ => return vec!["No local memory for this PE.".to_string()],
};
- let mut memory_cells: Box<[u8]> = Box::new([0_u8; 16 * 100]);
+ let mut memory_cells: Vec = vec![0_u8; 16 * number_of_lines];
match local_memory.dma().copy_from(0, &mut memory_cells) {
Ok(_) => {}
_ => return vec!["Could not read PE Local Memory!".to_string()],
@@ -610,21 +619,21 @@ impl<'a> TabsState<'a> {
}
}
-use tui::widgets::ListState;
-
pub struct StatefulList