Add graphical_debug module
This commit is contained in:
63
src/devices/graphical_debug/debug.rs
Normal file
63
src/devices/graphical_debug/debug.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
use super::Display;
|
||||
|
||||
pub struct DebugDisplay {
|
||||
pub (crate) display: Display,
|
||||
x: usize,
|
||||
y: usize,
|
||||
w: usize,
|
||||
h: usize,
|
||||
}
|
||||
|
||||
impl DebugDisplay {
|
||||
pub fn new(display: Display) -> DebugDisplay {
|
||||
let w = display.width/8;
|
||||
let h = display.height/16;
|
||||
DebugDisplay {
|
||||
display,
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: w,
|
||||
h: h,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_char(&mut self, c: char) {
|
||||
if self.x >= self.w || c == '\n' {
|
||||
self.x = 0;
|
||||
self.y += 1;
|
||||
}
|
||||
|
||||
if self.y >= self.h {
|
||||
let new_y = self.h - 1;
|
||||
let d_y = self.y - new_y;
|
||||
|
||||
self.display.scroll(d_y * 16);
|
||||
|
||||
unsafe {
|
||||
self.display.sync(0, 0, self.display.width, self.display.height);
|
||||
}
|
||||
|
||||
self.y = new_y;
|
||||
}
|
||||
|
||||
if c != '\n' {
|
||||
self.display.char(
|
||||
self.x * 8, self.y * 16,
|
||||
c,
|
||||
0xFFFFFF
|
||||
);
|
||||
|
||||
unsafe {
|
||||
self.display.sync(self.x * 8, self.y * 16, 8, 16);
|
||||
}
|
||||
|
||||
self.x += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&mut self, buf: &[u8]) {
|
||||
for &b in buf {
|
||||
self.write_char(b as char);
|
||||
}
|
||||
}
|
||||
}
|
||||
80
src/devices/graphical_debug/display.rs
Normal file
80
src/devices/graphical_debug/display.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use alloc::boxed::Box;
|
||||
use core::{cmp, ptr, slice};
|
||||
|
||||
use super::FONT;
|
||||
|
||||
/// A display
|
||||
pub struct Display {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub onscreen: &'static mut [u32],
|
||||
pub offscreen: Option<Box<[u32]>>
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub fn new(width: usize, height: usize, onscreen_ptr: *mut u32) -> Display {
|
||||
let size = width * height;
|
||||
let onscreen = unsafe {
|
||||
ptr::write_bytes(onscreen_ptr, 0, size);
|
||||
slice::from_raw_parts_mut(onscreen_ptr, size)
|
||||
};
|
||||
Display {
|
||||
width,
|
||||
height,
|
||||
onscreen,
|
||||
offscreen: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data_mut(&mut self) -> &mut [u32] {
|
||||
match &mut self.offscreen {
|
||||
Some(offscreen) => offscreen,
|
||||
None => self.onscreen,
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw a character
|
||||
pub fn char(&mut self, x: usize, y: usize, character: char, color: u32) {
|
||||
if x + 8 <= self.width && y + 16 <= self.height {
|
||||
let mut dst = self.data_mut().as_mut_ptr() as usize + (y * self.width + x) * 4;
|
||||
|
||||
let font_i = 16 * (character as usize);
|
||||
if font_i + 16 <= FONT.len() {
|
||||
for row in 0..16 {
|
||||
let row_data = FONT[font_i + row];
|
||||
for col in 0..8 {
|
||||
if (row_data >> (7 - col)) & 1 == 1 {
|
||||
unsafe { *((dst + col * 4) as *mut u32) = color; }
|
||||
}
|
||||
}
|
||||
dst += self.width * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Scroll the screen
|
||||
pub fn scroll(&mut self, lines: usize) {
|
||||
let offset = cmp::min(self.height, lines) * self.width;
|
||||
let size = (self.width * self.height) - offset;
|
||||
unsafe {
|
||||
let ptr = self.data_mut().as_mut_ptr();
|
||||
ptr::copy(ptr.add(offset), ptr, size);
|
||||
ptr::write_bytes(ptr.add(size), 0, offset);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sync from offscreen to onscreen, unsafe because it trusts provided x, y, w, h
|
||||
pub unsafe fn sync(&mut self, x: usize, y: usize, w: usize, mut h: usize) {
|
||||
if let Some(offscreen) = &self.offscreen {
|
||||
let mut offset = y * self.width + x;
|
||||
while h > 0 {
|
||||
self.onscreen[offset..offset+w].copy_from_slice(
|
||||
&offscreen[offset..offset+w]
|
||||
);
|
||||
offset += self.width;
|
||||
h -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
src/devices/graphical_debug/mod.rs
Normal file
70
src/devices/graphical_debug/mod.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use core::str;
|
||||
use spin::Mutex;
|
||||
|
||||
pub use self::debug::DebugDisplay;
|
||||
use self::display::Display;
|
||||
|
||||
pub mod debug;
|
||||
pub mod display;
|
||||
|
||||
pub static FONT: &'static [u8] = include_bytes!("../../../res/unifont.font");
|
||||
|
||||
pub static DEBUG_DISPLAY: Mutex<Option<DebugDisplay>> = Mutex::new(None);
|
||||
|
||||
pub fn init(env: &[u8]) {
|
||||
println!("Starting graphical debug");
|
||||
|
||||
let mut width = 0;
|
||||
let mut height = 0;
|
||||
let mut physbaseptr = 0;
|
||||
|
||||
//TODO: should errors be reported?
|
||||
for line in str::from_utf8(env).unwrap_or("").lines() {
|
||||
let mut parts = line.splitn(2, '=');
|
||||
let name = parts.next().unwrap_or("");
|
||||
let value = parts.next().unwrap_or("");
|
||||
|
||||
if name == "FRAMEBUFFER_ADDR" {
|
||||
physbaseptr = usize::from_str_radix(value, 16).unwrap_or(0);
|
||||
}
|
||||
|
||||
if name == "FRAMEBUFFER_WIDTH" {
|
||||
width = usize::from_str_radix(value, 16).unwrap_or(0);
|
||||
}
|
||||
|
||||
if name == "FRAMEBUFFER_HEIGHT" {
|
||||
height = usize::from_str_radix(value, 16).unwrap_or(0);
|
||||
}
|
||||
}
|
||||
|
||||
if physbaseptr == 0 || width == 0 || height == 0 {
|
||||
println!("Framebuffer not found");
|
||||
return;
|
||||
}
|
||||
|
||||
println!("Framebuffer {}x{} at {:X}", width, height, physbaseptr);
|
||||
|
||||
{
|
||||
let size = width * height * 4;
|
||||
|
||||
let virtbaseptr = physbaseptr + crate::PHYS_OFFSET;
|
||||
|
||||
let display = Display::new(width, height, virtbaseptr as *mut u32);
|
||||
let debug_display = DebugDisplay::new(display);
|
||||
*DEBUG_DISPLAY.lock() = Some(debug_display);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_heap() {
|
||||
if let Some(debug_display) = &mut *DEBUG_DISPLAY.lock() {
|
||||
debug_display.display.offscreen = Some(
|
||||
debug_display.display.onscreen.to_vec().into_boxed_slice()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fini() {
|
||||
DEBUG_DISPLAY.lock().take();
|
||||
|
||||
println!("Finished graphical debug");
|
||||
}
|
||||
Reference in New Issue
Block a user