1
0
Fork 0
mirror of https://github.com/imjasonh/nescript synced 2026-07-08 17:06:04 +00:00
nescript/examples/sha256/keyboard.ne
Claude ba23f8578a
examples/sha256: interactive SHA-256 hasher with on-screen keyboard
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
2026-04-16 14:02:58 +00:00

62 lines
1.9 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// sha256/keyboard.ne — key-to-character lookup + input dispatch.
//
// The on-screen keyboard is a 5-row × 8-column grid of cells.
// `kb_row` and `kb_col` in state.ne store the cursor position.
// The character produced when the user presses A is looked up
// here. Special values are encoded with ASCII control codes so
// they're distinguishable from printable bytes:
//
// KEY_BKSP (0x08) — bottom row col 6. Delete one char.
// KEY_ENTER (0x0A) — bottom row col 7. Start compression.
//
// The grid layout (matches the keyboard in background.ne):
//
// row 0: A B C D E F G H
// row 1: I J K L M N O P
// row 2: Q R S T U V W X
// row 3: Y Z 0 1 2 3 4 5
// row 4: 6 7 8 9 _ . < >
var KB_CHARS: u8[40] = [
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, // A B C D E F G H
0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, // I J K L M N O P
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, // Q R S T U V W X
0x59, 0x5A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, // Y Z 0 1 2 3 4 5
0x36, 0x37, 0x38, 0x39, 0x20, 0x2E, 0x08, 0x0A // 6 7 8 9 ' ' '.' BKSP ENTER
]
// Look up the character emitted by the key at (kb_row, kb_col).
fun current_key() -> u8 {
var idx: u8 = (kb_row << 3) + kb_col // row * 8 + col
return KB_CHARS[idx]
}
// Append a byte to the input buffer. Does nothing if the buffer
// is already at INPUT_MAX — users wanting to correct their
// input reach for backspace first.
fun input_append(ch: u8) {
if msg_len >= INPUT_MAX {
return
}
msg[msg_len] = ch
msg_len += 1
}
// Delete the last byte, if any.
fun input_backspace() {
if msg_len == 0 {
return
}
msg_len -= 1
msg[msg_len] = 0
}
// Wipe the entire buffer. Triggered by SELECT from any state.
fun input_clear() {
var i: u8 = 0
while i < INPUT_MAX {
msg[i] = 0
i += 1
}
msg_len = 0
}