added readme

This commit is contained in:
2026-06-04 04:20:07 -04:00
commit 1217b4beaa
14 changed files with 1330 additions and 0 deletions
+98
View File
@@ -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;
}
}
}