Compare commits

...

47 commits

Author SHA1 Message Date
peony 7ead8809c2 RTC works. 2025-01-31 22:24:10 +01:00
peony 5be0da8735 Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2025-01-31 21:04:04 +01:00
peony 895135e97d Implemented disabling and enabling interrupts and poc RTC. 2025-01-31 21:03:09 +01:00
peony 5db7237341 Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2025-01-30 18:27:22 +01:00
peony 4b28810372 Started on the PS2 refactor I guess. 2025-01-30 18:20:46 +01:00
peony 32e0e9fde1 throwaway 2024-12-27 20:57:55 +01:00
peony 04dd9a9700 throwaway 2024-12-23 20:19:10 +01:00
koniifer 82382d2a99 code churn to save the universe 2024-12-23 20:19:10 +01:00
Jakub Doka 5659ae1d0a adding instruction log
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
2024-12-23 20:19:10 +01:00
Able e21bb03912 VFSaur swapped to slices and parse to exclude the : 2024-12-23 20:19:10 +01:00
koniifer 75db10c339 semi-broken again 2024-12-23 20:19:10 +01:00
Able 4560c19652 VFSaur restructuring 2024-12-23 20:19:10 +01:00
koniifer 96dc726c35 printf, various syntax updates, better string manipulation miscellaneous changes 2024-12-23 20:19:10 +01:00
Able c9601fae4a VFSaur work. String split bug. 2024-12-23 20:19:10 +01:00
koniifer 6ec5af6df5 fiddling 2024-12-23 20:19:10 +01:00
koniifer 49d00313e2 tuple and array syntax 2024-12-23 20:19:10 +01:00
koniifer 0e27f57bc6 new broken 2024-12-23 20:19:10 +01:00
Jakub Doka 68f5d64dad migrating to new hblang syntax
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
2024-12-23 20:19:10 +01:00
koniifer 3d699d9db8 working + fiddling 2024-12-23 20:19:10 +01:00
koniifer 27376bc101 almost enums 2024-12-23 20:19:10 +01:00
koniifer 1eca77abaf logger work 2024-12-23 20:19:10 +01:00
koniifer 7f4f0218d0 update test 2024-12-23 20:19:10 +01:00
Jakub Doka 8ad1f12ebd fixing the optional formatting
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
2024-12-23 20:19:10 +01:00
koniifer c0a4c88c41 more and less broken 2024-12-23 20:19:10 +01:00
Jakub Doka 6ddc199b6a fixing a bug in a disasm
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
2024-12-23 20:19:10 +01:00
Jakub Doka 5a3ffbb1ec save 2024-12-23 20:19:10 +01:00
koniifer eae328afdb less less broken 2024-12-23 20:19:10 +01:00
koniifer 8cca5c8d1b less broken 2024-12-23 20:19:10 +01:00
koniifer 9e0ed8a5d7 broken for now 2024-12-23 20:19:10 +01:00
koniifer 8a78faecdf formatter update 2024-12-23 20:19:10 +01:00
koniifer 6dc17daa09 minor change 2024-12-23 20:19:10 +01:00
koniifer 15b3fde6e6 primitive string formatter with struct & array support 2024-12-23 20:19:10 +01:00
koniifer 98c3fa059f math changes & compiler update 2024-12-23 20:19:10 +01:00
Able 5cb3b956d9 fixes for the absolutely huge breakage pushed 2024-12-23 20:18:34 +01:00
koniifer afddfea8fb push 2024-12-23 20:18:21 +01:00
koniifer 0db997b435 fiddling and move some stuff to stn.math 2024-12-23 20:18:21 +01:00
koniifer 31b3d5e5ba hblang update 2024-12-23 20:18:21 +01:00
koniifer 89cd1eec9c cooler mandelbrot 2024-12-23 20:18:21 +01:00
koniifer 8aac85e9cf fixed struct method things 2024-12-23 20:18:08 +01:00
koniifer 73c9b633c4 broken struct method things 2024-12-23 20:18:08 +01:00
Able f1598a044e local changes 👍 2024-12-23 20:17:10 +01:00
Able dc43529c7b proposed replacement for system.toml 2024-12-23 20:16:57 +01:00
Able 6475e1bc26 Stress testing. 2024-12-23 20:16:57 +01:00
koniifer e6bdce0240 cool mandelbrot also fix circle rendering a bit 2024-12-23 20:16:57 +01:00
Able a623e62e8c ata pio mode 2024-12-23 20:16:27 +01:00
peony da12a5155c Merge remote-tracking branch 'AbleOS-main/master' 2024-12-06 20:33:13 +01:00
peony 0a863bc1f9 throwaway 2024-12-06 20:30:16 +01:00
18 changed files with 526 additions and 295 deletions
kernel/src/holeybytes
sysdata

