From 862e24969c946dba32ef348db68095ace7c204a5 Mon Sep 17 00:00:00 2001 From: jdah <20308439+jdah@users.noreply.github.com> Date: Mon, 15 Mar 2021 14:19:55 +0100 Subject: [PATCH] Literally everything post-sound, pre-music Everything --- .gitignore | 59 ++++ Makefile | 52 ++++ bin/bootsect.bin | Bin 0 -> 512 bytes bin/kernel.bin | Bin 0 -> 37152 bytes boot.iso | Bin 0 -> 1474560 bytes src/font.c | 158 ++++++++++ src/font.h | 21 ++ src/font.o | Bin 0 -> 5472 bytes src/fpu.c | 15 + src/fpu.h | 8 + src/fpu.o | Bin 0 -> 2288 bytes src/idt.c | 39 +++ src/idt.h | 10 + src/idt.o | Bin 0 -> 4492 bytes src/irq.c | 82 ++++++ src/irq.h | 10 + src/irq.o | Bin 0 -> 7628 bytes src/isr.c | 172 +++++++++++ src/isr.h | 16 + src/isr.o | Bin 0 -> 7396 bytes src/keyboard.c | 66 +++++ src/keyboard.h | 87 ++++++ src/keyboard.o | Bin 0 -> 5876 bytes src/link.ld | 29 ++ src/main.c | 743 +++++++++++++++++++++++++++++++++++++++++++++++ src/main.o | Bin 0 -> 57268 bytes src/math.c | 46 +++ src/math.h | 15 + src/math.o | Bin 0 -> 3604 bytes src/music.c | 359 +++++++++++++++++++++++ src/music.h | 9 + src/screen.c | 41 +++ src/screen.h | 53 ++++ src/screen.o | Bin 0 -> 6384 bytes src/sound.c | 355 ++++++++++++++++++++++ src/sound.h | 50 ++++ src/sound.o | Bin 0 -> 24328 bytes src/speaker.c | 44 +++ src/speaker.h | 10 + src/speaker.o | Bin 0 -> 5244 bytes src/stage0.S | 203 +++++++++++++ src/stage0.o | Bin 0 -> 1772 bytes src/start.S | 126 ++++++++ src/start.o | Bin 0 -> 18764 bytes src/system.c | 35 +++ src/system.h | 21 ++ src/system.o | Bin 0 -> 4156 bytes src/timer.c | 48 +++ src/timer.h | 12 + src/timer.o | Bin 0 -> 4452 bytes src/util.h | 202 +++++++++++++ 51 files changed, 3196 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100755 bin/bootsect.bin create mode 100755 bin/kernel.bin create mode 100644 boot.iso create mode 100644 src/font.c create mode 100644 src/font.h create mode 100644 src/font.o create mode 100644 src/fpu.c create mode 100644 src/fpu.h create mode 100644 src/fpu.o create mode 100644 src/idt.c create mode 100644 src/idt.h create mode 100644 src/idt.o create mode 100644 src/irq.c create mode 100644 src/irq.h create mode 100644 src/irq.o create mode 100644 src/isr.c create mode 100644 src/isr.h create mode 100644 src/isr.o create mode 100644 src/keyboard.c create mode 100644 src/keyboard.h create mode 100644 src/keyboard.o create mode 100644 src/link.ld create mode 100644 src/main.c create mode 100644 src/main.o create mode 100644 src/math.c create mode 100644 src/math.h create mode 100644 src/math.o create mode 100644 src/music.c create mode 100644 src/music.h create mode 100644 src/screen.c create mode 100644 src/screen.h create mode 100644 src/screen.o create mode 100644 src/sound.c create mode 100644 src/sound.h create mode 100644 src/sound.o create mode 100644 src/speaker.c create mode 100644 src/speaker.h create mode 100644 src/speaker.o create mode 100644 src/stage0.S create mode 100644 src/stage0.o create mode 100644 src/start.S create mode 100644 src/start.o create mode 100644 src/system.c create mode 100644 src/system.h create mode 100644 src/system.o create mode 100644 src/timer.c create mode 100644 src/timer.h create mode 100644 src/timer.o create mode 100644 src/util.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3345747 --- /dev/null +++ b/.gitignore @@ -0,0 +1,59 @@ +bin/ +*.iso + +*.icloud +.DS_Store +.vscode + +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..af179a4 --- /dev/null +++ b/Makefile @@ -0,0 +1,52 @@ +CC=i386-elf-gcc +ASM=i386-elf-as +LD=i386-elf-ld + +GFLAGS= +CCFLAGS=-m32 -std=c11 -O2 -g -Wall -Wextra -Wpedantic -Wstrict-aliasing +CCFLAGS+=-Wno-pointer-arith -Wno-unused-parameter +CCFLAGS+=-nostdlib -nostdinc -ffreestanding -fno-pie -fno-stack-protector +CCFLAGS+=-fno-builtin-function -fno-builtin +ASFLAGS= +LDFLAGS= + +BOOTSECT_SRCS=\ + src/stage0.S + +BOOTSECT_OBJS=$(BOOTSECT_SRCS:.S=.o) + +KERNEL_C_SRCS=$(wildcard src/*.c) +KERNEL_S_SRCS=$(filter-out $(BOOTSECT_SRCS), $(wildcard src/*.S)) +KERNEL_OBJS=$(KERNEL_C_SRCS:.c=.o) $(KERNEL_S_SRCS:.S=.o) + +BOOTSECT=bootsect.bin +KERNEL=kernel.bin +ISO=boot.iso + +all: dirs bootsect kernel + +dirs: + mkdir -p bin + +clean: + rm ./**/*.o + rm ./*.iso + rm ./**/*.elf + rm ./**/*.bin + +%.o: %.c + $(CC) -o $@ -c $< $(GFLAGS) $(CCFLAGS) + +%.o: %.S + $(ASM) -o $@ -c $< $(GFLAGS) $(ASFLAGS) + +bootsect: $(BOOTSECT_OBJS) + $(LD) -o ./bin/$(BOOTSECT) $^ -Ttext 0x7C00 --oformat=binary + +kernel: $(KERNEL_OBJS) + $(LD) -o ./bin/$(KERNEL) $^ $(LDFLAGS) -Tsrc/link.ld + +iso: bootsect kernel + dd if=/dev/zero of=boot.iso bs=512 count=2880 + dd if=./bin/$(BOOTSECT) of=boot.iso conv=notrunc bs=512 seek=0 count=1 + dd if=./bin/$(KERNEL) of=boot.iso conv=notrunc bs=512 seek=1 count=2048 diff --git a/bin/bootsect.bin b/bin/bootsect.bin new file mode 100755 index 0000000000000000000000000000000000000000..afe78312c02034fd85b374cf184f4dafc4ba6f51 GIT binary patch literal 512 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 literal 0 HcmV?d00001 diff --git a/boot.iso b/boot.iso new file mode 100644 index 0000000000000000000000000000000000000000..0b92f22605fba4ad237d4a2806501180e1a9d289 GIT binary patch literal 1474560 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%0DpRN2`KIS~MvT;;bPelu3up66hM`Goe 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 zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7{(mL#-vQ}w Botppv literal 0 HcmV?d00001 diff --git a/src/font.c b/src/font.c new file mode 100644 index 0000000..f276499 --- /dev/null +++ b/src/font.c @@ -0,0 +1,158 @@ +#include "font.h" +#include "screen.h" +#include "system.h" + +// 8x8 font for ASCII 0..127 +static const u8 FONT[128][8] = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space) + { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) + { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (") + { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#) + { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($) + { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%) + { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&) + { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (') + { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() + { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ()) + { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*) + { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,) + { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.) + { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/) + { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0) + { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1) + { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) + { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3) + { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4) + { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5) + { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6) + { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7) + { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8) + { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;) + { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) + { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=) + { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>) + { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?) + { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@) + { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A) + { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B) + { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C) + { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) + { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G) + { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H) + { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I) + { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J) + { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K) + { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L) + { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M) + { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N) + { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O) + { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) + { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q) + { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R) + { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S) + { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V) + { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W) + { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X) + { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y) + { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) + { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([) + { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\) + { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (]) + { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_) + { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`) + { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a) + { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b) + { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c) + { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) + { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e) + { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g) + { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h) + { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i) + { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j) + { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k) + { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l) + { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m) + { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) + { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o) + { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q) + { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r) + { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s) + { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v) + { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w) + { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y) + { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z) + { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({) + { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|) + { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (}) + { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F +}; + +void font_char(char c, size_t x, size_t y, u8 color) { + assert(c >= 0, "INVALID CHARACTER"); + + const u8 *glyph = FONT[(size_t) c]; + + for (size_t yy = 0; yy < 8; yy++) { + for (size_t xx = 0; xx < 8; xx++) { + if (glyph[yy] & (1 << xx)) { + screen_set(color, x + xx, y + yy); + } + } + } +} + +void font_str(const char *s, size_t x, size_t y, u8 color) { + char c; + + while ((c = *s++) != 0) { + font_char(c, x, y, color); + x += 8; + } +} diff --git a/src/font.h b/src/font.h new file mode 100644 index 0000000..9e695e4 --- /dev/null +++ b/src/font.h @@ -0,0 +1,21 @@ +#ifndef FONT_H +#define FONT_H + +#include "util.h" +#include "screen.h" + +#define font_width(_s) (strlen((_s)) * 8) +#define font_height() (8) +#define font_str_doubled(_s, _x, _y, _c) do {\ + const char *__s = (_s);\ + __typeof__(_x) __x = (_x);\ + __typeof__(_y) __y = (_y);\ + __typeof__(_c) __c = (_c);\ + font_str(__s, __x + 1, __y + 1, COLOR_ADD(__c, -2));\ + font_str(__s, __x, __y, __c);\ + } while (0); + +void font_char(char c, size_t x, size_t y, u8 color); +void font_str(const char *s, size_t x, size_t y, u8 color); + +#endif diff --git a/src/font.o b/src/font.o new file mode 100644 index 0000000000000000000000000000000000000000..4832b541d61dc53a3646f67af7a2e4a00eef323d GIT binary patch literal 5472 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 16) & 0xFFFF, + .selector = selector, + .type = flags | 0x60, + .__ignored = 0 + }; +} + +void idt_init() { + idt.pointer.limit = sizeof(idt.entries) - 1; + idt.pointer.base = (uintptr_t) &idt.entries[0]; + memset(&idt.entries[0], 0, sizeof(idt.entries)); + idt_load((uintptr_t) &idt.pointer); +} diff --git a/src/idt.h b/src/idt.h new file mode 100644 index 0000000..9f4ca2e --- /dev/null +++ b/src/idt.h @@ -0,0 +1,10 @@ +#ifndef IDT_H +#define IDT_H + +#include "util.h" +#include "isr.h" + +void idt_set(u8 index, void (*base)(struct Registers*), u16 selector, u8 flags); +void idt_init(); + +#endif diff --git a/src/idt.o b/src/idt.o new file mode 100644 index 0000000000000000000000000000000000000000..09316536415a25fe7401b68b16cc639a25734e61 GIT binary patch literal 4492 zcma)9U2I%O6`r|&d+lAX*WR_gCJx<1j*>vVwv*60p=qqxX`5n7n*M`YXT5vZd+B=D zy?eJLC6GWQnl!DN097jyHC2WB^U#NiidH<7R!tfeBnU4^r4I;%AVNr}5(OlX%=gXC zwXflYBh7s0Z_b=KGk0e9#DTe6q?95eDNL~@2{D`QSavDcCI&=KoV|P0?fvoWs8v0a zyG;GrxzSYhOzN@${(bARMcor~qnT45966o3Y(skY&lx&9VBb4;>MyD46s5S2QUfw@qL8K~=Xwjv5V92VuuxFrM_@S$VIwUC1fZ~)!l>(&DQu;% z&GkwYuBUK);xrTMQu9nCeyfB&T6VdfkI>!9GUb+$TDMBzCfBRhA@tL0I`JWTvwMib ztlOejf&6X4c?IA~)BS|&e;%E*x^9F{B(9>9wh|0g8R@uNptBM`qgz4=cH+BqbCsJT zoKGM*GU;x_iAy|9zmyKg!z+7wpM--Ux*S(#+!;FkmHNH`@}he?h5jKXgY%W-rrZTX ziroq~e-4@+zY+?WH93ckQzk_Ej~utznFhZbOu@6mN7=t?Zq0;uTM8TCUUPD?(o83l9ficGL{H23>Ihj2y z-`by~`u^kt$@`MjXKXQjKNmMgKiyO7dB_dR>cek2IN*X z;h>Equ~WS$7MXkz1?jAA>u^EMJ&eJt6~KPQV_~D>i^FCy5caAl_6^@O+(<{kuz%7< zbpTQwWS(OSC)d45?kgQ>C2^75gJ@mCTuBJAEJiL;EOk`8si~q^Tki!)Q71f&hM2gh zl{mqihFS-Y4`|gwDM}%-F$wxgaR|Ml5%l=pK%JL>Ty*u5e-+IXJJCz|uQU#5=fUG~ zZ3Sg~mX)wr=7-b{{d%!R&Tj=BM%Z@>TLm|Vq=Py+U$8U4{QdS$<1;xszsHtm>^^70 zw)fgY%Hg~{sPLj?*g5mpEN(VuCvnL+8OOJiFs2KDgN_U>Ml@eJA#Le=U|2}));sPg z%uG%eb{BUPCkkUrJ9nT9+YN88zjNva@TH(!)BIv#>`O4W!phzHoW6QqRVW2KQJhmJ(L$4e*gN|~c?bk!UF;;Ci%AwzEtka5?|Cl!)ie|Oi^1}I= zzgQD(JblYy0PVrqyAL$N;FuV{r{x8$@vl~DAdvR}+dh z-1tIO>&;Rq+KraK*zhWaa;+3F*r6sudx2OewLHcjVTejfhKz^jNQZwdK` zWj&zMY%kP3aoAh*TL^#|gYtN1OY2RPVO^AULbYC6YzgJ`zn++LzR?tQf5{JdLgtZn zC8|Ze`L)jMv{*m7V@|&H>50!Pjm)4o_P{q1`_27v}rWHO=2dUsij8_qzkvD*S-oG zI)pH*WQmVgRs}HYe*scfpXI8HiSG>Gzaq!wr?`FwQ>fb{<{x=?R3@*A7@4cDWMogp zteju}2-R9sRbb7<6u8;6$a?f6Bixs(wV)i;i*Br+{^+p}t6R6aCuG!a!>tERVtKI20t|) z@B!_2MB}2yhQ{L>zoqdhjr_sE`Ciocvc@+weh~+R_AhIEO5@8K-_ZE3#$RasNaHn) zf7fVY4UCu3xJ~2dG~TPRMnt`rv>X!A9@qG!#utbc}ZvSHG=+^y3Y(1gdPT2kjDR-MXVK^%`Mm?4_f|v& z%`l&63{~%-eJ>gWKCGo-x9?O!AE1j zia#J;yw;Iz8Mb(SrxA~NF&^)?DBel%9K$-2&g1_3M-&7yS+=tpBfrxK&R7vee$PQc zo}UZp0{rGWtm-*0>HBE${LaPJ%XLTj#ba^YH4Mr?$v1^B5&h`TSh3?F{)wXTOh&{w TB;M(9zZWp?i^|gJBESCtgijO+ literal 0 HcmV?d00001 diff --git a/src/irq.c b/src/irq.c new file mode 100644 index 0000000..4a02786 --- /dev/null +++ b/src/irq.c @@ -0,0 +1,82 @@ +#include "irq.h" +#include "idt.h" +#include "isr.h" + +// PIC constants +#define PIC1 0x20 +#define PIC1_OFFSET 0x20 +#define PIC1_DATA (PIC1 + 1) + +#define PIC2 0xA0 +#define PIC2_OFFSET 0x28 +#define PIC2_DATA (PIC2 + 1) + +#define PIC_EOI 0x20 +#define PIC_MODE_8086 0x01 +#define ICW1_ICW4 0x01 +#define ICW1_INIT 0x10 + +#define PIC_WAIT() do { \ + asm ("jmp 1f\n\t" \ + "1:\n\t" \ + " jmp 2f\n\t"\ + "2:"); \ + } while (0) + +static void (*handlers[32])(struct Registers *regs) = { 0 }; + +static void stub(struct Registers *regs) { + if (regs->int_no <= 47 && regs->int_no >= 32) { + if (handlers[regs->int_no - 32]) { + handlers[regs->int_no - 32](regs); + } + } + + // send EOI + if (regs->int_no >= 0x40) { + outportb(PIC2, PIC_EOI); + } + + outportb(PIC1, PIC_EOI); +} + +static void irq_remap() { + u8 mask1 = inportb(PIC1_DATA), mask2 = inportb(PIC2_DATA); + outportb(PIC1, ICW1_INIT | ICW1_ICW4); + outportb(PIC2, ICW1_INIT | ICW1_ICW4); + outportb(PIC1_DATA, PIC1_OFFSET); + outportb(PIC2_DATA, PIC2_OFFSET); + outportb(PIC1_DATA, 0x04); // PIC2 at IRQ2 + outportb(PIC2_DATA, 0x02); // Cascade indentity + outportb(PIC1_DATA, PIC_MODE_8086); + outportb(PIC1_DATA, PIC_MODE_8086); + outportb(PIC1_DATA, mask1); + outportb(PIC2_DATA, mask2); +} + +static void irq_set_mask(size_t i) { + u16 port = i < 8 ? PIC1_DATA : PIC2_DATA; + u8 value = inportb(port) | (1 << i); + outportb(port, value); +} + +static void irq_clear_mask(size_t i) { + u16 port = i < 8 ? PIC1_DATA : PIC2_DATA; + u8 value = inportb(port) & ~(1 << i); + outportb(port, value); +} + +void irq_install(size_t i, void (*handler)(struct Registers *)) { + CLI(); + handlers[i] = handler; + irq_clear_mask(i); + STI(); +} + +void irq_init() { + irq_remap(); + + for (size_t i = 0; i < 16; i++) { + isr_install(32 + i, stub); + } +} diff --git a/src/irq.h b/src/irq.h new file mode 100644 index 0000000..27a23b6 --- /dev/null +++ b/src/irq.h @@ -0,0 +1,10 @@ +#ifndef IRQ_H +#define IRQ_H + +#include "util.h" +#include "isr.h" + +void irq_install(size_t i, void (*handler)(struct Registers*)); +void irq_init(); + +#endif diff --git a/src/irq.o b/src/irq.o new file mode 100644 index 0000000000000000000000000000000000000000..da1420c536c5fec29e9ae5e3f67d500a3205fe06 GIT binary patch literal 7628 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 literal 0 HcmV?d00001 diff --git a/src/isr.c b/src/isr.c new file mode 100644 index 0000000..a3884aa --- /dev/null +++ b/src/isr.c @@ -0,0 +1,172 @@ +#include "isr.h" +#include "idt.h" +#include "system.h" + +#define NUM_ISRS 48 + +extern void _isr0(struct Registers*); +extern void _isr1(struct Registers*); +extern void _isr2(struct Registers*); +extern void _isr3(struct Registers*); +extern void _isr4(struct Registers*); +extern void _isr5(struct Registers*); +extern void _isr6(struct Registers*); +extern void _isr7(struct Registers*); +extern void _isr8(struct Registers*); +extern void _isr9(struct Registers*); +extern void _isr10(struct Registers*); +extern void _isr11(struct Registers*); +extern void _isr12(struct Registers*); +extern void _isr13(struct Registers*); +extern void _isr14(struct Registers*); +extern void _isr15(struct Registers*); +extern void _isr16(struct Registers*); +extern void _isr17(struct Registers*); +extern void _isr18(struct Registers*); +extern void _isr19(struct Registers*); +extern void _isr20(struct Registers*); +extern void _isr21(struct Registers*); +extern void _isr22(struct Registers*); +extern void _isr23(struct Registers*); +extern void _isr24(struct Registers*); +extern void _isr25(struct Registers*); +extern void _isr26(struct Registers*); +extern void _isr27(struct Registers*); +extern void _isr28(struct Registers*); +extern void _isr29(struct Registers*); +extern void _isr30(struct Registers*); +extern void _isr31(struct Registers*); +extern void _isr32(struct Registers*); +extern void _isr33(struct Registers*); +extern void _isr34(struct Registers*); +extern void _isr35(struct Registers*); +extern void _isr36(struct Registers*); +extern void _isr37(struct Registers*); +extern void _isr38(struct Registers*); +extern void _isr39(struct Registers*); +extern void _isr40(struct Registers*); +extern void _isr41(struct Registers*); +extern void _isr42(struct Registers*); +extern void _isr43(struct Registers*); +extern void _isr44(struct Registers*); +extern void _isr45(struct Registers*); +extern void _isr46(struct Registers*); +extern void _isr47(struct Registers*); + +static void (*stubs[NUM_ISRS])(struct Registers*) = { + _isr0, + _isr1, + _isr2, + _isr3, + _isr4, + _isr5, + _isr6, + _isr7, + _isr8, + _isr9, + _isr10, + _isr11, + _isr12, + _isr13, + _isr14, + _isr15, + _isr16, + _isr17, + _isr18, + _isr19, + _isr20, + _isr21, + _isr22, + _isr23, + _isr24, + _isr25, + _isr26, + _isr27, + _isr28, + _isr29, + _isr30, + _isr31, + _isr32, + _isr33, + _isr34, + _isr35, + _isr36, + _isr37, + _isr38, + _isr39, + _isr40, + _isr41, + _isr42, + _isr43, + _isr44, + _isr45, + _isr46, + _isr47, +}; + +static const char *exceptions[32] = { + "Divide by zero", + "Debug", + "NMI", + "Breakpoint", + "Overflow", + "OOB", + "Invalid opcode", + "No coprocessor", + "Double fault", + "Coprocessor segment overrun", + "Bad TSS", + "Segment not present", + "Stack fault", + "General protection fault", + "Page fault", + "Unrecognized interrupt", + "Coprocessor fault", + "Alignment check", + "Machine check", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED", + "RESERVED" +}; + +static struct { + size_t index; + void (*stub)(struct Registers*); +} isrs[NUM_ISRS]; + +static void (*handlers[NUM_ISRS])(struct Registers*) = { 0 }; + +void isr_install(size_t i, void (*handler)(struct Registers*)) { + handlers[i] = handler; +} + +// referenced from start.S +void isr_handler(struct Registers *regs) { + if (handlers[regs->int_no]) { + handlers[regs->int_no](regs); + } +} + +static void exception_handler(struct Registers *regs) { + panic(exceptions[regs->int_no]); +} + +void isr_init() { + for (size_t i = 0; i < NUM_ISRS; i++) { + isrs[i].index = i; + isrs[i].stub = stubs[i]; + idt_set(isrs[i].index, isrs[i].stub, 0x08, 0x8E); + } + + for (size_t i = 0; i < 32; i++) { + isr_install(i, exception_handler); + } +} diff --git a/src/isr.h b/src/isr.h new file mode 100644 index 0000000..0507ee8 --- /dev/null +++ b/src/isr.h @@ -0,0 +1,16 @@ +#ifndef ISR_H +#define ISR_H + +#include "util.h" + +struct Registers { + u32 __ignored, fs, es, ds; + u32 edi, esi, ebp, esp, ebx, edx, ecx, eax; + u32 int_no, err_no; + u32 eip, cs, efl, useresp, ss; +}; + +void isr_install(size_t i, void (*handler)(struct Registers*)); +void isr_init(); + +#endif diff --git a/src/isr.o b/src/isr.o new file mode 100644 index 0000000000000000000000000000000000000000..5ac82485155562e4018f00446a6f3569b0bc7b55 GIT binary patch literal 7396 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 PDSq8(_hsJ+===Q-Hqd$M literal 0 HcmV?d00001 diff --git a/src/keyboard.c b/src/keyboard.c new file mode 100644 index 0000000..6ec3cec --- /dev/null +++ b/src/keyboard.c @@ -0,0 +1,66 @@ +#include "keyboard.h" +#include "irq.h" +#include "system.h" +#include "timer.h" + +u8 keyboard_layout_us[2][128] = { + { + KEY_NULL, KEY_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '-', '=', KEY_BACKSPACE, KEY_TAB, 'q', 'w', 'e', 'r', 't', 'y', 'u', + 'i', 'o', 'p', '[', ']', KEY_ENTER, 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', + 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', + ',', '.', '/', 0, 0, 0, ' ', 0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, + KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, 0, 0, KEY_HOME, KEY_UP, + KEY_PAGE_UP, '-', KEY_LEFT, '5', KEY_RIGHT, '+', KEY_END, KEY_DOWN, + KEY_PAGE_DOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, KEY_F11, KEY_F12 + }, { + KEY_NULL, KEY_ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', + '_', '+', KEY_BACKSPACE, KEY_TAB, 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', + 'I', 'O', 'P', '{', '}', KEY_ENTER, 0, 'A', 'S', 'D', 'F', 'G', 'H', + 'J', 'K', 'L', ':', '\"', '~', 0, '|', 'Z', 'X', 'C', 'V', 'B', 'N', + 'M', '<', '>', '?', 0, 0, 0, ' ', 0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, + KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, 0, 0, KEY_HOME, KEY_UP, + KEY_PAGE_UP, '-', KEY_LEFT, '5', KEY_RIGHT, '+', KEY_END, KEY_DOWN, + KEY_PAGE_DOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, KEY_F11, KEY_F12 + } +}; + +struct Keyboard keyboard; + +// bad hack! for a better RNG +static bool seeded = false; + +static void keyboard_handler(struct Registers *regs) { + u16 scancode = (u16) inportb(0x60); + + if (!seeded) { + seed(((u32) scancode) * 17 + timer_get()); + seeded = true; + } + + if (KEY_SCANCODE(scancode) == KEY_LALT || + KEY_SCANCODE(scancode) == KEY_RALT) { + keyboard.mods = BIT_SET(keyboard.mods, HIBIT(KEY_MOD_ALT), KEY_IS_PRESS(scancode)); + } else if ( + KEY_SCANCODE(scancode) == KEY_LCTRL || + KEY_SCANCODE(scancode) == KEY_RCTRL) { + keyboard.mods = BIT_SET(keyboard.mods, HIBIT(KEY_MOD_CTRL), KEY_IS_PRESS(scancode)); + } else if ( + KEY_SCANCODE(scancode) == KEY_LSHIFT || + KEY_SCANCODE(scancode) == KEY_RSHIFT) { + keyboard.mods = BIT_SET(keyboard.mods, HIBIT(KEY_MOD_SHIFT), KEY_IS_PRESS(scancode)); + } else if (KEY_SCANCODE(scancode) == KEY_CAPS_LOCK) { + keyboard.mods = BIT_SET(keyboard.mods, HIBIT(KEY_MOD_CAPS_LOCK), KEY_IS_PRESS(scancode)); + } else if (KEY_SCANCODE(scancode) == KEY_NUM_LOCK) { + keyboard.mods = BIT_SET(keyboard.mods, HIBIT(KEY_MOD_NUM_LOCK), KEY_IS_PRESS(scancode)); + } else if (KEY_SCANCODE(scancode) == KEY_SCROLL_LOCK) { + keyboard.mods = BIT_SET(keyboard.mods, HIBIT(KEY_MOD_SCROLL_LOCK), KEY_IS_PRESS(scancode)); + } + + keyboard.keys[(u8) (scancode & 0x7F)] = KEY_IS_PRESS(scancode); + keyboard.chars[KEY_CHAR(scancode)] = KEY_IS_PRESS(scancode); +} + +void keyboard_init() { + irq_install(1, keyboard_handler); +} diff --git a/src/keyboard.h b/src/keyboard.h new file mode 100644 index 0000000..2beceb2 --- /dev/null +++ b/src/keyboard.h @@ -0,0 +1,87 @@ +#ifndef KEYBOARD_H +#define KEYBOARD_H + +#include "util.h" + +// TODO: some of this it 100% wrong lmao +#define KEY_NULL 0 +#define KEY_ESC 27 +#define KEY_BACKSPACE '\b' +#define KEY_TAB '\t' +#define KEY_ENTER '\n' +#define KEY_RETURN '\r' + +#define KEY_INSERT 0x90 +#define KEY_DELETE 0x91 +#define KEY_HOME 0x92 +#define KEY_END 0x93 +#define KEY_PAGE_UP 0x94 +#define KEY_PAGE_DOWN 0x95 +#define KEY_LEFT 0x4B +#define KEY_UP 0x48 +#define KEY_RIGHT 0x4D +#define KEY_DOWN 0x50 + +#define KEY_F1 0x80 +#define KEY_F2 (KEY_F1 + 1) +#define KEY_F3 (KEY_F1 + 2) +#define KEY_F4 (KEY_F1 + 3) +#define KEY_F5 (KEY_F1 + 4) +#define KEY_F6 (KEY_F1 + 5) +#define KEY_F7 (KEY_F1 + 6) +#define KEY_F8 (KEY_F1 + 7) +#define KEY_F9 (KEY_F1 + 8) +#define KEY_F10 (KEY_F1 + 9) +#define KEY_F11 (KEY_F1 + 10) +#define KEY_F12 (KEY_F1 + 11) + +#define KEY_LCTRL 0x1D +#define KEY_RCTRL 0x1D + +#define KEY_LALT 0x38 +#define KEY_RALT 0x38 + +#define KEY_LSHIFT 0x2A +#define KEY_RSHIFT 0x36 + +#define KEY_CAPS_LOCK 0x3A +#define KEY_SCROLL_LOCK 0x46 +#define KEY_NUM_LOCK 0x45 + +#define KEY_MOD_ALT 0x0200 +#define KEY_MOD_CTRL 0x0400 +#define KEY_MOD_SHIFT 0x0800 +#define KEY_MOD_CAPS_LOCK 0x1000 +#define KEY_MOD_NUM_LOCK 0x2000 +#define KEY_MOD_SCROLL_LOCK 0x4000 + +#define KEYBOARD_RELEASE 0x80 + +#define KEYBOARD_BUFFER_SIZE 256 + +#define KEY_IS_PRESS(_s) (!((_s) & KEYBOARD_RELEASE)) +#define KEY_IS_RELEASE(_s) (!!((_s) & KEYBOARD_RELEASE)) +#define KEY_SCANCODE(_s) ((_s) & 0x7F) +#define KEY_MOD(_s, _m) (!!((_s) & (_m))) +#define KEY_CHAR(_s) __extension__({\ + __typeof__(_s) __s = (_s);\ + KEY_SCANCODE(__s) < 128 ?\ + keyboard_layout_us[KEY_MOD(__s, KEY_MOD_SHIFT) ? 1 : 0][KEY_SCANCODE(__s)] :\ + 0;\ + }) + +struct Keyboard { + u16 mods; + bool keys[128]; + bool chars[128]; +}; + +extern u8 keyboard_layout_us[2][128]; +extern struct Keyboard keyboard; + +#define keyboard_key(_s) (keyboard.keys[(_s)]) +#define keyboard_char(_c) (keyboard.chars[(u8) (_c)]) + +void keyboard_init(); + +#endif diff --git a/src/keyboard.o b/src/keyboard.o new file mode 100644 index 0000000000000000000000000000000000000000..3824b8a3c497eaf98d5579b142fea898d2a3e393 GIT binary patch literal 5876 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 0 && (_y) >= 0 && (_x) < BOARD_WIDTH && (_y) < BOARD_HEIGHT) + +// max size of 4x4 to account for all rotations +#define TTM_SIZE 4 + +#define TTM_BLOCK(_t, _i, _j) (((_t) & (1 << (((_j) * 4) + (_i)))) != 0) + +#define TTM_OFFSET_X(_t)\ + MIN(_t & 0x000F ? LOBIT((_t >> 0) & 0xF) : 3,\ + MIN(_t & 0x00F0 ? LOBIT((_t >> 4) & 0xF) : 3,\ + MIN(_t & 0x0F00 ? LOBIT((_t >> 8) & 0xF) : 3,\ + _t & 0xF000 ? LOBIT((_t >> 12) & 0xF) : 3))) + +#define TTM_WIDTH(_t)\ + 1 + MAX(HIBIT((_t >> 0) & 0xF),\ + MAX(HIBIT((_t >> 4) & 0xF),\ + MAX(HIBIT((_t >> 8) & 0xF), HIBIT((_t >> 12) & 0xF)))) -\ + TTM_OFFSET_X(_t) + +#define TTM_HEIGHT(_t) ((HIBIT(_t) / 4) - (LOBIT(_t) / 4) + 1) +#define TTM_OFFSET_Y(_t) (LOBIT(_t) / 4) + +#define TTM_FOREACH(_xname, _yname, _xxname, _yyname, _xbase, _ybase)\ + for (i32 _yname = 0, _yyname = (_ybase); _yname < TTM_SIZE; _yname++,_yyname++)\ + for (i32 _xname = 0, _xxname = (_xbase); _xname < TTM_SIZE; _xname++,_xxname++)\ + +struct Tetromino { + enum Tile color; + u16 rotations[4]; +}; + +#define NUM_TETROMINOS 7 +static const struct Tetromino TETROMINOS[NUM_TETROMINOS] = { + { + // line + .color = CYAN, + .rotations = { + 0x00F0, + 0x2222, + 0x0F00, + 0x4444 + } + }, { + // left L + .color = BLUE, + .rotations = { + 0x8E00, + 0x6440, + 0x0E20, + 0x44C0 + } + }, { + // right L + .color = ORANGE, + .rotations = { + 0x2E00, + 0x4460, + 0x0E80, + 0xC440 + } + }, { + // cube + .color = YELLOW, + .rotations = { + 0xCC00, + 0xCC00, + 0xCC00, + 0xCC00 + } + }, { + // right skew + .color = GREEN, + .rotations = { + 0x6C00, + 0x4620, + 0x06C0, + 0x8C40 + } + }, { + // left skew + .color = RED, + .rotations = { + 0xC600, + 0x2640, + 0x0C60, + 0x4C80 + } + }, { + // T + .color = PURPLE, + .rotations = { + 0x4E00, + 0x4640, + 0x0E40, + 0x4C40 + } + } +}; + +#define NUM_LEVELS 30 + +// from listfist.com/list-of-tetris-levels-by-speed-nes-ntsc-vs-pal +static u8 FRAMES_PER_STEP[NUM_LEVELS] = { + 48, 43, 38, 33, 28, 23, 18, 13, 8, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1 +}; + +static u32 LINE_MULTIPLIERS[4] = { + 40, 100, 300, 1200 +}; + +#define NUM_CONTROLS 7 +struct Control { + bool down; + bool last; + bool pressed; + u32 pressed_frames; +}; + +static struct { + u8 board[BOARD_HEIGHT][BOARD_WIDTH]; + + u32 frames, steps, frames_since_step; + u32 score, lines, level; + i32 lines_left; + bool menu, pause, stopped, destroy, game_over, music; + + const struct Tetromino *next; + + struct { + const struct Tetromino *ttm; + u8 r; + i32 x, y; + bool done; + } curr; + + union { + struct { + struct Control rotate_left; + struct Control rotate_right; + struct Control rotate; + struct Control left; + struct Control right; + struct Control down; + struct Control fast_down; + }; + struct Control raw[NUM_CONTROLS]; + } controls; +} state; + +static void done() { + // flash tetromino which was just placed + TTM_FOREACH(x, y, xx, yy, state.curr.x, state.curr.y) { + if (IN_BOARD(xx, yy) && + TTM_BLOCK(state.curr.ttm->rotations[state.curr.r], x, y)) { + state.board[yy][xx] |= TILE_FLAG_FLASH; + } + } + + // check for lines + u32 lines = 0; + + for (size_t y = 0; y < BOARD_HEIGHT; y++) { + bool line = true; + + for (size_t x = 0; x < BOARD_WIDTH; x++) { + if ((state.board[y][x] & TILE_MASK) == NONE) { + line = false; + break; + } + } + + if (line) { + lines++; + + for (size_t x = 0; x < BOARD_WIDTH; x++) { + state.board[y][x] |= TILE_FLAG_FLASH | TILE_FLAG_DESTROY; + } + + state.destroy = true; + } + } + + if (lines > 0) { + state.lines += lines; + state.score += LINE_MULTIPLIERS[lines - 1] * (state.level + 1); + + // check for leveling up + if (state.level != NUM_LEVELS - 1) { + state.lines_left -= lines; + if (state.lines_left <= 0) { + state.level++; + state.lines_left = 10; + } + } + } + + // new tetromino is spawned in update() after destroy + state.curr.done = true; +} + +static bool try_modify( + const struct Tetromino *ttm, u16 tc, i32 xc, i32 yc, u16 tn, i32 xn, i32 yn) { + u8 board[BOARD_HEIGHT][BOARD_WIDTH]; + memcpy(&board, &state.board, sizeof(board)); + + // clear current tiles + if (tc != 0) { + TTM_FOREACH(x, y, xx, yy, xc, yc) { + if (IN_BOARD(xx, yy) && TTM_BLOCK(tc, x, y)) { + state.board[yy][xx] = NONE; + } + } + } + + TTM_FOREACH(x, y, xx, yy, xn, yn) { + if (yy < 0) { + if (TTM_BLOCK(tn, x, y) && + (xx < 0 || xx >= BOARD_WIDTH)) { + goto fail; + } + + continue; + } else if (!TTM_BLOCK(tn, x, y)) { + continue; + } else if (!IN_BOARD(xx, yy) || state.board[yy][xx] != NONE || + xx < 0 || xx > (BOARD_WIDTH - 1)) { + goto fail; + } + + state.board[yy][xx] = ttm->color; + } + + return true; +fail: + memcpy(&state.board, &board, sizeof(board)); + return false; +} + +static bool spawn() { + if (state.next == NULL) { + state.next = &TETROMINOS[rand() % NUM_TETROMINOS]; + } + + state.curr.ttm = state.next; + state.curr.r = 0; + state.curr.x = (BOARD_WIDTH / 2) - 2; + state.curr.y = -TTM_OFFSET_Y(state.curr.ttm->rotations[state.curr.r]) - 1; + state.curr.done = false; + + if (!try_modify( + state.curr.ttm, + 0, 0, 0, + state.curr.ttm->rotations[state.curr.r], + state.curr.x, state.curr.y)) { + return false; + } + + state.next = &TETROMINOS[rand() % NUM_TETROMINOS]; + return true; +} + +static bool move(i32 dx, i32 dy) { + if (try_modify( + state.curr.ttm, + state.curr.ttm->rotations[state.curr.r], + state.curr.x, state.curr.y, + state.curr.ttm->rotations[state.curr.r], + state.curr.x + dx, state.curr.y + dy)) { + state.curr.x += dx; + state.curr.y += dy; + return true; + } + + return false; +} + +static bool rotate(bool right) { + u8 r = (state.curr.r + (right ? 1 : -1) + 4) % 4; + + if (try_modify( + state.curr.ttm, + state.curr.ttm->rotations[state.curr.r], + state.curr.x, state.curr.y, + state.curr.ttm->rotations[r], + state.curr.x, state.curr.y)) { + state.curr.r = r; + return true; + } + + return false; +} + +static void generate_sprites() { + for (enum Tile t = 0; t < NUM_TILES; t++) { + if (t == NONE) { + continue; + } + + u8 color = TILE_COLORS[t]; + u8 *pixels = TILE_SPRITES[t]; + + for (size_t y = 0; y < TILE_SIZE; y++) { + for (size_t x = 0; x < TILE_SIZE; x++) { + u8 c = color; + + if (y == 0 || x == 0) { + c = COLOR_ADD(color, 1); + } else if (y == TILE_SIZE - 1 || x == TILE_SIZE - 1) { + c = COLOR_ADD(color, -1); + } + + pixels[y * TILE_SIZE + x] = c; + } + } + } +} + +static void render_tile(enum Tile tile, size_t x, size_t y) { + u8 *pixels = TILE_SPRITES[tile]; + for (size_t j = 0; j < TILE_SIZE; j++) { + memcpy(&screen_offset(x, y + j), pixels + (j * TILE_SIZE), TILE_SIZE); + } +} + +static void render_border() { + for (size_t y = 0; y < (SCREEN_HEIGHT / TILE_SIZE); y++) { + size_t yy = BOARD_Y + (y * TILE_SIZE); + + render_tile( + BORDER, + BOARD_X - TILE_SIZE, + yy + ); + + render_tile( + BORDER, + BOARD_X + (BOARD_WIDTH * TILE_SIZE), + yy + ); + } +} + +static void render_board() { + for (size_t y = 0; y < BOARD_HEIGHT; y++) { + for (size_t x = 0; x < BOARD_WIDTH; x++) { + u8 data = state.board[y][x]; + enum Tile tile = data & TILE_MASK; + + size_t xs = BOARD_X + (x * TILE_SIZE), + ys = BOARD_Y + (y * TILE_SIZE); + + if (data & TILE_FLAG_FLASH) { + screen_fill(COLOR(4, 4, 1), xs, ys, TILE_SIZE, TILE_SIZE); + } else if (tile != NONE) { + render_tile(tile, xs, ys); + } + } + } +} + +static void render_ui() { +#define X_OFFSET_RIGHT (BOARD_X + BOARD_WIDTH_PX + (TILE_SIZE * 2)) + +#define RENDER_STAT(_title, _value, _color, _x, _y, _w) do {\ + char buf[32];\ + itoa((_value), buf, 32);\ + font_str_doubled((_title), (_x), (_y), COLOR(7, 7, 3));\ + font_str_doubled(buf, (_x) + (_w) - font_width(buf), (_y) + TILE_SIZE, (_color));\ + } while (0); + + size_t w = font_width("SCORE"); + RENDER_STAT("SCORE", state.score, COLOR(5, 5, 0), X_OFFSET_RIGHT, TILE_SIZE * 1, w); + RENDER_STAT("LINES", state.lines, COLOR(5, 3, 0), X_OFFSET_RIGHT, TILE_SIZE * 4, w); + RENDER_STAT("LEVEL", state.level, COLOR(5, 0, 0), X_OFFSET_RIGHT, TILE_SIZE * 7, w); + +#define X_OFFSET_LEFT (BOARD_X - (TILE_SIZE * 8)) +#define Y_OFFSET_LEFT TILE_SIZE + + font_str_doubled("NEXT", X_OFFSET_LEFT, TILE_SIZE, COLOR(7, 7, 3)); + + for (size_t j = 0; j < TTM_SIZE; j++) { + for (size_t i = 0; i < TTM_SIZE; i++) { + u16 tiles = state.next->rotations[0]; + + if (TTM_BLOCK(tiles, i, j)) { + render_tile( + state.next->color, + X_OFFSET_LEFT + ((i - TTM_OFFSET_X(tiles)) * TILE_SIZE), + Y_OFFSET_LEFT + (TILE_SIZE / 2) + ((j - TTM_OFFSET_Y(tiles) + 1) * TILE_SIZE) + ); + } + } + } +} + +static void render_game_over() { + const size_t w = SCREEN_WIDTH / 3, h = SCREEN_HEIGHT / 3; + screen_fill( + COLOR(4, 4, 2), + (SCREEN_WIDTH - w) / 2, + (SCREEN_HEIGHT - h) / 2, + w, + h + ); + + screen_fill( + COLOR(2, 2, 1), + (SCREEN_WIDTH - (w - 8)) / 2, + (SCREEN_HEIGHT - (h - 8)) / 2, + w - 8, + h - 8 + ); + + font_str_doubled( + "GAME OVER", + (SCREEN_WIDTH - font_width("GAME OVER")) / 2, + (SCREEN_HEIGHT / 2) - TILE_SIZE, + (state.frames / 5) % 2 == 0 ? + COLOR(6, 2, 1) : + COLOR(7, 4, 2) + ); + + char buf_score[64]; + itoa(state.score, buf_score, 64); + + font_str_doubled( + "SCORE:", + (SCREEN_WIDTH - font_width("SCORE:")) / 2, + (SCREEN_HEIGHT / 2), + COLOR(6, 6, 0) + ); + + font_str_doubled( + buf_score, + (SCREEN_WIDTH - font_width(buf_score)) / 2, + (SCREEN_HEIGHT / 2) + TILE_SIZE, + COLOR(7, 7, 3) + ); +} + +static void step() { + bool stopped = !move(0, 1); + + if (stopped && state.stopped) { + // twice stop = end for this tetromino + done(); + } + + state.stopped = stopped; +} + +void reset(u32 level) { + // initialize game state + memset(&state, 0, sizeof(state)); + state.frames_since_step = FRAMES_PER_STEP[0]; + state.level = 0; + state.lines_left = state.level * 10 + 10; + spawn(); +} + +static void update() { + if (state.game_over) { + if (keyboard_char('\n')) { + reset(0); + } + + return; + } + + // un-flash flashing tiles, remove destroy tiles + for (size_t y = 0; y < BOARD_HEIGHT; y++) { + bool destroy = false; + + for (size_t x = 0; x < BOARD_WIDTH; x++) { + u8 data = state.board[y][x]; + + if (data & TILE_FLAG_DESTROY) { + state.board[y][x] = NONE; + destroy = true; + } else { + state.board[y][x] &= ~TILE_FLAG_FLASH; + } + } + + if (destroy) { + if (y != 0) { + memmove( + &state.board[1], + &state.board[0], + sizeof(state.board[0]) * y + ); + } + + memset(&state.board[0], NONE, sizeof(state.board[0])); + } + } + + // spawn a new tetromino if the current one is done + if (state.curr.done && !spawn()) { + state.game_over = true; + return; + } + + if (state.destroy) { + state.destroy = false; + return; + } + + const bool control_states[NUM_CONTROLS] = { + keyboard_char('a'), + keyboard_char('d'), + keyboard_char('r'), + keyboard_key(KEY_LEFT), + keyboard_key(KEY_RIGHT), + keyboard_key(KEY_DOWN), + keyboard_char(' ') + }; + + for (size_t i = 0; i < NUM_CONTROLS; i++) { + struct Control *c = &state.controls.raw[i]; + c->last = c->down; + c->down = control_states[i]; + c->pressed = !c->last && c->down; + + if (c->pressed) { + c->pressed_frames = state.frames; + } + } + + if (state.controls.rotate_left.pressed) { + rotate(false); + } else if (state.controls.rotate_right.pressed || + state.controls.rotate.pressed) { + rotate(true); + } + + if (state.controls.left.down && + (state.frames - state.controls.left.pressed_frames) % 2 == 0) { + move(-1, 0); + } else if (state.controls.right.down && + (state.frames - state.controls.right.pressed_frames) % 2 == 0) { + move(1, 0); + } else if (state.controls.down.down && + (state.frames - state.controls.down.pressed_frames) % 2 == 0) { + if (!move(0, 1)) { + done(); + } + } else if (state.controls.fast_down.pressed) { + while (move(0, 1)); + done(); + } + + if (--state.frames_since_step == 0) { + step(); + state.steps++; + state.frames_since_step = FRAMES_PER_STEP[state.level]; + } +} + +static void render() { + screen_clear(COLOR(0, 0, 0)); + render_border(); + render_board(); + render_ui(); + + if (state.game_over) { + render_game_over(); + } +} + +void update_menu() { + if (keyboard_char('\n')) { + reset(0); + state.menu = false; + } +} + +void render_menu() { + screen_clear(COLOR(0, 0, 0)); + + // render logo + size_t logo_width = strlen(LOGO[0]), + logo_x = (SCREEN_WIDTH - (logo_width * TILE_SIZE)) / 2, + logo_y = TILE_SIZE * 3; + + for (i32 x = -1; x < (i32) logo_width + 1; x++) { + render_tile(BORDER, logo_x + (x * TILE_SIZE), logo_y - (TILE_SIZE * 2)); + render_tile(BORDER, logo_x + (x * TILE_SIZE), logo_y + (TILE_SIZE * (1 + LOGO_HEIGHT))); + } + + for (size_t y = 0; y < LOGO_HEIGHT; y++) { + for (size_t x = 0; x < logo_width; x++) { + char c = LOGO[y][x]; + + if (c == ' ' || c == '\t' || c == '\n') { + continue; + } + + render_tile( + GREEN + ((((state.frames / 10) + (6 - (c - 'A'))) / 6) % 8), + logo_x + (x * TILE_SIZE), + logo_y + (y * TILE_SIZE) + ); + } + } + + const char *play = "PRESS ENTER TO PLAY"; + font_str_doubled( + play, + (SCREEN_WIDTH - font_width(play)) / 2, + logo_y + ((LOGO_HEIGHT + 6) * TILE_SIZE), + (state.frames / 6) % 2 == 0 ? + COLOR(6, 6, 2) : + COLOR(7, 7, 3) + ); +} + +void _main(u32 magic) { + idt_init(); + isr_init(); + fpu_init(); + irq_init(); + screen_init(); + timer_init(); + keyboard_init(); + sound_init(); + generate_sprites(); + music_init(); + + state.menu = true; + + state.music = true; + sound_master(255); + + bool last_music_toggle = false; + u32 last_frame = 0, last = 0; + + while (true) { + const u32 now = (u32) timer_get(); + + if (now != last) { + music_tick(); + last = now; + } + + if ((now - last_frame) > (TIMER_TPS / FPS)) { + last_frame = now; + + if (state.menu) { + update_menu(); + render_menu(); + } else { + update(); + render(); + } + + if (keyboard_char('m')) { + if (!last_music_toggle) { + state.music = !state.music; + sound_master(state.music ? 255 : 0); + } + + last_music_toggle = true; + } else { + last_music_toggle = false; + } + + screen_swap(); + state.frames++; + } + } +} diff --git a/src/main.o b/src/main.o new file mode 100644 index 0000000000000000000000000000000000000000..a3c8dc379a4983c4eb1d0a18505386394160389d GIT binary patch literal 57268 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 literal 0 HcmV?d00001 diff --git a/src/math.c b/src/math.c new file mode 100644 index 0000000..8b4b7e3 --- /dev/null +++ b/src/math.c @@ -0,0 +1,46 @@ +#include "math.h" + +f64 fabs(f64 x) { + return x < 0.0 ? -x : x; +} + +f64 fmod(f64 x, f64 m) { + f64 result; + asm("1: fprem\n\t" + "fnstsw %%ax\n\t" + "sahf\n\t" + "jp 1b" + : "=t"(result) : "0"(x), "u"(m) : "ax", "cc"); + return result; +} + +f64 sin(f64 x) { + f64 result; + asm("fsin" : "=t"(result) : "0"(x)); + return result; +} + +f64 cos(f64 x) { + return sin(x + PI / 2.0); +} + +// black magic +f64 pow(f64 x, f64 y) { + f64 out; + asm( + "fyl2x;" + "fld %%st;" + "frndint;" + "fsub %%st,%%st(1);" + "fxch;" + "fchs;" + "f2xm1;" + "fld1;" + "faddp;" + "fxch;" + "fld1;" + "fscale;" + "fstp %%st(1);" + "fmulp;" : "=t"(out) : "0"(x),"u"(y) : "st(1)" ); + return out; +} diff --git a/src/math.h b/src/math.h new file mode 100644 index 0000000..dbf1a6f --- /dev/null +++ b/src/math.h @@ -0,0 +1,15 @@ +#ifndef MATH_H +#define MATH_H + +#include "util.h" + +#define E 2.71828 +#define PI 3.14159265358979323846264338327950 + +f64 fmod(f64 x, f64 m); +f64 fabs(f64 x); +f64 sin(f64 x); +f64 cos(f64 x); +f64 pow(f64 x, f64 y); + +#endif diff --git a/src/math.o b/src/math.o new file mode 100644 index 0000000000000000000000000000000000000000..e0ce7bd5f6eef3a9c7473abb2195ddbc3a634d04 GIT binary patch literal 3604 zcma)8O>7%Q6rQnn9Tz)}6Sqy$A8@M#im08W4TTocmi_<*RG=uL6-britYd@Y4ZCal z1GGrJ6a-R%101S?_!Ea7dZX$AN{fVg;($Q7G&J0LKnMilNBn-@>`bx^2YAx#_rCYu zym>RTGrNbk-*=~!QW%jUF6NjJZ(kF7h83(5i^U=_y{*q`efMSS^32a4Z*Rt0Gv_PE zU`s3eua{>|9Q&s3r>zlUvT7Mn+IDP)bCz&hk_e1M! z>yJy{v@Wz}THm*>eEku$E3H4LTVG!|AC{n=H=nDnc=KY%g}*n2#!D#HQmQ5Uf$87z zSgB|5L>MDtX)6I!ENOiMOH3v|A;j9Q5UjQgA=!3H`4XQipWTBFam%hX0{Cp$5NUP6 zXjRq?i&!?h8YX+n-6!NS+k<`|8Y_^;nLV)|_IBE1FNwqfkcA;hwz(S%rW$#vkwEOt4m}{%2r%3Js1<*`LX!;+dtHPT7^nb|a`y zq*5DU!UkzIiEUXd;>iuE+fwUOJ95~WqTJML3^(-d$g%h4o>#Z@N_Z1?BskWC8iu2W z?)SG~oaAyjl-ngwZ%K`I?@sMWJ)9C^fh~q|vCw}_N{%8dH9TiZ&mT3P;&AQJ;e^Ow zu*_Vk9jcQy{HxS#G+2+^Swv;C6T%X!sxS@66dK=qDIOuEU}5E2;AXTX;wABOa`i9$ zKlP`hXKCdxt6!&oJ6cQxcxsWfutgGvFZ%WKjYSv+t~M?MjiH%CO3j=~>MYBY#zBm{ z2_-IW!c)rMGwpb)JBl;$y|NIKrJ!0Yb7sw;Rxehm3A|@t>N30J# zk&8*xRCgN_dG+8m(QNp&iH0+tC#jUid{LQn$HiScNAp{UhVtu+Yl?&U!sOaDcm&Oc zGg4c7>pJKquUysoM80r8+sW*2>gM-3A~zLz>O#F+PZZ^eifGJ z#&CTEuO5m#xJ$^VlX7X=vW{YNv#{}HqVPtc(8kNsTvx`n4T`x~Xrq5O8e@4^imjRK zXvR|gr$EikP1k(kdu7BDKm2WU;?-YD@_5t@7JiwGF)nPQDvXQ7JdS%TB5|=G!kAxw zjI}i`()0Z7^LWQR-Z_tFg&C1++J#fZ3}!vaX*X+0z8KuBBl!|=vwq~}WX`?+{QmIk z#!saXH={``17|LA^K%9g4^~FxcZ{e$fH=%6$Z_$q2HMsA0$iv0h(_)?{r76zrE!nO z35^Yn&l8dV10ojToW{?z{YQ6+fNV?_o2owwEv<;wO)8+bzK`Y=7BNv8`gNY#z!><8b#4RFd3A_fPoic)o7km zF9y#3KorMIK}i(Hd|wnjm!w$sgQ0a`2pMTWq2Sn^7Z z2?v?NSi|Nr)oTsMcu|TdmfcBS5MdIhy0_w$CLPrOf8{y^V!38d71t#Cu`#ESKPWs| zo6#s!+*e=@jr|!%-mkei)$f2ug|QTVrWpTUaXdHdWA3k0(7B&RsIzTBGr8$Ii#8K6 z7`VK-jeV~fNaD+cIWOKe3B0BA_BJN!(T1<|k;L&kUgK&R1 zF7G!p?rYH5XAq4tf_v!>lLVY9+gln<+#xKk*+aNy<4$QE%d6xV;-1wyf#Xt6qDAXF z3$h9}*2jC$)W@++E~p}l`*Jgkyq|fqGmh)YT;|<_DjvXOuce}ec__>sjk|)5XOt&= Hn7Drc|K6&3 literal 0 HcmV?d00001 diff --git a/src/music.c b/src/music.c new file mode 100644 index 0000000..9865812 --- /dev/null +++ b/src/music.c @@ -0,0 +1,359 @@ +#include "music.h" +#include "timer.h" +#include "sound.h" +#include "math.h" + +struct Note { + u8 octave; + u8 note; + u16 duration; +}; + +struct NoteActive { + struct Note note; + double ticks; +}; + +#define TRACK_BPM 150 +#define TRACK_BPS (TRACK_BPM / 60.0) +#define TICKS_PER_BEAT (TIMER_TPS / TRACK_BPS) +#define TICKS_PER_SIXTEENTH (TICKS_PER_BEAT / 16.0) + +#define CHORUS_MELODY_LENGTH (sizeof(CHORUS_MELODY) / sizeof(CHORUS_MELODY[0])) +static const struct Note CHORUS_MELODY[] = { + // CHORUS MELODY + { OCTAVE_5, NOTE_E, 16 }, + { OCTAVE_4, NOTE_B, 8 }, + { OCTAVE_5, NOTE_C, 8 }, + { OCTAVE_5, NOTE_D, 16 }, + + { OCTAVE_5, NOTE_C, 8 }, + { OCTAVE_4, NOTE_B, 8 }, + { OCTAVE_4, NOTE_A, 16 }, + + { OCTAVE_4, NOTE_A, 8 }, + { OCTAVE_5, NOTE_C, 8 }, + { OCTAVE_5, NOTE_E, 16 }, + + { OCTAVE_5, NOTE_D, 8 }, + { OCTAVE_5, NOTE_C, 8 }, + { OCTAVE_4, NOTE_B, 16 }, + + { OCTAVE_4, NOTE_B, 8 }, + { OCTAVE_5, NOTE_C, 8 }, + { OCTAVE_5, NOTE_D, 16 }, + { OCTAVE_5, NOTE_E, 16 }, + { OCTAVE_5, NOTE_C, 16 }, + { OCTAVE_4, NOTE_A, 16 }, + { OCTAVE_4, NOTE_A, 16 }, + { OCTAVE_4, NOTE_NONE, 24 }, + + { OCTAVE_5, NOTE_D, 16 }, + { OCTAVE_5, NOTE_F, 8 }, + { OCTAVE_5, NOTE_A, 8 }, + { OCTAVE_5, NOTE_A, 4 }, + { OCTAVE_5, NOTE_A, 4 }, + { OCTAVE_5, NOTE_G, 8 }, + { OCTAVE_5, NOTE_F, 8 }, + { OCTAVE_5, NOTE_E, 16 }, + { OCTAVE_5, NOTE_NONE, 8 }, + + { OCTAVE_5, NOTE_C, 8 }, + { OCTAVE_5, NOTE_E, 8 }, + { OCTAVE_5, NOTE_E, 4 }, + { OCTAVE_5, NOTE_E, 4 }, + { OCTAVE_5, NOTE_D, 8 }, + { OCTAVE_5, NOTE_C, 8 }, + { OCTAVE_4, NOTE_B, 16 }, + + { OCTAVE_4, NOTE_B, 8 }, + { OCTAVE_5, NOTE_C, 8 }, + { OCTAVE_5, NOTE_D, 16 }, + { OCTAVE_5, NOTE_E, 16 }, + { OCTAVE_5, NOTE_C, 16 }, + { OCTAVE_4, NOTE_A, 16 }, + { OCTAVE_4, NOTE_A, 16 }, + { OCTAVE_4, NOTE_NONE, 16 }, +}; + +#define BRIDGE_MELODY_LENGTH (sizeof(BRIDGE_MELODY) / sizeof(BRIDGE_MELODY[0])) +static const struct Note BRIDGE_MELODY[] = { + // BRIDGE + { OCTAVE_4, NOTE_E, 32 }, + { OCTAVE_4, NOTE_C, 32 }, + { OCTAVE_4, NOTE_D, 32 }, + { OCTAVE_3, NOTE_B, 32 }, + { OCTAVE_4, NOTE_C, 32 }, + { OCTAVE_3, NOTE_A, 32 }, + { OCTAVE_3, NOTE_AF, 48 }, + { OCTAVE_3, NOTE_NONE, 16 }, + + { OCTAVE_4, NOTE_E, 32 }, + { OCTAVE_4, NOTE_C, 32 }, + { OCTAVE_4, NOTE_D, 32 }, + { OCTAVE_3, NOTE_B, 32 }, + { OCTAVE_3, NOTE_A, 16 }, + { OCTAVE_4, NOTE_E, 16 }, + { OCTAVE_4, NOTE_A, 32 }, + { OCTAVE_4, NOTE_AF, 48 }, + { OCTAVE_4, NOTE_NONE, 16 }, +}; + +#define BASS_NOTE(_octave, _note)\ + { _octave, _note, 8 },\ + { (_octave + 1), _note, 8 } + +#define BASS_HALF_MEASURE(_octave, _note)\ + BASS_NOTE(_octave, _note),\ + BASS_NOTE(_octave, _note) + +#define BASS_MEASURE(_octave, _note)\ + BASS_HALF_MEASURE(_octave, _note),\ + BASS_HALF_MEASURE(_octave, _note) + +#define CHORUS_BASS_LENGTH (sizeof(CHORUS_BASS) / sizeof(CHORUS_BASS[0])) +static const struct Note CHORUS_BASS[] = { + // CHORUS BASS + BASS_MEASURE(OCTAVE_2, NOTE_E), + BASS_MEASURE(OCTAVE_2, NOTE_A), + BASS_HALF_MEASURE(OCTAVE_2, NOTE_AF), + BASS_HALF_MEASURE(OCTAVE_2, NOTE_E), + BASS_HALF_MEASURE(OCTAVE_2, NOTE_A), + { OCTAVE_2, NOTE_A, 8 }, + { OCTAVE_2, NOTE_A, 8 }, + { OCTAVE_2, NOTE_B, 8 }, + { OCTAVE_3, NOTE_C, 8 }, + + BASS_MEASURE(OCTAVE_2, NOTE_D), + BASS_MEASURE(OCTAVE_2, NOTE_C), + BASS_HALF_MEASURE(OCTAVE_2, NOTE_AF), + BASS_HALF_MEASURE(OCTAVE_2, NOTE_E), + BASS_MEASURE(OCTAVE_2, NOTE_A), +}; + +#define BRIDGE_BASS_NOTE(_octave_0, _note_0, _octave_1, _note_1)\ + { _octave_0, _note_0, 8 },\ + { _octave_1, _note_1, 8 } + +#define BRIDGE_BASS_HALF_MEASURE(_octave_0, _note_0, _octave_1, _note_1)\ + BRIDGE_BASS_NOTE(_octave_0, _note_0, _octave_1, _note_1),\ + BRIDGE_BASS_NOTE(_octave_0, _note_0, _octave_1, _note_1) + +#define BRIDGE_BASS_MEASURE(_octave_0, _note_0, _octave_1, _note_1)\ + BRIDGE_BASS_HALF_MEASURE(_octave_0, _note_0, _octave_1, _note_1),\ + BRIDGE_BASS_HALF_MEASURE(_octave_0, _note_0, _octave_1, _note_1) + +#define BRIDGE_BASS_LENGTH (sizeof(BRIDGE_BASS) / sizeof(BRIDGE_BASS[0])) +static const struct Note BRIDGE_BASS[] = { + BRIDGE_BASS_MEASURE(OCTAVE_2, NOTE_A, OCTAVE_3, NOTE_E), + BRIDGE_BASS_MEASURE(OCTAVE_2, NOTE_AF, OCTAVE_3, NOTE_E), + + BRIDGE_BASS_HALF_MEASURE(OCTAVE_2, NOTE_A, OCTAVE_3, NOTE_E), + BRIDGE_BASS_HALF_MEASURE(OCTAVE_2, NOTE_E, OCTAVE_2, NOTE_A), + + BRIDGE_BASS_HALF_MEASURE(OCTAVE_2, NOTE_E, OCTAVE_2, NOTE_AF), + BRIDGE_BASS_NOTE(OCTAVE_2, NOTE_E, OCTAVE_2, NOTE_AF), + { OCTAVE_2, NOTE_E, 8 }, + { OCTAVE_2, NOTE_NONE, 8 }, + + BRIDGE_BASS_MEASURE(OCTAVE_2, NOTE_A, OCTAVE_3, NOTE_E), + BRIDGE_BASS_MEASURE(OCTAVE_2, NOTE_AF, OCTAVE_3, NOTE_E), + + BRIDGE_BASS_HALF_MEASURE(OCTAVE_2, NOTE_A, OCTAVE_3, NOTE_E), + BRIDGE_BASS_HALF_MEASURE(OCTAVE_2, NOTE_E, OCTAVE_2, NOTE_A), + + BRIDGE_BASS_HALF_MEASURE(OCTAVE_2, NOTE_E, OCTAVE_2, NOTE_AF), + BRIDGE_BASS_NOTE(OCTAVE_2, NOTE_E, OCTAVE_2, NOTE_AF), + { OCTAVE_2, NOTE_E, 8 }, + { OCTAVE_2, NOTE_NONE, 8 } +}; + +#define CHORUS_HARMONY_LENGTH (sizeof(CHORUS_HARMONY) / sizeof(CHORUS_HARMONY[0])) +static const struct Note CHORUS_HARMONY[] = { + // CHORUS HARMONY + { OCTAVE_5, NOTE_NONE, 16 }, + { OCTAVE_4, NOTE_AF, 8 }, + { OCTAVE_4, NOTE_A, 8 }, + { OCTAVE_4, NOTE_B, 16 }, + + { OCTAVE_4, NOTE_A, 8 }, + { OCTAVE_4, NOTE_AF, 8 }, + { OCTAVE_4, NOTE_E, 16 }, + + { OCTAVE_4, NOTE_E, 8 }, + { OCTAVE_4, NOTE_A, 8 }, + { OCTAVE_4, NOTE_A, 16 }, + + { OCTAVE_4, NOTE_B, 8 }, + { OCTAVE_4, NOTE_A, 8 }, + { OCTAVE_4, NOTE_AF, 16 }, + + { OCTAVE_4, NOTE_AF, 8 }, + { OCTAVE_4, NOTE_A, 8 }, + { OCTAVE_4, NOTE_B, 16 }, + { OCTAVE_5, NOTE_C, 16 }, + { OCTAVE_4, NOTE_A, 16 }, + { OCTAVE_4, NOTE_E, 16 }, + { OCTAVE_4, NOTE_E, 16 }, + { OCTAVE_4, NOTE_NONE, 24 }, + + { OCTAVE_4, NOTE_F, 16 }, + { OCTAVE_4, NOTE_A, 8 }, + { OCTAVE_5, NOTE_C, 16 }, + { OCTAVE_4, NOTE_B, 8 }, + { OCTAVE_4, NOTE_A, 8 }, + { OCTAVE_4, NOTE_G, 16 }, + { OCTAVE_4, NOTE_NONE, 8 }, + + { OCTAVE_4, NOTE_E, 8 }, + { OCTAVE_4, NOTE_G, 16 }, + { OCTAVE_4, NOTE_F, 8 }, + { OCTAVE_4, NOTE_E, 8 }, + { OCTAVE_4, NOTE_AF, 16 }, + + { OCTAVE_4, NOTE_AF, 8 }, + { OCTAVE_4, NOTE_A, 8 }, + { OCTAVE_4, NOTE_B, 16 }, + { OCTAVE_5, NOTE_C, 16 }, + { OCTAVE_4, NOTE_A, 16 }, + { OCTAVE_4, NOTE_E, 16 }, + { OCTAVE_4, NOTE_E, 16 }, + { OCTAVE_4, NOTE_NONE, 16 }, +}; + +#define BRIDGE_HARMONY_LENGTH (sizeof(BRIDGE_HARMONY) / sizeof(BRIDGE_HARMONY[0])) +static const struct Note BRIDGE_HARMONY[] = { + { OCTAVE_4, NOTE_C, 32 }, + { OCTAVE_3, NOTE_A, 32 }, + { OCTAVE_3, NOTE_B, 32 }, + { OCTAVE_3, NOTE_AF, 32 }, + { OCTAVE_3, NOTE_A, 32 }, + { OCTAVE_3, NOTE_E, 32 }, + { OCTAVE_3, NOTE_E, 48 }, + { OCTAVE_3, NOTE_NONE, 16 }, + + { OCTAVE_4, NOTE_C, 32 }, + { OCTAVE_3, NOTE_A, 32 }, + { OCTAVE_3, NOTE_B, 32 }, + { OCTAVE_3, NOTE_AF, 32 }, + { OCTAVE_3, NOTE_E, 16 }, + { OCTAVE_3, NOTE_A, 16 }, + { OCTAVE_4, NOTE_E, 32 }, + { OCTAVE_4, NOTE_E, 48 }, + { OCTAVE_4, NOTE_NONE, 16 }, +}; + +#define SNARE_OCTAVE OCTAVE_4 +#define SNARE_NOTE NOTE_E +#define SNARE_AND\ + { SNARE_OCTAVE, NOTE_NONE, 8},\ + { SNARE_OCTAVE, SNARE_NOTE, 2},\ + { SNARE_OCTAVE, NOTE_NONE, 6} +#define SNARE_EIGTH\ + { SNARE_OCTAVE, SNARE_NOTE, 2},\ + { SNARE_OCTAVE, NOTE_NONE, 6} + +#define SNARE_MEASURE\ + SNARE_AND,\ + SNARE_AND,\ + SNARE_AND,\ + SNARE_AND + +#define CHORUS_SNARE_LENGTH (sizeof(CHORUS_SNARE) / sizeof(CHORUS_SNARE[0])) +static const struct Note CHORUS_SNARE[] = { + SNARE_MEASURE, + SNARE_MEASURE, + SNARE_MEASURE, + SNARE_AND, + SNARE_AND, + SNARE_AND, + SNARE_EIGTH, + SNARE_EIGTH, + SNARE_MEASURE, + SNARE_MEASURE, + SNARE_MEASURE, + SNARE_AND, + SNARE_AND, + SNARE_AND, + SNARE_EIGTH, + SNARE_EIGTH, +}; + +#define BRIDGE_SNARE_LENGTH (sizeof(BRIDGE_SNARE) / sizeof(BRIDGE_SNARE[0])) +static const struct Note BRIDGE_SNARE[] = { + SNARE_MEASURE, + SNARE_MEASURE, + SNARE_MEASURE, + SNARE_MEASURE, + SNARE_MEASURE, + SNARE_MEASURE, + SNARE_MEASURE, + SNARE_AND, + SNARE_AND, + SNARE_AND, + SNARE_EIGTH, + SNARE_EIGTH, +}; + +#define TRACK_MAX_LENGTH (4 * (CHORUS_MELODY_LENGTH + BRIDGE_MELODY_LENGTH)) +#define TRACK_PARTS 4 +static struct Note TRACK[TRACK_PARTS][TRACK_MAX_LENGTH]; +static size_t PART_LENGTHS[TRACK_PARTS]; + +static i32 indices[TRACK_PARTS]; +static struct NoteActive current[NUM_NOTES]; + +void music_tick() { + for (size_t i = 0; i < TRACK_PARTS; i++) { + if (indices[i] == -1 || (current[i].ticks -= 1) <= 0) { + indices[i] = (indices[i] + 1) % PART_LENGTHS[i]; + + double remainder = fabs(current[i].ticks); + + struct Note note = TRACK[i][indices[i]]; + current[i].note = note; + current[i].ticks = TICKS_PER_SIXTEENTH * note.duration - remainder; + + sound_note(i, note.octave, note.note); + } + + // remove last tick to give each note an attack + if (current[i].ticks == 1) { + sound_note(i, OCTAVE_1, NOTE_NONE); + } + } +} + +void music_init() { + sound_wave(0, WAVE_TRIANGLE); + sound_volume(0, 255); + + sound_wave(1, WAVE_NOISE); + sound_volume(1, 0); + + sound_wave(2, WAVE_TRIANGLE); + sound_volume(2, 0); + + sound_wave(3, WAVE_TRIANGLE); + sound_volume(3, 0); + + memcpy(&TRACK[0][0], CHORUS_MELODY, sizeof(CHORUS_MELODY)); + memcpy(&TRACK[0][CHORUS_MELODY_LENGTH], BRIDGE_MELODY, sizeof(BRIDGE_MELODY)); + PART_LENGTHS[0] = CHORUS_MELODY_LENGTH + BRIDGE_MELODY_LENGTH; + + memcpy(&TRACK[1][0], CHORUS_SNARE, sizeof(CHORUS_SNARE)); + memcpy(&TRACK[1][CHORUS_SNARE_LENGTH], BRIDGE_SNARE, sizeof(BRIDGE_SNARE)); + PART_LENGTHS[1] = CHORUS_SNARE_LENGTH + BRIDGE_SNARE_LENGTH; + + memcpy(&TRACK[2][0], CHORUS_BASS, sizeof(CHORUS_BASS)); + memcpy(&TRACK[2][CHORUS_BASS_LENGTH], BRIDGE_BASS, sizeof(BRIDGE_BASS)); + PART_LENGTHS[2] = CHORUS_BASS_LENGTH + BRIDGE_BASS_LENGTH; + + memcpy(&TRACK[3][0], CHORUS_HARMONY, sizeof(CHORUS_HARMONY)); + memcpy(&TRACK[3][CHORUS_HARMONY_LENGTH], BRIDGE_HARMONY, sizeof(BRIDGE_HARMONY)); + PART_LENGTHS[3] = CHORUS_HARMONY_LENGTH + BRIDGE_HARMONY_LENGTH; + + for (size_t i = 0; i < TRACK_PARTS; i++) { + indices[i] = -1; + } +} diff --git a/src/music.h b/src/music.h new file mode 100644 index 0000000..fd28a90 --- /dev/null +++ b/src/music.h @@ -0,0 +1,9 @@ +#ifndef MUSIC_H +#define MUSIC_H + +#include "util.h" + +void music_tick(); +void music_init(); + +#endif diff --git a/src/screen.c b/src/screen.c new file mode 100644 index 0000000..1a3ec26 --- /dev/null +++ b/src/screen.c @@ -0,0 +1,41 @@ +#include "screen.h" + +static u8 *BUFFER = (u8 *) 0xA0000; + +// double buffers +u8 _sbuffers[2][SCREEN_SIZE]; +u8 _sback = 0; + +#define CURRENT (_sbuffers[_sback]) +#define SWAP() (_sback = 1 - _sback) + +// VGA control port addresses +#define PALETTE_MASK 0x3C6 +#define PALETTE_READ 0x3C7 +#define PALETTE_WRITE 0x3C8 +#define PALETTE_DATA 0x3C9 + +void screen_swap() { + memcpy(BUFFER, &CURRENT, SCREEN_SIZE); + SWAP(); +} + +void screen_clear(u8 color) { + memset(&CURRENT, color, SCREEN_SIZE); +} + +void screen_init() { + // configure palette with 8-bit RRRGGGBB color + outportb(PALETTE_MASK, 0xFF); + outportb(PALETTE_WRITE, 0); + for (u8 i = 0; i < 255; i++) { + outportb(PALETTE_DATA, (((i >> 5) & 0x7) * (256 / 8)) / 4); + outportb(PALETTE_DATA, (((i >> 2) & 0x7) * (256 / 8)) / 4); + outportb(PALETTE_DATA, (((i >> 0) & 0x3) * (256 / 4)) / 4); + } + + // set color 255 = white + outportb(PALETTE_DATA, 0x3F); + outportb(PALETTE_DATA, 0x3F); + outportb(PALETTE_DATA, 0x3F); +} diff --git a/src/screen.h b/src/screen.h new file mode 100644 index 0000000..ddee993 --- /dev/null +++ b/src/screen.h @@ -0,0 +1,53 @@ +#ifndef SCREEN_H +#define SCREEN_H + +#include "util.h" + +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 200 +#define SCREEN_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT) + +#define COLOR(_r, _g, _b)((u8)( \ + (((_r) & 0x7) << 5) | \ + (((_g) & 0x7) << 2) | \ + (((_b) & 0x3) << 0))) + +#define COLOR_R(_index) (((_index) >> 5) & 0x7) +#define COLOR_G(_index) (((_index) >> 2) & 0x7) +#define COLOR_B(_index) (((_index) >> 0) & 0x3) + +#define COLOR_ADD(_index, _d) __extension__({ \ + __typeof__(_index) _c = (_index); \ + __typeof__(_d) __d = (_d); \ + COLOR( \ + CLAMP(COLOR_R(_c) + __d, 0, 7), \ + CLAMP(COLOR_G(_c) + __d, 0, 7), \ + CLAMP(COLOR_B(_c) + __d, 0, 3) \ + );}) + +extern u8 _sbuffers[2][SCREEN_SIZE]; +extern u8 _sback; + +#define screen_buffer() (_sbuffers[_sback]) + +#define screen_set(_p, _x, _y)\ + (_sbuffers[_sback][((_y) * SCREEN_WIDTH + (_x))]=(_p)) + +#define screen_offset(_x, _y) (screen_buffer()[(_y) * SCREEN_WIDTH + (_x)]) + +#define screen_fill(_c, _x, _y, _w, _h) do {\ + __typeof__(_x) __x = (_x);\ + __typeof__(_y) __y = (_y);\ + __typeof__(_w) __w = (_w);\ + __typeof__(_y) __ymax = __y + (_h);\ + __typeof__(_c) __c = (_c);\ + for (; __y < __ymax; __y++) {\ + memset(&screen_buffer()[__y * SCREEN_WIDTH + __x], __c, __w);\ + }\ + } while (0) + +void screen_swap(); +void screen_clear(u8 color); +void screen_init(); + +#endif diff --git a/src/screen.o b/src/screen.o new file mode 100644 index 0000000000000000000000000000000000000000..c0582b0fc7623449f19f49c0a611740f9f65e939 GIT binary patch literal 6384 zcma)Ad2C$89iDlYy4wWWUZBeDRf3%enXeoab1EolHkh=Z8dGmIk9scOZ zzxjUm{AS+Fytlslih(Pol)`ILn4%;Jv8Ud(^e9*?W{Y~Ut>zV*;sI+9|0?$!KO4B` zI5n>dQ6UaKc%tv2L$Xl#xUj!@jW|~!^6wpy7pstG=yl`Ck%JEnEU>1h3GX@nR^Y&1 zI^1(YoDy=xyoV@@8h z0{hOanB0GA-x>4x8Ef+LJyV7J*(1G^lanWJu!O)Lnx*De`BlInr4Zs}jYfWjFzkk< z5Y2_kwfr{#Bj3497*69xs*JMtl&ZT+7-h3>q{=D_BbilR)<%%dH3Y-n3$QIanaaUt z_d;?WW@uH_W))?fAe38Wu#|DQS3u?LWPp8PimCq$uHtcY=A7VR@+;tOwgwpxd<~s6 zE6)NdEo!QMMvY_HSQtpBDV1rddMhGji<5(L4Go80H-xCU7wjU?FJYaP6mnjbnmROW zwU=Sl9svVaghT?PaI4!4CA}^H)vbfj2WBnE^?wqK5kV*00^jibuZMgcNcrc%WI-at z{Cp0^3UqRQK;=FFo@=Fip9AwONQf|A$VK*( zUd#X#SA$ec988QJ^_Okf`q6Z zhJ&ng$oGTfq31DZJ-cS=*fmifvg>{iHkFzWNU#ne3W}vpFc{D?XcvgYW)``V_d{`w-GHER1^tXUS!SabL|j zCYobaT2o+JE3G9E=W=QcM6@c?P5k@=CyKRbtq_7w^Y|+p=LF}Hd~nGmjzb^R|c;NVI~&}g0(;dgKOc4 zn?bYKkq&&TOTJ}NUKNt?E^k9nM-UH1F*Xi=kI%EWX*HHT=vUzysKE#vs;Wn92)Rj( zMm)r*>}~Q!VUc}}U+-_?C^bQpU+0jWg?w`j6qVkz7ByWJim39M z5mcNAwuOIQ*cx0T?2HTX=;r#v-Qaot5rv3M_dpD{*S(;JL55gzn8;U%6rVw_nxTxm z2g}6mV(G%}1-!deE14`&aoY6h>CUS#fRL_*%bTYKdB&MR4EP?1<8(Lo_{Z@~GedZJ z?gp76Q1A`!sp0;*zbv|Px|}LNHA5w!7T%{y-cq~(9dAHWl=l|hOX``m(3O|pGoHF@q{cdGAN7FF|XBPFjK6ADCH;BReTtj8CFV2 zzMw=lo=GH9(Kt2vTyiWrN=|DPFYK_eRmo_~hv);s10qI|DyheBaHDD8k# z}BGsSxVSkTGDKib_KkpU8P2_&85*1Bnb$^G97b3 z`I9%h5kn?4!>W{K&tBRhCEGQn$gcAvmDP>x9+?q&Z7H(z{77YWBfE-YwlaldVlHzP zhY2Z+xFtK%8C3IbSMy%YmDuL4#HC7ux*hYguI3U?gN58K4T&wV;o9wyb)B7&mC>%~ zl1Te_cNe-`K9yLL>|U`9d@K_m)%=b~`(~K4x#2Z>U*0V8di{vD9!f1=~m}-9C{_ zxD3?s+uA2G>0Bb7OJ`i=P(C@9OQzaK@~L<(nNCg9ifr<(#9&SgW{2`4BZ*8_bZpN8 zI&K{v?O30V=f@MNT(%>Z$Yqk*_H8_Os35gN>XF*YG4P=Tk2k0ns1TNJ}lOMK!^fy3BQJd5dkjv+%rY*@GMvdCgQ zuZ!G=g`*qRM_b;tRmk1tvZd0p_T$Xr%SrHdVe4mid3E_d!{|F%ZHZYB`J;ue7=Dbi zQ8xhMyOh7NKCK~bv0387LQw!S{g*doT${dT`ffO?O`+ZfMGq6-0se;9s$YbE#SFP} zhFmp6u9+d%&X8vnGje_EaM8`y9-L<_>TLx^sQb5s{I9|yu-=-{zX!6nUX;CyGVVQH z^|~m#d?kE zH;y4h8)Yn``oRi6l@EA}_Dg6S)0owGk4C#7ahuG zMU=|n#87?*?vIf)Op1>U4P_E{_^o5$5>#eSP5l`TAje z->2}{tuy>Ov8NyNiuKv91@9ksXBcM(I*!ZvdE>^wd%3}i6S(UmWOVave1G`!J&kLV z4A+}&1B}mmNg$IYeN&_7_dzw^SJCn7g+HH> 4) & 0xF, + note = notes[j] & 0xF; + + if (note == NOTE_NONE) { + continue; + } + + double note_freq = NOTES[octave * OCTAVE_SIZE + note], + freq = note_freq / (double) SAMPLE_RATE, + d = 0.0, + offset = 0.0; + + switch (waves[j]) { + case WAVE_SIN: + d = sin(2.0 * PI * sample * freq); + break; + case WAVE_SQUARE: + d = sin(2.0 * PI * sample * freq) >= 0.0 ? 1.0 : -1.0; + break; + case WAVE_TRIANGLE: + d = fabs(fmod(4 * (sample * freq) + 1.0, 4.0) - 2.0) - 1; + break; + case WAVE_NOISE: + offset = (freq * 128.0) * ((rand() / 4294967295.0) - 0.5); + d = fabs(fmod(4 * (sample * freq + offset) + 1.0, 4.0) - 2.0) - 1; + break; + } + + d *= (volumes[j] / 255.0); + f += d; + } + + buf[i] = (i16) (((volume_master / 255.0) * 4096.0) * f); + + sample++; + + // avoid double overflow errors, instead just mess up one note every + // few minutes + sample %= (1 << 24); + } +} + +static void dsp_write(u8 b) { + while (inportb(DSP_WRITE) & 0x80); + outportb(DSP_WRITE, b); +} + +static void dsp_read(u8 b) { + while (inportb(DSP_READ_STATUS) & 0x80); + outportb(DSP_READ, b); +} + +static void reset() { + char buf0[128], buf1[128]; + + outportb(DSP_RESET, 1); + + // TODO: maybe not necessary + // ~3 microseconds? + for (size_t i = 0; i < 1000000; i++); + + outportb(DSP_RESET, 0); + + u8 status = inportb(DSP_READ_STATUS); + if (~status & 128) { + goto fail; + } + + status = inportb(DSP_READ); + if (status != 0xAA) { + goto fail; + } + + outportb(DSP_WRITE, DSP_VERSION); + u8 major = inportb(DSP_READ), + minor = inportb(DSP_READ); + + if (major < 4) { + status = (major << 4) | minor; + goto fail; + } + + return; +fail: + strlcpy(buf0, "FAILED TO RESET SB16: ", 128); + itoa(status, buf1, 128); + strlcat(buf0, buf1, 128); + panic(buf0); +} + +static void set_sample_rate(u16 hz) { + dsp_write(DSP_SET_RATE); + dsp_write((u8) ((hz >> 8) & 0xFF)); + dsp_write((u8) (hz & 0xFF)); +} + +static void transfer(void *buf, u32 len) { + u8 mode = 0x48; + + // disable DMA channel + outportb(DSP_ON_8, 4 + (DMA_CHANNEL_16 % 4)); + + // clear byte-poiner flip-flop + outportb(DMA_FLIP_FLOP, 1); + + // write DMA mode for transfer + outportb(DSP_ON_16, (DMA_CHANNEL_16 % 4) | mode | (1 << 4)); + + // write buffer offset (div 2 for 16-bit) + u16 offset = (((uintptr_t) buf) / 2) % 65536; + outportb(DMA_BASE_ADDR, (u8) ((offset >> 0) & 0xFF)); + outportb(DMA_BASE_ADDR, (u8) ((offset >> 8) & 0xFF)); + + // write transfer length + outportb(DMA_COUNT, (u8) (((len - 1) >> 0) & 0xFF)); + outportb(DMA_COUNT, (u8) (((len - 1) >> 8) & 0xFF)); + + // write buffer + outportb(0x8B, ((uintptr_t) buf) >> 16); + + // enable DMA channel + outportb(0xD4, DMA_CHANNEL_16 % 4); +} + +static void sb16_irq_handler(struct Registers *regs) { + buffer_flip = !buffer_flip; + + fill( + &buffer[buffer_flip ? 0 : (BUFFER_SIZE / 2)], + (BUFFER_SIZE / 2) + ); + + inportb(DSP_READ_STATUS); + inportb(DSP_ACK_16); +} + +static void configure() { + irq_install(MIXER_IRQ, sb16_irq_handler); + outportb(DSP_MIXER, DSP_IRQ); + outportb(DSP_MIXER_DATA, MIXER_IRQ_DATA); + + u8 v = MIXER_IRQ; + if (v != MIXER_IRQ) { + char buf0[128], buf1[128]; + itoa(v, buf0, 128); + strlcpy(buf1, "SB16 HAS INCORRECT IRQ: ", 128); + strlcat(buf1, buf0, 128); + panic(buf1); + } +} + +void sound_init() { + irq_install(MIXER_IRQ, sb16_irq_handler); + reset(); + configure(); + + transfer(buffer, BUFFER_SIZE); + set_sample_rate(SAMPLE_RATE); + + u16 sample_count = (BUFFER_SIZE / 2) - 1; + dsp_write(DSP_PLAY | DSP_PROG_16 | DSP_AUTO_INIT); + dsp_write(DSP_SIGNED | DSP_MONO); + dsp_write((u8) ((sample_count >> 0) & 0xFF)); + dsp_write((u8) ((sample_count >> 8) & 0xFF)); + + dsp_write(DSP_ON); + dsp_write(DSP_ON_16); + + memset(¬es, NOTE_NONE, sizeof(notes)); + memset(&waves, WAVE_SIN, sizeof(waves)); +} diff --git a/src/sound.h b/src/sound.h new file mode 100644 index 0000000..d1f3e95 --- /dev/null +++ b/src/sound.h @@ -0,0 +1,50 @@ +#ifndef SOUND_H +#define SOUND_H + +#include "util.h" + +#define NUM_NOTES 8 + +#define NUM_OCTAVES 7 +#define OCTAVE_SIZE 12 + +#define OCTAVE_1 0 +#define OCTAVE_2 1 +#define OCTAVE_3 2 +#define OCTAVE_4 3 +#define OCTAVE_5 4 +#define OCTAVE_6 5 +#define OCTAVE_7 6 + +#define NOTE_C 0 +#define NOTE_CS 1 +#define NOTE_DF NOTE_CS +#define NOTE_D 2 +#define NOTE_DS 3 +#define NOTE_EF NOTE_DS +#define NOTE_E 4 +#define NOTE_F 5 +#define NOTE_FS 6 +#define NOTE_GF NOTE_FS +#define NOTE_G 7 +#define NOTE_GS 8 +#define NOTE_AF NOTE_GS +#define NOTE_A 9 +#define NOTE_AS 10 +#define NOTE_BF NOTE_AS +#define NOTE_B 11 + +#define NOTE_NONE 12 + +#define WAVE_SIN 0 +#define WAVE_SQUARE 1 +#define WAVE_NOISE 2 +#define WAVE_TRIANGLE 3 + +void sound_init(); +void sound_note(u8 index, u8 octave, u8 note); +void sound_master(u8 v); +void sound_volume(u8 index, u8 v); +void sound_wave(u8 index, u8 wave); + +#endif diff --git a/src/sound.o b/src/sound.o new file mode 100644 index 0000000000000000000000000000000000000000..264cef588f24907e34e2c06de569b69a15ce0ec5 GIT binary patch literal 24328 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 TO96+|c6Nu+@5i1I(6jr0T%c$0 literal 0 HcmV?d00001 diff --git a/src/speaker.c b/src/speaker.c new file mode 100644 index 0000000..ab5efc1 --- /dev/null +++ b/src/speaker.c @@ -0,0 +1,44 @@ +#include "speaker.h" +#include "fpu.h" + +// SEE: https://wiki.osdev.org/PC_Speaker +// SEE ALSO: https://web.archive.org/web/20171115162742/http://guideme.itgo.com/atozofc/ch23.pdf + +static float notes[7][12] = { + { 130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.0, + 196.0, 207.65, 220.0, 227.31, 246.96 }, + { 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.63, + 392.0, 415.3, 440.0, 454.62, 493.92 }, + { 523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, + 783.99, 830.61, 880.0, 909.24, 987.84 }, + { 1046.5, 1108.73, 1174.66, 1244.51, 1328.51, 1396.91, 1479.98, + 1567.98, 1661.22, 1760.0, 1818.48, 1975.68 }, + { 2093.0, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, + 3135.96, 3322.44, 3520.0, 3636.96, 3951.36 }, + { 4186.0, 4434.92, 4698.64, 4978.04, 5274.04, 5587.86, 5919.92, + 6271.92, 6644.88, 7040.0, 7273.92, 7902.72 }, + { 8372.0, 8869.89, 9397.28,9956.08,10548.08,11175.32, 11839.84, + 12543.84, 13289.76, 14080.0, 14547.84, 15805.44 } +}; + +void speaker_note(u8 octave, u8 note) { + speaker_play((u32) notes[octave][note]); +} + +void speaker_play(u32 hz) { + u32 d = 1193180 / hz; + outportb(0x43, 0xB6); + //outportb(0x42, (u8) (d & 0xFF)); + //outportb(0x42, (u8) ((d >> 8) & 0xFF)); + outportb(0x42, 140); + outportb(0x42, 140); + + u8 t = inportb(0x61); + if (t != (t | 0x3)) { + outportb(0x61, t | 0x3); + } +} + +void speaker_pause() { + outportb(0x61, inportb(0x61) & 0xFC); +} diff --git a/src/speaker.h b/src/speaker.h new file mode 100644 index 0000000..464c370 --- /dev/null +++ b/src/speaker.h @@ -0,0 +1,10 @@ +#ifndef SPEAKER_H +#define SPEAKER_H + +#include "util.h" + +void speaker_note(u8 octave, u8 note); +void speaker_play(u32 hz); +void speaker_pause(); + +#endif diff --git a/src/speaker.o b/src/speaker.o new file mode 100644 index 0000000000000000000000000000000000000000..fe608db340b0fc6026e403d238e8e8e3f90554fc GIT binary patch literal 5244 zcmcgwYiwLc6`r|w?|SWZ9NX(x;xt`bah#Xev7Iz-nxvK8q_NwCHceIy>r)jbniX;wARWttz1ecgC#$P>q zW$en>2mWIh&%EW1UJRTo{!c#6zhn3h{4>9~4*Q;%Quv1!)Aylo97k7_*+$8uIkCES zfLj?=j@P+^j860$X6P2>#JeU*Idyvw=T=6Bl~dQzM=DWw**M2jusDu)6cCGf`9c7j z2NP1q9-u7|+XV1F59-^Hxamxv9r*EKx}dty5}y(zwxI@RZgVXXhHqZBE} zbmTX;aU&b9!GM3JC1b8qtDtsr*!W}c!%!S{tVwV78h#Bj1APmm;pZ6ahq4c%)QW59 z^qRPyLgJ?RhoN_J=T^=reN(;B0;Sg_7^<3wSaVmLdKW}L&*@s4sCISG#d%7#^qOH$ zIE*!NDQxfzi`1*U*4sg*CebAiqw`@o3aMv0HnW*LNWIqk2o7ciU%>cLh*`n2P@aZ_ zF?4mJ20FOiY62u$;on3Zjk!!sG6PTi3g2#&xQ}pXleh3L;)e7RpMFBIP&NhSU_*g2<)n9Xt)K ztOhSF3&C@m(bjC|YL7-J)e-fWNQL!uX0X(ydGK7CCGuHwG%q<`TCPg?F95@)Nl~=A zS170?cxT4dqN=~XddWSs@Jg@A!bgsm6u&gcL*SfR9YSxKxp2%w<*NGgOZlR7Vtk2q zj3@67c%NOCPK-rpdh*t|!MjRFy)`{qZOsytCPk^)2;M8a_?IPX5;$hb+~j7}czIi^ zy4v@YieK&PzN(fgt6KANOX0 zkdAt5QmnRSnRvm4uGtd4{)3QZ$(jT#ExZbN#e{9tD!>ESB-eaRwf;xb3Wc9G+%||V zm$FKg7jypcTq%sP$j5ZtLfFXhGC(WhdL*XC{~5uc3dxO+ewX1K~6 z44EOrWax7*nO1irnbh5JP40;Hl5y=Nc6s&jyG@D#8{lbopZ2=rz5l=Y4r{N&%x4Pi zHH8kMyf(Aw_%191RXwO3jqO_~7Ut5X;}5A~Htx^P5Mi?Oe#!3g z)S_Q0=M*-6u)6Pe9XygA9~w&Eni=yU0TPrzIb zW_D*0GB7(^%H_&|Uzo|Gs)5-;abPi@3l-4W;{%H&RFe&grI4JiW}yD=7f3{P}3IKC`wyiM82@y6gd%H1hEZ@lFiUl7}3>d*hSI6h8N+am}rG z-R=7AxDPz{g)`A^&k(mn?Pn)1m6(;r-JVZ|Gwbw1o;IseogqN1z!;Smf$%e{J$sortm)#{H5R}!S{*qzasc|;r}IAhwnGnlN4+x!hf~k zCgC%JI|OeN=CaQURMiIK2o-6}!^XI%--ihPhOva5_4^OnRS~xU literal 0 HcmV?d00001 diff --git a/src/stage0.S b/src/stage0.S new file mode 100644 index 0000000..9cb289e --- /dev/null +++ b/src/stage0.S @@ -0,0 +1,203 @@ +.code16 +.org 0 + +.text + +.global _start +_start: + cli + + /* segment setup */ + mov %cs, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + /* place stack pointer in middle of free memory area */ + movw $0x3000, %sp + + /* save drive number to read kernel later */ + mov %dl, drive_num + + sti + + /* should print TETRIS TIME */ + movw $welcome_str, %si + call print + + /* read kernel into memory at 0x10000 (segment 0x1000). + kernel binary has been placed on the disk directly after the first sector + reading $20 * num_sectors sectors after (value in %cx) + */ + movw $20, %cx + movb drive_num, %dl + movw $disk_packet, %si + movw $0x1000, segment + movw $1, sector +sector_loop: + movb $0x42, %ah + int $0x13 + jc disk_error + + addw $64, sector + addw $0x8000, offset + jnc sector_same_segment + + /* increment segment, reset offset if on different segment */ + addw $0x1000, segment + movw $0x0000, offset +sector_same_segment: + /* decrements %cx and loops if nonzero */ + loop sector_loop + + /* video mode: 320x200 @ 16 colors */ + movb $0x00, %ah + movb $0x13, %al + int $0x10 + + /* enable A20 line */ + cli + + /* read and save state */ + call enable_a20_wait0 + movb $0xD0, %al + outb $0x64 + call enable_a20_wait1 + xorw %ax, %ax + inb $0x60 + + /* write new state with A20 bit set (0x2) */ + pushw %ax + call enable_a20_wait0 + movb $0xD1, %al + outb $0x64 + call enable_a20_wait0 + popw %ax + orw $0x2, %ax + outb $0x60 + + /* enable PE flag */ + movl %cr0, %eax + orl $0x1, %eax + movl %eax, %cr0 + + /* jmp to flush prefetch queue */ + jmp flush +flush: + lidt idt + lgdt gdtp + + movw $(gdt_data_segment - gdt_start), %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + movl $0x3000, %esp + ljmp $0x8, $entry32 + +.code32 +entry32: + /* jump to kernel loaded at 0x10000 */ + movl $0x10000, %eax + jmpl *%eax + +_loop: + jmp _loop + +.code16 +enable_a20_wait0: + xorw %ax, %ax + inb $0x64 + btw $1, %ax + jc enable_a20_wait0 + ret + +enable_a20_wait1: + xorw %ax, %ax + inb $0x64 + btw $0, %ax + jnc enable_a20_wait1 + ret + +disk_error: + movw $disk_error_str, %si + call print + +/* prints string in %ds:si */ +print: + xorb %bh, %bh + movb $0x0E, %ah + + lodsb + + /* NULL check */ + cmpb $0, %al + je 1f + + /* print %al to screen */ + int $0x10 + jmp print + +1: ret + +welcome_str: + .asciz "TETRIS TIME\n" +disk_error_str: + .asciz "DISK ERROR\n" + +/* SAVED DRIVE NUMBER TO READ FROM */ +drive_num: + .word 0x0000 + +/* INT 13H PACKET */ +disk_packet: + .byte 0x10 + .byte 0x00 +num_sectors: + .word 0x0040 +offset: + .word 0x0000 +segment: + .word 0x0000 +sector: + .quad 0x00000000 + +/* GDT */ +.align 16 +gdtp: + .word gdt_end - gdt_start - 1 + /* .long (0x07C0 << 4) + gdt */ + .long gdt_start + +.align 16 +gdt_start: +gdt_null: + .quad 0 +gdt_code_segment: + .word 0xffff + .word 0x0000 + .byte 0x00 + .byte 0b10011010 + .byte 0b11001111 + .byte 0x00 +gdt_data_segment: + .word 0xffff + .word 0x0000 + .byte 0x00 + .byte 0b10010010 + .byte 0b11001111 + .byte 0x00 +gdt_end: + +/* IDT */ +idt: + .word 0 + .long 0 + +/* MBR BOOT SIGNATURE */ +.fill 510-(.-_start), 1, 0 +.word 0xAA55 diff --git a/src/stage0.o b/src/stage0.o new file mode 100644 index 0000000000000000000000000000000000000000..2d3b984fb34dbba343120d652916e81437df3be0 GIT binary patch literal 1772 zcmdT^Ur1A76hEJ?WftwGq7VHWMPx){T7;0$h-OKDSqk+u?{@EWxPRPxO@*M$h>{vo zZ_#5Eh=kDyix>k5EfDps9t4q)p^w543)eY!-`zfYs9rm8_WS+5bME=h_uaF5+k3Hv zF$R_~D2I{)7~N8coG_stDqyRXYU28%spQvWCb^KzCTBl_`$26Eex&Cin}YW>FoY_- z29x#;0BO<=xKZlNbhYE|Fbtyd4A_4H+|hRo@B~z_IG=*C>S<{`+YV#1OG@?zG-SSa zT+Oz?*c{5!aD8y9Y^lTH%!CG~nBzcZ1srT&6LYXyiH%EO_QN|0VM_qZBiQ#i;KA|> zD;ro%aeP={T5f_<&~p>%Wyk`!^QoPq&0yH3rIpo*HgB7+^_sJ-^^&&|&bD5=;Pm=@ zSA3P&r34=H{MOIo6aaZ0IPv-{6&kkU`8={`GhpJA8Eg4J$M%sw9boe$0Zvx=ru1^K znX{HFt}@t;d|uFX$V<1yU@z)5A^sdW4i`5DM~D>%n9UBiN_O#u&Qae91n%`Vv=8%sf^kgRk4T~lLHaeFE_gVy>i%a z|Gv-wp-7M31!2X2PQ^&jk6)1uxmbY~bVJstmZ9|@ZxnVmyT$G?nflYsr`4EZVyq_; zF-b74lp2C6yn`A%dM!sM$AcUXb3DfJ6h{xo^Bie*sLn%<^zKQ&?0~xEfOCfb~5RV&7_k|m>KB< ztYT0>WkjWmN*9(wX%|ITTBSO zzx(~?%x`AC<$Z1Eu7OxArlJv3aW(IhI{zqL32j-WT2+gBcgM;^D%Sbktx+|q^arpV zRZPF_RD*uiskp8>mC!|}8gmuD|s~Sz|q*H1A7j%m~wdw0lwQKFvo%&a&7VDp!>d+URx=VlS)ZO|Er#kgnr6$#7M>8H z;KYddf;-|W@ekifXG*|Z(TJ-gh?8($1C5w!kEE?})y;fbHLBhPUa7Urw?jIfPtokw z(%`p%jxy2rgYRP32SE2RzYFvR=AQwL894C%7ohI2j{F|bPcfedjeBt5{!yqyXkeh9 zfQoB4&>w(Wv5x!^(1)4FlO*0?{yos|F#i$g51IcM^l|1-fIh|iY0#fB|0(FNnExE~ z6!Tw${+@ZfHqAVqm+>3(KZ5>~`JX}GWd0Ir_kH8%{{w6*^H;zxX8s2FZsupe_c9*` zy^eXz3Yf=JLAEg83HlM{dq6+Nd>`ninO_h3Ip#yqFEPIrbe{Qbp!YNXIOq!VyFnjf z{&~=^GrtEko}YpP`4m9cnJN{a-8|YPUHRUI8|%8z57+MTFLG$kBybbX(2mY z*jF4^S-4uMsq9z|Ofg@}mdd%j%EImqcJ}P-+c~gvXy*s*{E(eD+If?mH{02BH`Co7 z-R{x-9tC)m;8BD}86Jgrl;Ts0?|PsVpHh5E@hQcp6rWOjO7STrpp<}80{2lUC7_gm zQUXc|C?%kjfKozA2`MF{l+Y2Ol#o(FN(nbwP|DN_2Wu*m&((4&GhD5zOthGpsFX|PeXkTC<3Elb*oQxl zCbu7-l^5CXCE?bWLdDklogad;fAE=#&uZL``_SXF82#K+A3oRIO(2)S3kN=> 19) ^ t ^ (t >> 8); +} + +void panic(const char *err) { + screen_clear(COLOR(7, 0, 0)); + + if (err != NULL) { + font_str(err, (SCREEN_WIDTH - font_width(err)) / 2, SCREEN_HEIGHT / 2 - 4, COLOR(7, 7, 3)); + } + + screen_swap(); + for (;;) {} +} diff --git a/src/system.h b/src/system.h new file mode 100644 index 0000000..d7eed35 --- /dev/null +++ b/src/system.h @@ -0,0 +1,21 @@ +#ifndef SYSTEM_H +#define SYSTEM_H + +#include "util.h" + +#define _assert_0() __error_illegal_macro__ +#define _assert_1(_e) do { if (!(_e)) panic(NULL); } while (0) +#define _assert_2(_e, _m) do { if (!(_e)) panic((_m)); } while (0) + +#define _assert(x, _e, _m, _f, ...) _f + +#define assert(...) _assert(,##__VA_ARGS__,\ + _assert_2(__VA_ARGS__),\ + _assert_1(__VA_ARGS__),\ + _assert_0(__VA_ARGS__)) + +void panic(const char *err); +u32 rand(); +void seed(u32 s); + +#endif diff --git a/src/system.o b/src/system.o new file mode 100644 index 0000000000000000000000000000000000000000..38592ba56deaf61eb5a9636d7a1dd989a5ec7736 GIT binary patch literal 4156 zcma)9TZ~&r8UDw|V|&-T-i!B2Hi?_&N?7kY8$xqwnr;H=(l(%kkc6gez24(p2d};I zIc_crA|*vll!vwgQGr6*C_RXljLK%3}+qJm6{I+ z4V@(N=wjX7`{@vme+~{#Dn0>7Zi4DNXeoB8gZ;|;jK3Dv&Rz5zOMeyG&JWNzYttN% zeg=A_yBJS9-2bkRqEjDAoCZ8j_WI*+>2@0pXh+D$UY5)~U=vp6uGVc~0zL1c>x4|| zU4bwM=JS;LYUnz#XMNuSGeqXwU^ak}{`f5V>|5wmS~CwG_7RHL-$amsbE3L>!~AF& zI4`Q($Sj6|3!*Yc=8+7X71d*8h%)Gl%64%4Wwht0>RN+NB@^VCu)5CWbbHYC&=Cui zp#xCGP7Ixg>@f9V&u>7njXN+>mDtHHnq<_09JC#Y(Z55%7SAR|?*ZAILPAuZ+LXzr zoy?j{pXyKa4kPps4sK6+Z+drnCJV2Pl1}f32L^8zYP8W{jS2W>+P+DpX0i${sR!UW zkrwF)7!*k7&WPtDqx(j2!ckRh1gp=hM@DVDEu&26z{o4pqm02L z)vJ`)5}_uLSwd|O2raU~Vlo-TqNkFhExT+6OEIDxgUFu%&OGSZ*~^3c7)whIf>Y|> znQrvKGN4snqa@;;_k4FLUqVc2`ju*ak(^g*xNa@v%k`Qca-#c12a}Cxoz>}t(&}a1 zmDmpnG@!H4B)_Y5;`ssHOa3JI37rJnmAIiZz$|bOs1rZc!@&NNdR<;`$?FaKbSAIW zDZMtaKd@hZO{Wqn9>YA&J|6-4bb3N}Bu?p0*wcyifmbE2pmU~`-sJ0!8;JWeiNz77 zhXB72bO@`Iu^4uvTCXkSf{r(2v*uM6YVLfFg6F#PZB1#h*buLB!JYMGxmc@| zxr2p5Zg+l1elj<{G_?br->kV0SEe4?1-{rQEgF6yH~uM@J%9e;5{8VI%h+JgFV^NO zn18%ntB)^N+>n8~^o8-|M%{Nye!USY=bDwOU#X3ko3)Z(sn=F%rGY@wUdrla1ZO$x zoh>d4&vKTRP_UX=Zw@n=!=5cwU9PZEnrPKT5OGzo`FeA%>Iz0S%VoFW34&GKns|%# zhM!yITCUcMzBGbe49(osiQ^uIO`MruoH$f3HJ99)?@jow->7)wbx-8*!Gn8pTd}p< z!hOYM%rXY43r9s=OsO?p@%R!TzH_Sx<}; zJet59WL*2g{}9B-3`*WRzvLI^fPN#yMawnZYTkFx`I4V6`bEjld7k8{oOkD%3$vA4 zxeimn7w6_0?z2{^)=N>xA};9#ch%TxrRG|1-pct>eTg?>ILuv~EjNlwE^_>TX+0dV zWkLOM4A&X`8sHs5;>Rm*f&*xzdF<69FsM@?{djZm?qNI}VL+@GdmmF_<822|f9v-T z8Y9FQB<5pz%JiGSIaso`NhqTE{Ra76f|2?0H*E7e0N#!PE9;TKa}kAQkNl6{YY6al z4lrc>o`!6Bns#Bb92rB_b_#Mdzb8<`tTpCGz0GeKyd48pKFfF!g=MR-MdO`DJnkps z@rJhXE`sM6?hol%6#9!c2xPKsFBr6b8o~OZvt<3g1_gP01S9Zc&XzbY=_Ryie)GtW zcPI11&$5+YG#1oy1@SIH$+_7WuNRH6Y^{Km6wa4>YKd`3j34#8h> 8) & PIT_MASK); +} + +u64 timer_get() { + return state.ticks; +} + +static void timer_handler(struct Registers *regs) { + state.ticks++; +} + +void timer_init() { + const u64 freq = REAL_FREQ_OF_FREQ(TIMER_TPS); + state.frequency = freq; + state.divisor = DIV_OF_FREQ(freq); + state.ticks = 0; + //timer_set(state.divisor); + timer_set(TIMER_TPS); + irq_install(0, timer_handler); +} diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 0000000..0980c0e --- /dev/null +++ b/src/timer.h @@ -0,0 +1,12 @@ +#ifndef TIMER_H +#define TIMER_H + +#include "util.h" + +// number chosen to be integer divisor of PIC frequency +#define TIMER_TPS 363 + +u64 timer_get(); +void timer_init(); + +#endif diff --git a/src/timer.o b/src/timer.o new file mode 100644 index 0000000000000000000000000000000000000000..28586203b501e36bf9a0b0751a7b1dd196cbd840 GIT binary patch literal 4452 zcma)9TWlOx89rxbXLszi*Oy)2YKLyALmXPK%IP2Z9cjEP| zGc((yQKU#10aXgL5`s#NC`B!(YAfZT;?@U{f-ny}gaWCA03m^*3LzxaCj=sV-74JspMTGF_R_4?;wXx(S}MxcEeJcz+IiWIe+!W&DpCRH)m@!oe>}W z=hm%T>pvg4Ce}S^lj%+t`DGW{aKuwDjODa-Xj*sOIbQ>hP>XX+rN z^kH<5nrZtLU}h)nnYKq@7xq#BzCb=@JLCt++jf=w2>A}%sk+Fk0=nTuAxBHWb{5wl z~aAsvhyQwRYrE) zOtNIX2e;gPFaQ;G%|N&d>>yg_Cv}L)5N;tkWUVsfb1>|N%BWO{~0vMB> ziW#w9jblzj_jxoG!>!ju6WtuA0>)scVzyaojITj{9!>eb2IjkHLi7aamJuX+-{Lfl zc2e7gCa)M!=YL0bbez0_SuLbqfuiph)D|tyFOQy@gDd?V%rMv~S;Ro?0{G!|SO=>@ z4!1oBPW1l-F2>1%$svcnsf2rI8Tto0G zSiTj7%kCrZpQ_JN%-AIFuX&3&qU)hP+%{6V^4}&FR;PJ};VHu^n0v{kA4$oyc|=C4 z2RBv6q;i_s)SSYI>35A3e#4RDPZZ}TCyNi2c9(V)$5*FzqYIm!v)`TCGXuWtS8AGH zE{;DAa}ZYdR}eD3wB$QZ5SG2F>%q3MJWYGq#=0%Qql z4L>ZltbB177U0?NovOfUPsEE|Z8R6_jyT~gyFrKwH#0J(-oU)5ZcD1F`-~ejd;ymQ zuaWR#jH+Y}!|Nibb9|qUYS4um=DY6rqR|ZLwut9qetvIp3@f=aT1I>$MIn#C&ehcq}(Emn$C4ZJrKV6d`qsQsSSt zS^}7@Uvrdk^(V;0J<+CR)@0z=;8s+`r&FqDOe+AUP+xZ~g()&Eo(#_PZE~DFQkw!- ze1c4&p1hXEY|TuhGDS{o0~^mzFDlvrIsQVR%m+Ls`b8^+yI|{zMLROmaj!<4+K9=$ z9$iBc^UTVLJsLSLl<(1apT-9?9@NNh2>PAW$PZbGJEs9OkSt9Z)1=;QbSgivk9y#c z_E+Ozx~8=Lu*Rn}p4E6><0Xw>)%XpKe9M{lI~w2C$nRC^Pip*<#y2$nK;t!yzt;FC zB7WarwEQ-Q8NA)A+c?QyOa; z>l)Si(MRzVl2h)f<(hW7#iz%lK=Oh^@Px6MJJgQK~dndGkj;PHkbyFRwbN z@&Bc};fO7w_CI6zJCjd5wv?h_^gMgBO2Rzj44ek9&Iyoyyk)kdF(0N?(VH4$ppC?H zO8?mJE%3bCVv5IQJ#h?e^b6ylgl!l2WPKs(s_>stdK$AA@YAm0r#nqpfWax&i+ zk&pAqeEjKgzKh@)!}%dy!XD?{5ffRqFKdkb=8(KMcG5Qbsrw6vsa5o8_?^}~f#Z^1 zKugy5JnG~6vOd0Paed4g=K?F _yn ? _xn : _yn);\ + }) +#define MAX(_x, _y) __MAX_IMPL(_x, _y, CONCAT(__x, __COUNTER__), CONCAT(__y, __COUNTER__)) + +#define CLAMP(_x, _mi, _ma) (MAX(_mi, MIN(_x, _ma))) + +// returns the highest set bit of x +// i.e. if x == 0xF, HIBIT(x) == 3 (4th index) +// WARNING: currently only works for up to 32-bit types +#define HIBIT(_x) (31 - __builtin_clz((_x))) + +// returns the lowest set bit of x +#define LOBIT(_x)\ + __extension__({ __typeof__(_x) __x = (_x); HIBIT(__x & -__x); }) + +// returns _v with _n-th bit = _x +#define BIT_SET(_v, _n, _x) __extension__({\ + __typeof__(_v) __v = (_v);\ + (__v ^ ((-(_x) ^ __v) & (1 << (_n))));\ + }) + +#define PACKED __attribute__((packed)) + +#ifndef asm +#define asm __asm__ volatile +#endif + +#define CLI() asm ("cli") +#define STI() asm ("sti") + +static inline u16 inports(u16 port) { + u16 r; + asm("inw %1, %0" : "=a" (r) : "dN" (port)); + return r; +} + +static inline void outports(u16 port, u16 data) { + asm("outw %1, %0" : : "dN" (port), "a" (data)); +} + +static inline u8 inportb(u16 port) { + u8 r; + asm("inb %1, %0" : "=a" (r) : "dN" (port)); + return r; +} + +static inline void outportb(u16 port, u8 data) { + asm("outb %1, %0" : : "dN" (port), "a" (data)); +} + +static inline size_t strlen(const char *str) { + size_t l = 0; + while (*str++ != 0) { + l++; + } + return l; +} + +static inline char *itoa(i32 x, char *s, size_t sz) { + // TODO: holy god this is bad code we need some error handling here + if (sz < 20) { + extern void panic(const char *); + panic("ITOA BUFFER TOO SMALL"); + } + + u32 tmp; + i32 i, j; + + tmp = x; + i = 0; + + do { + tmp = x % 10; + s[i++] = (tmp < 10) ? (tmp + '0') : (tmp + 'a' - 10); + } while (x /= 10); + s[i--] = 0; + + for (j = 0; j < i; j++, i--) { + tmp = s[j]; + s[j] = s[i]; + s[i] = tmp; + } + + return s; +} + +static inline void memset(void *dst, u8 value, size_t n) { + u8 *d = dst; + + while (n-- > 0) { + *d++ = value; + } +} + +static inline void *memcpy(void *dst, const void *src, size_t n) { + u8 *d = dst; + const u8 *s = src; + + while (n-- > 0) { + *d++ = *s++; + } + + return d; +} + +static inline void *memmove(void *dst, const void *src, size_t n) { + // OK since we know that memcpy copies forwards + if (dst < src) { + return memcpy(dst, src, n); + } + + u8 *d = dst; + const u8 *s = src; + + for (size_t i = n; i > 0; i--) { + d[i - 1] = s[i - 1]; + } + + return dst; +} + +// SEE: https://opensource.apple.com/source/Libc/Libc-1158.30.7/string/strlcat.c.auto.html +static inline size_t strlcat(char *dst, const char *src, size_t size) { + const size_t sl = strlen(src), + dl = strlen(dst); + + if (dl == size) { + return size + sl; + } + + if (sl < (size - dl)) { + memcpy(dst + dl, src, sl + 1); + } else { + memcpy(dst + dl, src, size - dl - 1); + dst[size - 1] = '\0'; + } + + return sl + dl; +} + +static inline size_t strlcpy(char *dst, const char *src, size_t n) { + // copy as many bytes as can fit + char *d = dst; + const char *s = src; + size_t size = n; + + while (--n > 0) { + if ((*d++ = *s++) == 0) { + break; + } + } + + // if we ran out of space, null terminate + if (n == 0) { + if (size != 0) { + *d = 0; + } + + // traverse the rest of s + while (*s++); + } + + return s - src - 1; +} + +#endif