added readme
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
use core::ptr::write_volatile;
|
||||
|
||||
/// VGA text mode display dimensions.
|
||||
///
|
||||
/// The standard VGA text mode provides an 80×25 grid of character cells.
|
||||
/// Each cell is 2 bytes: [ASCII byte] [attribute byte].
|
||||
/// The buffer starts at physical address 0xB8000 and is memory-mapped into
|
||||
/// the CPU's address space. The x86_64 bootloader identity-maps this region,
|
||||
/// so we can write to it with regular memory stores — but we must use volatile
|
||||
/// writes to prevent the compiler from optimizing away MMIO operations.
|
||||
pub const VGA_ADDR: *mut u8 = 0xB8000 as *mut u8;
|
||||
pub const WIDTH: usize = 80;
|
||||
pub const HEIGHT: usize = 25;
|
||||
|
||||
/// Standard VGA text-mode colors.
|
||||
///
|
||||
/// The attribute byte layout:
|
||||
/// bits 0-3: foreground color (0 = black, 15 = white)
|
||||
/// bits 4-6: background color (0-7, hardware limit; bit 7 = blink)
|
||||
#[allow(dead_code)]
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Color {
|
||||
Black = 0,
|
||||
Blue = 1,
|
||||
Green = 2,
|
||||
Cyan = 3,
|
||||
Red = 4,
|
||||
Magenta = 5,
|
||||
Brown = 6,
|
||||
LightGray = 7,
|
||||
DarkGray = 8,
|
||||
LightBlue = 9,
|
||||
LightGreen = 10,
|
||||
LightCyan = 11,
|
||||
LightRed = 12,
|
||||
Pink = 13,
|
||||
Yellow = 14,
|
||||
White = 15,
|
||||
}
|
||||
|
||||
/// A packed attribute byte encoding foreground + background color.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ColorCode(u8);
|
||||
|
||||
impl ColorCode {
|
||||
/// Constructs a color code from foreground and background colors.
|
||||
///
|
||||
/// ## Hardware note
|
||||
/// The VGA attribute byte stores the background color in bits 4-6 (3 bits,
|
||||
/// limiting backgrounds to 0-7). Bit 7 is the blink enable bit, which we
|
||||
/// keep cleared. The foreground color uses bits 0-3 (including intensity
|
||||
/// on bit 3), giving 16 possible foreground colors.
|
||||
pub const fn new(fg: Color, bg: Color) -> ColorCode {
|
||||
ColorCode(((bg as u8) << 4) | (fg as u8))
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the entire VGA screen to the given background color.
|
||||
///
|
||||
/// Writes a space character (0x20) with the appropriate attribute byte
|
||||
/// to every cell on the screen.
|
||||
pub fn clear_screen(bg: Color) {
|
||||
let color = ColorCode::new(Color::White, bg);
|
||||
for offset in (0..(WIDTH * HEIGHT * 2)).step_by(2) {
|
||||
unsafe {
|
||||
write_volatile(VGA_ADDR.add(offset), b' ');
|
||||
write_volatile(VGA_ADDR.add(offset + 1), color.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a single character at position (row, col) with the given color.
|
||||
///
|
||||
/// The position is bounds-checked against the 80×25 screen. Writes outside
|
||||
/// the visible area are silently ignored.
|
||||
pub fn write_char(row: usize, col: usize, ch: u8, color: ColorCode) {
|
||||
if row < HEIGHT && col < WIDTH {
|
||||
let offset = (row * WIDTH + col) * 2;
|
||||
unsafe {
|
||||
write_volatile(VGA_ADDR.add(offset), ch);
|
||||
write_volatile(VGA_ADDR.add(offset + 1), color.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a string starting at position (row, col) with the given color.
|
||||
///
|
||||
/// Stops at the right edge of the screen to avoid wrapping.
|
||||
pub fn write_str(row: usize, col: usize, s: &str, color: ColorCode) {
|
||||
for (i, &ch) in s.as_bytes().iter().enumerate() {
|
||||
if col + i < WIDTH {
|
||||
write_char(row, col + i, ch, color);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user