#include <io.h>
-#define VGA_CRTC_ADDR 0x3D4
-#define VGA_CRTC_DATA 0x3D5
-#define VGA_CRTC_START_ADDR_H 0xC
-#define VGA_CRTC_START_ADDR_L 0xD
-#define VGA_CRTC_CURSOR_H 0xE
-#define VGA_CRTC_CURSOR_L 0xF
+typedef struct {
+ u8_t c;
+ u8_t f;
+} __attribute__((packed)) vga_char_t;
+#define VIDEO_ADDR 0xC00B8000
-#define LINES_PER_SCREEN 24 //25
-#define CHARS_PER_LINE 80
-#define BYTES_PER_LINE (CHARS_PER_LINE<<1)
-#define MAX_LINES (LINES_PER_SCREEN<<1)
-#define VIDEO_ADDR 0xC00B8000
+#define VGA_CRTC_ADDR 0x3D4
+#define VGA_CRTC_DATA 0x3D5
+#define VGA_CRTC_START_ADDR_H 0xC
+#define VGA_CRTC_START_ADDR_L 0xD
+#define VGA_CRTC_CURSOR_H 0xE
+#define VGA_CRTC_CURSOR_L 0xF
-static unsigned int xpos, ypos;
+#define LINES_PER_SCREEN 25
+#define CHARS_PER_LINE 80
+#define BYTES_PER_LINE (sizeof(vga_char_t)*CHARS_PER_LINE)
-void setCursorPos(unsigned int x, unsigned int y);
-void printString(const char *buf, unsigned char color);
-void printChar(const unsigned char c, const unsigned char color);
-void ScrollUp();
+#define TAB_ALIGN 4
+#define TAB_MASK (TAB_ALIGN-1)
-void setCursorPos(unsigned int x, unsigned int y)
+static unsigned int g_offset = 0;
+
+static void set_offset(unsigned int x, unsigned int y)
+{
+ g_offset = (y * CHARS_PER_LINE) + x;
+}
+
+static unsigned int xpos()
+{
+ return (g_offset % CHARS_PER_LINE);
+}
+
+static unsigned int ypos()
+{
+ return (g_offset / CHARS_PER_LINE);
+}
+
+vga_char_t vga_char(unsigned char c, unsigned char f)
+{
+ vga_char_t x;
+ x.c = c;
+ x.f = f;
+
+ return x;
+}
+
+void vga_set_cursor_pos()
+{
+ outb(VGA_CRTC_CURSOR_H, VGA_CRTC_ADDR);
+ outb((g_offset>>8) & 0xFF, VGA_CRTC_DATA);
+ outb(VGA_CRTC_CURSOR_L, VGA_CRTC_ADDR);
+ outb(g_offset & 0xFF, VGA_CRTC_DATA);
+}
+
+void vga_clear(unsigned int b, unsigned int e)
+{
+ vga_char_t *base = (vga_char_t *) VIDEO_ADDR;
+
+ base += b;
+
+ memset((void *)base, 0, (e-b)*sizeof(vga_char_t));
+}
+
+void vga_scroll_up()
{
- unsigned short offset = x + y * CHARS_PER_LINE;
- outb(VGA_CRTC_CURSOR_H, VGA_CRTC_ADDR);
- outb((offset>>8) & 0xFF,VGA_CRTC_DATA);
- outb(VGA_CRTC_CURSOR_L, VGA_CRTC_ADDR);
- outb(offset & 0xFF, VGA_CRTC_DATA);
+ int delta = ypos() + 1 - LINES_PER_SCREEN;
+
+ if(delta <= 0)
+ return;
+
+ vga_char_t *base = (vga_char_t *) VIDEO_ADDR;
+ vga_char_t *head = base + delta*CHARS_PER_LINE;
+ vga_char_t *empt = base + (LINES_PER_SCREEN-delta)*CHARS_PER_LINE;
+
+ memcpy((void *)base, (void *)head, (empt-base)*sizeof(vga_char_t));
+ //memset((void *)empt, 0, delta*BYTES_PER_LINE);
+
+ vga_clear((LINES_PER_SCREEN-delta)*CHARS_PER_LINE, LINES_PER_SCREEN*CHARS_PER_LINE);
+
+ set_offset(xpos(), ypos() - delta);
}
-void printChar(const unsigned char c, const unsigned char color)
+
+
+void vga_putc(const unsigned char c, const unsigned char color)
{
- unsigned short * const pv = (unsigned short * const) VIDEO_ADDR;
+ vga_char_t * const pv = (vga_char_t * const) VIDEO_ADDR;
+ bool need_clear = true;
+ unsigned int old_offset = g_offset;
+
switch(c)
{
case '\r':
- xpos = 0;
+ set_offset(0, ypos());
break;
case '\n':
- xpos = 0; ypos++;
+ set_offset(0, ypos() + 1);
break;
case '\t':
- xpos &= (~0x07);
- xpos += 8;
- if(xpos >= CHARS_PER_LINE)
- {
- xpos = 0;
- ypos ++;
- }
- break;
- case '\b':
- if(xpos > 0)
- xpos--;
- else if(ypos > 0)
- {
- xpos = CHARS_PER_LINE - 1;
- ypos --;
- }
- *(pv + xpos + ypos*CHARS_PER_LINE) = ' ' | (color << 8);
+ set_offset((xpos() + 1 + TAB_MASK) & ~TAB_MASK, ypos());
break;
default:
- *(pv + xpos + ypos*CHARS_PER_LINE) = c | (color << 8);
- xpos ++;
- if(xpos == CHARS_PER_LINE)
- {
- xpos = 0;
- ypos ++;
- }
+ need_clear = false;
+ pv[g_offset] = vga_char(c, color);
+ set_offset(xpos()+1, ypos());
break;
}
- ScrollUp();
-
- setCursorPos(xpos, ypos);
-}
-
-void ScrollUp()
-{
- static unsigned int last_ypos;
- unsigned short topline;
- if((ypos >= LINES_PER_SCREEN) && (ypos > last_ypos))
+ if(need_clear)
{
- topline = ypos - LINES_PER_SCREEN;
-
- if(topline == MAX_LINES)
- {
-
- memcpy( VIDEO_ADDR,
- VIDEO_ADDR+MAX_LINES*BYTES_PER_LINE,
- LINES_PER_SCREEN*BYTES_PER_LINE);
-
- unsigned char *p;
- const unsigned char *pend;
- p=(unsigned char *)
- VIDEO_ADDR+LINES_PER_SCREEN*BYTES_PER_LINE;
- while(p <=(unsigned char *) VIDEO_ADDR
- + (LINES_PER_SCREEN+MAX_LINES)*BYTES_PER_LINE)
- {
- *p++ = ' ';
- *p++ = 0x0F;
- }
- ypos -= topline;
- topline = 0;
- }
- outb(VGA_CRTC_START_ADDR_H,VGA_CRTC_ADDR);
- outb(((topline*CHARS_PER_LINE)>>8)&0xFF,VGA_CRTC_DATA);
- outb(VGA_CRTC_START_ADDR_L,VGA_CRTC_ADDR);
- outb((topline*CHARS_PER_LINE)&0xFF,VGA_CRTC_DATA);
+ vga_clear(old_offset, g_offset);
}
- last_ypos = ypos;
+
+ vga_scroll_up();
+
+ vga_set_cursor_pos();
}
-void printString(const char *buf, unsigned char color)
+void vga_puts(const char *buf, unsigned char color)
{
char *p = (char *) buf;
while(*p)
{
- printChar(*p, color);
+ vga_putc(*p, color);
p++;
}
}