From 01d75b971ac1ff8e48db0ea85a6efeb8d977056f Mon Sep 17 00:00:00 2001 From: Ryan Kennedy Date: Sat, 21 Mar 2020 23:40:40 -0500 Subject: [PATCH] Testing performance with different write modes --- src/colors.rs | 6 ++++++ src/vga.rs | 32 ++++++++++++++++++++++++++++-- src/writers/graphics_640x480x16.rs | 32 +++++++++++++----------------- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/colors.rs b/src/colors.rs index 236c6dc..8bc44de 100644 --- a/src/colors.rs +++ b/src/colors.rs @@ -41,6 +41,12 @@ pub enum Color16Bit { White = 0xF, } +impl From for u8 { + fn from(value: Color16Bit) -> u8 { + value as u8 + } +} + /// Represents a color for vga text modes. #[derive(Debug, Copy, Clone)] #[repr(transparent)] diff --git a/src/vga.rs b/src/vga.rs index 6e47adc..5e32437 100644 --- a/src/vga.rs +++ b/src/vga.rs @@ -1,7 +1,7 @@ //! Provides access to the vga graphics card. use super::{ - colors::PALETTE_SIZE, + colors::{Color16Bit, PALETTE_SIZE}, configurations::{ VgaConfiguration, MODE_40X25_CONFIGURATION, MODE_40X50_CONFIGURATION, MODE_640X480X16_CONFIGURATION, MODE_80X25_CONFIGURATION, @@ -89,6 +89,8 @@ impl From for u8 { bitflags! { /// Represents the plane masks of the `SequencerIndex::PlaneMask` register. pub struct PlaneMask: u8 { + /// Represents none of the plane masks of vga memory. + const NONE = 0b0000_0000; /// Represents `Plane0` of vga memory. const PLANE0 = 0b0000_0001; /// Represents `Plane1` of vga memory. @@ -97,7 +99,7 @@ bitflags! { const PLANE2 = 0b0000_0100; /// Represents `Plane3` of vga memory. const PLANE3 = 0b0000_1000; - /// Represents a combination of all the plane masks. + /// Represents all of the plane masks of vga memory. const ALL_PLANES = Self::PLANE0.bits() | Self::PLANE1.bits() | Self::PLANE2.bits() | Self::PLANE3.bits(); } } @@ -351,6 +353,32 @@ impl Vga { .write(GraphicsControllerIndex::ReadPlaneSelect, read_plane); } + /// Sets the value to use for `GraphicsControllerIndex::SetReset`, + /// as spcified by `color`. + pub fn set_graphics_set_reset(&mut self, color: Color16Bit) { + let original_value = self + .graphics_controller_registers + .read(GraphicsControllerIndex::SetReset) + & 0xF0; + self.graphics_controller_registers.write( + GraphicsControllerIndex::SetReset, + original_value | u8::from(color), + ); + } + + /// Sets which planes are effected by `GraphicsControllerIndex::SetReset`, + /// as specified by `plane_mask`. + pub fn set_graphics_enable_set_reset(&mut self, plane_mask: PlaneMask) { + let original_value = self + .graphics_controller_registers + .read(GraphicsControllerIndex::EnableSetReset) + & 0xF0; + self.graphics_controller_registers.write( + GraphicsControllerIndex::EnableSetReset, + original_value | u8::from(plane_mask), + ); + } + fn set_registers(&mut self, configuration: &VgaConfiguration) { let emulation_mode = self.get_emulation_mode(); diff --git a/src/writers/graphics_640x480x16.rs b/src/writers/graphics_640x480x16.rs index 59c9a1c..e2f57ec 100644 --- a/src/writers/graphics_640x480x16.rs +++ b/src/writers/graphics_640x480x16.rs @@ -2,7 +2,6 @@ use crate::{ colors::{Color16Bit, DEFAULT_PALETTE}, vga::{PlaneMask, Vga, VideoMode, VGA}, }; -use core::convert::TryInto; use spinning_top::SpinlockGuard; const WIDTH: usize = 640; @@ -36,6 +35,7 @@ impl Graphics640x480x16 { pub fn clear_screen(&self) { let (mut vga, frame_buffer) = self.get_frame_buffer(); vga.set_plane_mask(PlaneMask::ALL_PLANES); + vga.set_graphics_enable_set_reset(PlaneMask::NONE); for offset in 0..ALL_PLANES_SCREEN_SIZE { unsafe { frame_buffer @@ -50,24 +50,20 @@ impl Graphics640x480x16 { let (mut vga, frame_buffer) = self.get_frame_buffer(); let offset = x / 8 + (WIDTH / 8) * y; - // Store the current value for masking. - let x = x & 7; - let mask = 0x80 >> (x & 7); - let mut plane_mask = 0x01; + // Write to all 4 planes + vga.set_plane_mask(PlaneMask::ALL_PLANES); - 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 - } else { - current_value & !mask - }; - unsafe { - frame_buffer.add(offset).write_volatile(new_value); - } - plane_mask <<= 1; + // Set the bits we want set/reset to the color + vga.set_graphics_set_reset(color); + + // Enable set/reset for all planes + vga.set_graphics_enable_set_reset(PlaneMask::ALL_PLANES); + unsafe { + // In write mode 0, when enable set/reset is turned on, cpu data + // is replaced with the data from the set/reset register. Since + // we're using set/reset for all 4 planes, it doesn't matter what value + // we write to the memory address. + frame_buffer.add(offset).write(0x0); } }