feat(vga): properly handle
and multiple subsequent VGA.puts@@ -8,75 +8,74 @@ global show_cursor
; Inputs: rdi = row, rsi = col
set_cursor_pos:
- push ebp
- mov ebp, esp
-
- mov eax, dword [ebp + 8] ; eax = row
- mov ebx, 80
- imul eax, ebx ; eax = row * 80
- add eax, dword [ebp + 12] ; eax += col
- mov bx, ax ; bx = position (16-bit)
-
- ; outb(0x3D4, 0x0E);
- mov dx, 0x3D4
- mov al, 0x0E
- out dx, al
-
- ; outb(0x3D5, (position >> 8) & 0xFF);
- mov dx, 0x3D5
- mov al, bh
- out dx, al
-
- ; outb(0x3D4, 0x0F);
- mov dx, 0x3D4
- mov al, 0x0F
- out dx, al
-
- ; outb(0x3D5, position & 0xFF);
- mov dx, 0x3D5
- mov al, bl
- out dx, al
-
- mov esp, ebp
- pop ebp
- ret
+ push ebp
+ mov ebp, esp
+
+ mov eax, dword [ebp + 8] ; eax = row
+ mov ebx, 80
+ imul eax, ebx ; eax = row * 80
+ add eax, dword [ebp + 12] ; eax += col
+ mov bx, ax ; bx = position (16-bit)
+
+ ; outb(0x3D4, 0x0E);
+ mov dx, 0x3D4
+ mov al, 0x0E
+ out dx, al
+
+ ; outb(0x3D5, (position >> 8) & 0xFF);
+ mov dx, 0x3D5
+ mov al, bh
+ out dx, al
+
+ ; outb(0x3D4, 0x0F);
+ mov dx, 0x3D4
+ mov al, 0x0F
+ out dx, al
+
+ ; outb(0x3D5, position & 0xFF);
+ mov dx, 0x3D5
+ mov al, bl
+ out dx, al
+
+ mov esp, ebp
+ pop ebp
+ ret
; void hide_cursor(void)
hide_cursor:
- ; Read: write index 0x0A, then write data with bit 5 set
- ; For simplicity we don't read current value; we set start = 0x20 (disabled)
- mov dx, 0x3D4
- mov al, 0x0A
- out dx, al
+ ; Read: write index 0x0A, then write data with bit 5 set
+ ; For simplicity we don't read current value; we set start = 0x20 (disabled)
+ mov dx, 0x3D4
+ mov al, 0x0A
+ out dx, al
- mov dx, 0x3D5
- mov al, 0x20 ; set bit 5 to disable cursor
- out dx, al
+ mov dx, 0x3D5
+ mov al, 0x20 ; set bit 5 to disable cursor
+ out dx, al
- ret
+ ret
; void show_cursor(void)
show_cursor:
- ; Restore a typical cursor shape: start = 0 (scanline start)
- mov dx, 0x3D4
- mov al, 0x0A
- out dx, al
+ ; Restore a typical cursor shape: start = 0 (scanline start)
+ mov dx, 0x3D4
+ mov al, 0x0A
+ out dx, al
- mov dx, 0x3D5
- mov al, 0x00 ; cursor start = 0
- out dx, al
+ mov dx, 0x3D5
+ mov al, 0x00 ; cursor start = 0
+ out dx, al
- ; set cursor end (e.g., 15)
- mov dx, 0x3D4
- mov al, 0x0B
- out dx, al
+ ; set cursor end (e.g., 15)
+ mov dx, 0x3D4
+ mov al, 0x0B
+ out dx, al
- mov dx, 0x3D5
- mov al, 0x0F ; cursor end = 15 (typical)
- out dx, al
-
- ret
+ mov dx, 0x3D5
+ mov al, 0x0F ; cursor end = 15 (typical)
+ out dx, al
+ ret
section .entry
@@ -23,16 +23,17 @@ fun kmain
VGA.init
VGA.puts(
- "[CrystalOS Kernel] Hello from Crystal.",
- VGA::Colors::BLACK_ON_CYAN,
+ "[CrystalOS Kernel] Hello from Crystal.\n",
+ color: VGA::Colors::BLACK_ON_CYAN,
)
- VGA.puts("\n")
- VGA.puts("Hello world!\n\nWorks maybe?\n", line: 1)
- VGA.puts("Can print on multiple lines\n", line: 2, color: VGA::Colors::BLACK_ON_LIME)
- VGA.puts("But because we don't have a Heap, we need to set lines number in puts call for now...\n", line: 3)
-
- VGA.set_cursor(5, 4)
- VGA.hide_cursor
+ VGA.puts("weeeeeeee\n")
+
+ VGA.puts("Hello world!\n \nWorks maybe?\n")
+ VGA.puts("Can print on multiple lines\n", color: VGA::Colors::BLACK_ON_LIME)
+ VGA.puts("\n\nWe still don't have a heap, but now the puts stores the last row and col so it can call the putchar method with the right col / row instead of overlaying subsequent calls on-top one of another (this is super long line to test word wrap).\n")
+
+ # VGA.set_cursor(0, 5)
+ # VGA.hide_cursor
while true
asm (%(hlt))
@@ -1,5 +1,5 @@
+# Definitions from kernel/entry.asm
lib KernelShim
- # Definition in kernel/entry.asm
fun hide_cursor()
fun show_cursor()
fun set_cursor_pos(
@@ -9,33 +9,11 @@ lib KernelShim
end
struct VGACursor
- col : Int32 = 0
- row : Int32 = 0
+ @col : Int32 = 0
+ property col
- def initialize
- @col = 0
- @row = 0
- end
-
- def col : Int32
- @col
- end
- def col=(c : Int32)
- @col = c
- end
- def col_incr(c : Int32)
- @col += c
- end
-
- def row : Int32
- @row
- end
- def row=(r : Int32)
- @row = r
- end
- def row_incr(r : Int32)
- @row += r
- end
+ @row : Int32 = 0
+ property row
end
module VGA
@@ -73,8 +51,8 @@ module VGA
(VGA_BUFFER + (i * 2) + 1).value = Colors::DEFAULT
i += 1
end
- VGA_CURSOR.col = 0
- VGA_CURSOR.row = 0
+ col = 0
+ row = 0
end
# Hide cursor
@@ -90,60 +68,79 @@ module VGA
# Set typing cursor position
def self.set_cursor(
col : Int32,
- row : Int32
+ next_row : Int32
) : Nil
KernelShim
- .set_cursor_pos(row.to_u32, col.to_u32)
+ .set_cursor_pos(next_row.to_u32, col.to_u32)
+ @@row = next_row
end
+ @@puts_count = 0
+ property puts_count
+
+ @@col = 0
+ class_property col
+
+ @@row = 0
+ class_property row
+
# Write a single character to the current cursor position
def self.putchar(
- ch : UInt8,
- i : Int32? = 0,
- line : Int32? = 0,
- color : UInt8? = Colors::DEFAULT
+ ch : UInt8,
+ i : Int32? = 0,
+ line : Int32? = 0,
+ color : UInt8? = Colors::DEFAULT
) : Nil
- VGA_CURSOR.col = i
- VGA_CURSOR.row = line
-
- if ch == 0x0A_u8 # \n (not working...)
- # VGA_CURSOR.col = 0
- VGA_CURSOR.row += 1
- if VGA_CURSOR.row >= VGA_HEIGHT
- VGA_CURSOR.row = VGA_HEIGHT - 1
- end
- ch = " ".to_unsafe.value
+ @@col ||= i || 0
+ @@row ||= line || 0
+
+ # somehow doesn't work...
+ if ch == 0x0A_u8 # \n handler
+ @@col = 0
+ @@row += 1
+ if @@row >= VGA_HEIGHT
+ @@row = VGA_HEIGHT - 1
end
-
- offset = (VGA_CURSOR.row * VGA_WIDTH + VGA_CURSOR.col) * 2
-
- (VGA_BUFFER + offset).value = ch
- (VGA_BUFFER + offset + 1).value = color
-
- VGA_CURSOR.col += 1
-
- # Wrap around if past screen
- if VGA_CURSOR.col >= VGA_WIDTH
- VGA_CURSOR.col = 0
- VGA_CURSOR.row += 1
- if VGA_CURSOR.row >= VGA_HEIGHT
- VGA_CURSOR.row = VGA_HEIGHT - 1
- end
+ end
+
+ offset = (@@row * VGA_WIDTH + @@col) * 2
+
+ (VGA_BUFFER + offset).value = ch
+ (VGA_BUFFER + offset + 1).value = color
+
+ @@col += 1
+
+ # Wrap around if past screen
+ if @@col >= VGA_WIDTH
+ @@col = 0
+ @@row += 1
+ if @@row >= VGA_HEIGHT
+ @@row = VGA_HEIGHT - 1
end
end
-
- # Write a string to VGA
- def self.puts(
- str : String,
- color : UInt8? = Colors::DEFAULT,
- line : Int32? = 0,
- ) : Nil
- i = 0
- while i < str.size - 1
- ch = (str.to_unsafe + i).value
- putchar(ch, i, line, color)
+ end
+
+ # Write a string to VGA
+ def self.puts(
+ str : String,
+ color : UInt8? = Colors::DEFAULT,
+ line : Int32? = nil,
+ ) : Nil
+ i = 0
+ @@row ||= (line || 0)
+ while i < str.size
+ ch = (str.to_unsafe + i).value
+ if ch == 0x0A_u8
+ @@row += 1
+ @@col = 0
i += 1
+ next
end
+ putchar(ch, i, @@row, color)
+ i += 1
end
+
+ VGA.set_cursor(0, @@row)
+ end
end