do not edit — generated by btf.
git.druid.rocksindexdruid520kaboomsrc/drivers/vga.nsc

src/drivers/vga.nsc


/*
 * text-mode vga driver: 0xb8000, 80x25, 2 bytes/cell (char, attr).
 *
 * nsc's `*p` through a raw ptr is always a full 8-byte load/store --
 * there is no byte or word-granular deref, and structs can't model a
 * packed hardware layout either (fields are word-addressed, not
 * byte-packed). every single-cell write here is therefore a
 * read-modify-write of the containing 8-byte-aligned word: read 8
 * bytes, clear the 2 bytes for this cell with a mask, or in the new
 * (char | attr<<8) value at the right bit offset, write the 8 bytes
 * back. see the kernel-wide note on this in kernel/kmain.nsc.
 *
 * cursor positioning (vga_set_cursor/vga_show_cursor/vga_hide_cursor)
 * and real scrolling (vga_scroll) are a port of tape-kernel's own
 * cm.c (cnb/cob/scur/hcur) and vga.c (scrl) -- not reinvented. the
 * one thing not ported: cnb (reading the cursor position back from
 * the crtc) has no caller here, since vga_row/vga_col already track
 * kaboom's own idea of "where the cursor is" and the two never
 * diverge (nothing else ever moves the hardware cursor independently
 * of a vga_putc/vga_newline call) -- cob's counterpart, cnb's actual
 * job, would only matter if something else could move the cursor
 * without going through this file.
 */
 
void outb(u16 port, u8 val);
u8 inb(u16 port);
 
global u32 vga_row;
global u32 vga_col;
 
void
vga_setcell(u32 row, u32 col, u8 ch, u8 attr)
{
	ptr base;
	ptr wordptr;
	u64 celloff;
	u64 wordoff;
	u64 byteoff;
	u64 shift;
	u64 word;
	u64 mask;
	u64 val;
 
	base = (ptr)0xb8000;
	celloff = (u64)(row * (u32)80 + col) * (u64)2;
	wordoff = celloff & ~(u64)7;
	byteoff = celloff & (u64)7;
	shift = byteoff * (u64)8;
 
	wordptr = base + wordoff;
	word = (u64)*wordptr;
 
	val = (u64)ch | ((u64)attr << (u64)8);
	mask = (u64)0xffff << shift;
	word = (word & ~mask) | (val << shift);
 
	*wordptr = (i64)word;
}
 
/* the (char|attr) pair packed the same way vga_setcell writes it --
 * scrolling needs to read a cell before overwriting it with the row
 * below's own content. */
u64
vga_getcell(u32 row, u32 col)
{
	ptr base;
	ptr wordptr;
	u64 celloff;
	u64 wordoff;
	u64 byteoff;
	u64 shift;
	u64 word;
 
	base = (ptr)0xb8000;
	celloff = (u64)(row * (u32)80 + col) * (u64)2;
	wordoff = celloff & ~(u64)7;
	byteoff = celloff & (u64)7;
	shift = byteoff * (u64)8;
 
	wordptr = base + wordoff;
	word = (u64)*wordptr;
	return (word >> shift) & (u64)0xffff;
}
 
/* sets the hardware text cursor's screen position (crtc index
 * registers 0x0e/0x0f) -- tape-kernel's cob, ported directly (same
 * clamping, same pos = y*80+x encoding). */
global void
vga_set_cursor(u32 row, u32 col)
{
	u64 pos;
 
	if(row >= (u32)25)
	{
		row = (u32)24;
	}
	if(col >= (u32)80)
	{
		col = (u32)79;
	}
	pos = (u64)(row * (u32)80 + col);
 
	outb((u16)0x3d4, (u8)0x0f);
	outb((u16)0x3d5, (u8)(pos & (u64)0xff));
	outb((u16)0x3d4, (u8)0x0e);
	outb((u16)0x3d5, (u8)((pos >> (u64)8) & (u64)0xff));
}
 
/* enables the blinking text cursor at a normal underline shape --
 * tape-kernel's scur. */
