Compare commits

...

10 Commits

54 changed files with 5210 additions and 976 deletions

6
.clang-format Normal file
View File

@ -0,0 +1,6 @@
BasedOnStyle: LLVM
IndentWidth: 4
ContinuationIndentWidth: 4
TabWidth: 4
UseTab: Never
BreakBeforeBraces: Attach

2
.gitignore vendored
View File

@ -9,9 +9,11 @@ tools/*
user/* user/*
!user/*.* !user/*.*
user/*.o user/*.o
snake/snake
.idea .idea
cmake-build-debug cmake-build-debug
CMakeLists.txt CMakeLists.txt
__pycache__ __pycache__
res.txt res.txt
vibing.txt

View File

@ -44,7 +44,9 @@ OBJECTS = ./kernel/kstart.o ./kernel.o ./console.o ./drivers/vga.o ./drivers/uar
./fs/fs.o ./drivers/ata.o ./lib/string.o ./proc.o ./drivers/pit.o ./kernel/vm.o ./fs/fs.o ./drivers/ata.o ./lib/string.o ./proc.o ./drivers/pit.o ./kernel/vm.o
run: image.bin run: image.bin
qemu-system-i386 -drive format=raw,file=$< -serial mon:stdio -qmp unix:qemu-monitor-socket,server,nowait qemu-system-i386 -drive format=raw,file=$< -serial mon:stdio -qmp unix:qemu-monitor-socket,server,nowait \
-audiodev pa,id=SAUND \
-machine pcspk-audiodev=SAUND
run-nox: image.bin run-nox: image.bin
qemu-system-i386 -nographic -drive format=raw,file=$< -serial mon:stdio -qmp unix:qemu-monitor-socket,server,nowait qemu-system-i386 -nographic -drive format=raw,file=$< -serial mon:stdio -qmp unix:qemu-monitor-socket,server,nowait
@ -106,7 +108,7 @@ debug-nox: image.bin
-ex "break _start" \ -ex "break _start" \
-ex "continue" -ex "continue"
USERPROGS=./user/false ./user/greet ./user/div0 ./user/shout ./user/badputs ./user/bss USERPROGS=./user/false ./user/greet ./user/div0 ./user/shout ./user/badputs ./user/bss ./user/player ./user/getc ./snake/snake
fs.img: ./kernel.bin ./tools/mkfs $(USERPROGS) fs.img: ./kernel.bin ./tools/mkfs $(USERPROGS)
./tools/mkfs $@ $< $(USERPROGS) ./tools/mkfs $@ $< $(USERPROGS)
@ -116,6 +118,9 @@ LDFLAGS=-m elf_i386
user/%: user/%.o user/crt.o user/%: user/%.o user/crt.o
$(LD) $(LDFLAGS) -o $@ -Ttext 0x401000 $^ $(LD) $(LDFLAGS) -o $@ -Ttext 0x401000 $^
snake/snake: snake/snake.o user/crt.o
$(LD) $(LDFLAGS) -o $@ -Ttext 0x401000 $^
kernel.bin: $(OBJECTS) kernel.bin: $(OBJECTS)
$(LD) $(LDFLAGS) $(LDKERNELFLAGS) -o $@ -Ttext 0x80009000 $^ $(LD) $(LDFLAGS) $(LDKERNELFLAGS) -o $@ -Ttext 0x80009000 $^

View File

@ -5,8 +5,8 @@
// bootmain() loads an ELF kernel image from the disk starting at // bootmain() loads an ELF kernel image from the disk starting at
// sector 3 and then jumps to the kernel entry routine. // sector 3 and then jumps to the kernel entry routine.
#include "elf.h"
#include "drivers/port.h" #include "drivers/port.h"
#include "elf.h"
#define SECTSIZE 512 #define SECTSIZE 512
@ -19,9 +19,7 @@ inline void stosb(uchar* addr, uchar byte, uint count) {
asm volatile("cld; rep stosb" : "+D"(addr), "+a"(byte) : "c"(count) : "cc"); asm volatile("cld; rep stosb" : "+D"(addr), "+a"(byte) : "c"(count) : "cc");
} }
void void bootmain(void) {
bootmain(void)
{
Elf32_Ehdr *elf; Elf32_Ehdr *elf;
Elf32_Phdr *ph, *eph; Elf32_Phdr *ph, *eph;
void (*entry)(void); void (*entry)(void);
@ -52,27 +50,21 @@ bootmain(void)
entry(); entry();
} }
void void waitdisk(void) {
waitdisk(void)
{
// Wait for disk ready. // Wait for disk ready.
while ((port_byte_in(0x1F7) & 0xC0) != 0x40) while ((port_byte_in(0x1F7) & 0xC0) != 0x40)
; ;
} }
static inline void static inline void insl(int port, void *addr, int cnt) {
insl(int port, void *addr, int cnt) asm volatile("cld; rep insl"
{ : "=D"(addr), "=c"(cnt)
asm volatile("cld; rep insl" : : "d"(port), "0"(addr), "1"(cnt)
"=D" (addr), "=c" (cnt) : : "memory", "cc");
"d" (port), "0" (addr), "1" (cnt) :
"memory", "cc");
} }
// Read a single sector at offset into dst. // Read a single sector at offset into dst.
void void readsect(void *dst, uint offset) {
readsect(void *dst, uint offset)
{
// Issue command. // Issue command.
waitdisk(); waitdisk();
port_byte_out(0x1F2, 1); // count = 1 port_byte_out(0x1F2, 1); // count = 1
@ -89,9 +81,7 @@ readsect(void *dst, uint offset)
// Read 'count' bytes at 'offset' from kernel into physical address 'pa'. // Read 'count' bytes at 'offset' from kernel into physical address 'pa'.
// Might copy more than asked. // Might copy more than asked.
void void readseg(uchar *pa, uint count, uint offset) {
readseg(uchar* pa, uint count, uint offset)
{
uchar *epa; uchar *epa;
epa = pa + count; epa = pa + count;

View File

@ -1,6 +1,6 @@
#include "console.h" #include "console.h"
#include "drivers/vga.h"
#include "drivers/uart.h" #include "drivers/uart.h"
#include "drivers/vga.h"
void printk(const char *msg) { void printk(const char *msg) {
vga_print_string(msg); vga_print_string(msg);

View File

@ -3,4 +3,4 @@
void printk(const char *msg); void printk(const char *msg);
_Noreturn void panic(const char *msg); _Noreturn void panic(const char *msg);
#define check(expr) if (!(expr)) { panic("Assertion failed at " __FILE__ " : " " : " #expr "\n"); } #define check(expr) if (!(expr)) {panic("Assertion failed at " __FILE__ " : " #expr "\n");}

View File

@ -1,8 +1,8 @@
#include "gdt.h" #include "gdt.h"
#include "x86.h"
#include "memlayout.h"
#include "../lib/string.h" #include "../lib/string.h"
#include "kernel/mem.h" #include "kernel/mem.h"
#include "memlayout.h"
#include "x86.h"
#include <stdint.h> #include <stdint.h>
@ -22,14 +22,34 @@ struct seg_desc_t {
uint8_t base_31_24; // High bits of segment base address uint8_t base_31_24; // High bits of segment base address
} __attribute__((packed)); } __attribute__((packed));
#define SEG(type, base, lim, dpl) (struct seg_desc_t) \ #define SEG(type, base, lim, dpl) \
{ ((lim) >> 12) & 0xffff, (uint)(base) & 0xffff, \ (struct seg_desc_t){((lim) >> 12) & 0xffff, \
((uint)(base) >> 16) & 0xff, type, 1, dpl, 1, \ (uint)(base) & 0xffff, \
(uint)(lim) >> 28, 0, 0, 1, 1, (uint)(base) >> 24 } ((uint)(base) >> 16) & 0xff, \
#define SEG16(type, base, lim, dpl) (struct seg_desc_t) \ type, \
{ (lim) & 0xffff, (uint)(base) & 0xffff, \ 1, \
((uint)(base) >> 16) & 0xff, type, 1, dpl, 1, \ dpl, \
(uint)(lim) >> 16, 0, 0, 1, 0, (uint)(base) >> 24 } 1, \
(uint)(lim) >> 28, \
0, \
0, \
1, \
1, \
(uint)(base) >> 24}
#define SEG16(type, base, lim, dpl) \
(struct seg_desc_t){(lim) & 0xffff, \
(uint)(base) & 0xffff, \
((uint)(base) >> 16) & 0xff, \
type, \
1, \
dpl, \
1, \
(uint)(lim) >> 16, \
0, \
0, \
1, \
0, \
(uint)(base) >> 24}
struct seg_desc_t seg_desc[6]; struct seg_desc_t seg_desc[6];

198
cpu/idt.c
View File

@ -1,10 +1,13 @@
#include "isr.h"
#include "gdt.h"
#include "memlayout.h"
#include "../syscall.h"
#include "../proc.h"
#include "../drivers/port.h"
#include "../console.h" #include "../console.h"
#include "../drivers/keyboard.h"
#include "../drivers/pit.h"
#include "../drivers/port.h"
#include "../drivers/vga.h"
#include "../proc.h"
#include "../syscall.h"
#include "gdt.h"
#include "isr.h"
#include "memlayout.h"
enum { enum {
IDT_HANDLERS = 256, IDT_HANDLERS = 256,
@ -118,25 +121,136 @@ void trap(registers_t *r) {
} }
/* takes a ptr that is supposed to be from userspace. If it is not, we /* takes a ptr that is supposed to be from userspace. If it is not, we
* return 0, if it is a valid userspace pointer, we return the usable * return 0, if it is a valid we return 1
* kernelspace pointer
*/ */
uint32_t is_userspace_ptr_mapped(uint32_t ptr) { bool is_userspace_ptr_mapped(uint32_t ptr) {
// todo: implement if (ptr >= KERNBASE) {
return ptr; return 0;
} }
static void* get_userspace_cstr(uint32_t ptr) { pde_t *pgdir = get_user_proc_page_directory();
// todo: implement if (!pgdir) {
return (void*)(ptr); return 0;
} }
static int handle_puts(const char* s) { pde_t pde = pgdir[PDX(ptr)];
if (!s) { if ((pde & (PTE_P | PTE_U)) != (PTE_P | PTE_U)) {
return 0;
}
if (pde & PDE_PS) {
return 0;
}
pte_t *table = (pte_t *)P2V(PTE_ADDR(pde));
pte_t pte = table[PTX(ptr)];
if ((pte & (PTE_P | PTE_U)) != (PTE_P | PTE_U)) {
return 0;
}
return 1;
}
static bool is_userspace_range_mapped(uint32_t ptr, uint32_t size) {
if (size == 0) {
return 1;
}
if (ptr >= KERNBASE) {
return 0;
}
uint32_t end = ptr + size - 1;
if (end < ptr || end >= KERNBASE) {
return 0;
}
uint32_t last_page = PGROUNDDOWN(end);
for (uint32_t addr = ptr;; addr = PGROUNDDOWN(addr) + PGSIZE) {
if (!is_userspace_ptr_mapped(addr)) {
return 0;
}
if (PGROUNDDOWN(addr) == last_page) {
return 1;
}
}
}
static bool is_userspace_cstr(uint32_t ptr) {
for (uint32_t addr = ptr;; addr++) {
if (addr == 0 || !is_userspace_ptr_mapped(addr)) {
return 0;
}
if (*(const char *)addr == '\0') {
return (void *)ptr;
}
}
}
static _Noreturn void userspace_panic(const char *msg) {
if (!vga_is_text_mode()) {
switch_to_text_mode();
vga_clear_screen();
}
printk(msg);
killproc();
}
static void handle_puts(uintptr_t s) {
if (!is_userspace_cstr(s)) {
userspace_panic("SYS_puts panic: page fault\n");
}
printk((const char *)s);
}
static void require_text_mode_for_userspace_text_syscall() {
if (!vga_is_text_mode()) {
userspace_panic("Userspace panic: text syscall in graphics mode\n");
}
}
static void handle_swap_frame(uintptr_t frame) {
enum {
VGA_GRAPHICS_FRAME_SIZE = VGA_GRAPHICS_WIDTH * VGA_GRAPHICS_HEIGHT,
};
if (vga_is_text_mode()) {
userspace_panic("Userspace panic: frame swap in text mode\n");
}
if (!is_userspace_range_mapped(frame, VGA_GRAPHICS_FRAME_SIZE)) {
userspace_panic("SYS_swap_frame panic: page fault\n");
}
uint8_t *video = (uint8_t *)(KERNBASE + 0xA0000);
uint8_t *user = (uint8_t *)frame;
for (uint32_t i = 0; i < VGA_GRAPHICS_FRAME_SIZE; i++) {
video[i] = user[i];
}
}
static void refill_keyboard_copy_buffer(void) {
size_t count = kbd_state_shrd.len;
if (count == 0) {
return;
}
cli();
size_t rem = KEYBOARD_INTERRUPT_BUF_CAP - kbd_state_shrd.copy_len;
size_t copying = rem < count ? rem : count;
memcpy(kbd_state_shrd.copy_buf, kbd_state_shrd.buf, copying);
kbd_state_shrd.len -= copying;
kbd_state_shrd.copy_len += copying;
sti();
}
static int handle_getc(void) {
if (kbd_can_take_from_copy_buffer()) {
return kbd_take_from_copy_buffer();
}
refill_keyboard_copy_buffer();
if (!kbd_can_take_from_copy_buffer()) {
return -1; return -1;
} }
printk(s); return kbd_take_from_copy_buffer();
return 0;
} }
static void handle_syscall(registers_t *r) { static void handle_syscall(registers_t *r) {
@ -149,19 +263,51 @@ static void handle_syscall(registers_t* r) {
} }
killproc(); killproc();
case SYS_greet: case SYS_greet:
require_text_mode_for_userspace_text_syscall();
printk("Hello world!\n"); printk("Hello world!\n");
r->eax = 0; r->eax = 0;
break; break;
case SYS_putc: case SYS_putc:
printk((const char[]){r->ebx, '\0'}); require_text_mode_for_userspace_text_syscall();
printk((const char[]){(char)r->ebx, '\0'});
r->eax = 0; r->eax = 0;
break; break;
case SYS_puts: case SYS_puts:
r->eax = handle_puts(get_userspace_cstr(r->ebx)); require_text_mode_for_userspace_text_syscall();
handle_puts(r->ebx);
r->eax = 0;
break;
case SYS_switch_to_text:
switch_to_text_mode();
r->eax = 0;
break;
case SYS_switch_to_graphics:
switch_to_graphics_mode();
r->eax = 0;
break;
case SYS_swap_frame:
handle_swap_frame(r->ebx);
r->eax = 0;
break;
case SYS_time_ms:
r->eax = get_uptime_ms();
break;
case SYS_halt:
asm volatile("hlt");
r->eax = 0;
break;
case SYS_getc:
r->eax = handle_getc();
break;
case SYS_set_beep:
if (r->ebx > MAX_BEEP_FREQUENCY_HZ) {
userspace_panic("Userspace panic: beep frequency out of range\n");
}
set_beep_frequency_hz(r->ebx);
r->eax = 0;
break; break;
default: default:
printk("Unknown syscall\n"); userspace_panic("Userspace panic: Unknown syscall\n");
r->eax = -1;
} }
} }
@ -206,10 +352,6 @@ void load_idt() {
register_interrupt_handler(T_SYSCALL, handle_syscall); register_interrupt_handler(T_SYSCALL, handle_syscall);
} }
void cli() { void cli() { asm("cli"); }
asm("cli");
}
void sti() { void sti() { asm("sti"); }
asm("sti");
}

