Merge pull request #10 from rust-osdev/develop

Develop
pull/14/head
RKennedy9064 2020-03-25 20:48:06 -05:00 committed by GitHub
commit 85c237d637
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 228 additions and 10 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "vga"
version = "0.2.0"
version = "0.2.1"
authors = ["Ryan Kennedy <rkennedy9064@gmail.com>"]
edition = "2018"
description = "Support for vga specific functions, data structures, and registers."

View File

@ -1,3 +1,8 @@
# 0.2.1
- Added `Graphics320x200x256` mode.
- Implemented `Screen` for `Graphics640x480x16`.
# 0.2.0
## Breaking

View File

@ -315,3 +315,77 @@ pub const MODE_640X480X16_CONFIGURATION: VgaConfiguration = VgaConfiguration {
(AttributeControllerIndex::ColorSelect, 0x00),
],
};
/// Register values for Vga mode 640x480x16 Graphics.
pub const MODE_320X200X256_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, 0x0E),
],
crtc_controller_registers: &[
(CrtcControllerIndex::HorizontalTotal, 0x5F),
(CrtcControllerIndex::HorizontalDisplayEnableEnd, 0x4F),
(CrtcControllerIndex::HorizontalBlankingStart, 0x50),
(CrtcControllerIndex::HorizontalBlankingEnd, 0x82),
(CrtcControllerIndex::HorizontalSyncStart, 0x54),
(CrtcControllerIndex::HorizontalSyncEnd, 0x80),
(CrtcControllerIndex::VeritcalTotal, 0xBF),
(CrtcControllerIndex::Overflow, 0x1F),
(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, 0x9C),
(CrtcControllerIndex::VerticalSyncEnd, 0x0E),
(CrtcControllerIndex::VerticalDisplayEnableEnd, 0x8F),
(CrtcControllerIndex::Offset, 0x28),
(CrtcControllerIndex::UnderlineLocation, 0x40),
(CrtcControllerIndex::VerticalBlankingStart, 0x96),
(CrtcControllerIndex::VerticalBlankingEnd, 0xB9),
(CrtcControllerIndex::ModeControl, 0xA3),
(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),
],
};

View File

