The Hugi Compo (short for "competition") was a size coding competition to see who could code the smallest executable, but still complete the task at hand and pass the test suite.
The long-running competition was hosted by a team of programmers who challenged participants with common (and not so common) tasks. I participated in Hugo Compo first as a competitor, and later as a tester and host of the results. It was someone on this team who suggested that we do something different -- create an emulator for a fictious CPU we called the "Spew processor" that 4k of memory accessed with 12 bits, 4 registers, and 18 instructions. The goal of the Spew Compo, Compo #9 was to see who could code the smallest executable to emulate the Spew CPU given a number of Spew image files.
The winner (and usually one of the top scoring competitors) had an executable entry size of 179 bytes. My entry was 15 out of 21, not as good, but still a respectable 261 bytes. In this article, I present my entry to the competition. The source code for my entry, the SPEW assembler, source code, debugger, and detailed information here. The results of this competition and 25 others along with complete rules, examples, test suites, and source code to each competitors entry for each competition are available here.
The Spew CPU only had 4k of RAM, and was set up with specific areas and values; see Table 1.
Address |
Description |
000..0FF |
Pre-set to values 00..FF (after boot-up) |
100..EFF |
Code/Data area |
F00 |
"A" (accumulator) register |
F01 |
"Status" register |
F02..F03 |
"STK" register (16-bit stack pointer) |
F04..F05 |
"PC" register (16-bit instruction pointer) |
F06..FFF |
Default stack space |
The first 256 bytes of the 4k image are set to values from 0 to 255 respectively. This is done at boot time. These values aren't used for anything other than to make the emulator more involved for the competition. It has little or no effect on the actual SPEW CPU.
The memory area from 0x100 to 0xEFF is used for code and data. This is the area where the actual binary code and data is loaded to and executed.
The byte at 0xF00 is the accumulator register. This is a byte wide general-purpose register.
The byte at 0xF01 is the status register. It is almost identical to the lower byte of the 80x86 flags register, with a small difference; the overflow flag is moved to bit 3 in the spew status register (see Figure 1).
The word at 0xF02 is the stack register.
The word at 0xF04 is the current instruction pointer register.
The memory area from 0xF06 to 0xFFF is the default stack space.
Even though the stack pointer and instruction pointer fields are 16 bits each, only the lower 12 bits are used for memory access. The values in these fields should remain 16-bit values, but when the actual memory access is made, the high nibble should be ignored.
The default stack location is simply that, default. The loader (the host) will only load your data and code to offset 0x100 through 0xEFF. However, the memory from 0x000 to 0x0FF and the memory currently allocated for the default stack can be used however you like. You may place a value in the STACK register to use a different stack.
The stack space, memory from 0xF06 to 0xFFF, is not cleared at load time, so technically, you could place code and data in the image file at this location as long as you changed the stack register to point somewhere else before you used the stack. This process was never discussed enough to rule out using the default stack space as code and data too. Therefore, if you need more memory than the area from 0x100 to 0xEFF allows, simply use the area from 0x100 to 0xFFF making sure you do not overwrite the four system registers. Then as one of the first things you do, point the stack pointer to use the memory area 0x000 to 0x0FF. This frees up about 250 bytes for code and data.