1
0
Fork 0
forked from AbleOS/ableos

Complete revert to mainline, I think?

This commit is contained in:
peony 2024-11-10 15:04:59 +01:00
commit b5b122f451
102 changed files with 2543 additions and 1661 deletions

View file

@ -1,3 +1,3 @@
[alias] [alias]
repbuild = "run --manifest-path ./repbuild/Cargo.toml -r --" repbuild = "run --manifest-path ./repbuild/Cargo.toml -- "
dev = "run --manifest-path ./dev/Cargo.toml -r --" dev = "run --manifest-path ./dev/Cargo.toml -r --"

1040
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -138,8 +138,8 @@ fn build(name: String) {
} }
} }
pub fn build_program(name: String) {} pub fn build_program(_name: String) {}
pub fn build_library(name: String) {} pub fn build_library(_name: String) {}
fn help() { fn help() {
println!( println!(

View file

@ -4,9 +4,3 @@ build-std-features = ["compiler-builtins-mem"]
[build] [build]
target = "./targets/x86_64-ableos.json" target = "./targets/x86_64-ableos.json"
# [target.'cfg(target_arch = "x86_64")']
# rustflags = [
# "-C",
#"target-feature=+sse4.1,+avx,+aes,+fma,+popcnt,+bmi2,+avx2,+lzcnt,+xsave",
# ]

View file

@ -16,7 +16,7 @@ uart_16550 = { version = "0.3", features = ["nightly"] }
xml.git = "https://git.ablecorp.us/ableos/ableos_userland" xml.git = "https://git.ablecorp.us/ableos/ableos_userland"
versioning.git = "https://git.ablecorp.us/ableos/ableos_userland" versioning.git = "https://git.ablecorp.us/ableos/ableos_userland"
# able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland" # able_graphics_library.git = "https://git.ablecorp.us/ableos/ableos_userland"
hashbrown = { version = "0.14", features = ["nightly"] } hashbrown = { version = "0.15", features = ["nightly"] }
limine = "0.1" limine = "0.1"
[dependencies.crossbeam-queue] [dependencies.crossbeam-queue]
@ -24,10 +24,6 @@ version = "0.3"
default-features = false default-features = false
features = ["alloc", "nightly"] features = ["alloc", "nightly"]
# [dependencies.clparse]
# git = "https://git.ablecorp.us/ableos/ableos_userland"
# default-features = false
[dependencies.derive_more] [dependencies.derive_more]
version = "1" version = "1"
default-features = false default-features = false

View file

@ -3,7 +3,7 @@ pub static SERIAL_CONSOLE: Mutex<SerialConsole> = Mutex::new(SerialConsole {
uart: 0x09000000 as *mut u8, uart: 0x09000000 as *mut u8,
}); });
struct SerialConsole { pub struct SerialConsole {
uart: *mut u8, uart: *mut u8,
} }

View file

@ -30,6 +30,7 @@ const INITIAL_KERNEL_HEAP_SIZE: *const () = _initial_kernel_heap_size as _;
#[no_mangle] #[no_mangle]
#[naked] #[naked]
#[cfg(not(target_feature = "avx2"))]
unsafe extern "C" fn _kernel_start() -> ! { unsafe extern "C" fn _kernel_start() -> ! {
// Initialise SSE, then jump to kernel entrypoint // Initialise SSE, then jump to kernel entrypoint
core::arch::asm!( core::arch::asm!(
@ -49,58 +50,59 @@ unsafe extern "C" fn _kernel_start() -> ! {
) )
} }
// #[no_mangle] #[no_mangle]
// #[naked] #[naked]
// unsafe extern "C" fn _kernel_start() -> ! { #[cfg(target_feature = "avx2")]
// core::arch::asm!( unsafe extern "C" fn _kernel_start() -> ! {
// // Enable protected mode and configure control registers core::arch::asm!(
// "mov rax, cr0", // Enable protected mode and configure control registers
// "and ax, 0xFFFB", // Clear CR0.EM (bit 2) for coprocessor emulation "mov rax, cr0",
// "or ax, 0x2", // Set CR0.MP (bit 1) for coprocessor monitoring "and ax, 0xFFFB", // Clear CR0.EM (bit 2) for coprocessor emulation
// "mov cr0, rax", "or ax, 0x2", // Set CR0.MP (bit 1) for coprocessor monitoring
"mov cr0, rax",
// "mov rax, cr4", "mov rax, cr4",
// "or ax, (1 << 9) | (1 << 10)", // Set CR4.OSFXSR (bit 9) and CR4.OSXMMEXCPT (bit 10) "or ax, (1 << 9) | (1 << 10)", // Set CR4.OSFXSR (bit 9) and CR4.OSXMMEXCPT (bit 10)
// "mov cr4, rax", "mov cr4, rax",
// // Enable OSXSAVE (required for AVX, AVX2, and XSAVE) // Enable OSXSAVE (required for AVX, AVX2, and XSAVE)
// "mov rax, cr4", "mov rax, cr4",
// "or eax, 1 << 18", // Set CR4.OSXSAVE (bit 18) "or eax, 1 << 18", // Set CR4.OSXSAVE (bit 18)
// "mov cr4, rax", "mov cr4, rax",
// // Enable AVX and AVX2 state saving // Enable AVX and AVX2 state saving
// "xor rcx, rcx", "xor rcx, rcx",
// "xgetbv", "xgetbv",
// "or eax, 7", // Enable SSE, AVX, and AVX2 state saving "or eax, 7", // Enable SSE, AVX, and AVX2 state saving
// "xsetbv", "xsetbv",
// // Check for AVX and XSAVE support // Check for AVX and XSAVE support
// "mov eax, 1", "mov eax, 1",
// "cpuid", "cpuid",
// "and ecx, 0x18000000", "and ecx, 0x18000000",
// "cmp ecx, 0x18000000", "cmp ecx, 0x18000000",
// "jne {1}", // Jump if AVX/OSXSAVE is not supported "jne {1}", // Jump if AVX/OSXSAVE is not supported
// // Check for BMI2 and AVX2 support // Check for BMI2 and AVX2 support
// "mov eax, 7", "mov eax, 7",
// "xor ecx, ecx", "xor ecx, ecx",
// "cpuid", "cpuid",
// "and ebx, (1 << 8) | (1 << 5)", // Check BMI2 (bit 8) and AVX2 (bit 5) "and ebx, (1 << 8) | (1 << 5)", // Check BMI2 (bit 8) and AVX2 (bit 5)
// "cmp ebx, (1 << 8) | (1 << 5)", // Compare to ensure both are supported "cmp ebx, (1 << 8) | (1 << 5)", // Compare to ensure both are supported
// // Check for LZCNT and POPCNT support // Check for LZCNT and POPCNT support
// "mov eax, 1", "mov eax, 1",
// "cpuid", "cpuid",
// "and ecx, (1 << 5) | (1 << 23)", // Check LZCNT (bit 5) and POPCNT (bit 23) "and ecx, (1 << 5) | (1 << 23)", // Check LZCNT (bit 5) and POPCNT (bit 23)
// "cmp ecx, (1 << 5) | (1 << 23)", // Compare to ensure both are supported "cmp ecx, (1 << 5) | (1 << 23)", // Compare to ensure both are supported
// // Jump to the kernel entry point // Jump to the kernel entry point
// "jmp {0}", "jmp {0}",
// sym start, sym start,
// sym oops, sym oops,
// options(noreturn), options(noreturn),
// ) )
// } }
unsafe extern "C" fn oops() -> ! { unsafe extern "C" fn oops() -> ! {
panic!("your cpu is ancient >:(") panic!("your cpu is ancient >:(")
@ -249,6 +251,7 @@ unsafe extern "C" fn start() -> ! {
/// Spin loop /// Spin loop
pub fn spin_loop() -> ! { pub fn spin_loop() -> ! {
loop { loop {
core::hint::spin_loop();
x86_64::instructions::hlt() x86_64::instructions::hlt()
} }
} }

View file

@ -26,9 +26,6 @@ unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
#[inline(always)] #[inline(always)]
pub fn handler(vm: &mut Vm) { pub fn handler(vm: &mut Vm) {
let ecall_number = vm.registers[2].cast::<u64>(); let ecall_number = vm.registers[2].cast::<u64>();
// log::info!("eca called :pensive:");
// debug!("Ecall number {:?}", ecall_number);
//info!("Register dump: {:?}", vm.registers);
match ecall_number { match ecall_number {
0 => { 0 => {
@ -97,7 +94,8 @@ pub fn handler(vm: &mut Vm) {
match msg_type { match msg_type {
0 => unsafe { 0 => unsafe {
let size = msg_vec[1]; let size = msg_vec[1];
let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap()); let addr =
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
let value = match size { let value = match size {
0 => x86_in::<u8>(addr) as u64, 0 => x86_in::<u8>(addr) as u64,
1 => x86_in::<u16>(addr) as u64, 1 => x86_in::<u16>(addr) as u64,
@ -109,7 +107,8 @@ pub fn handler(vm: &mut Vm) {
}, },
1 => unsafe { 1 => unsafe {
let size = msg_vec[1]; let size = msg_vec[1];
let addr = u16::from_le_bytes(msg_vec[2..4].try_into().unwrap()); let addr =
u16::from_le_bytes(msg_vec[2..4].try_into().unwrap_unchecked());
// info!("Setting address {}", addr); // info!("Setting address {}", addr);
match size { match size {
@ -132,9 +131,13 @@ pub fn handler(vm: &mut Vm) {
3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"), 3 => unimplemented!("TODO: implement whatever buffer 3 does for no x86_64"),
// source of rng // source of rng
4 => { 4 => {
// limit to last 32 bits let block = block_read(mem_addr, length);
vm.registers[1] = block.chunks_mut(8.min(length)).for_each(|chunk| {
hbvm::value::Value(crate::arch::hardware_random_u64() & 0xFFFFFFFF); chunk.clone_from_slice(
&crate::arch::hardware_random_u64().to_le_bytes()[..chunk.len()],
);
});
vm.registers[1] = hbvm::value::Value(mem_addr);
} }
5 => match dt_msg_handler(vm, mem_addr, length) { 5 => match dt_msg_handler(vm, mem_addr, length) {
Ok(()) => {} Ok(()) => {}
@ -173,7 +176,7 @@ pub fn handler(vm: &mut Vm) {
Ok(msg) => msg, Ok(msg) => msg,
Err(_) => return, Err(_) => return,
}; };
if msg.len() > max_length.try_into().unwrap() { if msg.len() > unsafe { max_length.try_into().unwrap_unchecked() } {
info!("{}", max_length); info!("{}", max_length);
error!("Message is too long to map in."); error!("Message is too long to map in.");
} else { } else {
@ -205,15 +208,3 @@ pub enum LogError {
NoMessages, NoMessages,
InvalidLogFormat, InvalidLogFormat,
} }
// use {alloc::vec, log::Record};
// fn memory_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
// let mut val = alloc::vec::Vec::new();
// for _ in 0..4096 {
// val.push(0);
// }
// info!("Block address: {:?}", val.as_ptr());
// vm.registers[1] = hbvm::value::Value(val.as_ptr() as u64);
// vm.registers[2] = hbvm::value::Value(4096);
// Ok(())
// }

View file

@ -9,12 +9,16 @@ use log::Record;
pub fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> { pub fn log_msg_handler(_vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), LogError> {
let msg_vec = block_read(mem_addr, length); let msg_vec = block_read(mem_addr, length);
let log_level = msg_vec.last().unwrap(); let log_level = msg_vec[0];
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
let str = block_read(strptr, strlen);
let file_name = "None"; let file_name = "None";
let line_number = 0; let line_number = 0;
match core::str::from_utf8(&msg_vec[..msg_vec.len()]) { match core::str::from_utf8(&str) {
Ok(strr) => { Ok(strr) => {
use log::Level::*; use log::Level::*;
let log_level = match log_level { let log_level = match log_level {

View file

@ -17,13 +17,54 @@ pub enum MemoryQuotaType {
} }
fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> { fn alloc_page(vm: &mut Vm, _mem_addr: u64, _length: usize) -> Result<(), MemoryServiceError> {
let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 4096)) }; let ptr = unsafe { alloc(Layout::from_size_align_unchecked(4096, 8)) };
info!("Block address: {:?}", ptr); info!("Block address: {:?}", ptr);
vm.registers[1] = hbvm::value::Value(ptr as u64); vm.registers[1] = hbvm::value::Value(ptr as u64);
vm.registers[2] = hbvm::value::Value(4096); vm.registers[2] = hbvm::value::Value(4096);
Ok(()) Ok(())
} }
#[inline(always)]
unsafe fn memset(mut dest: *mut u8, src: *const u8, count: usize, size: usize) {
const BLOCK_SIZE: usize = 64;
let mut remaining = count * size;
if remaining < 16 {
src.copy_to_nonoverlapping(dest, remaining);
return;
}
let mut buffer = [0u8; BLOCK_SIZE];
let mut buffer_size = size;
src.copy_to_nonoverlapping(buffer.as_mut_ptr(), size);
while core::intrinsics::likely(buffer_size * 2 <= BLOCK_SIZE) {
buffer
.as_mut_ptr()
.copy_to_nonoverlapping(buffer.as_mut_ptr().add(buffer_size), buffer_size);
buffer_size *= 2;
}
let buffer_ptr = buffer.as_ptr() as *const u64;
while (dest as usize) & 7 != 0 && remaining >= 8 {
buffer.as_ptr().copy_to_nonoverlapping(dest, 1);
dest = dest.add(1);
remaining -= 1;
}
while core::intrinsics::likely(remaining >= 8) {
*(dest as *mut u64) = *buffer_ptr;
dest = dest.add(8);
remaining -= 8;
}
if remaining > 0 {
buffer.as_ptr().copy_to_nonoverlapping(dest, remaining);
}
}
#[inline(always)]
pub fn memory_msg_handler( pub fn memory_msg_handler(
vm: &mut Vm, vm: &mut Vm,
mem_addr: u64, mem_addr: u64,
@ -32,40 +73,35 @@ pub fn memory_msg_handler(
let msg_vec = block_read(mem_addr, length); let msg_vec = block_read(mem_addr, length);
let msg_type = msg_vec[0]; let msg_type = msg_vec[0];
match msg_type { match msg_type {
0 => { 0 => unsafe {
let page_count = msg_vec[1]; let page_count = msg_vec[1];
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let mptr: u64 = u64::from_le_bytes(mptr_raw);
log::debug!("Allocating {} pages @ {:x}", page_count, mptr); let ptr = alloc(Layout::from_size_align_unchecked(
let ptr = unsafe {
alloc(Layout::from_size_align_unchecked(
page_count as usize * 4096, page_count as usize * 4096,
4096, 8,
)) ));
};
log::debug!("Allocating {} pages @ {:x}", page_count, ptr as u64);
vm.registers[1] = hbvm::value::Value(ptr as u64); vm.registers[1] = hbvm::value::Value(ptr as u64);
log::debug!("Kernel ptr: {:x}", ptr as u64); log::debug!("Kernel ptr: {:x}", ptr as u64);
} },
1 => { 1 => unsafe {
let page_count = msg_vec[1]; let page_count = msg_vec[1];
let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap(); let mptr_raw: [u8; 8] = msg_vec[2..10].try_into().unwrap();
let mptr: u64 = u64::from_le_bytes(mptr_raw); let mptr: u64 = u64::from_le_bytes(mptr_raw);
log::debug!("Deallocating {} pages @ {:x}", page_count, mptr); log::debug!("Deallocating {} pages @ {:x}", page_count, mptr);
unsafe {
dealloc( dealloc(
mptr as *mut u8, mptr as *mut u8,
Layout::from_size_align_unchecked(page_count as usize * 4096, 4096), Layout::from_size_align_unchecked(page_count as usize * 4096, 8),
) )
} },
}
2 => { 2 => {
use MemoryQuotaType::*; use MemoryQuotaType::*;
let quota_type = match msg_vec[0] { let quota_type = match msg_vec[1] {
0 => NoQuota, 0 => NoQuota,
1 => SoftQuota, 1 => SoftQuota,
2 => HardQuota, 2 => HardQuota,
@ -82,10 +118,24 @@ pub fn memory_msg_handler(
) )
} }
3 => { 3 => {
let page_count = msg_vec[0]; let page_count = msg_vec[1];
log::debug!(" {} pages", page_count); log::debug!(" {} pages", page_count);
} }
4 => unsafe {
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
let src = u64::from_le_bytes(msg_vec[5..13].try_into().unwrap_unchecked()) as *const u8;
let dest = u64::from_le_bytes(msg_vec[13..21].try_into().unwrap_unchecked()) as *mut u8;
src.copy_to_nonoverlapping(dest, count);
},
5 => unsafe {
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
let size = u32::from_le_bytes(msg_vec[5..9].try_into().unwrap_unchecked()) as usize;
let src = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as *const u8;
let dest = u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *mut u8;
memset(dest, src, count, size);
},
_ => { _ => {
log::debug!("Unknown memory service message type: {}", msg_type); log::debug!("Unknown memory service message type: {}", msg_type);
} }

View file

@ -22,21 +22,19 @@ pub enum ServiceError {
pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> { pub fn sds_msg_handler(vm: &mut Vm, mem_addr: u64, length: usize) -> Result<(), ServiceError> {
let msg_vec = block_read(mem_addr, length); let msg_vec = block_read(mem_addr, length);
let sds_event_type: ServiceEventType = msg_vec[0].into(); let sds_event_type: ServiceEventType = msg_vec[0].into();
let strptr = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap());
// info!("Length {}", msg_vec.len()); let strlen = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap()) as usize;
let string_vec = block_read(strptr, strlen);
let string = core::str::from_utf8(string_vec).expect("Our bytes should be valid utf8");
use ServiceEventType::*; use ServiceEventType::*;
match sds_event_type { match sds_event_type {
CreateService => { CreateService => {
let string =
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
let ret = sds_create_service(string); let ret = sds_create_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64); vm.registers[1] = hbvm::value::Value(ret as u64);
} }
DeleteService => todo!(), DeleteService => todo!(),
SearchServices => { SearchServices => {
let string =
core::str::from_utf8(&msg_vec[1..]).expect("Our bytes should be valid utf8");
let ret = sds_search_service(string); let ret = sds_search_service(string);
vm.registers[1] = hbvm::value::Value(ret as u64); vm.registers[1] = hbvm::value::Value(ret as u64);
} }

View file

@ -37,7 +37,6 @@ impl hbvm::mem::Memory for Memory {
target: *mut u8, target: *mut u8,
count: usize, count: usize,
) -> Result<(), hbvm::mem::LoadError> { ) -> Result<(), hbvm::mem::LoadError> {
// if addr.get() % 4096 == 0 {}
core::ptr::copy_nonoverlapping(addr.get() as *const u8, target, count); core::ptr::copy_nonoverlapping(addr.get() as *const u8, target, count);
Ok(()) Ok(())
} }

View file

@ -97,7 +97,7 @@ impl HandlePageFault for PageFaultHandler {
#[inline(always)] #[inline(always)]
const fn stack_layout() -> Layout { const fn stack_layout() -> Layout {
unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 4096) } unsafe { Layout::from_size_align_unchecked(STACK_SIZE, 8) }
} }
#[inline(always)] #[inline(always)]

View file

@ -6,6 +6,7 @@
slice_split_once, slice_split_once,
exclusive_wrapper, exclusive_wrapper,
new_uninit, new_uninit,
core_intrinsics,
abi_x86_interrupt, abi_x86_interrupt,
alloc_error_handler, alloc_error_handler,
ptr_sub_ptr, ptr_sub_ptr,
@ -14,8 +15,7 @@
pointer_is_aligned_to pointer_is_aligned_to
)] )]
#![test_runner(crate::test_runner)] #![test_runner(crate::test_runner)]
#![cfg_attr(not(debug_assertions), allow(unused, deprecated))] #![allow(dead_code, internal_features)]
#![allow(dead_code)]
extern crate alloc; extern crate alloc;
mod allocator; mod allocator;

View file

@ -36,7 +36,19 @@ impl log::Log for Logger {
Level::Debug => "25", Level::Debug => "25",
Level::Trace => "103", Level::Trace => "103",
}; };
let module = record.module_path().unwrap_or_default(); let module = record
.module_path()
.unwrap_or_default()
.rsplit_once(':')
.unwrap_or_default()
.1;
if module == "" {
crate::arch::log(format_args!(
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m: {}\r\n",
record.args(),
))
.expect("write to serial console");
} else {
let line = record.line().unwrap_or_default(); let line = record.line().unwrap_or_default();
crate::arch::log(format_args!( crate::arch::log(format_args!(
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n", "\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
@ -44,6 +56,7 @@ impl log::Log for Logger {
)) ))
.expect("write to serial console"); .expect("write to serial console");
} }
}
fn flush(&self) {} fn flush(&self) {}
} }

2
known_bugs.md Normal file
View file

@ -0,0 +1,2 @@
# i did not know where to put this
- memcpy / memset cause crash on debug builds due to ptr misalignment that is not present on release builds

View file

@ -6,26 +6,15 @@ edition = "2021"
[dependencies] [dependencies]
str-reader = "0.1" str-reader = "0.1"
derive_more = { version = "1", default-features = false, features = [ derive_more = { version = "1", default-features = false, features = [
"add",
"add_assign",
"constructor",
"display", "display",
"from",
"into",
"mul",
"mul_assign",
"not",
"sum",
] } ] }
error-stack = "0.5" error-stack = "0.5"
fatfs = "0.3" fatfs = { version = "0.3", default-features = false, features = [
"std",
"alloc",
] }
toml = "0.8" toml = "0.8"
# hbasm.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git" hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
log = "0.4" log = "0.4"
raw-cpuid = "11" raw-cpuid = "11"
ureq = { version = "2", default-features = false, features = ["tls"] }
[dependencies.reqwest]
version = "0.12"
default-features = false
features = ["rustls-tls", "blocking"]

View file

@ -47,7 +47,6 @@ impl Package {
for (count, (name, table)) in bin_table.into_iter().enumerate() { for (count, (name, table)) in bin_table.into_iter().enumerate() {
// if count != 0 { // if count != 0 {
println!("{}", name);
binaries.push(name.clone()); binaries.push(name.clone());
// } // }
} }
@ -63,40 +62,49 @@ impl Package {
build_cmd, build_cmd,
} }
} }
pub fn build(&self) { pub fn build(&self, out: &mut Vec<u8>) -> std::io::Result<()> {
if self.binaries.contains(&"hblang".to_string()) { if self.binaries.contains(&"hblang".to_string()) {
let file = self.build_cmd.split_ascii_whitespace().last().unwrap(); let file = self.build_cmd.split_ascii_whitespace().last().unwrap();
let path = format!("sysdata/programs/{}/{}", self.name, file); let path = format!("sysdata/programs/{}/{}", self.name, file);
let mut bytes = Vec::new();
// compile here // compile here
let _ = hblang::run_compiler( hblang::run_compiler(
&path, &path,
Options { Options {
fmt: true, fmt: true,
..Default::default() ..Default::default()
}, },
&mut bytes, out,
); )?;
let _ = hblang::run_compiler(&path, Default::default(), &mut bytes);
match std::fs::create_dir("target/programs") { match std::fs::create_dir("target/programs") {
Ok(_) => (), Ok(_) => (),
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (), Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => (),
Err(e) => panic!("{}", e), Err(e) => panic!("{}", e),
} }
std::fs::write(format!("target/programs/{}.hbf", self.name), &bytes).unwrap();
bytes.clear(); hblang::run_compiler(
let _ = hblang::run_compiler( &path,
Options {
..Default::default()
},
out,
)?;
std::fs::write(format!("target/programs/{}.hbf", self.name), &out)?;
out.clear();
hblang::run_compiler(
&path, &path,
Options { Options {
dump_asm: true, dump_asm: true,
..Default::default() ..Default::default()
}, },
&mut bytes, out,
); )?;
std::fs::write(format!("target/programs/{}.hba", self.name), &bytes).unwrap(); std::fs::write(format!("target/programs/{}.hba", self.name), &out)?;
out.clear();
} }
Ok(())
} }
} }

View file

@ -1,14 +1,12 @@
// #![allow(unused)]
mod dev; mod dev;
use { use {
core::fmt::Write as _,
derive_more::Display, derive_more::Display,
dev::Package, dev::Package,
error_stack::{bail, report, Context, Report, Result, ResultExt}, error_stack::{bail, report, Context, Report, Result, ResultExt},
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek}, fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
std::{ std::{
// fmt::Display,
fs::{self, File}, fs::{self, File},
io::{self, Write}, io::{self, Write},
path::Path, path::Path,
@ -38,6 +36,8 @@ fn main() -> Result<(), Error> {
target = Target::Riscv64Virt; target = Target::Riscv64Virt;
} else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" { } else if arg == "arm64" || arg == "aarch64" || arg == "aarch64-virt" {
target = Target::Aarch64; target = Target::Aarch64;
} else if arg == "avx2" {
target = Target::X86_64Avx2;
} else { } else {
return Err(report!(Error::InvalidSubCom)); return Err(report!(Error::InvalidSubCom));
} }
@ -61,6 +61,8 @@ fn main() -> Result<(), Error> {
target = Target::Aarch64; target = Target::Aarch64;
} else if arg == "--noaccel" { } else if arg == "--noaccel" {
do_accel = false; do_accel = false;
} else if arg == "avx2" {
target = Target::X86_64Avx2;
} else { } else {
return Err(report!(Error::InvalidSubCom)); return Err(report!(Error::InvalidSubCom));
} }
@ -80,7 +82,7 @@ fn main() -> Result<(), Error> {
" -r / --release: build in release mode\n", " -r / --release: build in release mode\n",
" -d / --debuginfo: build with debug info\n", " -d / --debuginfo: build with debug info\n",
" --noaccel: run without acceleration (e.g, no kvm)\n", " --noaccel: run without acceleration (e.g, no kvm)\n",
"[ rv64 / riscv64 / riscv64-virt / aarch64 / arm64 / aarch64-virt ]: sets target" "[ rv64 / riscv64 / riscv64-virt / aarch64 / arm64 / aarch64-virt / avx2 ]: sets target"
),); ),);
Ok(()) Ok(())
} }
@ -203,7 +205,12 @@ TERM_BACKDROP={}
let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap(); let modules = value.get_mut("modules").unwrap().as_table_mut().unwrap();
// let mut real_modules = modules.clone(); // let mut real_modules = modules.clone();
modules.into_iter().for_each(|(_, value)| { let mut errors = String::new();
let mut out = Vec::new();
modules
.into_iter()
.map(|(_, value)| -> Result<(), io::Error> {
if value.is_table() { if value.is_table() {
let path = get_path_without_boot_prefix( let path = get_path_without_boot_prefix(
value.get("path").expect("You must have `path` as a value"), value.get("path").expect("You must have `path` as a value"),
@ -215,9 +222,26 @@ TERM_BACKDROP={}
let p = Package::load_from_file( let p = Package::load_from_file(
format!("sysdata/programs/{}/meta.toml", path).to_owned(), format!("sysdata/programs/{}/meta.toml", path).to_owned(),
); );
p.build(); match p.build(&mut out) {
Ok(()) => {}
Err(_) => {
writeln!(errors, "========= while compiling {} =========", path)
.unwrap();
errors.push_str(core::str::from_utf8(&out).expect("no"));
out.clear();
} }
}); }
}
Ok(())
})
.for_each(drop);
if !errors.is_empty() {
let _ = writeln!(errors, "!!! STOPPING DUE TO PREVIOUS ERRORS !!!");
std::eprint!("{errors}");
continue;
}
modules.into_iter().for_each(|(_key, value)| { modules.into_iter().for_each(|(_key, value)| {
if value.is_table() { if value.is_table() {
let path = value.get("path").expect("You must have `path` as a value"); let path = value.get("path").expect("You must have `path` as a value");
@ -304,6 +328,9 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
if target == Target::Aarch64 { if target == Target::Aarch64 {
com.args(["--target", "targets/aarch64-virt-ableos.json"]); com.args(["--target", "targets/aarch64-virt-ableos.json"]);
} }
if target == Target::X86_64Avx2 {
com.args(["--target", "targets/x86_64_v3-ableos.json"]);
}
match com.status() { match com.status() {
Ok(s) if s.code() != Some(0) => bail!(Error::Build), Ok(s) if s.code() != Some(0) => bail!(Error::Build),
@ -317,6 +344,10 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
path.push_str("_x86-64"); path.push_str("_x86-64");
"target/x86_64-ableos" "target/x86_64-ableos"
} }
Target::X86_64Avx2 => {
path.push_str("_x86-64");
"target/x86_64_v3-ableos"
}
Target::Riscv64Virt => "target/riscv64-virt-ableos", Target::Riscv64Virt => "target/riscv64-virt-ableos",
Target::Aarch64 => { Target::Aarch64 => {
path.push_str("_aarch64"); path.push_str("_aarch64");
@ -341,7 +372,7 @@ fn build(release: bool, target: Target, debuginfo: bool) -> Result<(), Error> {
fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> { fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
let target_str = match target { let target_str = match target {
Target::X86_64 => "qemu-system-x86_64", Target::X86_64 | Target::X86_64Avx2 => "qemu-system-x86_64",
Target::Riscv64Virt => "qemu-system-riscv64", Target::Riscv64Virt => "qemu-system-riscv64",
Target::Aarch64 => "qemu-system-aarch64", Target::Aarch64 => "qemu-system-aarch64",
}; };
@ -384,23 +415,19 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
}; };
match target { match target {
Target::X86_64 => { Target::X86_64 | Target::X86_64Avx2 => {
#[rustfmt::skip] #[rustfmt::skip]
com.args([ com.args([
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?, "-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
"-drive", "file=target/disk.img,format=raw", "-drive", "file=target/disk.img,format=raw",
"-device", "vmware-svga", "-device", "vmware-svga",
// "-serial", "stdio",
"-m", "2G", "-m", "2G",
"-smp", "1", "-smp", "1",
"-parallel", "none", "-parallel", "none",
"-monitor", "none", "-monitor", "none",
"-machine", accel, "-machine", accel,
"-cpu", "-cpu", "max",
if accel != "accel=tcg" {
"host"
} else {
"Broadwell-v4"
},
"-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04",
]); ]);
} }
@ -445,7 +472,7 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> { fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
let (ovmf_url, ovmf_path) = match target { let (ovmf_url, ovmf_path) = match target {
Target::X86_64 => ( Target::X86_64 | Target::X86_64Avx2 => (
"https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd", "https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
"target/RELEASEX64_OVMF.fd", "target/RELEASEX64_OVMF.fd",
), ),
@ -467,12 +494,12 @@ fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
Ok(_) => return Ok(ovmf_path.to_owned()), Ok(_) => return Ok(ovmf_path.to_owned()),
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)), Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
}; };
let mut bytes = reqwest::blocking::get(ovmf_url) let req = ureq::get(ovmf_url)
.call()
.map_err(Report::from) .map_err(Report::from)
.change_context(OvmfFetchError::Fetch)?; .change_context(OvmfFetchError::Fetch)?;
bytes std::io::copy(&mut req.into_reader(), &mut file)
.copy_to(&mut file)
.map_err(Report::from) .map_err(Report::from)
.change_context(OvmfFetchError::Io)?; .change_context(OvmfFetchError::Io)?;
@ -494,6 +521,7 @@ impl Context for OvmfFetchError {}
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
enum Target { enum Target {
X86_64, X86_64,
X86_64Avx2,
Riscv64Virt, Riscv64Virt,
Aarch64, Aarch64,
} }

BIN
sysdata/assets/able.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,10 @@
Tamsyn font is free. You are hereby granted permission to use, copy, modify,
and distribute it as you see fit.
Tamsyn font is provided "as is" without any express or implied warranty.
The author makes no representations about the suitability of this font for
a particular purpose.
In no event will the author be held liable for damages arising from the use
of this font.

BIN
sysdata/assets/mini.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
sysdata/assets/mini.qoi Normal file

Binary file not shown.

Binary file not shown.

View file

@ -1 +0,0 @@
# dt_api

View file

@ -1,6 +0,0 @@
.{string} := @use("../../stn/src/lib.hb")
dt_get := fn(query: ^u8): int {
length := string.length(query)
return @eca(3, 5, query, length)
}

View file

@ -0,0 +1,4 @@
(horizontal
spacing : 10
(label "hi")
(label "goodbye"))

View file

@ -0,0 +1 @@
(label "hello")

View file

@ -0,0 +1,3 @@
(vertical
(label "hello")
(label "hello" color:red))

View file

@ -1,25 +1,49 @@
stn := @use("../../stn/src/lib.hb"); stn := @use("../../stn/src/lib.hb");
.{string, memory, buffer} := stn .{string, memory, buffer, log} := stn
render := @use("../../../libraries/render/src/lib.hb")
input := @use("../../intouch/src/lib.hb") input := @use("../../intouch/src/lib.hb")
widgets := @use("widgets/widgets.hb")
ui := @use("ui.hb")
WindowID := struct { WindowID := struct {
host_id: int, host_id: int,
window_id: int, window_id: int,
} }
create_window := fn(channel: int): void { VoidWindowID := WindowID.(0, 0)
create_window := fn(channel: int): ^render.Surface {
// get the horizon buffer // get the horizon buffer
// request a new window and provide the callback buffer // request a new window and provide the callback buffer
// wait to recieve a message // wait to recieve a message
windowing_system_buffer := buffer.search("XHorizon\0") windowing_system_buffer := buffer.search("XHorizon\0")
mem_buf := memory.request_page(1)
if windowing_system_buffer == 0 { if windowing_system_buffer == 0 {
return return @as(^render.Surface, idk)
} else { } else {
msg := "\{01}\0" // ! bad able, stop using string messages :ragey:
msg_length := 2 // msg := "\{01}\0"
return @eca(3, windowing_system_buffer, msg, msg_length) // msg_length := 2
// @as(void, @eca(3, windowing_system_buffer, msg, msg_length))
x := 0
loop if x > 1000 break else x += 1
ret := buffer.recv([u8; 4096], windowing_system_buffer, mem_buf)
if ret == null {
log.info("No messages\0")
}
if *mem_buf == 0 {
log.info("No messages\0")
}
return @as(^render.Surface, idk)
} }
} }

View file

@ -0,0 +1,47 @@
stn := @use("../../../libraries/stn/src/lib.hb");
.{string, log} := stn;
.{Vec2} := stn.math
render := @use("../../../libraries/render/src/lib.hb");
.{Surface} := render;
.{Font} := render.text
UI := struct {raw: ^u8, raw_length: uint, is_dirty: bool, surface: Surface, // Each child has their WidgetType as their first byte
// children: ^^u8,
}
render_ui := fn(surface: Surface, ui: UI): void {
if ui.is_dirty {
render.clear(ui.surface, render.black)
ui.is_dirty = false
}
pos := Vec2(uint).(0, 0)
render.put_surface(surface, ui.surface, pos, false)
}
sexpr_parser := fn(sexpr: ^u8): UI {
cursor := sexpr
paren_balance := 0
loop {
if *cursor == 0 {
if paren_balance != 0 {
log.error("Unbalanced Parens\0")
}
break
} else if *cursor == 40 {
log.info("Open paren\0")
paren_balance += 1
} else if *cursor == 41 {
log.info("Closed paren\0")
paren_balance -= 1
}
cursor += 1
}
length := string.length(sexpr)
ui_surface := render.new_surface(100, 100)
return UI.(sexpr, length, true, ui_surface)
}

View file

@ -0,0 +1,13 @@
render := @use("../../../../libraries/render/src/lib.hb");
.{Surface} := render
Image := struct {
magic: uint,
is_dirty: bool,
surface: Surface,
}
image_from_surface := fn(surface: Surface): Image {
img := Image.(4, true, surface)
return img
}

View file

@ -0,0 +1,38 @@
stn := @use("../../../../libraries/stn/src/lib.hb");
.{string, log} := stn;
.{Vec2} := stn.math
render := @use("../../../../libraries/render/src/lib.hb");
.{Surface} := render;
.{Font} := render.text
Label := struct {
magic: uint,
is_dirty: bool,
surface: Surface,
text: ^u8,
text_length: uint,
}
set_label_text := fn(label: Label, text: ^u8): void {
text_length := string.length(text)
label.is_dirty = true
label.text = text
label.text_length = text_length
}
render_label_to_surface := fn(surface: Surface, label: Label, font: Font, pos: Vec2(uint)): void {
if label.is_dirty {
render.clear(label.surface, render.black)
render.put_text(label.surface, font, .(0, 0), render.white, label.text)
}
render.put_surface(surface, label.surface, pos, false)
}
new_label := fn(text: ^u8): Label {
text_surface := render.new_surface(1024, 20)
text_length := string.length(text)
label := Label.(3, true, text_surface, text, text_length)
return label
}

View file

@ -0,0 +1,7 @@
NoWidget := 0
VerticalWidgetType := 1
HorizontalWidgetType := 2
LabelWidgetType := 3
ImageWidgetType := 4

View file

@ -0,0 +1,36 @@
// Widget types
// End types
stn := @use("../../../../libraries/stn/src/lib.hb");
.{string, log} := stn;
.{Vec2} := stn.math
render := @use("../../../../libraries/render/src/lib.hb");
.{Surface} := render;
.{Font} := render.text
widget_types := @use("widget_types.hb")
label := @use("label.hb")
image := @use("image.hb")
Size := struct {
min_width: int,
max_width: int,
min_height: int,
max_height: int,
}
Vertical := packed struct {
magic: uint,
// array of children, idk
// use a vec or linked list or whatever
children: ^^u8,
}
Horizontal := packed struct {
magic: uint,
// array of children, idk
// use a vec or linked list or whatever
children: ^^u8,
}

View file

@ -7,7 +7,7 @@ ApplicationInfo := struct {
pNext: ^int, pNext: ^int,
application_name: ^u8, application_name: ^u8,
application_version: int, application_version: int,
engine_name: int, engine_name: ^u8,
engine_version: int, engine_version: int,
api_version: int, api_version: int,
} }

View file

@ -0,0 +1,22 @@
keycodes := @use("keycodes.hb");
.{KeyCode} := keycodes
KeyEvent := struct {
// 0 if down
// 1 if up
up: u8,
// 0 if not just triggered
// 1 if just triggered
just_triggered: u8,
key: KeyCode,
}
MouseEvent := packed struct {
x_change: i8,
y_change: i8,
left: bool,
middle: bool,
right: bool,
}
GamepadEvent := struct {}

View file

@ -1,67 +1,121 @@
/*
Originally I was modelling this after the following(1). I have since changed my mind.
I am now modelling it as I see fit. This is likely not the final version.
1) https://www.libsdl.org/release/SDL-1.2.15/include/SDL_keysym.h
*/
KeyCode := u32 KeyCode := u32
// https://www.libsdl.org/release/SDL-1.2.15/include/SDL_keysym.h // Typically this is not a keycode you will ever recieve.
Backspace := KeyCode.(8) None := KeyCode.(0)
Tab := KeyCode.(9)
Clear := KeyCode.(12)
Return := KeyCode.(13)
Pause := KeyCode.(19)
Escape := KeyCode.(27)
Space := KeyCode.(32)
A := KeyCode.(97) Escape := KeyCode.(1)
/* /* Alphabet keycodes */
ETC
*/
Z := KeyCode.(122)
Delete := KeyCode.(127) A := KeyCode.(2)
B := KeyCode.(3)
C := KeyCode.(4)
D := KeyCode.(5)
E := KeyCode.(6)
F := KeyCode.(7)
G := KeyCode.(8)
H := KeyCode.(9)
I := KeyCode.(10)
J := KeyCode.(11)
K := KeyCode.(12)
L := KeyCode.(13)
M := KeyCode.(14)
N := KeyCode.(15)
O := KeyCode.(16)
P := KeyCode.(17)
Q := KeyCode.(18)
R := KeyCode.(19)
S := KeyCode.(20)
T := KeyCode.(21)
U := KeyCode.(22)
V := KeyCode.(23)
W := KeyCode.(24)
X := KeyCode.(25)
Y := KeyCode.(26)
Z := KeyCode.(27)
/* /* Numeric keycodes*/
ETC
*/
KeypadNumber0 := KeyCode.(256) Number0 := KeyCode.(28)
KeypadNumber1 := KeyCode.(257) Number1 := KeyCode.(29)
KeypadNumber2 := KeyCode.(258) Number2 := KeyCode.(30)
KeypadNumber3 := KeyCode.(259) Number3 := KeyCode.(31)
KeypadNumber4 := KeyCode.(260) Number4 := KeyCode.(32)
KeypadNumber5 := KeyCode.(261) Number5 := KeyCode.(33)
KeypadNumber6 := KeyCode.(262) Number6 := KeyCode.(34)
KeypadNumber7 := KeyCode.(263) Number7 := KeyCode.(35)
KeypadNumber8 := KeyCode.(264) Number8 := KeyCode.(36)
KeypadNumber9 := KeyCode.(265) Number9 := KeyCode.(37)
KeypadPeriod := KeyCode.(266) KeypadNumber0 := KeyCode.(38)
KeypadDivide := KeyCode.(267) KeypadNumber1 := KeyCode.(39)
KeypadMultiply := KeyCode.(268) KeypadNumber2 := KeyCode.(40)
KeypadMinus := KeyCode.(269) KeypadNumber3 := KeyCode.(41)
KeypadPlus := KeyCode.(270) KeypadNumber4 := KeyCode.(42)
KeypadEnter := KeyCode.(271) KeypadNumber5 := KeyCode.(43)
KeypadEquals := KeyCode.(272) KeypadNumber6 := KeyCode.(44)
KeypadNumber7 := KeyCode.(45)
KeypadNumber8 := KeyCode.(46)
KeypadNumber9 := KeyCode.(47)
NumLock := KeyCode.(300) KeypadPeriod := KeyCode.(48)
CapsLock := KeyCode.(301) KeypadDivide := KeyCode.(49)
ScrollLock := KeyCode.(302) KeypadMultiply := KeyCode.(50)
KeypadMinus := KeyCode.(51)
KeypadPlus := KeyCode.(52)
KeypadEnter := KeyCode.(53)
KeypadEquals := KeyCode.(54)
RightShift := KeyCode.(303) Delete := KeyCode.(55)
LeftShift := KeyCode.(304) /* Locking Keys */
NumLock := KeyCode.(56)
RightControl := KeyCode.(305) CapsLock := KeyCode.(57)
LeftControl := KeyCode.(306) ScrollLock := KeyCode.(58)
RightAlt := KeyCode.(307)
LeftAlt := KeyCode.(308)
RightMeta := KeyCode.(309)
LeftMeta := KeyCode.(310)
/* Left "Windows" key */
LeftSuper := KeyCode.(311)
/* Right "Windows" key */
RightSuper := KeyCode.(312)
/* "Alt Gr" key */ /* "Alt Gr" key */
Mode := KeyCode.(313) Mode := KeyCode.(59)
/* Multi-key compose key */ /* Multi-key compose key */
Compose := KeyCode.(314) Compose := KeyCode.(60)
LeftAlt := KeyCode.(61)
LeftControl := KeyCode.(62)
LeftMeta := KeyCode.(63)
LeftShift := KeyCode.(64)
/* Left "Windows" key */
LeftSuper := KeyCode.(65)
RightAlt := KeyCode.(66)
RightControl := KeyCode.(67)
RightMeta := KeyCode.(68)
RightShift := KeyCode.(69)
/* Right "Windows" key */
RightSuper := KeyCode.(70)
/*
This block of any triggers on any press of any of the keys.
Typically this is the event to care about.
*/
AnyNumber0 := KeyCode.(71)
AnyNumber1 := KeyCode.(72)
AnyNumber2 := KeyCode.(73)
AnyNumber3 := KeyCode.(74)
AnyNumber4 := KeyCode.(75)
AnyNumber5 := KeyCode.(76)
AnyNumber6 := KeyCode.(77)
AnyNumber7 := KeyCode.(78)
AnyNumber8 := KeyCode.(79)
AnyNumber9 := KeyCode.(80)
AnyAlt := KeyCode.(81)
AnyControl := KeyCode.(82)
AnyMeta := KeyCode.(83)
AnyShift := KeyCode.(84)
/* Any "Windows" key */
AnySuper := KeyCode.(85)

View file

@ -1,22 +1,25 @@
keycodes := @use("keycodes.hb"); stn := @use("../../stn/src/lib.hb");
.{KeyCode} := keycodes .{log, buffer, memory} := stn
keycodes := @use("keycodes.hb")
MouseEvent := struct { events := @use("events.hb");
x_change: u8, .{KeyEvent, MouseEvent} := events
y_change: u8,
left: u8, recieve_key_event := fn(): ?KeyEvent {
middle: u8, return null
right: u8,
} }
KeyEvent := struct { recieve_mouse_event := fn(): ?MouseEvent {
// 0 if down mevent := MouseEvent.(0, 0, false, false, false)
// 1 if up
up: u8,
// 0 if not just triggered
// 1 if just triggered
just_triggered: u8,
key: KeyCode,
}
GamepadEvent := struct {} buf_id := buffer.search("PS/2 Mouse\0")
// Read out of the Mouse buffer here
buffer.recv(MouseEvent, buf_id, @bitcast(&mevent))
if mevent.x_change != 0 | mevent.y_change != 0 | mevent.left | mevent.middle | mevent.right {
return mevent
}
return null
}

View file

@ -0,0 +1,30 @@
# Images
- General over image format
- Support formats:
- PNG
- Animation
# API
- Colour operations:
- Alpha Composite
- Invert
- Surface Operations:
- FlipH
- Resize
- Wrap the colour operations
- Tile
- Gradient overlay
- Draw operations:
- Curve raster algorithm
- VGA font fast blit
- Polygon
- Rounded rects
# Backend
- SVGA Driver
- Support whatever vulkan stuff able is cooking
# Bits and bobs on the table
- Funny 3D Renderer
- stn.memory.swap & kernel message
- Make memory.{copy, set} smart

View file

@ -0,0 +1,49 @@
.{Color, Surface, new_surface, put_surface} := @use("../lib.hb");
.{log, memory} := @use("../../../stn/src/lib.hb")
BitmapFileHeader := packed struct {
magic: u16,
size: u32,
reserved_1: u16,
reserved_2: u16,
offset: u32,
}
BitmapInfoHeader := packed struct {
size: u32,
width: i32,
height: i32,
planes: u16,
bits: u16,
compression: u32,
image_size: u32,
x_resolution: i32,
y_resolution: i32,
n_colours: u32,
important_colours: u32,
}
BitmapColorHeader := packed struct {
red_mask: u32,
green_mask: u32,
blue_mask: u32,
alpha_mask: u32,
color_space_type: u32,
unused: u32,
}
from := fn(bmp: ^u8): ?Surface {
file_header := @as(^BitmapFileHeader, @bitcast(bmp))
info_header := @as(^BitmapInfoHeader, @bitcast(bmp + @sizeof(BitmapFileHeader)))
if file_header.magic != 0x4D42 | info_header.width == 0 | info_header.height == 0 {
log.error("Invalid BMP image.\0")
return null
}
lhs := Surface.(@bitcast(bmp + file_header.offset), info_header.width, info_header.height)
rhs := new_surface(info_header.width, info_header.height)
put_surface(rhs, lhs, .(0, 0), true)
return rhs
}

View file

@ -0,0 +1,31 @@
.{log} := @use("../../../stn/src/lib.hb");
.{Surface} := @use("../lib.hb")
bmp := @use("bmp.hb")
qoi := @use("qoi.hb")
$BMP := 0x4D42
$QOI := 0x66696F71
get_format := fn(file: ^u8): ?uint {
if *@as(^u16, @bitcast(file)) == BMP {
return BMP
} else if *@as(^u32, @bitcast(file)) == QOI {
return QOI
} else {
return null
}
}
from := fn(file: ^u8): ?Surface {
format := get_format(file)
if format == null {
log.error("Could not detect image format.\0")
return null
} else if format == BMP {
return bmp.from(file)
} else if format == QOI {
return qoi.from(file)
}
return null
}

View file

@ -0,0 +1,101 @@
.{Color, Surface, new_surface} := @use("../lib.hb");
.{log, memory} := @use("../../../stn/src/lib.hb")
/* source:
https://github.com/phoboslab/qoi/blob/master/qoi.h */
$QOI_SRGB := 0
$QOI_LINEAR := 1
$QOI_OP_INDEX := 0x0
$QOI_OP_DIFF := 0x40
$QOI_OP_LUMA := 0x80
$QOI_OP_RUN := 0xC0
$QOI_OP_RGB := 0xFE
$QOI_OP_RGBA := 0xFF
$QOI_MASK_2 := 0xC0
QOI_COLOR_HASH := fn(c: Color): u8 {
return (c.r * 3 + c.g * 5 + c.b * 7 + c.a * 11) % 64
}
$QOI_MAGIC := 0x716F6966
$QOI_PIXELS_MAX := 400000000
QuiteOkayHeader := packed struct {
magic: u32,
width: u32,
height: u32,
channels: u8,
colorspace: u8,
}
be_to_le := fn(big: u32): u32 {
return big >> 24 | big >> 8 & 0xFF00 | big << 8 & 0xFF0000 | big << 24
}
from := fn(qoi: ^u8): ?Surface {
header := @as(^QuiteOkayHeader, @bitcast(qoi))
qoi += @sizeof(QuiteOkayHeader)
width := be_to_le(header.width)
height := be_to_le(header.height)
if be_to_le(header.magic) != QOI_MAGIC | width == 0 | height == 0 | header.channels < 3 | header.channels > 4 {
log.error("Invalid QOI image.\0")
return null
}
surface := new_surface(width, height)
index := @as([Color; 64], idk)
run := 0
px := Color.(0, 0, 0, 255)
px_pos := 0
total_pixels := width * height
loop if px_pos >= total_pixels break else {
if run > 0 {
run -= 1
} else {
b1 := *qoi
qoi += 1
if b1 == QOI_OP_RGB {
px.r = *qoi
px.g = *(qoi + 1)
px.b = *(qoi + 2)
qoi += 3
} else if b1 == QOI_OP_RGBA {
px.r = *qoi
px.g = *(qoi + 1)
px.b = *(qoi + 2)
px.a = *(qoi + 3)
qoi += 4
} else if (b1 & QOI_MASK_2) == QOI_OP_INDEX {
px = index[b1 & 0x3F]
} else if (b1 & QOI_MASK_2) == QOI_OP_DIFF {
px.r = px.r + (b1 >> 4 & 0x3) - 2 & 0xFF
px.g = px.g + (b1 >> 2 & 0x3) - 2 & 0xFF
px.b = px.b + (b1 & 0x3) - 2 & 0xFF
} else if (b1 & QOI_MASK_2) == QOI_OP_LUMA {
b2 := *qoi
vg := (b1 & 0x3F) - 32
px.r = px.r + vg - 8 + (b2 >> 4 & 0xF) & 0xFF
px.g = px.g + vg & 0xFF
px.b = px.b + vg - 8 + (b2 & 0xF) & 0xFF
qoi += 1
} else if (b1 & QOI_MASK_2) == QOI_OP_RUN {
run = b1 & 0x3F
}
index[@inline(QOI_COLOR_HASH, px)] = px
};
*(surface.buf + px_pos) = px
px_pos += 1
}
return surface
}

View file

@ -1,30 +1,38 @@
svga := @use("svga.hb")
software := @use("software.hb") software := @use("software.hb")
image := @use("image/lib.hb")
text := @use("text.hb")
// default mode // default mode
mode := software mode := software
init := mode.init init := mode.init
doublebuffer := mode.doublebuffer doublebuffer := mode.doublebuffer
Surface := mode.Surface
new_surface := mode.new_surface
surface_from_ptr := mode.surface_from_ptr
clone_surface := mode.clone_surface
free_surface := mode.free_surface
index := mode.index
indexptr := mode.indexptr
// Colours // Colours
Color := mode.Color Color := packed struct {b: u8, g: u8, r: u8, a: u8}
white := mode.white $white := Color.(255, 255, 255, 255)
black := mode.black $black := Color.(0, 0, 0, 255)
gray := mode.gray $gray := Color.(127, 127, 127, 255)
red := mode.red $red := Color.(0, 0, 205, 255)
green := mode.green $green := Color.(0, 205, 0, 255)
yellow := mode.yellow $yellow := Color.(0, 205, 205, 255)
blue := mode.blue $blue := Color.(205, 0, 0, 255)
magenta := mode.magenta $magenta := Color.(205, 0, 205, 255)
cyan := mode.cyan $cyan := Color.(205, 205, 0, 255)
light_gray := mode.light_gray $light_gray := Color.(229, 229, 229, 255)
light_red := mode.light_red $light_red := Color.(0, 0, 255, 255)
light_green := mode.light_green $light_green := Color.(0, 255, 0, 255)
light_yellow := mode.light_yellow $light_yellow := Color.(0, 255, 255, 255)
light_blue := mode.light_blue $light_blue := Color.(255, 0, 0, 255)
light_magenta := mode.light_magenta $light_magenta := Color.(255, 0, 255, 255)
light_cyan := mode.light_cyan $light_cyan := Color.(255, 255, 0, 255)
// Drawing // Drawing
put_pixel := mode.put_pixel put_pixel := mode.put_pixel
@ -35,19 +43,12 @@ put_line := mode.put_line
put_vline := mode.put_vline put_vline := mode.put_vline
put_hline := mode.put_hline put_hline := mode.put_hline
clear := mode.clear clear := mode.clear
put_img := mode.put_img put_surface := mode.put_surface
put_text := mode.put_text
// thanks peony for these three!
put_trirect := mode.put_trirect
put_vline := mode.put_vline
put_hline := mode.put_hline
// Display // Display
width := mode.width
height := mode.height
dimensions := mode.dimensions
set_height := mode.set_height
set_width := mode.set_width
set_dimensions := mode.set_dimensions
sync := mode.sync sync := mode.sync
// Trash Image
Image := struct {
start: ^Color,
end: ^Color,
}

View file

@ -1,220 +1,118 @@
.{math, memory} := @use("../../stn/src/lib.hb"); .{math, memory, dt} := @use("../../stn/src/lib.hb");
.{dt_get} := @use("../../dt_api/src/lib.hb"); .{Color, text} := @use("lib.hb");
.{Image} := @use("lib.hb"); .{get_glyph, get_glyph_unicode, Font, UNC_TABLE_SIZE} := text;
.{Vec2} := math .{Vec2} := math
Color := struct {b: u8, g: u8, r: u8, a: u8} // safety: don't use before init() or you will get a memory access violation
white := Color.(255, 255, 255, 255) framebuffer := memory.dangling(Color)
black := Color.(0, 0, 0, 255)
gray := Color.(127, 127, 127, 255)
red := Color.(0, 0, 205, 255)
green := Color.(0, 205, 0, 255)
yellow := Color.(0, 205, 205, 255)
blue := Color.(205, 0, 0, 255)
magenta := Color.(205, 0, 205, 255)
cyan := Color.(205, 205, 0, 255)
light_gray := Color.(229, 229, 229, 255)
light_red := Color.(0, 0, 255, 255)
light_green := Color.(0, 255, 0, 255)
light_yellow := Color.(0, 255, 255, 255)
light_blue := Color.(255, 0, 0, 255)
light_magenta := Color.(255, 0, 255, 255)
light_cyan := Color.(255, 255, 0, 255)
// might not work for some resolutions, but needs to be comptime because... Surface := struct {
copy_pixels := 0xC000 >> 2
ctx := @as(Context, idk)
// some of these are redudant holdovers from fb_driver
// will keep them for future work if necessary
Context := struct {
fb: ^Color,
bb: ^Color,
buf: ^Color, buf: ^Color,
width: int, width: uint,
height: int, height: uint,
partitions: int,
pixels: int,
bb_pages: int,
double_buffer: bool,
} }
init := fn(): void { new_surface := fn(width: uint, height: uint): Surface {
width := dt_get("framebuffer/fb0/width\0") return .(
height := dt_get("framebuffer/fb0/height\0") @inline(memory.alloc, Color, width * height),
pixels := width * height
bytes := pixels << 2
partitions := pixels / copy_pixels
pages := 1 + bytes >> 12
back_buffer := create_back_buffer(pages)
ctx = Context.{
fb: dt_get("framebuffer/fb0/ptr\0"),
bb: back_buffer,
buf: back_buffer,
width, width,
height, height,
partitions, )
pixels,
bb_pages: pages,
double_buffer: true,
}
return
} }
doublebuffer := fn(enable: bool): void { clone_surface := fn(surface: ^Surface): Surface {
if enable { new := new_surface(surface.width, surface.height)
ctx.buf = ctx.bb @inline(memory.copy, Color, surface.buf, new.buf, @intcast(surface.width * surface.height))
return new
}
init := fn(doublebuffer: bool): Surface {
framebuffer = dt.get(^Color, "framebuffer/fb0/ptr\0")
width := dt.get(uint, "framebuffer/fb0/width\0")
height := dt.get(uint, "framebuffer/fb0/height\0")
if doublebuffer {
return new_surface(width, height)
} else { } else {
ctx.buf = ctx.fb return .(framebuffer, width, height)
} }
ctx.double_buffer = enable }
clear := fn(surface: Surface, color: Color): void {
return @inline(memory.set, Color, &color, surface.buf, surface.width * surface.height)
}
sync := fn(surface: Surface): void {
if surface.buf == framebuffer {
return
}
return @inline(memory.copy, Color, surface.buf, framebuffer, @bitcast(surface.width * surface.height))
}
index := fn(surface: Surface, x: uint, y: uint): uint {
return x + surface.width * y
}
indexptr := fn(surface: Surface, x: uint, y: uint): ^Color {
return surface.buf + @inline(index, surface, x, y)
}
put_pixel := fn(surface: Surface, pos: Vec2(uint), color: Color): void {
*@inline(indexptr, surface, pos.x, pos.y) = color
return return
} }
create_back_buffer := fn(pages: int): ^Color { put_filled_rect := fn(surface: Surface, pos: Vec2(uint), tr: Vec2(uint), color: Color): void {
if pages <= 0xFF { top_start_idx := @inline(indexptr, surface, pos.x, pos.y)
return @bitcast(@inline(memory.request_page, pages)) bottom_start_idx := @inline(indexptr, surface, pos.x, pos.y + tr.y - 1)
} rows_to_fill := tr.y
ptr := @inline(memory.request_page, 255)
remaining := pages - 0xFF
loop if remaining <= 0 break else {
if remaining < 0xFF {
memory.request_page(remaining)
} else {
memory.request_page(0xFF)
}
remaining -= 0xFF
}
return @bitcast(ptr)
}
clear := fn(color: Color): void { loop if rows_to_fill <= 1 break else {
cursor := ctx.buf @inline(memory.set, Color, &color, top_start_idx, tr.x)
boundary := cursor + 512 @inline(memory.set, Color, &color, bottom_start_idx, tr.x)
loop if cursor == boundary break else {
*cursor = color
cursor += 1
}
boundary += 512 * 7
loop if cursor == boundary break else {
*@as(^[Color; 512], @bitcast(cursor)) = *@as(^[Color; 512], @bitcast(ctx.buf))
cursor += 512
}
boundary += copy_pixels - 4096
loop if cursor == boundary break else {
*@as(^[Color; 4096], @bitcast(cursor)) = *@as(^[Color; 4096], @bitcast(ctx.buf))
cursor += 4096
}
boundary += (ctx.partitions - 1) * copy_pixels
loop if cursor == boundary break else {
*@as(^[Color; copy_pixels], @bitcast(cursor)) = *@as(^[Color; copy_pixels], @bitcast(ctx.buf))
cursor += @sizeof([u8; copy_pixels])
}
return
}
sync := fn(): void { top_start_idx += surface.width
if ctx.double_buffer { bottom_start_idx -= surface.width
bb := ctx.buf rows_to_fill -= 2
fb := ctx.fb
boundary := bb + ctx.pixels
loop if bb >= boundary break else {
*@as(^[Color; copy_pixels], @bitcast(fb)) = *@as(^[Color; copy_pixels], @bitcast(bb))
bb += copy_pixels
fb += copy_pixels
}
}
return
}
width := fn(): int {
return ctx.width
}
height := fn(): int {
return ctx.height
}
screenidx := fn(x: int, y: int): int {
/*if x < 0 || y < 0 || x >= ctx.width || y >= ctx.height {
return -1
}*/
return x + ctx.width * y
}
put_pixel := fn(pos: Vec2(int), color: Color): void {
*(ctx.buf + @inline(screenidx, pos.x, pos.y)) = color
return
}
put_filled_rect := fn(pos: Vec2(int), tr: Vec2(int), color: Color): void {
x := pos.x
y := pos.y
end := pos + tr
loop if x == end.x break else {
loop if y == end.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color
y += 1
}
x += 1
y = pos.y
}
return
}
put_rect := fn(pos: Vec2(int), tr: Vec2(int), color: Color): void {
x := pos.x
y := pos.y
end := pos + tr
loop if y == end.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color;
*(ctx.buf + @inline(screenidx, x + tr.x, y)) = color
y += 1
}
y = pos.y
loop if x == end.x break else {
*(ctx.buf + @inline(screenidx, x, y)) = color;
*(ctx.buf + @inline(screenidx, x, y + tr.y)) = color
x += 1
}
return
}
put_trirect := fn(pos: Vec2(int), size: Vec2(int), color0: Color, color1: Color): void {
step := Vec2(int).(1, 1)
if size.x < 0 {
step.x = -1
}
if size.y < 0 {
step.y = size.y / size.x
} }
start_y := pos.y if rows_to_fill == 1 {
target := pos + size @inline(memory.set, Color, &color, top_start_idx, tr.x)
loop if pos.x == target.x break else {
put_vline(pos.x, pos.y, target.y, color0)
put_vline(pos.x, pos.y, start_y, color1)
pos += step
} }
return return
} }
put_line_low := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { put_rect := fn(surface: Surface, pos: Vec2(uint), tr: Vec2(uint), color: Color): void {
dx := p1.x - p0.x start_idx := @inline(indexptr, surface, pos.x, pos.y)
dy := p1.y - p0.y end_idx := @inline(indexptr, surface, pos.x, pos.y + tr.y)
right_start_idx := @inline(indexptr, surface, pos.x + tr.x, pos.y)
loop if start_idx > end_idx break else {
*start_idx = color;
*right_start_idx = color
start_idx += surface.width
right_start_idx += surface.width
}
@inline(memory.set, Color, &color, @inline(indexptr, surface, pos.x, pos.y), @bitcast(tr.x + 1))
@inline(memory.set, Color, &color, @inline(indexptr, surface, pos.x, pos.y + tr.y), @bitcast(tr.x + 1))
return
}
put_line_low := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
dx := @as(int, @bitcast(p1.x - p0.x))
dy := @as(int, @bitcast(p1.y - p0.y))
yi := 1 yi := 1
if dy < 0 { if dy < 0 {
yi = -1 yi = -1
dy = -dy dy = -dy
} }
D := 2 * dy - dx D := @as(int, 2) * dy - dx
y := p0.y y := p0.y
x := p0.x x := p0.x
loop if x == p1.x break else { loop if x == p1.x break else {
*(ctx.buf + @inline(screenidx, x, y)) = color *@inline(indexptr, surface, x, y) = color
if D > 0 { if D > 0 {
y += yi y += yi
D += 2 * (dy - dx) D += 2 * (dy - dx)
@ -226,19 +124,19 @@ put_line_low := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void {
return return
} }
put_line_high := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { put_line_high := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
dx := p1.x - p0.x dx := @as(int, @bitcast(p1.x - p0.x))
dy := p1.y - p0.y dy := @as(int, @bitcast(p1.y - p0.y))
xi := 1 xi := 1
if dy < 0 { if dy < 0 {
xi = -1 xi = -1
dx = -dx dx = -dx
} }
D := 2 * dx - dy D := @as(int, 2) * dx - dy
x := p0.x x := p0.x
y := p0.y y := p0.y
loop if y == p1.y break else { loop if y == p1.y break else {
*(ctx.buf + @inline(screenidx, x, y)) = color *@inline(indexptr, surface, x, y) = color
if D > 0 { if D > 0 {
x += xi x += xi
D += 2 * (dx - dy) D += 2 * (dx - dy)
@ -250,24 +148,83 @@ put_line_high := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void {
return return
} }
put_line := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void { put_line := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
if math.abs(int, p1.y - p0.y) < math.abs(int, p1.x - p0.x) { if math.abs(uint, p1.y - p0.y) < math.abs(uint, p1.x - p0.x) {
if p0.x > p1.x { if p0.x > p1.x {
@inline(put_line_low, p1, p0, color) @inline(put_line_low, surface, p1, p0, color)
} else { } else {
@inline(put_line_low, p0, p1, color) @inline(put_line_low, surface, p0, p1, color)
} }
} else { } else {
if p0.y > p1.y { if p0.y > p1.y {
@inline(put_line_high, p1, p0, color) @inline(put_line_high, surface, p1, p0, color)
} else { } else {
@inline(put_line_high, p0, p1, color) @inline(put_line_high, surface, p0, p1, color)
} }
} }
return return
} }
put_vline := fn(x: int, y0: int, y1: int, color: Color): void { put_surface := fn(surface: Surface, top: Surface, pos: Vec2(uint), flip_v: bool): void {
src_top_cursor := top.buf
src_bottom_cursor := top.buf + top.width * (top.height - 1)
dst_top_idx := @inline(indexptr, surface, pos.x, pos.y)
dst_bottom_idx := @inline(indexptr, surface, pos.x, pos.y + top.height - 1)
dst_increment := surface.width
if flip_v {
dst_increment = -dst_increment
tmp := dst_top_idx
dst_top_idx = dst_bottom_idx
dst_bottom_idx = tmp
}
rows_to_copy := top.height
loop if rows_to_copy <= 1 break else {
@inline(memory.copy, Color, src_top_cursor, dst_top_idx, top.width)
@inline(memory.copy, Color, src_bottom_cursor, dst_bottom_idx, top.width)
dst_top_idx += dst_increment
dst_bottom_idx -= dst_increment
src_top_cursor += top.width
src_bottom_cursor -= top.width
rows_to_copy -= 2
}
if rows_to_copy == 1 {
@inline(memory.copy, Color, src_top_cursor, dst_top_idx, top.width)
}
return
}
// peony-made
put_trirect := fn(surface: Surface, pos: Vec2(uint), size: Vec2(int), color0: Color, color1: Color): void {
step := Vec2(int).(1, 1)
if size.x < 0 {
step.x = -1
}
if size.y < 0 {
step.y /= @bitcast(size.x)
}
start_y := pos.y
target := pos + @bitcast(size)
loop if pos.x == target.x break else {
@inline(put_vline, surface, pos.x, pos.y, target.y, color0)
@inline(put_vline, surface, pos.x, pos.y, start_y, color1)
pos += @bitcast(step)
}
return
}
// peony-made
put_vline := fn(surface: Surface, x: uint, y0: uint, y1: uint, color: Color): void {
if y1 < y0 { if y1 < y0 {
tmp := y0 tmp := y0
y0 = y1 y0 = y1
@ -276,45 +233,157 @@ put_vline := fn(x: int, y0: int, y1: int, color: Color): void {
y := y0 y := y0
loop if y == y1 break else { loop if y == y1 break else {
*(ctx.buf + @inline(screenidx, x, y)) = color *@inline(indexptr, surface, x, y) = color
y += 1 y += 1
} }
return return
} }
put_hline := fn(y: int, x0: int, x1: int, color: Color): void { // peony-made
put_hline := fn(surface: Surface, y: uint, x0: uint, x1: uint, color: Color): void {
if x1 < x0 { if x1 < x0 {
tmp := x0 tmp := x0
x0 = x1 x0 = x1
x1 = tmp x1 = tmp
} }
x := x0 @inline(memory.set, Color, &color, @inline(indexptr, surface, x0, y), @bitcast(x1 - x0 - 1))
loop if x == x1 break else { return
*(ctx.buf + @inline(screenidx, x, y)) = color }
x += 1 utf8_len_table := [u8].(0, 0, 2, 3)
put_text := fn(surface: Surface, font: Font, pos: Vec2(uint), color: Color, str: ^u8): void {
cursor := Vec2(uint).(pos.x, pos.y)
max_y := surface.height - font.height
next_line_y := font.height + font.line_gap
char_advance := font.width + font.char_gap
surface_width := surface.width
loop if *str == 0 break else {
if cursor.y > max_y break
glyph_data := @as(^u8, idk)
code_point := @as(uint, 0)
if (*str & 0x80) == 0 {
if *str == 10 {
cursor.x = pos.x
cursor.y += next_line_y
str += 1
continue
}
if font.unicode == null {
if *str > font.num_glyphs {
str += 1
continue
}
glyph_data = @inline(get_glyph, font, *str)
} else {
if *str < UNC_TABLE_SIZE {
glyph_index := *(font.unicode + *str)
if glyph_index == 0xFFFF {
str += 1
continue
}
glyph_data = font.data + glyph_index * font.bytes_per_glyph
} else {
str += 1
continue
}
}
str += 1
} else if font.unicode != null {
first_byte := *str
num_bytes := @as(uint, 0)
num_bytes = utf8_len_table[first_byte >> 5 & 0x3]
if num_bytes == 0 {
str += 1
continue
}
code_point = first_byte & (0x7F >> num_bytes | 0x1F)
valid_sequence := true
bytes_processed := 1
loop if bytes_processed >= num_bytes break else {
str += 1
if *str == 0 | (*str & 0xC0) != 0x80 {
valid_sequence = false
}
if valid_sequence == false {
break
}
code_point = code_point << 6 | *str & 0x3F
bytes_processed += 1
}
if valid_sequence == false {
str += 1
continue
}
str += 1
if code_point == 10 {
cursor.x = pos.x
cursor.y += next_line_y
continue
}
if code_point >= UNC_TABLE_SIZE {
continue
}
glyph_index := *(font.unicode + code_point)
if glyph_index == 0xFFFF {
continue
}
glyph_data = font.data + glyph_index * font.bytes_per_glyph
}
if cursor.x + font.width >= surface_width {
cursor.x = pos.x
cursor.y += next_line_y
}
dest := @inline(indexptr, surface, cursor.x, cursor.y)
rows := font.height
loop if rows == 0 break else {
byte := *glyph_data
pixel_dest := dest
mask := @as(u8, 0x80)
bits := font.width
loop if bits == 0 break else {
if (byte & mask) != 0 {
*pixel_dest = color
}
pixel_dest += 1
mask >>= 1
if mask == 0 & bits > 0 {
glyph_data += 1
byte = *glyph_data
mask = 0x80
}
bits -= 1
}
if mask != 0x80 {
glyph_data += 1
}
dest += surface_width
rows -= 1
}
cursor.x += char_advance
} }
return return
} }
set_height := fn(new: int): void {
return
}
set_width := fn(new: int): void {
return
}
dimensions := fn(): Vec2(int) {
return .(ctx.width, ctx.height)
}
set_dimensions := fn(new: Vec2(int)): void {
return
}
put_img := fn(img: Image, pos: Vec2(int)): void {
return
}

View file

@ -1,84 +0,0 @@
.{Vec2, Image} := @use("lib.hb")
// .{pci, memory, string, log} := @use("../../stn/src/lib.hb");
Color := struct {b: u8, g: u8, r: u8, a: u8}
white := Color.(255, 255, 255, 255)
black := Color.(0, 0, 0, 255)
gray := Color.(127, 127, 127, 255)
red := Color.(0, 0, 205, 255)
green := Color.(0, 205, 0, 255)
yellow := Color.(0, 205, 205, 255)
blue := Color.(205, 0, 0, 255)
magenta := Color.(205, 0, 205, 255)
cyan := Color.(205, 205, 0, 255)
light_gray := Color.(229, 229, 229, 255)
light_red := Color.(0, 0, 255, 255)
light_green := Color.(0, 255, 0, 255)
light_yellow := Color.(0, 255, 255, 255)
light_blue := Color.(255, 0, 0, 255)
light_magenta := Color.(255, 0, 255, 255)
light_cyan := Color.(255, 255, 0, 255)
clear := fn(color: Color): void {
return
}
width := fn(): int {
return 0
}
height := fn(): int {
return 0
}
dimensions := fn(): Vec2(int) {
return .(0, 0)
}
put_pixel := fn(position: Vec2(int), color: Color): void {
return
}
put_filled_rect := fn(pos: Vec2(int), tr: Vec2(int), color: Color): void {
return
}
put_rect := fn(pos: Vec2(int), tr: Vec2(int), color: Color): void {
return
}
put_line_low := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void {
return
}
// do not use, use line() instead
put_line_high := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void {
return
}
put_line := fn(p0: Vec2(int), p1: Vec2(int), color: Color): void {
return
}
set_height := fn(new: int): void {
return
}
set_width := fn(new: int): void {
return
}
set_dimensions := fn(new: Vec2(int)): void {
return
}
sync := fn(): void {
return
}
init := fn(): void {
return
}
put_img := fn(img: Image, pos: Vec2(int)): void {
return
}

View file

@ -0,0 +1,162 @@
.{log, memory} := @use("../../stn/src/lib.hb")
PSF1Header := packed struct {
magic: u16,
font_mode: u8,
character_size: u8,
}
PSF2Header := packed struct {
magic: u32,
version: u32,
header_size: u32,
flags: u32,
num_glyph: u32,
bytes_per_glyph: u32,
height: u32,
width: u32,
}
Font := struct {
data: ^u8,
width: uint,
height: uint,
num_glyphs: uint,
bytes_per_glyph: uint,
line_gap: uint,
char_gap: uint,
unicode: ?^u16,
}
font_from_psf1 := fn(psf: ^u8): ?Font {
header := @as(^PSF1Header, @bitcast(psf))
if header.magic != 0x436 {
log.error("failed to load psf font: not a psf1 font, idiot\0")
return null
}
psf += @sizeof(PSF1Header)
return .(
psf,
8,
header.character_size,
256,
header.character_size,
0,
0,
null,
)
}
font_from_psf2 := fn(psf: ^u8, unicode: bool): ?Font {
header := @as(^PSF2Header, @bitcast(psf))
if header.magic != 0x864AB572 {
log.error("failed to load psf font: not a psf2 font, idiot\0")
return null
}
psf += header.header_size
font := Font.(
psf,
header.width,
header.height,
header.num_glyph,
header.bytes_per_glyph,
0,
0,
null,
)
if (header.flags & 1) != 0 & unicode {
init_unicode(&font)
}
return font
}
get_glyph := fn(font: Font, index: u8): ^u8 {
return font.data + @as(uint, index) * font.bytes_per_glyph
}
UNC_TABLE_SIZE := 1 << 16
init_unicode := fn(font: ^Font): void {
font.unicode = memory.alloc(u16, UNC_TABLE_SIZE)
@inline(memory.set, u16, &0xFFFF, font.unicode, UNC_TABLE_SIZE)
table := font.data + font.num_glyphs * font.bytes_per_glyph
curr_glyph := @as(u16, 0)
loop if curr_glyph >= font.num_glyphs break else {
loop {
byte := *table
table += 1
if byte == 0xFF break
if byte == 0xFE {
continue
}
unicode := @as(uint, 0)
bytes_to_read := @as(uint, 1)
if (byte & 0x80) == 0 {
unicode = byte
} else if (byte & 0xE0) == 0xC0 {
unicode = byte & 0x1F
bytes_to_read = 2
} else if (byte & 0xF0) == 0xE0 {
unicode = byte & 0xF
bytes_to_read = 3
} else if (byte & 0xF8) == 0xF0 {
unicode = byte & 0x7
bytes_to_read = 4
} else {
continue
}
valid := true
loop if bytes_to_read <= 1 break else {
next_byte := *table
if (next_byte & 0xC0) != 0x80 {
valid = false
}
if valid == false {
break
}
unicode = unicode << 6 | next_byte & 0x3F
table += 1
bytes_to_read -= 1
}
if valid == false continue
if bytes_to_read == 4 {
if unicode < 0x10000 | unicode > 0x10FFFF continue
if unicode <= 0xFFFF {
if unicode < UNC_TABLE_SIZE {
*(@unwrap(font.unicode) + unicode) = curr_glyph
}
} else {
unicode -= 0x10000
high_surrogate := 0xD800 | unicode >> 10 & 0x3FF
low_surrogate := 0xDC00 | unicode & 0x3FF
if high_surrogate < UNC_TABLE_SIZE {
*(@unwrap(font.unicode) + high_surrogate) = curr_glyph
}
if low_surrogate < UNC_TABLE_SIZE {
*(@unwrap(font.unicode) + low_surrogate) = curr_glyph
}
}
} else {
if unicode < UNC_TABLE_SIZE {
*(@unwrap(font.unicode) + unicode) = curr_glyph
}
}
}
curr_glyph += 1
}
}

View file

@ -1,22 +1,27 @@
string := @use("string.hb") string := @use("string.hb")
recv := fn(buffer_id: int, memory_map_location: ^u8, length: int): ^u8 { recv := fn($Expr: type, buffer_id: int, memory_map_location: ^u8): void {
return @eca(4, buffer_id, memory_map_location, @sizeof(Expr))
}
write := fn($Expr: type, msg: ^Expr, buffer_id: int): void {
return @eca(3, buffer_id, msg, @sizeof(Expr))
}
recv_length := fn(buffer_id: int, memory_map_location: ^u8, length: int): void {
return @eca(4, buffer_id, memory_map_location, length) return @eca(4, buffer_id, memory_map_location, length)
} }
write := fn(msg: ^u8, buffer_id: int, length: int): void { write_length := fn(msg: ^u8, buffer_id: int, length: int): void {
return @eca(3, buffer_id, msg, length) return @eca(3, buffer_id, msg, length)
} }
BufferMsg := packed struct {operation: u8, msg: ^u8, msg_len: uint}
create := fn(msg: ^u8): int { create := fn(msg: ^u8): int {
msg_length := @inline(string.length, msg); return @eca(3, 0, BufferMsg.(0, msg, @inline(string.length, msg)), @sizeof(BufferMsg))
*msg = 0
return @eca(3, 0, msg, msg_length)
} }
search := fn(msg: ^u8): int { search := fn(msg: ^u8): int {
msg_length := @inline(string.length, msg); return @eca(3, 0, BufferMsg.(3, msg, @inline(string.length, msg)), @sizeof(BufferMsg))
*msg = 3
return @eca(3, 0, msg, msg_length)
} }

View file

@ -0,0 +1,5 @@
.{string} := @use("../../stn/src/lib.hb")
get := fn($Expr: type, query: ^u8): Expr {
return @eca(3, 5, query, @inline(string.length, query))
}

View file

@ -1,5 +1,4 @@
acs := @use("acs.hb") acs := @use("acs.hb")
string := @use("string.hb") string := @use("string.hb")
log := @use("log.hb") log := @use("log.hb")
memory := @use("memory.hb") memory := @use("memory.hb")
@ -7,3 +6,14 @@ buffer := @use("buffer.hb")
math := @use("math.hb") math := @use("math.hb")
random := @use("random.hb") random := @use("random.hb")
file := @use("file_io.hb") file := @use("file_io.hb")
dt := @use("dt.hb")
panic := fn(message: ?^u8): never {
log.error("Error: Panic Called, Message:\0")
if message == null {
log.error("None\0")
} else {
log.error(message)
}
die
}

View file

@ -1,15 +1,13 @@
string := @use("string.hb") string := @use("string.hb")
buffer := @use("buffer.hb")
log := fn(message: ^u8, level: u8): void { LogMsg := packed struct {level: u8, string: ^u8, strlen: uint}
message_length := @inline(string.length, message);
*(message + message_length) = level
return @eca(3, 1, message, message_length + 1) log := fn(level: u8, message: ^u8): void {
return @eca(3, 1, LogMsg.(level, message, @inline(string.length, message)), @sizeof(LogMsg))
} }
error := fn(message: ^u8): void return log(message, 0) error := fn(message: ^u8): void return @inline(log, 0, message)
warn := fn(message: ^u8): void return log(message, 1) warn := fn(message: ^u8): void return @inline(log, 1, message)
info := fn(message: ^u8): void return log(message, 2) info := fn(message: ^u8): void return @inline(log, 2, message)
debug := fn(message: ^u8): void return log(message, 3) debug := fn(message: ^u8): void return @inline(log, 3, message)
trace := fn(message: ^u8): void return log(message, 4) trace := fn(message: ^u8): void return @inline(log, 4, message)

File diff suppressed because one or more lines are too long

View file

@ -1,39 +1,71 @@
request_page := fn(page_count: u8): ^u8 { PAGE_SIZE := 4096
msg := "\{00}\{01}xxxxxxxx\0" MAX_ALLOC := 0xFF
msg_page_count := msg + 1; MAX_FREE := 0xFF
*msg_page_count = page_count
return @eca(3, 2, msg, 12) dangling := fn($Expr: type): ^Expr {
return @bitcast(@alignof(Expr))
} }
release_page := fn(ptr: ^u8, page_count: u8): void { calc_pages := fn($Expr: type, num: uint): uint {
msg := "\{01}\{00}xxxxxxxx\0" return 1 + @sizeof(Expr) * num / PAGE_SIZE
}
msg_page_count := msg + 1; alloc := fn($Expr: type, num: uint): ^Expr {
*msg_page_count = page_count pages := @inline(calc_pages, Expr, num)
if pages <= MAX_ALLOC {
return @bitcast(request_page(@intcast(pages)))
}
ptr := request_page(0xFF)
remaining := pages - MAX_ALLOC
loop if remaining < MAX_ALLOC break else {
_ = request_page(@intcast(MAX_ALLOC))
remaining -= MAX_ALLOC
}
_ = request_page(@intcast(remaining))
return @bitcast(ptr)
}
msg_ptr := @as(^^u8, @bitcast(msg + 2)); // ! stub
*msg_ptr = ptr free := fn($Expr: type, ptr: ^Expr, num: uint, nullify: bool): void {
return
}
return @eca(3, 2, msg, 12) RqPageMsg := packed struct {a: u8, count: u8}
request_page := fn(count: u8): ^u8 {
return @eca(3, 2, &RqPageMsg.(0, count), @sizeof(RqPageMsg))
}
RlPageMsg := packed struct {a: u8, count: u8, ptr: ^u8}
release_page := fn(ptr: ^u8, count: u8): void {
return @eca(3, 2, &RlPageMsg.(1, count, ptr), @sizeof(RlPageMsg))
} }
OutbMsg := packed struct {a: u8, b: u8, addr: u16, value: u8} OutbMsg := packed struct {a: u8, b: u8, addr: u16, value: u8}
InbMsg := packed struct {a: u8, b: u8, addr: u16}
OutlMsg := packed struct {a: u8, b: u8, addr: u16, value: u32}
InlMsg := packed struct {a: u8, b: u8, addr: u16}
outb := fn(addr: u16, value: u8): void { outb := fn(addr: u16, value: u8): void {
return @eca(3, 3, &OutbMsg.(1, 0, addr, value), @sizeof(OutbMsg)) return @eca(3, 3, &OutbMsg.(1, 0, addr, value), @sizeof(OutbMsg))
} }
InbMsg := packed struct {a: u8, b: u8, addr: u16}
inb := fn(addr: u16): u8 { inb := fn(addr: u16): u8 {
return @eca(3, 3, &InbMsg.(0, 0, addr), @sizeof(InbMsg)) return @eca(3, 3, &InbMsg.(0, 0, addr), @sizeof(InbMsg))
} }
OutlMsg := packed struct {a: u8, b: u8, addr: u16, value: u32}
outl := fn(addr: u16, value: u32): void { outl := fn(addr: u16, value: u32): void {
return @eca(3, 3, &OutlMsg.(1, 2, addr, value), @sizeof(OutlMsg)) return @eca(3, 3, &OutlMsg.(1, 2, addr, value), @sizeof(OutlMsg))
} }
InlMsg := packed struct {a: u8, b: u8, addr: u16}
inl := fn(addr: u16): u32 { inl := fn(addr: u16): u32 {
return @eca(3, 3, &InlMsg.(0, 2, addr), @sizeof(InlMsg)) return @eca(3, 3, &InlMsg.(0, 2, addr), @sizeof(InlMsg))
} }
CopyMsg := packed struct {a: u8, count: u32, src: ^u8, dest: ^u8}
copy := fn($Expr: type, src: ^Expr, dest: ^Expr, count: uint): void {
return @eca(3, 2, &CopyMsg.(4, @intcast(count * @sizeof(Expr)), @bitcast(src), @bitcast(dest)), @sizeof(CopyMsg))
}
SetMsg := packed struct {a: u8, count: u32, size: u32, src: ^u8, dest: ^u8}
set := fn($Expr: type, src: ^Expr, dest: ^Expr, count: uint): void {
return @eca(3, 2, &SetMsg.(5, @intcast(count), @intcast(@sizeof(Expr)), @bitcast(src), @bitcast(dest)), @sizeof(SetMsg))
}

View file

@ -1,7 +1,7 @@
any := fn($Expr: type): Expr { any := fn($Expr: type): Expr {
return @intcast(@eca(3, 4)) return *@eca(3, 4, &@as(Expr, idk), @sizeof(Expr))
} }
range := fn($Expr: type, min: Expr, max: Expr): Expr { range := fn($Expr: type, min: Expr, max: Expr): Expr {
return @eca(3, 4) % (max - min + 1) + min return @inline(any, Expr) % (max - min) + @intcast(1) + min
} }

View file

@ -1,42 +1,64 @@
length := fn(ptr: ^u8): int { length := fn(ptr: ^u8): uint {
len := 0 len := 0
loop if *(ptr + len) == 0 break else len += 1 loop if *(ptr + len) == 0 return len else len += 1
return len
} }
// WTFFF is wrong with display_int display_int := fn(num: int, p: ^u8, radix: uint): ^u8 {
display_int := fn(num: int, p: ^u8): ^u8 {
ptr := p ptr := p
negative := num < 0 negative := num < 0
if negative { if negative {
num = -num num = -num
} }
if radix == 2 {
*ptr = 48
ptr += 1;
*ptr = 98
ptr += 1
} else if radix == 16 {
*ptr = 48
ptr += 1;
*ptr = 120
ptr += 1
} else if radix == 8 {
*ptr = 48
ptr += 1;
*ptr = 111
ptr += 1
}
digits_start := ptr
if num == 0 { if num == 0 {
*ptr = 48 *ptr = 48
ptr += 1 ptr += 1
} else { } else {
loop if num == 0 break else { loop if num == 0 break else {
*ptr = num % 10 + 48 digit := num % @bitcast(radix)
if digit < 10 {
*ptr = @intcast(digit) + 48
} else {
*ptr = @intcast(digit) + 55
}
ptr += 1 ptr += 1
num /= 10 num /= @bitcast(radix)
} }
} }
if negative { if negative {
*ptr = 45 *ptr = 45
ptr += 1 ptr += 1
}; };
*ptr = 0 *ptr = 0
@inline(reverse, p)
@inline(reverse, digits_start)
return p return p
} }
reverse := fn(s: ^u8): void { reverse := fn(s: ^u8): void {
//reverse a string, don't remove digits
len := 0
loop if *(s + len) == 0 break else len += 1
i := 0 i := 0
j := len - 1 j := @inline(length, s) - 1
temp := 0 temp := @as(u8, 0)
loop if i >= j break else { loop if i >= j break else {
temp = *(s + i); temp = *(s + i);
*(s + i) = *(s + j); *(s + i) = *(s + j);
@ -46,3 +68,54 @@ reverse := fn(s: ^u8): void {
} }
return return
} }
equals := fn(lhs: ^u8, rhs: ^u8): bool {
if lhs == rhs {
return true
}
i := 0
loop if *(lhs + i) != *(rhs + i) {
return false
} else if *lhs == 0 {
return true
} else {
i += 1
}
}
contains := fn(haystack: ^u8, needle: ^u8): bool {
haystack_len := @inline(length, haystack)
needle_len := @inline(length, needle)
if needle_len == 0 {
return true
}
if haystack_len < needle_len {
return false
}
max_start := haystack_len - needle_len
pos := 0
loop if pos > max_start break else {
is_match := true
offset := 0
loop if offset >= needle_len break else {
if *(haystack + pos + offset) != *(needle + offset) {
is_match = false
}
if is_match == false {
break
}
offset += 1
}
if is_match {
return true
}
pos += 1
}
return false
}

View file

@ -1,14 +1,13 @@
dt_api := @use("../../../libraries/dt_api/src/lib.hb"); .{dt} := @use("../../../libraries/stn/src/lib.hb")
.{dt_get} := dt_api
main := fn(): int { main := fn(): void {
dt_api.dt_get("framebuffer/fb0/width\0") dt.get(void, "framebuffer/fb0/width\0")
dt_api.dt_get("cpu/cpu0/architecture\0") dt.get(void, "cpu/cpu0/architecture\0")
// Checking if the first detected serial port is memory mapped or port mapped // Checking if the first detected serial port is memory mapped or port mapped
// 0 -> memory mapped // 0 -> memory mapped
// 1 -> port mapped // 1 -> port mapped
dt_get("serial_ports/sp0/mapping\0") dt.get(void, "serial_ports/sp0/mapping\0")
return 0 return
} }

View file

@ -1,7 +1,7 @@
READ_ONLY := 0x1 READ_ONLY := @as(u32, 0x1)
HIDDEN := 0x2 HIDDEN := @as(u32, 0x2)
SYSTEM := 0x4 SYSTEM := @as(u32, 0x4)
VOLUME_ID := 0x8 VOLUME_ID := @as(u32, 0x8)
DIRECTORY := 0x10 DIRECTORY := @as(u32, 0x10)
ARCHIVE := 0x20 ARCHIVE := @as(u32, 0x20)
LFN := READ_ONLY | HIDDEN | SYSTEM | VOLUME_ID LFN := READ_ONLY | HIDDEN | SYSTEM | VOLUME_ID

View file

@ -9,8 +9,7 @@ OemIdent := struct {
} }
new_oem_ident := fn(major: int, minor: int): OemIdent { new_oem_ident := fn(major: int, minor: int): OemIdent {
ver := [u8].(0, 0, 0, 0, 0, 0, 0, 0) return .(.(0, 0, 0, 0, 0, 0, 0, 0), .(0, 0, 0, 0, 0, 0, 0, 0))
return OemIdent.(ver, ver)
} }
BiosParameterBlock := struct { BiosParameterBlock := struct {
@ -38,9 +37,7 @@ bpb_sanity_check := fn(bpb: BiosParameterBlock): int {
} }
new_bpb := fn(): BiosParameterBlock { new_bpb := fn(): BiosParameterBlock {
oem := new_oem_ident(0, 0) return .(VALID_JUMP_BYTES, new_oem_ident(0, 0), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
return BiosParameterBlock.(VALID_JUMP_BYTES, oem, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
} }
sector_count := fn(bpb: BiosParameterBlock): u32 { sector_count := fn(bpb: BiosParameterBlock): u32 {
@ -63,7 +60,7 @@ VolumeName := [u8; 11]
SystemIdentifierString := [u8; 8] SystemIdentifierString := [u8; 8]
VALID_SYSTEM_IDENTIFIER_STRING := [u8].(46, 41, 54, 33, 32, 20, 20, 20) VALID_SYSTEM_IDENTIFIER_STRING := [u8].(46, 41, 54, 33, 32, 20, 20, 20)
BOOTABLE_PARTITION_SIGNATURE := 0xAA55 BOOTABLE_PARTITION_SIGNATURE := @as(u32, 0xAA55)
BootCode := [u8; 420] BootCode := [u8; 420]
@ -100,9 +97,10 @@ ebr_sanity_check := fn(ebr: ExtendedBootRecord): int {
log.warn("EBR-Signature sanity check failed\0") log.warn("EBR-Signature sanity check failed\0")
} }
if ebr.system_identifier_string != VALID_SYSTEM_IDENTIFIER_STRING { // ! comparison between [u8] is not supported in hblang
log.warn("EBR-Signature-Identifier-String sanity check failed\0") // if ebr.system_identifier_string != VALID_SYSTEM_IDENTIFIER_STRING {
} // log.warn("EBR-Signature-Identifier-String sanity check failed\0")
// }
return 0 return 0
} }
@ -131,8 +129,8 @@ new_ebr := fn(): ExtendedBootRecord {
) )
} }
VALID_LEAD_FS_INFO := 0x41615252 VALID_LEAD_FS_INFO := @as(u32, 0x41615252)
VALID_TRAIL_FS_INFO := 0xAA550000 VALID_TRAIL_FS_INFO := @as(u32, 0xAA550000)
FSInfo := struct { FSInfo := struct {
// Must be 0x41615252 to indicate a valid FSInfo structure // Must be 0x41615252 to indicate a valid FSInfo structure
@ -145,7 +143,7 @@ FSInfo := struct {
trail_signature: u32, trail_signature: u32,
} }
fs_info_sanity_check := fn(fs_info: FSInfo): int { fs_info_sanity_check := fn(fs_info: FSInfo): uint {
ret := 0 ret := 0
if fs_info.lead_signature != VALID_LEAD_FS_INFO { if fs_info.lead_signature != VALID_LEAD_FS_INFO {
ret &= 1 ret &= 1

View file

@ -16,7 +16,7 @@ FAT12 := 1
FAT16 := 2 FAT16 := 2
FAT32 := 3 FAT32 := 3
calculate_fat_type := fn(sector_size: int, total_clusters: int): int { calculate_fat_type := fn(sector_size: uint, total_clusters: uint): uint {
if sector_size == 0 { if sector_size == 0 {
return ExFAT return ExFAT
} else if total_clusters < 4085 { } else if total_clusters < 4085 {

View file

@ -1,11 +1,152 @@
stn := @use("../../../libraries/stn/src/lib.hb"); stn := @use("../../../libraries/stn/src/lib.hb");
.{string, memory, buffer} := stn .{string, memory, buffer, random, log} := stn;
.{Vec2} := stn.math
horizon_api := @use("../../../libraries/horizon_api/src/lib.hb") horizon_api := @use("../../../libraries/horizon_api/src/lib.hb");
.{new_label, render_label_to_surface, set_label_text} := horizon_api.widgets.label;
.{sexpr_parser, render_ui} := horizon_api.ui
render := @use("../../../libraries/render/src/lib.hb");
.{Surface} := render;
.{Font} := render.text
intouch := @use("../../../libraries/intouch/src/lib.hb")
Window := struct {
// TODO: Replace this with widgets
implicit_framebuffer: render.Surface,
width: int,
height: int,
x: int,
y: int,
}
psf := @embed("../../../assets/consolefonts/tamsyn/10x20r.psf")
img := @embed("../../../assets/wallpaper.qoi")
main := fn(): int { main := fn(): int {
a := buffer.create("XHorizon\0") win_buff := buffer.create("XHorizon\0")
screen := render.init(true)
// Clear the screen to black.
render.clear(screen, render.black)
wallpaper := render.image.from(@bitcast(&img))
if wallpaper == null {
return 1
}
window := render.new_surface(screen.width / 3, screen.height / 3)
mem_buf := memory.request_page(1)
color := random.any(render.Color)
side := window.width / 8
// really we should null check but it is a bit broked
font := @unwrap(render.text.font_from_psf2(@bitcast(&psf), false))
mouse_x := @as(i16, 0)
mouse_y := @as(i16, 0)
text_label := new_label("Hi\0")
// widgets := "()\0"
// ui := sexpr_parser(widgets)
loop { loop {
// Clear the screen
render.clear(screen, render.black)
render.put_surface(screen, wallpaper, .(0, 0), false)
// TODO: Read the window buffer here
{
// ret := buffer.recv([u8; 4096], win_buff, mem_buf)
// for some reason this null check causes the compiler to spin forever
// if ret == null {
// log.info("No messages\0")
// } else {
// log.info("Handle Messages\0")
// }
}
// get input events from drivers via intouch
// key_event := intouch.recieve_key_event();
// log.info("before mouse event check\0");
if false {
// Scroll bar :ThumbsUp:
render.put_rect(screen, .(100, 100), .(100, 10), render.white)
render.put_filled_rect(screen, .(110, 100), .(20, 10), render.white)
render.put_rect(screen, .(90, 110), .(10, 100), render.white)
render.put_filled_rect(screen, .(90, 120), .(10, 20), render.white)
}
{
pos := Vec2(uint).(1, screen.height - 21)
render_label_to_surface(screen, text_label, font, pos)
render.put_rect(screen, .(0, screen.height - 21), .(screen.width - 1, 20), render.white)
}
// Screen border
render.put_rect(screen, .(0, 0), .(screen.width - 1, screen.height - 1), render.white)
{
mouse_event := intouch.recieve_mouse_event()
//
if mouse_event != null {
// log.warn("Mouse event recieved\0")
change_x := @as(i16, mouse_event.x_change)
change_x = change_x << 8
change_x = change_x >> 8
mouse_x += change_x
if mouse_x < 0 {
mouse_x = 0
}
if mouse_x >= screen.width - 20 {
mouse_x = @intcast(screen.width - 21)
}
change_y := @as(i16, mouse_event.y_change)
change_y = change_y << 8
change_y = change_y >> 8
if mouse_y < 0 {
mouse_y = 0
}
if mouse_y >= screen.height - 20 {
mouse_y = @intcast(screen.height - 21)
}
mouse_y -= change_y
if mouse_event.left {
set_label_text(text_label, "LEFT CLICK\0")
}
if mouse_event.middle {
set_label_text(text_label, "MIDDLE CLICK\0")
}
if mouse_event.right {
set_label_text(text_label, "RIGHT CLICK\0")
}
}
// render mouse
lum := render.indexptr(screen, mouse_x, mouse_y)
if lum.r / 3 + lum.g / 3 + lum.b / 3 < 128 {
render.put_rect(screen, .(mouse_x, mouse_y), .(20, 20), render.white)
} else {
render.put_rect(screen, .(mouse_x, mouse_y), .(20, 20), render.black)
}
// Send events to focused window
}
// TODO: Get windows out of a collection and iter through
// Sync the screen
render.sync(screen)
} }
return 0 return 0

View file

@ -7,12 +7,16 @@ horizon_api := @use("../../../libraries/horizon_api/src/lib.hb");
ignim := @use("../../../libraries/ignim/src/lib.hb"); ignim := @use("../../../libraries/ignim/src/lib.hb");
.{errors} := ignim .{errors} := ignim
psf := @embed("../../../consolefonts/tamsyn/10x20r.psf")
main := fn(): int { main := fn(): int {
windowing_system_buffer := buffer.create("XHorizon\0") x := 0
// loop if x > 10000 break else x += 1
windowing_system_buffer := buffer.search("XHorizon\0")
// TODO: get WindowID // TODO: get WindowID
create_window(windowing_system_buffer) wid := create_window(windowing_system_buffer)
if false {
program_name := "Horizon Testing Program\0" program_name := "Horizon Testing Program\0"
program_version := ignim.version.make_version(0, 1, 0) program_version := ignim.version.make_version(0, 1, 0)
engine_name := "None\0" engine_name := "None\0"
@ -25,11 +29,14 @@ main := fn(): int {
instance := ignim.instance.void_instance() instance := ignim.instance.void_instance()
// TODO: recursively follow this https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Instance // // TODO: recursively follow this https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Instance
ret := ignim.instance.create_instance(&create_info, 0, &instance) ret := ignim.instance.create_instance(&create_info, 0, &instance)
if ret == errors.IncompatibleDriver { if ret == errors.IncompatibleDriver {
log.error("Driver Incompatible with Vulkan\0") log.error("Driver Incompatible with Vulkan\0")
} }
}
// TODO: get window from the window system and draw to the surface
return 0 return 0
} }

View file

@ -1,5 +1,5 @@
[package] [package]
name = "ps2_driver" name = "ps2_keyboard_driver"
authors = ["Talha Qamar"] authors = ["Talha Qamar"]
[dependants.libraries] [dependants.libraries]

View file

@ -1,4 +1,4 @@
.{memory, log, string, buffer} := @use("../../../libraries/stn/src/lib.hb") .{memory, log, buffer} := @use("../../../libraries/stn/src/lib.hb")
send_byte := fn(byte: u8): u8 { send_byte := fn(byte: u8): u8 {
memory.outb(96, byte) memory.outb(96, byte)
@ -7,7 +7,7 @@ send_byte := fn(byte: u8): u8 {
main := fn(): int { main := fn(): int {
buf := buffer.create("XKeyboard\0") buf := buffer.create("XKeyboard\0")
send_byte(238) _ = send_byte(238)
log.info("PS/2 Driver Loaded\0") log.info("PS/2 Driver Loaded\0")
if send_byte(238) == 238 { if send_byte(238) == 238 {
log.info("PS/2 Keyboard Echoed\0") log.info("PS/2 Keyboard Echoed\0")
@ -15,7 +15,6 @@ main := fn(): int {
if send_byte(244) == 250 { if send_byte(244) == 250 {
log.info("Enabled scanning\0") log.info("Enabled scanning\0")
} }
ptr := memory.request_page(1)
prev_input := 250 prev_input := 250
loop { loop {
input := memory.inb(96) input := memory.inb(96)
@ -23,7 +22,7 @@ main := fn(): int {
continue continue
} }
prev_input = input prev_input = input
buffer.write(&input, buf, 1) buffer.write(u8, &input, buf)
} }
return 0 return 0
} }

View file

@ -0,0 +1,2 @@
# ps2_mouse_driver
A small PS/2 mouse driver. This driver pushes changes to the input service in ableOS.

View file

@ -1,6 +1,6 @@
[package] [package]
name = "tests" name = "ps2_mouse_driver"
authors = ["able"] authors = ["able", "peony"]
[dependants.libraries] [dependants.libraries]

View file

@ -0,0 +1,152 @@
.{memory, buffer, log, string, math} := @use("../../../libraries/stn/src/lib.hb")
Vec2 := math.Vec2
intouch := @use("../../../libraries/intouch/src/lib.hb");
.{MouseEvent} := intouch.events
i9 := packed struct {sign: bool, value: u8}
Button := struct {id: u8}
$LeftButton := Button.(1)
$RightButton := Button.(2)
$MiddleButton := Button.(4)
$Button4 := Button.(8)
$Button5 := Button.(16)
send_byte := fn(target: u8, data: u8): void {
loop if (memory.inb(0x64) & 2) == 0 break
memory.outb(target, data)
}
reset_mouse := fn(): void {
@inline(send_byte, 0x64, 0xD4)
@inline(send_byte, 0x60, 0xFF)
loop if memory.inb(0x60) == 0xAA {
log.info("Self check passed.\0")
return
}
}
send_command_byte := fn(byte: u8): void {
@inline(send_byte, 0x64, 0xD4)
@inline(send_byte, 0x60, byte)
loop if memory.inb(0x60) == 0xFA {
return
}
}
set_defaults := fn(): void @inline(send_command_byte, 0xF6)
disable_streaming := fn(): void @inline(send_command_byte, 0xF5)
enable_streaming := fn(): void @inline(send_command_byte, 0xF4)
set_remote_mode := fn(): void @inline(send_command_byte, 0xF0)
set_warp_mode := fn(): void @inline(send_command_byte, 0xEE)
reset_warp_mode := fn(): void @inline(send_command_byte, 0xEC)
set_stream_mode := fn(): void @inline(send_command_byte, 0xEA)
set_non_linear_scaling := fn(): void @inline(send_command_byte, 0xE7)
set_linear_scaling := fn(): void @inline(send_command_byte, 0xE6)
resend_packet := fn(): void @inline(send_command_byte, 0xFE)
SampleRate := struct {value: u8}
$sr10 := SampleRate.(10)
$sr20 := SampleRate.(20)
$sr40 := SampleRate.(40)
$sr60 := SampleRate.(60)
$sr80 := SampleRate.(80)
$sr100 := SampleRate.(100)
$sr200 := SampleRate.(200)
set_sample_rate := fn(sample_rate: SampleRate): void {
@inline(send_command_byte, 0xE6)
@inline(send_command_byte, sample_rate.value)
}
Resolution := struct {value: u8}
$res_1count_per_mm := Resolution.(0)
$res_2count_per_mm := Resolution.(1)
$res_4count_per_mm := Resolution.(2)
$res_8count_per_mm := Resolution.(3)
set_resolution := fn(resolution: Resolution): void {
@inline(send_command_byte, 0xE6)
@inline(send_command_byte, resolution.value)
}
set_up_mouse := fn(): void {
@inline(reset_mouse)
@inline(set_resolution, res_8count_per_mm)
@inline(enable_streaming)
}
button_states := @as(u8, 0)
main := fn(): int {
mouse_buffer := buffer.create("PS/2 Mouse\0")
format_page := memory.alloc(u8, 1024)
send_byte(0x64, 0xA8)
log.info("Aux mouse device enabled.\0")
set_up_mouse()
set_resolution(res_8count_per_mm)
x := @as(u8, 0)
y := @as(u8, 0)
loop {
loop if (memory.inb(0x64) & 0x20) == 0x20 break
status := memory.inb(0x60)
if status == 0xAA {
loop if memory.inb(0x60) == 0 break
log.info("Mouse plugged in!\0")
set_up_mouse()
continue
}
event := MouseEvent.(0, 0, false, false, false)
changes := button_states ^ status & 7
if (changes & LeftButton.id) != 0 | (status & LeftButton.id) != 0 {
event.left = true
} else {
event.left = false
}
if (changes & MiddleButton.id) != 0 | (status & MiddleButton.id) != 0 {
event.middle = true
} else {
event.middle = false
}
if (changes & RightButton.id) != 0 | (status & RightButton.id) != 0 {
event.right = true
} else {
event.right = false
}
button_states ^= changes
dx := i9.(false, 0)
dy := i9.(false, 0)
dx.value = memory.inb(0x60)
dx.sign = (status & 0x10) > 0
dy.value = memory.inb(0x60)
dy.sign = (status & 0x20) != 0
y_change := @as(i8, @bitcast(dy.value))
x_change := @as(i8, @bitcast(dx.value))
event.x_change = x_change
event.y_change = y_change
buffer.write(MouseEvent, &event, mouse_buffer)
}
return 0
}

View file

@ -4,16 +4,16 @@ render := @use("../../../../libraries/render/src/lib.hb")
the impostor travels left and loops around the screen */ the impostor travels left and loops around the screen */
example := fn(): void { example := fn(): void {
render.init() screen := render.init(true)
x := 0 x := 0
loop { loop {
render.put_rect(.(200 - x, 80), .(430, 380), render.red) render.put_rect(screen, .(200 - x, 80), .(430, 380), render.red)
render.put_rect(.(630 - x, 120), .(120, 300), render.red) render.put_rect(screen, .(630 - x, 120), .(120, 300), render.red)
render.put_rect(.(200 - x, 460), .(160, 270), render.red) render.put_rect(screen, .(200 - x, 460), .(160, 270), render.red)
render.put_rect(.(470 - x, 460), .(160, 270), render.red) render.put_rect(screen, .(470 - x, 460), .(160, 270), render.red)
render.put_rect(.(140 - x, 140), .(340, 250), render.cyan) render.put_rect(screen, .(140 - x, 140), .(340, 250), render.cyan)
render.sync() render.sync(screen)
render.clear(render.black) render.clear(screen, render.black)
x += 1 x += 1
} }
return return

View file

@ -6,12 +6,12 @@ render := @use("../../../../libraries/render/src/lib.hb")
note that this may happen too fast for you to notice... */ note that this may happen too fast for you to notice... */
example := fn(): void { example := fn(): void {
render.init() screen := render.init(true)
color := render.light_cyan color := render.light_cyan
n := @as(u8, 1) n := @as(u8, 1)
loop { loop {
render.clear(color) render.clear(screen, color)
render.sync() render.sync(screen)
if (color.b & 255) == 255 | (color.b & 255) == 0 { if (color.b & 255) == 255 | (color.b & 255) == 0 {
n = -n n = -n
} }

View file

@ -0,0 +1,26 @@
.{log, math, string} := @use("../../../../libraries/stn/src/lib.hb")
render := @use("../../../../libraries/render/src/lib.hb")
/* expected result:
a cute qoi image and a cute bmp image */
example := fn(): void {
screen := render.init(true)
image_qoi := render.image.from(@bitcast(&@embed("../../../../assets/mini.qoi")))
image_bmp := render.image.from(@bitcast(&@embed("../../../../assets/mini.bmp")))
if image_qoi == null | image_bmp == null {
log.error("failed to load images for whatever reason\0")
return
}
t := 0.0
loop {
render.clear(screen, render.black)
render.put_surface(screen, image_bmp, .(@bitcast(@fti(math.cos(t) * 100.0)) + (screen.width - image_bmp.width * 3) / 2, (screen.height - image_bmp.height) / 2), false)
render.put_surface(screen, image_qoi, .((screen.width + image_qoi.width) / 2, @bitcast(@fti(math.sin(t) * 100.0)) + (screen.height - image_qoi.height) / 2), false)
render.sync(screen)
t += 0.02
}
return
}

View file

@ -6,18 +6,16 @@ render := @use("../../../../libraries/render/src/lib.hb")
created on a blue background */ created on a blue background */
example := fn(): void { example := fn(): void {
render.init() screen := render.init(true)
render.clear(.(100, 50, 0, 255)) render.clear(screen, .(100, 50, 0, 255))
width := render.width() p0 := Vec2(uint).(0, 0)
height := render.height() p1 := Vec2(uint).(0, screen.height)
p0 := Vec2(int).(0, 0) loop if p0.y >= screen.height break else {
p1 := Vec2(int).(0, height) render.put_line(screen, p0, p1, .(255, 180, 100, 255))
loop if p0.y >= height break else { render.put_line(screen, .(screen.width, screen.height) - p0, .(screen.width, screen.height) - p1, .(255, 180, 100, 255))
render.put_line(p0, p1, .(255, 180, 100, 255)) p0.y += screen.height >> 6
render.put_line(.(width, height) - p0, .(width, height) - p1, .(255, 180, 100, 255)) p1.x += screen.width >> 6
p0.y += height >> 6
p1.x += width >> 6
} }
render.sync() render.sync(screen)
return return
} }

View file

@ -2,16 +2,15 @@
render := @use("../../../../libraries/render/src/lib.hb") render := @use("../../../../libraries/render/src/lib.hb")
example := fn(): void { example := fn(): void {
render.init() screen := render.init(false)
render.doublebuffer(false) render.clear(screen, render.black)
render.clear(render.black)
loop { loop {
x := random.range(int, 0, 1024) x := random.range(uint, 0, screen.width)
y := random.range(int, 0, 768) y := random.range(uint, 0, screen.height)
r := random.range(int, 0, 255) r := random.range(u8, 0, 255)
g := random.range(int, 0, 75) g := random.range(u8, 0, 75)
b := random.range(int, 0, 155) b := random.range(u8, 0, 155)
render.put_pixel(.(x, y), .(b, g, r, 255)) render.put_pixel(screen, .(x, y), .(b, g, r, 255))
} }
return return
} }

View file

@ -6,27 +6,26 @@ render := @use("../../../../libraries/render/src/lib.hb")
a square that changes colour bounces around the screen */ a square that changes colour bounces around the screen */
example := fn(): void { example := fn(): void {
render.init() screen := render.init(true)
vel := Vec2(int).(1, 1) vel := Vec2(int).(1, 1)
pos := Vec2(int).(100, 100) side := screen.width / 8
width := render.width() pos := Vec2(uint).((screen.width - side) / 2, (screen.height - side) / 2)
height := render.height() color := random.any(render.Color)
color := @as(render.Color, @intcast(random.range(int, 0, 0xFFFFFF)))
loop { loop {
render.put_filled_rect(pos, .(100, 100), color) render.put_filled_rect(screen, pos, .(side, side), color)
render.sync() render.sync(screen)
render.clear(render.black) render.clear(screen, render.black)
if pos.x == 0 | pos.x == width - 100 { if pos.x == 0 | pos.x == screen.width - side {
vel.x = -vel.x vel.x = -vel.x
color = @as(render.Color, @intcast(random.range(int, 0, 0xFFFFFF))) color = random.any(render.Color)
} }
if pos.y == 0 | pos.y == height - 100 { if pos.y == 0 | pos.y == screen.height - side {
vel.y = -vel.y vel.y = -vel.y
color = @as(render.Color, @intcast(random.range(int, 0, 0xFFFFFF))) color = random.any(render.Color)
} }
pos += vel pos += @bitcast(vel)
} }
return return
} }

View file

@ -1,15 +0,0 @@
render := @use("../../../../libraries/render/src/lib.hb")
/* expected result: (EPILEPSY WARNING)
the screen rapidly flashes red then black */
example := fn(): void {
render.init()
loop {
render.clear(render.red)
render.sync()
render.clear(render.yellow)
render.sync()
}
return
}

View file

@ -0,0 +1,55 @@
.{Vec2} := @use("../../../../libraries/stn/src/lib.hb").math;
.{random} := @use("../../../../libraries/stn/src/lib.hb")
render := @use("../../../../libraries/render/src/lib.hb")
/* expected result:
bouncing gradient square inside coloured bouncing box inside black screen */
example := fn(): void {
screen := render.init(true)
image := render.new_surface(screen.width / 3, screen.height / 3)
vel := Vec2(int).(-1, -1)
pos := Vec2(uint).(100, 100)
side := image.width / 8
vel_inner := Vec2(int).(1, 1)
pos_inner := Vec2(uint).((image.width - side) / 2, (image.height - side) / 2)
color := random.any(render.Color)
target_color := random.any(render.Color)
loop {
render.clear(screen, render.black)
render.put_filled_rect(image, pos_inner, .(side, side), color)
render.put_rect(image, pos_inner, .(side, side), render.black)
render.put_rect(image, .(0, 0), .(image.width - 1, image.height - 1), color)
render.put_surface(screen, image, pos, false)
render.put_rect(image, pos_inner, .(side, side), color)
render.sync(screen)
if pos_inner.x == 0 | pos_inner.x == image.width - side {
vel_inner.x = -vel_inner.x
target_color = random.any(render.Color)
}
if pos_inner.y == 0 | pos_inner.y == image.height - side {
vel_inner.y = -vel_inner.y
target_color = random.any(render.Color)
}
if pos.x == 0 | pos.x == screen.width - image.width {
vel.x = -vel.x
}
if pos.y == 0 | pos.y == screen.height - image.height {
vel.y = -vel.y
}
color += .(
@bitcast(color.b < target_color.b) - @bitcast(color.b > target_color.b),
@bitcast(color.g < target_color.g) - @bitcast(color.g > target_color.g),
@bitcast(color.r < target_color.r) - @bitcast(color.r > target_color.r),
0,
)
pos += @bitcast(vel)
pos_inner += @bitcast(vel_inner)
}
return
}

View file

@ -1,8 +0,0 @@
render := @use("../../../../libraries/render/src/lib.hb")
render.mode = render.svga
example := fn(): void {
render.init()
return
}

View file

@ -4,15 +4,15 @@ Vec2 := math.Vec2
/* expected result: /* expected result:
a grid of green lines scrolling from the left top corner to the right bottom one a grid of green lines scrolling from the left top corner to the right bottom one
with a "target" randomly apperaing in one of them and a "seeker" "catching" it*/ with a "target" randomly apperaing in one of them and a "seeker" "catching" it */
example := fn(): void { example := fn(): void {
render.init() screen := render.init(true)
width := render.width() width := screen.width
height := render.height() height := screen.height
cell_size := 0 cell_size := 0
range := Vec2(int).(0, 0) range := Vec2(uint).(0, 0)
if width > height { if width > height {
cell_size = width / 40 cell_size = width / 40
range = .(39, height / cell_size - 1) range = .(39, height / cell_size - 1)
@ -24,41 +24,41 @@ example := fn(): void {
height -= 1 height -= 1
scroll := 0 scroll := 0
target := Vec2(int).(random.range(int, 0, range.x), random.range(int, 0, range.y)) target := Vec2(uint).(random.range(uint, 0, range.x), random.range(uint, 0, range.y))
halfcell := cell_size / 2 halfcell := cell_size / 2
octcell := cell_size / 8 octcell := cell_size / 8
sevenoctcell := cell_size - octcell sevenoctcell := cell_size - octcell
seeker := Vec2(int).(random.range(int, 0, range.x), random.range(int, 0, range.y)) seeker := Vec2(uint).(random.range(uint, 0, range.x), random.range(uint, 0, range.y))
loop { loop {
render.clear(render.black) render.clear(screen, render.black)
target_pixel_coord := target * .(cell_size, cell_size) + .(scroll, scroll) target_pixel_coord := target * .(@bitcast(cell_size), @bitcast(cell_size)) + .(scroll, scroll)
render.put_trirect(target_pixel_coord, .(cell_size, cell_size), render.red, render.light_red) render.put_trirect(screen, target_pixel_coord, .(@bitcast(cell_size), @bitcast(cell_size)), render.red, render.light_red)
render.put_hline(target_pixel_coord.y + halfcell, target_pixel_coord.x - octcell, target_pixel_coord.x - sevenoctcell, render.light_red) render.put_hline(screen, target_pixel_coord.y + halfcell, target_pixel_coord.x - octcell, target_pixel_coord.x - sevenoctcell, render.light_red)
render.put_hline(target_pixel_coord.y + halfcell, target_pixel_coord.x + cell_size + octcell, target_pixel_coord.x + cell_size + sevenoctcell, render.light_red) render.put_hline(screen, target_pixel_coord.y + halfcell, target_pixel_coord.x + cell_size + octcell, target_pixel_coord.x + cell_size + sevenoctcell, render.light_red)
render.put_vline(target_pixel_coord.x + halfcell, target_pixel_coord.y - octcell, target_pixel_coord.y - sevenoctcell, render.light_red) render.put_vline(screen, target_pixel_coord.x + halfcell, target_pixel_coord.y - octcell, target_pixel_coord.y - sevenoctcell, render.light_red)
render.put_vline(target_pixel_coord.x + halfcell, target_pixel_coord.y + cell_size + octcell, target_pixel_coord.y + cell_size + sevenoctcell, render.light_red) render.put_vline(screen, target_pixel_coord.x + halfcell, target_pixel_coord.y + cell_size + octcell, target_pixel_coord.y + cell_size + sevenoctcell, render.light_red)
x := scroll x := scroll
loop if x > width break else { loop if x > width break else {
render.put_vline(x, 0, height, .(0, 127, 0, 127)) render.put_vline(screen, x, 0, height, .(0, 127, 0, 127))
x += cell_size x += cell_size
} }
y := scroll y := scroll
loop if y > height break else { loop if y > height break else {
render.put_hline(y, 0, width, .(0, 127, 0, 127)) render.put_hline(screen, y, 0, width, .(0, 127, 0, 127))
y += cell_size y += cell_size
} }
render.put_hline(seeker.y * cell_size + halfcell + scroll, 0, width, render.light_green) render.put_hline(screen, seeker.y * cell_size + halfcell + scroll, 0, width, render.blue)
render.put_vline(seeker.x * cell_size + halfcell + scroll, 0, height, render.light_green) render.put_vline(screen, seeker.x * cell_size + halfcell + scroll, 0, height, render.blue)
render.sync() render.sync(screen)
if seeker.x < target.x { if seeker.x < target.x {
seeker.x += 1 seeker.x += 1
@ -69,7 +69,7 @@ example := fn(): void {
} else if seeker.y > target.y { } else if seeker.y > target.y {
seeker.y -= 1 seeker.y -= 1
} else { } else {
target = .(random.range(int, 0, range.x), random.range(int, 0, range.y)) target = .(random.range(uint, 0, range.x), random.range(uint, 0, range.y))
} }
scroll += 1 scroll += 1

View file

@ -0,0 +1,243 @@
.{memory, log, string, math} := @use("../../../../libraries/stn/src/lib.hb")
render := @use("../../../../libraries/render/src/lib.hb")
/* expected result: pretty decent notepad app
slightly jank
-----------------
features:
- basic keys
- holding support with DAS
- visible cursor
- l+r arrow key support
- proper insertion and deletion
- shift key support
*/
psf := @embed("../../../../assets/consolefonts/tamsyn/10x20r.psf")
img := @embed("../../../../assets/wallpaper.qoi")
is_shift_pressed := false
is_ctrl_pressed := false
is_extended := false
$initial_delay := 50
$repeat_delay := 7
$left_arrow := 0x4B
$right_arrow := 0x4D
$up_arrow := 0x48
$down_arrow := 0x50
example := fn(): void {
screen := render.init(true)
window := render.new_surface(600, 300)
font := render.text.font_from_psf2(@bitcast(&psf), false)
wallpaper := render.image.from(@bitcast(&img))
if font == null {
return
}
if wallpaper == null {
return
}
msg := "sticky note:\n\0"
msg_len := string.length(msg)
buf := memory.alloc(u8, 4096)
bottom := buf + msg_len
@inline(memory.copy, u8, msg, buf, msg_len)
cursor := bottom
draw_window(window, font, buf, cursor)
draw_screen(screen, window, wallpaper)
memory.outb(96, 238)
memory.outb(96, 238)
memory.outb(96, 244)
prev_input := @as(u8, 0xFF)
current_key := @as(u8, 0)
holding_timer := 0
loop {
input := memory.inb(96)
if input != prev_input {
if input == 0xE0 {
is_extended = true
} else {
if (input & 0x80) != 0 {
if (input & 0x7F) == current_key {
current_key = 0
holding_timer = 0
} else if input == 0xAA | input == 0xB6 {
is_shift_pressed = false
} else if input == 0x9D {
is_ctrl_pressed = false
}
is_extended = false
} else {
if is_extended {
current_key = input
holding_timer = 1
cursor = handle_extended_key(input, cursor, bottom, font)
} else {
if input == 0x2A | input == 0x36 {
is_shift_pressed = true
} else if input == 0x1D {
is_ctrl_pressed = true
} else {
current_key = input
holding_timer = 1
cursor = handle_char(map_keys(current_key), cursor, bottom)
}
}
}
}
prev_input = input
}
if current_key != 0 & holding_timer > 0 {
holding_timer += 1
if holding_timer >= initial_delay {
if is_extended {
cursor = handle_extended_key(current_key, cursor, bottom, font)
} else {
cursor = handle_char(map_keys(current_key), cursor, bottom)
}
holding_timer = initial_delay - repeat_delay
}
}
draw_window(window, font, buf, cursor)
draw_screen(screen, window, wallpaper)
if holding_timer > 0 & current_key != 0 {
if (memory.inb(96) & 0x80) != 0 {
current_key = 0
holding_timer = 0
}
}
}
}
handle_extended_key := fn(scancode: u8, cursor: ^u8, bottom: ^u8, font: render.text.Font): ^u8 {
if scancode == left_arrow {
if cursor > bottom {
return cursor - 1
}
} else if scancode == right_arrow {
if *cursor != 0 {
return cursor + 1
}
}
return cursor
}
padding := 3 * @sizeof(render.Color)
draw_window := fn(window: render.Surface, font: render.text.Font, buf: ^u8, cursor: ^u8): void {
render.clear(window, .(0x88, 0xF4, 0xFC, 0x0))
line := font.height + padding - 1
render.put_rect(window, .(0, 0), .(window.width - 1, window.height - 1), render.black)
loop if line >= window.height break else {
render.put_hline(window, line, padding, window.width - padding, render.yellow)
line += font.height
}
render.put_text(window, font, .(padding, padding), render.black, buf)
cursor_offset := cursor - buf
y_pos := padding
x_pos := padding
i := 0
loop if i >= cursor_offset break else {
if *(buf + i) == 10 {
y_pos += font.height + font.line_gap
x_pos = padding
} else {
if x_pos + font.width >= window.width - padding {
y_pos += font.height + font.line_gap
x_pos = padding - font.width
}
x_pos += font.width
}
i += 1
}
render.put_rect(window, .(x_pos, y_pos), .(1, font.height - 1), render.black)
}
draw_screen := fn(screen: render.Surface, window: render.Surface, wallpaper: render.Surface): void {
render.put_surface(screen, wallpaper, .(0, 0), false)
render.put_surface(screen, window, .(100, 100), false)
render.sync(screen)
}
handle_char := fn(char: u8, cursor: ^u8, bottom: ^u8): ^u8 {
if char == 0 {
return cursor
}
if is_ctrl_pressed & char == 48 {
cursor = bottom
} else if char != 0x8 {
end := cursor
loop if *end == 0 break else {
end += 1
}
if cursor < end {
src := end
dst := end + 1
loop if src < cursor break else {
*dst = *src
dst -= 1
src -= 1
}
};
*cursor = char
return cursor + 1
} else if char == 0xA {
*cursor = 32
cursor += 1;
*cursor = 92
return cursor + 1
} else if cursor > bottom {
if cursor == bottom {
return cursor
}
end := cursor
loop if *end == 0 break else {
end += 1
}
if cursor < end {
src := cursor
dst := cursor - 1
loop if src > end break else {
*dst = *src
dst += 1
src += 1
}
return cursor - 1
} else {
cursor -= 1;
*cursor = 32
return cursor
}
}
return cursor
}
map_keys := fn(scancode: u8): u8 {
if is_shift_pressed {
return ps2_table[scancode + 0x40]
}
return ps2_table[scancode]
}
ps2_table := [u8].(0x0, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x8, 0x9, 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, 0x6F, 0x70, 0x5B, 0x5D, 0xA, 0x0, 0x61, 0x73, 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B, 0x27, 0x60, 0x0, 0x5C, 0x7A, 0x78, 0x63, 0x76, 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x0, 0x2A, 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x8, 0x9, 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F, 0x50, 0x7B, 0x7D, 0xA, 0x0, 0x41, 0x53, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A, 0x22, 0x7E, 0x0, 0x7C, 0x5A, 0x58, 0x43, 0x56, 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x0, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)

View file

@ -1,6 +1 @@
.{example} := @use("./examples/tactical_screen.hb") .{example: main} := @use("./examples/text.hb")
main := fn(): void {
@inline(example)
return
}

View file

@ -1,7 +1,7 @@
.{memory, buffer} := @use("../../../libraries/stn/src/lib.hb") .{memory, buffer} := @use("../../../libraries/stn/src/lib.hb")
serial_print := fn(ptr: ^u8): void { serial_print := fn(ptr: ^u8): void {
letter := 0 letter := @as(u8, 0)
loop if *ptr == 0 break else { loop if *ptr == 0 break else {
letter = *ptr letter = *ptr
memory.outb(0xF803, letter) memory.outb(0xF803, letter)
@ -25,7 +25,7 @@ main := fn(): int {
mem := memory.request_page(1) mem := memory.request_page(1)
loop { loop {
ptr := @eca(4, a, mem, 0x1000) ptr := @as(^u8, @eca(4, a, mem, 0x1000))
if ptr == 0 { if ptr == 0 {
serial_println("No message\0") serial_println("No message\0")
} }

View file

@ -5,8 +5,10 @@ log_info := fn(): void {
if a == 0 { if a == 0 {
} else { } else {
msg := "XABC\0" msg := "XABC\0"
msg_length := @inline(string.length, msg) // inline is broked
@eca(3, a, msg, msg_length) // msg_length := @inline(string.length, msg)
msg_length := 5
@as(void, @eca(3, a, msg, msg_length))
} }
return return

View file

@ -2,9 +2,7 @@ stn := @use("../../../libraries/stn/src/lib.hb");
.{string, memory, buffer, log} := stn .{string, memory, buffer, log} := stn
pci := @use("../../../libraries/pci/src/lib.hb"); pci := @use("../../../libraries/pci/src/lib.hb");
.{PCIAddress, get_ids, config_read32} := pci; .{PCIAddress, get_ids, config_read32} := pci
.{dt_get} := @use("../../../libraries/dt_api/src/lib.hb")
reg := @use("./reg.hb") reg := @use("./reg.hb")

View file

@ -1,13 +0,0 @@
.{log, string, memory, buffer} := @use("../../../libraries/stn/src/lib.hb")
service_search := fn(): void {
a := "\{01}\0"
@eca(3, 0, a, 2)
return
}
main := fn(): int {
//service_search()
return 0
}

View file

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

View file

@ -3,11 +3,12 @@
default_entry = 1 default_entry = 1
timeout = 0 timeout = 0
verbose = false verbose = false
interface_resolution = "1600x900x24" # interface_resolution = "1920x1080x24"
# interface_resolution = "640x480x32" interface_resolution = "1024x768x24"
# interface_resolution = "640x480x24"
# Terminal related settings # Terminal related settings
term_wallpaper = "boot:///background.bmp" # term_wallpaper = "boot:///background.bmp"
# term_wallpaper = "boot:///empty-background.bmp" term_wallpaper = "boot:///empty-background.bmp"
term_background = "008080" term_background = "008080"
[boot.limine.ableos] [boot.limine.ableos]
@ -15,46 +16,20 @@ comment = "Default AbleOS boot entry."
protocol = "limine" protocol = "limine"
kernel_path = "boot:///kernel_${ARCH}" kernel_path = "boot:///kernel_${ARCH}"
kernel_cmdline = "" kernel_cmdline = ""
# resolution = "640x480x32" # resolution = "1920x1080x24"
resolution = "1600x900x24" resolution = "1024x768x24"
# resolution = "640x480x24"
[boot.limine.ableos.modules] [boot.limine.ableos.modules]
# [boot.limine.ableos.modules.tests] # [boot.limine.ableos.modules.render_example]
# path = "boot:///tests.hbf" # path = "boot:///render_example.hbf"
# [boot.limine.ableos.modules.serial_driver] [boot.limine.ableos.modules.horizon]
# path = "boot:///serial_driver.hbf" path = "boot:///horizon.hbf"
# [boot.limine.ableos.modules.diskio_driver] [boot.limine.ableos.modules.ps2_mouse_driver]
# path = "boot:///diskio_driver.hbf" path = "boot:///ps2_mouse_driver.hbf"
[boot.limine.ableos.modules.render_example] # [boot.limine.ableos.modules.ps2_keyboard_driver]
path = "boot:///render_example.hbf" # path = "boot:///ps2_keyboard_driver.hbf"
# [boot.limine.ableos.modules.serial_driver_test]
# path = "boot:///serial_driver_test.hbf"
# [boot.limine.ableos.modules.horizon]
# path = "boot:///horizon.hbf"
# [boot.limine.ableos.modules.horizon_testing_program]
# path = "boot:///horizon_testing_program.hbf"
# [boot.limine.ableos.modules.dt_buffer_test]
# path = "boot:///dt_buffer_test.hbf"
# [boot.limine.ableos.modules.svga_driver]
# path = "boot:///svga_driver.hbf"
# [boot.limine.ableos.modules.ps2_driver]
# path = "boot:///ps2_driver.hbf"
# [boot.limine.ableos.modules.filesystem_fat32]
# path = "boot:///filesystem_fat32.hbf"
# [boot.limine.ableos.modules.pumpkin_print]
# path = "boot:///pumpkin_print.hbf"
# [boot.limine.ableos.modules.tetris]
# path = "boot:///tetris.hbf"