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

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) }
}