Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 75 additions & 1 deletion src/configurations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ pub const MODE_320X200X256_CONFIGURATION: VgaConfiguration = VgaConfiguration {
],
};

/// Register values for Vga mode 320x200x256x Graphics.
/// Register values for Vga mode 320x240x256 Graphics.
pub const MODE_320X240X256_CONFIGURATION: VgaConfiguration = VgaConfiguration {
// Configuration values acquired from https://www.singlix.com/trdos/archive/vga/Graphics%20in%20pmode.pdf
miscellaneous_output: 0x63,
Expand Down Expand Up @@ -463,3 +463,77 @@ pub const MODE_320X240X256_CONFIGURATION: VgaConfiguration = VgaConfiguration {
(AttributeControllerIndex::ColorSelect, 0x00),
],
};

/// Register values for Vga mode 1280x800x256 Graphics.
pub const MODE_1280X800X256_CONFIGURATION: VgaConfiguration = VgaConfiguration {
// Configuration values acquired from https://www.singlix.com/trdos/archive/vga/Graphics%20in%20pmode.pdf
miscellaneous_output: 0x63,
sequencer_registers: &[
(SequencerIndex::SequencerReset, 0x03),
(SequencerIndex::ClockingMode, 0x01),
(SequencerIndex::PlaneMask, 0x0F),
(SequencerIndex::CharacterFont, 0x00),
(SequencerIndex::MemoryMode, 0x06),
],
crtc_controller_registers: &[
(CrtcControllerIndex::HorizontalTotal, 0x5F),
(CrtcControllerIndex::HorizontalDisplayEnableEnd, 0x4F),
(CrtcControllerIndex::HorizontalBlankingStart, 0x50),
(CrtcControllerIndex::HorizontalBlankingEnd, 0x82),
(CrtcControllerIndex::HorizontalSyncStart, 0x54),
(CrtcControllerIndex::HorizontalSyncEnd, 0x80),
(CrtcControllerIndex::VeritcalTotal, 0x0D),
(CrtcControllerIndex::Overflow, 0x3E),
(CrtcControllerIndex::PresetRowScan, 0x00),
(CrtcControllerIndex::MaximumScanLine, 0x41),
(CrtcControllerIndex::TextCursorStart, 0x00),
(CrtcControllerIndex::TextCursorEnd, 0x00),
(CrtcControllerIndex::StartAddressHigh, 0x00),
(CrtcControllerIndex::StartAddressLow, 0x00),
(CrtcControllerIndex::TextCursorLocationHigh, 0x00),
(CrtcControllerIndex::TextCursorLocationLow, 0x00),
(CrtcControllerIndex::VerticalSyncStart, 0xEA),
(CrtcControllerIndex::VerticalSyncEnd, 0xAC),
(CrtcControllerIndex::VerticalDisplayEnableEnd, 0xDF),
(CrtcControllerIndex::Offset, 0x28),
(CrtcControllerIndex::UnderlineLocation, 0x00),
(CrtcControllerIndex::VerticalBlankingStart, 0xE7),
(CrtcControllerIndex::VerticalBlankingEnd, 0x06),
(CrtcControllerIndex::ModeControl, 0xE3),
(CrtcControllerIndex::LineCompare, 0xFF),
],
graphics_controller_registers: &[
(GraphicsControllerIndex::SetReset, 0x00),
(GraphicsControllerIndex::EnableSetReset, 0x00),
(GraphicsControllerIndex::ColorCompare, 0x00),
(GraphicsControllerIndex::DataRotate, 0x00),
(GraphicsControllerIndex::ReadPlaneSelect, 0x00),
(GraphicsControllerIndex::GraphicsMode, 0x40),
(GraphicsControllerIndex::Miscellaneous, 0x05),
(GraphicsControllerIndex::ColorDontCare, 0x0F),
(GraphicsControllerIndex::BitMask, 0xFF),
],
attribute_controller_registers: &[
(AttributeControllerIndex::PaletteRegister0, 0x00),
(AttributeControllerIndex::PaletteRegister1, 0x01),
(AttributeControllerIndex::PaletteRegister2, 0x02),
(AttributeControllerIndex::PaletteRegister3, 0x03),
(AttributeControllerIndex::PaletteRegister4, 0x04),
(AttributeControllerIndex::PaletteRegister5, 0x05),
(AttributeControllerIndex::PaletteRegister6, 0x06),
(AttributeControllerIndex::PaletteRegister7, 0x07),
(AttributeControllerIndex::PaletteRegister8, 0x08),
(AttributeControllerIndex::PaletteRegister9, 0x09),
(AttributeControllerIndex::PaletteRegisterA, 0x0A),
(AttributeControllerIndex::PaletteRegisterB, 0x0B),
(AttributeControllerIndex::PaletteRegisterC, 0x0C),
(AttributeControllerIndex::PaletteRegisterD, 0x0D),
(AttributeControllerIndex::PaletteRegisterE, 0x0E),
(AttributeControllerIndex::PaletteRegisterF, 0x0F),
(AttributeControllerIndex::ModeControl, 0x41),
(AttributeControllerIndex::OverscanColor, 0x00),
(AttributeControllerIndex::MemoryPlaneEnable, 0x0F),
(AttributeControllerIndex::HorizontalPixelPanning, 0x00),
(AttributeControllerIndex::ColorSelect, 0x00),
],
};
10 changes: 10 additions & 0 deletions src/vga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use super::{
GraphicsControllerRegisters, PlaneMask, SequencerIndex, SequencerRegisters,
},
};
use crate::configurations::MODE_1280X800X256_CONFIGURATION;
use conquer_once::spin::Lazy;
use spinning_top::Spinlock;

