blob: 11fbc0c0ffd1ef5648a54f045dde4dfbe8fc9b3a [file] [log] [blame]
swissChilid8137922021-02-17 15:34:07 -08001#include "vga.h"
2#include "mem.h"
swissChili0b35bf22021-02-18 12:49:40 -08003#include "log.h"
swissChilid8137922021-02-17 15:34:07 -08004
5static uint cursor_x = 0;
6static uint cursor_y = 0;
7
8static ushort color = WHITE;
9
10static ushort *fb = (ushort *)0xB8000;
11
12static void move_cursor()
13{
14 ushort loc = cursor_y * 80 + cursor_x;
15 outb(0x3d4, 14); // Setting high cursor byte
16 outb(0x3d4, loc >> 8);
17
18 outb(0x3d4, 15); // low byte
19 outb(0x3d4, loc & 0xff);
20}
21
22static void scroll()
23{
24 ushort blank = ' ' | color << 8;
25
26 while (cursor_y >= 25) // end of line
27 {
28 // scroll everything up
29 memcpy(fb, &fb[80], 24 * 80 * 2);
30
31 for (int i = 24 * 80; i < 25 * 80; i++)
32 {
33 fb[i] = blank;
34 }
35
36 cursor_y--;
37 }
38}
39
40void vga_set_color(enum vga_colors fg, enum vga_colors bg)
41{
42 color = (bg << 4) | fg & 0xf;
43}
44
45void vga_put(char c)
46{
47 switch (c)
48 {
49 case '\b':
50 if (cursor_x > 0)
51 cursor_x--;
52 break;
53 case '\t':
54 cursor_x = (cursor_x + 8) & ~ 7;
55 break;
56 case '\n':
57 cursor_y++;
58 case '\r':
59 cursor_x = 0;
60 break;
61 default:
62 cursor_x++;
63 fb[cursor_y * 80 + cursor_x] = c | (color << 8);
64 }
65
66 if (cursor_x >= 80) // off screen
67 {
68 cursor_x = 0;
69 cursor_y++;
70 }
71
72 scroll();
73 move_cursor();
74}
75
76void vga_clear()
77{
78 memset(fb, 0, 80 * 25 * 2);
79 cursor_x = 0;
80 cursor_y = 0;
81 move_cursor();
82}
83
84void vga_write(char *c)
85{
86 for (int i = 0; c[i]; i++)
87 vga_put(c[i]);
88}
89
90void vga_putd(uint d)
91{
swissChili0b35bf22021-02-18 12:49:40 -080092 char str[48];
93 memset(str, 0, 48);
94 uint i = 0;
95
96 while (d > 0 && i < 48) // should never be more than 48 digits anyway
97 {
98 str[i++] = (d % 10) + '0';
99 d /= 10;
100 }
101
102 for (uint j = i; j; j--)
103 {
104 vga_put(str[j - 1]);
105 }
swissChilid8137922021-02-17 15:34:07 -0800106}
107
swissChili0b35bf22021-02-18 12:49:40 -0800108static bool vga_put_nibble(uchar n, bool first)
swissChilid8137922021-02-17 15:34:07 -0800109{
swissChili0b35bf22021-02-18 12:49:40 -0800110 if (first && n == 0)
111 return true;
112
swissChilid8137922021-02-17 15:34:07 -0800113 if (n <= 9)
114 vga_put('0' + n);
115 else
116 vga_put('A' + n - 10);
swissChili0b35bf22021-02-18 12:49:40 -0800117
118 return false;
swissChilid8137922021-02-17 15:34:07 -0800119}
120
121void vga_putx(uint x)
122{
swissChili0b35bf22021-02-18 12:49:40 -0800123 bool first = true;
124
swissChilid8137922021-02-17 15:34:07 -0800125 for (uint mask = 0xFF000000, shift = 24; mask; mask >>= 8, shift -= 8)
126 {
127 uchar byte = (x & mask) >> shift;
128
swissChili0b35bf22021-02-18 12:49:40 -0800129 first = vga_put_nibble((byte & 0xf0) >> 8, first);
130 first = vga_put_nibble(byte & 0x0f, first);
swissChilid8137922021-02-17 15:34:07 -0800131 }
132}