View File

@ -30,8 +30,10 @@ enum {
typedef struct { typedef struct {
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */ uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; /* Pushed by pusha. */
uint32_t gs, fs, es, ds; /* Data segment selector */ uint32_t gs, fs, es, ds; /* Data segment selector */
uint32_t int_no, err_code; /* Interrupt number and error code (if applicable) */ uint32_t int_no,
uint32_t eip, cs, eflags, useresp, ss; /* Pushed by the processor automatically */ err_code; /* Interrupt number and error code (if applicable) */
uint32_t eip, cs, eflags, useresp,
ss; /* Pushed by the processor automatically */
} registers_t; } registers_t;
void isr_install(); void isr_install();

View File

@ -1,20 +1,20 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
static inline void static inline void stosl(void *addr, int data, int cnt) {
stosl(void *addr, int data, int cnt) asm volatile("cld; rep stosl"
{ :
asm volatile("cld; rep stosl" : : "D"(addr), "c"(cnt), "a"(data) : "memory"); : "D"(addr), "c"(cnt), "a"(data)
: "memory");
} }
static inline void static inline void stosb(void *addr, unsigned char data, int cnt) {
stosb(void *addr, unsigned char data, int cnt) asm volatile("cld; rep stosb"
{ :
asm volatile("cld; rep stosb" : : "D"(addr), "c"(cnt), "a"(data) : "memory"); : "D"(addr), "c"(cnt), "a"(data)
: "memory");
} }
static inline void static inline void lcr3(uint32_t val) {
lcr3(uint32_t val)
{
asm volatile("mov %0,%%cr3" : : "r"(val)); asm volatile("mov %0,%%cr3" : : "r"(val));
} }

View File

@ -19,8 +19,8 @@
static void ATA_wait_BSY(); static void ATA_wait_BSY();
static void ATA_wait_RDY(); static void ATA_wait_RDY();
void read_sectors_ATA_PIO(void* target_address, uint32_t LBA, uint8_t sector_count) void read_sectors_ATA_PIO(void *target_address, uint32_t LBA,
{ uint8_t sector_count) {
ATA_wait_BSY(); ATA_wait_BSY();
port_byte_out(0x1F6, 0xE0 | ((LBA >> 24) & 0xF)); port_byte_out(0x1F6, 0xE0 | ((LBA >> 24) & 0xF));
port_byte_out(0x1F2, sector_count); port_byte_out(0x1F2, sector_count);
@ -31,8 +31,7 @@ void read_sectors_ATA_PIO(void* target_address, uint32_t LBA, uint8_t sector_cou
uint16_t *target = (uint16_t *)target_address; uint16_t *target = (uint16_t *)target_address;
for (int j = 0; j < sector_count; j++) for (int j = 0; j < sector_count; j++) {
{
ATA_wait_BSY(); ATA_wait_BSY();
ATA_wait_RDY(); ATA_wait_RDY();
for (int i = 0; i < 256; i++) for (int i = 0; i < 256; i++)
@ -41,8 +40,8 @@ void read_sectors_ATA_PIO(void* target_address, uint32_t LBA, uint8_t sector_cou
} }
} }
void write_sectors_ATA_PIO(uint32_t LBA, uint8_t sector_count, uint32_t *bytes) void write_sectors_ATA_PIO(uint32_t LBA, uint8_t sector_count,
{ uint32_t *bytes) {
ATA_wait_BSY(); ATA_wait_BSY();
port_byte_out(0x1F6, 0xE0 | ((LBA >> 24) & 0xF)); port_byte_out(0x1F6, 0xE0 | ((LBA >> 24) & 0xF));
port_byte_out(0x1F2, sector_count); port_byte_out(0x1F2, sector_count);
@ -51,12 +50,10 @@ void write_sectors_ATA_PIO(uint32_t LBA, uint8_t sector_count, uint32_t *bytes)
port_byte_out(0x1F5, (uint8_t)(LBA >> 16)); port_byte_out(0x1F5, (uint8_t)(LBA >> 16));
port_byte_out(0x1F7, 0x30); // Send the write command port_byte_out(0x1F7, 0x30); // Send the write command
for (int j = 0; j < sector_count; j++) for (int j = 0; j < sector_count; j++) {
{
ATA_wait_BSY(); ATA_wait_BSY();
ATA_wait_RDY(); ATA_wait_RDY();
for (int i = 0; i < 256; i++) for (int i = 0; i < 256; i++) {
{
port_long_out(0x1F0, bytes[i]); port_long_out(0x1F0, bytes[i]);
} }
} }

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
void read_sectors_ATA_PIO(void* target_address, uint32_t LBA, uint8_t sector_count); void read_sectors_ATA_PIO(void *target_address, uint32_t LBA,
uint8_t sector_count);

View File

@ -4,287 +4,408 @@
borrowed bits from http://files.osdev.org/mirrors/geezer/osd/graphics/modes.c borrowed bits from http://files.osdev.org/mirrors/geezer/osd/graphics/modes.c
*/ */
#include "cpu/x86.h"
#include "cpu/memlayout.h" #include "cpu/memlayout.h"
#include "cpu/x86.h"
#include "port.h" #include "port.h"
#include "vga.h"
static inline char inb(int port) { static vga_display_mode_t current_display_mode = VGA_DISPLAY_MODE_TEXT;
return port_byte_in(port);
}
static inline void outb(int port, char data) { static inline char inb(int port) { return port_byte_in(port); }
port_byte_out(port, data);
}
/* This is the standard 256-color palette, in 0xRRGGBB format. Of course the VGA registers want 6 bits, not 8 per channel, so we do a bit static inline void outb(int port, char data) { port_byte_out(port, data); }
of shifting when setting the registers: much easier than writing down the values in 6-bit form!
/* This is the standard 256-color palette, in 0xRRGGBB format. Of course the VGA
registers want 6 bits, not 8 per channel, so we do a bit of shifting when
setting the registers: much easier than writing down the values in 6-bit
form!
*/ */
int vga256_24bit[256] = { 0x000000, 0x0000a8, 0x00a800, 0x00a8a8, 0xa80000, 0xa800a8, 0xa85400, 0xa8a8a8, 0x545454, 0x5454fc, 0x54fc54, 0x54fcfc, 0xfc5454, 0xfc54fc, 0xfcfc54, 0xfcfcfc, 0x000000, 0x141414, 0x202020, 0x2c2c2c, 0x383838, 0x444444, 0x505050, 0x606060, 0x707070, 0x808080, 0x909090, 0xa0a0a0, 0xb4b4b4, 0xc8c8c8, 0xe0e0e0, 0xfcfcfc, 0x0000fc, 0x4000fc, 0x7c00fc, 0xbc00fc, 0xfc00fc, 0xfc00bc, 0xfc007c, 0xfc0040, 0xfc0000, 0xfc4000, 0xfc7c00, 0xfcbc00, 0xfcfc00, 0xbcfc00, 0x7cfc00, 0x40fc00, 0x00fc00, 0x00fc40, 0x00fc7c, 0x00fcbc, 0x00fcfc, 0x00bcfc, 0x007cfc, 0x0040fc, 0x7c7cfc, 0x9c7cfc, 0xbc7cfc, 0xdc7cfc, 0xfc7cfc, 0xfc7cdc, 0xfc7cbc, 0xfc7c9c, 0xfc7c7c, 0xfc9c7c, 0xfcbc7c, 0xfcdc7c, 0xfcfc7c, 0xdcfc7c, 0xbcfc7c, 0x9cfc7c, 0x7cfc7c, 0x7cfc9c, 0x7cfcbc, 0x7cfcdc, 0x7cfcfc, 0x7cdcfc, 0x7cbcfc, 0x7c9cfc, 0xb4b4fc, 0xc4b4fc, 0xd8b4fc, 0xe8b4fc, 0xfcb4fc, 0xfcb4e8, 0xfcb4d8, 0xfcb4c4, 0xfcb4b4, 0xfcc4b4, 0xfcd8b4, 0xfce8b4, 0xfcfcb4, 0xe8fcb4, 0xd8fcb4, 0xc4fcb4, 0xb4fcb4, 0xb4fcc4, 0xb4fcd8, 0xb4fce8, 0xb4fcfc, 0xb4e8fc, 0xb4d8fc, 0xb4c4fc, 0x000070, 0x1c0070, 0x380070, 0x540070, 0x700070, 0x700054, 0x700038, 0x70001c, 0x700000, 0x701c00, 0x703800, 0x705400, 0x707000, 0x547000, 0x387000, 0x1c7000, 0x007000, 0x00701c, 0x007038, 0x007054, 0x007070, 0x005470, 0x003870, 0x001c70, 0x383870, 0x443870, 0x543870, 0x603870, 0x703870, 0x703860, 0x703854, 0x703844, 0x703838, 0x704438, 0x705438, 0x706038, 0x707038, 0x607038, 0x547038, 0x447038, 0x387038, 0x387044, 0x387054, 0x387060, 0x387070, 0x386070, 0x385470, 0x384470, 0x505070, 0x585070, 0x605070, 0x685070, 0x705070, 0x705068, 0x705060, 0x705058, 0x705050, 0x705850, 0x706050, 0x706850, 0x707050, 0x687050, 0x607050, 0x587050, 0x507050, 0x507058, 0x507060, 0x507068, 0x507070, 0x506870, 0x506070, 0x505870, 0x000040, 0x100040, 0x200040, 0x300040, 0x400040, 0x400030, 0x400020, 0x400010, 0x400000, 0x401000, 0x402000, 0x403000, 0x404000, 0x304000, 0x204000, 0x104000, 0x004000, 0x004010, 0x004020, 0x004030, 0x004040, 0x003040, 0x002040, 0x001040, 0x202040, 0x282040, 0x302040, 0x382040, 0x402040, 0x402038, 0x402030, 0x402028, 0x402020, 0x402820, 0x403020, 0x403820, 0x404020, 0x384020, 0x304020, 0x284020, 0x204020, 0x204028, 0x204030, 0x204038, 0x204040, 0x203840, 0x203040, 0x202840, 0x2c2c40, 0x302c40, 0x342c40, 0x3c2c40, 0x402c40, 0x402c3c, 0x402c34, 0x402c30, 0x402c2c, 0x40302c, 0x40342c, 0x403c2c, 0x40402c, 0x3c402c, 0x34402c, 0x30402c, 0x2c402c, 0x2c4030, 0x2c4034, 0x2c403c, 0x2c4040, 0x2c3c40, 0x2c3440, 0x2c3040, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000 }; int vga256_24bit[256] = {
0x000000, 0x0000a8, 0x00a800, 0x00a8a8, 0xa80000, 0xa800a8, 0xa85400,
0xa8a8a8, 0x545454, 0x5454fc, 0x54fc54, 0x54fcfc, 0xfc5454, 0xfc54fc,
/* VGA fonts aren't actually stored in the graphics card, they disappear when you change modes, 0xfcfc54, 0xfcfcfc, 0x000000, 0x141414, 0x202020, 0x2c2c2c, 0x383838,
so we have to keep one here to restore when we switch back to text mode. */ 0x444444, 0x505050, 0x606060, 0x707070, 0x808080, 0x909090, 0xa0a0a0,
static unsigned char g_8x16_font[4096] = 0xb4b4b4, 0xc8c8c8, 0xe0e0e0, 0xfcfcfc, 0x0000fc, 0x4000fc, 0x7c00fc,
{ 0xbc00fc, 0xfc00fc, 0xfc00bc, 0xfc007c, 0xfc0040, 0xfc0000, 0xfc4000,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc7c00, 0xfcbc00, 0xfcfc00, 0xbcfc00, 0x7cfc00, 0x40fc00, 0x00fc00,
0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00fc40, 0x00fc7c, 0x00fcbc, 0x00fcfc, 0x00bcfc, 0x007cfc, 0x0040fc,
0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x7c7cfc, 0x9c7cfc, 0xbc7cfc, 0xdc7cfc, 0xfc7cfc, 0xfc7cdc, 0xfc7cbc,
0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0xfc7c9c, 0xfc7c7c, 0xfc9c7c, 0xfcbc7c, 0xfcdc7c, 0xfcfc7c, 0xdcfc7c,
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbcfc7c, 0x9cfc7c, 0x7cfc7c, 0x7cfc9c, 0x7cfcbc, 0x7cfcdc, 0x7cfcfc,
0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x99, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x7cdcfc, 0x7cbcfc, 0x7c9cfc, 0xb4b4fc, 0xc4b4fc, 0xd8b4fc, 0xe8b4fc,
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0xfcb4fc, 0xfcb4e8, 0xfcb4d8, 0xfcb4c4, 0xfcb4b4, 0xfcc4b4, 0xfcd8b4,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfce8b4, 0xfcfcb4, 0xe8fcb4, 0xd8fcb4, 0xc4fcb4, 0xb4fcb4, 0xb4fcc4,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xb4fcd8, 0xb4fce8, 0xb4fcfc, 0xb4e8fc, 0xb4d8fc, 0xb4c4fc, 0x000070,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c0070, 0x380070, 0x540070, 0x700070, 0x700054, 0x700038, 0x70001c,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x700000, 0x701c00, 0x703800, 0x705400, 0x707000, 0x547000, 0x387000,
0x00, 0x00, 0x1E, 0x0E, 0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00, 0x1c7000, 0x007000, 0x00701c, 0x007038, 0x007054, 0x007070, 0x005470,
0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x003870, 0x001c70, 0x383870, 0x443870, 0x543870, 0x603870, 0x703870,
0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30, 0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x703860, 0x703854, 0x703844, 0x703838, 0x704438, 0x705438, 0x706038,
0x00, 0x00, 0x7F, 0x63, 0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00, 0x707038, 0x607038, 0x547038, 0x447038, 0x387038, 0x387044, 0x387054,
0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x387060, 0x387070, 0x386070, 0x385470, 0x384470, 0x505070, 0x585070,
0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x605070, 0x685070, 0x705070, 0x705068, 0x705060, 0x705058, 0x705050,
0x00, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x705850, 0x706050, 0x706850, 0x707050, 0x687050, 0x607050, 0x587050,
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x507050, 0x507058, 0x507060, 0x507068, 0x507070, 0x506870, 0x506070,
0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x505870, 0x000040, 0x100040, 0x200040, 0x300040, 0x400040, 0x400030,
0x00, 0x00, 0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x400020, 0x400010, 0x400000, 0x401000, 0x402000, 0x403000, 0x404000,
0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x304000, 0x204000, 0x104000, 0x004000, 0x004010, 0x004020, 0x004030,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x004040, 0x003040, 0x002040, 0x001040, 0x202040, 0x282040, 0x302040,
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x382040, 0x402040, 0x402038, 0x402030, 0x402028, 0x402020, 0x402820,
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x403020, 0x403820, 0x404020, 0x384020, 0x304020, 0x284020, 0x204020,
0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x204028, 0x204030, 0x204038, 0x204040, 0x203840, 0x203040, 0x202840,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c2c40, 0x302c40, 0x342c40, 0x3c2c40, 0x402c40, 0x402c3c, 0x402c34,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x402c30, 0x402c2c, 0x40302c, 0x40342c, 0x403c2c, 0x40402c, 0x3c402c,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34402c, 0x30402c, 0x2c402c, 0x2c4030, 0x2c4034, 0x2c403c, 0x2c4040,
0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c3c40, 0x2c3440, 0x2c3040, 0x000000, 0x000000, 0x000000, 0x000000,
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x000000, 0x000000, 0x000000, 0x000000};
0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x86, 0xC6, 0x7C, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18, 0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xCE, 0xD6, 0xD6, 0xE6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xFC, 0x0E, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE, 0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF8, 0x6C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xE6, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x0C, 0x0E, 0x00, 0x00,
0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x6C, 0x38, 0x38, 0x6C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xE0, 0x60, 0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0xDC, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00,
0x00, 0x00, 0xE0, 0x60, 0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00,
0x00, 0x00, 0xE0, 0x60, 0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60, 0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00,
0x00, 0x00, 0xCC, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x6C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xCC, 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x38, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06, 0x3C, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x3C, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xC6, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x38, 0x6C, 0x38, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36, 0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3E, 0x6C, 0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00,
0x00, 0xC6, 0xC6, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x18, 0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0xF8, 0xCC, 0xCC, 0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0x70, 0x00, 0x00,
0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x76, 0xDC, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xCE, 0x93, 0x06, 0x0C, 0x1F, 0x00, 0x00,
0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xCE, 0x9A, 0x3F, 0x06, 0x0F, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xC6, 0xFC, 0xC6, 0xC6, 0xFC, 0xC0, 0xC0, 0xC0, 0x00, 0x00,
0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xCF, 0xDB, 0xF3, 0x7E, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0F, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00,
0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x70, 0x98, 0x30, 0x60, 0xC8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/* VGA fonts aren't actually stored in the graphics card, they disappear when
you change modes, so we have to keep one here to restore when we switch back
to text mode. */
static unsigned char g_8x16_font[4096] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD,
0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xFF,
0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7C, 0xFE,
0x7C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
0x3C, 0x3C, 0xE7, 0xE7, 0xE7, 0x99, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x18, 0x18, 0x3C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0x99, 0xBD,
0xBD, 0x99, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x1E, 0x0E,
0x1A, 0x32, 0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x33, 0x3F, 0x30, 0x30, 0x30,
0x30, 0x70, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x63,
0x7F, 0x63, 0x63, 0x63, 0x63, 0x67, 0xE7, 0xE6, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0xDB, 0x3C, 0xE7, 0x3C, 0xDB, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFE, 0xF8,
0xF0, 0xE0, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0E,
0x1E, 0x3E, 0xFE, 0x3E, 0x1E, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDB,
0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xC6, 0x60, 0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x38, 0x0C, 0xC6,
0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFE, 0xFE, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C,
0x7E, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x7E, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC0,
0xC0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x28, 0x6C, 0xFE, 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7C, 0x7C, 0xFE, 0xFE, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x7C, 0x7C,
0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C,
0x6C, 0xFE, 0x6C, 0x6C, 0x6C, 0xFE, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x7C, 0xC6, 0xC2, 0xC0, 0x7C, 0x06, 0x86, 0xC6, 0x7C, 0x18,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xC6, 0x0C, 0x18,
0x30, 0x60, 0xC6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C,
0x6C, 0x38, 0x76, 0xDC, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E,
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xCE, 0xD6, 0xD6, 0xE6, 0xC6, 0xC6, 0x7C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x3C, 0x6C, 0xCC, 0xFE,
0x0C, 0x0C, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0,
0xC0, 0xC0, 0xFC, 0x0E, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x60, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0x06, 0x06, 0x0C, 0x18,
0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x0C, 0x78,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00,
0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0x0C, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xDE, 0xDE,
0xDE, 0xDC, 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0xC2, 0xC0, 0xC0, 0xC0,
0xC0, 0xC2, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x6C,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68,
0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66,
0xC2, 0xC0, 0xC0, 0xDE, 0xC6, 0xC6, 0x66, 0x3A, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x0C,
0x0C, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0xCC, 0x78, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xE6, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0xE6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x60, 0x60,
0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE,
0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6, 0xC6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66,
0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C,
0x0C, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x6C,
0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6,
0xC6, 0x60, 0x38, 0x0C, 0x06, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7E, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x6C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x6C, 0x38, 0x38,
0x6C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66,
0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFE, 0xC6, 0x86, 0x0C, 0x18, 0x30, 0x60, 0xC2, 0xC6, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C,
0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C,
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x60,
0x60, 0x78, 0x6C, 0x66, 0x66, 0x66, 0x66, 0xDC, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0C, 0x0C, 0x3C, 0x6C, 0xCC,
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xF0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xCC, 0xCC,
0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xCC, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x60,
0x60, 0x6C, 0x76, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0E, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0xE0, 0x60,
0x60, 0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFE, 0xD6,
0xD6, 0xD6, 0xD6, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66,
0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x76, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0x0C, 0x1E, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x76, 0x62, 0x60, 0x60, 0x60, 0xF0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x60,
0x38, 0x0C, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
0x30, 0xFC, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC6, 0xC6, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFE, 0xCC, 0x18, 0x30, 0x60, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0E, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0E,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
0x18, 0x18, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0xC6,
0xC6, 0xC6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x66,
0xC2, 0xC0, 0xC0, 0xC0, 0xC2, 0x66, 0x3C, 0x0C, 0x06, 0x7C, 0x00, 0x00,
0x00, 0x00, 0xCC, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x00, 0x7C, 0xC6, 0xFE,
0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C,
0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xCC, 0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76,
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0C, 0x7C,
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38,
0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, 0x0C, 0x06,
0x3C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xFE,
0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6,
0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x30, 0x18, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0xC0, 0xC6, 0x7C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x38, 0x18, 0x18,
0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3C, 0x66,
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0x10, 0x38, 0x6C, 0xC6, 0xC6,
0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x38, 0x00,
0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x18, 0x30, 0x60, 0x00, 0xFE, 0x66, 0x60, 0x7C, 0x60, 0x60, 0x66, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x76, 0x36,
0x7E, 0xD8, 0xD8, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x6C,
0xCC, 0xCC, 0xFE, 0xCC, 0xCC, 0xCC, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x10, 0x38, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0x00, 0x7C, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x76,
0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xCC, 0xCC, 0xCC,
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6,
0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x0C, 0x78, 0x00,
0x00, 0xC6, 0xC6, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0x00, 0xC6, 0xC6, 0xC6, 0xC6,
0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x3C,
0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x6C, 0x64, 0x60, 0xF0, 0x60, 0x60, 0x60, 0x60, 0xE6, 0xFC,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
0x7E, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xCC, 0xCC,
0xF8, 0xC4, 0xCC, 0xDE, 0xCC, 0xCC, 0xCC, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0E, 0x1B, 0x18, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18,
0xD8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0C, 0x7C,
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x30,
0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x30, 0x60, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xCC, 0xCC, 0xCC,
0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC,
0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
0x76, 0xDC, 0x00, 0xC6, 0xE6, 0xF6, 0xFE, 0xDE, 0xCE, 0xC6, 0xC6, 0xC6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C,
0x38, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xC0, 0xC6, 0xC6, 0x7C,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC0,
0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFE, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30, 0x60, 0xCE, 0x93, 0x06,
0x0C, 0x1F, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0xC2, 0xC6, 0xCC, 0x18, 0x30,
0x66, 0xCE, 0x9A, 0x3F, 0x06, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
0x00, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x3C, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x66, 0x33,
0x66, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x55, 0xAA, 0x55, 0xAA, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0xF8,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x06, 0xF6,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0xF8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xF7, 0x00, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xF8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xF0, 0xF0, 0xF0,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x76, 0xDC, 0xD8, 0xD8, 0xD8, 0xDC, 0x76, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xC6, 0xFC, 0xC6, 0xC6, 0xFC, 0xC0,
0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0,
0xC0, 0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFE, 0xC6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xC6, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD8, 0xD8,
0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xC0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x18, 0x3C, 0x66, 0x66,
0x66, 0x3C, 0x18, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
0x6C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x6C, 0x6C, 0x6C, 0xEE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x30, 0x18, 0x0C, 0x3E, 0x66,
0x66, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x06, 0x7E, 0xCF, 0xDB, 0xF3, 0x7E, 0x60, 0xC0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x30, 0x60, 0x60, 0x7C, 0x60,
0x60, 0x60, 0x30, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C,
0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xFE, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18,
0x18, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x7E,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xDC, 0x00,
0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6C, 0x6C,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0C, 0x0C,
0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00,
0x00, 0xD8, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x98, 0x30, 0x60, 0xC8, 0xF8, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
#define VGA 0x3C0 #define VGA 0x3C0
@ -296,9 +417,7 @@ void write3C0(unsigned char index, unsigned char value) {
outb(0x3C0, value); outb(0x3C0, value);
} }
void write3C2(unsigned char value) { void write3C2(unsigned char value) { outb(0x3C2, value); }
outb(0x3C2, value);
}
void write3C4(unsigned char index, unsigned char value) { void write3C4(unsigned char index, unsigned char value) {
outb(0x3C4, index); outb(0x3C4, index);
@ -315,9 +434,7 @@ void write3D4(unsigned char index, unsigned char value) {
outb(0x3D5, value); outb(0x3D5, value);
} }
void write3C6(unsigned char value) { void write3C6(unsigned char value) { outb(0x3C6, value); }
outb(0x3C6,value);
}
void vgaSetPalette(int index, int r, int g, int b) { void vgaSetPalette(int index, int r, int g, int b) {
outb(0x3C8, index); outb(0x3C8, index);
@ -329,9 +446,7 @@ void vgaSetPalette(int index, int r, int g, int b) {
void setdefaultVGApalette() { void setdefaultVGApalette() {
for (int index = 0; index < 256; index++) { for (int index = 0; index < 256; index++) {
int value = vga256_24bit[index]; int value = vga256_24bit[index];
vgaSetPalette(index, vgaSetPalette(index, (value >> 18) & 0x3f, (value >> 10) & 0x3f,
(value>>18)&0x3f,
(value>>10)&0x3f,
(value >> 2) & 0x3f); (value >> 2) & 0x3f);
} }
} }
@ -351,7 +466,6 @@ void vgaMode13() {
// see http://www.osdever.net/FreeVGA/vga/crtcreg.htm#11 // see http://www.osdever.net/FreeVGA/vga/crtcreg.htm#11
write3D4(0x11, 0x0E); write3D4(0x11, 0x0E);
write3D4(0x00, 0x5F); write3D4(0x00, 0x5F);
write3D4(0x01, 0x4F); write3D4(0x01, 0x4F);
write3D4(0x02, 0x50); write3D4(0x02, 0x50);
@ -410,6 +524,7 @@ void vgaMode13() {
outb(0x3C0, 0x20); outb(0x3C0, 0x20);
setdefaultVGApalette(); setdefaultVGApalette();
current_display_mode = VGA_DISPLAY_MODE_GRAPHICS;
} }
void vgaMode3() { void vgaMode3() {
@ -435,7 +550,6 @@ void vgaMode3() {
write3D4(0x06, 0xBF); write3D4(0x06, 0xBF);
write3D4(0x07, 0x1F); write3D4(0x07, 0x1F);
write3D4(0x08, 0x00); write3D4(0x08, 0x00);
write3D4(0x09, 0x4F); write3D4(0x09, 0x4F);
write3D4(0x0A, 0x20); write3D4(0x0A, 0x20);
@ -489,7 +603,6 @@ void vgaMode3() {
write3C0(0x13, 0x08); write3C0(0x13, 0x08);
write3C0(0x14, 0x00); write3C0(0x14, 0x00);
write3C4(0x00, 0x01); // seq reset write3C4(0x00, 0x01); // seq reset
write3C4(0x02, 0x04); // image plane 2 write3C4(0x02, 0x04); // image plane 2
write3C4(0x04, 0x07); // disable odd/even in sequencer write3C4(0x04, 0x07); // disable odd/even in sequencer
@ -518,4 +631,15 @@ void vgaMode3() {
inb(VGA + 0x1A); inb(VGA + 0x1A);
outb(0x3C0, 0x20); outb(0x3C0, 0x20);
current_display_mode = VGA_DISPLAY_MODE_TEXT;
}
void switch_to_graphics_mode() { vgaMode13(); }
void switch_to_text_mode() { vgaMode3(); }
vga_display_mode_t vga_get_display_mode() { return current_display_mode; }
bool vga_is_text_mode() {
return current_display_mode == VGA_DISPLAY_MODE_TEXT;
} }

View File

@ -1,9 +1,9 @@
#include "keyboard.h" #include "keyboard.h"
#include "console.h"
#include "cpu/isr.h" #include "cpu/isr.h"
#include "cpu/memlayout.h" #include "cpu/memlayout.h"
#include "console.h"
#include "port.h"
#include "kernel/mem.h" #include "kernel/mem.h"
#include "port.h"
keyboard_interrupt_shared_t kbd_state_shrd; keyboard_interrupt_shared_t kbd_state_shrd;
@ -14,7 +14,6 @@ static void kbd_interrupt_handler(registers_t *r) {
} }
} }
void init_keyboard() { void init_keyboard() {
kbd_state_shrd.len = 0; kbd_state_shrd.len = 0;
kbd_state_shrd.buf = (uint8_t *)kalloc(); kbd_state_shrd.buf = (uint8_t *)kalloc();
@ -32,16 +31,17 @@ uint8_t kbd_take_from_copy_buffer() {
uint8_t key_event_code = kbd_state_shrd.copy_buf[--kbd_state_shrd.copy_len]; uint8_t key_event_code = kbd_state_shrd.copy_buf[--kbd_state_shrd.copy_len];
uint8_t keycode = (key_event_code & 0x7f); uint8_t keycode = (key_event_code & 0x7f);
if (key_event_code & 0x80) { if (key_event_code & 0x80) {
kbd_state_shrd.copy_pressed[keycode >> 3] = kbd_state_shrd.copy_pressed[keycode >> 3] & (~(1u << (keycode & 0x7))); kbd_state_shrd.copy_pressed[keycode >> 3] =
kbd_state_shrd.copy_pressed[keycode >> 3] &
(~(1u << (keycode & 0x7)));
} else { } else {
kbd_state_shrd.copy_pressed[keycode >> 3] = kbd_state_shrd.copy_pressed[keycode >> 3] | (1u << (keycode & 0x7)); kbd_state_shrd.copy_pressed[keycode >> 3] =
kbd_state_shrd.copy_pressed[keycode >> 3] | (1u << (keycode & 0x7));
} }
return key_event_code; return key_event_code;
} }
bool kbd_can_take_from_copy_buffer() { bool kbd_can_take_from_copy_buffer() { return kbd_state_shrd.copy_len > 0; }
return kbd_state_shrd.copy_len > 0;
}
bool kbd_is_pressed(uint8_t code) { bool kbd_is_pressed(uint8_t code) {
check(code < 128); check(code < 128);
return kbd_state_shrd.copy_pressed[code >> 3] & (1u << (code & 0x7)); return kbd_state_shrd.copy_pressed[code >> 3] & (1u << (code & 0x7));

View File

@ -20,22 +20,22 @@ typedef struct {
/* decoding */ /* decoding */
static const char keysym_mapped_ascii_lower[] = { static const char keysym_mapped_ascii_lower[] = {
0 , 0 , '1', '2', '3', '4', '5', '6', 0, 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0,
'7', '8', '9', '0', '-', '=', 0 , 0 , 'q', 'w', 'e', 'r', 't', 'y', 0, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0,
'u', 'i', 'o', 'p', '[', ']', '\n', 0 , 'a', 's', 'd', 'f', 'g', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z',
'h', 'j', 'k', 'l', ';', '\'', '`', 0 , '\\', 'z', 'x', 'c', 'v', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, ' ',
'b', 'n', 'm', ',', '.', '/', 0 , 0 , 0 , ' ',
}; };
static const char keysym_mapped_ascii_upper[] = { static const char keysym_mapped_ascii_upper[] = {
0 , 0 , '!', '@', '#', '$', '%', '^', 0, 0, '!', '@', '#', '$', '%', '^', '&',
'&', '*', '(', ')', '_', '+', 0 , 0 , 'Q', 'W', 'E', 'R', 'T', 'Y', '*', '(', ')', '_', '+', 0, 0, 'Q', 'W',
'U', 'I', 'O', 'P', '{', '}', '\n', 0 , 'A', 'S', 'D', 'F', 'G', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{',
'H', 'J', 'K', 'L', ':', '"', '~', 0 , '\\', 'Z', 'X', 'C', 'V', '}', '\n', 0, 'A', 'S', 'D', 'F', 'G', 'H',
'B', 'N', 'M', '<', '>', '?' /* an actual question mark */, 0 , 0 , 0 , ' ', 'J', 'K', 'L', ':', '"', '~', 0, '\\', 'Z',
'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?' /* an actual question mark */,
0, 0, 0, ' ',
}; };
extern keyboard_interrupt_shared_t kbd_state_shrd; extern keyboard_interrupt_shared_t kbd_state_shrd;
void init_keyboard(); void init_keyboard();

View File

@ -1,8 +1,7 @@
#pragma once #pragma once
#include "port.h" #include "port.h"
__attribute__((noreturn)) __attribute__((noreturn)) static inline void qemu_shutdown() {
static inline void qemu_shutdown() {
port_word_out(0x604, 0x2000); port_word_out(0x604, 0x2000);
__builtin_unreachable(); __builtin_unreachable();
} }

View File

@ -1,6 +1,6 @@
#include "pit.h" #include "pit.h"
#include "port.h"
#include "../cpu/isr.h" #include "../cpu/isr.h"
#include "port.h"
enum { enum {
PIT_CRYSTAL_HZ = 1193182, PIT_CRYSTAL_HZ = 1193182,
@ -23,10 +23,18 @@ enum {
PIT_MODES_SQUARE_WAVE_GENERATOR = 0x3, PIT_MODES_SQUARE_WAVE_GENERATOR = 0x3,
PIT_MODES_SW_TRIGGERRED_STROBE = 0x4, PIT_MODES_SW_TRIGGERRED_STROBE = 0x4,
PIT_MODES_HW_TRIGGERRED_STROBE = 0x5, PIT_MODES_HW_TRIGGERRED_STROBE = 0x5,
PIT_COMMAND_PORT = 0x43,
PIT_CHANNEL0_DATA_PORT = 0x40,
PIT_CHANNEL2_DATA_PORT = 0x42,
PC_SPEAKER_PORT = 0x61,
}; };
// Wtf is that O_o
static timer_callback callbacks[100]; static timer_callback callbacks[100];
static int registered_callbacks = 0; static int registered_callbacks = 0;
static volatile uint32_t uptime_ms = 0;
static volatile uint32_t speaker_frequency_hz = 0;
void add_timer_callback(timer_callback tc) { void add_timer_callback(timer_callback tc) {
callbacks[registered_callbacks++] = tc; callbacks[registered_callbacks++] = tc;
@ -45,7 +53,7 @@ struct pit_command_t {
unsigned char select_channel : 2; unsigned char select_channel : 2;
} __attribute__((packed)); } __attribute__((packed));
static void dec_sleep_counter(void); static void timer_int_callback(void);
void init_pit() { void init_pit() {
struct pit_command_t cmd = { struct pit_command_t cmd = {
@ -54,20 +62,60 @@ void init_pit() {
.operating_mode = PIT_MODES_SQUARE_WAVE_GENERATOR, .operating_mode = PIT_MODES_SQUARE_WAVE_GENERATOR,
.bcd = 0, .bcd = 0,
}; };
port_byte_out(0x43, *(unsigned char *)(&cmd)); port_byte_out(PIT_COMMAND_PORT, *(unsigned char *)(&cmd));
port_byte_out(0x40, PIT_PROGRAM_REG & 0xff); port_byte_out(PIT_CHANNEL0_DATA_PORT, PIT_PROGRAM_REG & 0xff);
port_byte_out(0x40, (PIT_PROGRAM_REG & 0xff00) >> 8); port_byte_out(PIT_CHANNEL0_DATA_PORT, (PIT_PROGRAM_REG & 0xff00) >> 8);
register_interrupt_handler(IRQ0, timer_interrupt_handler); register_interrupt_handler(IRQ0, timer_interrupt_handler);
add_timer_callback(dec_sleep_counter); add_timer_callback(timer_int_callback);
} }
static volatile int sleep_counter = 0; static volatile int sleep_counter = 0;
static void dec_sleep_counter(void) { static void timer_int_callback(void) {
uptime_ms += 1000 / CLOCK_PRECISION_HZ;
sleep_counter--; sleep_counter--;
} }
uint32_t get_uptime_ms(void) { return uptime_ms; }
void set_beep_frequency_hz(uint32_t frequency_hz) {
if (frequency_hz == 0) {
disable_beep();
return;
}
uint32_t divisor = PIT_CRYSTAL_HZ / frequency_hz;
if (divisor == 0) {
divisor = 1;
}
if (divisor > 0xffff) {
divisor = 0xffff;
}
struct pit_command_t cmd = {
.select_channel = PIT_SELECT_CHANNEL2,
.access_mode = PIT_ACCESS_MODE_LOHIBYTE,
.operating_mode = PIT_MODES_SQUARE_WAVE_GENERATOR,
.bcd = 0,
};
port_byte_out(PIT_COMMAND_PORT, *(unsigned char *)(&cmd));
port_byte_out(PIT_CHANNEL2_DATA_PORT, divisor & 0xff);
port_byte_out(PIT_CHANNEL2_DATA_PORT, (divisor & 0xff00) >> 8);
uint8_t speaker = port_byte_in(PC_SPEAKER_PORT);
port_byte_out(PC_SPEAKER_PORT, speaker | 0x03);
speaker_frequency_hz = frequency_hz;
}
void disable_beep(void) {
uint8_t speaker = port_byte_in(PC_SPEAKER_PORT);
port_byte_out(PC_SPEAKER_PORT, speaker & 0xfc);
speaker_frequency_hz = 0;
}
uint32_t get_beep_frequency_hz(void) { return speaker_frequency_hz; }
void msleep(int ms) { void msleep(int ms) {
sleep_counter = ms / 10; sleep_counter = ms / 10;
while (sleep_counter > 0) { while (sleep_counter > 0) {

View File

@ -1,8 +1,16 @@
#pragma once #pragma once
#include <stdint.h>
#define MAX_BEEP_FREQUENCY_HZ 44100u
typedef void (*timer_callback)(void); typedef void (*timer_callback)(void);
void init_pit(void); void init_pit(void);
void add_timer_callback(timer_callback tc); void add_timer_callback(timer_callback tc);
uint32_t get_uptime_ms(void);
void set_beep_frequency_hz(uint32_t frequency_hz);
void disable_beep(void);
uint32_t get_beep_frequency_hz(void);
void msleep(int ms); void msleep(int ms);

View File

@ -30,9 +30,7 @@ void uartinit() {
port_byte_in(COM1 + 0); port_byte_in(COM1 + 0);
} }
void void uartputc(char c) {
uartputc(char c)
{
int i; int i;
if (!uart) if (!uart)

View File

@ -1,7 +1,7 @@
#include "vga.h" #include "vga.h"
#include "port.h"
#include "../lib/string.h" #include "../lib/string.h"
#include "cpu/memlayout.h" #include "cpu/memlayout.h"
#include "port.h"
static char *const video_memory = (char *)(KERNBASE + 0xb8000); static char *const video_memory = (char *)(KERNBASE + 0xb8000);
@ -32,9 +32,7 @@ unsigned vga_get_offset(unsigned col, unsigned row) {
return row * VGA_COLS + col; return row * VGA_COLS + col;
} }
unsigned vga_get_row_from_offset(unsigned offset) { unsigned vga_get_row_from_offset(unsigned offset) { return offset / VGA_COLS; }
return offset / VGA_COLS;
}
void vga_set_cursor(unsigned offset) { void vga_set_cursor(unsigned offset) {
port_byte_out(VGA_CTRL_REGISTER, VGA_OFFSET_HIGH); port_byte_out(VGA_CTRL_REGISTER, VGA_OFFSET_HIGH);
@ -64,7 +62,8 @@ void vga_clear_screen() {
} }
static unsigned scroll() { static unsigned scroll() {
kmemmove(video_memory, video_memory + 2 * VGA_COLS, 2 * VGA_COLS * (VGA_ROWS-1)); kmemmove(video_memory, video_memory + 2 * VGA_COLS,
2 * VGA_COLS * (VGA_ROWS - 1));
for (int col = 0; col < VGA_COLS; col++) { for (int col = 0; col < VGA_COLS; col++) {
vga_set_char(vga_get_offset(col, VGA_ROWS - 1), ' '); vga_set_char(vga_get_offset(col, VGA_ROWS - 1), ' ');
} }

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
enum { enum {
@ -12,8 +13,6 @@ enum {
VGA_OFFSET_HIGH = 0x0e, VGA_OFFSET_HIGH = 0x0e,
}; };
unsigned vga_get_cursor(); unsigned vga_get_cursor();
unsigned vga_get_row_from_offset(unsigned offset); unsigned vga_get_row_from_offset(unsigned offset);
unsigned vga_get_offset(unsigned col, unsigned row); unsigned vga_get_offset(unsigned col, unsigned row);
@ -23,5 +22,17 @@ void vga_clear_screen();
void vga_set_char(unsigned offset, char c); void vga_set_char(unsigned offset, char c);
void vga_print_string(const char *s); void vga_print_string(const char *s);
#define VGA_GRAPHICS_WIDTH 320
#define VGA_GRAPHICS_HEIGHT 200
typedef enum {
VGA_DISPLAY_MODE_TEXT = 0,
VGA_DISPLAY_MODE_GRAPHICS = 1,
} vga_display_mode_t;
void vgaMode13(); void vgaMode13();
void vgaMode3(); void vgaMode3();
void switch_to_graphics_mode();
void switch_to_text_mode();
vga_display_mode_t vga_get_display_mode();
bool vga_is_text_mode();

View File

@ -1,6 +1,6 @@
#include "fs.h" #include "fs.h"
#include "../lib/string.h"
#include "../drivers/ata.h" #include "../drivers/ata.h"
#include "../lib/string.h"
enum { enum {
fs_start = 1, // sector where the FS starts fs_start = 1, // sector where the FS starts

View File

@ -1,17 +1,17 @@
#include "console.h" #include "console.h"
#include "cpu/isr.h"
#include "cpu/gdt.h" #include "cpu/gdt.h"
#include "cpu/isr.h"
#include "cpu/memlayout.h" #include "cpu/memlayout.h"
#include "drivers/keyboard.h"
#include "drivers/vga.h"
#include "drivers/ata.h" #include "drivers/ata.h"
#include "drivers/keyboard.h"
#include "drivers/misc.h" #include "drivers/misc.h"
#include "drivers/pit.h" #include "drivers/pit.h"
#include "drivers/uart.h" #include "drivers/uart.h"
#include "drivers/vga.h"
#include "fs/fs.h" #include "fs/fs.h"
#include "kernel/mem.h"
#include "lib/string.h" #include "lib/string.h"
#include "proc.h" #include "proc.h"
#include "kernel/mem.h"
void vga_set_pixel(int x, int y, int color) { void vga_set_pixel(int x, int y, int color) {
unsigned char *pixel = (unsigned char *)(KERNBASE + 0xA0000 + 320 * y + x); unsigned char *pixel = (unsigned char *)(KERNBASE + 0xA0000 + 320 * y + x);
@ -19,14 +19,14 @@ void vga_set_pixel(int x, int y, int color) {
} }
void graphtest() { void graphtest() {
vgaMode13(); switch_to_graphics_mode();
for (int i = 0; i < 320; ++i) { for (int i = 0; i < 320; ++i) {
for (int j = 0; j < 200; ++j) { for (int j = 0; j < 200; ++j) {
vga_set_pixel(i, j, (i + j) / 2); vga_set_pixel(i, j, (i + j) / 2);
} }
} }
msleep(5000); msleep(5000);
vgaMode3(); switch_to_text_mode();
vga_clear_screen(); vga_clear_screen();
} }
@ -50,8 +50,8 @@ void read_line_input(char* buf, size_t* ret_len, size_t cap) {
len--; len--;
} }
} else if (keycode < keycodes) { } else if (keycode < keycodes) {
char ch = shift_pressed ? keysym_mapped_ascii_upper[keycode] : char ch = shift_pressed ? keysym_mapped_ascii_upper[keycode]
keysym_mapped_ascii_lower[keycode]; : keysym_mapped_ascii_lower[keycode];
if (ch != 0) { if (ch != 0) {
char haha[2] = {ch, 0}; char haha[2] = {ch, 0};
printk(haha); printk(haha);
@ -81,7 +81,6 @@ void read_line_input(char* buf, size_t* ret_len, size_t cap) {
*ret_len = len; *ret_len = len;
} }
void kmain() { void kmain() {
freerange(P2V(3u << 20), P2V(4u << 20)); freerange(P2V(3u << 20), P2V(4u << 20));
kvmalloc(); // map all of physical memory at KERNBASE kvmalloc(); // map all of physical memory at KERNBASE
@ -106,7 +105,9 @@ void kmain() {
input[input_len] = 0; input[input_len] = 0;
printk(input); printk(input);
printk("\n"); printk("\n");
if (cstr_equal(input, "halt")) { if (cstr_equal(input, "")) {
run_elf("snake");
} else if (cstr_equal(input, "halt")) {
printk("Bye\n"); printk("Bye\n");
qemu_shutdown(); qemu_shutdown();
} else if (cstr_equal(input, "work")) { } else if (cstr_equal(input, "work")) {

View File

@ -2,11 +2,11 @@
// memory for user processes, kernel stacks, page table pages, // memory for user processes, kernel stacks, page table pages,
// and pipe buffers. Allocates 4096-byte pages. // and pipe buffers. Allocates 4096-byte pages.
#include <stdint.h>
#include "mem.h" #include "mem.h"
#include "console.h" #include "console.h"
#include "cpu/memlayout.h" #include "cpu/memlayout.h"
#include "cpu/x86.h" #include "cpu/x86.h"
#include <stdint.h>
struct run { struct run {
struct run *next; struct run *next;
@ -16,18 +16,14 @@ struct {
struct run *freelist; struct run *freelist;
} kmem; } kmem;
void void freerange(void *vstart, void *vend) {
freerange(void *vstart, void *vend)
{
char *p; char *p;
p = (char *)PGROUNDUP((uintptr_t)vstart); p = (char *)PGROUNDUP((uintptr_t)vstart);
for (; p + PGSIZE <= (char *)vend; p += PGSIZE) for (; p + PGSIZE <= (char *)vend; p += PGSIZE)
kfree(p); kfree(p);
} }
void* void *memset(void *dst, unsigned c, uint64_t n) {
memset(void *dst, unsigned c, uint64_t n)
{
if ((uintptr_t)dst % 4 == 0 && n % 4 == 0) { if ((uintptr_t)dst % 4 == 0 && n % 4 == 0) {
c &= 0xFF; c &= 0xFF;
stosl(dst, (c << 24) | (c << 16) | (c << 8) | c, n / 4); stosl(dst, (c << 24) | (c << 16) | (c << 8) | c, n / 4);
@ -40,9 +36,7 @@ memset(void *dst, unsigned c, uint64_t n)
// which normally should have been returned by a // which normally should have been returned by a
// call to kalloc(). (The exception is when // call to kalloc(). (The exception is when
// initializing the allocator; see kinit above.) // initializing the allocator; see kinit above.)
void void kfree(void *v) {
kfree(void *v)
{
struct run *r; struct run *r;
if ((uintptr_t)v % PGSIZE || V2P(v) >= PHYSTOP) if ((uintptr_t)v % PGSIZE || V2P(v) >= PHYSTOP)
@ -59,8 +53,7 @@ kfree(void *v)
// Allocate one 4096-byte page of physical memory. // Allocate one 4096-byte page of physical memory.
// Returns a pointer that the kernel can use. // Returns a pointer that the kernel can use.
// Returns 0 if the memory cannot be allocated. // Returns 0 if the memory cannot be allocated.
void* kalloc(void) void *kalloc(void) {
{
struct run *r; struct run *r;
r = kmem.freelist; r = kmem.freelist;

View File

@ -1,7 +1,7 @@
#include "mem.h" #include "console.h"
#include "cpu/memlayout.h" #include "cpu/memlayout.h"
#include "cpu/x86.h" #include "cpu/x86.h"
#include "console.h" #include "mem.h"
pde_t *kvm; pde_t *kvm;
@ -22,8 +22,7 @@ void kvmalloc() {
switchkvm(); switchkvm();
} }
void switchkvm(void) void switchkvm(void) {
{
lcr3(V2P(kvm)); // switch to the kernel page table lcr3(V2P(kvm)); // switch to the kernel page table
} }
@ -33,9 +32,7 @@ void switchkvm(void)
// Return the address of the PTE in page table pgdir // Return the address of the PTE in page table pgdir
// that corresponds to virtual address va. If alloc!=0, // that corresponds to virtual address va. If alloc!=0,
// create any required page table pages. // create any required page table pages.
static pte_t * static pte_t *walkpgdir(pde_t *pgdir, const void *va, int alloc) {
walkpgdir(pde_t *pgdir, const void *va, int alloc)
{
pde_t *pde; pde_t *pde;
pte_t *pgtab; pte_t *pgtab;
@ -65,8 +62,8 @@ walkpgdir(pde_t *pgdir, const void *va, int alloc)
// Create PTEs for virtual addresses starting at va that refer to // Create PTEs for virtual addresses starting at va that refer to
// physical addresses starting at pa. // physical addresses starting at pa.
// size might not be page-aligned. // size might not be page-aligned.
static int static int mappages(pde_t *pgdir, void *va, uintptr_t size, uintptr_t pa,
mappages(pde_t *pgdir, void *va, uintptr_t size, uintptr_t pa, int perm){ int perm) {
if ((uintptr_t)va % PGSIZE != 0) if ((uintptr_t)va % PGSIZE != 0)
panic("Why??"); panic("Why??");
char *a = va; char *a = va;

View File

@ -1,6 +1,5 @@
#include "string.h" #include "string.h"
void memcpy(void *dst, const void *src, size_t size) { void memcpy(void *dst, const void *src, size_t size) {
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
((char *)dst)[i] = ((const char *)src)[i]; ((char *)dst)[i] = ((const char *)src)[i];
@ -8,7 +7,8 @@ void memcpy(void*dst, const void *src, size_t size) {
} }
void kmemmove(char *dst, char *src, size_t size) { void kmemmove(char *dst, char *src, size_t size) {
if (dst == src) return; if (dst == src)
return;
if (dst > src && dst < src + size) { // s d if (dst > src && dst < src + size) { // s d
// copy right-to-left // copy right-to-left
for (; size != 0; size--) { for (; size != 0; size--) {
@ -42,7 +42,6 @@ bool cstr_equal(const char* s1, const char* s2) {
return *s1 == 0 && *s2 == 0; return *s1 == 0 && *s2 == 0;
} }
bool cstr_starts_with(const char *A, const char *B) { bool cstr_starts_with(const char *A, const char *B) {
while (*A && *B) { while (*A && *B) {
if (*A != *B) if (*A != *B)

19
proc.c
View File

@ -1,4 +1,6 @@
#include "proc.h" #include "proc.h"
#include "drivers/pit.h"
#include "drivers/vga.h"
struct context { struct context {
// matches the behavior of swtch() // matches the behavior of swtch()
@ -28,6 +30,9 @@ void trapret();
void swtch(void **oldstack, void *newstack); void swtch(void **oldstack, void *newstack);
pde_t *get_user_proc_page_directory() { pde_t *get_user_proc_page_directory() {
if (!vm.user_task) {
return 0;
}
return vm.user_task->pgdir; return vm.user_task->pgdir;
} }
@ -42,17 +47,20 @@ void run_elf(const char* name) {
vm.user_task = kalloc(); vm.user_task = kalloc();
} }
// todo: this code contains 9999 memory leaks but I don't care // todo: this code contains 9999 memory leaks but I don't care
// todo: yabloko is fucking shit made my monkeys, I want to forget this fucking nightmare // todo: yabloko is fucking shit made my monkeys, I want to forget this
// fucking nightmare
vm.user_task->pgdir = setupkvm(); vm.user_task->pgdir = setupkvm();
if (allocuvm(vm.user_task->pgdir, USER_BASE, USER_BASE + statbuf.size)) { if (allocuvm(vm.user_task->pgdir, USER_BASE, USER_BASE + statbuf.size)) {
printk("Fail: out of memory\n"); printk("Fail: out of memory\n");
return; return;
} }
if (allocuvm(vm.user_task->pgdir, USER_STACK_BASE - 2 * PGSIZE, USER_STACK_BASE)) { if (allocuvm(vm.user_task->pgdir, USER_STACK_BASE - 2 * PGSIZE,
USER_STACK_BASE)) {
printk("Fail: out of memory\n"); printk("Fail: out of memory\n");
return; return;
} }
switchuvm(&vm.user_task->tss, vm.user_task->stack.bottom, vm.user_task->pgdir); switchuvm(&vm.user_task->tss, vm.user_task->stack.bottom,
vm.user_task->pgdir);
if (read_file(&statbuf, (void *)USER_BASE, 100 << 20) <= 0) { if (read_file(&statbuf, (void *)USER_BASE, 100 << 20) <= 0) {
printk(name); printk(name);
@ -84,6 +92,11 @@ void run_elf(const char* name) {
_Noreturn void killproc() { _Noreturn void killproc() {
void *task_stack; void *task_stack;
disable_beep();
if (!vga_is_text_mode()) {
switch_to_text_mode();
vga_clear_screen();
}
switchkvm(); switchkvm();
freevm(vm.user_task->pgdir); freevm(vm.user_task->pgdir);
sti(); sti();

7
proc.h
View File

@ -1,14 +1,13 @@
#pragma once #pragma once
#include "elf.h" #include "console.h"
#include "fs/fs.h"
#include "cpu/gdt.h" #include "cpu/gdt.h"
#include "cpu/isr.h" #include "cpu/isr.h"
#include "cpu/memlayout.h" #include "cpu/memlayout.h"
#include "elf.h"
#include "fs/fs.h"
#include "kernel/mem.h" #include "kernel/mem.h"
#include "lib/string.h" #include "lib/string.h"
#include "console.h"
pde_t *get_user_proc_page_directory(); pde_t *get_user_proc_page_directory();

39
snake/keymapping.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
/* We still have beef with keyboard, even in userspace */
#define KEYCODE_SHIFT 42
#define KEYCODE_ENTER 28
#define KEYCODE_BACKSPACE 14
#define KEYCODE_SPACE 57
#define KEYCODE_ESCAPE 1
#define KEYCODE_A 30
#define KEYCODE_S 31
#define KEYCODE_D 32
#define KEYCODE_W 17
#define KEYCODE_Q 16
#define KEYCODE_ENTER 28
#define KEYCODE_LEFT 75
#define KEYCODE_RIGHT 77
#define KEYCODE_UP 72
#define KEYCODE_DOWN 80
#define KEYCODE_1 2
#define KEYCODE_2 3
bool is_keycode_for_press_left(uint8_t keycode) {
return keycode == KEYCODE_LEFT || keycode == KEYCODE_A;
}
bool is_keycode_for_press_right(uint8_t keycode) {
return keycode == KEYCODE_RIGHT || keycode == KEYCODE_D;
}
bool is_keycode_for_press_up(uint8_t keycode) {
return keycode == KEYCODE_UP || keycode == KEYCODE_W;
}
bool is_keycode_for_press_down(uint8_t keycode) {
return keycode == KEYCODE_DOWN || keycode == KEYCODE_S;
}

714
snake/map_data.h Normal file
View File

@ -0,0 +1,714 @@
#pragma once
#include "maps.h"
static const MapList
map_list = {.maps =
{
/* CLUSTERTRACT.png */
[0] =
{
.name = "CLUSTERTRACT",
.map =
{
[0] = {tile_wall_t, tile_wall_lr,
tile_wall_lr, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_wall_lr,
tile_wall_lr, tile_wall_b},
[1] = {tile_wall_rb, tile_wall_lt,
tile_wall_lr, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_wall_lr,
tile_wall_lb, tile_wall_rt},
[2] =
{tile_wall_lr,
tile_wall_rb, tile_wall_lt, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_lb, tile_wall_rt, tile_wall_lr},
[3] =
{tile_wall_lr,
tile_wall_lr, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_lr, tile_wall_lr},
[4] =
{tile_wall_lr,
tile_wall_lr, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_lr, tile_wall_lr},
[5] =
{tile_wall_lr,
tile_wall_lr, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_b, tile_wall_lrt, tile_wall_lr},
[6] =
{tile_wall_lr,
tile_wall_lr, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_lr, tile_wall_lr},
[7] =
{tile_wall_lr,
tile_wall_lrb, tile_wall_rt, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_lr, tile_wall_lr},
[8] =
{tile_wall_lr,
tile_wall_lrb, tile_wall_lt, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_rb, tile_wall_lrt, tile_wall_lr},
[9] =
{tile_wall_lr,
tile_wall_lr, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_lb, tile_wall_lrt, tile_wall_lr},
[10] =
{tile_wall_lr,
tile_wall_lr, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_lr,
tile_wall_lr},
[11] =
{tile_wall_lr,
tile_wall_lrb, tile_wall_t, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_lr,
tile_wall_lr},
[12] =
{tile_wall_lr, tile_wall_lr,
tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_lr,
tile_wall_lr},
[13] =
{tile_wall_lr, tile_wall_lr,
tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_lr,
tile_wall_lr},
[14] =
{tile_wall_lr, tile_wall_lb,
tile_wall_rt,
tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_rb,
tile_wall_lt, tile_wall_lr},
[15] =
{tile_wall_lb, tile_wall_rt,
tile_wall_lr,
tile_empty, tile_empty, tile_empty, tile_empty, tile_wall_lr,
tile_wall_rb, tile_wall_lt},
},
},
/* EMPTY.png */
[1] =
{
.name = "EMPTY",
.map =
{
[0] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[1] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[2] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[3] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[4] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[5] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[6] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[7] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[8] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[9] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[10] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[11] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[12] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[13] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[14] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[15] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
},
},
/* GREEN DAYS.png */
[2] =
{
.name = "GREEN DAYS",
.map =
{
[0] = {tile_wall_rb, tile_wall_tb,
tile_wall_tb, tile_wall_t,
tile_empty, tile_empty,
tile_wall_b, tile_wall_tb,
tile_wall_tb, tile_wall_rt},
[1] = {tile_wall_lr, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_wall_lr},
[2] = {tile_wall_lr, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_wall_lr},
[3] = {tile_wall_l, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_wall_l},
[4] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[5] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[6] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[7] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[8] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[9] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[10] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[11] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[12] =
{tile_wall_r, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_wall_r},
[13] =
{tile_wall_lr, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_wall_lr},
[14] =
{tile_wall_lr, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_wall_lr},
[15] =
{tile_wall_lb, tile_wall_tb,
tile_wall_tb, tile_wall_t,
tile_empty, tile_empty,
tile_wall_b, tile_wall_tb,
tile_wall_tb, tile_wall_lt},
},
},
/* QUARTERHOUSE.png */
[3] =
{
.name = "QUARTERHOUSE",
.map =
{
[0] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[1] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[2] = {tile_empty, tile_empty,
tile_empty, tile_wall_b,
tile_wall_rtb, tile_wall_tb,
tile_wall_t, tile_empty,
tile_empty, tile_empty},
[3] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_lr,
tile_wall, tile_empty,
tile_empty, tile_empty,
tile_empty},
[4] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_lr,
tile_wall, tile_empty,
tile_empty, tile_empty,
tile_empty},
[5] = {tile_wall_rt, tile_empty,
tile_empty, tile_empty,
tile_wall_lb, tile_wall_rt,
tile_empty, tile_empty,
tile_empty, tile_wall_rb},
[6] = {tile_wall_lrt, tile_empty,
tile_empty, tile_empty,
tile_wall, tile_wall_lr,
tile_empty, tile_empty,
tile_empty, tile_wall_lrb},
[7] = {tile_wall_lrt,
tile_wall, tile_wall_rb,
tile_wall_tb, tile_wall_rtb,
tile_wall_lrtb, tile_wall_tb,
tile_wall_rt,
tile_wall, tile_wall_lrb},
[8] = {tile_wall_lrtb, tile_wall_tb,
tile_wall_lt,
tile_wall, tile_wall_lrb,
tile_wall_lt,
tile_wall, tile_wall_lb,
tile_wall_tb, tile_wall_lrtb},
[9] = {tile_wall_lrt, tile_empty,
tile_empty, tile_empty,
tile_wall_lr,
tile_wall, tile_empty,
tile_empty, tile_empty,
tile_wall_lrb},
[10] =
{tile_wall_lt, tile_empty,
tile_empty, tile_empty,
tile_wall_lb, tile_wall_rt,
tile_empty, tile_empty, tile_empty,
tile_wall_lb},
[11] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_wall,
tile_wall_lr, tile_empty,
tile_empty, tile_empty,
tile_empty},
[12] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_wall,
tile_wall_lr, tile_empty,
tile_empty, tile_empty,
tile_empty},
[13] =
{tile_empty, tile_empty, tile_empty,
tile_wall_b, tile_wall_tb,
tile_wall_ltb, tile_wall_t,
tile_empty, tile_empty,
tile_empty},
[14] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[15] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
},
},
/* SERPENTINE STRUTS.png */
[4] =
{
.name = "SERPENTINE STRUTS",
.map =
{
[0] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[1] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_r, tile_empty,
tile_empty, tile_wall_r,
tile_empty, tile_empty},
[2] = {tile_empty, tile_empty,
tile_empty, tile_wall_b,
tile_wall_lrtb, tile_wall_tb,
tile_wall_tb, tile_wall_lrtb,
tile_wall_t, tile_empty},
[3] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_l, tile_empty,
tile_empty, tile_wall_l,
tile_empty, tile_empty},
[4] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[5] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[6] = {tile_empty, tile_empty,
tile_empty, tile_wall_r,
tile_empty, tile_empty,
tile_wall_r, tile_empty,
tile_empty, tile_empty},
[7] = {tile_empty, tile_empty,
tile_wall_b, tile_wall_lrtb,
tile_wall_tb, tile_wall_tb,
tile_wall_lrtb, tile_wall_t,
tile_empty, tile_empty},
[8] = {tile_empty, tile_empty,
tile_empty, tile_wall_l,
tile_empty, tile_empty,
tile_wall_l, tile_empty,
tile_empty, tile_empty},
[9] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[10] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[11] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[12] =
{tile_empty, tile_empty,
tile_wall_r, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_wall_r, tile_empty,
tile_empty},
[13] = {tile_empty, tile_wall_b,
tile_wall_lrtb, tile_wall_tb,
tile_wall_tb, tile_wall_tb,
tile_wall_tb, tile_wall_lrtb,
tile_wall_t, tile_empty},
[14] =
{tile_empty, tile_empty,
tile_wall_l, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_wall_l, tile_empty,
tile_empty},
[15] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
},
},
/* SHEER GIRTH.png */
[5] =
{
.name = "SHEER GIRTH",
.map =
{
[0] = {tile_empty, tile_wall_rb,
tile_wall_rtb, tile_wall_rtb,
tile_wall_rtb, tile_wall_rtb,
tile_wall_rtb, tile_wall_rtb,
tile_wall_rt, tile_empty},
[1] = {tile_empty, tile_wall_lrb,
tile_wall_lrtb, tile_wall_lrtb,
tile_wall_lrtb, tile_wall_lrtb,
tile_wall_lrtb, tile_wall_lrtb,
tile_wall_lrt, tile_empty},
[2] = {tile_empty, tile_wall_lb,
tile_wall_ltb, tile_wall_ltb,
tile_wall_ltb, tile_wall_ltb,
tile_wall_ltb, tile_wall_ltb,
tile_wall_lt, tile_empty},
[3] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[4] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[5] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[6] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[7] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[8] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[9] = {tile_empty, tile_wall_rb,
tile_wall_rtb, tile_wall_rt,
tile_empty, tile_empty,
tile_wall_rb, tile_wall_rtb,
tile_wall_rt, tile_empty},
[10] =
{tile_empty, tile_wall_lrb,
tile_wall_lrtb, tile_wall_lrt,
tile_empty, tile_empty,
tile_wall_lrb, tile_wall_lrtb,
tile_wall_lrt, tile_empty},
[11] =
{tile_empty, tile_wall_lrb,
tile_wall_lrtb, tile_wall_lrt,
tile_empty, tile_empty,
tile_wall_lrb, tile_wall_lrtb,
tile_wall_lrt, tile_empty},
[12] =
{tile_empty, tile_wall_lrb,
tile_wall_lrtb, tile_wall_lrt,
tile_empty, tile_empty,
tile_wall_lrb, tile_wall_lrtb,
tile_wall_lrt, tile_empty},
[13] =
{tile_empty, tile_wall_lb,
tile_wall_ltb, tile_wall_lt,
tile_empty, tile_empty,
tile_wall_lb, tile_wall_ltb,
tile_wall_lt, tile_empty},
[14] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[15] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
},
},
/* VAULT.png */
[6] =
{
.name = "VAULT",
.map =
{
[0] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[1] = {tile_empty, tile_empty,
tile_empty, tile_wall_rb,
tile_wall_tb, tile_wall_tb,
tile_wall_tb, tile_wall_tb,
tile_wall_rt, tile_empty},
[2] = {tile_empty, tile_empty,
tile_empty, tile_wall_lr,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_lr, tile_empty},
[3] = {tile_empty, tile_empty,
tile_empty, tile_wall_lr,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_lr, tile_empty},
[4] = {tile_empty, tile_empty,
tile_empty, tile_wall_lr,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_lr, tile_empty},
[5] = {tile_empty, tile_empty,
tile_empty, tile_wall_lr,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_lr, tile_empty},
[6] = {tile_empty, tile_empty,
tile_empty, tile_wall_lb,
tile_wall_t, tile_empty,
tile_empty, tile_wall_b,
tile_wall_lrt, tile_empty},
[7] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_lr, tile_empty},
[8] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_lr, tile_empty},
[9] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_lr, tile_empty},
[10] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty,
tile_wall_lr, tile_empty},
[11] =
{tile_empty, tile_empty,
tile_wall_rb, tile_wall_t,
tile_empty, tile_empty,
tile_wall_b, tile_wall_tb,
tile_wall_lrt, tile_empty},
[12] =
{tile_empty, tile_empty,
tile_wall_lr, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_wall_lr,
tile_empty},
[13] =
{tile_empty, tile_empty,
tile_wall_lr, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_wall_lr,
tile_empty},
[14] =
{tile_empty, tile_empty,
tile_wall_lb, tile_wall_tb,
tile_wall_tb, tile_wall_tb,
tile_wall_tb, tile_wall_tb,
tile_wall_lt, tile_empty},
[15] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
},
},
/* WALLS.png */
[7] =
{
.name = "WALLS",
.map =
{
[0] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[1] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[2] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[3] = {tile_wall_tb, tile_wall_t,
tile_empty, tile_empty,
tile_wall_b, tile_wall_tb,
tile_wall_tb, tile_wall_tb,
tile_wall_tb, tile_wall_tb},
[4] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[5] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[6] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[7] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[8] = {tile_wall_tb, tile_wall_tb,
tile_wall_tb, tile_wall_tb,
tile_wall_t, tile_empty,
tile_empty, tile_wall_b,
tile_wall_tb, tile_wall_tb},
[9] = {tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty,
tile_empty, tile_empty},
[10] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[11] =
{tile_wall_t, tile_empty,
tile_empty, tile_wall_b,
tile_wall_tb, tile_wall_tb,
tile_wall_tb, tile_wall_tb,
tile_wall_tb, tile_wall_tb},
[12] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[13] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
[14] =
{tile_wall_tb, tile_wall_tb,
tile_wall_tb, tile_wall_tb,
tile_wall_tb, tile_wall_tb,
tile_wall_t, tile_empty,
tile_empty, tile_wall_b},
[15] =
{tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty, tile_empty, tile_empty,
tile_empty},
},
},
}};

72
snake/maps.h Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include "misc_utils.h"
typedef enum {
tile_empty = 0,
tile_apple = 1,
tile_wall = 2,
tile_wall_lr = 3,
tile_wall_l = 4,
tile_wall_r = 5,
tile_wall_lrt = 6,
tile_wall_lt = 7,
tile_wall_rt = 8,
tile_wall_lrb = 9,
tile_wall_lb = 10,
tile_wall_rb = 11,
tile_wall_lrtb = 12,
tile_wall_ltb = 13,
tile_wall_rtb = 14,
tile_wall_t = 15,
tile_wall_b = 16,
tile_wall_tb = 17,
tile_snake_l = 18,
tile_snake_r = 19,
tile_snake_t = 20,
tile_snake_b = 21,
tile_snake_bl = 22,
tile_snake_br = 23,
tile_snake_lb = 24,
tile_snake_rb = 25,
tile_snake_tl = 26,
tile_snake_tr = 27,
tile_snake_lt = 28,
tile_snake_rt = 29,
tile_pupa_m2_l = 30,
tile_pupa_m2_r = 31,
tile_pupa_m1_l = 32,
tile_pupa_m1_r = 33,
tile_pupa_0_l = 34,
tile_pupa_0_r = 35,
tile_pupa_p1_l = 36,
tile_pupa_p1_r = 37,
tile_pupa_p2_l = 38,
tile_pupa_p2_r = 39,
tile_pupa_m2_t = 40,
tile_pupa_m1_t = 41,
tile_pupa_0_t = 42,
tile_pupa_p1_t = 43,
tile_pupa_p2_t = 44,
tile_pupa_m2_b = 45,
tile_pupa_m1_b = 46,
tile_pupa_0_b = 47,
tile_pupa_p1_b = 48,
tile_pupa_p2_b = 49,
} tile_t;
#define WORLD_WIDTH 16
#define WORLD_HEIGHT 10
typedef struct {
const char *name;
tile_t map[WORLD_WIDTH][WORLD_HEIGHT];
} MapConfig;
#define PLAYABLE_MAPS_COUNT 8
typedef struct {
MapConfig maps[PLAYABLE_MAPS_COUNT];
} MapList;

91
snake/misc_utils.h Normal file
View File

@ -0,0 +1,91 @@
#pragma once
#include "../syscall.h"
#include <stdbool.h>
#include <stdint.h>
void _Noreturn panic(const char *message) {
syscall(SYS_switch_to_text, 0); // ???
syscall(SYS_puts, (uintptr_t)message);
syscall(SYS_exit, 1);
__builtin_unreachable();
}
#define check(expr) \
if (!(expr)) { \
panic("Assertion failed at " __FILE__ ": " #expr "\n"); \
}
typedef struct {
int x, y;
} ivec2;
void *memcpy(void *dst, const void *src, uint32_t size) {
uint8_t *d = (uint8_t *)dst;
const uint8_t *s = (const uint8_t *)src;
for (uint32_t i = 0; i < size; i++) {
d[i] = s[i];
}
return dst;
}
void *memset(void *dst, int value, uint32_t size) {
uint8_t *d = (uint8_t *)dst;
uint8_t byte = (uint8_t)value;
for (uint32_t i = 0; i < size; i++) {
d[i] = byte;
}
return dst;
}
#define STRING_BUILDER_CAPACITY 150
typedef struct {
char buf[STRING_BUILDER_CAPACITY];
int len;
} StringBuilder;
void StringBuilder_putc(StringBuilder *self, char ch) {
if (self->len + 1 > STRING_BUILDER_CAPACITY) {
panic("string builder\n");
}
self->buf[self->len++] = ch;
}
void StringBuilder_append_cstr(StringBuilder *self, const char *str) {
for (const char *p = str; *p; p++) {
StringBuilder_putc(self, *p);
}
}
void StringBuilder_append_u32(StringBuilder *self, uint32_t x) {
char b[11];
int len = 0;
if (x == 0) {
b[len++] = '0';
} else {
while (x > 0) {
b[len++] = (char)('0' + (x % 10));
x /= 10;
}
int i = 0, j = len - 1;
while (i < j) {
char tmp = b[i];
b[i] = b[j];
b[j] = tmp;
i++;
j--;
}
}
b[len] = 0;
StringBuilder_append_cstr(self, b);
}
const char *StringBuilder_get_cstr(StringBuilder *self) {
StringBuilder_putc(self, 0);
return self->buf;
}
uint32_t time_ms(void) { return (uint32_t)syscall(SYS_time_ms, 0); }

22
snake/pause_effect.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <stdint.h>
static const uint8_t VGA_GRAY_LUT[256] = {
16, 17, 23, 24, 20, 21, 23, 27, 22, 23, 28, 29, 25, 27, 30, 31, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 18, 19, 21, 22, 23, 23,
23, 22, 22, 24, 26, 28, 30, 29, 28, 27, 26, 27, 27, 27, 28, 26, 23, 21, 26,
26, 27, 27, 28, 28, 27, 27, 27, 28, 29, 30, 30, 30, 30, 29, 29, 29, 29, 29,
30, 29, 28, 27, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 31, 30, 30,
30, 30, 30, 30, 30, 30, 30, 29, 29, 17, 17, 18, 18, 19, 19, 19, 18, 18, 19,
21, 22, 23, 23, 22, 21, 21, 21, 21, 22, 22, 21, 19, 18, 20, 21, 21, 21, 22,
22, 22, 21, 21, 22, 23, 23, 24, 23, 23, 23, 22, 23, 23, 23, 23, 22, 22, 21,
22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 23, 23, 23, 23, 23,
23, 23, 23, 23, 22, 16, 17, 17, 17, 18, 17, 17, 17, 17, 18, 18, 19, 20, 20,
19, 19, 18, 19, 19, 19, 19, 18, 17, 17, 18, 18, 19, 19, 19, 19, 19, 19, 19,
19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 20,
20, 20, 20, 20, 19, 20, 20, 20, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
19, 16, 16, 16, 16, 16, 16, 16, 16,
};
static inline uint8_t vga_to_gray(uint8_t color) { return VGA_GRAY_LUT[color]; }

32
snake/random.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include "misc_utils.h"
#include <stdint.h>
typedef struct {
uint32_t state;
} RandomEngine;
static void RandomEngine_init(RandomEngine *self) { self->state = 0x6d2b79f5u; }
static uint32_t RandomEngine_rnd(RandomEngine *self) {
uint32_t x = self->state;
if (x == 0) {
x = 0x6d2b79f5u;
}
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
x = x * 1664525u + 1013904223u;
self->state = x;
return x;
}
static uint32_t RandomEngine_rnd_interval(RandomEngine *self, uint32_t from,
uint32_t until) {
check(from < until);
return from + RandomEngine_rnd(self) % (until - from);
}

807
snake/snake.c Normal file
View File

@ -0,0 +1,807 @@
#include "../drivers/vga.h"
#include "../syscall.h"
#include "keymapping.h"
#include "map_data.h"
#include "maps.h"
#include "misc_utils.h"
#include "pause_effect.h"
#include "random.h"
#include "sprite_data.h"
#include "sprites.h"
#include <stdbool.h>
#include <stdint.h>
#define FRAME_SIZE (VGA_GRAPHICS_WIDTH * VGA_GRAPHICS_HEIGHT)
#define HUD_OFFSET 3
#define GLYPH_SPACING 3
#define FONT_SPACE_INDEX 0
#define FONT_DIGIT_BASE 1
#define FONT_LETTER_BASE (FONT_DIGIT_BASE + 10)
uint8_t frame[FRAME_SIZE] = {1};
#define SNAKE_GAMEMODE_MAX_APPLES 10
#define SNAKE_GAMEMODE_DEFAULT_APPLES 5
typedef enum {
game_screen_gaming,
game_screen_pause,
game_screen_select_map,
game_screen_select_apple_count,
} game_screen_t;
#define SNAKE_START_Y 2
#define SNAKE_START_HEAD_X 4
#define SNAKE_START_PUPA_X 6
typedef enum {
snake_direction_left = 0,
snake_direction_right = 1,
snake_direction_top = 2,
snake_direction_bottom = 3,
} snake_direction_t;
#define WALKING_ANIM_TIME_VERY_SLOW 600
#define HATCHING_ANIM_TIME_VERY_SLOW 400
#define WALKING_ANIM_TIME_SLOW 450
#define HATCHING_ANIM_TIME_SLOW 150
#define WALKING_ANIM_TIME_FAST 200
#define HATCHING_ANIM_TIME_FAST 40
#define WEIRD_SOUND 400
typedef enum {
waiting_reason_step,
waiting_reason_p1,
waiting_reason_p2,
waiting_reason_cross,
/* we go from cross pupa state to m1 pupa state through 'step',
* not through a separate animation target */
waiting_reason_m1,
waiting_reason_zero_pupa,
waiting_reason_postmortum,
} waiting_reason_t;
struct Snake {
bool is_space_pressed;
bool is_shift_pressed;
game_screen_t game_screen;
bool have_game;
/* from 0 to PLAYABLE_MAPS_COUNT - 1 */
int selected_map_index;
/* from 1 to SNAKE_GAMEMODE_MAX_APPLES, default is
* SNAKE_GAMEMODE_DEFAULT_APPLES */
int gamemode_apples_count;
RandomEngine r_eng;
tile_t world[WORLD_WIDTH][WORLD_HEIGHT];
uint8_t ghost_apples[WORLD_WIDTH][WORLD_HEIGHT];
ivec2 snake_head;
ivec2 snake_tail;
snake_direction_t cur_snake_direction;
snake_direction_t new_snake_direction;
/* If we are about to make a step into a wall, we start dying,
* we enter into dying mode, where we keep making steps, but the head
* just disappears after walking, moving back.
* When the pupa disappears this way, we enter 'awaiting postmortum' state,
* where nothing moves. If we are about to hit ourselves, we don't even
* move, we immediately draw one small splash and enter 'awaiting
* postmortum' state. There is no winning state, you just raise your score
* until you are dead.
*/
bool is_dying;
int score;
/* from -1 to PUDDLE_SPRITES - 1 (where -1 means there is no puddle) */
int puddle_sprite;
ivec2 puddle_center;
/* This stuff regulates game flow and animation progress */
waiting_reason_t waiting_reason;
uint32_t waiting_time; // Measures how much time we already accumulated
int animation_speed_boost;
} snake = {1};
void init_snake() {
snake.is_space_pressed = false;
snake.is_shift_pressed = false;
snake.game_screen = game_screen_pause;
snake.have_game = false;
snake.selected_map_index = 6;
snake.gamemode_apples_count = SNAKE_GAMEMODE_DEFAULT_APPLES;
snake.r_eng = (RandomEngine){.state = time_ms()};
/* snake_head and snake_pupa and snake.world
* and other gameplay-related variables will be initialized during
* map loading */
}
bool place_random_apple() {
for (int t = 0; t < 50; t++) {
uint32_t i = RandomEngine_rnd_interval(&snake.r_eng, 0,
WORLD_WIDTH * WORLD_HEIGHT);
if ((&snake.world[0][0])[i] == tile_empty) {
(&snake.world[0][0])[i] = tile_apple;
return true;
}
}
/* I had enough */
for (uint32_t i = 0; i < WORLD_WIDTH * WORLD_HEIGHT; i++) {
if ((&snake.world[0][0])[i] == tile_empty) {
(&snake.world[0][0])[i] = tile_apple;
return true;
}
}
return false;
}
void start_snake_game() {
snake.have_game = true;
snake.game_screen = game_screen_gaming;
const MapConfig *map_config = &map_list.maps[snake.selected_map_index];
memcpy(&snake.world[0][0], &map_config->map[0][0],
sizeof(tile_t) * WORLD_WIDTH * WORLD_HEIGHT);
memset(&snake.ghost_apples, 0, sizeof(snake.ghost_apples));
for (int tx = SNAKE_START_HEAD_X; tx < SNAKE_START_PUPA_X; tx++) {
snake.world[tx][SNAKE_START_Y] = tile_snake_l;
}
snake.world[SNAKE_START_PUPA_X][SNAKE_START_Y] = tile_pupa_0_l;
snake.snake_head = (ivec2){SNAKE_START_HEAD_X, SNAKE_START_Y};
snake.snake_tail = (ivec2){SNAKE_START_PUPA_X, SNAKE_START_Y};
for (int app = 0; app < snake.gamemode_apples_count; app++) {
place_random_apple();
}
snake.new_snake_direction = snake.cur_snake_direction =
snake_direction_left;
snake.is_dying = false;
snake.score = 0;
snake.waiting_reason = waiting_reason_step;
snake.waiting_time = 0;
snake.animation_speed_boost = 0;
snake.puddle_sprite = -1;
}
void set_tile(ivec2 pos, tile_t val) {
check(0 <= pos.x && pos.x < WORLD_WIDTH && 0 <= pos.y &&
pos.y < WORLD_HEIGHT);
snake.world[pos.x][pos.y] = val;
}
tile_t get_tile(ivec2 pos) {
check(0 <= pos.x && pos.x < WORLD_WIDTH && 0 <= pos.y &&
pos.y < WORLD_HEIGHT);
return snake.world[pos.x][pos.y];
}
snake_direction_t get_opposite_direction(snake_direction_t x) {
if (x == snake_direction_left) {
return snake_direction_right;
} else if (x == snake_direction_right) {
return snake_direction_left;
} else if (x == snake_direction_top) {
return snake_direction_bottom;
} else {
return snake_direction_top;
}
}
ivec2 world_walk_direction(ivec2 v, snake_direction_t dir) {
if (dir == snake_direction_left) {
return (ivec2){v.x == 0 ? WORLD_WIDTH - 1 : v.x - 1, v.y};
} else if (dir == snake_direction_right) {
return (ivec2){v.x + 1 == WORLD_WIDTH ? 0 : v.x + 1, v.y};
} else if (dir == snake_direction_top) {
return (ivec2){v.x, v.y == 0 ? WORLD_HEIGHT - 1 : v.y - 1};
} else {
return (ivec2){v.x, v.y + 1 == WORLD_HEIGHT ? 0 : v.y + 1};
}
}
ivec2 get_puddle_center_for_contact(ivec2 head, snake_direction_t dir) {
ivec2 tile_pos = (ivec2){TILE_WIDTH * head.x, TILE_WIDTH * head.y};
if (dir == snake_direction_left || dir == snake_direction_right) {
tile_pos.y += TILE_WIDTH / 2;
} else if (dir == snake_direction_bottom) {
tile_pos.y += TILE_WIDTH;
}
if (dir == snake_direction_top || dir == snake_direction_bottom) {
tile_pos.x += TILE_WIDTH / 2;
} else if (dir == snake_direction_right) {
tile_pos.x += TILE_WIDTH;
}
return tile_pos;
}
/* takes snake tile, returns cardinal direction of snake origin */
snake_direction_t get_snake_origin_dir(tile_t tile) {
switch (tile) {
case tile_snake_l:
return snake_direction_right;
case tile_snake_r:
return snake_direction_left;
case tile_snake_t:
return snake_direction_bottom;
case tile_snake_b:
return snake_direction_top;
case tile_snake_bl:
return snake_direction_bottom;
case tile_snake_br:
return snake_direction_bottom;
case tile_snake_lb:
return snake_direction_left;
case tile_snake_rb:
return snake_direction_right;
case tile_snake_tl:
return snake_direction_top;
case tile_snake_tr:
return snake_direction_top;
case tile_snake_lt:
return snake_direction_left;
case tile_snake_rt:
return snake_direction_right;
default:
check(false);
}
}
tile_t construct_snake_tile(snake_direction_t from, snake_direction_t to) {
check(from != to);
if (from == snake_direction_left) {
if (to == snake_direction_right)
return tile_snake_r;
if (to == snake_direction_top)
return tile_snake_lt;
/* to bottom */
return tile_snake_lb;
}
if (from == snake_direction_right) {
if (to == snake_direction_left)
return tile_snake_l;
if (to == snake_direction_top)
return tile_snake_rt;
/* to bottom */
return tile_snake_rb;
}
if (from == snake_direction_top) {
if (to == snake_direction_left)
return tile_snake_tl;
if (to == snake_direction_right)
return tile_snake_tr;
/* to bottom */
return tile_snake_b;
}
if (from == snake_direction_bottom) {
if (to == snake_direction_left)
return tile_snake_bl;
if (to == snake_direction_right)
return tile_snake_br;
/* to top */
return tile_snake_t;
}
check(false);
}
tile_t construct_straight_snake_tile(snake_direction_t to) {
return construct_snake_tile(get_opposite_direction(to), to);
}
tile_t construct_zero_pupa(snake_direction_t to) {
if (to == snake_direction_left)
return tile_pupa_0_l;
if (to == snake_direction_right)
return tile_pupa_0_r;
if (to == snake_direction_top)
return tile_pupa_0_t;
if (to == snake_direction_bottom)
return tile_pupa_0_b;
check(false);
}
/* takes snake tile, returns it's target direction*/
snake_direction_t get_snake_destination(tile_t tile) {
switch (tile) {
case tile_snake_l:
return snake_direction_left;
case tile_snake_r:
return snake_direction_right;
case tile_snake_t:
return snake_direction_top;
case tile_snake_b:
return snake_direction_bottom;
case tile_snake_bl:
return snake_direction_left;
case tile_snake_br:
return snake_direction_right;
case tile_snake_lb:
return snake_direction_bottom;
case tile_snake_rb:
return snake_direction_bottom;
case tile_snake_tl:
return snake_direction_left;
case tile_snake_tr:
return snake_direction_right;
case tile_snake_lt:
return snake_direction_top;
case tile_snake_rt:
return snake_direction_top;
default:
check(false);
}
}
snake_direction_t get_zero_pupa_destination(tile_t tile) {
if (tile == tile_pupa_0_r)
return snake_direction_right;
if (tile == tile_pupa_0_l)
return snake_direction_left;
if (tile == tile_pupa_0_t)
return snake_direction_top;
if (tile == tile_pupa_0_b)
return snake_direction_bottom;
check(false);
}
bool is_tile_pupa(tile_t tile) {
if (tile == tile_pupa_0_r || tile == tile_pupa_0_l ||
tile == tile_pupa_0_b || tile == tile_pupa_0_t) {
return true;
}
return false;
}
void clear_frame(uint8_t color) {
for (uint32_t i = 0; i < FRAME_SIZE; i++) {
frame[i] = color;
}
}
void put_pixel(int x, int y, uint8_t color) {
if (x < 0 || x >= VGA_GRAPHICS_WIDTH || y < 0 || y >= VGA_GRAPHICS_HEIGHT) {
return;
}
frame[y * VGA_GRAPHICS_WIDTH + x] = color;
}
void draw_sprite(int dst_x, int dst_y, int sprite_width, int sprite_height,
const uint8_t *sprite) {
for (int x = 0; x < sprite_width; x++) {
for (int y = 0; y < sprite_height; y++) {
uint8_t color = sprite[x * sprite_height + y];
if (color != TRANSPARENCY_COLOR) {
put_pixel(dst_x + x, dst_y + y, color);
}
}
}
}
bool font_index_for_char(char ch, int *out_index) {
if (ch == ' ') {
*out_index = FONT_SPACE_INDEX;
return true;
}
if (ch >= '0' && ch <= '9') {
*out_index = FONT_DIGIT_BASE + (ch - '0');
return true;
}
if (ch >= 'A' && ch <= 'Z') {
*out_index = FONT_LETTER_BASE + (ch - 'A');
return true;
}
return false;
}
void draw_hud(const char *text) {
// int lines_count = 1;
int y0 = HUD_OFFSET;
for (const char *line_start = text; *line_start;) {
int glyph_count = 0;
const char *p = line_start;
for (; *p != '\n' && *p != 0; p++) {
glyph_count++;
}
if (glyph_count > 0) {
const int text_width =
glyph_count * FONT_WIDTH + (glyph_count - 1) * GLYPH_SPACING;
int x0 = VGA_GRAPHICS_WIDTH - HUD_OFFSET - text_width;
for (const char *q = line_start; q != p; q++) {
int glyph_index;
check(font_index_for_char(*q, &glyph_index));
draw_sprite(x0, y0, FONT_WIDTH, FONT_HEIGHT,
&sprite_data.font[glyph_index].tex[0][0]);
x0 += FONT_WIDTH + GLYPH_SPACING;
}
}
if (*p == 0) {
break;
}
line_start = p + 1;
y0 += FONT_HEIGHT + GLYPH_SPACING;
}
}
/* You see, we never store pupa hatching stage in world array.
* Instead, we store pupa 0 in world matrix and deduce the correct tile
* in draw_game_world using snake.waiting_reason
*/
tile_t correct_game_tile(tile_t x) {
/* waiting for p2 => we are in p1 */
if (snake.waiting_reason == waiting_reason_p2) {
if (x == tile_pupa_0_l)
return tile_pupa_p1_l;
if (x == tile_pupa_0_r)
return tile_pupa_p1_r;
if (x == tile_pupa_0_t)
return tile_pupa_p1_t;
if (x == tile_pupa_0_b)
return tile_pupa_p1_b;
}
/* waiting for cross => we are in p2 */
if (snake.waiting_reason == waiting_reason_cross) {
if (x == tile_pupa_0_l)
return tile_pupa_p2_l;
if (x == tile_pupa_0_r)
return tile_pupa_p2_r;
if (x == tile_pupa_0_t)
return tile_pupa_p2_t;
if (x == tile_pupa_0_b)
return tile_pupa_p2_b;
}
/* waiting for m1 => we are in m2 */
if (snake.waiting_reason == waiting_reason_m1) {
if (x == tile_pupa_0_l)
return tile_pupa_m2_l;
if (x == tile_pupa_0_r)
return tile_pupa_m2_r;
if (x == tile_pupa_0_t)
return tile_pupa_m2_t;
if (x == tile_pupa_0_b)
return tile_pupa_m2_b;
}
/* waiting for zero_pupa => we are in m1 */
if (snake.waiting_reason == waiting_reason_zero_pupa) {
if (x == tile_pupa_0_l)
return tile_pupa_m1_l;
if (x == tile_pupa_0_r)
return tile_pupa_m1_r;
if (x == tile_pupa_0_t)
return tile_pupa_m1_t;
if (x == tile_pupa_0_b)
return tile_pupa_m1_b;
}
/* When waiting postmortum, step or p1, pupa looks exactly the same
* (default is zero pupa) */
return x;
}
void draw_game_world() {
for (int tx = 0; tx < WORLD_WIDTH; tx++) {
for (int ty = 0; ty <= WORLD_HEIGHT; ty++) {
int iy = ty < WORLD_HEIGHT ? ty : 0;
tile_t tt = correct_game_tile(snake.world[tx][iy]);
if (tt == tile_empty)
continue;
check((uint8_t)tt < TILE_SPRITES);
draw_sprite(TILE_WIDTH * tx, TILE_WIDTH * ty - TILE_HEIGHT_OFFSET,
TILE_WIDTH, TILE_HEIGHT,
&sprite_data.tile[tt].tex[0][0]);
}
}
if (snake.game_screen != game_screen_gaming) {
for (uint32_t pix = 0; pix < FRAME_SIZE; pix++) {
frame[pix] = vga_to_gray(frame[pix]);
}
}
}
void draw_game_text() {
StringBuilder hud = {0};
if (snake.game_screen == game_screen_gaming) {
if (snake.waiting_reason == waiting_reason_postmortum) {
StringBuilder_append_cstr(&hud, "YOU DIED ");
} else if (snake.is_dying) {
StringBuilder_append_cstr(&hud, "LOL ");
}
// StringBuilder_append_u32(&hud, snake.animation_speed_boost);
// StringBuilder_append_cstr(&hud, " ");
StringBuilder_append_u32(&hud, snake.score);
} else if (snake.game_screen == game_screen_pause) {
if (snake.have_game) {
StringBuilder_append_cstr(&hud, "PAUSED\n");
}
StringBuilder_append_cstr(&hud, "PRESS 1 FOR NEW GAME\n");
if (snake.have_game) {
StringBuilder_append_cstr(&hud, "PRESS ESC TO CONTINUE\n");
}
StringBuilder_append_cstr(&hud, "PRESS Q TO QUIT\n");
} else if (snake.game_screen == game_screen_select_map) {
StringBuilder_append_cstr(&hud, "SELECT LEVEL\nCURRENTLY SELECTED\n");
check(snake.selected_map_index < PLAYABLE_MAPS_COUNT);
StringBuilder_append_cstr(&hud,
map_list.maps[snake.selected_map_index].name);
} else if (snake.game_screen == game_screen_select_apple_count) {
StringBuilder_append_cstr(&hud,
"SELECT DIFFICULTY\n"
"HOW MANY APPLES\nCURRENTLY SELECTED\n");
StringBuilder_append_u32(&hud, snake.gamemode_apples_count);
}
draw_hud(StringBuilder_get_cstr(&hud));
}
void draw_game_puddles() {
if (snake.puddle_sprite >= 0) {
const PuddleSprite *sprite = &sprite_data.puddle[snake.puddle_sprite];
draw_sprite(snake.puddle_center.x - PUDDLE_WIDTH / 2,
snake.puddle_center.y - PUDDLE_WIDTH / 2, PUDDLE_WIDTH,
PUDDLE_WIDTH, (&sprite->tex[0][0]));
}
}
void draw_frame() {
clear_frame(226);
if (snake.have_game) {
draw_game_puddles();
draw_game_world();
}
draw_game_text();
}
/* Called when game_screen is game_screen_gaming */
void handle_gaming_keycode(uint8_t keycode) {
if (keycode == KEYCODE_ESCAPE) {
snake.game_screen = game_screen_pause;
}
if (!snake.is_dying) {
if (is_keycode_for_press_left(keycode) &&
snake.cur_snake_direction != snake_direction_right) {
snake.new_snake_direction = snake_direction_left;
} else if (is_keycode_for_press_right(keycode) &&
snake.cur_snake_direction != snake_direction_left) {
snake.new_snake_direction = snake_direction_right;
} else if (is_keycode_for_press_up(keycode) &&
snake.cur_snake_direction != snake_direction_bottom) {
snake.new_snake_direction = snake_direction_top;
} else if (is_keycode_for_press_down(keycode) &&
snake.cur_snake_direction != snake_direction_top) {
snake.new_snake_direction = snake_direction_bottom;
}
}
}
/* return 1 if we are quitting */
int handle_incoming_keycode_after_halt(uint8_t keycode) {
if (keycode == KEYCODE_SPACE) {
snake.is_space_pressed = true;
} else if (keycode == (KEYCODE_SPACE | 0x80)) {
snake.is_space_pressed = false;
}
if (keycode == KEYCODE_SHIFT) {
snake.is_shift_pressed = true;
} else if (keycode == (KEYCODE_SHIFT | 0x80)) {
snake.is_shift_pressed = false;
}
if (keycode == KEYCODE_Q && snake.game_screen != game_screen_gaming) {
return 1;
}
if (snake.game_screen == game_screen_gaming) {
handle_gaming_keycode(keycode);
} else if (snake.game_screen == game_screen_pause) {
if (keycode == KEYCODE_1 ||
(keycode == KEYCODE_ENTER && !snake.have_game)) {
snake.game_screen = game_screen_select_map;
} else if (keycode == KEYCODE_ESCAPE && snake.have_game) {
snake.game_screen = game_screen_gaming;
}
} else if (snake.game_screen == game_screen_select_map) {
if (keycode == KEYCODE_ESCAPE) {
snake.game_screen = game_screen_pause;
} else if (is_keycode_for_press_left(keycode)) {
snake.selected_map_index--;
if (snake.selected_map_index < 0)
snake.selected_map_index = PLAYABLE_MAPS_COUNT - 1;
} else if (is_keycode_for_press_right(keycode)) {
snake.selected_map_index++;
if (snake.selected_map_index >= PLAYABLE_MAPS_COUNT)
snake.selected_map_index = 0;
} else if (keycode == KEYCODE_ENTER) {
snake.game_screen = game_screen_select_apple_count;
}
} else if (snake.game_screen == game_screen_select_apple_count) {
if (keycode == KEYCODE_ESCAPE) {
snake.game_screen = game_screen_select_map;
} else if (is_keycode_for_press_left(keycode)) {
if (snake.gamemode_apples_count > 1)
snake.gamemode_apples_count--;
} else if (is_keycode_for_press_right(keycode)) {
if (snake.gamemode_apples_count < SNAKE_GAMEMODE_MAX_APPLES)
snake.gamemode_apples_count++;
} else if (keycode == KEYCODE_ENTER) {
start_snake_game();
}
}
return 0;
}
/* Time flows only in gaming mode. This function can call frame drawing */
void handle_time_difference(uint32_t time_diff) {
if (snake.game_screen != game_screen_gaming)
return;
if (snake.waiting_reason == waiting_reason_postmortum)
return;
snake.waiting_time += time_diff;
uint32_t target_required_time;
if (snake.animation_speed_boost == 1) {
if (snake.waiting_reason == waiting_reason_step) {
target_required_time = WALKING_ANIM_TIME_FAST;
} else {
target_required_time = HATCHING_ANIM_TIME_FAST;
}
} else if (snake.animation_speed_boost == 0) {
if (snake.waiting_reason == waiting_reason_step) {
target_required_time = WALKING_ANIM_TIME_SLOW;
} else {
target_required_time = HATCHING_ANIM_TIME_SLOW;
}
} else {
if (snake.waiting_reason == waiting_reason_step) {
target_required_time = WALKING_ANIM_TIME_VERY_SLOW;
} else {
target_required_time = HATCHING_ANIM_TIME_VERY_SLOW;
}
}
if (snake.waiting_time > target_required_time) {
snake.waiting_time -= target_required_time;
if (snake.waiting_reason == waiting_reason_step) {
ivec2 tile_pos_ahead = world_walk_direction(
snake.snake_head, snake.new_snake_direction);
tile_t tile_ahead = get_tile(tile_pos_ahead);
/* Processing collisions */
if (tile_ahead == tile_apple) {
snake.ghost_apples[tile_pos_ahead.x][tile_pos_ahead.y] = 1;
snake.score += 5;
} else if (18 <= tile_ahead && tile_ahead <= 49) {
snake.waiting_reason = waiting_reason_postmortum;
snake.puddle_center = get_puddle_center_for_contact(
snake.snake_head, snake.new_snake_direction);
snake.puddle_sprite = 0;
return;
} else if (2 <= tile_ahead && tile_ahead <= 17) {
snake.is_dying = true;
snake.puddle_center = get_puddle_center_for_contact(
snake.snake_head, snake.new_snake_direction);
if (snake.puddle_sprite + 1 < PUDDLE_SPRITES) {
snake.puddle_sprite++;
}
}
/* normal stuff */
/* Step 1 */
ivec2 old_head_pos = snake.snake_head;
if (tile_ahead == tile_empty || tile_ahead == tile_apple) {
set_tile(tile_pos_ahead, construct_straight_snake_tile(
snake.new_snake_direction));
snake.snake_head = tile_pos_ahead;
}
/* Step 2 */
set_tile(old_head_pos,
construct_snake_tile(
get_opposite_direction(snake.cur_snake_direction),
snake.new_snake_direction));
snake.cur_snake_direction = snake.new_snake_direction;
/* Steps 3... */
if (is_tile_pupa(get_tile(snake.snake_tail))) {
/* Step 3a */
snake_direction_t pupa_dir =
get_zero_pupa_destination(get_tile(snake.snake_tail));
ivec2 penultimate_pos =
world_walk_direction(snake.snake_tail, pupa_dir);
set_tile(snake.snake_tail, tile_empty);
/* Step 4a */
snake_direction_t penultimate_part_dir =
get_snake_destination(get_tile(penultimate_pos));
set_tile(penultimate_pos,
construct_zero_pupa(penultimate_part_dir));
snake.snake_tail = penultimate_pos;
/* WARNING: we updated snake_tail by moving pupa forward, we
* WARNING: should check if we moved onto a ghost apple */
// check, this is important. This is the only place where we
// move pupa to a new pos we check for ghost apples. Clear ghost
// apples and enter p1-waiting state (instead of remaining in
// step awaiting state)
if (snake.snake_tail.x == snake.snake_head.x &&
snake.snake_tail.y == snake.snake_head.y) {
snake.waiting_reason = waiting_reason_postmortum;
return;
}
if (snake.ghost_apples[penultimate_pos.x][penultimate_pos.y]) {
snake.ghost_apples[penultimate_pos.x][penultimate_pos.y] =
0;
syscall(SYS_set_beep, WEIRD_SOUND);
snake.waiting_reason = waiting_reason_p1;
/* Nothing changed on screen because we need to wait even
* for the first stage of hatching.
* We could go to p1 immediately, though */
}
} else {
snake_direction_t tail_dir =
get_snake_destination(get_tile(snake.snake_tail));
set_tile(snake.snake_tail, construct_zero_pupa(tail_dir));
syscall(SYS_set_beep, WEIRD_SOUND);
snake.waiting_reason = waiting_reason_m1;
}
/* If we went with route 3a, pupa has moved and we definitely can
* place an apple. But if it had not and we went through route 3b,
* well, okay, we just won't have a free space for apple */
if (tile_ahead == tile_apple) {
place_random_apple();
}
} /* But there are more animation
targets that can finish, other than 'step' */
else if (snake.waiting_reason == waiting_reason_p1) {
snake.waiting_reason = waiting_reason_p2;
} else if (snake.waiting_reason == waiting_reason_p2) {
snake.waiting_reason = waiting_reason_cross;
} else if (snake.waiting_reason == waiting_reason_cross) {
/* Finished pupa hatching */
snake_direction_t tail_dir =
get_zero_pupa_destination(get_tile(snake.snake_tail));
set_tile(snake.snake_tail, construct_straight_snake_tile(tail_dir));
syscall(SYS_set_beep, 0);
snake.waiting_reason = waiting_reason_step;
} else if (snake.waiting_reason == waiting_reason_m1) {
snake.waiting_reason = waiting_reason_zero_pupa;
} else if (snake.waiting_reason == waiting_reason_zero_pupa) {
/* Finished pupa regrowing */
syscall(SYS_set_beep, 0);
snake.waiting_reason = waiting_reason_step;
}
}
}
void after_awake_action(uint32_t time_diff) {
handle_time_difference(time_diff);
snake.animation_speed_boost = 0;
draw_frame();
syscall(SYS_swap_frame, (uintptr_t)frame);
}
int main(void) {
init_snake();
syscall(SYS_switch_to_graphics, 0);
uint32_t prev_time = time_ms();
while (1) {
/* Returned from halt, we can enjoy keyboard input and animation
* progress*/
for (int ch; (ch = syscall(SYS_getc, 0)) >= 0;) {
int ret = handle_incoming_keycode_after_halt((uint8_t)ch);
if (ret == 1)
goto quit;
}
/* As an additional benefit, we can check if is_space_pressed here */
if (snake.is_space_pressed) {
snake.animation_speed_boost = 1;
} else if (snake.is_shift_pressed) {
snake.animation_speed_boost = -1;
}
/* snake.is_time_sped_up will be relevant when checking animation end */
uint32_t current_time = time_ms();
after_awake_action(current_time - prev_time);
prev_time = current_time;
syscall(SYS_halt, 0);
}
quit:
syscall(SYS_switch_to_text, 0);
syscall(SYS_puts, (uintptr_t)"Quit from game\n");
return 0;
}

2024
snake/sprite_data.h Normal file

File diff suppressed because it is too large Load Diff

37
snake/sprites.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#define TRANSPARENCY_COLOR 47
#define TILE_WIDTH 20
#define TILE_HEIGHT 32
#define TILE_HEIGHT_OFFSET 12
typedef struct {
uint8_t tex[TILE_WIDTH][TILE_HEIGHT];
} TileSprite;
#define FONT_WIDTH 12
#define FONT_HEIGHT 21
typedef struct {
uint8_t tex[FONT_WIDTH][FONT_HEIGHT];
} FontSprite;
#define PUDDLE_WIDTH 40
typedef struct {
uint8_t tex[PUDDLE_WIDTH][PUDDLE_WIDTH];
} PuddleSprite;
#define TILE_SPRITES 50
#define FONT_SPRITES (1 + 10 + 26)
#define PUDDLE_SPRITES 5
typedef struct {
TileSprite tile[TILE_SPRITES];
FontSprite font[FONT_SPRITES];
PuddleSprite puddle[PUDDLE_SPRITES];
} SpriteData;

View File

@ -8,6 +8,13 @@ enum {
SYS_greet = 1, SYS_greet = 1,
SYS_putc = 2, SYS_putc = 2,
SYS_puts = 3, SYS_puts = 3,
SYS_switch_to_text = 4,
SYS_switch_to_graphics = 5,
SYS_swap_frame = 6,
SYS_time_ms = 7,
SYS_halt = 8,
SYS_getc = 9,
SYS_set_beep = 10,
}; };
int syscall(int call, uintptr_t arg); int syscall(int call, uintptr_t arg);

View File

@ -1,7 +1,7 @@
#include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <unistd.h>
enum { enum {
MBR_END = 510, MBR_END = 510,

View File

@ -7,12 +7,9 @@ int syscall(int call, uintptr_t arg) {
return call; return call;
} }
_Noreturn _Noreturn void _exit(int exit_status) {
void _exit(int exit_status) {
syscall(SYS_exit, exit_status); syscall(SYS_exit, exit_status);
__builtin_unreachable(); __builtin_unreachable();
} }
void _start() { void _start() { _exit(main()); }
_exit(main());
}

View File

@ -1,3 +1 @@
int main() { int main() { return 1; }
return 1;
}

18
user/getc.c Normal file
View File

@ -0,0 +1,18 @@
#include "../snake/misc_utils.h"
#include "../syscall.h"
#include <stdint.h>
int main(void) {
while (1) {
int keycode = syscall(SYS_getc, 0);
if (keycode == -1) {
syscall(SYS_halt, 0);
continue;
}
StringBuilder sb = {0};
StringBuilder_append_u32(&sb, (uint32_t)keycode);
StringBuilder_putc(&sb, '\n');
syscall(SYS_puts, (uintptr_t)StringBuilder_get_cstr(&sb));
}
}

22
user/player.c Normal file
View File

@ -0,0 +1,22 @@
#include "../syscall.h"
#include <stdint.h>
static uint32_t time_ms(void) { return (uint32_t)syscall(SYS_time_ms, 0); }
static void wait_ms(uint32_t duration_ms) {
uint32_t start = time_ms();
while ((uint32_t)(time_ms() - start) < duration_ms) {
syscall(SYS_halt, 0);
}
}
int main(void) {
syscall(SYS_set_beep, 10000);
wait_ms(1000);
syscall(SYS_set_beep, 15000);
wait_ms(1000);
// syscall(SYS_set_beep, 0);
return 0;
}