@ -2,8 +2,8 @@
use super::{
configurations::{
VgaConfiguration, MODE_40X25_CONFIGURATION, MODE_40X50_CONFIGURATION,
MODE_640X480X16_CONFIGURATION, MODE_80X25_CONFIGURATION,
VgaConfiguration, MODE_320X200X256_CONFIGURATION, MODE_40X25_CONFIGURATION,
MODE_40X50_CONFIGURATION, MODE_640X480X16_CONFIGURATION, MODE_80X25_CONFIGURATION,
},
fonts::VgaFont,
registers::{
@ -57,6 +57,8 @@ pub enum VideoMode {
Mode40x50,
/// Represents text mode 80x25.
Mode80x25,
/// Represents graphics mode 320x200x256.
Mode320x200x256,
/// Represents graphics mode 640x480x16.
Mode640x480x16,
}
@ -98,6 +100,7 @@ impl Vga {
VideoMode::Mode40x25 => self.set_video_mode_40x25(),
VideoMode::Mode40x50 => self.set_video_mode_40x50(),
VideoMode::Mode80x25 => self.set_video_mode_80x25(),
VideoMode::Mode320x200x256 => self.set_video_mode_320x200x256(),
VideoMode::Mode640x480x16 => self.set_video_mode_640x480x16(),
}
}
@ -266,6 +269,12 @@ impl Vga {
self.most_recent_video_mode = Some(VideoMode::Mode80x25);
}
/// Sets the video card to Mode 320x200x256.
fn set_video_mode_320x200x256(&mut self) {
self.set_registers(&MODE_320X200X256_CONFIGURATION);
self.most_recent_video_mode = Some(VideoMode::Mode320x200x256);
}
/// Sets the video card to Mode 640x480x16.
fn set_video_mode_640x480x16(&mut self) {
self.set_registers(&MODE_640X480X16_CONFIGURATION);

View File

@ -0,0 +1,116 @@
use super::{GraphicsWriter, Screen};
use crate::{
colors::DEFAULT_PALETTE,
drawing::{Bresenham, Point},
vga::{Vga, VideoMode, VGA},
};
use font8x8::UnicodeFonts;
use spinning_top::SpinlockGuard;
const WIDTH: usize = 320;
const HEIGHT: usize = 200;
const SIZE: usize = WIDTH * HEIGHT;
/// A basic interface for interacting with vga graphics mode 320x200x256.
///
/// # Examples
///
/// Basic usage:
///
/// ```no_run
/// use vga::colors::Color16;
/// use vga::writers::{Graphics320x200x256, GraphicsWriter};
/// let mode = Graphics320x200x256::new();
/// mode.set_mode();
/// mode.clear_screen(0);
/// mode.draw_line((60, 20), (260, 20), 255);
/// mode.draw_line((60, 20), (60, 180), 255);
/// mode.draw_line((60, 180), (260, 180), 255);
/// mode.draw_line((260, 180), (260, 20), 255);
/// mode.draw_line((60, 40), (260, 40), 255);
/// for (offset, character) in "Hello World!".chars().enumerate() {
/// mode.draw_character(118 + offset * 8, 27, character, 255);
/// }
/// ```
#[derive(Default)]
pub struct Graphics320x200x256 {}
impl Screen for Graphics320x200x256 {
#[inline]
fn get_width(&self) -> usize {
WIDTH
}
#[inline]
fn get_height(&self) -> usize {
HEIGHT
}
#[inline]
fn get_size(&self) -> usize {
SIZE
}
}
impl GraphicsWriter<u8> for Graphics320x200x256 {
fn clear_screen(&self, color: u8) {
for x in 0..WIDTH {
for y in 0..HEIGHT {
self.set_pixel(x, y, color);
}
}
}
fn draw_line(&self, start: Point<isize>, end: Point<isize>, color: u8) {
for (x, y) in Bresenham::new(start, end) {
self.set_pixel(x as usize, y as usize, color);
}
}
fn set_pixel(&self, x: usize, y: usize, color: u8) {
let (_vga, frame_buffer) = self.get_frame_buffer();
let offset = (y * WIDTH) + x;
unsafe {
frame_buffer.add(offset).write_volatile(color);
}
}
fn draw_character(&self, x: usize, y: usize, character: char, color: u8) {
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_mode(&self) {
let mut vga = VGA.lock();
vga.set_video_mode(VideoMode::Mode320x200x256);
// Some bios mess up the palette when switching modes,
// so explicitly set it.
vga.color_palette_registers.load_palette(&DEFAULT_PALETTE);
}
}
impl Graphics320x200x256 {
/// Creates a new `Graphics320x200x256`.
pub fn new() -> Graphics320x200x256 {
Graphics320x200x256 {}
}
/// Returns the start of the `FrameBuffer` as `*mut u8` as
/// well as a lock to the vga driver. This ensures the vga
/// driver stays locked while the frame buffer is in use.
fn get_frame_buffer(&self) -> (SpinlockGuard<Vga>, *mut u8) {
let mut vga = VGA.lock();
let frame_buffer = vga.get_frame_buffer();
(vga, u32::from(frame_buffer) as *mut u8)
}
}

View File

@ -1,4 +1,4 @@
use super::GraphicsWriter;
use super::{GraphicsWriter, Screen};
use crate::{
colors::{Color16, DEFAULT_PALETTE},
drawing::{Bresenham, Point},
@ -10,6 +10,7 @@ use spinning_top::SpinlockGuard;
const WIDTH: usize = 640;
const HEIGHT: usize = 480;
const SIZE: usize = WIDTH * HEIGHT;
const ALL_PLANES_SCREEN_SIZE: usize = (WIDTH * HEIGHT) / 8;
const WIDTH_IN_BYTES: usize = WIDTH / 8;
@ -38,6 +39,18 @@ const WIDTH_IN_BYTES: usize = WIDTH / 8;
#[derive(Default)]
pub struct Graphics640x480x16;
impl Screen for Graphics640x480x16 {
fn get_width(&self) -> usize {
WIDTH
}
fn get_height(&self) -> usize {
HEIGHT
}
fn get_size(&self) -> usize {
SIZE
}
}
impl GraphicsWriter<Color16> for Graphics640x480x16 {
fn clear_screen(&self, color: Color16) {
self.set_write_mode_2();
@ -74,6 +87,10 @@ impl GraphicsWriter<Color16> for Graphics640x480x16 {
}
}
/// **Note:** This method is provided for convenience, but has terrible
/// performance since it needs to ensure the correct `WriteMode` per pixel
/// drawn. If you need to draw more then one pixel, consider using a method
/// such as `draw_line`.
fn set_pixel(&self, x: usize, y: usize, color: Color16) {
self.set_write_mode_2();
self._set_pixel(x, y, color);

View File

@ -1,4 +1,5 @@
//! Writers for common vga modes.
mod graphics_320x200x256;
mod graphics_640x480x16;
mod text_40x25;
mod text_40x50;
@ -12,6 +13,7 @@ use super::{
};
use spinning_top::SpinlockGuard;
pub use graphics_320x200x256::Graphics320x200x256;
pub use graphics_640x480x16::Graphics640x480x16;
pub use text_40x25::Text40x25;
pub use text_40x50::Text40x50;
@ -183,16 +185,11 @@ pub trait TextWriter: Screen {
pub trait GraphicsWriter<Color> {
/// Clears the screen by setting all pixels to the specified `color`.
fn clear_screen(&self, color: Color);
/// /// Draws a line from `start` to `end` with the specified `color`.
/// Draws a line from `start` to `end` with the specified `color`.
fn draw_line(&self, start: Point<isize>, end: Point<isize>, color: Color);
/// Draws a character at the given `(x, y)` coordinant to the specified `color`.
fn draw_character(&self, x: usize, y: usize, character: char, color: Color);
/// Sets the given pixel at `(x, y)` to the given `color`.
///
/// **Note:** This method is provided for convenience, but has terrible
/// performance since it needs to ensure the correct `WriteMode` per pixel
/// drawn. If you need to draw more then one pixel, consider using a method
/// such as `draw_line`.
fn set_pixel(&self, x: usize, y: usize, color: Color);
/// Sets the graphics device to a `VideoMode`.
fn set_mode(&self);