Lotus Text

Originally a thought experiment inspired by Valve’s steam controller UI, LotusText is a demo ROM that experiments with alternative text input for the NES. Typically, text entry on vintage consoles uses slow, boring interfaces that require scrolling back and forth across the alphabet to type one letter at a time. LotusText instead maps each symbol to a button combination, making everything quickly accessible. Possible uses for homebrew include things like quiz games, text adventures, dynamic personalization, or password systems.

Download ROM

Though a runnable demo ROM is available, LotusText is intended to be usable as an embeddable library. This is a little tricky to do, as NES homebrew doesn’t have many tools for creating reusable code, but the source code of the ROM demonstrates typical usage.



On screen are 12 leaves, facing away from the center. On each leaf and in the center are three symbols, left, right and center. By pressing a direction on the d-pad the user highlights a leaf, using diagonal presses for diagonal leaves, and double taps for leaves far from the center. Once highlighted, the user can press B or A or both to pick a symbol to type. When B and/or A are released, the symbol is inserted. Start is used to confirm the inputted text.

Technical description

LotusText uses 3 of the 4 background palettes, and 1 of the 4 sprite palettes. The remaining palettes may be utilized by host programs to provide custom decoration. It only uses 2 sprites, and 14 bytes of zeropage RAM. CPU usage is low, requiring about ~160 cycles per frame and ~70 cycles in vblank.

Required assembler is ca65. Ports may be made in the future if demand exists. Graphics are compiled using makechr. Building is done using Make.

The main operations performed by LotusText are input smoothing and attribute changes. Leaves are highlighted based upon which direction is being pressed by the user, and the attributes used to highlight each leaf are decided from a pre-compiled metadata image. Changing this metadata requires python and PIL / Pillow.

Unit testing NES 6502 assembly using Common Lisp

As part of the NES homebrew development I’ve been working on, I wanted to have some way to unit test my code. Doing so provides peace of mind that code works, and also allows for future changes to made safely. This is particularly important for low-level assembly, where correctness and speed are both important, and attempts at optimization can easily break code. Not finding any pre-existing tools, I figured I could easily pull something together.

The first step was finding a 6502 / NES emulator that allowed programmatic inspection of state (memory / registers) from the command-line with minimal overhead. The project cl-6502 by redline6561 fit the bill, allowing tests to use Common Lisp code to setup state, run assembled code, and then make assertions on the final state.

Next, I needed to make a tiny framework to bridge between cl-6502’s features and how my NES code was organized. My project uses ca65 as its assembler, which is nice because it can assemble files separately, and also it matches the syntax of cl-6502’s assembler. On the other hand cl-6502, being quite minimalistic, doesn’t support directives, so we need to preprocess our source to filter these out. It also has a very granular interface, and we’d prefer something a little higher-level, at the level of subroutines.

Since it’s safe to assume most homebrew developers aren’t familiar with Common Lisp, I wanted to provide a very simple and obvious API for the unit tests. The result, nes_unit_testing.lisp, favors convention over configuration, making a number of assumptions about how subroutines are written. For example, unit test filenames match the assembly source except they end in “_test.lisp”. Also, the test framework starts executing at the very beginning of the source file, meaning only one subroutine can exist per file.

Provided is a simple calculator ROM, that enables the input of two numbers, and can add them together. As part of this, there’s a file convert_decimal.asm which contains a function to convert an integer into 3 decimal digits. This is the documentation of the subroutine:


; Given a number in A, convert it to three decimal digits, in Y, X, A.
; .reg:a @in  The number to convert.
; .reg:a @out The ones digit, 0-9.
; .reg:x @out The tens digit, 0-9.
; .reg:y @out The hundreds digit, 0-2.
.proc ConvertDecimal

Complete code is here.

And the complete test code, which verifies every possible 8-bit value, looks like this:


(in-package :nes-unit-testing)

(deftest convert-decimal-test
  (initialize-test-case :env `((remainder-mod8 :byte)))
  (loop for num from 0 upto 255
     do (run-test-case :a num)
        (expect-result :y (floor (/ num 100))
                       :x (mod (floor (/ num 10)) 10)
                       :a (mod num 10))))

Most of what’s happening here should be self-explanatory, but just in case, here’s a line by line breakdown.

Lines 1-3 set our package and start defining a test.

Line 4 initializes the test by parsing the source code, clearing ram, and defining variables our subroutine uses.

Line 5 performs a loop, iterating from 0 to 255, inclusive.

Line 6 assigns the number to the A register, then executes the subroutine.

Lines 7-9 verify that the Y register is set to the hundreds digit, the X register is set to the tens digit, and the A register is set to the ones digit.

Running the unit test is simple, once all the dependencies are installed. The included script ./run_tests.sh loads cl-6502, nes_unit_testing.lisp, and then runs all-tests-in-current-directory which loads every *_test.lisp script in the current directory and runs all the defined tests. Here’s what running the test looks like, with timing:

> time ./run_tests.sh

real 0m1.828s
user 0m1.468s
sys 0m0.249s

Even failures are pleasant. Removing line 57 from convert_decmal.asm (adc #$0a) breaks the code as shown:

> ./run_tests.sh
Failed on test: ((A 88))
A - Actual 254, Expect 8

Failed on test: ((A 89))
A - Actual 255, Expect 9

Failed on test: ((A 96))
A - Actual 252, Expect 6

Code for the calculator rom is on github here, and code for the unit testing framework is here.