1
0

Reorganize
All checks were successful
CI / Typos (push) Successful in 11s
CI / Clippy (push) Successful in 30s
CI / Build (push) Successful in 1m8s

This commit is contained in:
Mark 2025-03-02 10:44:55 -08:00
parent 4250e51f29
commit 8f2edd69f7
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
13 changed files with 130 additions and 123 deletions

View File

@ -1,4 +1,5 @@
- quick drop
- faster timer
- fix asm loader
- document everything
- prettier pictures

View File

@ -1,4 +1,4 @@
use core::arch::asm;
use crate::os::util::outb;
/// IO base address for master PIC
const PIC_A: u32 = 0x20;
@ -13,14 +13,6 @@ const PIC_B_DATA: u32 = PIC_B + 1;
/// PIC `EOI` command
const CMD_EOI: u8 = 0x20;
unsafe fn outb(port: u32, value: u8) {
asm!(
"out dx, al",
in("dx") port,
in("al") value,
);
}
/// A driver for the PIC
///
/// Reference:

View File

@ -1,9 +1,6 @@
mod draw;
mod falling;
use crate::drivers::vga::{Vga13h, VgaColor};
pub use falling::FallingTetromino;
use crate::drivers::vga::VgaColor;
use super::FallingTetromino;
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -109,3 +106,70 @@ impl TetrisBoard {
return Some(&mut self.board[y * TetrisBoard::BOARD_WIDTH + x]);
}
}
impl TetrisBoard {
fn draw_cell(&self, fb: &mut [u8], color: VgaColor, x: usize, y: usize) {
let color = color.as_u8();
for yo in 0..TetrisBoard::CELL_SIZE {
let left = Vga13h::pix_idx(x, y + yo);
let right = Vga13h::pix_idx(x + TetrisBoard::CELL_SIZE, y + yo);
fb[left..right].copy_from_slice(&[color; TetrisBoard::CELL_SIZE]);
}
}
fn draw_frame(&self, fb: &mut [u8], x: usize, y: usize) {
let color = VgaColor::Gray.as_u8();
for yo in 0..TetrisBoard::CELL_SIZE {
let left = Vga13h::pix_idx(x, y + yo);
let right = Vga13h::pix_idx(x + TetrisBoard::CELL_SIZE, y + yo);
fb[left..right].copy_from_slice(&[color; TetrisBoard::CELL_SIZE]);
}
}
pub fn draw(&self, vga: &mut Vga13h, falling: Option<&FallingTetromino>) {
let fb = vga.get_fb();
// Draw cells
for bx in 0..TetrisBoard::BOARD_WIDTH {
for by in 0..TetrisBoard::BOARD_HEIGHT {
let cell = self.board[by * TetrisBoard::BOARD_WIDTH + bx];
let dx = (bx + 1) * TetrisBoard::CELL_SIZE;
let dy = (by + 1) * TetrisBoard::CELL_SIZE;
if let TetrisCell::Filled { color } = cell {
self.draw_cell(fb, color, dx, dy);
} else {
self.draw_cell(fb, VgaColor::Black, dx, dy);
}
}
}
// Draw falling tetromino
if let Some(falling) = falling {
for (x, y) in falling.tiles() {
let dx = (x + 1) * TetrisBoard::CELL_SIZE;
let dy = (y + 1) * TetrisBoard::CELL_SIZE;
self.draw_cell(fb, falling.color, dx, dy);
}
}
// Draw frame
for bx in 0..TetrisBoard::BOARD_WIDTH + 2 {
self.draw_frame(fb, bx * TetrisBoard::CELL_SIZE, 0);
self.draw_frame(
fb,
bx * TetrisBoard::CELL_SIZE,
(TetrisBoard::BOARD_HEIGHT + 1) * TetrisBoard::CELL_SIZE,
);
}
for by in 0..TetrisBoard::BOARD_HEIGHT + 2 {
self.draw_frame(fb, 0, by * 9);
self.draw_frame(
fb,
(TetrisBoard::BOARD_WIDTH + 1) * TetrisBoard::CELL_SIZE,
by * TetrisBoard::CELL_SIZE,
);
}
}
}

5
tetros/src/game/mod.rs Normal file
View File

