mirror of
https://github.com/imjasonh/nescript
synced 2026-07-08 17:06:04 +00:00
An end-to-end FIPS 180-4 SHA-256 hasher running entirely on the NES.
The player types up to 16 ASCII characters on a 5x8 on-screen
keyboard, presses Enter, and the program computes and displays the
64-character hex digest.
Layout (`examples/sha256/*.ne`):
constants.ne layout + K[64] / H_INIT[8] tables
(declared as `var` with init_array because the
v0.1 compiler treats `const u8[N] = [...]` as
a no-op — noted in the file)
assets.ne 44-tile Tileset (A..Z, 0..9, punctuation,
special keys, cursor) shared between BG and
sprite layers
background.ne static nametable (title, labels, keyboard
grid) painted at reset
state.ne globals
sha_core.ne 32-bit byte primitives (copy, xor, and, add,
not, rotr, shr) in inline asm + sigma/Sigma
mixers + schedule/round steps + fold
render.ne OAM helpers for cursor, input buffer, and
64-nibble digest
keyboard.ne key dispatch table
entering_state.ne cursor navigation + typing + auto-demo
computing_state.ne phased driver (48 schedule steps + 64 rounds
+ fold across ~30 frames at 4 iterations each)
showing_state.ne renders the 256-bit digest as 8 rows of 8
sprite glyphs
Implementation notes:
- All 32-bit words live as 4 little-endian bytes in `wk[64]`,
`w[256]`, `h_state[32]` so every primitive walks four bytes with
`LDA {arr},X`/`STA {arr},X` chains and, for adds, a carry chain.
- Every primitive reads its parameters straight out of the
transport slots `$04`/`$05` rather than `{dst}`/`{src}`
substitutions: the inline-asm resolver looks parameters up in
the analyzer's allocation table but the codegen spills them to a
different per-function RAM slot, so `{dst}` would resolve to a
ZP slot nothing ever writes to. Bypassing the substitution
entirely sidesteps the issue without a compiler change.
- Rotate-right by any amount is a byte-rotate loop plus a bit-
rotate loop so the 10 SHA amounts (2, 6, 7, 11, 13, 17, 18, 19,
22, 25) all compile to a handful of chained `ROR`s.
- The headless jsnes golden auto-types "NES" after 1 s of idle and
captures its SHA-256 digest
AE9145DB5CABC41FE34B54E34AF8881F462362EA20FD8F861B26532FFBB84E0D
— byte-identical to `shasum` / `hashlib.sha256(b"NES")`.
Build: `cargo run --release -- build examples/sha256.ne`
https://claude.ai/code/session_01FRmSBruVWCufm3LsUVMs8v
436 lines
15 KiB
Text
436 lines
15 KiB
Text
// sha256/assets.ne — one big Tileset sprite block.
|
||
//
|
||
// The ROM uses a single 8 KB CHR page that both the background
|
||
// layer and the sprite layer read from, so every tile declared
|
||
// here is available either way. User tiles start at index 1
|
||
// (index 0 is reserved for the compiler's built-in smiley).
|
||
//
|
||
// The alphabet is a 2-pixel-stroke sans-serif that reads well on
|
||
// NES resolution. Every tile keeps its glyph inside a 6×6 window
|
||
// (columns 1..6, rows 1..6) so adjacent characters never touch.
|
||
//
|
||
// Colour vocabulary:
|
||
// . palette index 0 — transparent (sprites) / bg universal
|
||
// 2 palette index 2 — main glyph colour (white in bg0/sp0)
|
||
// 3 palette index 3 — accent (cursor bar, key arrows)
|
||
|
||
sprite Tileset {
|
||
pixels: [
|
||
// ── 1: A ─────────────────────────────────────────
|
||
"........",
|
||
"..2222..",
|
||
".22..22.",
|
||
".22..22.",
|
||
".222222.",
|
||
".22..22.",
|
||
".22..22.",
|
||
"........",
|
||
// ── 2: B ─────────────────────────────────────────
|
||
"........",
|
||
".22222..",
|
||
".22..22.",
|
||
".22222..",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22222..",
|
||
"........",
|
||
// ── 3: C ─────────────────────────────────────────
|
||
"........",
|
||
"..22222.",
|
||
".22..22.",
|
||
".22.....",
|
||
".22.....",
|
||
".22..22.",
|
||
"..22222.",
|
||
"........",
|
||
// ── 4: D ─────────────────────────────────────────
|
||
"........",
|
||
".2222...",
|
||
".22.22..",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22.22..",
|
||
".2222...",
|
||
"........",
|
||
// ── 5: E ─────────────────────────────────────────
|
||
"........",
|
||
".222222.",
|
||
".22.....",
|
||
".22222..",
|
||
".22.....",
|
||
".22.....",
|
||
".222222.",
|
||
"........",
|
||
// ── 6: F ─────────────────────────────────────────
|
||
"........",
|
||
".222222.",
|
||
".22.....",
|
||
".22222..",
|
||
".22.....",
|
||
".22.....",
|
||
".22.....",
|
||
"........",
|
||
// ── 7: G ─────────────────────────────────────────
|
||
"........",
|
||
"..22222.",
|
||
".22.....",
|
||
".22.222.",
|
||
".22..22.",
|
||
".22..22.",
|
||
"..2222..",
|
||
"........",
|
||
// ── 8: H ─────────────────────────────────────────
|
||
"........",
|
||
".22..22.",
|
||
".22..22.",
|
||
".222222.",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
"........",
|
||
// ── 9: I ─────────────────────────────────────────
|
||
"........",
|
||
"..2222..",
|
||
"...22...",
|
||
"...22...",
|
||
"...22...",
|
||
"...22...",
|
||
"..2222..",
|
||
"........",
|
||
// ── 10: J ────────────────────────────────────────
|
||
"........",
|
||
"....222.",
|
||
".....22.",
|
||
".....22.",
|
||
".....22.",
|
||
".22..22.",
|
||
"..2222..",
|
||
"........",
|
||
// ── 11: K ────────────────────────────────────────
|
||
"........",
|
||
".22..22.",
|
||
".22.22..",
|
||
".2222...",
|
||
".22.22..",
|
||
".22..22.",
|
||
".22..22.",
|
||
"........",
|
||
// ── 12: L ────────────────────────────────────────
|
||
"........",
|
||
".22.....",
|
||
".22.....",
|
||
".22.....",
|
||
".22.....",
|
||
".22.....",
|
||
".222222.",
|
||
"........",
|
||
// ── 13: M ────────────────────────────────────────
|
||
"........",
|
||
".22..22.",
|
||
".222222.",
|
||
".222222.",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
"........",
|
||
// ── 14: N ────────────────────────────────────────
|
||
"........",
|
||
".22..22.",
|
||
".222.22.",
|
||
".222222.",
|
||
".22.222.",
|
||
".22..22.",
|
||
".22..22.",
|
||
"........",
|
||
// ── 15: O ────────────────────────────────────────
|
||
"........",
|
||
"..2222..",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
"..2222..",
|
||
"........",
|
||
// ── 16: P ────────────────────────────────────────
|
||
"........",
|
||
".22222..",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22222..",
|
||
".22.....",
|
||
".22.....",
|
||
"........",
|
||
// ── 17: Q ────────────────────────────────────────
|
||
"........",
|
||
"..2222..",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22.222.",
|
||
".22.22..",
|
||
"..222.2.",
|
||
"........",
|
||
// ── 18: R ────────────────────────────────────────
|
||
"........",
|
||
".22222..",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22222..",
|
||
".22.22..",
|
||
".22..22.",
|
||
"........",
|
||
// ── 19: S ────────────────────────────────────────
|
||
"........",
|
||
"..22222.",
|
||
".22.....",
|
||
"..2222..",
|
||
".....22.",
|
||
".....22.",
|
||
".22222..",
|
||
"........",
|
||
// ── 20: T ────────────────────────────────────────
|
||
"........",
|
||
".222222.",
|
||
"...22...",
|
||
"...22...",
|
||
"...22...",
|
||
"...22...",
|
||
"...22...",
|
||
"........",
|
||
// ── 21: U ────────────────────────────────────────
|
||
"........",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
"..2222..",
|
||
"........",
|
||
// ── 22: V ────────────────────────────────────────
|
||
"........",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
"..2222..",
|
||
"...22...",
|
||
"........",
|
||
// ── 23: W ────────────────────────────────────────
|
||
"........",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
".222222.",
|
||
".222222.",
|
||
".22..22.",
|
||
"........",
|
||
// ── 24: X ────────────────────────────────────────
|
||
"........",
|
||
".22..22.",
|
||
"..2222..",
|
||
"...22...",
|
||
"...22...",
|
||
"..2222..",
|
||
".22..22.",
|
||
"........",
|
||
// ── 25: Y ────────────────────────────────────────
|
||
"........",
|
||
".22..22.",
|
||
".22..22.",
|
||
"..2222..",
|
||
"...22...",
|
||
"...22...",
|
||
"...22...",
|
||
"........",
|
||
// ── 26: Z ────────────────────────────────────────
|
||
"........",
|
||
".222222.",
|
||
".....22.",
|
||
"....22..",
|
||
"...22...",
|
||
"..22....",
|
||
".222222.",
|
||
"........",
|
||
// ── 27: 0 ────────────────────────────────────────
|
||
"........",
|
||
"..2222..",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
".22..22.",
|
||
"..2222..",
|
||
"........",
|
||
// ── 28: 1 ────────────────────────────────────────
|
||
"........",
|
||
"...22...",
|
||
"..222...",
|
||
".2.22...",
|
||
"...22...",
|
||
"...22...",
|
||
"..2222..",
|
||
"........",
|
||
// ── 29: 2 ────────────────────────────────────────
|
||
"........",
|
||
"..2222..",
|
||
".22..22.",
|
||
".....22.",
|
||
"....22..",
|
||
"..22....",
|
||
".222222.",
|
||
"........",
|
||
// ── 30: 3 ────────────────────────────────────────
|
||
"........",
|
||
"..2222..",
|
||
".22..22.",
|
||
"....22..",
|
||
".....22.",
|
||
".22..22.",
|
||
"..2222..",
|
||
"........",
|
||
// ── 31: 4 ────────────────────────────────────────
|
||
"........",
|
||
"....22..",
|
||
"...222..",
|
||
"..2.22..",
|
||
".22.22..",
|
||
".222222.",
|
||
"....22..",
|
||
"........",
|
||
// ── 32: 5 ────────────────────────────────────────
|
||
"........",
|
||
".222222.",
|
||
".22.....",
|
||
".22222..",
|
||
".....22.",
|
||
".22..22.",
|
||
"..2222..",
|
||
"........",
|
||
// ── 33: 6 ────────────────────────────────────────
|
||
"........",
|
||
"..2222..",
|
||
".22.....",
|
||
".22222..",
|
||
".22..22.",
|
||
".22..22.",
|
||
"..2222..",
|
||
"........",
|
||
// ── 34: 7 ────────────────────────────────────────
|
||
"........",
|
||
".222222.",
|
||
".....22.",
|
||
"....22..",
|
||
"...22...",
|
||
"..22....",
|
||
"..22....",
|
||
"........",
|
||
// ── 35: 8 ────────────────────────────────────────
|
||
"........",
|
||
"..2222..",
|
||
".22..22.",
|
||
"..2222..",
|
||
".22..22.",
|
||
".22..22.",
|
||
"..2222..",
|
||
"........",
|
||
// ── 36: 9 ────────────────────────────────────────
|
||
"........",
|
||
"..2222..",
|
||
".22..22.",
|
||
".22..22.",
|
||
"..22222.",
|
||
".....22.",
|
||
"..2222..",
|
||
"........",
|
||
// ── 37: underscore / space ('_') ─────────────────
|
||
// A shallow underline so the "space" key is visible
|
||
// in the keyboard grid and the rendered input buffer
|
||
// shows blanks where the user typed spaces.
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"........",
|
||
".222222.",
|
||
"........",
|
||
// ── 38: period ('.') ─────────────────────────────
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"..22....",
|
||
"..22....",
|
||
"........",
|
||
// ── 39: colon (':') — used in labels only ────────
|
||
"........",
|
||
"........",
|
||
"...22...",
|
||
"...22...",
|
||
"........",
|
||
"...22...",
|
||
"...22...",
|
||
"........",
|
||
// ── 40: dash ('-') — used in labels only ─────────
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"........",
|
||
".222222.",
|
||
"........",
|
||
"........",
|
||
"........",
|
||
// ── 41: backspace arrow ('<') ────────────────────
|
||
// A left-pointing arrow with a vertical bar on the
|
||
// right, read as "rub out" by anyone who's used a
|
||
// Unix terminal.
|
||
"........",
|
||
"...2..2.",
|
||
"..22..2.",
|
||
".222222.",
|
||
"..22..2.",
|
||
"...2..2.",
|
||
"........",
|
||
"........",
|
||
// ── 42: enter / return arrow ('>') ───────────────
|
||
// An arrow pointing down and left — the classic
|
||
// ↵ glyph flattened to monochrome. Drawn offset to
|
||
// the right so it reads as "confirm".
|
||
"........",
|
||
"......2.",
|
||
"......2.",
|
||
"..2...2.",
|
||
".22...2.",
|
||
"222222..",
|
||
".22.....",
|
||
"..2.....",
|
||
// ── 43: cursor glyph ─────────────────────────────
|
||
// A right-pointing triangle in the accent colour
|
||
// (palette index 3). When placed as a sprite at the
|
||
// cell immediately left of the selected key, it sits
|
||
// on a row that carries only this sprite, so it never
|
||
// contributes to the keyboard row's 8-per-scanline
|
||
// budget.
|
||
"........",
|
||
"..3.....",
|
||
"..33....",
|
||
"..333...",
|
||
"..333...",
|
||
"..33....",
|
||
"..3.....",
|
||
"........",
|
||
// ── 44: blank tile ───────────────────────────────
|
||
// Every pixel is palette index 0 — renders as the
|
||
// universal colour (dk_blue) in the background and
|
||
// as fully transparent when used as a sprite. Used
|
||
// to pad the nametable so short rows don't fall back
|
||
// to tile 0 (the built-in smiley glyph).
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"........",
|
||
"........"
|
||
]
|
||
}
|