278 lines
6.1 KiB
C
278 lines
6.1 KiB
C
#include "headers/screen.h"
|
|
#include "headers/common.h"
|
|
|
|
#include <stdbool.h>
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
|
|
volatile uint16_t* vga_buffer = (uint16_t*) 0xB8000;
|
|
|
|
uint8_t current_color;
|
|
|
|
void set_current_color(enum vga_colors color) {
|
|
current_color = color;
|
|
}
|
|
|
|
/* Entries of the VGA Buffer take the form BBBBFFFFCCCCCCCC
|
|
* BBBB = Background Color
|
|
* FFFF = Foreground Color
|
|
* CCCCCCCC = Character code
|
|
*/
|
|
|
|
//Get the 8 color bits from the above enumerator
|
|
static inline uint8_t vga_entry_color(enum vga_colors fg, enum vga_colors bg) {
|
|
return fg | bg << 4; //Shift the background to the left, then OR with fg to add them together.
|
|
}
|
|
//Apply the color bits to make a printed character
|
|
static inline uint16_t vga_entry(unsigned char uc, uint8_t color) {
|
|
return (uint16_t) uc | (uint16_t) color << 8; //Same here - shift the color to the left, then OR with the character to append.
|
|
}
|
|
|
|
int i; // offset to framebuffer
|
|
uint8_t row; // current row between 1-25
|
|
uint8_t col; // current col between 1-80
|
|
short calc = 0; // random var for various calcs must be initialized or cleaned after func calls
|
|
// ^ attempt at packing may need calc to be an int however...
|
|
|
|
// simple printf style function(needs testing with errenous data)
|
|
// add tab support and %p specifier
|
|
// also add support for printing the register state
|
|
void kprintf(const char *string, ...) // look up how this is properly done
|
|
{
|
|
int j = 0;
|
|
int num = 0; // number to hold our stuff :)
|
|
char string2[11] = {0}; // string for printing ints :)
|
|
|
|
/* list stuff :) */
|
|
va_list ap;
|
|
// find how many things we are parsing
|
|
|
|
va_start(ap, string);
|
|
|
|
while(string[j] != 0)
|
|
{
|
|
if(string[j] == '%') // if a format specifier
|
|
{
|
|
if(string[j+1] == 'd') // print a decimal
|
|
{
|
|
num = va_arg(ap, int);
|
|
itoa(num, string2); // account for negatives...
|
|
print(string2);
|
|
zerostring(string2);
|
|
j += 2;
|
|
}
|
|
|
|
else if(string[j+1] == 'x') // print as hex
|
|
{
|
|
num = va_arg(ap, int);
|
|
tohex(num, string2);
|
|
print(string2);
|
|
zerostring(string2);
|
|
j += 2;
|
|
}
|
|
|
|
else if(string[j+1] == 's') // print a string
|
|
{
|
|
print(va_arg(ap, char*));
|
|
j += 2;
|
|
}
|
|
|
|
else if(string[j+1] == 'c') // print a char
|
|
{
|
|
char c = va_arg(ap,int);
|
|
printchar(c);
|
|
j += 2;
|
|
}
|
|
|
|
else // unknown format string
|
|
{
|
|
//serial_printf("[ERROR]attempted to parse unknown format string\n");
|
|
return; // prevent undefined behaviour
|
|
}
|
|
}
|
|
|
|
else // is a regular character
|
|
{
|
|
printchar(string[j]);
|
|
j++;
|
|
}
|
|
}
|
|
va_end(ap); // clean up variable length list
|
|
}
|
|
|
|
void printchar(char character) {
|
|
|
|
switch (character) {
|
|
case '\n': { //For newline, move to next row and focus on the first character.
|
|
col = 0;
|
|
row++;
|
|
break;
|
|
}
|
|
default: { // All other characters simply get written to the buffer.
|
|
const size_t i = (row * 80) + col; //i = index
|
|
vga_buffer[i] = ((uint16_t) current_color << 8) | character;
|
|
col++;
|
|
}
|
|
}
|
|
|
|
if(col > 79) // keep track of row and column for scrolling and newlines
|
|
{
|
|
col = 0;
|
|
row++;
|
|
}
|
|
|
|
if(row > 25)
|
|
{
|
|
handle_scrolling();
|
|
}
|
|
}
|
|
|
|
|
|
void print(const char *string) {
|
|
unsigned int len = strlen(string); // may be better to pass len as an arg
|
|
unsigned int j = 0;
|
|
while(j < len)
|
|
{
|
|
printchar(string[j]);
|
|
j++;
|
|
}
|
|
}
|
|
|
|
// Fill screen with spaces, effectively clearing the screen.
|
|
void clear() {
|
|
unsigned char *vga_memory = (unsigned char *) vga_buffer;
|
|
for(int j = 0; j < 4001; j = j + 2) // 80 * 25 * 2 =4000(end of framebuffer)
|
|
{
|
|
vga_memory[j] = 0x20; // assign a space to current pos
|
|
vga_memory[j + 1] = 0x00; // clear the attribute
|
|
}
|
|
row = 0;
|
|
col = 0;
|
|
i = 0;
|
|
|
|
}
|
|
|
|
// note learn how inline asm works properly
|
|
void set_cursor(int row, int col) {
|
|
unsigned short position=(row*80) + col;
|
|
outb(0x3D4, 0X0F);
|
|
outb(0x3D5, (unsigned char)(position&0xff));
|
|
outb(0x3D4, 0x0E);
|
|
outb(0x3D5, (unsigned char)((position>>8)&0xFF));
|
|
}
|
|
|
|
|
|
// scroll the screen when it gets to the last line
|
|
void handle_scrolling(){
|
|
int x = 160; // start of 2nd line
|
|
|
|
unsigned char *vga_memory = (unsigned char *) vga_buffer;
|
|
|
|
|
|
|
|
while(x < 4001) { // max each char is 2 apart
|
|
vga_memory[x-160] = vga_memory[x]; //Move every character up a line
|
|
vga_memory[x-159] = vga_memory[x+1]; //Move the character attributes too
|
|
x += 2; //Move to next character
|
|
}
|
|
x = 3840; //Start of the last line
|
|
|
|
for(i = 1920; i < 2001; i++) { // Memory locations for the characters in the last line
|
|
vga_memory[x] = 0; //Set current character to 0 (null)
|
|
x += 2; // Move to next character
|
|
}
|
|
|
|
i = 3840; // set i to start of last line
|
|
row = 24; // set row to 25 so when a \n is printed the screen will scroll
|
|
}
|
|
|
|
|
|
void itoa(int num, char *string2) {// convert from int to ascii eqiv
|
|
|
|
int j = 0; // counter
|
|
calc = 0; //Result of a calculation
|
|
bool flag_negative = false;
|
|
|
|
|
|
if(num == 0) { // catch 0
|
|
string2[0] = '0';
|
|
string2[1] = '\0'; // null term
|
|
return;
|
|
}
|
|
|
|
if(num < 0) {
|
|
flag_negative = true;
|
|
num = -num; //invert it so it calcs
|
|
}
|
|
|
|
while(num != 0) {// while we can still divide
|
|
|
|
calc = num % 10; // get raminder in calc
|
|
num = num / 10; // div by 10
|
|
calc += 48; // convert to ascii
|
|
//printchar(calc);
|
|
string2[j] = calc;
|
|
j++; // inc amount of chars to print
|
|
|
|
}
|
|
if(flag_negative) {
|
|
string2[j] = '-';
|
|
j += 1;
|
|
}
|
|
|
|
for(int i=0; i<j/2; i++) {
|
|
calc = string2[i];
|
|
string2[i] = string2[j-i-1];
|
|
string2[j-i-1] = calc;
|
|
|
|
}
|
|
}
|
|
|
|
// convert a number to a hex
|
|
void tohex(int val, char *string) {
|
|
zerostring(string);
|
|
uint8_t j = 8;
|
|
uint8_t temp = 0;
|
|
while(j != 0) {
|
|
j--; // decerment j
|
|
temp = val & 0xf; // get just nibble into temp
|
|
val = val >> 4; // shr val four so that it loses char
|
|
if(temp >= 10) {
|
|
temp += 7; // if higher than 10 convert to letter
|
|
}
|
|
temp += 48; //convert to ascii
|
|
string[j] = temp;
|
|
}
|
|
}
|
|
|
|
// Fill the string pointer with 0 (null) characters
|
|
void zerostring(char *string) {
|
|
unsigned int len = strlen(string);
|
|
for(unsigned int i = 0; i <= len; i++)
|
|
{
|
|
string[i] = '\0';
|
|
}
|
|
}
|
|
|
|
|
|
unsigned int strlen(const char *string) {
|
|
unsigned int len = 0;
|
|
while(string[len])
|
|
{
|
|
len++;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
// print out registers for debugging
|
|
/*void writeregs(void)
|
|
{
|
|
unsigned int Register = 0;
|
|
|
|
|
|
|
|
|
|
}*/
|