1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00
Achilleas Anagnostopoulos 616fc6a412 Implement simple terminal
The terminal uses console.Vga as its output device. A proper terminal
implementation would be using a console.Console interface as its output.
However, at this point we cannot use Go interfaces as the fn pointers in
the itables have not been yet initialized. The Go runtime bits that set
up the itables need access to a memory allocator, a facility which is
not yet provided by the kernel.
2017-03-27 20:12:01 +01:00

117 lines
2.6 KiB
Go

package console
import (
"reflect"
"sync"
"unsafe"
)
const (
clearColor = Black
clearChar = byte(' ')
)
// Vga implements an EGA-compatible text console. At the moment, it uses the
// ega console physical address as its outpucons. After implementing a memory
// allocator, each console will use its own framebuffer while the active console
// will periodically sync its internal buffer with the physical screen buffer.
type Vga struct {
sync.Mutex
width uint16
height uint16
fb []uint16
}
// Init sets up the console.
func (cons *Vga) Init() {
cons.width = 80
cons.height = 25
// Set up our frame buffer object by creating a fake slice object pointing
// to the physical address of the screen buffer.
if cons.fb != nil {
return
}
cons.fb = *(*[]uint16)(unsafe.Pointer(&reflect.SliceHeader{
Len: int(cons.width * cons.height),
Cap: int(cons.width * cons.height),
Data: uintptr(0xB8000),
}))
}
// OverrideFb overrides the console framebuffer slice with the supplied slice.
// This is a temporary function used by tests that will be removed once we can work
// with interfaces.
func (cons *Vga) OverrideFb(fb []uint16) {
cons.fb = fb
}
// Clear clears the specified rectangular region
func (cons *Vga) Clear(x, y, width, height uint16) {
var (
attr = uint16((clearColor << 4) | clearColor)
clr = attr | uint16(clearChar)
rowOffset, colOffset uint16
)
// clip rectangle
if x >= cons.width {
x = cons.width
}
if y >= cons.height {
y = cons.height
}
if x+width > cons.width {
width = cons.width - x
}
if y+height > cons.height {
height = cons.height - y
}
rowOffset = (y * cons.width) + x
for ; height > 0; height, rowOffset = height-1, rowOffset+cons.width {
for colOffset = rowOffset; colOffset < rowOffset+width; colOffset++ {
cons.fb[colOffset] = clr
}
}
}
// Dimensions returns the console width and height in characters.
func (cons *Vga) Dimensions() (uint16, uint16) {
return cons.width, cons.height
}
// Scroll a particular number of lines to the specified direction.
func (cons *Vga) Scroll(dir ScrollDir, lines uint16) {
if lines == 0 || lines > cons.height {
return
}
var i uint16
offset := lines * cons.width
switch dir {
case Up:
for ; i < (cons.height-lines)*cons.width; i++ {
cons.fb[i] = cons.fb[i+offset]
}
case Down:
for i = cons.height*cons.width - 1; i >= lines*cons.width; i-- {
cons.fb[i] = cons.fb[i-offset]
}
}
}
// Write a char to the specified location.
func (cons *Vga) Write(ch byte, attr Attr, x, y uint16) {
if x >= cons.width || y >= cons.height {
return
}
cons.fb[(y*cons.width)+x] = (uint16(attr) << 8) | uint16(ch)
}