灵符lingfu

ling-lang

↓ 0 downloads

Ling - The Omniglot Systems Language

Keywords systems, polyglot, ai, crypto, game
lingfu install ling-lang
LicenseApache-2.0 OR MIT
AuthorsLing Lin, Sanny Lin
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / Files (995)

crates/ling-kernel/src/drivers/fbcon.rs
//! Scrolling framebuffer text console for aarch64 (Raspberry Pi).
//!
//! The x86_64 side has VGA text mode plus the `term`/`wm` compositor; the Pi
//! only has a linear framebuffer, so kernel console output is rendered here
//! with `font8x8`, straight to the live framebuffer. A character grid is kept
//! alongside the pixels so scrolling is a cheap grid shift + redraw rather than
//! reading pixels back out of (often uncached / write-combining) VRAM.
//!
//! Assumes `font8x8` scale 1 (8x8 glyphs). The boot banner above the console
//! area leaves the scale at 1 when it finishes.

use crate::drivers::{font8x8, framebuffer};

const MAX_COLS: usize = 200;
const MAX_ROWS: usize = 120;
const CELL_W: u32 = 8; // font8x8 advance at scale 1
const CELL_H: u32 = 10; // 8px glyph + 2px leading
const MARGIN: u32 = 8;
/// Pixels reserved at the top for the welcome/first-boot banner
/// (see `lib.rs::rpi_boot_screen`).
const TOP: u32 = 224;

const FG: u32 = 0xC8_D0_E0;
const BG: u32 = 0x10_10_18;

static mut GRID: [u8; MAX_COLS * MAX_ROWS] = [b' '; MAX_COLS * MAX_ROWS];
static mut COL: usize = 0;
static mut ROW: usize = 0;
static mut READY: bool = false;

fn cols() -> usize {
    let w = framebuffer::width();
    if w <= MARGIN * 2 {
        return 0;
    }
    (((w - MARGIN * 2) / CELL_W) as usize).min(MAX_COLS)
}

fn rows() -> usize {
    let h = framebuffer::height();
    if h <= TOP + CELL_H {
        return 0;
    }
    (((h - TOP) / CELL_H) as usize).min(MAX_ROWS)
}

/// Clear the console area (below the banner) and home the cursor. Call once the
/// framebuffer and boot banner are up.
pub fn init() {
    if !framebuffer::available() {
        return;
    }
    let (w, h) = (framebuffer::width(), framebuffer::height());
    framebuffer::fill_rect(0, TOP, w, h.saturating_sub(TOP), BG);
    unsafe {
        for cell in (&mut *&raw mut GRID).iter_mut() {
            *cell = b' ';
        }
        COL = 0;
        ROW = 0;
        READY = true;
    }
}

fn draw_cell(col: usize, row: usize, c: u8) {
    let x = MARGIN + col as u32 * CELL_W;
    let y = TOP + row as u32 * CELL_H;
    font8x8::draw_char(x, y, c, FG, BG);
}

/// Shift the grid up one line and repaint the whole console from it.
fn scroll() {
    let (nc, nr) = (cols(), rows());
    if nr == 0 {
        return;
    }
    unsafe {
        let grid = &mut *&raw mut GRID;
        for r in 1..nr {
            for c in 0..nc {
                grid[(r - 1) * MAX_COLS + c] = grid[r * MAX_COLS + c];
            }
        }
        for c in 0..nc {
            grid[(nr - 1) * MAX_COLS + c] = b' ';
        }
    }
    let (w, h) = (framebuffer::width(), framebuffer::height());
    framebuffer::fill_rect(0, TOP, w, h.saturating_sub(TOP), BG);
    unsafe {
        let grid = &*&raw const GRID;
        for r in 0..nr {
            for c in 0..nc {
                let ch = grid[r * MAX_COLS + c];
                if ch != b' ' {
                    draw_cell(c, r, ch);
                }
            }
        }
    }
}

pub fn putc(ch: u8) {
    if unsafe { !READY } || !framebuffer::available() {
        return;
    }
    let nc = cols();
    let nr = rows();
    if nc == 0 || nr == 0 {
        return;
    }
    unsafe {
        if ch == b'\n' {
            COL = 0;
            ROW += 1;
        } else if ch == b'\r' {
            COL = 0;
        } else if ch == 0x08 {
            if COL > 0 {
                COL -= 1;
                GRID[ROW * MAX_COLS + COL] = b' ';
                draw_cell(COL, ROW, b' ');
            }
        } else if (0x20..0x7F).contains(&ch) {
            if COL >= nc {
                COL = 0;
                ROW += 1;
            }
            if ROW >= nr {
                scroll();
                ROW = nr - 1;
            }
            GRID[ROW * MAX_COLS + COL] = ch;
            draw_cell(COL, ROW, ch);
            COL += 1;
        }
        if ROW >= nr {
            scroll();
            ROW = nr - 1;
        }
    }
}

/// Stop drawing console text (a full-screen app or the desktop owns the
/// framebuffer); `init` brings the console back.
pub fn suspend() {
    unsafe { READY = false };
}

pub fn write(bytes: &[u8]) {
    for &b in bytes {
        putc(b);
    }
}

← Back to index