pluto/src/kernel/vga.zig
ED 995268b04e Added GDT, IDT, IRQ, updated build.zig
Added new build.zig


Interrupts no work :(


Added isr


Interrupts work


Added spurious irq


Code review comments


New name


Refactor


Build asm
2019-05-31 07:41:28 +01:00

409 lines
11 KiB
Zig

// Zig version: 0.4.0
const builtin = @import("builtin");
const arch = @import("arch.zig").internals;
const expectEqual = @import("std").testing.expectEqual;
const warn = @import("std").debug.warn;
/// The port address for the VGA register selection.
const PORT_ADDRESS: u16 = 0x03D4;
/// The port address for the VGA data.
const PORT_DATA: u16 = 0x03D5;
// The indexes that is passed to the address port to select the register for the data to be
// read or written to.
const REG_HORIZONTAL_TOTAL: u8 = 0x00;
const REG_HORIZONTAL_DISPLAY_ENABLE_END: u8 = 0x01;
const REG_START_HORIZONTAL_BLINKING: u8 = 0x02;
const REG_END_HORIZONTAL_BLINKING: u8 = 0x03;
const REG_START_HORIZONTAL_RETRACE_PULSE: u8 = 0x04;
const REG_END_HORIZONTAL_RETRACE_PULSE: u8 = 0x05;
const REG_VERTICAL_TOTAL: u8 = 0x06;
const REG_OVERFLOW: u8 = 0x07;
const REG_PRESET_ROW_SCAN: u8 = 0x08;
const REG_MAXIMUM_SCAN_LINE: u8 = 0x09;
/// The command for setting the start of the cursor scan line.
const REG_CURSOR_START: u8 = 0x0A;
/// The command for setting the end of the cursor scan line.
const REG_CURSOR_END: u8 = 0x0B;
const REG_START_ADDRESS_HIGH: u8 = 0x0C;
const REG_START_ADDRESS_LOW: u8 = 0x0D;
/// The command for setting the upper byte of the cursor's linear location.
const REG_CURSOR_LOCATION_HIGH: u8 = 0x0E;
/// The command for setting the lower byte of the cursor's linear location.
const REG_CURSOR_LOCATION_LOW: u8 = 0x0F;
const REG_VERTICAL_RETRACE_START: u8 = 0x10;
const REG_VERTICAL_RETRACE_END: u8 = 0x11;
const REG_VERTICAL_DISPLAY_ENABLE_END: u8 = 0x12;
const REG_OFFSET: u8 = 0x13;
const REG_UNDERLINE_LOCATION: u8 = 0x14;
const REG_START_VERTICAL_BLINKING: u8 = 0x15;
const REG_END_VERTICAL_BLINKING: u8 = 0x16;
const REG_CRT_MODE_CONTROL: u8 = 0x17;
const REG_LINE_COMPARE: u8 = 0x18;
///The start of the cursor scan line, the very beginning.
const CURSOR_SCANLINE_START: u8 = 0x0;
///The scan line for use in the underline cursor shape.
const CURSOR_SCANLINE_MIDDLE: u8 = 0xE;
///The end of the cursor scan line, the very end.
const CURSOR_SCANLINE_END: u8 = 0xF;
/// If set, disables the cursor.
const CURSOR_DISABLE: u8 = 0x20;
pub const WIDTH: u16 = 80;
pub const HEIGHT: u16 = 25;
// The set of colours that VGA supports and can display for the foreground and background.
pub const COLOUR_BLACK: u4 = 0x00;
pub const COLOUR_BLUE: u4 = 0x01;
pub const COLOUR_GREEN: u4 = 0x02;
pub const COLOUR_CYAN: u4 = 0x03;
pub const COLOUR_RED: u4 = 0x04;
pub const COLOUR_MAGENTA: u4 = 0x05;
pub const COLOUR_BROWN: u4 = 0x06;
pub const COLOUR_LIGHT_GREY: u4 = 0x07;
pub const COLOUR_DARK_GREY: u4 = 0x08;
pub const COLOUR_LIGHT_BLUE: u4 = 0x09;
pub const COLOUR_LIGHT_GREEN: u4 = 0x0A;
pub const COLOUR_LIGHT_CYAN: u4 = 0x0B;
pub const COLOUR_LIGHT_RED: u4 = 0x0C;
pub const COLOUR_LIGHT_MAGENTA: u4 = 0x0D;
pub const COLOUR_LIGHT_BROWN: u4 = 0x0E;
pub const COLOUR_WHITE: u4 = 0x0F;
/// The set of shapes that can be displayed.
pub const CursorShape = enum(u1) {
/// The cursor has the underline shape.
UNDERLINE,
/// The cursor has the block shape.
BLOCK,
};
/// The cursor scan line start so to know whether is in block or underline mode.
var cursor_scanline_start: u8 = undefined;
/// The cursor scan line end so to know whether is in block or underline mode.
var cursor_scanline_end: u8 = undefined;
///
/// Takes two 4 bit values that represent the foreground and background colour of the text and
/// returns a 8 bit value that gives both to be displayed.
///
/// Arguments:
/// IN fg: u4 - The foreground colour.
/// IN bg: u4 - The background colour.
///
/// Return:
/// Both combined into 1 byte for the colour to be displayed.
///
pub fn entryColour(fg: u4, bg: u4) u8 {
return u8(fg) | u8(bg) << 4;
}
///
/// Create the 2 bytes entry that the VGA used to display a character with a foreground and
/// background colour.
///
/// Arguments:
/// IN uc: u8 - The character.
/// IN colour: u8 - The foreground and background colour.
///
/// Return:
/// The VGA entry.
///
pub fn entry(uc: u8, colour: u8) u16 {
return u16(uc) | u16(colour) << 8;
}
///
/// Update the hardware on screen cursor.
///
/// Arguments:
/// IN x: u16 - The horizontal position of the cursor.
/// IN y: u16 - The vertical position of the cursor.
///
/// Return:
/// The VGA entry.
///
pub fn updateCursor(x: u16, y: u16) void {
var pos: u16 = undefined;
var pos_upper: u16 = undefined;
var pos_lower: u16 = undefined;
// Make sure new cursor position is within the screen
if (x < WIDTH and y < HEIGHT) {
pos = y * WIDTH + x;
} else {
// If not within the screen, then just put the cursor at the very end
pos = (HEIGHT - 1) * WIDTH + (WIDTH - 1);
}
pos_upper = (pos >> 8) & 0x00FF;
pos_lower = pos & 0x00FF;
// Set the cursor position
arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_LOW);
arch.outb(PORT_DATA, @truncate(u8, pos_lower));
arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH);
arch.outb(PORT_DATA, @truncate(u8, pos_upper));
}
///
/// Get the hardware cursor position.
///
/// Return:
/// The linear cursor position.
///
pub fn getCursor() u16 {
var cursor: u16 = 0;
arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_LOW);
cursor |= u16(arch.inb(PORT_DATA));
arch.outb(PORT_ADDRESS, REG_CURSOR_LOCATION_HIGH);
cursor |= u16(arch.inb(PORT_DATA)) << 8;
return cursor;
}
///
/// Enables the blinking cursor to that is is visible.
///
pub fn enableCursor() void {
arch.outb(PORT_ADDRESS, REG_CURSOR_START);
arch.outb(PORT_DATA, cursor_scanline_start);
arch.outb(PORT_ADDRESS, REG_CURSOR_END);
arch.outb(PORT_DATA, cursor_scanline_end);
}
///
/// Disables the blinking cursor to that is is visible.
///
pub fn disableCursor() void {
arch.outb(PORT_ADDRESS, REG_CURSOR_START);
arch.outb(PORT_DATA, CURSOR_DISABLE);
}
///
/// Set the shape of the cursor. This can be and underline or block shape.
///
/// Arguments:
/// IN shape: CURSOR_SHAPE - The enum CURSOR_SHAPE that selects which shape to use.
///
pub fn setCursorShape(shape: CursorShape) void {
switch (shape) {
CursorShape.UNDERLINE => {
arch.outb(PORT_ADDRESS, REG_CURSOR_START);
arch.outb(PORT_DATA, CURSOR_SCANLINE_MIDDLE);
arch.outb(PORT_ADDRESS, REG_CURSOR_END);
arch.outb(PORT_DATA, CURSOR_SCANLINE_END);
cursor_scanline_start = CURSOR_SCANLINE_MIDDLE;
cursor_scanline_end = CURSOR_SCANLINE_END;
},
CursorShape.BLOCK => {
arch.outb(PORT_ADDRESS, REG_CURSOR_START);
arch.outb(PORT_DATA, CURSOR_SCANLINE_START);
arch.outb(PORT_ADDRESS, REG_CURSOR_END);
arch.outb(PORT_DATA, CURSOR_SCANLINE_END);
cursor_scanline_start = CURSOR_SCANLINE_START;
cursor_scanline_end = CURSOR_SCANLINE_END;
},
}
}
///
/// Initialise the VGA text mode. This sets the cursor and underline shape.
///
pub fn init() void {
// Set the maximum scan line to 0x0F
arch.outb(PORT_ADDRESS, REG_MAXIMUM_SCAN_LINE);
arch.outb(PORT_DATA, CURSOR_SCANLINE_END);
// Set by default the underline cursor
setCursorShape(CursorShape.UNDERLINE);
}
test "entryColour" {
var fg: u4 = COLOUR_BLACK;
var bg: u4 = COLOUR_BLACK;
var res: u8 = entryColour(fg, bg);
expectEqual(u8(0x00), res);
fg = COLOUR_LIGHT_GREEN;
bg = COLOUR_BLACK;
res = entryColour(fg, bg);
expectEqual(u8(0x0A), res);
fg = COLOUR_BLACK;
bg = COLOUR_LIGHT_GREEN;
res = entryColour(fg, bg);
expectEqual(u8(0xA0), res);
fg = COLOUR_BROWN;
bg = COLOUR_LIGHT_GREEN;
res = entryColour(fg, bg);
expectEqual(u8(0xA6), res);
}
test "entry" {
var colour: u8 = entryColour(COLOUR_BROWN, COLOUR_LIGHT_GREEN);
expectEqual(u8(0xA6), colour);
// Character '0' is 0x30
var video_entry: u16 = entry('0', colour);
expectEqual(u16(0xA630), video_entry);
video_entry = entry(0x55, colour);
expectEqual(u16(0xA655), video_entry);
}
fn testOutOfBounds(x: u16, y: u16) bool {
if (x < HEIGHT and y < WIDTH) {
return true;
}
return false;
}
fn testUpperVal(x: u16, y: u16) u16 {
const pos: u16 = x * WIDTH + y;
const pos_upper: u16 = (pos >> 8) & 0x00FF;
return pos_upper;
}
fn testLowerVal(x: u16, y: u16) u16 {
const pos: u16 = x * WIDTH + y;
const pos_lower: u16 = pos & 0x00FF;
return pos_lower;
}
test "updateCursor out of bounds" {
var x: u16 = 0;
var y: u16 = 0;
var res: bool = testOutOfBounds(x, y);
expectEqual(true, res);
x = HEIGHT - 1;
res = testOutOfBounds(x, y);
expectEqual(true, res);
y = WIDTH - 1;
res = testOutOfBounds(x, y);
expectEqual(true, res);
x = HEIGHT;
y = WIDTH;
res = testOutOfBounds(x, y);
expectEqual(false, res);
x = HEIGHT - 1;
y = WIDTH;
res = testOutOfBounds(x, y);
expectEqual(false, res);
x = HEIGHT;
y = WIDTH - 1;
res = testOutOfBounds(x, y);
expectEqual(false, res);
}
test "updateCursor lower values" {
var x: u16 = 0x0000;
var y: u16 = 0x0000;
var res: u16 = testLowerVal(x, y);
var expected: u16 = 0x0000;
expectEqual(expected, res);
x = 0x0000;
y = 0x000A;
res = testLowerVal(x, y);
expected = 0x000A;
expectEqual(expected, res);
x = 0x000A;
y = 0x0000;
res = testLowerVal(x, y);
expected = 0x0020;
expectEqual(expected, res);
x = 0x000A;
y = 0x000A;
res = testLowerVal(x, y);
expected = 0x002A;
expectEqual(expected, res);
}
test "updateCursor upper values" {
var x: u16 = 0x0000;
var y: u16 = 0x0000;
var res: u16 = testUpperVal(x, y);
var expected: u16 = 0x0000;
expectEqual(expected, res);
x = 0x0000;
y = 0x000A;
res = testUpperVal(x, y);
expected = 0x0000;
expectEqual(expected, res);
x = 0x000A;
y = 0x0000;
res = testUpperVal(x, y);
expected = 0x0003;
expectEqual(expected, res);
x = 0x000A;
y = 0x000A;
res = testUpperVal(x, y);
expected = 0x0003;
expectEqual(expected, res);
}
test "getCursor all" {
warn(" Waiting for mocking ");
var res = getCursor();
}
test "enableCursor all" {
warn(" Waiting for mocking ");
enableCursor();
}
test "disableCursor all" {
warn(" Waiting for mocking ");
disableCursor();
}
test "setCursorShape all" {
setCursorShape(CursorShape.UNDERLINE);
expectEqual(CURSOR_SCANLINE_MIDDLE, cursor_scanline_start);
expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end);
setCursorShape(CursorShape.BLOCK);
expectEqual(CURSOR_SCANLINE_START, cursor_scanline_start);
expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end);
}
test "init all" {
warn(" Waiting for mocking ");
init();
expectEqual(CURSOR_SCANLINE_MIDDLE, cursor_scanline_start);
expectEqual(CURSOR_SCANLINE_END, cursor_scanline_end);
}