Level 59: Knight Rider RISC

Open level →

Task

Goal: run the finale of the single-cycle line — the "Knight Rider" program: a running LED light through MMIO. No new instructions or schematics: the LED address 0xFFFF_F000 is built as lui x10, 0xFFFFF, and every sw x11, 0(x10) lights the runner bits and lands a line in the MMIO trace. The per-period sequence is 1,2,4,8,16,32,64,128,64,32,16,8,4,2,1 — repeat it twice and halt on LED = 1. LED is write-only (lw from it — ERR_WRITEONLY_READ), switches are read-only (sw — ERR_READONLY_WRITE). After passing the check, your level-58 core goes to the Tang Nano 9K board via the ZIP button.

The finale of the single-cycle line: the light runs across eight LEDs and back, as in the Knight Rider series. No new instructions and no schematics — this is a pure-programming level, and its program will travel to a real board.

The output goes through MMIO (memory-mapped I/O): peripherals live in the memory address space. The LED is address 0xFFFF_F000, write-only: an ordinary sw lights the runner bits, but reading from this address is forbidden (ERR_WRITEONLY_READ). The switches are 0xFFFF_F004, read-only: writing there gives ERR_READONLY_WRITE. Every sw to the LED lands a line in the MMIO trace — the check compares it pairwise.

Level tasks:

  1. Build the LED address. 0xFFFF_F000 does not fit a 12-bit immediate — the upper half is built with lui x10, 0xFFFFF.
  2. Lay down the header. The boundary x13 = 128 (the stop mask 0x80) and the period counter x14 = 2.
  3. Write the period. The period label: the light x11 = 1; to the right (right) — sw, slli, bne until 0x80; a separate 0x80 write; to the left (left) — srli down to zero. The per-period sequence: 1,2,4,8,16,32,64,128,64,32,16,8,4,2,1.
  4. Repeat the period twice and halt on .end — the LED must stay 1.
  5. Run and compare. "Check" first asks for the number of MMIO trace writes — count it yourself: 15 per period × 2. After passing, the ZIP button packs your level-58 core into a Gowin project for the Tang Nano 9K.

Solution for self-check

First write the program yourself. The solution below gives the checkpoints.

What you should get: Knight Rider halts cleanly: 115 cycles, 30 MMIO trace records (15 per period × 2), the final LED = 1, registers x10 = 0xFFFF_F000, x11 = 1, x13 = 128, x14 = 0; after the check the core ships to the Tang Nano 9K via the ZIP button.

Step 1 — the address via lui. lui x10, 0xFFFFF: imm20 = 0xFFFFF lands in bits [31:12], the low bits are zeros. The result is exactly 0xFFFF_F000. A common mistake is assembling the address with addi — a 12-bit signed immediate cannot cover such a constant.

Step 2 — the golden program. Two periods on the x14 counter; inside a period the light x11 walks right with left shifts up to the 0x80 boundary and back with right shifts down to zero:

        lui  x10, 0xFFFFF   # 0:  LED base 0xFFFFF000
        addi x13, x0, 128   # 4:  0x80, stop boundary
        addi x14, x0, 2     # 8:  period counter
period: addi x11, x0, 1     # 12
        beq  x14, x0, halt  # 16
        addi x14, x14, -1   # 20
right:  sw   x11, 0(x10)    # 24
        slli x11, x11, 1    # 28
        bne  x11, x13, right# 32 → 24
        sw   x11, 0(x10)    # 36: 0x80
left:   srli x11, x11, 1    # 40
        beq  x11, x0, period# 44 → 12
        sw   x11, 0(x10)    # 48
        beq  x0, x0, left   # 52 → 40
halt:   .end                # 56

Step 3 — the checkpoint numbers. The run: 115 instructions = 115 cycles; the .end halt at PC = 56 adds no cycle. The MMIO trace holds 30 writes: 15 per period (eight to the right, the 0x80 write, six to the left), two periods; the final LED = 1. The final registers: x10 = 0xFFFF_F000, x11 = 1, x13 = 128, x14 = 0. Delays (a pause between steps) are a student variant on top of the golden: an inner counting loop. The golden has no delays — for a deterministic trace length.

Step 4 — the MMIO contract. Probes on the reference runner: lw from 0xFFFF_F000 — ERR_WRITEONLY_READ (err 7) with a frozen state; sw to 0xFFFF_F004 — ERR_READONLY_WRITE (err 6); a misaligned sw to 0xFFFF_F002 — ERR_DATA_ADDRESS_MISALIGNED (err 1), the multiple-of-4 check runs before the MMIO decode. Reading the switches works: lw x6, 4(x10) with the switches at 0x01 returns 1 (a byte in the low bits, the upper bits zero).

Step 5 — the ZIP. After passing, the export button validates your saved level-58 core (parse, structural checks, schematic build) and packs an archive: 28 .v core files, the program in rtl/ROM.v, a clock divider down to ≈3 Hz, a wrapper with the clk/top_sw/top_led ports, CST pins and a Gowin project. The bitstream is not part of the archive — build it in Gowin EDA yourself. After flashing, the same code runs on a physical chip.

Check yourself

Why is sw at 0xFFFF_F002 an alignment error rather than a write to the LED?

The multiple-of-4 check runs before the MMIO decode: a misaligned address is caught as ERR_DATA_ADDRESS_MISALIGNED before the circuit even looks at which peripheral it points to. There is no such thing as a half write.