mirror of
https://github.com/cfenollosa/os-tutorial.git
synced 2024-10-27 20:34:19 +00:00
lesson 17, video scroll
This commit is contained in:
parent
3530dd700c
commit
f8369ec919
1
17-video-scroll/Makefile
Symbolic link
1
17-video-scroll/Makefile
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../14-checkpoint/Makefile
|
22
17-video-scroll/README.md
Normal file
22
17-video-scroll/README.md
Normal file
@ -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.
|
1
17-video-scroll/boot
Symbolic link
1
17-video-scroll/boot
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../14-checkpoint/boot/
|
1
17-video-scroll/drivers/ports.c
Symbolic link
1
17-video-scroll/drivers/ports.c
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../16-video-driver/drivers/ports.c
|
1
17-video-scroll/drivers/ports.h
Symbolic link
1
17-video-scroll/drivers/ports.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../16-video-driver/drivers/ports.h
|
139
17-video-scroll/drivers/screen.c
Normal file
139
17-video-scroll/drivers/screen.c
Normal file
@ -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; }
|
1
17-video-scroll/drivers/screen.h
Symbolic link
1
17-video-scroll/drivers/screen.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../16-video-driver/drivers/screen.h
|
17
17-video-scroll/kernel/kernel.c
Normal file
17
17-video-scroll/kernel/kernel.c
Normal file
@ -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!");
|
||||||
|
}
|
23
17-video-scroll/kernel/util.c
Normal file
23
17-video-scroll/kernel/util.c
Normal file
@ -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" */
|
||||||
|
}
|
2
17-video-scroll/kernel/util.h
Normal file
2
17-video-scroll/kernel/util.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
void memory_copy(char *source, char *dest, int nbytes);
|
||||||
|
void int_to_ascii(int n, char str[]);
|
Loading…
Reference in New Issue
Block a user