From 3eae6fb32d876cd64bf3171b0c70a54906243589 Mon Sep 17 00:00:00 2001 From: Ryan Kennedy Date: Sun, 22 Mar 2020 18:41:14 -0500 Subject: [PATCH] Initial refactor of registers --- src/registers.rs | 510 -------------------------- src/registers/attribute_controller.rs | 145 ++++++++ src/registers/color_palette.rs | 44 +++ src/registers/crtc_controller.rs | 122 ++++++ src/registers/general.rs | 42 +++ src/registers/graphics_controller.rs | 71 ++++ src/registers/mod.rs | 64 ++++ src/registers/sequencer.rs | 59 +++ 8 files changed, 547 insertions(+), 510 deletions(-) delete mode 100644 src/registers.rs create mode 100644 src/registers/attribute_controller.rs create mode 100644 src/registers/color_palette.rs create mode 100644 src/registers/crtc_controller.rs create mode 100644 src/registers/general.rs create mode 100644 src/registers/graphics_controller.rs create mode 100644 src/registers/mod.rs create mode 100644 src/registers/sequencer.rs diff --git a/src/registers.rs b/src/registers.rs deleted file mode 100644 index 3589278..0000000 --- a/src/registers.rs +++ /dev/null @@ -1,510 +0,0 @@ -//! Common registers used in vga programming. - -use crate::colors::PALETTE_SIZE; -use x86_64::instructions::port::{Port, PortReadOnly, PortWriteOnly}; - -const ST00_READ_ADDRESS: u16 = 0x3C2; -const ST01_READ_CGA_ADDRESS: u16 = 0x3DA; -const ST01_READ_MDA_ADDRESS: u16 = 0x3BA; -const FCR_READ_ADDRESS: u16 = 0x3CA; -const FCR_CGA_WRITE_ADDRESS: u16 = 0x3DA; -const FCR_MDA_WRITE_ADDRESS: u16 = 0x3BA; -const MSR_READ_ADDRESS: u16 = 0x3CC; -const MSR_WRITE_ADDRESS: u16 = 0x3C2; - -const SRX_INDEX_ADDRESS: u16 = 0x3C4; -const SRX_DATA_ADDRESS: u16 = 0x3C5; - -const GRX_INDEX_ADDRESS: u16 = 0x3CE; -const GRX_DATA_ADDRESS: u16 = 0x3CF; - -const ARX_INDEX_ADDRESS: u16 = 0x3C0; -const ARX_DATA_ADDRESS: u16 = 0x3C1; - -const CRX_INDEX_CGA_ADDRESS: u16 = 0x3D4; -const CRX_INDEX_MDA_ADDRESS: u16 = 0x3B4; -const CRX_DATA_CGA_ADDRESS: u16 = 0x3D5; -const CRX_DATA_MDA_ADDRESS: u16 = 0x3B5; - -const COLOR_PALETTE_DATA_ADDRESS: u16 = 0x3C9; -const COLOR_PALETTE_INDEX_READ_ADDRESS: u16 = 0x3C7; -const COLOR_PALETTE_INDEX_WRITE_ADDRESSS: u16 = 0x3C8; - -/// Represents a vga emulation mode. -#[derive(Debug, Copy, Clone)] -#[repr(u8)] -pub enum EmulationMode { - /// Represents a monochrome emulation mode. - Mda = 0x0, - /// Respresents a color emulation mode. - Cga = 0x1, -} - -impl From for EmulationMode { - fn from(value: u8) -> EmulationMode { - match value { - 0x0 => EmulationMode::Mda, - 0x1 => EmulationMode::Cga, - _ => panic!("{} is an invalid emulation mode", value), - } - } -} - -/// Represents an index for the seqeuncer registers. -#[derive(Debug, Clone, Copy)] -#[repr(u8)] -pub enum SequencerIndex { - /// Represents the `Sequencer Reset` register index. - SequencerReset = 0x0, - /// Represents the `Clocking Mode` register index. - ClockingMode = 0x1, - /// Represents the `Plane/Map` mask register index. - PlaneMask = 0x2, - /// Represents the `Character Font` register index. - CharacterFont = 0x3, - /// Represents the `Memory Mode` register index. - MemoryMode = 0x4, - /// Represents the `Horizontal Character Counter Reset` register index. - CounterReset = 0x7, -} - -impl From for u8 { - fn from(value: SequencerIndex) -> u8 { - value as u8 - } -} - -/// Represents an index for the graphics controller registers. -#[derive(Debug, Copy, Clone)] -#[repr(u8)] -pub enum GraphicsControllerIndex { - /// Represents the `Set/Reset` register index. - SetReset = 0x0, - /// Represents the `Enable Set/Reset` register index. - EnableSetReset = 0x1, - /// Represents the `Color Compare` register index. - ColorCompare = 0x2, - /// Represents the `Data Rotate` register index. - DataRotate = 0x3, - /// Represents the `Read Plane Select` register index. - ReadPlaneSelect = 0x4, - /// Represents the `Graphics Mode` register index. - GraphicsMode = 0x5, - /// Represents the `Miscellaneous` register index. - Miscellaneous = 0x6, - /// Represents the `Color Don't Care` register index. - ColorDontCare = 0x7, - /// Represents the `Bit Mask` register index. - BitMask = 0x8, - /// Represents the `Address Mapping` register index. - AddressMapping = 0x10, - /// Represents the `Page Selector` register index. - PageSelector = 0x11, - /// Represents the `Software Flags` register index. - SoftwareFlags = 0x18, -} - -impl From for u8 { - fn from(value: GraphicsControllerIndex) -> u8 { - value as u8 - } -} - -/// Represents an index for the attribute controller registers. -#[derive(Debug, Copy, Clone)] -#[repr(u8)] -pub enum AttributeControllerIndex { - /// Represents the `Palette 0` register index. - PaletteRegister0 = 0x00, - /// Represents the `Palette 1` register index. - PaletteRegister1 = 0x01, - /// Represents the `Palette 2` register index. - PaletteRegister2 = 0x02, - /// Represents the `Palette 3` register index. - PaletteRegister3 = 0x03, - /// Represents the `Palette 4` register index. - PaletteRegister4 = 0x04, - /// Represents the `Palette 5` register index. - PaletteRegister5 = 0x05, - /// Represents the `Palette 6` register index. - PaletteRegister6 = 0x06, - /// Represents the `Palette 7` register index. - PaletteRegister7 = 0x07, - /// Represents the `Palette 8` register index. - PaletteRegister8 = 0x08, - /// Represents the `Palette 9` register index. - PaletteRegister9 = 0x09, - /// Represents the `Palette A` register index. - PaletteRegisterA = 0x0A, - /// Represents the `Palette B` register index. - PaletteRegisterB = 0x0B, - /// Represents the `Palette C` register index. - PaletteRegisterC = 0x0C, - /// Represents the `Palette D` register index. - PaletteRegisterD = 0x0D, - /// Represents the `Palette E` register index. - PaletteRegisterE = 0x0E, - /// Represents the `Palette F` register index. - PaletteRegisterF = 0x0F, - /// Represents the `Mode Control` register index. - ModeControl = 0x10, - /// Represents the `Overscan Color` register index. - OverscanColor = 0x11, - /// Represents the `Memory Plane Enable` register index. - MemoryPlaneEnable = 0x12, - /// Represents the `Horizontal Pixel Panning` register index. - HorizontalPixelPanning = 0x13, - /// Represents the `Color Select` register index. - ColorSelect = 0x14, -} - -impl From for u8 { - fn from(value: AttributeControllerIndex) -> u8 { - value as u8 - } -} - -/// Represents an index for the crtc controller registers. -#[derive(Debug, Copy, Clone)] -#[repr(u8)] -pub enum CrtcControllerIndex { - /// Represents the `Horizontal Total` register index. - HorizontalTotal = 0x00, - /// Represents the `Horizontal Display Enable End` register index. - HorizontalDisplayEnableEnd = 0x01, - /// Represents the `Horizontal Blanking Start` register index. - HorizontalBlankingStart = 0x02, - /// Represents the `Horizontal Blanking End` register index. - HorizontalBlankingEnd = 0x03, - /// Represents the `Horizontal Sync Start` register index. - HorizontalSyncStart = 0x04, - /// Represents the `Horizontal Sync End` register index. - HorizontalSyncEnd = 0x05, - /// Represents the `Vertical Total` register index. - VeritcalTotal = 0x06, - /// Represents the `Overflow` register index. - Overflow = 0x07, - /// Represents the `Preset Row Scan` register index. - PresetRowScan = 0x08, - /// Represents the `Maximum Scan Line` register index. - MaximumScanLine = 0x09, - /// Represents the `Text Cursor Start` register index. - TextCursorStart = 0x0A, - /// Represents the `Text Cursor End` register index. - TextCursorEnd = 0x0B, - /// Represents the `Start Address High` register index. - StartAddressHigh = 0x0C, - /// Represents the `Start Address Low` register index. - StartAddressLow = 0x0D, - /// Represents the `Text Cursor Location High` register index. - TextCursorLocationHigh = 0x0E, - /// Represents the `Text Cursor Location Low` register index. - TextCursorLocationLow = 0x0F, - /// Represents the `Vertical Sync Start` register index. - VerticalSyncStart = 0x10, - /// Represents the `Vertical Sync End` register index. - VerticalSyncEnd = 0x11, - /// Represents the `Vertical Display Enable End` register index - VerticalDisplayEnableEnd = 0x12, - /// Represents the `Offset` register index. - Offset = 0x13, - /// Represents the `Underline Location` register index. - UnderlineLocation = 0x14, - /// Represents the `Vertical Blanking Start` register index. - VerticalBlankingStart = 0x15, - /// Represents the `Vertical Blanking End` register index. - VerticalBlankingEnd = 0x16, - /// Represents the `Mode Control` register index. - ModeControl = 0x17, - /// Represents the `Line Compare` register index. - LineCompare = 0x18, - /// Represents the `Memory Read Latch Data` register index. - MemoryReadLatchData = 0x22, - /// Represents the `Toggle State Of Attribute Controller` register index. - ToggleStateOfAttributeController = 0x24, -} - -impl From for u8 { - fn from(value: CrtcControllerIndex) -> u8 { - value as u8 - } -} - -#[derive(Debug)] -pub(crate) struct GeneralRegisters { - st00_read: PortReadOnly, - st01_read_cga: PortReadOnly, - st01_read_mda: PortReadOnly, - fcr_read: PortReadOnly, - fcr_write_cga: PortWriteOnly, - fcr_write_mda: PortWriteOnly, - msr_read: PortReadOnly, - msr_write: PortWriteOnly, -} - -impl GeneralRegisters { - pub fn new() -> GeneralRegisters { - GeneralRegisters { - st00_read: PortReadOnly::new(ST00_READ_ADDRESS), - st01_read_cga: PortReadOnly::new(ST01_READ_CGA_ADDRESS), - st01_read_mda: PortReadOnly::new(ST01_READ_MDA_ADDRESS), - fcr_read: PortReadOnly::new(FCR_READ_ADDRESS), - fcr_write_cga: PortWriteOnly::new(FCR_CGA_WRITE_ADDRESS), - fcr_write_mda: PortWriteOnly::new(FCR_MDA_WRITE_ADDRESS), - msr_read: PortReadOnly::new(MSR_READ_ADDRESS), - msr_write: PortWriteOnly::new(MSR_WRITE_ADDRESS), - } - } - - pub fn read_msr(&mut self) -> u8 { - unsafe { self.msr_read.read() } - } - - pub fn write_msr(&mut self, value: u8) { - unsafe { - self.msr_write.write(value); - } - } -} - -#[derive(Debug)] -pub(crate) struct SequencerRegisters { - srx_index: Port, - srx_data: Port, -} - -impl SequencerRegisters { - pub fn new() -> SequencerRegisters { - SequencerRegisters { - srx_index: Port::new(SRX_INDEX_ADDRESS), - srx_data: Port::new(SRX_DATA_ADDRESS), - } - } - - pub fn read(&mut self, index: SequencerIndex) -> u8 { - self.set_index(index); - unsafe { self.srx_data.read() } - } - - pub fn write(&mut self, index: SequencerIndex, value: u8) { - self.set_index(index); - unsafe { - self.srx_data.write(value); - } - } - - fn set_index(&mut self, index: SequencerIndex) { - unsafe { - self.srx_index.write(u8::from(index)); - } - } -} - -#[derive(Debug)] -pub(crate) struct GraphicsControllerRegisters { - grx_index: Port, - grx_data: Port, -} - -impl GraphicsControllerRegisters { - pub fn new() -> GraphicsControllerRegisters { - GraphicsControllerRegisters { - grx_index: Port::new(GRX_INDEX_ADDRESS), - grx_data: Port::new(GRX_DATA_ADDRESS), - } - } - - pub fn read(&mut self, index: GraphicsControllerIndex) -> u8 { - self.set_index(index); - unsafe { self.grx_data.read() } - } - - pub fn write(&mut self, index: GraphicsControllerIndex, value: u8) { - self.set_index(index); - unsafe { - self.grx_data.write(value); - } - } - - fn set_index(&mut self, index: GraphicsControllerIndex) { - unsafe { - self.grx_index.write(u8::from(index)); - } - } -} - -#[derive(Debug)] -pub(crate) struct AttributeControllerRegisters { - arx_index: Port, - arx_data: Port, - st01_read_cga: Port, - st01_read_mda: Port, -} - -impl AttributeControllerRegisters { - pub fn new() -> AttributeControllerRegisters { - AttributeControllerRegisters { - arx_index: Port::new(ARX_INDEX_ADDRESS), - arx_data: Port::new(ARX_DATA_ADDRESS), - st01_read_cga: Port::new(ST01_READ_CGA_ADDRESS), - st01_read_mda: Port::new(ST01_READ_MDA_ADDRESS), - } - } - - pub fn read(&mut self, emulation_mode: EmulationMode, index: AttributeControllerIndex) -> u8 { - self.toggle_index(emulation_mode); - self.set_index(index); - unsafe { self.arx_data.read() } - } - - pub fn write( - &mut self, - emulation_mode: EmulationMode, - index: AttributeControllerIndex, - value: u8, - ) { - self.toggle_index(emulation_mode); - self.set_index(index); - unsafe { - self.arx_index.write(value); - } - } - - fn set_index(&mut self, index: AttributeControllerIndex) { - unsafe { - self.arx_index.write(u8::from(index)); - } - } - - fn toggle_index(&mut self, emulation_mode: EmulationMode) { - let st01_read = match emulation_mode { - EmulationMode::Cga => &mut self.st01_read_cga, - EmulationMode::Mda => &mut self.st01_read_mda, - }; - unsafe { - st01_read.read(); - } - } - - /// Video Enable. Note that In the VGA standard, this is called the "Palette Address Source" bit. - /// Clearing this bit will cause the VGA display data to become all 00 index values. For the default - /// palette, this will cause a black screen. The video timing signals continue. Another control bit will - /// turn video off and stop the data fetches. - /// - /// 0 = Disable. Attribute controller color registers (AR[00:0F]) can be accessed by the CPU. - /// - /// 1 = Enable. Attribute controller color registers (AR[00:0F]) are inaccessible by the CPU. - pub fn blank_screen(&mut self, emulation_mode: EmulationMode) { - self.toggle_index(emulation_mode); - let arx_index_value = unsafe { self.arx_index.read() }; - unsafe { - self.arx_index.write(arx_index_value & 0xDF); - } - } - - /// Video Enable. Note that In the VGA standard, this is called the "Palette Address Source" bit. - /// Clearing this bit will cause the VGA display data to become all 00 index values. For the default - /// palette, this will cause a black screen. The video timing signals continue. Another control bit will - /// turn video off and stop the data fetches. - /// - /// 0 = Disable. Attribute controller color registers (AR[00:0F]) can be accessed by the CPU. - /// - /// 1 = Enable. Attribute controller color registers (AR[00:0F]) are inaccessible by the CPU. - pub fn unblank_screen(&mut self, emulation_mode: EmulationMode) { - self.toggle_index(emulation_mode); - let arx_index_value = unsafe { self.arx_index.read() }; - unsafe { - self.arx_index.write(arx_index_value | 0x20); - } - } -} - -#[derive(Debug)] -pub(crate) struct CrtcControllerRegisters { - crx_index_cga: Port, - crx_index_mda: Port, - crx_data_cga: Port, - crx_data_mda: Port, -} - -impl CrtcControllerRegisters { - pub fn new() -> CrtcControllerRegisters { - CrtcControllerRegisters { - crx_index_cga: Port::new(CRX_INDEX_CGA_ADDRESS), - crx_index_mda: Port::new(CRX_INDEX_MDA_ADDRESS), - crx_data_cga: Port::new(CRX_DATA_CGA_ADDRESS), - crx_data_mda: Port::new(CRX_DATA_MDA_ADDRESS), - } - } - - pub fn read(&mut self, emulation_mode: EmulationMode, index: CrtcControllerIndex) -> u8 { - self.set_index(emulation_mode, index); - unsafe { self.get_data_port(emulation_mode).read() } - } - - pub fn write(&mut self, emulation_mode: EmulationMode, index: CrtcControllerIndex, value: u8) { - self.set_index(emulation_mode, index); - unsafe { - self.get_data_port(emulation_mode).write(value); - } - } - - fn set_index(&mut self, emulation_mode: EmulationMode, index: CrtcControllerIndex) { - unsafe { - self.get_index_port(emulation_mode).write(u8::from(index)); - } - } - - fn get_data_port(&mut self, emulation_mode: EmulationMode) -> &mut Port { - match emulation_mode { - EmulationMode::Cga => &mut self.crx_data_cga, - EmulationMode::Mda => &mut self.crx_data_mda, - } - } - - fn get_index_port(&mut self, emulation_mode: EmulationMode) -> &mut Port { - match emulation_mode { - EmulationMode::Cga => &mut self.crx_index_cga, - EmulationMode::Mda => &mut self.crx_index_mda, - } - } -} - -#[derive(Debug)] -pub(crate) struct ColorPaletteRegisters { - data_port: Port, - index_read_port: Port, - index_write_port: Port, -} - -impl ColorPaletteRegisters { - pub fn new() -> ColorPaletteRegisters { - ColorPaletteRegisters { - data_port: Port::new(COLOR_PALETTE_DATA_ADDRESS), - index_read_port: Port::new(COLOR_PALETTE_INDEX_READ_ADDRESS), - index_write_port: Port::new(COLOR_PALETTE_INDEX_WRITE_ADDRESSS), - } - } - - pub fn load_palette(&mut self, palette: &[u8; PALETTE_SIZE]) { - unsafe { - self.index_write_port.write(0); - } - for i in palette.iter() { - unsafe { - self.data_port.write(*i); - } - } - } - - pub fn read_palette(&mut self, palette: &mut [u8; PALETTE_SIZE]) { - unsafe { - self.index_read_port.write(0); - } - for byte in palette.iter_mut().take(PALETTE_SIZE) { - unsafe { - *byte = self.data_port.read(); - } - } - } -} diff --git a/src/registers/attribute_controller.rs b/src/registers/attribute_controller.rs new file mode 100644 index 0000000..63554e9 --- /dev/null +++ b/src/registers/attribute_controller.rs @@ -0,0 +1,145 @@ +use super::{ + EmulationMode, ARX_DATA_ADDRESS, ARX_INDEX_ADDRESS, ST01_READ_CGA_ADDRESS, + ST01_READ_MDA_ADDRESS, +}; +use x86_64::instructions::port::Port; + +/// Represents an index for the attribute controller registers. +#[derive(Debug, Copy, Clone)] +#[repr(u8)] +pub enum AttributeControllerIndex { + /// Represents the `Palette 0` register index. + PaletteRegister0 = 0x00, + /// Represents the `Palette 1` register index. + PaletteRegister1 = 0x01, + /// Represents the `Palette 2` register index. + PaletteRegister2 = 0x02, + /// Represents the `Palette 3` register index. + PaletteRegister3 = 0x03, + /// Represents the `Palette 4` register index. + PaletteRegister4 = 0x04, + /// Represents the `Palette 5` register index. + PaletteRegister5 = 0x05, + /// Represents the `Palette 6` register index. + PaletteRegister6 = 0x06, + /// Represents the `Palette 7` register index. + PaletteRegister7 = 0x07, + /// Represents the `Palette 8` register index. + PaletteRegister8 = 0x08, + /// Represents the `Palette 9` register index. + PaletteRegister9 = 0x09, + /// Represents the `Palette A` register index. + PaletteRegisterA = 0x0A, + /// Represents the `Palette B` register index. + PaletteRegisterB = 0x0B, + /// Represents the `Palette C` register index. + PaletteRegisterC = 0x0C, + /// Represents the `Palette D` register index. + PaletteRegisterD = 0x0D, + /// Represents the `Palette E` register index. + PaletteRegisterE = 0x0E, + /// Represents the `Palette F` register index. + PaletteRegisterF = 0x0F, + /// Represents the `Mode Control` register index. + ModeControl = 0x10, + /// Represents the `Overscan Color` register index. + OverscanColor = 0x11, + /// Represents the `Memory Plane Enable` register index. + MemoryPlaneEnable = 0x12, + /// Represents the `Horizontal Pixel Panning` register index. + HorizontalPixelPanning = 0x13, + /// Represents the `Color Select` register index. + ColorSelect = 0x14, +} + +impl From for u8 { + fn from(value: AttributeControllerIndex) -> u8 { + value as u8 + } +} + +#[derive(Debug)] +pub struct AttributeControllerRegisters { + arx_index: Port, + arx_data: Port, + st01_read_cga: Port, + st01_read_mda: Port, +} + +impl AttributeControllerRegisters { + pub fn new() -> AttributeControllerRegisters { + AttributeControllerRegisters { + arx_index: Port::new(ARX_INDEX_ADDRESS), + arx_data: Port::new(ARX_DATA_ADDRESS), + st01_read_cga: Port::new(ST01_READ_CGA_ADDRESS), + st01_read_mda: Port::new(ST01_READ_MDA_ADDRESS), + } + } + + pub fn read(&mut self, emulation_mode: EmulationMode, index: AttributeControllerIndex) -> u8 { + self.toggle_index(emulation_mode); + self.set_index(index); + unsafe { self.arx_data.read() } + } + + pub fn write( + &mut self, + emulation_mode: EmulationMode, + index: AttributeControllerIndex, + value: u8, + ) { + self.toggle_index(emulation_mode); + self.set_index(index); + unsafe { + self.arx_index.write(value); + } + } + + fn set_index(&mut self, index: AttributeControllerIndex) { + unsafe { + self.arx_index.write(u8::from(index)); + } + } + + fn toggle_index(&mut self, emulation_mode: EmulationMode) { + let st01_read = match emulation_mode { + EmulationMode::Cga => &mut self.st01_read_cga, + EmulationMode::Mda => &mut self.st01_read_mda, + }; + unsafe { + st01_read.read(); + } + } + + /// Video Enable. Note that In the VGA standard, this is called the "Palette Address Source" bit. + /// Clearing this bit will cause the VGA display data to become all 00 index values. For the default + /// palette, this will cause a black screen. The video timing signals continue. Another control bit will + /// turn video off and stop the data fetches. + /// + /// 0 = Disable. Attribute controller color registers (AR[00:0F]) can be accessed by the CPU. + /// + /// 1 = Enable. Attribute controller color registers (AR[00:0F]) are inaccessible by the CPU. + pub fn blank_screen(&mut self, emulation_mode: EmulationMode) { + self.toggle_index(emulation_mode); + let arx_index_value = unsafe { self.arx_index.read() }; + unsafe { + self.arx_index.write(arx_index_value & 0xDF); + } + } + + /// Video Enable. Note that In the VGA standard, this is called the "Palette Address Source" bit. + /// Clearing this bit will cause the VGA display data to become all 00 index values. For the default + /// palette, this will cause a black screen. The video timing signals continue. Another control bit will + /// turn video off and stop the data fetches. + /// + /// 0 = Disable. Attribute controller color registers (AR[00:0F]) can be accessed by the CPU. + /// + /// 1 = Enable. Attribute controller color registers (AR[00:0F]) are inaccessible by the CPU. + pub fn unblank_screen(&mut self, emulation_mode: EmulationMode) { + self.toggle_index(emulation_mode); + let arx_index_value = unsafe { self.arx_index.read() }; + unsafe { + self.arx_index.write(arx_index_value | 0x20); + } + } +} diff --git a/src/registers/color_palette.rs b/src/registers/color_palette.rs new file mode 100644 index 0000000..8f49f2f --- /dev/null +++ b/src/registers/color_palette.rs @@ -0,0 +1,44 @@ +use super::{ + COLOR_PALETTE_DATA_ADDRESS, COLOR_PALETTE_INDEX_READ_ADDRESS, + COLOR_PALETTE_INDEX_WRITE_ADDRESSS, PALETTE_SIZE, +}; +use x86_64::instructions::port::Port; + +#[derive(Debug)] +pub struct ColorPaletteRegisters { + data_port: Port, + index_read_port: Port, + index_write_port: Port, +} + +impl ColorPaletteRegisters { + pub fn new() -> ColorPaletteRegisters { + ColorPaletteRegisters { + data_port: Port::new(COLOR_PALETTE_DATA_ADDRESS), + index_read_port: Port::new(COLOR_PALETTE_INDEX_READ_ADDRESS), + index_write_port: Port::new(COLOR_PALETTE_INDEX_WRITE_ADDRESSS), + } + } + + pub fn load_palette(&mut self, palette: &[u8; PALETTE_SIZE]) { + unsafe { + self.index_write_port.write(0); + } + for i in palette.iter() { + unsafe { + self.data_port.write(*i); + } + } + } + + pub fn read_palette(&mut self, palette: &mut [u8; PALETTE_SIZE]) { + unsafe { + self.index_read_port.write(0); + } + for byte in palette.iter_mut().take(PALETTE_SIZE) { + unsafe { + *byte = self.data_port.read(); + } + } + } +} diff --git a/src/registers/crtc_controller.rs b/src/registers/crtc_controller.rs new file mode 100644 index 0000000..8c16388 --- /dev/null +++ b/src/registers/crtc_controller.rs @@ -0,0 +1,122 @@ +use super::{ + EmulationMode, CRX_DATA_CGA_ADDRESS, CRX_DATA_MDA_ADDRESS, CRX_INDEX_CGA_ADDRESS, + CRX_INDEX_MDA_ADDRESS, +}; +use x86_64::instructions::port::Port; + +/// Represents an index for the crtc controller registers. +#[derive(Debug, Copy, Clone)] +#[repr(u8)] +pub enum CrtcControllerIndex { + /// Represents the `Horizontal Total` register index. + HorizontalTotal = 0x00, + /// Represents the `Horizontal Display Enable End` register index. + HorizontalDisplayEnableEnd = 0x01, + /// Represents the `Horizontal Blanking Start` register index. + HorizontalBlankingStart = 0x02, + /// Represents the `Horizontal Blanking End` register index. + HorizontalBlankingEnd = 0x03, + /// Represents the `Horizontal Sync Start` register index. + HorizontalSyncStart = 0x04, + /// Represents the `Horizontal Sync End` register index. + HorizontalSyncEnd = 0x05, + /// Represents the `Vertical Total` register index. + VeritcalTotal = 0x06, + /// Represents the `Overflow` register index. + Overflow = 0x07, + /// Represents the `Preset Row Scan` register index. + PresetRowScan = 0x08, + /// Represents the `Maximum Scan Line` register index. + MaximumScanLine = 0x09, + /// Represents the `Text Cursor Start` register index. + TextCursorStart = 0x0A, + /// Represents the `Text Cursor End` register index. + TextCursorEnd = 0x0B, + /// Represents the `Start Address High` register index. + StartAddressHigh = 0x0C, + /// Represents the `Start Address Low` register index. + StartAddressLow = 0x0D, + /// Represents the `Text Cursor Location High` register index. + TextCursorLocationHigh = 0x0E, + /// Represents the `Text Cursor Location Low` register index. + TextCursorLocationLow = 0x0F, + /// Represents the `Vertical Sync Start` register index. + VerticalSyncStart = 0x10, + /// Represents the `Vertical Sync End` register index. + VerticalSyncEnd = 0x11, + /// Represents the `Vertical Display Enable End` register index + VerticalDisplayEnableEnd = 0x12, + /// Represents the `Offset` register index. + Offset = 0x13, + /// Represents the `Underline Location` register index. + UnderlineLocation = 0x14, + /// Represents the `Vertical Blanking Start` register index. + VerticalBlankingStart = 0x15, + /// Represents the `Vertical Blanking End` register index. + VerticalBlankingEnd = 0x16, + /// Represents the `Mode Control` register index. + ModeControl = 0x17, + /// Represents the `Line Compare` register index. + LineCompare = 0x18, + /// Represents the `Memory Read Latch Data` register index. + MemoryReadLatchData = 0x22, + /// Represents the `Toggle State Of Attribute Controller` register index. + ToggleStateOfAttributeController = 0x24, +} + +impl From for u8 { + fn from(value: CrtcControllerIndex) -> u8 { + value as u8 + } +} + +#[derive(Debug)] +pub struct CrtcControllerRegisters { + crx_index_cga: Port, + crx_index_mda: Port, + crx_data_cga: Port, + crx_data_mda: Port, +} + +impl CrtcControllerRegisters { + pub fn new() -> CrtcControllerRegisters { + CrtcControllerRegisters { + crx_index_cga: Port::new(CRX_INDEX_CGA_ADDRESS), + crx_index_mda: Port::new(CRX_INDEX_MDA_ADDRESS), + crx_data_cga: Port::new(CRX_DATA_CGA_ADDRESS), + crx_data_mda: Port::new(CRX_DATA_MDA_ADDRESS), + } + } + + pub fn read(&mut self, emulation_mode: EmulationMode, index: CrtcControllerIndex) -> u8 { + self.set_index(emulation_mode, index); + unsafe { self.get_data_port(emulation_mode).read() } + } + + pub fn write(&mut self, emulation_mode: EmulationMode, index: CrtcControllerIndex, value: u8) { + self.set_index(emulation_mode, index); + unsafe { + self.get_data_port(emulation_mode).write(value); + } + } + + fn set_index(&mut self, emulation_mode: EmulationMode, index: CrtcControllerIndex) { + unsafe { + self.get_index_port(emulation_mode).write(u8::from(index)); + } + } + + fn get_data_port(&mut self, emulation_mode: EmulationMode) -> &mut Port { + match emulation_mode { + EmulationMode::Cga => &mut self.crx_data_cga, + EmulationMode::Mda => &mut self.crx_data_mda, + } + } + + fn get_index_port(&mut self, emulation_mode: EmulationMode) -> &mut Port { + match emulation_mode { + EmulationMode::Cga => &mut self.crx_index_cga, + EmulationMode::Mda => &mut self.crx_index_mda, + } + } +} diff --git a/src/registers/general.rs b/src/registers/general.rs new file mode 100644 index 0000000..323f5f5 --- /dev/null +++ b/src/registers/general.rs @@ -0,0 +1,42 @@ +use super::{ + FCR_CGA_WRITE_ADDRESS, FCR_MDA_WRITE_ADDRESS, FCR_READ_ADDRESS, MSR_READ_ADDRESS, + MSR_WRITE_ADDRESS, ST00_READ_ADDRESS, ST01_READ_CGA_ADDRESS, ST01_READ_MDA_ADDRESS, +}; +use x86_64::instructions::port::{PortReadOnly, PortWriteOnly}; + +#[derive(Debug)] +pub struct GeneralRegisters { + st00_read: PortReadOnly, + st01_read_cga: PortReadOnly, + st01_read_mda: PortReadOnly, + fcr_read: PortReadOnly, + fcr_write_cga: PortWriteOnly, + fcr_write_mda: PortWriteOnly, + msr_read: PortReadOnly, + msr_write: PortWriteOnly, +} + +impl GeneralRegisters { + pub fn new() -> GeneralRegisters { + GeneralRegisters { + st00_read: PortReadOnly::new(ST00_READ_ADDRESS), + st01_read_cga: PortReadOnly::new(ST01_READ_CGA_ADDRESS), + st01_read_mda: PortReadOnly::new(ST01_READ_MDA_ADDRESS), + fcr_read: PortReadOnly::new(FCR_READ_ADDRESS), + fcr_write_cga: PortWriteOnly::new(FCR_CGA_WRITE_ADDRESS), + fcr_write_mda: PortWriteOnly::new(FCR_MDA_WRITE_ADDRESS), + msr_read: PortReadOnly::new(MSR_READ_ADDRESS), + msr_write: PortWriteOnly::new(MSR_WRITE_ADDRESS), + } + } + + pub fn read_msr(&mut self) -> u8 { + unsafe { self.msr_read.read() } + } + + pub fn write_msr(&mut self, value: u8) { + unsafe { + self.msr_write.write(value); + } + } +} diff --git a/src/registers/graphics_controller.rs b/src/registers/graphics_controller.rs new file mode 100644 index 0000000..289e508 --- /dev/null +++ b/src/registers/graphics_controller.rs @@ -0,0 +1,71 @@ +use super::{GRX_DATA_ADDRESS, GRX_INDEX_ADDRESS}; +use x86_64::instructions::port::Port; + +/// Represents an index for the graphics controller registers. +#[derive(Debug, Copy, Clone)] +#[repr(u8)] +pub enum GraphicsControllerIndex { + /// Represents the `Set/Reset` register index. + SetReset = 0x0, + /// Represents the `Enable Set/Reset` register index. + EnableSetReset = 0x1, + /// Represents the `Color Compare` register index. + ColorCompare = 0x2, + /// Represents the `Data Rotate` register index. + DataRotate = 0x3, + /// Represents the `Read Plane Select` register index. + ReadPlaneSelect = 0x4, + /// Represents the `Graphics Mode` register index. + GraphicsMode = 0x5, + /// Represents the `Miscellaneous` register index. + Miscellaneous = 0x6, + /// Represents the `Color Don't Care` register index. + ColorDontCare = 0x7, + /// Represents the `Bit Mask` register index. + BitMask = 0x8, + /// Represents the `Address Mapping` register index. + AddressMapping = 0x10, + /// Represents the `Page Selector` register index. + PageSelector = 0x11, + /// Represents the `Software Flags` register index. + SoftwareFlags = 0x18, +} + +impl From for u8 { + fn from(value: GraphicsControllerIndex) -> u8 { + value as u8 + } +} + +#[derive(Debug)] +pub struct GraphicsControllerRegisters { + grx_index: Port, + grx_data: Port, +} + +impl GraphicsControllerRegisters { + pub fn new() -> GraphicsControllerRegisters { + GraphicsControllerRegisters { + grx_index: Port::new(GRX_INDEX_ADDRESS), + grx_data: Port::new(GRX_DATA_ADDRESS), + } + } + + pub fn read(&mut self, index: GraphicsControllerIndex) -> u8 { + self.set_index(index); + unsafe { self.grx_data.read() } + } + + pub fn write(&mut self, index: GraphicsControllerIndex, value: u8) { + self.set_index(index); + unsafe { + self.grx_data.write(value); + } + } + + fn set_index(&mut self, index: GraphicsControllerIndex) { + unsafe { + self.grx_index.write(u8::from(index)); + } + } +} diff --git a/src/registers/mod.rs b/src/registers/mod.rs new file mode 100644 index 0000000..a51901c --- /dev/null +++ b/src/registers/mod.rs @@ -0,0 +1,64 @@ +//! Common registers used in vga programming. + +mod attribute_controller; +mod color_palette; +mod crtc_controller; +mod general; +mod graphics_controller; +mod sequencer; + +use crate::colors::PALETTE_SIZE; + +pub use attribute_controller::{AttributeControllerIndex, AttributeControllerRegisters}; +pub use color_palette::ColorPaletteRegisters; +pub use crtc_controller::{CrtcControllerIndex, CrtcControllerRegisters}; +pub use general::GeneralRegisters; +pub use graphics_controller::{GraphicsControllerIndex, GraphicsControllerRegisters}; +pub use sequencer::{SequencerIndex, SequencerRegisters}; + +const ST00_READ_ADDRESS: u16 = 0x3C2; +const ST01_READ_CGA_ADDRESS: u16 = 0x3DA; +const ST01_READ_MDA_ADDRESS: u16 = 0x3BA; +const FCR_READ_ADDRESS: u16 = 0x3CA; +const FCR_CGA_WRITE_ADDRESS: u16 = 0x3DA; +const FCR_MDA_WRITE_ADDRESS: u16 = 0x3BA; +const MSR_READ_ADDRESS: u16 = 0x3CC; +const MSR_WRITE_ADDRESS: u16 = 0x3C2; + +const SRX_INDEX_ADDRESS: u16 = 0x3C4; +const SRX_DATA_ADDRESS: u16 = 0x3C5; + +const GRX_INDEX_ADDRESS: u16 = 0x3CE; +const GRX_DATA_ADDRESS: u16 = 0x3CF; + +const ARX_INDEX_ADDRESS: u16 = 0x3C0; +const ARX_DATA_ADDRESS: u16 = 0x3C1; + +const CRX_INDEX_CGA_ADDRESS: u16 = 0x3D4; +const CRX_INDEX_MDA_ADDRESS: u16 = 0x3B4; +const CRX_DATA_CGA_ADDRESS: u16 = 0x3D5; +const CRX_DATA_MDA_ADDRESS: u16 = 0x3B5; + +const COLOR_PALETTE_DATA_ADDRESS: u16 = 0x3C9; +const COLOR_PALETTE_INDEX_READ_ADDRESS: u16 = 0x3C7; +const COLOR_PALETTE_INDEX_WRITE_ADDRESSS: u16 = 0x3C8; + +/// Represents a vga emulation mode. +#[derive(Debug, Copy, Clone)] +#[repr(u8)] +pub enum EmulationMode { + /// Represents a monochrome emulation mode. + Mda = 0x0, + /// Respresents a color emulation mode. + Cga = 0x1, +} + +impl From for EmulationMode { + fn from(value: u8) -> EmulationMode { + match value { + 0x0 => EmulationMode::Mda, + 0x1 => EmulationMode::Cga, + _ => panic!("{} is an invalid emulation mode", value), + } + } +} diff --git a/src/registers/sequencer.rs b/src/registers/sequencer.rs new file mode 100644 index 0000000..29938c1 --- /dev/null +++ b/src/registers/sequencer.rs @@ -0,0 +1,59 @@ +use super::{SRX_DATA_ADDRESS, SRX_INDEX_ADDRESS}; +use x86_64::instructions::port::Port; + +/// Represents an index for the seqeuncer registers. +#[derive(Debug, Clone, Copy)] +#[repr(u8)] +pub enum SequencerIndex { + /// Represents the `Sequencer Reset` register index. + SequencerReset = 0x0, + /// Represents the `Clocking Mode` register index. + ClockingMode = 0x1, + /// Represents the `Plane/Map` mask register index. + PlaneMask = 0x2, + /// Represents the `Character Font` register index. + CharacterFont = 0x3, + /// Represents the `Memory Mode` register index. + MemoryMode = 0x4, + /// Represents the `Horizontal Character Counter Reset` register index. + CounterReset = 0x7, +} + +impl From for u8 { + fn from(value: SequencerIndex) -> u8 { + value as u8 + } +} + +#[derive(Debug)] +pub struct SequencerRegisters { + srx_index: Port, + srx_data: Port, +} + +impl SequencerRegisters { + pub fn new() -> SequencerRegisters { + SequencerRegisters { + srx_index: Port::new(SRX_INDEX_ADDRESS), + srx_data: Port::new(SRX_DATA_ADDRESS), + } + } + + pub fn read(&mut self, index: SequencerIndex) -> u8 { + self.set_index(index); + unsafe { self.srx_data.read() } + } + + pub fn write(&mut self, index: SequencerIndex, value: u8) { + self.set_index(index); + unsafe { + self.srx_data.write(value); + } + } + + fn set_index(&mut self, index: SequencerIndex) { + unsafe { + self.srx_index.write(u8::from(index)); + } + } +}