1
0

Added VGA graphics

This commit is contained in:
Mark 2025-02-17 21:33:29 -08:00
parent fa2ff36610
commit 59df532105
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
3 changed files with 192 additions and 113 deletions

View File

@ -1,7 +1,7 @@
use linked_list_allocator::LockedHeap;
use spin::Mutex;
use crate::serial_println;
use tetris::TetrisBoard;
use vga::Vga13h;
use self::memory_map::memory_map;
use self::thunk::ThunkData;
@ -10,6 +10,7 @@ use crate::println;
mod memory_map;
mod panic;
mod tetris;
mod thunk;
mod vga;
@ -17,12 +18,11 @@ mod vga;
// 0x500 to 0x7BFF is free
const MEMORY_MAP_ADDR: usize = 0x1380; // 24 bytes, ends at 0x1397
const THUNK_STACK_ADDR: usize = 0x7C00; // Grows downwards
const VGA_ADDR: usize = 0xB8000;
#[global_allocator]
static ALLOCATOR: LockedHeap = LockedHeap::empty();
pub(crate) static VGA: Mutex<Vga> = Mutex::new(unsafe { Vga::new(VGA_ADDR, 80, 25) });
pub(crate) static VGA: Mutex<Vga13h> = Mutex::new(unsafe { Vga13h::new() });
#[no_mangle]
pub unsafe extern "C" fn start(
@ -35,9 +35,9 @@ pub unsafe extern "C" fn start(
println!("Entered Rust, serial ready.");
{
// Make sure we are in mode 3 (80x25 text mode)
// Set vga mode
let mut data = ThunkData::new();
data.eax = 0x03;
data.eax = 0x13;
data.with(thunk10);
}
@ -50,7 +50,19 @@ pub unsafe extern "C" fn start(
}
// Clear screen
VGA.lock().clear();
let mut v = VGA.lock();
/*
let fb = v.get_fb();
let mut c: u8 = 0;
for x in 0..128 {
for y in 0..128 {
let idx = Vga13h::pix_idx(x, y);
fb[idx] = c;
c = c.wrapping_add(1);
}
}
*/
let (heap_start, heap_size) = memory_map(thunk15).expect("No memory for heap");

View File

@ -0,0 +1,119 @@
use core::{fmt, slice};
#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct VgaTextBlock {
pub char: u8,
pub color: u8,
}
#[allow(dead_code)]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum VgaTextColor {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Purple = 5,
Brown = 6,
Gray = 7,
DarkGray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
LightPurple = 13,
Yellow = 14,
White = 15,
}
pub struct Vga {
pub base: usize,
pub width: usize,
pub height: usize,
pub x: usize,
pub y: usize,
pub bg: VgaTextColor,
pub fg: VgaTextColor,
}
impl Vga {
pub const unsafe fn new(base: usize, width: usize, height: usize) -> Self {
Self {
base,
width,
height,
x: 0,
y: 0,
bg: VgaTextColor::Black,
fg: VgaTextColor::Gray,
}
}
pub unsafe fn blocks(&mut self) -> &'static mut [VgaTextBlock] {
slice::from_raw_parts_mut(self.base as *mut VgaTextBlock, self.width * self.height)
}
pub fn clear(&mut self) {
self.x = 0;
self.y = 0;
let blocks = unsafe { self.blocks() };
for i in 0..blocks.len() {
blocks[i] = VgaTextBlock {
char: 0,
color: ((self.bg as u8) << 4) | (self.fg as u8),
};
}
}
}
impl fmt::Write for Vga {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
let blocks = unsafe { self.blocks() };
for c in s.chars() {
if self.x >= self.width {
self.x = 0;
self.y += 1;
}
while self.y >= self.height {
for y in 1..self.height {
for x in 0..self.width {
let i = y * self.width + x;
let j = i - self.width;
blocks[j] = blocks[i];
if y + 1 == self.height {
blocks[i].char = 0;
}
}
}
self.y -= 1;
}
match c {
'\x08' => {
if self.x > 0 {
self.x -= 1;
}
}
'\r' => {
self.x = 0;
}
'\n' => {
self.x = 0;
self.y += 1;
}
_ => {
let i = self.y * self.width + self.x;
if let Some(block) = blocks.get_mut(i) {
block.char = c as u8;
block.color = ((self.bg as u8) << 4) | (self.fg as u8);
}
self.x += 1;
}
}
}
Ok(())
}
}

View File

@ -1,119 +1,67 @@
use core::{fmt, slice};
use core::slice;
#[derive(Clone, Copy)]
#[repr(C, packed)]
pub struct VgaTextBlock {
pub char: u8,
pub color: u8,
/// 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,
}
#[allow(dead_code)]
#[derive(Clone, Copy)]
#[repr(u8)]
pub enum VgaTextColor {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Purple = 5,
Brown = 6,
Gray = 7,
DarkGray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
LightPurple = 13,
Yellow = 14,
White = 15,
}
impl Vga13h {
pub const WIDTH: usize = 320;
pub const HEIGHT: usize = 200;
pub const ADDR: usize = 0xA0000;
pub struct Vga {
pub base: usize,
pub width: usize,
pub height: usize,
pub x: usize,
pub y: usize,
pub bg: VgaTextColor,
pub fg: VgaTextColor,
}
impl Vga {
pub const unsafe fn new(base: usize, width: usize, height: usize) -> Self {
pub const unsafe fn new() -> Self {
Self {
base,
width,
height,
x: 0,
y: 0,
bg: VgaTextColor::Black,
fg: VgaTextColor::Gray,
fb_a: [0; Vga13h::WIDTH * Vga13h::HEIGHT],
fb_b: [0; Vga13h::WIDTH * Vga13h::HEIGHT],
show_fb_a: true,
}
}
pub unsafe fn blocks(&mut self) -> &'static mut [VgaTextBlock] {
slice::from_raw_parts_mut(self.base as *mut VgaTextBlock, self.width * self.height)
unsafe fn segment(&mut self) -> &'static mut [u8] {
slice::from_raw_parts_mut(Vga13h::ADDR as *mut u8, Vga13h::WIDTH * Vga13h::HEIGHT)
}
pub fn clear(&mut self) {
self.x = 0;
self.y = 0;
let blocks = unsafe { self.blocks() };
for i in 0..blocks.len() {
blocks[i] = VgaTextBlock {
char: 0,
color: ((self.bg as u8) << 4) | (self.fg as u8),
};
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
} else {
seg.copy_from_slice(&self.fb_a);
self.show_fb_a = true
}
}
}
impl fmt::Write for Vga {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
let blocks = unsafe { self.blocks() };
for c in s.chars() {
if self.x >= self.width {
self.x = 0;
self.y += 1;
}
while self.y >= self.height {
for y in 1..self.height {
for x in 0..self.width {
let i = y * self.width + x;
let j = i - self.width;
blocks[j] = blocks[i];
if y + 1 == self.height {
blocks[i].char = 0;
}
}
}
self.y -= 1;
}
match c {
'\x08' => {
if self.x > 0 {
self.x -= 1;
}
}
'\r' => {
self.x = 0;
}
'\n' => {
self.x = 0;
self.y += 1;
}
_ => {
let i = self.y * self.width + self.x;
if let Some(block) = blocks.get_mut(i) {
block.char = c as u8;
block.color = ((self.bg as u8) << 4) | (self.fg as u8);
}
self.x += 1;
}
}
}
Ok(())
}
pub fn get_fb(&mut self) -> &mut [u8; Vga13h::WIDTH * Vga13h::HEIGHT] {
unsafe { self.segment().try_into().unwrap() }
/*
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;
}
}