207 lines
3.7 KiB
C
207 lines
3.7 KiB
C
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <string_volatile.h>
|
|
#include <stdarg.h>
|
|
#include <sys.h>
|
|
|
|
#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;
|
|
}
|