You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.2 KiB
134 lines
3.2 KiB
use core::fmt::Write; |
|
|
|
use crate::rlibc::{SpinLock, memcpy, memsetw}; |
|
|
|
pub static mut SCREEN: SpinLock<Screen> = SpinLock::new(Screen::new((80, 25), 0xB8000 as *mut ())); |
|
|
|
#[allow(dead_code)] |
|
#[repr(u8)] |
|
#[derive(Copy, Clone)] |
|
pub enum BackgroundColor { |
|
Black = 0, |
|
Blue = 1, |
|
Green = 2, |
|
Cyan = 3, |
|
Red = 4, |
|
Magenta = 5, |
|
Brown = 6, |
|
LightGrey = 7 |
|
} |
|
|
|
#[allow(dead_code)] |
|
#[repr(u8)] |
|
#[derive(Copy, Clone)] |
|
pub enum ForegroundColor { |
|
DarkGrey = 0, |
|
LightBlue = 1, |
|
LightGreen = 2, |
|
LightCyan = 3, |
|
LightRed = 4, |
|
LightMagenta = 5, |
|
LightBrown = 6, |
|
White = 7 |
|
} |
|
|
|
#[repr(C)] |
|
pub struct ScreenChar(u8, u8); |
|
|
|
impl ScreenChar { |
|
pub fn new(background_color: BackgroundColor, foreground_color: ForegroundColor, char: char) -> Self { |
|
Self |
|
( char as u8, |
|
(((background_color as u8) << 4) & 0b11110000) | (foreground_color as u8 & 0b00001111) |
|
) |
|
} |
|
|
|
fn background_color(&self) -> u8 { |
|
self.0 & 0b11110000 >> 4 |
|
} |
|
|
|
fn foreground_color(&self) -> u8 { |
|
self.0 & 0b00001111 |
|
} |
|
|
|
fn char(&self) -> u8 { |
|
self.1 |
|
} |
|
} |
|
|
|
impl From<u16> for ScreenChar { |
|
fn from(word: u16) -> Self { |
|
ScreenChar((word & 0b11110000 >> 4) as u8, (word & 0b00001111) as u8) |
|
} |
|
} |
|
|
|
impl Into<u16> for ScreenChar { |
|
fn into(self) -> u16 { |
|
(self.0 as u16) | ((self.1 as u16) << 8) |
|
} |
|
} |
|
|
|
struct Screen { |
|
cursor: (u16, u16), |
|
size: (usize, usize), |
|
buffer: *mut ScreenChar |
|
} |
|
|
|
impl Screen { |
|
pub const fn new(size: (usize, usize), buffer: *mut ()) -> Self { |
|
Screen { |
|
cursor: (0, 0), |
|
size, |
|
buffer: buffer as *mut ScreenChar |
|
} |
|
} |
|
|
|
fn scroll(&mut self) { |
|
unsafe { |
|
for i in 0..self.size.1 { |
|
memcpy(self.buffer.add(i * self.size.0) as *mut u8, self.buffer.add((i + 1) * self.size.0) as *mut u8, self.size.1 * 2); |
|
} |
|
memsetw(self.buffer.add(self.size.0* (self.size.1 - 1)) as *mut u16, ScreenChar::new(BackgroundColor::Black, ForegroundColor::White, ' ').into(), self.size.0); |
|
} |
|
} |
|
|
|
pub fn putc(&mut self, background_color: BackgroundColor, foreground_color: ForegroundColor, char: char) { |
|
if char == '\n' { |
|
self.cursor = (0, self.cursor.1 + 1); |
|
} else if char >= ' ' && char <= '~' { |
|
unsafe { |
|
self.buffer.add((self.cursor.1 * self.size.0 as u16) as usize + self.cursor.0 as usize).write_volatile(ScreenChar::new(background_color, foreground_color, char)) |
|
} |
|
self.cursor.0 += 1; |
|
} |
|
|
|
if self.cursor.0 >= self.size.0 as u16 { |
|
self.cursor = (0, self.cursor.1 + 1); |
|
} |
|
if self.cursor.1 >= self.size.1 as u16 { |
|
self.cursor.1 -= 1; |
|
self.scroll(); |
|
} |
|
} |
|
|
|
pub fn put_str(&mut self, background_color: BackgroundColor, foreground_color: ForegroundColor, str: &str) { |
|
for c in str.chars() { |
|
self.putc(background_color, foreground_color, c) |
|
} |
|
} |
|
} |
|
|
|
pub fn print(string: &str) { |
|
let mut screen = unsafe { SCREEN.take() }; |
|
|
|
screen.put_str(BackgroundColor::Black, ForegroundColor::White, string); |
|
unsafe { SCREEN.put(screen) } |
|
} |
|
|
|
pub fn println(string: &str) { |
|
let mut screen = unsafe { SCREEN.take() }; |
|
|
|
screen.put_str(BackgroundColor::Black, ForegroundColor::White, string); |
|
screen.putc(BackgroundColor::Black, ForegroundColor::White, '\n'); |
|
unsafe { SCREEN.put(screen) } |
|
}
|
|
|