View file

@ -1,5 +1,7 @@
//! Environment call handling routines
use core::arch::asm;
use {alloc::boxed::Box, core::cell::LazyCell, hbvm::mem::Address};
use crate::{
@ -288,6 +290,20 @@ pub fn handler(thr: &mut ExecThread, pid: &usize) {
.buffer_subscribe(*pid, buffer_id);
}
}
8 => {
// Disable/enable interrupts.
// TODO: This is the quickest dirtiest hack to ever exist.
let state = thr.vm.registers[3].cast::<u8>();
if state == 0 {
debug!("Interrupts disabled.");
unsafe {asm!("cli");};
}
else
{
debug!("Interrupts enabled.");
unsafe {asm!("sti");};
}
}
_ => {
log::error!("Syscall unknown {:?}{:?}", ecall_number, thr.vm.registers);
}

View file

@ -4,4 +4,16 @@ $subscribe_to_interrupt := fn(interrupt_number: u8): bool {
// Pauses execution until the interrupt occures
$sleep_until_interrupt := fn(interrupt_number: u8): void {
@eca(6, interrupt_number)
}
//InterruptGuard := struct {}
// Disables recieving interrupts..
$disable_interrupts := fn(): void {
@eca(8, false)
}
// Enables recieving interrupts..
$enable_interrupts := fn(): void {
@eca(8, true)
}

View file

@ -1,23 +0,0 @@
# Unified PS/2 Driver
Te entire thing is held together inspite
## !!Assumptions!!
Anyone who works on this should work to keep this list as small as possible/remove as many of these as possible.
- Bit 5 of the response form 0x64 indicates which port the data is coming from. (Not true on all systems)
- A parity or timeout error never occurs.
- PS/2 controller exists.
- Both PS/2 ports being broken doesn't need handling.
- One PS/2 port being broken doesn't need special attention.
- PS/2 controller doesn't need to perform a self-check.
- These DeviceIDs never exist:
- 0xFFFD
- 0xFFFE
- 0xFFFF
- 0x01xx
- 0x03xx
- 0x04xx
- Literally all PS/2 keyboards can be handeled the exact same way. We have the capability for detecting different keyboard types, I just don't bother with it because that would litreally take months to get working.
- The device doesn't send any data while we're waiting for an `ACK`.
Supporting mice in the keyboard port and vice versa was a ***bad*** idea, but I do not regret it because it means we're "superior" to real world operating systems.

View file

@ -1,101 +0,0 @@
.{memory, log} := @use("stn");
.{bit0, bit1, bit5, bit6, bit7} := @use("bits.hb");
.{Port, PORT_AT_STARTUP} := @use("port.hb")
port1 := @as(Port, PORT_AT_STARTUP)
port2 := @as(Port, PORT_AT_STARTUP)
//wiki.osdev.org/"8042"_PS/2_Controller#PS/2_Controller_IO_Ports
$CONTROLLER_PORT := 0x64
$DATA_PORT := 0x60
$disable_port1 := fn(): void memory.outb(CONTROLLER_PORT, 0xAD)
$enable_port1 := fn(): void memory.outb(CONTROLLER_PORT, 0xAE)
$disable_port2 := fn(): void memory.outb(CONTROLLER_PORT, 0xA7)
$enable_port2 := fn(): void memory.outb(CONTROLLER_PORT, 0xA8)
test_port1 := fn(): bool {
memory.outb(CONTROLLER_PORT, 0xAB)
loop if has_input(get_info()) break
input := get_input()
return input == 0x0
}
test_port2 := fn(): bool {
memory.outb(CONTROLLER_PORT, 0xA9)
loop if has_input(get_info()) break
input := get_input()
return input == 0x0
}
get_config_byte := fn(): u8 {
memory.outb(CONTROLLER_PORT, 0x20)
loop if has_input(get_info()) break
return get_input()
}
Info := struct {d: u8}
$get_info := fn(): Info return .(memory.inb(CONTROLLER_PORT))
//inline when can
has_input := fn(info: Info): bool return bit0(info.d)
can_send := fn(info: Info): bool return bit1(info.d) == false
timed_out := fn(info: Info): bool return bit6(info.d)
check_parity := fn(info: Info): bool return bit7(info.d)
get_port := fn(info: Info): ^Port {
if bit5(info.d) {
return &port2
} else {
return &port1
}
}
//T
port2_ptr := &port2
send_byte := fn(port: ^Port, byte: u8): void {
if port == port2_ptr {
memory.outb(CONTROLLER_PORT, 0xD4)
}
loop if can_send(get_info()) break
memory.outb(DATA_PORT, byte)
}
$get_input := fn(): u8 return memory.inb(DATA_PORT)
$write_out := fn(data: u8): void memory.outb(DATA_PORT, data)
flush_input := fn(): void {
loop if has_input(get_info()) == false break else get_info()
}
init := fn(): void {
disable_port1()
disable_port2()
//Disables ports to make sure that they won't interfere with the setup process.
flush_input()
enable_port2()
port2.exists = bit5(@inline(get_config_byte)) == false
disable_port2()
flush_input()
port1.exists = test_port1()
if port2.exists {
port2.exists = test_port2()
}
if (port1.exists | port2.exists) == false {
log.error("No ports detected! No input will be processed! Cannot handle this!")
}
if port1.exists {
log.info("Port 1 exists.")
enable_port1()
}
if port2.exists {
log.info("Port 2 exists.")
enable_port2()
}
}

View file

@ -1,150 +1,5 @@
.{memory, log, buffer, string} := @use("stn");
.{MouseEvent} := @use("lib:intouch").events;
.{bit0, bit1, bit2, bit3, bit4} := @use("bits.hb")
devices := @use("devices.hb")
controller := @use("controller.hb");
.{Info, Port} := controller
mouse := @use("mouse.hb")
mouse_buffer := 0
keyboard_buffer := 0
info := Info.(0)
send_command := fn(port: ^Port, byte: u8): void {
tries := 3
loop if tries == 0 break else {
controller.send_byte(port, byte)
loop {
info = controller.get_info()
if controller.has_input(info) == false {
continue
}
input := controller.get_input()
if controller.get_port(info) != port {
if check_complete(port) == false {
port.packet[port.packet_length] = input
port.packet_length += 1
}
continue
}
if input == 0xFA {
return
} else {
break
}
}
tries -= 1
}
}
enable_streaming := fn(port: ^Port): void {
@inline(send_command, port, 0xF4)
}
process := fn(port: ^controller.Port): void {
if port.device.value < devices.MOUSE_5_BUTTON.value {
event := MouseEvent.(0, 0, false, false, false)
event.left = bit0(port.packet[0])
event.right = bit1(port.packet[0])
event.middle = bit2(port.packet[0])
event.x_change = @intcast(port.packet[1])
event.y_change = @intcast(port.packet[2])
buffer.write(MouseEvent, mouse_buffer, &event)
} else if port.device == devices.MOUSE_INIT_1 {
port.device.value = port.packet[0]
if port.device != devices.MOUSE_SCROLLWHEEL {
enable_streaming(port)
return
}
port.device = devices.MOUSE_INIT_2
} else if port.device == devices.MOUSE_INIT_2 {
port.device.value = port.packet[0]
} else if port.device == devices.NO_DEVICE {
if port.packet_length == 1 {
port.device.value = port.packet[0]
enable_streaming(port)
//TODO: Upgrade mouse.
} else {
port.device.value = port.packet[1] | port.packet[0] << 8
enable_streaming(port)
}
log.info("Identified device!")
log.print(port.device.value, .{radix: 16})
} else {
log.info("KEY PRESSED")
}
}
check_complete := fn(port: ^controller.Port): bool {
last_value := port.packet[port.packet_length - 1]
if port.device == devices.NO_DEVICE {
if last_value == 0 | last_value == 3 | last_value == 4 {
return true
} else if port.packet_length == 2 {
return true
}
} else if port.device == devices.MOUSE_3_BUTTON {
if port.packet_length == 3 return true
} else if port.device == devices.MOUSE_SCROLLWHEEL | port.device == devices.MOUSE_5_BUTTON {
if port.packet_length == 4 return true
} else {
if port.packet[0] == 0xE1 {
if port.packet_length == 6 {
return true
}
} else if port.packet[0] != 0xE0 {
return true
} else if port.packet_length == 2 & port.packet[1] != 0x2A & port.packet[1] != 0xB7 {
return true
} else if port.packet_length == 4 {
return true
}
}
return false
}
Port := @use("port.hb").Port;
main := fn(): void {
mouse_buffer = buffer.create("PS/2 Mouse")
controller.init()
if controller.port1.exists {
//log.info("Port 1 exists.")
controller.send_byte(@bitcast(0), 0xF4)
}
if controller.port2.exists {
//controller.send_byte(&controller.port2, 0xF4)
}
loop {
info = controller.get_info()
if controller.timed_out(info) {
log.error("Timeout error! Cannot handle these!")
}
if controller.check_parity(info) {
log.error("Parity error! Cannot handle these!")
}
/*
if controller.has_input(info) {
port := controller.get_port(info)
if port.packet_length > 0 & check_complete(port) {
process(port)
}
input := controller.get_input()
/*if input == 0xAA & port.can_hot_plug {
port.device = devices.NO_DEVICE
controller.send_byte(port, 0xF4)
}*/
port.packet[port.packet_length] = input
port.packet_length += 1
if check_complete(port) {
process(port)
port.packet_length = 0
}
}*/
}
}