global void
vga_show_cursor(void)
{
	outb((u16)0x3d4, (u8)0x0a);
	outb((u16)0x3d5, (u8)0x06);
	outb((u16)0x3d4, (u8)0x0b);
	outb((u16)0x3d5, (u8)0x07);
}
 
/* tape-kernel's hcur -- bit 5 of the cursor-start register disables
 * the cursor entirely. not called anywhere yet (vga_init always
 * shows it), kept for symmetry and whatever wants it later. */
global void
vga_hide_cursor(void)
{
	outb((u16)0x3d4, (u8)0x0a);
	outb((u16)0x3d5, (u8)0x20);
}
 
/* shifts every row up by one and clears the new bottom row --
 * tape-kernel's scrl, ported directly. called instead of wrapping
 * back to row 0 the moment output reaches the bottom, so the screen
 * behaves like a real terminal (oldest line scrolls off, newest
 * stays visible) instead of overwriting from the top over whatever
 * was already there. */
void
vga_scroll(void)
{
	u32 row;
	u32 col;
	u64 cell;
 
	row = 1;
	while(row < (u32)25)
	{
		col = 0;
		while(col < (u32)80)
		{
			cell = vga_getcell(row, col);
			vga_setcell(row - (u32)1, col, (u8)(cell & (u64)0xff), (u8)((cell >> (u64)8) & (u64)0xff));
			col = col + (u32)1;
		}
		row = row + (u32)1;
	}
	col = 0;
	while(col < (u32)80)
	{
		vga_setcell((u32)24, col, (u8)32, (u8)7);
		col = col + (u32)1;
	}
}
 
void
vga_newline(void)
{
	vga_row = vga_row + (u32)1;
	vga_col = 0;
	if(vga_row >= (u32)25)
	{
		vga_scroll();
		vga_row = (u32)24;
	}
	vga_set_cursor(vga_row, vga_col);
}
 
global void
vga_clear(void)
{
	u32 row;
	u32 col;
 
	row = 0;
	while(row < (u32)25)
	{
		col = 0;
		while(col < (u32)80)
		{
			vga_setcell(row, col, (u8)32, (u8)7);
			col = col + (u32)1;
		}
		row = row + (u32)1;
	}
	vga_row = 0;
	vga_col = 0;
	vga_set_cursor(0, 0);
}
 
global void
vga_putc(u8 ch)
{
	if(ch == (u8)10)
	{
		vga_newline();
		return;
	}
	vga_setcell(vga_row, vga_col, ch, (u8)7);
	vga_col = vga_col + (u32)1;
	if(vga_col >= (u32)80)
	{
		vga_newline();
		return;
	}
	vga_set_cursor(vga_row, vga_col);
}
 
/* erases the character immediately before the cursor and moves the
 * cursor back onto it -- fd_read_stdin's own backspace handling
 * calls this once it's confirmed there's something on the current
 * line to erase (see that function's note on why the decision itself
 * lives there, not in the keyboard driver). backing up across a
 * wrapped line (col already 0) moves to the end of the previous row;
 * this is an approximation, not a real "how long was that row"
 * tracker, but matches the common case (a line that filled the
 * screen width) well enough for a line editor's own input. */
global void
vga_backspace(void)
{
	if(vga_col > (u32)0)
	{
		vga_col = vga_col - (u32)1;
	}
	else if(vga_row > (u32)0)
	{
		vga_row = vga_row - (u32)1;
		vga_col = (u32)79;
	}
	vga_setcell(vga_row, vga_col, (u8)32, (u8)7);
	vga_set_cursor(vga_row, vga_col);
}
 
global void
vga_puts(ptr str)
{
	ptr p;
	u64 word;
	u8 ch;
 
	p = str;
	while(1)
	{
		word = (u64)*p;
		ch = (u8)(word & (u64)0xff);
		if(ch == (u8)0)
		{
			return;
		}
		vga_putc(ch);
		p = p + 1;
	}
}
 
global void
vga_init(void)
{
	vga_row = 0;
	vga_col = 0;
	vga_clear();
	vga_show_cursor();
}
powered by btf.