From 86c575e7bc35b01358e44744d509c24a1ab52174 Mon Sep 17 00:00:00 2001 From: Ryan Kennedy Date: Sat, 21 Mar 2020 22:05:53 -0500 Subject: [PATCH] Plane refactor --- Cargo.toml | 1 + src/registers.rs | 2 +- src/vga.rs | 79 ++++++++++++++++++++++++------ src/writers/graphics_640x480x16.rs | 12 ++--- 4 files changed, 73 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 91d4fe4..e931d8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ repository = "https://github.com/rust-osdev/vga" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bitflags = "1.2.1" conquer-once = { version = "0.2.0", default-features = false } spinning_top = { version = "0.1.0", features = ["nightly"] } x86_64 = "0.9.6" diff --git a/src/registers.rs b/src/registers.rs index 0d3ef39..3589278 100644 --- a/src/registers.rs +++ b/src/registers.rs @@ -58,7 +58,7 @@ pub enum SequencerIndex { SequencerReset = 0x0, /// Represents the `Clocking Mode` register index. ClockingMode = 0x1, - /// Represents the Plane/Map mask register index. + /// Represents the `Plane/Map` mask register index. PlaneMask = 0x2, /// Represents the `Character Font` register index. CharacterFont = 0x3, diff --git a/src/vga.rs b/src/vga.rs index c717f81..44e6420 100644 --- a/src/vga.rs +++ b/src/vga.rs @@ -13,7 +13,9 @@ use super::{ GraphicsControllerIndex, GraphicsControllerRegisters, SequencerIndex, SequencerRegisters, }, }; +use bitflags::bitflags; use conquer_once::spin::Lazy; +use core::convert::TryFrom; use spinning_top::Spinlock; /// Provides mutable access to the vga graphics card. @@ -49,11 +51,11 @@ impl From for u32 { } } -/// Represents a plane for reading and writing vga data. +/// Represents a plane for the `GraphicsControllerIndex::ReadPlaneSelect` register. #[allow(dead_code)] #[derive(Debug, Copy, Clone)] #[repr(u8)] -pub enum Plane { +pub enum ReadPlane { /// Represents `Plane 0 (0x0)`. Plane0 = 0x0, /// Represents `Plane 1 (0x1)`. @@ -64,12 +66,60 @@ pub enum Plane { Plane3 = 0x3, } -impl From for u8 { - fn from(value: Plane) -> u8 { +impl TryFrom for ReadPlane { + type Error = &'static str; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(ReadPlane::Plane0), + 1 => Ok(ReadPlane::Plane1), + 2 => Ok(ReadPlane::Plane2), + 3 => Ok(ReadPlane::Plane3), + _ => Err("ReadPlane only accepts values between 0-3!"), + } + } +} + +impl From for u8 { + fn from(value: ReadPlane) -> u8 { value as u8 } } +bitflags! { + /// Represents the plane masks of the `SequencerIndex::PlaneMask` register. + pub struct PlaneMask: u8 { + /// Represents `Plane0` of vga memory. + const PLANE0 = 0b00000001; + /// Represents `Plane1` of vga memory. + const PLANE1 = 0b00000010; + /// Represents `Plane2` of vga memory. + const PLANE2 = 0b00000100; + /// Represents `Plane3` of vga memory. + const PLANE3 = 0b00001000; + } +} + +impl TryFrom for PlaneMask { + type Error = &'static str; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(PlaneMask::PLANE0), + 1 => Ok(PlaneMask::PLANE1), + 2 => Ok(PlaneMask::PLANE2), + 3 => Ok(PlaneMask::PLANE3), + _ => Err("PlaneMask only accepts values between 0-3!"), + } + } +} + +impl From for u8 { + fn from(value: PlaneMask) -> u8 { + value.bits() + } +} + /// Represents a specified vga video mode. #[derive(Debug, Clone, Copy)] pub enum VideoMode { @@ -226,7 +276,7 @@ impl Vga { ); // Write font to plane - self.set_plane(Plane::Plane2); + self.set_plane_mask(PlaneMask::PLANE2); let frame_buffer = u32::from(self.get_frame_buffer()) as *mut u8; @@ -286,16 +336,17 @@ impl Vga { ) } - /// Turns on the given `Plane` in the vga graphics card. - pub fn set_plane(&mut self, plane: Plane) { - let mut plane = u8::from(plane); - - plane &= 0x3; - - self.graphics_controller_registers - .write(GraphicsControllerIndex::ReadPlaneSelect, plane); + /// Sets the plane mask of the sequencer controller, as specified by `plane_mask`. + pub fn set_plane_mask(&mut self, plane_mask: PlaneMask) { self.sequencer_registers - .write(SequencerIndex::PlaneMask, 0x1 << plane); + .write(SequencerIndex::PlaneMask, u8::from(plane_mask)); + } + + /// Sets the read plane of the graphics controller, as specified by `read_plane`. + pub fn set_read_plane(&mut self, read_plane: ReadPlane) { + let read_plane = u8::from(read_plane) & 0x3; + self.graphics_controller_registers + .write(GraphicsControllerIndex::ReadPlaneSelect, read_plane); } fn set_registers(&mut self, configuration: &VgaConfiguration) { diff --git a/src/writers/graphics_640x480x16.rs b/src/writers/graphics_640x480x16.rs index 98eb549..8914011 100644 --- a/src/writers/graphics_640x480x16.rs +++ b/src/writers/graphics_640x480x16.rs @@ -1,14 +1,13 @@ use crate::{ colors::{Color16Bit, DEFAULT_PALETTE}, - vga::{Plane, Vga, VideoMode, VGA}, + vga::{Vga, VideoMode, VGA}, }; +use core::convert::TryInto; use spinning_top::SpinlockGuard; const WIDTH: usize = 640; const HEIGHT: usize = 480; -static PLANES: &[Plane] = &[Plane::Plane0, Plane::Plane1, Plane::Plane2, Plane::Plane3]; - /// A basic interface for interacting with vga graphics mode 640x480x16 /// /// # Examples @@ -37,7 +36,7 @@ impl Graphics640x480x16 { // TODO: Clear the screen by using 4-plane mode instead of slow `set_pixel`. for x in 0..WIDTH { for y in 0..HEIGHT { - self.set_pixel(x, y, Color16Bit::Yellow); + self.set_pixel(x, y, Color16Bit::Black); } } } @@ -56,8 +55,9 @@ impl Graphics640x480x16 { let mask = 0x80 >> (x & 7); let mut plane_mask = 0x01; - for plane in PLANES { - vga.set_plane(*plane); + for plane in 0u8..4u8 { + vga.set_read_plane(plane.try_into().unwrap()); + vga.set_plane_mask(plane.try_into().unwrap()); let current_value = unsafe { frame_buffer.add(offset).read_volatile() }; let new_value = if plane_mask & color as u8 != 0 { current_value | mask