Reorganize
This commit is contained in:
parent
4250e51f29
commit
8f2edd69f7
@ -1,4 +1,5 @@
|
||||
- quick drop
|
||||
- faster timer
|
||||
- fix asm loader
|
||||
- document everything
|
||||
- prettier pictures
|
@ -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:
|
||||
|
@ -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
5
tetros/src/game/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
mod board;
|
||||
pub use board::*;
|
||||
|
||||
mod falling;
|
||||
pub use falling::*;
|
@ -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.
|
||||
|
@ -18,5 +18,3 @@ pub use handler::*;
|
||||
|
||||
mod stackframe;
|
||||
pub use stackframe::*;
|
||||
|
||||
mod util;
|
||||
|
@ -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
|
||||
}
|
@ -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.");
|
||||
|
@ -4,8 +4,7 @@ pub use thunk::*;
|
||||
mod eflags;
|
||||
pub use eflags::*;
|
||||
|
||||
pub mod util;
|
||||
|
||||
#[macro_use]
|
||||
pub mod panic;
|
||||
|
||||
pub mod util;
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user