1
0
Mark a1d788fd5f
All checks were successful
CI / Typos (push) Successful in 7s
CI / Build (push) Successful in 47s
CI / Clippy (push) Successful in 1m0s
Comments
2025-03-04 19:18:21 -08:00

117 lines
2.3 KiB
Rust

use core::slice;
use rand::seq::IndexedRandom;
use crate::RNG;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VgaColor {
Black,
Gray,
Blue,
Cyan,
Orange,
Red,
Green,
Purple,
Yellow,
}
impl VgaColor {
pub fn as_u8(self) -> u8 {
match self {
Self::Black => 0b0000_0000,
Self::Gray => 0b1110_0000,
Self::Blue => 0b0000_0001,
Self::Cyan => 0b0000_0011,
Self::Orange => 0b0000_0110,
Self::Red => 0b0000_0100,
Self::Green => 0b0000_0010,
Self::Purple => 0b0000_0101,
Self::Yellow => 0b1100_0000,
}
}
/// Pick a random non-utility color
pub fn choose_rand() -> Self {
let colors = [
VgaColor::Blue,
VgaColor::Cyan,
VgaColor::Orange,
VgaColor::Red,
VgaColor::Green,
VgaColor::Purple,
VgaColor::Yellow,
];
let mut rng = RNG.lock();
*(colors.choose(&mut rng).unwrap())
}
}
/// VGA driver for mode 0x13:
///
/// - mode: graphics
/// - text res: 40x25
/// - pixel box: 8x8
/// - pixel res: 320x200
/// - colors: 256/256k
/// - addr: A000
/// - pixel format: RRRGGGBB
pub struct Vga13h {
// Double frame buffers
fb_a: [u8; Vga13h::WIDTH * Vga13h::HEIGHT],
fb_b: [u8; Vga13h::WIDTH * Vga13h::HEIGHT],
/// If true, show fb_a (and write to fb_b).
/// if false, show fb_b.
show_fb_a: bool,
}
impl Vga13h {
pub const WIDTH: usize = 320;
pub const HEIGHT: usize = 200;
pub const ADDR: usize = 0xA0000;
/// Initialize a new VGA driver.
///
/// Only one of these should exist.
pub const unsafe fn new() -> Self {
Self {
fb_a: [0; Vga13h::WIDTH * Vga13h::HEIGHT],
fb_b: [0; Vga13h::WIDTH * Vga13h::HEIGHT],
show_fb_a: true,
}
}
unsafe fn segment(&mut self) -> &'static mut [u8] {
slice::from_raw_parts_mut(Vga13h::ADDR as *mut u8, Vga13h::WIDTH * Vga13h::HEIGHT)
}
pub fn swap(&mut self) {
let seg = unsafe { self.segment() };
if self.show_fb_a {
seg.copy_from_slice(&self.fb_b);
self.show_fb_a = false;
self.fb_a.fill(0);
} else {
seg.copy_from_slice(&self.fb_a);
self.show_fb_a = true;
self.fb_b.fill(0);
}
}
pub fn get_fb(&mut self) -> &mut [u8; Vga13h::WIDTH * Vga13h::HEIGHT] {
if self.show_fb_a {
&mut self.fb_b
} else {
&mut self.fb_a
}
}
pub fn pix_idx(x: usize, y: usize) -> usize {
debug_assert!(x < Vga13h::WIDTH);
debug_assert!(y < Vga13h::HEIGHT);
return y * Vga13h::WIDTH + x;
}
}