2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018-2023 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY, without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
30 #define TEXT_ADDR ((char*)0xb8000)
32 #define CRTC_ADDR 0x3d4
33 #define CRTC_DATA 0x3d5
35 #define CRTC_REG_CURSTART 0x0a
36 #define CRTC_REG_CUREND 0x0b
37 #define CRTC_REG_START_H 0x0c
38 #define CRTC_REG_START_L 0x0d
39 #define CRTC_REG_CURLOC_H 0x0e
40 #define CRTC_REG_CURLOC_L 0x0f
42 #define VMEM_CHAR(c, attr) \
43 (((uint16_t)(c) & 0xff) | ((uint16_t)(attr) << 8))
45 static void scroll(void);
46 static void crtc_cursor(int x, int y);
47 static void crtc_getcursor(int *x, int *y);
48 static void crtc_setstart(int y);
49 static int crtc_getstart(void);
50 static inline unsigned char crtc_read(int reg);
51 static inline void crtc_write(int reg, unsigned char val);
53 static int cursor_x, cursor_y;
54 static unsigned char txattr = 0x07;
55 static int start_line;
56 static unsigned char cy0, cy1;
58 static int scr_on = 1;
64 ser_open(1, 9600, SER_8N1);
68 cy0 = crtc_read(CRTC_REG_CURSTART);
69 curvis = cy0 & 0x20 ? 1 : 0;
71 cy1 = crtc_read(CRTC_REG_CUREND) & 0x1f;
73 start_line = crtc_getstart();
74 crtc_getcursor(&cursor_x, &cursor_y);
82 void con_scr_enable(void)
87 void con_scr_disable(void)
92 void con_show_cursor(int show)
95 unsigned char val = cy0 & 0x1f;
99 crtc_write(CRTC_REG_CURSTART, val);
104 void con_cursor(int x, int y)
113 void con_curattr(int shape, int blink)
117 cy0 = (shape == CON_CURSOR_LINE) ? 0xd : 0;
125 crtc_write(CRTC_REG_CURSTART, start);
126 crtc_write(CRTC_REG_CUREND, cy0);
130 void con_fgcolor(int c)
132 txattr = (txattr & 0xf0) | c;
135 void con_bgcolor(int c)
137 txattr = (txattr & 0x0f) | (c << 4);
140 void con_setattr(unsigned char attr)
145 unsigned char con_getattr(void)
153 memset16(TEXT_ADDR, VMEM_CHAR(' ', txattr), NCOLS * NROWS);
158 cursor_x = cursor_y = 0;
163 static inline void linefeed(void)
165 if(++cursor_y >= NROWS) {
171 void con_putchar(int c)
180 crtc_cursor(cursor_x, cursor_y);
184 cursor_x = (cursor_x & 0x7) + 8;
185 if(cursor_x >= NCOLS) {
189 crtc_cursor(cursor_x, cursor_y);
193 if(cursor_x > 0) cursor_x--;
194 con_putchar_scr(cursor_x, cursor_y, ' ');
195 crtc_cursor(cursor_x, cursor_y);
199 con_putchar_scr(cursor_x, cursor_y, c);
201 if(++cursor_x >= NCOLS) {
205 crtc_cursor(cursor_x, cursor_y);
215 void con_putchar_scr(int x, int y, int c)
218 uint16_t *ptr = (uint16_t*)TEXT_ADDR;
219 ptr[(y + start_line) * NCOLS + x] = VMEM_CHAR(c, txattr);
223 int con_printf(int x, int y, const char *fmt, ...)
231 vsnprintf(buf, 80, fmt, ap);
234 while(*ptr && x < 80) {
235 con_putchar_scr(x++, y, *ptr++);
243 static void scroll(void)
247 if(++start_line > VIRT_ROWS - NROWS) {
248 /* The bottom of the visible range reached the end of our text buffer.
249 * Copy the rest of the lines to the top and reset start_line.
251 memcpy(TEXT_ADDR, TEXT_ADDR + start_line * NCOLS, (NROWS - 1) * NCOLS * 2);
255 /* clear the next line that will be revealed by scrolling */
256 new_line = start_line + NROWS - 1;
257 memset16(TEXT_ADDR + new_line * NCOLS * 2, VMEM_CHAR(' ', txattr), NCOLS);
258 crtc_setstart(start_line);
261 static void crtc_cursor(int x, int y)
265 addr = (y + start_line) * NCOLS + x;
267 crtc_write(CRTC_REG_CURLOC_L, addr);
268 crtc_write(CRTC_REG_CURLOC_H, addr >> 8);
271 static void crtc_getcursor(int *x, int *y)
275 addr = crtc_read(CRTC_REG_CURLOC_L);
276 addr |= (unsigned int)crtc_read(CRTC_REG_CURLOC_H) << 8;
278 *y = addr / NCOLS - start_line;
282 static void crtc_setstart(int y)
284 unsigned int addr = y * NCOLS;
286 crtc_write(CRTC_REG_START_L, addr);
287 crtc_write(CRTC_REG_START_H, addr >> 8);
290 static int crtc_getstart(void)
294 addr = crtc_read(CRTC_REG_START_L);
295 addr |= (unsigned int)crtc_read(CRTC_REG_START_H) << 8;
300 static inline unsigned char crtc_read(int reg)
302 outp(CRTC_ADDR, reg);
303 return inp(CRTC_DATA);
306 static inline void crtc_write(int reg, unsigned char val)
308 outp(CRTC_ADDR, reg);
309 outp(CRTC_DATA, val);