gioser

tawasuyu/brahman

Rust 334TOML 129Markdown 39JSON 174745 Definiciones

⎇ 4bcdc88c838739c9bdac50c6d6d9a906c1d2f729 renaser/apps/pulso/src/lib.rs Rust · 137 líneas · 5.4 KB Historia Quién tocó qué crudo

feat(renaser): Fase 11 — el reloj del sistema como capacidad de host 4bcdc88c8 · sergio ·

1// =============================================================================
2//  renaser :: apps/pulso — Fase 11 :: el compas visual del reloj del host
3// -----------------------------------------------------------------------------
4//  Hasta la Fase 10 una aplicacion solo sabia CUANTAS veces la habian llamado
5//  —un `tick` tras otro—, no CUANTO tiempo habia pasado. La Fase 11 le da al
6//  userspace un reloj: la capacidad `sys_tiempo_mono`, los milisegundos
7//  monotonos desde el arranque.
8//
9//  `pulso` es su testigo. Dibuja un compas —una cabeza brillante que recorre
10//  una pista y vuelve— cuya posicion es una FUNCION PURA del reloj del host.
11//  No guarda estado entre fotogramas: no le hace falta. Y de ahi su prueba:
12//  dos instancias de `pulso`, nazca una al arrancar y otra mucho despues con
13//  un `Alt+N`, laten EXACTAMENTE al unisono — porque ambas leen el mismo
14//  reloj, no un contador propio de fotogramas.
15// =============================================================================
16
17#![no_std]
18
19// --- Las capacidades que el kernel `renaser` inyecta a esta aplicacion. ---
20#[link(wasm_import_module = "renaser")]
21extern "C" {
22    /// Compone un bufer de pixeles (de ESTA memoria lineal) en la region que el
23    /// kernel asigno a esta aplicacion.
24    fn sys_render_frame(ptr: u32, len: u32);
25    /// El reloj monotono del sistema: milisegundos desde el arranque.
26    fn sys_tiempo_mono() -> u64;
27}
28
29/// Sin sistema operativo bajo nosotros, un panico solo puede detenerse en seco.
30#[panic_handler]
31fn al_fallar(_: &core::panic::PanicInfo) -> ! {
32    loop {}
33}
34
35// --- Geometria de la escena. El ancho y el alto DEBEN coincidir con la region
36//     que el kernel asigna a esta app. ---
37const ANCHO: usize = 360;
38const ALTO: usize = 120;
39
40/// El periodo del compas, en milisegundos: la cabeza recorre la pista entera y
41/// vuelve a empezar cada `PERIODO`.
42const PERIODO: u64 = 6000;
43
44/// Azul nocturno: el fondo del lienzo.
45const FONDO: u32 = 0x0A_18_30;
46/// La pista por donde corre el compas — un surco tenue.
47const PISTA: u32 = 0x1E_2A_44;
48/// La estela ya recorrida en este ciclo.
49const ESTELA: u32 = 0x2E_50_C8;
50/// La cabeza del compas — el indigo brillante del foco del compositor.
51const CABEZA: u32 = 0x8B_5C_F6;
52
53/// Margen lateral de la pista, en pixeles.
54const MARGEN: usize = 24;
55/// Filas que ocupa la pista — un surco horizontal centrado en el lienzo.
56const PISTA_Y0: usize = 46;
57const PISTA_Y1: usize = 74;
58/// Anchura de la cabeza del compas, en pixeles.
59const CABEZA_ANCHO: usize = 7;
60
61/// El lienzo de la aplicacion, en SU propia memoria lineal. El kernel jamas lo
62/// ve directamente: solo recibe el (ptr, len) que cada fotograma le entrega.
63static mut LIENZO: [u32; ANCHO * ALTO] = [0; ANCHO * ALTO];
64
65/// Preparacion: el kernel la invoca UNA sola vez, al cargar el modulo. Pinta el
66/// primer fotograma — el compas en el instante de nacer.
67#[no_mangle]
68pub extern "C" fn init() {
69    pintar();
70}
71
72/// Un fotograma de trabajo: vuelve a pintar el compas en el instante actual y
73/// RETORNA, cediendo la CPU al kernel y a las apps vecinas.
74#[no_mangle]
75pub extern "C" fn tick() {
76    pintar();
77}
78
79/// Pinta el compas en el instante ACTUAL. No guarda estado alguno: la escena es
80/// una funcion pura del reloj del host. Por eso dos instancias de `pulso`,
81/// nazcan cuando nazcan, laten EXACTAMENTE al unisono.
82fn pintar() {
83    // SEGURIDAD: durante `init` y `tick` esta es la unica via de acceso a
84    // LIENZO, y el kernel jamas reentra el modulo mientras una de ellas corre.
85    let lienzo: &mut [u32] = unsafe { &mut *core::ptr::addr_of_mut!(LIENZO) };
86
87    // La fase del compas: 0 al inicio del periodo, casi 1 al final. Se deriva
88    // SOLO del reloj del host — ni un contador propio, ni un origen guardado.
89    // SEGURIDAD: `sys_tiempo_mono` es una capacidad del host; no toca memoria.
90    let tiempo = unsafe { sys_tiempo_mono() };
91    let fase = tiempo % PERIODO;
92
93    // El ancho util de la pista y hasta donde ha llegado la cabeza.
94    let util = ANCHO - 2 * MARGEN;
95    let avance = (fase as usize * util) / PERIODO as usize;
96
97    // Fondo limpio.
98    for pixel in lienzo.iter_mut() {
99        *pixel = FONDO;
100    }
101    // La pista entera, tenue.
102    banda(lienzo, MARGEN, MARGEN + util, PISTA);
103    // La estela ya recorrida en este ciclo.
104    banda(lienzo, MARGEN, MARGEN + avance, ESTELA);
105    // La cabeza del compas: una barra brillante al frente de la estela.
106    let cabeza0 = MARGEN + avance;
107    banda(lienzo, cabeza0, cabeza0 + CABEZA_ANCHO, CABEZA);
108
109    volcar(lienzo);
110}
111
112/// Rellena la pista —las filas [`PISTA_Y0`, `PISTA_Y1`)— entre las columnas
113/// [x0, x1) con un color, recortado con firmeza al ancho del lienzo.
114fn banda(lienzo: &mut [u32], x0: usize, x1: usize, color: u32) {
115    let x0 = x0.min(ANCHO);
116    let x1 = x1.min(ANCHO);
117    let mut fila = PISTA_Y0;
118    while fila < PISTA_Y1 {
119        let base = fila * ANCHO;
120        let mut col = x0;
121        while col < x1 {
122            lienzo[base + col] = color;
123            col += 1;
124        }
125        fila += 1;
126    }
127}
128
129/// Entrega el lienzo completo al kernel. El (ptr, len) apunta SIEMPRE dentro de
130/// nuestra memoria lineal, y su tamaño es, exactamente, el de la region.
131fn volcar(lienzo: &[u32]) {
132    // SEGURIDAD: `sys_render_frame` es una capacidad del host; el (ptr, len)
133    // describe nuestra propia memoria lineal y el host lo verifica sin piedad.
134    unsafe {
135        sys_render_frame(lienzo.as_ptr() as u32, (ANCHO * ALTO * 4) as u32);
136    }
137}