Compare commits
4 Commits
8f2edd69f7
...
cbf6c48b22
Author | SHA1 | Date | |
---|---|---|---|
cbf6c48b22 | |||
1b401b46b2 | |||
f5ede33bc8 | |||
de3ff45f1b |
41
README.md
41
README.md
@ -1,5 +1,36 @@
|
|||||||
- quick drop
|
# TetrOS: bare-metal tetris
|
||||||
- faster timer
|
|
||||||
- fix asm loader
|
## TODO:
|
||||||
- document everything
|
- Fix stage 1 loader
|
||||||
- prettier pictures
|
|
||||||
|
## Features
|
||||||
|
- Compiles to a standalone disk image
|
||||||
|
- Written from scratch using only Nasm and Rust
|
||||||
|
- Custom BIOS bootloader
|
||||||
|
- 32-bit x86 OS
|
||||||
|
- 🌟 Detailed comments. Read the [makefile](./Makefile), then start in [`./bios/main.asm`](./bios/main.asm).
|
||||||
|
|
||||||
|
|
||||||
|
## Non-Features
|
||||||
|
- Never tested on real hardware
|
||||||
|
- Minimal gameplay and graphics. These features aren't hard to implement, but also don't present any interesting challenges. I have other things to do.
|
||||||
|
|
||||||
|
|
||||||
|
## 🚀 Building and Running
|
||||||
|
- All scripts are in the [makefile](./Makefile).
|
||||||
|
- To build and run, use `make qemu`.
|
||||||
|
- Dependencies: `nasm`, `cargo`, GNU `binutils`, `qemu`
|
||||||
|
- This will NOT work on MacOS. BSD `ld` does not work like GNU `ld`.
|
||||||
|
- Alternatively, a compiled disk image for the latest commit is [here](https://git.betalupi.com/api/packages/Mark/generic/tetros/latest/disk.img). This is the same file produced by `make`.
|
||||||
|
- Download it and run `qemu-system-i386 -d cpu_reset -no-reboot -smp 1 -m 2048 -machine q35 -net none -serial stdio -fda "disk.img"`
|
||||||
|
|
||||||
|
|
||||||
|
## 📜 Resources
|
||||||
|
**Used directly:**
|
||||||
|
- [jdh's video](https://www.youtube.com/watch?v=FaILnmUYS_U)
|
||||||
|
- [The OSDev wiki](https://wiki.osdev.org/Main_Page)
|
||||||
|
- [RedoxOS bootloader](https://gitlab.redox-os.org/redox-os/bootloader)
|
||||||
|
|
||||||
|
**Useful background knowledge:**
|
||||||
|
- [Writing an OS in Rust](https://os.phil-opp.com)
|
||||||
|
- [Operating Systems: From 0 to 1](https://github.com/tuhdo/os01)
|
176
bios/cpuid.asm
176
bios/cpuid.asm
@ -1,176 +0,0 @@
|
|||||||
SECTION .text
|
|
||||||
USE16
|
|
||||||
|
|
||||||
cpuid_required_features:
|
|
||||||
.edx equ cpuid_edx.fpu | cpuid_edx.pse | cpuid_edx.pge | cpuid_edx.fxsr
|
|
||||||
.ecx equ 0
|
|
||||||
|
|
||||||
cpuid_check:
|
|
||||||
; If bit 21 of EFLAGS can be changed, then CPUID is supported
|
|
||||||
pushfd ;Save EFLAGS
|
|
||||||
pushfd ;Store EFLAGS
|
|
||||||
xor dword [esp],0x00200000 ;Invert the ID bit in stored EFLAGS
|
|
||||||
popfd ;Load stored EFLAGS (with ID bit inverted)
|
|
||||||
pushfd ;Store EFLAGS again (ID bit may or may not be inverted)
|
|
||||||
pop eax ;eax = modified EFLAGS (ID bit may or may not be inverted)
|
|
||||||
xor eax,[esp] ;eax = whichever bits were changed
|
|
||||||
popfd ;Restore original EFLAGS
|
|
||||||
test eax,0x00200000 ;eax = zero if ID bit can't be changed, else non-zero
|
|
||||||
jz .no_cpuid
|
|
||||||
|
|
||||||
mov eax, 1
|
|
||||||
cpuid
|
|
||||||
|
|
||||||
and edx, cpuid_required_features.edx
|
|
||||||
cmp edx, cpuid_required_features.edx
|
|
||||||
jne .error
|
|
||||||
|
|
||||||
and ecx, cpuid_required_features.ecx
|
|
||||||
cmp ecx, cpuid_required_features.ecx
|
|
||||||
jne .error
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
.no_cpuid:
|
|
||||||
mov si, .msg_cpuid
|
|
||||||
call print
|
|
||||||
|
|
||||||
mov si, .msg_line
|
|
||||||
call print
|
|
||||||
|
|
||||||
jmp .halt
|
|
||||||
|
|
||||||
.error:
|
|
||||||
push ecx
|
|
||||||
push edx
|
|
||||||
|
|
||||||
mov si, .msg_features
|
|
||||||
call print
|
|
||||||
|
|
||||||
mov si, .msg_line
|
|
||||||
call print
|
|
||||||
|
|
||||||
mov si, .msg_edx
|
|
||||||
call print
|
|
||||||
|
|
||||||
pop ebx
|
|
||||||
push ebx
|
|
||||||
shr ebx, 16
|
|
||||||
call print_hex
|
|
||||||
|
|
||||||
pop ebx
|
|
||||||
call print_hex
|
|
||||||
|
|
||||||
mov si, .msg_must_contain
|
|
||||||
call print
|
|
||||||
|
|
||||||
mov ebx, cpuid_required_features.edx
|
|
||||||
shr ebx, 16
|
|
||||||
call print_hex
|
|
||||||
|
|
||||||
mov ebx, cpuid_required_features.edx
|
|
||||||
call print_hex
|
|
||||||
|
|
||||||
mov si, .msg_line
|
|
||||||
call print
|
|
||||||
|
|
||||||
mov si, .msg_ecx
|
|
||||||
call print
|
|
||||||
|
|
||||||
pop ebx
|
|
||||||
push ebx
|
|
||||||
shr ebx, 16
|
|
||||||
call print_hex
|
|
||||||
|
|
||||||
pop ebx
|
|
||||||
call print_hex
|
|
||||||
|
|
||||||
mov si, .msg_must_contain
|
|
||||||
call print
|
|
||||||
|
|
||||||
mov ebx, cpuid_required_features.ecx
|
|
||||||
shr ebx, 16
|
|
||||||
call print_hex
|
|
||||||
|
|
||||||
mov ebx, cpuid_required_features.ecx
|
|
||||||
call print_hex
|
|
||||||
|
|
||||||
mov si, .msg_line
|
|
||||||
call print
|
|
||||||
|
|
||||||
.halt:
|
|
||||||
cli
|
|
||||||
hlt
|
|
||||||
jmp .halt
|
|
||||||
|
|
||||||
.msg_cpuid: db "CPUID not supported",0
|
|
||||||
.msg_features: db "Required CPU features are not present",0
|
|
||||||
.msg_line: db 13,10,0
|
|
||||||
.msg_edx: db "EDX ",0
|
|
||||||
.msg_ecx: db "ECX ",0
|
|
||||||
.msg_must_contain: db " must contain ",0
|
|
||||||
|
|
||||||
cpuid_edx:
|
|
||||||
.fpu equ 1 << 0
|
|
||||||
.vme equ 1 << 1
|
|
||||||
.de equ 1 << 2
|
|
||||||
.pse equ 1 << 3
|
|
||||||
.tsc equ 1 << 4
|
|
||||||
.msr equ 1 << 5
|
|
||||||
.pae equ 1 << 6
|
|
||||||
.mce equ 1 << 7
|
|
||||||
.cx8 equ 1 << 8
|
|
||||||
.apic equ 1 << 9
|
|
||||||
.sep equ 1 << 11
|
|
||||||
.mtrr equ 1 << 12
|
|
||||||
.pge equ 1 << 13
|
|
||||||
.mca equ 1 << 14
|
|
||||||
.cmov equ 1 << 15
|
|
||||||
.pat equ 1 << 16
|
|
||||||
.pse_36 equ 1 << 17
|
|
||||||
.psn equ 1 << 18
|
|
||||||
.clfsh equ 1 << 19
|
|
||||||
.ds equ 1 << 21
|
|
||||||
.acpi equ 1 << 22
|
|
||||||
.mmx equ 1 << 23
|
|
||||||
.fxsr equ 1 << 24
|
|
||||||
.sse equ 1 << 25
|
|
||||||
.sse2 equ 1 << 26
|
|
||||||
.ss equ 1 << 27
|
|
||||||
.htt equ 1 << 28
|
|
||||||
.tm equ 1 << 29
|
|
||||||
.ia64 equ 1 << 30
|
|
||||||
.pbe equ 1 << 31
|
|
||||||
|
|
||||||
cpuid_ecx:
|
|
||||||
.sse3 equ 1 << 0
|
|
||||||
.pclmulqdq equ 1 << 1
|
|
||||||
.dtes64 equ 1 << 2
|
|
||||||
.monitor equ 1 << 3
|
|
||||||
.ds_cpl equ 1 << 4
|
|
||||||
.vmx equ 1 << 5
|
|
||||||
.smx equ 1 << 6
|
|
||||||
.est equ 1 << 7
|
|
||||||
.tm2 equ 1 << 8
|
|
||||||
.ssse3 equ 1 << 9
|
|
||||||
.cnxt_id equ 1 << 10
|
|
||||||
.sdbg equ 1 << 11
|
|
||||||
.fma equ 1 << 12
|
|
||||||
.cmpxchg16b equ 1 << 13
|
|
||||||
.xtpr equ 1 << 14
|
|
||||||
.pdcm equ 1 << 15
|
|
||||||
.pcid equ 1 << 17
|
|
||||||
.dca equ 1 << 18
|
|
||||||
.sse4_1 equ 1 << 19
|
|
||||||
.sse4_2 equ 1 << 20
|
|
||||||
.x2apic equ 1 << 21
|
|
||||||
.movbe equ 1 << 22
|
|
||||||
.popcnt equ 1 << 23
|
|
||||||
.tsc_deadline equ 1 << 24
|
|
||||||
.aes equ 1 << 25
|
|
||||||
.xsave equ 1 << 26
|
|
||||||
.osxsave equ 1 << 27
|
|
||||||
.avx equ 1 << 28
|
|
||||||
.f16c equ 1 << 29
|
|
||||||
.rdrand equ 1 << 30
|
|
||||||
.hypervisor equ 1 << 31
|
|
@ -8,10 +8,6 @@ stage2.entry:
|
|||||||
call print_char
|
call print_char
|
||||||
call print_line
|
call print_line
|
||||||
|
|
||||||
|
|
||||||
; check for required features
|
|
||||||
call cpuid_check
|
|
||||||
|
|
||||||
; enable A20-Line via IO-Port 92, might not work on all motherboards
|
; enable A20-Line via IO-Port 92, might not work on all motherboards
|
||||||
in al, 0x92
|
in al, 0x92
|
||||||
or al, 2
|
or al, 2
|
||||||
@ -20,7 +16,6 @@ stage2.entry:
|
|||||||
mov dword [protected_mode.func], stage3.entry
|
mov dword [protected_mode.func], stage3.entry
|
||||||
jmp protected_mode.entry
|
jmp protected_mode.entry
|
||||||
|
|
||||||
%include "cpuid.asm"
|
|
||||||
%include "gdt.asm"
|
%include "gdt.asm"
|
||||||
%include "protected_mode.asm"
|
%include "protected_mode.asm"
|
||||||
%include "thunk.asm"
|
%include "thunk.asm"
|
||||||
|
@ -62,6 +62,7 @@ impl Direction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
pub fn rot_ccw(self) -> Self {
|
pub fn rot_ccw(self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::North => Self::West,
|
Self::North => Self::West,
|
||||||
@ -70,6 +71,7 @@ impl Direction {
|
|||||||
Self::East => Self::North,
|
Self::East => Self::North,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -124,9 +126,11 @@ impl FallingTetromino {
|
|||||||
self.direction = self.direction.rot_cw()
|
self.direction = self.direction.rot_cw()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
pub fn rotate_ccw(&mut self) {
|
pub fn rotate_ccw(&mut self) {
|
||||||
self.direction = self.direction.rot_ccw()
|
self.direction = self.direction.rot_ccw()
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/// Returns the positions of this falling tetromino's tiles.
|
/// Returns the positions of this falling tetromino's tiles.
|
||||||
pub fn tiles(&self) -> [(usize, usize); 4] {
|
pub fn tiles(&self) -> [(usize, usize); 4] {
|
||||||
|
@ -205,12 +205,14 @@ pub unsafe extern "C" fn start(thunk10: extern "C" fn()) -> ! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(InputKey::Down) => {
|
Some(InputKey::Down) => loop {
|
||||||
fall_test.rotate_ccw();
|
fall_test.translate(0, 1);
|
||||||
if board.tetromino_valid(&fall_test) {
|
if board.tetromino_valid(&fall_test) {
|
||||||
fall.rotate_ccw()
|
fall.translate(0, 1);
|
||||||
};
|
} else {
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
Some(InputKey::Left) => {
|
Some(InputKey::Left) => {
|
||||||
fall_test.translate(-1, 0);
|
fall_test.translate(-1, 0);
|
||||||
@ -244,7 +246,7 @@ pub unsafe extern "C" fn start(thunk10: extern "C" fn()) -> ! {
|
|||||||
board.draw(&mut v, fall.as_ref());
|
board.draw(&mut v, fall.as_ref());
|
||||||
|
|
||||||
if let Some(fall_inner) = fall.as_mut() {
|
if let Some(fall_inner) = fall.as_mut() {
|
||||||
if t % 5 == 0 {
|
if t % 4 == 0 {
|
||||||
let mut fall_test = fall_inner.clone();
|
let mut fall_test = fall_inner.clone();
|
||||||
fall_test.translate(0, 1);
|
fall_test.translate(0, 1);
|
||||||
|
|
||||||
@ -258,7 +260,10 @@ pub unsafe extern "C" fn start(thunk10: extern "C" fn()) -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*fall = Some(FallingTetromino::random(5, 1))
|
*fall = Some(FallingTetromino::random(5, 1));
|
||||||
|
if !board.tetromino_valid(fall.as_ref().unwrap()) {
|
||||||
|
panic!("\nGAME OVER");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user