Skip to content

Commit f8369ec

Browse files
committed
lesson 17, video scroll
1 parent 3530dd7 commit f8369ec

File tree

10 files changed

+208
-0
lines changed

10 files changed

+208
-0
lines changed

17-video-scroll/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../14-checkpoint/Makefile

17-video-scroll/README.md

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

17-video-scroll/boot

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../14-checkpoint/boot/

17-video-scroll/drivers/ports.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../16-video-driver/drivers/ports.c

17-video-scroll/drivers/ports.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../16-video-driver/drivers/ports.h

17-video-scroll/drivers/screen.c

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#include "screen.h"
2+
#include "ports.h"
3+
#include "../kernel/util.h"
4+
5+
/* Declaration of private functions */
6+
int get_cursor_offset();
7+
void set_cursor_offset(int offset);
8+
int print_char(char c, int col, int row, char attr);
9+
int get_offset(int col, int row);
10+
int get_offset_row(int offset);
11+
int get_offset_col(int offset);
12+
13+
/**********************************************************
14+
* Public Kernel API functions *
15+
**********************************************************/
16+
17+
/**
18+
* Print a message on the specified location
19+
* If col, row, are negative, we will use the current offset
20+
*/
21+
void kprint_at(char *message, int col, int row) {
22+
/* Set cursor if col/row are negative */
23+
int offset;
24+
if (col >= 0 && row >= 0)
25+
offset = get_offset(col, row);
26+
else {
27+
offset = get_cursor_offset();
28+
row = get_offset_row(offset);
29+
col = get_offset_col(offset);
30+
}
31+
32+
/* Loop through message and print it */
33+
int i = 0;
34+
while (message[i] != 0) {
35+
offset = print_char(message[i++], col, row, WHITE_ON_BLACK);
36+
/* Compute row/col for next iteration */
37+
row = get_offset_row(offset);
38+
col = get_offset_col(offset);
39+
}
40+
}
41+
42+
void kprint(char *message) {
43+
kprint_at(message, -1, -1);
44+
}
45+
46+
47+
/**********************************************************
48+
* Private kernel functions *
49+
**********************************************************/
50+
51+
52+
/**
53+
* Innermost print function for our kernel, directly accesses the video memory
54+
*
55+
* If 'col' and 'row' are negative, we will print at current cursor location
56+
* If 'attr' is zero it will use 'white on black' as default
57+
* Returns the offset of the next character
58+
* Sets the video cursor to the returned offset
59+
*/
60+
int print_char(char c, int col, int row, char attr) {
61+
unsigned char *vidmem = (unsigned char*) VIDEO_ADDRESS;
62+
if (!attr) attr = WHITE_ON_BLACK;
63+
64+
/* Error control: print a red 'E' if the coords aren't right */
65+
if (col >= MAX_COLS || row >= MAX_ROWS) {
66+
vidmem[2*(MAX_COLS)*(MAX_ROWS)-2] = 'E';
67+
vidmem[2*(MAX_COLS)*(MAX_ROWS)-1] = RED_ON_WHITE;
68+
return get_offset(col, row);
69+
}
70+
71+
int offset;
72+
if (col >= 0 && row >= 0) offset = get_offset(col, row);
73+
else offset = get_cursor_offset();
74+
75+
if (c == '\n') {
76+
row = get_offset_row(offset);
77+
offset = get_offset(0, row+1);
78+
} else {
79+
vidmem[offset] = c;
80+
vidmem[offset+1] = attr;
81+
offset += 2;
82+
}
83+
84+
/* Check if the offset is over screen size and scroll */
85+
if (offset >= MAX_ROWS * MAX_COLS * 2) {
86+
int i;
87+
for (i = 1; i < MAX_ROWS; i++)
88+
memory_copy(get_offset(0, i) + VIDEO_ADDRESS,
89+
get_offset(0, i-1) + VIDEO_ADDRESS,
90+
MAX_COLS * 2);
91+
92+
/* Blank last line */
93+
char *last_line = get_offset(0, MAX_ROWS-1) + VIDEO_ADDRESS;
94+
for (i = 0; i < MAX_COLS * 2; i++) last_line[i] = 0;
95+
96+
offset -= 2 * MAX_COLS;
97+
}
98+
99+
set_cursor_offset(offset);
100+
return offset;
101+
}
102+
103+
int get_cursor_offset() {
104+
/* Use the VGA ports to get the current cursor position
105+
* 1. Ask for high byte of the cursor offset (data 14)
106+
* 2. Ask for low byte (data 15)
107+
*/
108+
port_byte_out(REG_SCREEN_CTRL, 14);
109+
int offset = port_byte_in(REG_SCREEN_DATA) << 8; /* High byte: << 8 */
110+
port_byte_out(REG_SCREEN_CTRL, 15);
111+
offset += port_byte_in(REG_SCREEN_DATA);
112+
return offset * 2; /* Position * size of character cell */
113+
}
114+
115+
void set_cursor_offset(int offset) {
116+
/* Similar to get_cursor_offset, but instead of reading we write data */
117+
offset /= 2;
118+
port_byte_out(REG_SCREEN_CTRL, 14);
119+
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset >> 8));
120+
port_byte_out(REG_SCREEN_CTRL, 15);
121+
port_byte_out(REG_SCREEN_DATA, (unsigned char)(offset & 0xff));
122+
}
123+
124+
void clear_screen() {
125+
int screen_size = MAX_COLS * MAX_ROWS;
126+
int i;
127+
char *screen = VIDEO_ADDRESS;
128+
129+
for (i = 0; i < screen_size; i++) {
130+
screen[i*2] = ' ';
131+
screen[i*2+1] = WHITE_ON_BLACK;
132+
}
133+
set_cursor_offset(get_offset(0, 0));
134+
}
135+
136+
137+
int get_offset(int col, int row) { return 2 * (row * MAX_COLS + col); }
138+
int get_offset_row(int offset) { return offset / (2 * MAX_COLS); }
139+
int get_offset_col(int offset) { return (offset - (get_offset_row(offset)*2*MAX_COLS))/2; }

17-video-scroll/drivers/screen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../16-video-driver/drivers/screen.h

17-video-scroll/kernel/kernel.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include "../drivers/screen.h"
2+
#include "util.h"
3+
4+
void main() {
5+
clear_screen();
6+
7+
/* Fill up the screen */
8+
int i = 0;
9+
for (i = 0; i < 24; i++) {
10+
char str[255];
11+
int_to_ascii(i, str);
12+
kprint_at(str, 0, i);
13+
}
14+
15+
kprint_at("This text forces the kernel to scroll. Row 0 will disappear. ", 60, 24);
16+
kprint("And with this text, the kernel will scroll again, and row 1 will disappear too!");
17+
}

17-video-scroll/kernel/util.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
void memory_copy(char *source, char *dest, int nbytes) {
2+
int i;
3+
for (i = 0; i < nbytes; i++) {
4+
*(dest + i) = *(source + i);
5+
}
6+
}
7+
8+
/**
9+
* K&R implementation
10+
*/
11+
void int_to_ascii(int n, char str[]) {
12+
int i, sign;
13+
if ((sign = n) < 0) n = -n;
14+
i = 0;
15+
do {
16+
str[i++] = n % 10 + '0';
17+
} while ((n /= 10) > 0);
18+
19+
if (sign < 0) str[i++] = '-';
20+
str[i] = '\0';
21+
22+
/* TODO: implement "reverse" */
23+
}

17-video-scroll/kernel/util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
void memory_copy(char *source, char *dest, int nbytes);
2+
void int_to_ascii(int n, char str[]);

0 commit comments

Comments
 (0)