@ -0,0 +1,5 @@
mod board;
pub use board::*;
mod falling;
pub use falling::*;

View File

@ -3,6 +3,8 @@ use core::{
marker::PhantomData,
};
use crate::os::util::get_cs;
use super::{HandlerFuncType, VirtAddr};
/// An Interrupt Descriptor Table entry.
@ -97,7 +99,7 @@ impl<F> Entry<F> {
self.options = 0b1000_1110; // Present 32-bit interrupt gate
// SAFETY: The current CS is a valid, long-mode code segment.
self.segment = super::util::get_cs();
self.segment = get_cs();
}
/// True if the "present" bit is set, false otherwise.

View File

@ -18,5 +18,3 @@ pub use handler::*;
mod stackframe;
pub use stackframe::*;
mod util;

View File

@ -1,10 +0,0 @@
use core::arch::asm;
/// Get the current value of the CS register
pub(super) fn get_cs() -> u16 {
let segment: u16;
unsafe {
asm!("mov {0:x}, cs", out(reg) segment, options(nomem, nostack, preserves_flags));
}
segment
}

View File

@ -4,34 +4,37 @@
#![feature(abi_x86_interrupt)]
#![allow(internal_features)]
use core::arch::asm;
use lazy_static::lazy_static;
use rand::{rngs::SmallRng, Rng, SeedableRng};
use spin::Mutex;
use drivers::{pic::PICDriver, vga::Vga13h};
use game::{FallingTetromino, TetrisBoard};
use idt::{InterruptDescriptorTable, InterruptStackFrame};
use os::{
util::{sti, without_interrupts},
util::{inb, sti, without_interrupts},
ThunkData,
};
use tetrisboard::{FallingTetromino, TetrisBoard};
mod game;
mod idt;
mod os;
mod tetrisboard;
#[macro_use]
mod drivers;
const PIC_OFFSET: u8 = 32;
pub(crate) static VGA: Mutex<Vga13h> = Mutex::new(unsafe { Vga13h::new() });
pub(crate) static PIC: Mutex<PICDriver> = Mutex::new(PICDriver::new(PIC_OFFSET, PIC_OFFSET + 8));
pub(crate) static TICK_COUNTER: Mutex<u32> = Mutex::new(0);
pub(crate) static BOARD: Mutex<TetrisBoard> = Mutex::new(TetrisBoard::new());
pub(crate) static FALLING: Mutex<Option<FallingTetromino>> = Mutex::new(None);
pub(crate) static LAST_INPUT: Mutex<Option<InputKey>> = Mutex::new(None);
//
// MARK: globals
//
static VGA: Mutex<Vga13h> = Mutex::new(unsafe { Vga13h::new() });
static PIC: Mutex<PICDriver> = Mutex::new(PICDriver::new(PIC_OFFSET, PIC_OFFSET + 8));
static TICK_COUNTER: Mutex<u32> = Mutex::new(0);
static BOARD: Mutex<TetrisBoard> = Mutex::new(TetrisBoard::new());
static FALLING: Mutex<Option<FallingTetromino>> = Mutex::new(None);
static LAST_INPUT: Mutex<Option<InputKey>> = Mutex::new(None);
lazy_static! {
static ref RNG: Mutex<SmallRng> = Mutex::new(SmallRng::seed_from_u64(1337));
@ -47,6 +50,10 @@ lazy_static! {
};
}
//
// MARK: interrupts
//
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum InterruptIndex {
@ -68,18 +75,6 @@ extern "x86-interrupt" fn divide_handler(stack_frame: InterruptStackFrame) {
println!("DIVIDE ERROR {:?}", stack_frame);
}
unsafe fn inb(port: u32) -> u8 {
let mut out;
asm!(
"in al, dx",
out("al") out,
in("dx") port,
);
return out;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum InputKey {
Left,
@ -146,6 +141,10 @@ extern "x86-interrupt" fn double_fault_handler(
panic!("DOUBLE FAULT (err = 0x{error_code:x}\n{:#?}", stack_frame);
}
//
// MARK: main
//
#[no_mangle]
pub unsafe extern "C" fn start(thunk10: extern "C" fn()) -> ! {
println!("Entered Rust, serial ready.");

View File

@ -4,8 +4,7 @@ pub use thunk::*;
mod eflags;
pub use eflags::*;
pub mod util;
#[macro_use]
pub mod panic;
pub mod util;

View File

@ -9,7 +9,6 @@ use crate::println;
#[no_mangle]
pub extern "C" fn rust_eh_personality() {}
/// Required to handle panics
#[panic_handler]
#[no_mangle]
pub fn rust_begin_unwind(info: &PanicInfo<'_>) -> ! {
@ -22,7 +21,6 @@ pub fn rust_begin_unwind(info: &PanicInfo<'_>) -> ! {
}
#[no_mangle]
/// Required to handle panics
pub extern "C" fn _Unwind_Resume() -> ! {
loop {
unsafe {

View File

@ -45,3 +45,32 @@ where
ret
}
pub unsafe fn inb(port: u32) -> u8 {
let mut out;
asm!(
"in al, dx",
out("al") out,
in("dx") port,
);
return out;
}
pub unsafe fn outb(port: u32, value: u8) {
asm!(
"out dx, al",
in("dx") port,
in("al") value,
);
}
/// Get the current value of the CS register
pub fn get_cs() -> u16 {
let segment: u16;
unsafe {
asm!("mov {0:x}, cs", out(reg) segment, options(nomem, nostack, preserves_flags));
}
segment
}

View File

@ -1,70 +0,0 @@
use crate::drivers::vga::{Vga13h, VgaColor};
use super::{falling::FallingTetromino, TetrisBoard, TetrisCell};
impl TetrisBoard {
fn draw_cell(&self, fb: &mut [u8], color: VgaColor, x: usize, y: usize) {
let color = color.as_u8();
for yo in 0..TetrisBoard::CELL_SIZE {
let left = Vga13h::pix_idx(x, y + yo);
let right = Vga13h::pix_idx(x + TetrisBoard::CELL_SIZE, y + yo);
fb[left..right].copy_from_slice(&[color; TetrisBoard::CELL_SIZE]);
}
}
fn draw_frame(&self, fb: &mut [u8], x: usize, y: usize) {
let color = VgaColor::Gray.as_u8();
for yo in 0..TetrisBoard::CELL_SIZE {
let left = Vga13h::pix_idx(x, y + yo);
let right = Vga13h::pix_idx(x + TetrisBoard::CELL_SIZE, y + yo);
fb[left..right].copy_from_slice(&[color; TetrisBoard::CELL_SIZE]);
}
}
pub fn draw(&self, vga: &mut Vga13h, falling: Option<&FallingTetromino>) {
let fb = vga.get_fb();
// Draw cells
for bx in 0..TetrisBoard::BOARD_WIDTH {
for by in 0..TetrisBoard::BOARD_HEIGHT {
let cell = self.board[by * TetrisBoard::BOARD_WIDTH + bx];
let dx = (bx + 1) * TetrisBoard::CELL_SIZE;
let dy = (by + 1) * TetrisBoard::CELL_SIZE;
if let TetrisCell::Filled { color } = cell {
self.draw_cell(fb, color, dx, dy);
} else {
self.draw_cell(fb, VgaColor::Black, dx, dy);
}
}
}
// Draw falling tetromino
if let Some(falling) = falling {
for (x, y) in falling.tiles() {
let dx = (x + 1) * TetrisBoard::CELL_SIZE;
let dy = (y + 1) * TetrisBoard::CELL_SIZE;
self.draw_cell(fb, falling.color, dx, dy);
}
}
// Draw frame
for bx in 0..TetrisBoard::BOARD_WIDTH + 2 {
self.draw_frame(fb, bx * TetrisBoard::CELL_SIZE, 0);
self.draw_frame(
fb,
bx * TetrisBoard::CELL_SIZE,
(TetrisBoard::BOARD_HEIGHT + 1) * TetrisBoard::CELL_SIZE,
);
}
for by in 0..TetrisBoard::BOARD_HEIGHT + 2 {
self.draw_frame(fb, 0, by * 9);
self.draw_frame(
fb,
(TetrisBoard::BOARD_WIDTH + 1) * TetrisBoard::CELL_SIZE,
by * TetrisBoard::CELL_SIZE,
);
}
}
}