Expand Down Expand Up @@ -68,6 +69,8 @@ pub enum VideoMode {
Mode320x240x256,
/// Represents graphics mode 640x480x16.
Mode640x480x16,
/// Represents graphics mode 1280x800x256.
Mode1280x800x256,
}

/// Represents a vga graphics card with it's common registers,
Expand Down Expand Up @@ -128,6 +131,7 @@ impl Vga {
VideoMode::Mode320x200x256 => self.set_video_mode_320x200x256(),
VideoMode::Mode320x240x256 => self.set_video_mode_320x240x256(),
VideoMode::Mode640x480x16 => self.set_video_mode_640x480x16(),
VideoMode::Mode1280x800x256 => self.set_video_mode_1280x800x256(),
}
}

Expand Down Expand Up @@ -313,6 +317,12 @@ impl Vga {
self.most_recent_video_mode = Some(VideoMode::Mode640x480x16);
}

/// Sets the video card to Mode 1280x800x256.
fn set_video_mode_1280x800x256(&mut self) {
self.set_registers(&MODE_1280X800X256_CONFIGURATION);
self.most_recent_video_mode = Some(VideoMode::Mode1280x800x256);
}

/// Unlocks the CRTC registers by setting bit 7 to 0 `(value & 0x7F)`.
///
/// `Protect Registers [0:7]`: Note that the ability to write to Bit 4 of the Overflow Register (CR07)
Expand Down
103 changes: 103 additions & 0 deletions src/writers/graphics_1280x800x256.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use super::{GraphicsWriter, Screen};
use crate::colors::DEFAULT_PALETTE;
use crate::drawing::{Bresenham, Point};
use crate::registers::PlaneMask;
use crate::vga::VGA;
use core::slice::from_raw_parts_mut;
use font8x8::UnicodeFonts;

const WIDTH: usize = 1280;
const HEIGHT: usize = 800;
const BYTES_PER_PIXEL: usize = 4;
const PIXEL_COUNT: usize = WIDTH * HEIGHT;
const SIZE: usize = PIXEL_COUNT * BYTES_PER_PIXEL;

type ColorT = u32;

/// A basic interface for interacting with vga graphics mode 1280x800x256.
///
/// # Examples
///
/// Basic usage:
///
/// ```no_run
/// use vga::writers::{Graphics1280x800x256, GraphicsWriter};
///
/// let mode = Graphics1280x800x256::new();
/// mode.set_mode();
/// mode.clear_screen(0x00_FF_00);
/// mode.draw_line((60, 20), (260, 20), 0xFF_00_FF);
/// mode.draw_line((60, 20), (60, 180), 0xFF_00_FF);
/// mode.draw_line((60, 180), (260, 180), 0xFF_00_FF);
/// mode.draw_line((260, 180), (260, 20), 0xFF_00_FF);
/// mode.draw_line((60, 40), (260, 40), 0xFF_00_FF);
/// for (offset, character) in "Hello World!".chars().enumerate() {
/// mode.draw_character(118 + offset * 8, 27, character, 0xFF_00_FF);
/// }
/// ```
#[derive(Debug, Clone, Copy, Default)]
pub struct Graphics1280x800x256;