View file

@ -1,21 +1,52 @@
.{DeviceID, NO_DEVICE} := @use("devices.hb")
log := @use("stn:log")
State := struct {s: u8}
$Recive := State.(0)
$Reboot := State.(1)
Port := packed struct {
exists: bool,
device: DeviceID,
packet: [8]u8,
packet_length: u8,
can_hot_plug: bool,
Uninitialized := struct {
}
$PORT_AT_STARTUP := Port.(
true,
NO_DEVICE,
.[0, 0, 0, 0, 0, 0, 0, 0],
0,
true,
)
ThreeButtonMouse := struct {
}
ScrollMouse := struct {
}
FiveButtonMouse := struct {
}
Keyboard := struct {
}
DeviceType := enum {
None,
Uninitialized,
ThreeButtonMouse,
ScrollMouse,
FiveButtonMouse,
Keyboard,
}
Port := struct {
device_type: DeviceType,
_: union {
uninitialized: Uninitialized,
three_button_mouse: ThreeButtonMouse,
scroll_mouse: ScrollMouse,
five_button_mouse: FiveButtonMouse,
keyboard: Keyboard,
},
recive_byte := fn(self: Self, byte: u8): void {
match self.device_type {
.Uninitialized => @inline(self._.uninitialized.recive_byte, byte)
.ThreeButtonMouse => @inline(self._.three_button_mouse.recive_byte, byte)
.ScrollMouse => @inline(self._.scroll_mouse.recive_byte, byte)
.FiveButtonMouse => @inline(self._.five_button_mouse.recive_byte, byte)
.Keyboard => @inline(self._.keyboard.recive_byt, byte)
}
},
}

View file

@ -0,0 +1,23 @@
# Unified PS/2 Driver
Te entire thing is held together inspite
## !!Assumptions!!
Anyone who works on this should work to keep this list as small as possible/remove as many of these as possible.
- Bit 5 of the response form 0x64 indicates which port the data is coming from. (Not true on all systems)
- A parity or timeout error never occurs.
- PS/2 controller exists.
- Both PS/2 ports being broken doesn't need handling.
- One PS/2 port being broken doesn't need special attention.
- PS/2 controller doesn't need to perform a self-check.
- These DeviceIDs never exist:
- 0xFFFD
- 0xFFFE
- 0xFFFF
- 0x01xx
- 0x03xx
- 0x04xx
- Literally all PS/2 keyboards can be handeled the exact same way. We have the capability for detecting different keyboard types, I just don't bother with it because that would litreally take months to get working.
- The device doesn't send any data while we're waiting for an `ACK`.
Supporting mice in the keyboard port and vice versa was a ***bad*** idea, but I do not regret it because it means we're "superior" to real world operating systems.

View file

@ -0,0 +1,11 @@
[package]
name = "ps2_driver"
authors = ["Peony"]
[dependants.libraries]
[dependants.binaries]
hblang.version = "1.0.0"
[build]
command = "hblang src/main.hb"

View file

@ -0,0 +1,101 @@
.{memory, log} := @use("stn");
.{bit0, bit1, bit5, bit6, bit7} := @use("bits.hb");
.{Port, PORT_AT_STARTUP} := @use("port.hb")
port1 := @as(Port, PORT_AT_STARTUP)
port2 := @as(Port, PORT_AT_STARTUP)
//wiki.osdev.org/"8042"_PS/2_Controller#PS/2_Controller_IO_Ports
$CONTROLLER_PORT := 0x64
$DATA_PORT := 0x60
//These are implementations of a few simple controller commands.
$disable_port1 := fn(): void memory.outb(CONTROLLER_PORT, 0xAD)
$enable_port1 := fn(): void memory.outb(CONTROLLER_PORT, 0xAE)
$disable_port2 := fn(): void memory.outb(CONTROLLER_PORT, 0xA7)
$enable_port2 := fn(): void memory.outb(CONTROLLER_PORT, 0xA8)
test_port1 := fn(): bool {
memory.outb(CONTROLLER_PORT, 0xAB)
loop if has_input(get_info()) break
input := get_input()
return input == 0x0
}
test_port2 := fn(): bool {
memory.outb(CONTROLLER_PORT, 0xA9)
loop if has_input(get_info()) break
input := get_input()
return input == 0x0
}
get_config_byte := fn(): u8 {
memory.outb(CONTROLLER_PORT, 0x20)
loop if has_input(get_info()) break
return get_input()
}
Info := struct {d: u8}
$get_info := fn(): Info return .(memory.inb(CONTROLLER_PORT))
//inline when can
has_input := fn(info: Info): bool return bit0(info.d)
can_send := fn(info: Info): bool return bit1(info.d) == false
timed_out := fn(info: Info): bool return bit6(info.d)
check_parity := fn(info: Info): bool return bit7(info.d)
get_port := fn(info: Info): ^Port {
if bit5(info.d) {
return &port2
} else {
return &port1
}
}
port2_ptr := &port2
send_byte := fn(port: ^Port, byte: u8): void {
if port == port2_ptr {
memory.outb(CONTROLLER_PORT, 0xD4)
}
loop if can_send(get_info()) break
memory.outb(DATA_PORT, byte)
}
$get_input := fn(): u8 return memory.inb(DATA_PORT)
$write_out := fn(data: u8): void memory.outb(DATA_PORT, data)
flush_input := fn(): void {
loop if has_input(get_info()) == false break else get_info()
}
init := fn(): void {
disable_port1()
disable_port2()
//Disables ports to make sure that they won't interfere with the setup process.
flush_input()
enable_port2()
port2.exists = bit5(@inline(get_config_byte)) == false
disable_port2()
flush_input()
port1.exists = test_port1()
if port2.exists {
port2.exists = test_port2()
}
if (port1.exists | port2.exists) == false {
log.error("No ports detected! No input will be processed! Cannot handle this!")
}
if port1.exists {
log.info("Port 1 exists.")
enable_port1()
}
if port2.exists {
log.info("Port 2 exists.")
enable_port2()
}
}

View file

@ -0,0 +1,150 @@
.{memory, log, buffer, string} := @use("stn");
.{MouseEvent} := @use("lib:intouch").events;
.{bit0, bit1, bit2, bit3, bit4} := @use("bits.hb")
devices := @use("devices.hb")
controller := @use("controller.hb");
.{Info, Port} := controller
mouse := @use("mouse.hb")
mouse_buffer := 0
keyboard_buffer := 0
info := Info.(0)
send_command := fn(port: ^Port, byte: u8): void {
tries := 3
loop if tries == 0 break else {
controller.send_byte(port, byte)
loop {
info = controller.get_info()
if controller.has_input(info) == false {
continue
}
input := controller.get_input()
if controller.get_port(info) != port {
if check_complete(port) == false {
port.packet[port.packet_length] = input
port.packet_length += 1
}
continue
}
if input == 0xFA {
return
} else {
break
}
}
tries -= 1
}
}
enable_streaming := fn(port: ^Port): void {
@inline(send_command, port, 0xF4)
}
process := fn(port: ^controller.Port): void {
if port.device.value < devices.MOUSE_5_BUTTON.value {
event := MouseEvent.(0, 0, false, false, false)
event.left = bit0(port.packet[0])
event.right = bit1(port.packet[0])
event.middle = bit2(port.packet[0])
event.x_change = @intcast(port.packet[1])
event.y_change = @intcast(port.packet[2])
buffer.write(MouseEvent, mouse_buffer, &event)
} else if port.device == devices.MOUSE_INIT_1 {
port.device.value = port.packet[0]
if port.device != devices.MOUSE_SCROLLWHEEL {
enable_streaming(port)
return
}
port.device = devices.MOUSE_INIT_2
} else if port.device == devices.MOUSE_INIT_2 {
port.device.value = port.packet[0]
} else if port.device == devices.NO_DEVICE {
if port.packet_length == 1 {
port.device.value = port.packet[0]
enable_streaming(port)
//TODO: Upgrade mouse.
} else {
port.device.value = port.packet[1] | port.packet[0] << 8
enable_streaming(port)
}
log.info("Identified device!")
log.print(port.device.value, .{radix: 16})
} else {
log.info("KEY PRESSED")
}
}
check_complete := fn(port: ^controller.Port): bool {
last_value := port.packet[port.packet_length - 1]
if port.device == devices.NO_DEVICE {
if last_value == 0 | last_value == 3 | last_value == 4 {
return true
} else if port.packet_length == 2 {
return true
}
} else if port.device == devices.MOUSE_3_BUTTON {
if port.packet_length == 3 return true
} else if port.device == devices.MOUSE_SCROLLWHEEL | port.device == devices.MOUSE_5_BUTTON {
if port.packet_length == 4 return true
} else {
if port.packet[0] == 0xE1 {
if port.packet_length == 6 {
return true
}
} else if port.packet[0] != 0xE0 {
return true
} else if port.packet_length == 2 & port.packet[1] != 0x2A & port.packet[1] != 0xB7 {
return true
} else if port.packet_length == 4 {
return true
}
}
return false
}
main := fn(): void {
mouse_buffer = buffer.create("PS/2 Mouse")
controller.init()
if controller.port1.exists {
//log.info("Port 1 exists.")
controller.send_byte(@bitcast(0), 0xF4)
}
if controller.port2.exists {
//controller.send_byte(&controller.port2, 0xF4)
}
loop {
info = controller.get_info()
if controller.timed_out(info) {
log.error("Timeout error! Cannot handle these!")
}
if controller.check_parity(info) {
log.error("Parity error! Cannot handle these!")
}
/*
if controller.has_input(info) {
port := controller.get_port(info)
if port.packet_length > 0 & check_complete(port) {
process(port)
}
input := controller.get_input()
/*if input == 0xAA & port.can_hot_plug {
port.device = devices.NO_DEVICE
controller.send_byte(port, 0xF4)
}*/
port.packet[port.packet_length] = input
port.packet_length += 1
if check_complete(port) {
process(port)
port.packet_length = 0
}
}*/
}
}

