this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

update docs

alice 450e7ff0 89ca7139

+190 -1
+3
AGENTS.md
··· 15 15 - Reference new/updated plans from AGENTS.md and the docs index. 16 16 - Keep hygiene visible: mention clippy/test status with each change. 17 17 - ALWAYS format code with `cargo fmt` after changes, in addition to fixing all compiler/clippy warnings and errors. 18 + - ALWAYS update the test carts catalog when adding a new cart: 19 + - Add the cart to `docs/testing/test_carts.md` with purpose, run instructions, and expected behavior. 20 + - If needed, add a short run snippet to `docs/README.md`. 18 21 19 22 **Context** 20 23 - **Rewrite code location:** All Rust rewrite code lives under `tic80_rust/` (crate root). Tests live in `tic80_rust/tests/`. The windowed demo binary is `tic80_rust/src/main.rs`.
+4
docs/README.md
··· 21 21 - `docs/testing/strategy.md`: Testing and validation strategy across API/VRAM/audio. 22 22 - `docs/testing/frame_hashes.md`: Conventions for deterministic frame/audio hashing (stub). 23 23 - `docs/testing/test_catalog.md`: Summary of current tests and their intent. 24 + - `docs/testing/test_carts.md`: Manual test carts (Lua) for quick verification (FFT, time/trace). 24 25 25 26 ## Decisions (ADR) 26 27 - `docs/adr/0001-winit-pixels.md`: Windowing/presentation stack decision. ··· 41 42 - Audio FFT test cart: 42 43 - `cargo run --manifest-path tic80_rust/Cargo.toml -- tic80_rust/assets/fft_test.lua --audio-device "<name-substr>"` 43 44 - Add `--audio-vu` to print a 1s peak; add `--debug-fft` to print the first few bins. 45 + - Time/Trace test cart: 46 + - `cargo run --manifest-path tic80_rust/Cargo.toml -- tic80_rust/assets/time_trace_test.lua` 47 + - Shows elapsed ms and emits a trace once per second to the console.
+5 -1
docs/specs/implementation_status.md
··· 21 21 - Memory 22 22 - `peek(addr[,bits=8])`, `poke(addr, value[,bits=8])`: 8/4/2/1-bit addressing across full 96 KB; VRAM screen region mapped to live framebuffer (nibble-packed 2 px/byte). 23 23 - `peek1/peek2/peek4`, `poke1/poke2/poke4`: Bit-specific helpers. 24 - - `memcpy(dst, src, size)`, `memset(dst, value, size)`: Byte-wise operations; overlap-safe memcpy; VRAM ops update on-screen pixels immediately. 24 + - `memcpy(dst, src, size)`, `memset(dst, value, size)`: Byte-wise operations; overlap-safe memcpy; VRAM ops update on-screen pixels immediately. 25 + 26 + Implemented (System) 27 + - `trace(message, color=15)`: Prints to console (color informational only in CLI); tests verify trace messages via an internal buffer used only in tests. 28 + - `time() -> milliseconds`: Monotonic milliseconds since cart start (tick-thread time origin); tested for monotonic increase across ticks. 25 29 26 30 Implemented (Runner/CLI) 27 31 - `.lua` loader: First CLI arg as a `.lua` path runs external script; fallback to bundled `assets/default.lua`.
+2
docs/specs/lua_api_parity.md
··· 133 133 134 134 - trace: `trace(message color=15)` 135 135 - Effect: Print to console (not screen) in color. 136 + - Status: Implemented (color accepted; prints to console; tests use internal buffer). 136 137 - Subsystem: tic-core (logger). 137 138 - time: `time() -> ticks` 138 139 - Effect: Milliseconds since cart start (double); used for animation/timing. 140 + - Status: Implemented (monotonic; tick-thread time origin). 139 141 - Subsystem: tic-core (timer). 140 142 - tstamp: `tstamp() -> timestamp` 141 143 - Effect: Seconds since Unix epoch.
+33
docs/testing/test_carts.md
··· 1 + # Test Carts (Manual Verification) 2 + 3 + This page lists small Lua carts in `tic80_rust/assets/` intended for quick, manual checks of subsystems. 4 + 5 + - `tic80_rust/assets/default.lua` 6 + - Purpose: Graphics primitives demo (cls, pix, line, rect/rectb, circ/circb, elli/ellib, tri/trib, clip, print) with gentle animation. 7 + - How to run: 8 + - `cargo run --manifest-path tic80_rust/Cargo.toml` (default cart), or 9 + - `cargo run --manifest-path tic80_rust/Cargo.toml -- tic80_rust/assets/default.lua` 10 + - Expected: Crosshair, shapes, clipping box toggling every few seconds, and sprinkled “stars”. 11 + 12 + - `tic80_rust/assets/alt.lua` 13 + - Purpose: Minimal cart to validate `cls`, `rect`, `pix` origin behavior. 14 + - How to run: 15 + - `cargo run --manifest-path tic80_rust/Cargo.toml -- tic80_rust/assets/alt.lua` 16 + - Expected: Background fill, small filled square at origin, and a single marker pixel at (0,0). 17 + 18 + - `tic80_rust/assets/fft_test.lua` 19 + - Purpose: Visualize normalized FFT bins as 32 bars. 20 + - How to run: 21 + - `cargo run --manifest-path tic80_rust/Cargo.toml -- tic80_rust/assets/fft_test.lua --audio-device "<name-substr>"` 22 + - Optional: `--audio-vu` to print a 1s peak; `--debug-fft` to print the first 16 bins (throttled). 23 + - Expected: Bars respond to audio; silence trends to near-zero. VU ~-180 dBFS with silence. 24 + 25 + - `tic80_rust/assets/time_trace_test.lua` 26 + - Purpose: Exercise `time()` and `trace()` APIs. 27 + - How to run: 28 + - `cargo run --manifest-path tic80_rust/Cargo.toml -- tic80_rust/assets/time_trace_test.lua` 29 + - Expected: On-screen elapsed ms text; a small marker toggles color every second; console prints `sec=<n>` lines via `trace()`. 30 + 31 + Notes 32 + - These carts are designed for fast feedback during local development. They complement headless tests and can reveal platform quirks (devices, timing). 33 + - Keep carts small, single-purpose, and deterministic where possible.
+1
docs/testing/test_catalog.md
··· 53 53 Notes 54 54 - Tests prefer headless framebuffer inspection over image baselines. 55 55 - Hashing uses FNV‑1a over VRAM palette indices for portability and stability. 56 + - For manual carts, see `docs/testing/test_carts.md`.
+32
tic80_rust/assets/time_trace_test.lua
··· 1 + -- Simple time/trace test cart 2 + -- Shows elapsed ms since start and emits a trace every second. 3 + 4 + local last_ms = 0 5 + local last_sec = -1 6 + 7 + function BOOT() 8 + cls(0) 9 + end 10 + 11 + function TIC() 12 + cls(0) 13 + local ms = math.floor(time()) 14 + local sec = math.floor(ms / 1000) 15 + 16 + -- Draw elapsed ms and a ticking marker 17 + print("time(ms): " .. ms, 2, 2, 14, false, 1, false) 18 + if (sec % 2) == 0 then 19 + rect(2, 14, 10, 10, 6) 20 + else 21 + rect(2, 14, 10, 10, 12) 22 + end 23 + 24 + -- Emit a trace once per new second 25 + if sec ~= last_sec then 26 + trace("sec=" .. tostring(sec), 7) 27 + last_sec = sec 28 + end 29 + 30 + last_ms = ms 31 + end 32 +
+62
tic80_rust/src/script/lua_runner.rs
··· 1 1 use std::cell::RefCell; 2 2 use std::rc::Rc; 3 + use std::sync::{Mutex, OnceLock}; 4 + use std::time::Instant; 3 5 4 6 use mlua::{Function, Lua, MultiValue, RegistryKey, Result as LuaResult, Value}; 5 7 ··· 12 14 tic_key: Option<RegistryKey>, 13 15 } 14 16 17 + // Optional trace buffer (used by tests); if present, trace() will also append messages here. 18 + static TRACE_BUFFER: OnceLock<Mutex<Vec<String>>> = OnceLock::new(); 19 + 15 20 impl LuaRunner { 16 21 pub fn new( 17 22 fb: Rc<RefCell<Framebuffer>>, ··· 19 24 script_src: &str, 20 25 ) -> LuaResult<Self> { 21 26 let lua = Lua::new(); 27 + let start_time = Instant::now(); 22 28 let tic_key = { 23 29 let globals = lua.globals(); 24 30 ··· 220 226 })?; 221 227 globals.set("fftrs", fftrs_fn)?; 222 228 229 + // trace(message, color=15) 230 + let trace_fn = lua.create_function(move |_, args: MultiValue| { 231 + let msg = match args.get(0) { 232 + Some(Value::String(s)) => s.to_str()?.to_string(), 233 + Some(Value::Number(n)) => n.to_string(), 234 + Some(Value::Integer(i)) => i.to_string(), 235 + Some(Value::Boolean(b)) => b.to_string(), 236 + Some(Value::Nil) | None => String::new(), 237 + _ => String::new(), 238 + }; 239 + let color = match args.get(1) { 240 + Some(Value::Integer(n)) => *n as i32, 241 + Some(Value::Number(n)) => *n as i32, 242 + _ => 15, 243 + }; 244 + // Print to console; color is informational only here. 245 + println!("[trace:{}] {}", color, msg); 246 + if let Some(buf) = TRACE_BUFFER.get() { 247 + if let Ok(mut b) = buf.lock() { 248 + b.push(msg); 249 + } 250 + } 251 + Ok(()) 252 + })?; 253 + globals.set("trace", trace_fn)?; 254 + 255 + // time() -> milliseconds since cart start 256 + let start_copy = start_time; 257 + let time_fn = lua.create_function(move |_, ()| { 258 + let ms = start_copy.elapsed().as_millis() as f64; 259 + Ok(ms) 260 + })?; 261 + globals.set("time", time_fn)?; 262 + 223 263 // memory: peek/poke + bit variants + memcpy/memset 224 264 let mem_peek = mem.clone(); 225 265 let peek_fn = lua.create_function(move |_, (addr, bits): (u32, Option<u8>)| { ··· 387 427 } 388 428 } 389 429 } 430 + 431 + // Test support: initialize a shared trace buffer (clears any existing messages). 432 + pub fn trace_buffer_init() { 433 + let _ = TRACE_BUFFER.set(Mutex::new(Vec::new())); 434 + if let Some(b) = TRACE_BUFFER.get() { 435 + if let Ok(mut v) = b.lock() { 436 + v.clear(); 437 + } 438 + } 439 + } 440 + 441 + // Test support: take and clear all trace messages. 442 + pub fn trace_buffer_take() -> Vec<String> { 443 + if let Some(b) = TRACE_BUFFER.get() { 444 + if let Ok(mut v) = b.lock() { 445 + let out = v.clone(); 446 + v.clear(); 447 + return out; 448 + } 449 + } 450 + Vec::new() 451 + }
+48
tic80_rust/tests/time_trace_tests.rs
··· 1 + use std::cell::RefCell; 2 + use std::rc::Rc; 3 + use std::thread; 4 + use std::time::Duration; 5 + 6 + use tic80_rust::core::memory::Memory; 7 + use tic80_rust::gfx::framebuffer::Framebuffer; 8 + use tic80_rust::script::lua_runner::{trace_buffer_init, trace_buffer_take, LuaRunner}; 9 + 10 + #[test] 11 + fn lua_trace_buffers_and_prints() { 12 + trace_buffer_init(); 13 + let script = r#" 14 + function BOOT() cls(0) end 15 + function TIC() 16 + trace("hello", 7) 17 + end 18 + "#; 19 + let fb = Rc::new(RefCell::new(Framebuffer::new())); 20 + let mem = Rc::new(RefCell::new(Memory::new(fb.clone()))); 21 + let runner = LuaRunner::new(fb, mem, script).expect("lua init"); 22 + runner.tick(); 23 + let out = trace_buffer_take(); 24 + assert!( 25 + out.iter().any(|s| s.contains("hello")), 26 + "expected trace buffer to contain 'hello'" 27 + ); 28 + } 29 + 30 + #[test] 31 + fn lua_time_increases_over_real_time() { 32 + let script = r#" 33 + tprev = nil 34 + function BOOT() cls(0) end 35 + function TIC() 36 + local t = time() 37 + if tprev ~= nil and t > tprev + 1 then pix(0,0,9) end 38 + tprev = t 39 + end 40 + "#; 41 + let fb = Rc::new(RefCell::new(Framebuffer::new())); 42 + let mem = Rc::new(RefCell::new(Memory::new(fb.clone()))); 43 + let runner = LuaRunner::new(fb.clone(), mem, script).expect("lua init"); 44 + runner.tick(); 45 + thread::sleep(Duration::from_millis(10)); 46 + runner.tick(); 47 + assert_eq!(fb.borrow_mut().pix(0, 0, None), Some(9)); 48 + }