impl Screen for Graphics1280x800x256 {
const WIDTH: usize = WIDTH;
const HEIGHT: usize = HEIGHT;
const SIZE: usize = SIZE;
}

impl GraphicsWriter<ColorT> for Graphics1280x800x256 {
fn clear_screen(&self, color: ColorT) {
let frame_buffer = self.get_frame_buffer() as *mut ColorT;
VGA.lock()
.sequencer_registers
.set_plane_mask(PlaneMask::ALL_PLANES);
unsafe {
from_raw_parts_mut(frame_buffer, PIXEL_COUNT).fill(color);
}
}

fn draw_line(&self, start: Point<isize>, end: Point<isize>, color: ColorT) {
for (x, y) in Bresenham::new(start, end) {
self.set_pixel(x as usize, y as usize, color);
}
}

fn draw_character(&self, x: usize, y: usize, character: char, color: ColorT) {
let character = match font8x8::BASIC_FONTS.get(character) {
Some(character) => character,
// Default to a filled block if the character isn't found
None => font8x8::unicode::BLOCK_UNICODE[8].byte_array(),
};

for (row, byte) in character.iter().enumerate() {
for bit in 0..8 {
match *byte & 1 << bit {
0 => (),
_ => self.set_pixel(x + bit, y + row, color),
}
}
}
}

fn set_pixel(&self, x: usize, y: usize, color: ColorT) {
let frame_buffer = self.get_frame_buffer() as *mut ColorT;
let offset = WIDTH * y + x;
unsafe {
frame_buffer.add(offset).write_volatile(color);
}
}

fn set_mode(&self) {
let mut vga = VGA.lock();

// Some bios mess up the palette when switching modes,
// so explicitly set it.
vga.color_palette_registers.load_palette(&DEFAULT_PALETTE);
}
}

impl Graphics1280x800x256 {
/// Creates a new `Graphics1280x800x256`.
pub const fn new() -> Graphics1280x800x256 {
Graphics1280x800x256
}
}
2 changes: 2 additions & 0 deletions src/writers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Writers for common vga modes.
mod graphics_1280x800x256;
mod graphics_320x200x256;
mod graphics_320x240x256;
mod graphics_640x480x16;
Expand All @@ -14,6 +15,7 @@ use super::{
};
use spinning_top::SpinlockGuard;

pub use graphics_1280x800x256::Graphics1280x800x256;
pub use graphics_320x200x256::Graphics320x200x256;
pub use graphics_320x240x256::Graphics320x240x256;
pub use graphics_640x480x16::Graphics640x480x16;
Expand Down
5 changes: 1 addition & 4 deletions testing/src/interrupts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,7 @@ extern "x86-interrupt" fn page_fault_handler(
hlt_loop();
}

extern "x86-interrupt" fn segment_not_present(
_stack_frame: InterruptStackFrame,
_error_code: u64,
) {
extern "x86-interrupt" fn segment_not_present(_stack_frame: InterruptStackFrame, _error_code: u64) {
// For some reason this sometimes gets thrown when running tests in qemu,
// so leave empty so the tests finish for now.
}
15 changes: 13 additions & 2 deletions testing/tests/vga.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use core::panic::PanicInfo;
use testing::{gdt, interrupts, serial_print, serial_println};
use vga::colors::{DEFAULT_PALETTE, PALETTE_SIZE};
use vga::configurations::{
VgaConfiguration, MODE_40X25_CONFIGURATION, MODE_40X50_CONFIGURATION,
MODE_640X480X16_CONFIGURATION, MODE_80X25_CONFIGURATION,
VgaConfiguration, MODE_1280X800X256_CONFIGURATION, MODE_40X25_CONFIGURATION,
MODE_40X50_CONFIGURATION, MODE_640X480X16_CONFIGURATION, MODE_80X25_CONFIGURATION,
};
use vga::vga::{Vga, VideoMode, VGA};

Expand Down Expand Up @@ -77,6 +77,17 @@ fn set_mode_640x480x16() {
serial_println!("[ok]");
}

#[test_case]
fn set_mode_1280x800x256() {
serial_print!("mode 1280x800x256... ");

let mut vga = VGA.lock();
vga.set_video_mode(VideoMode::Mode1280x800x256);
check_registers(&mut vga, &MODE_1280X800X256_CONFIGURATION);

serial_println!("[ok]");
}

#[test_case]
fn load_palette() {
serial_print!("load palette... ");
Expand Down