View file

@ -0,0 +1,21 @@
.{DeviceID, NO_DEVICE} := @use("devices.hb")
State := struct {s: u8}
$Recive := State.(0)
$Reboot := State.(1)
Port := packed struct {
exists: bool,
device: DeviceID,
packet: [8]u8,
packet_length: u8,
can_hot_plug: bool,
}
$PORT_AT_STARTUP := Port.(
true,
NO_DEVICE,
.[0, 0, 0, 0, 0, 0, 0, 0],
0,
true,
)

View file

@ -1,12 +1,89 @@
stn := @use("stn");
.{sleep, log, memory} := stn
main := fn(): int {
loop {
log.info("BEFORE")
sleep.sleep_until_interrupt(8)
log.info("AFTER")
$decode_bcd := fn(value: u8): u8 {
return (value & 0xF) + ((value & 0xF0) >> 4) * 10
}
read_register := fn(register: u8): u8 {
memory.outb(0x70, register | 0x80)
return memory.inb(0x71)
}
$MONTH_TABLE := uint.[
267840000,
0,
267840000,
259200000,
267840000,
259200000,
267840000,
267840000,
259200000,
267840000,
259200000,
267840000,
]
fetch_time := fn(): uint {
sleep.disable_interrupts()
format := read_register(0xB)
second := read_register(0x0)
minute := read_register(0x2)
hour := read_register(0x4)
week := read_register(0x6)
day := read_register(0x7)
month := read_register(0x8)
year := read_register(0x9)
century := @as(u8, 0x20)
if (format & 4) == 4 {
century = 20
}
if read_register(0x6C) != 0 {
century = read_register(0x32)
}
return 0
sleep.enable_interrupts()
if (format & 4) != 4 {
second = decode_bcd(second)
minute = decode_bcd(minute)
hour = decode_bcd(hour & 0b1111111)
day = decode_bcd(day)
month = decode_bcd(month)
year = decode_bcd(year)
century = decode_bcd(century)
}
if (format & 2) != 2 & (hour & 0x80) == 0x80 {
hour = hour & 0b1111111 + 12
}
log.printf("{}-{}-{} at {}:{}:{}", .(@as(u16, year) + @as(u16, century) * 100, month, day, hour, minute, second), .{})
delta_epoch := @as(uint, year) + @as(uint, century) * 100 - 1970
result := (second + (minute + @as(uint, hour) * 60) * 60) * 100 + delta_epoch * 3155692608
test_month := 1
loop if test_month == month break else {
if test_month == 2 {
if year % 4 == 0 & year % 100 != 0 | year % 400 == 0 {
result += 250560000
} else {
result += 241920000
}
} else {
result += MONTH_TABLE[test_month]
}
test_month += 1
}
result += @as(uint, day - 1) * 8640000
return result / 100
}
main := fn(): void {
log.print(fetch_time(), .{})
}

View file

@ -0,0 +1,48 @@
stn := @use("stn");
.{sleep, log, memory} := stn
microseconds := @as(u32, 0)
seconds := @as(uint, 0)
padding := fn(): void {
iter := 0
loop if iter == 0xFFFF break else iter += 1
}
read_register := fn(register: u8): u8 {
memory.outb(0x70, register)
padding()
return memory.inb(0x71)
}
write_register := fn(register: u8, value: u8): void {
memory.outb(0x70, register)
padding()
memory.outb(0x71, value)
}
main := fn(): void {
sleep.disable_interrupts()
reg_a := read_register(0x8A)
write_register(0x8A, 3 | 0xF0 & reg_a)
log.print(read_register(0x86), log.fmt.FormatOptions.(2, 10, log.LogLevel.Info))
reg_b := read_register(0x8B)
write_register(0xB, 0x40 | reg_b)
sleep.enable_interrupts()
loop {
sleep.sleep_until_interrupt(8)
read_register(0xC)
microseconds += 122
if microseconds >= 1000000 {
microseconds -= 1000000
seconds += 1
}
log.print(seconds, log.fmt.FormatOptions.(2, 10, log.LogLevel.Info))
}
}

View file

@ -0,0 +1,7 @@
.{log, sleep} := @use("stn")
main := fn(): void {
log.info("Hello, World!")
// fake interrupt, sleep forever
sleep.sleep_until_interrupt(100)
}

View file

@ -50,8 +50,11 @@ resolution = "1024x768x24"
# [boot.limine.ableos.modules.angels_halo]
# path = "boot:///angels_halo.hbf"
[boot.limine.ableos.modules.test]
path = "boot:///test.hbf"
# [boot.limine.ableos.modules.test]
# path = "boot:///test.hbf"
# [boot.limine.ableos.modules.vfsaur]
# path = "boot:///vfsaur.hbf"
[boot.limine.ableos.modules.rtc_driver]
path = "boot:///rtc_driver.hbf"