lesson 17, video scroll

pull/6/head
Carlos Fenollosa 10 years ago
parent 3530dd700c
commit f8369ec919

@ -0,0 +1 @@
../14-checkpoint/Makefile

@ -0,0 +1,22 @@
*Concepts you may want to Google beforehand: scroll*
**Goal: Scroll the screen when the text reaches the bottom**
For this short lesson, open `drivers/screen.c` and note that at the
bottom of `print_char` there is a new section (line 84) which checks
if the current offset is over the screen size and scrolls the text.
The actual scrolling is handled by a new function, `memory_copy`. It is
a simpler version of the standard `memcpy` but we named it differently
to avoid namespace collisions, at least for now. Open `kernel/util.c` to
see its implementation.
To help visualize scrolling, we will also implement a function to
convert integers to text, `int_to_ascii`. Again, it is a quick implementation
of the standard `itoa`. Notice that for integers which have double digits
or more, they are printed in reverse. This is intended. On future lessons
we will extend our helper functions, but that is not the point for now.
Finally, open `kernel/kernel.c`. Initially, each line displays its line
number. You can set a breakpoint on line 14 to confirm this. Then,
the following `kprint`s force the kernel to scroll down.

@ -0,0 +1 @@
../14-checkpoint/boot/

@ -0,0 +1 @@
../../16-video-driver/drivers/ports.c

@ -0,0 +1 @@
../../16-video-driver/drivers/ports.h

@ -0,0 +1,139 @@
#include "screen.h"
#include "ports.h"
#include "../kernel/util.h"
/* Declaration of private functions */
int get_cursor_offset();
void set_cursor_offset(int offset);
int print_char(char c, int col, int row, char attr);
int get_offset(int col, int row);
int get_offset_row(int offset);
int get_offset_col(int offset);
/**********************************************************
* Public Kernel API functions *
**********************************************************/
/**
* Print a message on the specified location
* If col, row, are negative, we will use the current offset
*/
void kprint_at(char *message, int col, int row) {
/* Set cursor if col/row are negative */
int offset;
if (col >= 0 && row >= 0)
offset = get_offset(col, row);
else {
offset = get_cursor_offset();
row = get_offset_row(offset);
col = get_offset_col(offset);
}
/* Loop through message and print it */
int i = 0;
while (message[i] != 0) {
offset = print_char(message[i++], col, row, WHITE_ON_BLACK);
/* Compute row/col for next iteration */
row = get_offset_row(offset);
col = get_offset_col(offset);
}
}
void kprint(char *message) {
kprint_at(message, -1, -1);
}
/**********************************************************
* Private kernel functions *
**********************************************************/
/**
* Innermost print function for our kernel, directly accesses the video memory
*
* If 'col' and 'row' are negative, we will print at current cursor location
* If 'attr' is zero it will use 'white on black' as default
* Returns the offset of the next character
* Sets the video cursor to the returned offset
*/
int print_char(char c, int col, int row, char attr) {
unsigned char *vidmem = (unsigned char*) VIDEO_ADDRESS;
if (!attr) attr = WHITE_ON_BLACK;
/* Error control: print a red 'E' if the coords aren't right */
if (col >= MAX_COLS || row >= MAX_ROWS) {
vidmem[2*(MAX_COLS)*(MAX_ROWS)-2] = 'E';
vidmem[2*(MAX_COLS)*(MAX_ROWS)-1] = RED_ON_WHITE;
return get_offset(col, row);
}
int offset;
if (col >= 0 && row >= 0) offset = get_offset(col, row);
else offset = get_cursor_offset();
if (c == '\n') {
row = get_offset_row(offset);
offset = get_offset(0, row+1);
} else {
vidmem[offset] = c;
vidmem[offset+1] = attr;
offset += 2;
}
/* Check if the offset is over screen size and scroll */
if (offset >= MAX_ROWS * MAX_COLS * 2) {
int i;
for (i = 1; i < MAX_ROWS; i++)
memory_copy(get_offset(0, i) + VIDEO_ADDRESS,
get_offset(0, i-1) + VIDEO_ADDRESS,
MAX_COLS * 2);
/* Blank last line */
char *last_line = get_offset(0, MAX_ROWS-1) + VIDEO_ADDRESS;
for (i = 0; i < MAX_COLS * 2; i++) last_line[i] = 0;
offset -= 2 * MAX_COLS;
}
set_cursor_offset(offset);
return offset;
}
int get_cursor_offset() {
/* Use the VGA ports to get the current cursor position
* 1. Ask for high byte of the cursor offset (data 14)
* 2. Ask for low byte (data 15)
*/
port_byte_out(REG_SCREEN_CTRL, 14);
int offset = port_byte_in(REG_SCREEN_DATA) << 8; /* High byte: << 8 */
port_byte_out(REG_SCREEN_CTRL, 15);
offset += port_byte_in(REG_SCREEN_DATA);
return offset * 2; /* Position * size of character cell */
}
void set_cursor_offset(int offset) {
/* Similar to get_cursor_offset, but instead of reading we write data */
offset /= 2;
port_byte_out(REG_SCREEN_CTRL, 14);
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
port_byte_out(REG_SCREEN_CTRL, 15);
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff));
}
void clear_screen() {
int screen_size = MAX_COLS * MAX_ROWS;
int i;
char *screen = VIDEO_ADDRESS;
for (i = 0; i < screen_size; i++) {
screen[i*2] = ' ';
screen[i*2+1] = WHITE_ON_BLACK;
}
set_cursor_offset(get_offset(0, 0));
}
int get_offset(int col, int row) { return 2 * (row * MAX_COLS + col); }
int get_offset_row(int offset) { return offset / (2 * MAX_COLS); }
int get_offset_col(int offset) { return (offset - (get_offset_row(offset)*2*MAX_COLS))/2; }

@ -0,0 +1 @@
../../16-video-driver/drivers/screen.h

@ -0,0 +1,17 @@
#include "../drivers/screen.h"
#include "util.h"
void main() {
clear_screen();
/* Fill up the screen */
int i = 0;
for (i = 0; i < 24; i++) {
char str[255];
int_to_ascii(i, str);
kprint_at(str, 0, i);
}
kprint_at("This text forces the kernel to scroll. Row 0 will disappear. ", 60, 24);
kprint("And with this text, the kernel will scroll again, and row 1 will disappear too!");
}

@ -0,0 +1,23 @@
void memory_copy(char *source, char *dest, int nbytes) {
int i;
for (i = 0; i < nbytes; i++) {
*(dest + i) = *(source + i);
}
}
/**
* K&R implementation
*/
void int_to_ascii(int n, char str[]) {
int i, sign;
if ((sign = n) < 0) n = -n;
i = 0;
do {
str[i++] = n % 10 + '0';
} while ((n /= 10) > 0);
if (sign < 0) str[i++] = '-';
str[i] = '\0';
/* TODO: implement "reverse" */
}

@ -0,0 +1,2 @@
void memory_copy(char *source, char *dest, int nbytes);
void int_to_ascii(int n, char str[]);
Loading…
Cancel
Save