diff --git a/.cargo/config.toml b/.cargo/config.toml index cd125e0..400f704 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -10,4 +10,14 @@ build-std-features = ["compiler-builtins-mem"] RUST_TARGET_PATH = { value = "kernel", relative = true } [target.x86_64-kernel] -runner = "scripts/run.sh" \ No newline at end of file +runner = "scripts/run.sh" + +[registry] +default = "gitea" + +[registries.gitea] +index = "sparse+https://git.zxq5.dev/api/packages/OsDev/cargo/" # Sparse index +# index = "https://gitea.example.com/{owner}/_cargo-index.git" # Git + +# [net] +# git-fetch-with-cli = true diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 66cee7a..0000000 --- a/.gitmodules +++ /dev/null @@ -1,21 +0,0 @@ -[submodule "lib/lib_application"] - path = lib/lib_application - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_application.git -[submodule "lib/lib_ascii"] - path = lib/lib_ascii - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_ascii.git -[submodule "lib/lib_framebuffer"] - path = lib/lib_framebuffer - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_framebuffer.git -[submodule "lib/lib_serial"] - path = lib/lib_serial - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_serial.git -[submodule "lib/lib_alloc"] - path = lib/lib_alloc - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_alloc.git -[submodule "lib/lib_async"] - path = lib/lib_async - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_async.git -[submodule "lib/lib_keyboard"] - path = lib/lib_keyboard - url = https://git.zxq5.dev/OsDev/FoundryOS-lib_keyboard.git diff --git a/Cargo.lock b/Cargo.lock index 5f2a6c8..5d87614 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,9 +22,9 @@ checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "cc" -version = "1.2.14" +version = "1.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" +checksum = "c736e259eea577f443d5c86c304f9f4ae0295c43f3ba05c21f1d66b5f06001af" dependencies = [ "shlex", ] @@ -69,13 +69,7 @@ name = "foundry_os" version = "0.1.0" dependencies = [ "cc", - "lib_alloc", - "lib_application", - "lib_ascii", - "lib_async", - "lib_framebuffer", - "lib_keyboard", - "lib_serial", + "libk", "limine", "pc-keyboard", "pic8259", @@ -108,73 +102,15 @@ dependencies = [ ] [[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "lib_alloc" -version = "0.1.0" -dependencies = [ - "linked_list_allocator", - "x86_64", -] - -[[package]] -name = "lib_application" -version = "0.1.0" -dependencies = [ - "lib_ascii", -] - -[[package]] -name = "lib_ascii" -version = "0.1.0" -dependencies = [ - "lazy_static", - "lib_framebuffer", - "spin", - "x86_64", -] - -[[package]] -name = "lib_async" -version = "0.1.0" -dependencies = [ - "crossbeam", - "spin", - "x86_64", -] - -[[package]] -name = "lib_framebuffer" -version = "0.1.0" -dependencies = [ - "limine", - "spin", -] - -[[package]] -name = "lib_keyboard" +name = "libk" version = "0.1.0" dependencies = [ "crossbeam", "futures-util", - "lib_ascii", + "limine", + "linked_list_allocator", "pc-keyboard", "spin", -] - -[[package]] -name = "lib_serial" -version = "0.1.0" -dependencies = [ - "lazy_static", - "spin", "x86_64", ] diff --git a/Cargo.toml b/Cargo.toml index c6a9865..b3cb7bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,11 @@ [workspace] -members = [ - "kernel", - "lib/lib_framebuffer", - "lib/lib_serial", - "lib/lib_ascii", - "lib/lib_application", - "lib/lib_alloc", - "lib/lib_async", - "lib/lib_keyboard", -] +members = ["kernel", "libk"] resolver = "2" [workspace.package] version = "0.1.0" edition = "2021" +authors = ["The Foundry OS contributors"] [profile.dev] opt-level = "z" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index feb1490..48f4be3 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -5,13 +5,7 @@ edition = "2021" [dependencies] limine = "0.3.1" -lib_framebuffer = { version = "0.1.0", path = "../lib/lib_framebuffer", registry = "gitea" } -lib_serial = { version = "0.1.0", path = "../lib/lib_serial", registry = "gitea" } -lib_ascii = { version = "0.1.0", path = "../lib/lib_ascii", registry = "gitea" } -lib_application = { version = "0.1.0", path = "../lib/lib_application", registry = "gitea" } -lib_async = { version = "0.1.0", path = "../lib/lib_async", registry = "gitea" } -lib_keyboard = { version = "0.1.0", path = "../lib/lib_keyboard", registry = "gitea" } -lib_alloc = { version = "0.1.0", path = "../lib/lib_alloc", registry = "gitea" } +libk = { path = "../libk" } x86_64 = "0.15.2" spin = "0.9.8" pic8259 = "0.11.0" diff --git a/kernel/src/arch/x86_64/interrupts.rs b/kernel/src/arch/x86_64/interrupts.rs index 3ad7ef9..f5e7d2e 100644 --- a/kernel/src/arch/x86_64/interrupts.rs +++ b/kernel/src/arch/x86_64/interrupts.rs @@ -1,6 +1,4 @@ -use lib_ascii::println_log; -use lib_serial::serial_println; -// use x86_64::instructions::port::Port; +use libk::prelude::*; use x86_64::registers::control::Cr2; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, PageFaultErrorCode}; @@ -98,7 +96,7 @@ extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStac let mut port = Port::new(0x60); let scancode: u8 = unsafe { port.read() }; - lib_keyboard::add_scancode(scancode); + libk::io::keyboard::add_scancode(scancode); unsafe { PICS.lock() diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 68bf61b..4d1a129 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -4,13 +4,11 @@ extern crate alloc; use core::arch::asm; -use lib_alloc::allocator::init_heap; use limine::BaseRevision; -pub use lib_ascii::{print, print_log, println, println_log, WRITER}; -pub use lib_serial::{serial_print, serial_println, serial_read}; -// use x86_64::structures::paging::Translate; -// use x86_64::PhysAddr; +use libk::alloc::init_heap; +use libk::prelude::*; + use x86_64::VirtAddr; mod arch; @@ -53,7 +51,7 @@ pub fn boot() -> Result<(), &'static str> { let memory_map = memmap::get_memory_map(); print_log!(" Initialising Serial... "); - lib_serial::init()?; + libk::io::serial::init()?; println_log!("[Success]"); print_log!(" Setting Up Global Descriptor Table... "); diff --git a/kernel/src/main.rs b/kernel/src/main.rs index d9e5708..8b5b3b8 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -3,9 +3,11 @@ extern crate alloc; -use foundry_os::{println, println_log}; -use lib_async::task::{Executor, Task}; -use lib_keyboard::print_keypresses; +use libk::{ + io, + prelude::*, + scheduling::task::{Executor, Task}, +}; #[no_mangle] extern "C" fn kmain() -> ! { @@ -16,8 +18,8 @@ extern "C" fn kmain() -> ! { println_log!("[ Kernel Initialised Successfully ] "); - let dimensions = lib_ascii::screensize_chars(); - let dimensions2 = lib_framebuffer::screensize_px(); + let dimensions = io::ascii::screensize_chars(); + let dimensions2 = io::ascii::screensize_px(); println!("Dimensions: {}x{} (px)", dimensions2.0, dimensions2.1); println!("Dimensions: {}x{} (chars)", dimensions.0, dimensions.1); @@ -44,7 +46,7 @@ extern "C" fn kmain() -> ! { ); let mut executor = Executor::new(); - executor.spawn(Task::new(print_keypresses())); + executor.spawn(Task::new(io::keyboard::print_keypresses())); executor.try_run(); loop {} diff --git a/lib/lib_alloc b/lib/lib_alloc deleted file mode 160000 index cce44f5..0000000 --- a/lib/lib_alloc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cce44f5273d51ff44a234f3745e97f97a5ed66d4 diff --git a/lib/lib_application b/lib/lib_application deleted file mode 160000 index 4b1c606..0000000 --- a/lib/lib_application +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4b1c60676a2f67c2f95139ef2820238cdcbbf19e diff --git a/lib/lib_ascii b/lib/lib_ascii deleted file mode 160000 index 70d528b..0000000 --- a/lib/lib_ascii +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 70d528b2e8dc4d5b522955c248f47da74ce28678 diff --git a/lib/lib_async b/lib/lib_async deleted file mode 160000 index 5e74d22..0000000 --- a/lib/lib_async +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5e74d22e25e1c2b79e50e40b3182828efcbc159c diff --git a/lib/lib_framebuffer b/lib/lib_framebuffer deleted file mode 160000 index 5355327..0000000 --- a/lib/lib_framebuffer +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 53553278d11e798f8dc770b9f5efe50d9b737c68 diff --git a/lib/lib_keyboard b/lib/lib_keyboard deleted file mode 160000 index b475480..0000000 --- a/lib/lib_keyboard +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b475480d8f3783acdba4d6cf457464794da7af70 diff --git a/lib/lib_serial b/lib/lib_serial deleted file mode 160000 index ed2fa6b..0000000 --- a/lib/lib_serial +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ed2fa6b50102607d33973c1851a0ec8c895ed4fa diff --git a/libk/Cargo.toml b/libk/Cargo.toml new file mode 100644 index 0000000..a6d272e --- /dev/null +++ b/libk/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "libk" +publish = ["gitea"] +version.workspace = true +edition.workspace = true +authors.workspace = true +description = "A library crate used to write the kernel for Foundry OS." + +[dependencies] +limine = "0.3.1" +x86_64 = "0.15.2" +crossbeam = { version = "0.8.4", default-features = false, features = [ + "alloc", + "crossbeam-queue", +] } +pc-keyboard = "0.8.0" +spin = "0.9.8" +futures-util = { version = "0.3.31", default-features = false, features = [ + "alloc", +] } +linked_list_allocator = "0.10.5" diff --git a/libk/README.md b/libk/README.md new file mode 100644 index 0000000..0603a21 --- /dev/null +++ b/libk/README.md @@ -0,0 +1,24 @@ +# libk is for the code that did not make the kernel* + +\*crate, lol. + +libk is an attempt to move away from the godforsaken git submodules that plagued our forefathers. Now we have a crate containing a bunch of code that didn't quite make the core kernel crate, which should be: + +* simpler to maintain +* has a catchier name +* less fighting with Cargo.toml manifests + +## TODO: + +A lot of things must be improved and worked on, feel free to add extra TODOs below. + +[] Create a kernel logging abstraction similar to Linux. (this should probably just use the serial drivers) + +The rationale behind this is that we want some sort of debug log/tracing support so we aren't just printf debugging forever. + +## Authors + +Again, write your name below if you like: + +* @zxq5 (wrote most of the libraries as of 23/02/25) +* @nullndvoid (made this lushious library crate) \ No newline at end of file diff --git a/libk/src/alloc.rs b/libk/src/alloc.rs new file mode 100644 index 0000000..56c2a60 --- /dev/null +++ b/libk/src/alloc.rs @@ -0,0 +1,3 @@ +pub mod allocator; + +pub use self::allocator::init_heap; diff --git a/libk/src/alloc/allocator.rs b/libk/src/alloc/allocator.rs new file mode 100644 index 0000000..31547ed --- /dev/null +++ b/libk/src/alloc/allocator.rs @@ -0,0 +1,45 @@ +use linked_list_allocator::LockedHeap; +use x86_64::{ + structures::paging::{ + mapper::MapToError, FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB, + }, + VirtAddr, +}; + +/// We are currently using a linked list heap allocator which uses our underlying page allocator. +pub type FoundryAllocator = LockedHeap; + +#[global_allocator] +/// This is now Rust's global allocator, so we can use stuff requiring heap allocations. +static ALLOCATOR: FoundryAllocator = FoundryAllocator::empty(); + +pub const HEAP_START: usize = 0x4444_4444_0000; +pub const HEAP_SIZE: usize = 1000 * 1024; + +/// Sets up the heap using the backing page frame allocator. +pub fn init_heap( + mapper: &mut impl Mapper, + frame_allocator: &mut impl FrameAllocator, +) -> Result<(), MapToError> { + let range = { + let heap_start = VirtAddr::new(HEAP_START as u64); + let heap_end = heap_start + HEAP_SIZE as u64 - 1u64; + let heap_start_page = Page::::containing_address(heap_start); + let heap_end_page = Page::::containing_address(heap_end); + Page::range_inclusive(heap_start_page, heap_end_page) + }; + + for page in range { + let frame = frame_allocator + .allocate_frame() + .ok_or(MapToError::FrameAllocationFailed)?; + let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE; + unsafe { mapper.map_to(page, frame, flags, frame_allocator)?.flush() }; + } + + unsafe { + ALLOCATOR.lock().init(HEAP_START as *mut u8, HEAP_SIZE); + } + + Ok(()) +} diff --git a/libk/src/io.rs b/libk/src/io.rs new file mode 100644 index 0000000..a1bd4a0 --- /dev/null +++ b/libk/src/io.rs @@ -0,0 +1,17 @@ +pub mod ascii; +pub mod framebuffer; +pub mod keyboard; +pub mod port; +pub mod serial; + +// Re-exported macro definitions. + +pub use crate::print; +pub use crate::print_log; +pub use crate::printerr; +pub use crate::println; +pub use crate::println_log; +pub use crate::printlnerr; + +pub use crate::serial_print; +pub use crate::serial_println; diff --git a/libk/src/io/ascii.rs b/libk/src/io/ascii.rs new file mode 100644 index 0000000..a75520b --- /dev/null +++ b/libk/src/io/ascii.rs @@ -0,0 +1,210 @@ +use core::fmt; +use spin::{Lazy, Mutex}; +use x86_64::instructions::interrupts; + +pub use super::framebuffer::screensize_px; +use super::framebuffer::{Color, FRAMEBUFFER_WRITER}; + +mod font; +use font::FONT; + +static FONT_WIDTH: u32 = 8; +static FONT_HEIGHT: u32 = 16; + +pub static WRITER: Lazy> = Lazy::new(|| Mutex::new(Writer::new())); + +pub fn screensize_chars() -> (u32, u32) { + let writer = WRITER.lock(); + (writer.screen_width, writer.screen_height) +} + +pub struct Writer { + /// Measured in chars not pixels. + screen_width: u32, + /// Measured in chars not pixels. + screen_height: u32, + /// 16 pixels tall. + text_line: u32, + /// 8 pixels wide. + text_col: u32, + + fg_color: Color, + bg_color: Color, + + offset1: usize, + offset2: usize, +} + +impl Writer { + pub fn new() -> Self { + if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { + Self { + screen_width: writer.width() as u32 / 8, + screen_height: writer.height() as u32 / 16, + text_line: 0, + text_col: 0, + fg_color: Color::White, + bg_color: Color::Black, + offset1: 16, + offset2: 0, + } + } else { + panic!("Framebuffer writer not initialized"); + } + } + + pub fn write_char(&mut self, c: u16) { + if c as u8 == b'\n' { + self.newline(); + return; + } + + // get the character data from the font array. -- each byte is a row of pixels + let data: &[u8] = &FONT[c as usize * 16..(c as usize + 1) * 16]; + + if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { + for row in 0..16 { + let line: u8 = data[row]; + for col in 0..8 { + let pixel_x: u32 = self.text_col * FONT_WIDTH + col; + let pixel_y: u32 = self.text_line * FONT_HEIGHT + row as u32; + + if line & (0x80 >> col) != 0 { + // write the foreground color + writer.write_pixel(pixel_x as usize, pixel_y as usize, self.fg_color); + } else { + // write the background color + writer.write_pixel(pixel_x as usize, pixel_y as usize, self.bg_color); + } + } + } + } + + // go to next position + if self.text_col + 1 >= self.screen_width { + self.newline(); + } else { + self.text_col += 1; + } + } + + pub fn set_offset(&mut self, offset1: usize, offset2: usize) { + self.offset1 = offset1; + self.offset2 = offset2; + } + + pub fn dimensions(&self) -> (u32, u32) { + (self.screen_width, self.screen_height) + } + + pub fn next_char(&mut self) { + self.text_col += 1; + } + + pub fn newline(&mut self) { + self.text_col = 0; + + if self.text_line + 1 >= self.screen_height { + self.text_line = 0; + } else { + self.text_line += 1; + } + } + + pub fn write_string(&mut self, s: &str) { + for c in s.chars() { + self.write_char(c as u16); + } + } + + pub fn set_colour(&mut self, fg: Color, bg: Color) { + self.fg_color = fg; + self.bg_color = bg; + } + + pub fn reset_colour(&mut self) { + self.fg_color = Color::White; + self.bg_color = Color::Black; + } +} + +impl core::fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.write_string(s); + Ok(()) + } +} + +fn write(args: fmt::Arguments, fg: Color, bg: Color) { + use core::fmt::Write; + + interrupts::without_interrupts(|| { + let mut writer = WRITER.lock(); + writer.set_colour(fg, bg); + writer.write_fmt(args).unwrap(); + writer.reset_colour(); + }); +} + +pub fn _print(args: fmt::Arguments) { + x86_64::instructions::interrupts::without_interrupts(|| { + write(args, Color::White, Color::Black); + }) +} + +pub fn _print_err(args: fmt::Arguments) { + x86_64::instructions::interrupts::without_interrupts(|| { + write(args, Color::Red, Color::Black); + }) +} + +pub fn _print_log(args: fmt::Arguments) { + x86_64::instructions::interrupts::without_interrupts(|| { + write(args, Color::Yellow, Color::Black); + }) +} + +pub fn clear_screen() { + interrupts::without_interrupts(|| { + let mut writer = WRITER.lock(); + writer.text_line = 0; + writer.text_col = 0; + + if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { + writer.clear(); + } + }); +} + +#[macro_export] +macro_rules! println_log { + () => ($crate::print_log!("\n")); + ($($arg:tt)*) => ($crate::print_log!("{}\n", format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! print_log { + ($($arg:tt)*) => ($crate::io::ascii::_print_log(format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::io::ascii::_print(format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! printlnerr { + () => ($crate::printerr!("\n")); + ($($arg:tt)*) => ($crate::printerr!("{}\n", format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! printerr { + ($($arg:tt)*) => ($crate::_print_err(format_args!($($arg)*))); +} diff --git a/libk/src/io/ascii/font.rs b/libk/src/io/ascii/font.rs new file mode 100644 index 0000000..6d5ded3 --- /dev/null +++ b/libk/src/io/ascii/font.rs @@ -0,0 +1,578 @@ +pub static FONT: [u8; 288 * 16] = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 0 + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, + 0x00, // 1 + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 2 + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 3 + 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, // 4 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, // 5 + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 6 + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 8 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // 9 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, // 10 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, + 0xff, // 11 + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, + 0x00, // 12 + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 13 + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, + 0x00, // 14 + 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 15 + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, + 0x00, // 16 + 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, + 0x00, // 17 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, // 18 + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, // 19 + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, + 0x00, // 20 + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, + 0x00, // 21 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 22 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 23 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 24 + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, // 25 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 26 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 27 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 28 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 29 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, // 30 + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, // 31 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 32 + 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 33 + 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 34 + 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, + 0x00, // 35 + 0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, + 0x00, // 36 + 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, + 0x00, // 37 + 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 38 + 0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 39 + 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, + 0x00, // 40 + 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, // 41 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 42 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 43 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, + 0x00, // 44 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 45 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 46 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, + 0x00, // 47 + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xd6, 0xd6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, // 48 + 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 49 + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 50 + 0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 51 + 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, + 0x00, // 52 + 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 53 + 0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 54 + 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, + 0x00, // 55 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 56 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, + 0x00, // 57 + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, // 58 + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, + 0x00, // 59 + 0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, + 0x00, // 60 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 61 + 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, + 0x00, // 62 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 63 + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 64 + 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 65 + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, + 0x00, // 66 + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 67 + 0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, + 0x00, // 68 + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 69 + 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, // 70 + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, + 0x00, // 71 + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 72 + 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 73 + 0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, + 0x00, // 74 + 0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, // 75 + 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 76 + 0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 77 + 0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 78 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 79 + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, // 80 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, + 0x00, // 81 + 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, // 82 + 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 83 + 0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 84 + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 85 + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, // 86 + 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0xee, 0x6c, 0x00, 0x00, 0x00, + 0x00, // 87 + 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x7c, 0x38, 0x38, 0x7c, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 88 + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 89 + 0x00, 0x00, 0xfe, 0xc6, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 90 + 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 91 + 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, + 0x00, // 92 + 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 93 + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 94 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, // 95 + 0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 96 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 97 + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 98 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 99 + 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 101 + 0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, // 102 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, + 0x00, // 103 + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, // 104 + 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 105 + 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, + 0x00, // 106 + 0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, + 0x00, // 107 + 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 108 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 109 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, // 110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 111 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, + 0x00, // 112 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, + 0x00, // 113 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, + 0x00, // 114 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 115 + 0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, + 0x00, // 116 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 117 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, // 118 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00, + 0x00, // 119 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, + 0x00, // 121 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 122 + 0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, + 0x00, // 123 + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 124 + 0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, + 0x00, // 125 + 0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 126 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, // 127 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 128 + 0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, // 129 + 0x00, 0x18, 0x18, 0x3c, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3c, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 130 + 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, + 0x00, // 131 + 0x00, 0x00, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 132 + 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, + 0x00, // 133 + 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 134 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 135 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, // 136 + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 137 + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, // 138 + 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 139 + 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, + 0x00, // 140 + 0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, + 0x00, // 141 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 142 + 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 143 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 144 + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xce, 0x9e, 0x3e, 0x06, 0x06, 0x00, + 0x00, // 145 + 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00, + 0x00, // 146 + 0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 147 + 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 148 + 0x38, 0x6c, 0x38, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 149 + 0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, + 0x00, // 150 + 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, + 0x00, // 151 + 0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 152 + 0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 153 + 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 154 + 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 155 + 0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, + 0x00, // 156 + 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 157 + 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 158 + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 159 + 0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 160 + 0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 161 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x76, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, + 0x00, // 162 + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 0x3c, 0x00, 0x00, + 0x00, // 163 + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 164 + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 165 + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 166 + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 167 + 0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 168 + 0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 169 + 0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 170 + 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 171 + 0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, // 172 + 0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 173 + 0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 174 + 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 175 + 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, + 0x00, // 176 + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, // 177 + 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 178 + 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 179 + 0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 180 + 0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 181 + 0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, + 0x00, // 182 + 0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, + 0x00, // 183 + 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, + 0x00, // 184 + 0x00, 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, + 0x00, // 185 + 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 186 + 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 187 + 0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, + 0x00, // 188 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, + 0x00, // 189 + 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 190 + 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, + 0x00, // 191 + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, + 0x00, // 192 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, + 0x00, // 193 + 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 194 + 0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, + 0x00, // 195 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 196 + 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, + 0x00, // 197 + 0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 198 + 0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 199 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 200 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 201 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 202 + 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, + 0x00, // 203 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 204 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, // 205 + 0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 206 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 207 + 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, + 0x00, // 208 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 209 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 210 + 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, + 0x00, // 211 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 212 + 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, // 213 + 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 214 + 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 215 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, // 216 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, // 217 + 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 218 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, + 0x00, // 219 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 220 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 221 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 222 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 223 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 224 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 225 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 226 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 227 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 228 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 229 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 230 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 231 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 232 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 233 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 234 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 235 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 236 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 237 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 238 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 239 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 240 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 241 + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 242 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 243 + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 244 + 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 245 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 246 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 247 + 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 248 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 249 + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 250 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 251 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 252 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 253 + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 254 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 255 + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 256 + 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, // 257 + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 258 + 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, // 259 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // 260 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // 261 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // 262 + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, // 263 + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, // 264 + 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, + 0x44, // 265 + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, + 0xaa, // 266 + 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, + 0x77, // 267 + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, + 0x00, // 268 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, + 0x00, // 269 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, // 270 + 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, + 0x00, // 271 + 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, // 272 + 0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, + 0x00, // 273 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x00, // 274 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, // 275 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, + 0xff, // 276 + 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 277 + 0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, + 0x00, // 278 + 0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 279 + 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, // 280 + 0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, + 0x00, // 281 + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 282 + 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, + 0x00, // 283 + 0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, + 0x00, // 284 + 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, // 285 + 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, + 0x00, // 286 + 0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, + 0x00, // 287 +]; diff --git a/libk/src/io/framebuffer.rs b/libk/src/io/framebuffer.rs new file mode 100644 index 0000000..29cf8e6 --- /dev/null +++ b/libk/src/io/framebuffer.rs @@ -0,0 +1,83 @@ +use limine::request::FramebufferRequest; + +#[used] +#[link_section = ".requests"] +static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); + +mod colour; + +pub use colour::Color; +use core::panic; + +use limine::framebuffer::Framebuffer; +use spin::{Lazy, Mutex}; + +// use crate::{colour::Color, FRAMEBUFFER_REQUEST}; + +pub static FRAMEBUFFER_WRITER: Lazy>> = Lazy::new(|| { + Mutex::new( + if let Some(framebuffer_response) = FRAMEBUFFER_REQUEST.get_response() { + let framebuffer = framebuffer_response.framebuffers().next().unwrap(); + Some(FramebufferWriter::new(framebuffer)) + } else { + panic!("Framebuffer request failed"); + }, + ) +}); + +pub struct FramebufferWriter<'a> { + framebuffer: Framebuffer<'a>, +} + +unsafe impl<'a> Send for FramebufferWriter<'a> {} +unsafe impl<'a> Sync for FramebufferWriter<'a> {} +impl<'a> FramebufferWriter<'a> { + pub fn new(framebuffer: Framebuffer<'a>) -> Self { + Self { framebuffer } + } + + pub fn write_pixel(&self, x: usize, y: usize, color: Color) { + let pitch = self.framebuffer.pitch() as usize; + let bpp = (self.framebuffer.bpp() / 8) as usize; + let pixel_offset = y * pitch + x * bpp; + + unsafe { + *(self.framebuffer.addr().add(pixel_offset) as *mut u32) = color.into(); + } + } + + pub fn render_frame(&self, buffer: &[Color; 1280 * 800]) { + for (y, row) in buffer.chunks(1280).enumerate() { + for (x, pixel) in row.iter().enumerate() { + self.write_pixel(x, y, *pixel); + } + } + } + + pub fn width(&self) -> u32 { + self.framebuffer.width() as u32 + } + + pub fn height(&self) -> u32 { + self.framebuffer.height() as u32 + } + + pub fn clear(&self) { + let width = self.framebuffer.width() as usize; + let height = self.framebuffer.height() as usize; + + for y in 0..height { + for x in 0..width { + self.write_pixel(x, y, Color::Black); + } + } + } +} + +pub fn screensize_px() -> (u32, u32) { + if let Some(writer) = FRAMEBUFFER_WRITER.lock().as_mut() { + (writer.width(), writer.height()) + } else { + (0, 0) + } +} diff --git a/libk/src/io/framebuffer/colour.rs b/libk/src/io/framebuffer/colour.rs new file mode 100644 index 0000000..bc80d80 --- /dev/null +++ b/libk/src/io/framebuffer/colour.rs @@ -0,0 +1,53 @@ +#[repr(u32)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Color { + ARGB(u8, u8, u8, u8), + RGB(u8, u8, u8), + HexARGB(u32), + Black = 0x000000FF, + Blue = 0x0000FFFF, + Green = 0x00FF00FF, + Cyan = 0x00FFFFFF, + Red = 0xFF0000FF, + Magenta = 0xFF00FFFF, + Yellow = 0xFFFF00FF, + White = 0xFFFFFFFF, +} + +impl Into for Color { + fn into(self) -> u32 { + match self { + Color::ARGB(a, r, g, b) => { + (a as u32) << 24 | (r as u32) << 16 | (g as u32) << 8 | (b as u32) + } + Color::RGB(r, g, b) => (0u32) << 24 | (r as u32) << 16 | (g as u32) << 8 | (b as u32), + Color::HexARGB(hex) => hex, + Color::Black => 0xFF000000, + Color::Blue => 0xFF0000FF, + Color::Green => 0xFF00FF00, + Color::Cyan => 0xFF00FFFF, + Color::Red => 0xFFFF0000, + Color::Magenta => 0xFFFF00FF, + Color::Yellow => 0xFFFFFF00, + Color::White => 0xFFFFFFFF, + } + } +} + +impl core::fmt::Display for Color { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Color::ARGB(r, g, b, a) => write!(f, "RGBA(#{:x}{:x}{:x}{:x})", r, g, b, a), + Color::RGB(r, g, b) => write!(f, "RGB(#{:x}{:x}{:x})", r, g, b), + Color::HexARGB(hex) => write!(f, "Hex(#{:x})", hex), + Color::Black => write!(f, "Black"), + Color::Blue => write!(f, "Blue"), + Color::Green => write!(f, "Green"), + Color::Cyan => write!(f, "Cyan"), + Color::Red => write!(f, "Red"), + Color::Magenta => write!(f, "Magenta"), + Color::Yellow => write!(f, "Yellow"), + Color::White => write!(f, "White"), + } + } +} diff --git a/libk/src/io/keyboard.rs b/libk/src/io/keyboard.rs new file mode 100644 index 0000000..3d2ad1a --- /dev/null +++ b/libk/src/io/keyboard.rs @@ -0,0 +1,90 @@ +extern crate alloc; + +use core::{ + pin::Pin, + task::{Context, Poll}, +}; + +use super::{print, println}; +use crossbeam::queue::ArrayQueue; +use futures_util::{task::AtomicWaker, Stream}; +use spin::Once; + +static KBD_QUEUE: Once> = Once::new(); +static WAKER: AtomicWaker = AtomicWaker::new(); + +pub fn add_scancode(scancode: u8) { + if let Some(queue) = KBD_QUEUE.get() { + if let Err(_) = queue.push(scancode) { + println!("WARNING: scancode queue full; dropping keyboard input"); + } else { + println!("waking waker"); + WAKER.wake(); + } + } else { + println!("WARNING: scancode queue not initialised"); + } +} + +pub struct ScanCodeStream { + _private: (), +} + +impl ScanCodeStream { + pub fn new() -> Self { + KBD_QUEUE.call_once(|| ArrayQueue::new(5)); + ScanCodeStream { _private: () } + } +} + +impl Stream for ScanCodeStream { + type Item = u8; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let queue = KBD_QUEUE.get().expect("scancode queue not initialized"); + print!("polling or smth"); + + // fast path + if let Some(scancode) = queue.pop() { + return Poll::Ready(Some(scancode)); + } + + WAKER.register(&cx.waker()); + match queue.pop() { + Some(scancode) => { + print!("scancode found"); + WAKER.take(); + Poll::Ready(Some(scancode)) + } + None => { + print!("returning"); + Poll::Pending + } + } + } +} + +use futures_util::stream::StreamExt; +use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1}; + +pub async fn print_keypresses() { + let mut scancodes = ScanCodeStream::new(); + let mut keyboard = Keyboard::new( + ScancodeSet1::new(), + layouts::Us104Key, + HandleControl::Ignore, + ); + + println!("OK!!!"); + + while let Some(scancode) = scancodes.next().await { + if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { + if let Some(key) = keyboard.process_keyevent(key_event) { + match key { + DecodedKey::Unicode(character) => print!("{}", character), + DecodedKey::RawKey(key) => print!("{:?}", key), + } + } + } + } +} diff --git a/libk/src/io/port.rs b/libk/src/io/port.rs new file mode 100644 index 0000000..860058d --- /dev/null +++ b/libk/src/io/port.rs @@ -0,0 +1,25 @@ +//! Functions for IO using ports. + +use core::arch::asm; + +#[inline] +pub unsafe fn inb(port: u16) -> u8 { + let value: u8; + asm!( + "in al, dx", + out("al") value, + in("dx") port, + options(nomem, nostack, preserves_flags) + ); + value +} + +#[inline] +pub unsafe fn outb(port: u16, value: u8) { + asm!( + "out dx, al", + in("dx") port, + in("al") value, + options(nomem, nostack, preserves_flags) + ); +} diff --git a/libk/src/io/serial.rs b/libk/src/io/serial.rs new file mode 100644 index 0000000..2d5d674 --- /dev/null +++ b/libk/src/io/serial.rs @@ -0,0 +1,159 @@ +use core::{ + fmt, + sync::atomic::{AtomicUsize, Ordering}, +}; +use spin::{Lazy, Mutex}; + +#[macro_export] +macro_rules! serial_println { + () => ($crate::serial_print!("\n")); + ($($arg:tt)*) => ($crate::io::serial_print!("{}\n", format_args!($($arg)*))); +} + +#[macro_export] +macro_rules! serial_print { + ($($arg:tt)*) => ($crate::io::serial::_serial_write(format_args!($($arg)*))); +} + +use super::port::{inb, outb}; + +use x86_64::instructions::interrupts; + +pub fn _serial_write(args: fmt::Arguments) { + use core::fmt::Write; + + interrupts::without_interrupts(|| { + if let Some(writer) = WRITER.lock().as_mut() { + writer.write_fmt(args).unwrap(); + } + }) +} + +pub fn serial_read() -> &'static str { + serial_println!("getting value!"); + + interrupts::without_interrupts(|| { + if let Some(reader) = READER.lock().as_mut() { + serial_println!("stuff happnin."); + reader.read_str_to_buffer(); + } else { + serial_println!("failed to get writer"); + } + }); + + serial_println!("eee"); + + let i = BUFFER_LEN.load(Ordering::SeqCst); + + return unsafe { + if i != 0 { + core::str::from_utf8(&BUFFER[..i - 1]).unwrap() + } else { + serial_println!("empty string"); + "" + } + }; +} + +static PORT: u16 = 0x3f8; +static mut BUFFER: [u8; 256] = [0; 256]; +static BUFFER_LEN: AtomicUsize = AtomicUsize::new(0); + +static READER: Lazy>> = Lazy::new(|| Mutex::new(None)); +static WRITER: Lazy>> = Lazy::new(|| Mutex::new(None)); + +struct Reader; + +struct Writer; + +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.chars() { + self.write_byte(c as u8); + } + Ok(()) + } +} + +impl Writer { + unsafe fn write_success(&self) -> bool { + inb(PORT + 5) & 0x20 != 0 + } + + pub fn write_byte(&self, data: u8) { + unsafe { + while !self.write_success() {} + outb(PORT + 0, data); + } + } +} + +pub fn init() -> Result<(), &'static str> { + if let Err(e) = test() { + return Err(e); + } + + if READER.lock().is_none() { + *READER.lock() = Some(Reader); + } + + if WRITER.lock().is_none() { + *WRITER.lock() = Some(Writer); + } + + Ok(()) +} + +pub fn test() -> Result<(), &'static str> { + unsafe { + outb(PORT + 1, 0x00); // Disable all interrupts + outb(PORT + 3, 0x80); // Enable DLAB (set baud rate divisor) + outb(PORT + 0, 0x03); // Set divisor to 3 (lo byte) 38400 baud + outb(PORT + 1, 0x00); // (hi byte) + outb(PORT + 3, 0x03); // 8 bits, no parity, one stop bit + outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-bytethreshold + outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set + outb(PORT + 4, 0x1E); // Set in loopback mode, test the serial chip + outb(PORT + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte) + + if inb(PORT + 0) != 0xAE { + return Err("serial test failed"); + } + + outb(PORT + 4, 0x0F); + } + + Ok(()) +} + +impl Reader { + pub fn read_str_to_buffer(&mut self) { + unsafe { + while !self.read_ready() {} + + BUFFER_LEN.store(0, Ordering::SeqCst); + + while BUFFER_LEN.load(Ordering::SeqCst) < 256 { + let c = self.read(); + BUFFER[BUFFER_LEN.load(Ordering::SeqCst)] = c; + if c as char == '\r' { + break; + } + BUFFER_LEN.fetch_add(1, Ordering::SeqCst); + } + + serial_println!("returning") + } + } + + unsafe fn read_ready(&self) -> bool { + inb(PORT + 5) & 1 != 0 + } + + pub fn read(&self) -> u8 { + unsafe { + while !self.read_ready() {} + return inb(PORT + 0); + } + } +} diff --git a/libk/src/lib.rs b/libk/src/lib.rs new file mode 100644 index 0000000..dfcc3ba --- /dev/null +++ b/libk/src/lib.rs @@ -0,0 +1,15 @@ +#![no_std] + +// alloc +// io : serial, framebuffer, ascii(?), keyboard +// ????? +// scheduling / tasks : async + +pub mod alloc; +pub mod io; +pub mod scheduling; + +/// Re-exports most of the IO macros. +pub mod prelude { + pub use crate::{print_log, println, println_log, serial_print, serial_println}; +} diff --git a/libk/src/scheduling.rs b/libk/src/scheduling.rs new file mode 100644 index 0000000..cdafe4a --- /dev/null +++ b/libk/src/scheduling.rs @@ -0,0 +1 @@ +pub mod task; diff --git a/libk/src/scheduling/task.rs b/libk/src/scheduling/task.rs new file mode 100644 index 0000000..844b873 --- /dev/null +++ b/libk/src/scheduling/task.rs @@ -0,0 +1,133 @@ +extern crate alloc; +use alloc::{boxed::Box, collections::BTreeMap, sync::Arc, task::Wake}; +use core::{ + future::Future, + pin::Pin, + sync::atomic::{AtomicU64, Ordering}, + task::{Context, Poll, Waker}, +}; +use crossbeam::queue::ArrayQueue; + +pub struct Task { + id: TaskId, + future: Pin>>, +} + +impl Task { + pub fn new(future: impl Future + 'static) -> Task { + Task { + id: TaskId::new(), + future: Box::pin(future), + } + } + + fn poll(&mut self, context: &mut Context) -> Poll<()> { + self.future.as_mut().poll(context) + } +} + +pub struct Executor { + tasks: BTreeMap, + task_queue: Arc>, + waker_cache: BTreeMap, +} + +impl Executor { + pub fn new() -> Self { + Executor { + tasks: BTreeMap::new(), + task_queue: Arc::new(ArrayQueue::new(100)), + waker_cache: BTreeMap::new(), + } + } + + pub fn spawn(&mut self, task: Task) { + let task_id = task.id; + if self.tasks.insert(task.id, task).is_some() { + panic!("a task with this id has already been allocated"); + } + self.task_queue.push(task_id).expect("task queue is full"); + } + + fn run_ready_tasks(&mut self) { + let Self { + tasks, + task_queue, + waker_cache, + } = self; + + while let Some(task_id) = task_queue.pop() { + let task = match tasks.get_mut(&task_id) { + Some(task) => task, + None => continue, + }; + let waker = waker_cache + .entry(task_id) + .or_insert_with(|| TaskWaker::new(task_id, task_queue.clone())); + let mut context = Context::from_waker(waker); + match task.poll(&mut context) { + Poll::Ready(()) => { + tasks.remove(&task_id); + waker_cache.remove(&task_id); + } + Poll::Pending => {} + } + } + } + + pub fn try_run(&mut self) { + self.run_ready_tasks(); + self.sleep_if_idle(); + } + + fn sleep_if_idle(&self) { + use x86_64::instructions::interrupts::{self, enable_and_hlt}; + + interrupts::disable(); + if self.task_queue.is_empty() { + enable_and_hlt(); + } else { + interrupts::enable(); + } + } +} + +struct TaskWaker { + task_id: TaskId, + task_queue: Arc>, +} + +impl TaskWaker { + fn new(task_id: TaskId, task_queue: Arc>) -> Waker { + Waker::from(Arc::new(TaskWaker { + task_id, + task_queue, + })) + } + + fn wake_task(&self) { + self.task_queue + .push(self.task_id) + .expect("task queue is full!"); + } +} + +impl Wake for TaskWaker { + fn wake(self: Arc) { + self.wake_task(); + } + + fn wake_by_ref(self: &Arc) { + self.wake_task(); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +struct TaskId(u64); + +impl TaskId { + fn new() -> Self { + static NEXT: AtomicU64 = AtomicU64::new(0); + TaskId(NEXT.fetch_add(1, Ordering::Relaxed)) + } +}