#include #include #include #include #include #include #include #include "term.h" static volatile uint16_t *screen = (uint16_t*)0xb8000; static size_t term_x = 0; static size_t term_y = 0; static uint8_t color = 0x0f; static uint16_t screen_buf[TERM_W * TERM_H * 2]; static inline uint16_t screen_entry(char c, uint8_t col) { return (uint16_t)c | ((uint16_t)col << 8); } void putc(char c) { switch(c) { case '\n': term_x = TERM_W; break; case '\t': if(term_x % 8 == 0) term_x += 8; term_x += 7 - (term_x % 8); break; default: screen_buf[term_x + term_y * TERM_W] = screen_entry(c, color); term_x += 1; break; } if(term_x >= TERM_W) { term_x = 0; term_y += 1; } if(term_y >= TERM_H) { term_scroll(1); } if(c == '\n') { term_flush(); } } void puts(const char *s) { for(; *s != '\0'; s++) { putc(*s); } } static uint8_t hex2i(char hex) { if(hex < 'A') { return hex - '0'; } else if(hex < 'a') { return hex - 'A' + 10; } else { return hex - 'a' + 10; } } static char i2d(int i, bool upper) { if(i < 10) { return '0' + i; } else { return 'a' + (i - 10) + (upper ? 'A' - 'a' : 0); } } static void itoa(int n, char *buf, int base, bool upper) { if(n == 0) { buf[0] = '0'; buf[1] = '\0'; return; } if(n < 0) { n = -n; buf[0] = '-'; buf++; } char *start = buf; while(n != 0) { *buf++ = i2d(n % base, upper); n /= base; } *buf-- = '\0'; while(buf > start) { char tmp = *start; *start++ = *buf; *buf-- = tmp; } } static void utoa(unsigned int n, char *buf, int base, bool upper) { if(n == 0) { buf[0] = '0'; buf[1] = '\0'; return; } char *start = buf; while(n != 0) { *buf++ = i2d(n % base, upper); n /= base; } *buf-- = '\0'; while(buf > start) { char tmp = *start; *start++ = *buf; *buf-- = tmp; } } void vprintf(const char *fstr, va_list args) { char buf[80]; for(; *fstr != '\0'; fstr++) { if(*fstr == '%') { fstr++; switch(*fstr) { case '%': putc('%'); break; case 's': puts(va_arg(args, char*)); break; case 'd': itoa(va_arg(args, int), buf, 10, false); puts(buf); break; case 'u': utoa(va_arg(args, unsigned int), buf, 10, false); puts(buf); break; case 'x': utoa(va_arg(args, unsigned int), buf, 16, false); puts(buf); break; case 'X': utoa(va_arg(args, unsigned int), buf, 16, true); puts(buf); break; case '@': { uint8_t hi = hex2i(*++fstr); uint8_t lo = hex2i(*++fstr); term_setcol((hi << 4) | lo); break; } default: break; } } else { putc(*fstr); } } } void printf(const char *fstr, ...) { va_list args; va_start(args, fstr); vprintf(fstr, args); va_end(args); } void term_clear(void) { memset(screen_buf, 0, TERM_W * TERM_H * 2); } void term_setpos(size_t new_x, size_t new_y) { term_x = new_x; term_y = new_y; } void term_setcol(uint8_t new_col) { color = new_col; } void term_scroll(ptrdiff_t lines) { term_y -= lines; if(lines == 0) return; if(lines >= TERM_H || lines <= -TERM_H) { term_clear(); } else if(lines > 0) { memmove(screen_buf, screen_buf + lines * TERM_W, 2 * (TERM_H - lines) * TERM_W); memset(screen_buf + (TERM_H - lines) * TERM_W, 0, 2 * lines * TERM_W); } else { memmove(screen_buf + lines * TERM_W, screen_buf + lines, (TERM_H + lines) * TERM_W); } } void term_flush(void) { int_disable(); memcpy_volatile(screen, screen_buf, TERM_W * TERM_H * 2); int_enable(); } uint32_t term_save(void) { return color | ((term_x + term_y * TERM_W) << 8); } void term_load(uint32_t state) { color = state & 0xff; state >>= 8; term_x = state % TERM_W; term_y = state / TERM_W; }