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
|
||||
- faster timer
|
||||
- fix asm loader
|
||||
- document everything
|
||||
- prettier pictures
|
||||
# TetrOS: bare-metal tetris
|
||||
|
||||
## TODO:
|
||||
- Fix stage 1 loader
|
||||
|
||||
## 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_line
|
||||
|
||||
|
||||
; check for required features
|
||||
call cpuid_check
|
||||
|
||||
; enable A20-Line via IO-Port 92, might not work on all motherboards
|
||||
in al, 0x92
|
||||
or al, 2
|
||||
@ -20,7 +16,6 @@ stage2.entry:
|
||||
mov dword [protected_mode.func], stage3.entry
|
||||
jmp protected_mode.entry
|
||||
|
||||
%include "cpuid.asm"
|
||||
%include "gdt.asm"
|
||||
%include "protected_mode.asm"
|
||||
%include "thunk.asm"
|
||||
|
@ -62,6 +62,7 @@ impl Direction {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn rot_ccw(self) -> Self {
|
||||
match self {
|
||||
Self::North => Self::West,
|
||||
@ -70,6 +71,7 @@ impl Direction {
|
||||
Self::East => Self::North,
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -124,9 +126,11 @@ impl FallingTetromino {
|
||||
self.direction = self.direction.rot_cw()
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn rotate_ccw(&mut self) {
|
||||
self.direction = self.direction.rot_ccw()
|
||||
}
|
||||
*/
|
||||
|
||||
/// Returns the positions of this falling tetromino's tiles.
|
||||
pub fn tiles(&self) -> [(usize, usize); 4] {
|
||||
|
@ -205,12 +205,14 @@ pub unsafe extern "C" fn start(thunk10: extern "C" fn()) -> ! {
|
||||
};
|
||||
}
|
||||
|
||||
Some(InputKey::Down) => {
|
||||
fall_test.rotate_ccw();
|
||||
Some(InputKey::Down) => loop {
|
||||
fall_test.translate(0, 1);
|
||||
if board.tetromino_valid(&fall_test) {
|
||||
fall.rotate_ccw()
|
||||
};
|
||||
}
|
||||
fall.translate(0, 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
Some(InputKey::Left) => {
|
||||
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());
|
||||
|
||||
if let Some(fall_inner) = fall.as_mut() {
|
||||
if t % 5 == 0 {
|
||||
if t % 4 == 0 {
|
||||
let mut fall_test = fall_inner.clone();
|
||||
fall_test.translate(0, 1);
|
||||
|
||||
@ -258,7 +260,10 @@ pub unsafe extern "C" fn start(thunk10: extern "C" fn()) -> ! {
|
||||
}
|
||||
}
|
||||
} 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