tape-kernel 1.0
a modular modern independent kernel
Loading...
Searching...
No Matches
vga.c
Go to the documentation of this file.
1//vga.c - vga based out and inp stuff
2#include "../lib/types.h"
3#include "vga.h"
4#include "kb.h"
5#include "cm.h"
6#include "../lib/err.h"
7#include "../lib/utils.h"
8
9/**
10 * @brief the vga framebuffer pointer
11 *
12 * vga points to the vga text-mode framebuffer at physical address
13 * 0xB8000, each cell is a uint16_t with the lower byte as the
14 * character and the upper byte as the color attribute
15 *
16 * @see prt(), clscr(), scrl()
17 */
18uint16_t* vga = (uint16_t*)0xB8000;
19
20/**
21 * @brief scrl scrolls the vga text screen up by one row
22 *
23 * scrl is a function that shifts all rows up by one and clears
24 * the bottom row, used for when text output fills the screen
25 *
26 * scrl is called automatically by prt when y goes past 24
27 *
28 * @see prt(), clscr()
29 */
30void __scrl(void) {
31 for (int rw = 1; rw < 25; rw++) { //main row loop
32 for (int cl = 0; cl < 80; cl++) { //main collum loop
33 int src = rw * 80 + cl; //define source dest
34 int dst = (rw - 1) * 80 + cl; //define dest dest
35 vga[dst] = vga[src]; //define vga loc
36 }
37 }
38 for (int cl = 0; cl < 80; cl++) { //actual scroll loop
39 int btm = 24 * 80 + cl; //bottom def
40 vga[btm] = (0x0F << 8) | ' '; //clear bottom row
41 }
42}
43
44/**
45 * @brief prt prints a string to the vga screen at a given position
46 *
47 * prt is a function that writes a null-terminated string to the vga
48 * text framebuffer handling newlines, line wrapping, and scrolling
49 * @param x, the column to start printing at (0-79)
50 * @param y, the row to start printing at (0-24)
51 * @param txt, the null-terminated string to print
52 * @param col, the vga color attribute byte (0x00-0xFF)
53 *
54 * using prt is done with
55 * @code{.c}
56 * #include "../io/vga.h" //or just vga.h
57 * prt(0, 0, "hello, kernel!", 0x0F); //white text on black bg
58 * @endcode
59 *
60 * @see scrl(), pchr(), prtd(), prth()
61 */
62void __prt(int x, int y, const char* txt, uint8_t col) {
63 assert(txt != NULL, "prt: NULL string"); //err checking
64 if (x >= 80) { x = 79; }; //cases
65 if (x < 0) { x = 0; };
66 if (y >= 25 && x == 0) {
67 scrl(); //scroll
68 y = 24; //reset
69 } else if (y >= 25 && x > 0) { y = 24; }
70 if (y < 0) { y = 0; };
71
72
73
74 int ofst = y * 80 + x; //ofst calculation
75
76 while (*txt != 0) { //main loop
77 assert(ofst >= 0 && ofst < 2000, "prt: vga buffer overflow"); //err handle AFTER calc, do not move
78
79 if (*txt == '\n') { //newline handle
80 y++; //inc y for the new line
81 x = 0; //reset x
82 ofst = y * 80 + x; //recalc
83 } else {
84 vga[ofst] = (col << 8) | *txt; //print txt
85 //format is 0x<bg><txtcolor>, ignoring first letter of code, so 0xED is light purple text on a yellow bg
86 //0 is black
87 //1 is blue
88 //2 is green
89 //3 is cyan
90 //4 is red
91 //5 is purple
92 //6 is orange
93 //7 is light grey
94 //8 is dark grey
95 //9 is light blue
96 //A is light green
97 //B is light cyan
98 //C is light red
99 //D is light purple
100 //E is yellow
101 //F is white
102 ofst++; //increment ofst char loc
103 x++; //increment x for check
104 if (x >= 80) { //line wrapping check
105 x = 0; //reset x
106 y++; //inc y for the line wrap
107 ofst = y * 80 + x; //recalc
108 }
109 }
110 txt++; //now increment txt++ outside of loops to make sure we dont inc under only one condition
111
112 if (y >= 25) {
113 scrl(); //scroll stuff and handle
114 y = 24; //make y clamp
115 ofst = y * 80 + x;
116 }
117 }
118}
119
120/**
121 * @brief prtd prints a decimal integer to the vga screen
122 *
123 * prtd is a function that converts an integer to a decimal string
124 * using itoa and prints it at the given position
125 * @param x, the column to start printing at
126 * @param y, the row to start printing at
127 * @param num, the signed integer to print
128 * @param col, the vga color attribute byte
129 *
130 * using prtd is done with
131 * @code{.c}
132 * #include "../io/vga.h" //or just vga.h
133 * prtd(0, 5, 42, 0x0F);
134 * @endcode
135 *
136 * @see prt(), prth(), itoa()
137 */
138void __prtd(int x, int y, int num, uint8_t col) {
139 char buff[12] = {0}; //12 bytes is safe for 32 bit int
140 itoa(num, buff); //convert with itoa
141 prt(x, y, buff, col); //print
142}
143
144/**
145 * @brief prth prints a 32 bit hex value to the vga screen
146 *
147 * prth is a function that converts a uint32_t to an 8 character
148 * hexadecimal string and prints it at the given position
149 * @param x, the column to start printing at
150 * @param y, the row to start printing at
151 * @param hex, the 32 bit unsigned integer to print in hex
152 * @param col, the vga color attribute byte
153 *
154 * using prth is done with
155 * @code{.c}
156 * #include "../io/vga.h" //or just vga.h
157 * prth(0, 0, 0x00007C00, 0x0F);
158 * @endcode
159 *
160 * @see prt(), prtd()
161 */
162void __prth(int x, int y, uint32_t hex, uint8_t col) {
163 static const char chars[] = "0123456789ABCDEF";
164 char output[9]; //make array
165
166 output[0] = chars[(hex >> 28) & 0xF]; //output table
167 output[1] = chars[(hex >> 24) & 0xF];
168 output[2] = chars[(hex >> 20) & 0xF];
169 output[3] = chars[(hex >> 16) & 0xF];
170 output[4] = chars[(hex >> 12) & 0xF];
171 output[5] = chars[(hex >> 8) & 0xF];
172 output[6] = chars[(hex >> 4) & 0xF];
173 output[7] = chars[hex & 0xF];
174 output[8] = '\0';
175 //this is crude but works
176 prt(x, y, output, col); //prt
177}
178
179/**
180 * @brief clscr clears the entire vga text screen
181 *
182 * clscr is a function that fills all 2000 vga cells with spaces
183 * using the default white-on-black color attribute
184 *
185 * using clscr is done with
186 * @code{.c}
187 * #include "../io/vga.h" //or just vga.h
188 * clscr();
189 * @endcode
190 *
191 * @see scrl(), prt()
192 */
193void __clscr(void) {
194 for (int ctr = 0; ctr < 2000; ctr++) { //main loop, we do this for all vga cells, aka 2000
195 vga[ctr] = (0x0F << 8) | ' '; //set to space aka blank
196 }
197}
198
199/**
200 * @brief rdln reads a line of text input from the keyboard
201 *
202 * rdln is a function that reads keyboard input into a buffer,
203 * handling backspace, echoing characters, and returning on enter
204 * @param buffer, the buffer to store the input string in
205 * @param maxlen, the maximum length of the input including null
206 *
207 * using rdln is done with
208 * @code{.c}
209 * #include "../io/vga.h" //or just vga.h
210 * char input[100];
211 * rdln(input, 100);
212 * @endcode
213 *
214 * @see gtchr(), prt(), cob()
215 */
216void __rdln(char *buffer, int maxlen) {
217 assert(buffer != NULL, "rdln: NULL buffer"); //err handle
218 assert(maxlen > 0, "rdln: maxlen zero");
219
220 int pos = 0; //pos counter and nchr setup
221 uint8_t nchr; //make not-char
222 int cx; //cursor vals
223 int cy;
224 cnb(&cx, &cy); //read current
225
226 while (1) {
227 nchr = gtchr(); //set nchr to gtchr
228
229 if (nchr == '\n') {
230 cnb(&cx, &cy);
231 buffer[pos] = 0; //buffer pos ctr
232 cy++; //inc cursor y
233 if (cy >= 25) { //scrl handle
234 scrl();
235 cy = 24; //decrement cy
236 }
237 cx = 0; //cx handle
238 cob(cx, cy); //export
239 return; //break
240 }
241 else if (nchr == '\b' && pos > 0) { //backspace handle
242 pos--; //decrement pos for counting
243 prt(cx - 1, cy, " ", 0x0F); //clear chr
244 cnb(&cx, &cy);
245 cx--; //decrement cursor x
246 cob(cx, cy); //export new csr vals
247 }
248 else if (nchr >= ' ' && pos < maxlen - 1) { //actual handle for maxlen check and other stuff
249 buffer[pos] = (char)nchr; //change buffer
250 pos++; //inc pos
251 char chr[2] = {(char)nchr, 0}; //convert it
252 prt(cx, cy, chr, 0x0F); //echo char
253 cnb(&cx, &cy);
254 cx++; //inc
255 cob(cx, cy); //export
256 }
257 }
258}
259
260/**
261 * @brief drw draws a line on the vga screen using '#' characters
262 *
263 * drw is a function that draws horizontal, vertical, or diagonal
264 * lines on the vga screen using bresenhams line algorithm for the
265 * diagonal case
266 * @param x1, the starting column (0-79)
267 * @param y1, the starting row (0-24)
268 * @param x2, the ending column (0-79)
269 * @param y2, the ending row (0-24)
270 * @param col, the vga color attribute byte
271 *
272 * using drw is done with
273 * @code{.c}
274 * #include "../io/vga.h" //or just vga.h
275 * drw(10, 5, 50, 5, 0x0A); //horizontal green line
276 * @endcode
277 *
278 * @see prt(), pchr()
279 */
280void __drw(int x1, int y1, int x2, int y2, uint8_t col) {
281 //err handle
282 assert(x1 >= 0 && x1 < 80, "drw: invalid x1");
283 assert(y1 >= 0 && y1 < 25, "drw: invalid y1");
284 assert(x2 >= 0 && x2 < 80, "drw: invalid x2");
285 assert(y2 >= 0 && y2 < 25, "drw: invalid y2");
286
287 int tx = x1;
288 int ty = y1;
289
290 //horizontal line
291 if (y1 == y2) {
292 int start = (x1 < x2) ? x1 : x2;
293 int end = (x1 > x2) ? x1 : x2;
294 for (tx = start; tx <= end; tx++) {
295 prt(tx, y1, "#", col); //enumerate
296 }
297 }
298 //vertical line
299 else if (x1 == x2) {
300 int start = (y1 < y2) ? y1 : y2;
301 int end = (y1 > y2) ? y1 : y2;
302 for (ty = start; ty <= end; ty++) { //enum for v
303 prt(x1, ty, "#", col);
304 }
305 }
306 //diagonal line using bresenhams algorithm
307 else {
308 int dx = abs(x2 - x1);
309 int dy = abs(y2 - y1);
310 int sx = (x1 < x2) ? 1 : -1;
311 int sy = (y1 < y2) ? 1 : -1;
312 int err = dx - dy;
313
314 tx = x1;
315 ty = y1;
316
317 while (1) {
318 prt(tx, ty, "#", col); //main prt loop
319 if (tx == x2 && ty == y2) break;
320
321 int err2 = 2 * err; //err is for diagonal not err handling lol
322 if (err2 > -dy) {
323 err -= dy;
324 tx += sx;
325 }
326 if (err2 < dx) {
327 err += dx;
328 ty += sy;
329 }
330 }
331 }
332}
333
334/**
335 * @brief pchr prints a single raw character to the vga screen
336 *
337 * pchr is a function that prints a single character at a given
338 * screen position, useful for printing extended ascii characters
339 * @param x, the column to print at
340 * @param y, the row to print at
341 * @param chr, the raw character to print (e.g. a char literal)
342 * @param col, the vga color attribute byte
343 *
344 * using pchr is done with
345 * @code{.c}
346 * #include "../io/vga.h" //or just vga.h
347 * pchr(40, 12, 0xDB, 0x0F); //solid block char
348 * @endcode
349 *
350 * @see prt(), drw()
351 */
352void __pchr(int x, int y, char chr, uint8_t col) {
353 char str[2] = {chr, 0}; //0 is null term
354 prt(x, y, str, col); //prt
355}
#define cnb
Definition cm.h:6
#define cob
Definition cm.h:7
#define assert
Definition err.h:4
#define gtchr
Definition kb.h:6
#define NULL
Definition types.h:38
unsigned short uint16_t
Definition types.h:29
unsigned int uint32_t
Definition types.h:30
unsigned char uint8_t
Definition types.h:28
int abs(int x)
Definition utils.c:5
void itoa(int num, char *str)
itoa converts an integer to a decimal string
Definition utils.c:49
void __prtd(int x, int y, int num, uint8_t col)
prtd prints a decimal integer to the vga screen
Definition vga.c:138
void __scrl(void)
scrl scrolls the vga text screen up by one row
Definition vga.c:30
void __drw(int x1, int y1, int x2, int y2, uint8_t col)
drw draws a line on the vga screen using '#' characters
Definition vga.c:280
uint16_t * vga
the vga framebuffer pointer
Definition vga.c:18
void __rdln(char *buffer, int maxlen)
rdln reads a line of text input from the keyboard
Definition vga.c:216
void __pchr(int x, int y, char chr, uint8_t col)
pchr prints a single raw character to the vga screen
Definition vga.c:352
void __prt(int x, int y, const char *txt, uint8_t col)
prt prints a string to the vga screen at a given position
Definition vga.c:62
void __clscr(void)
clscr clears the entire vga text screen
Definition vga.c:193
void __prth(int x, int y, uint32_t hex, uint8_t col)
prth prints a 32 bit hex value to the vga screen
Definition vga.c:162
#define scrl
Definition vga.h:8
#define prt
Definition vga.h:6