A library for developing Pokemon Mini homebrew in Nelua, targeting the Epson S1C88 8-bit CPU. Nelua source compiles to C89 via an intermediate conversion step, then builds into a .min ROM using the TASKING E0C88 toolchain.
- TASKING E0C88 Toolchain: Install via c88-pokemini:
cd C:\Users\your-user\c88-pokemini .\install.ps1
- Nelua: nelua.io
- PokeMini Emulator
Build and run an example from its directory:
cd examples\demo
.\build.ps1 # Build ROM
.\build.ps1 run # Build and run in emulatorOr build any source file directly from the project root:
.\tools\build.ps1 -Source examples\text\main.nelua
.\tools\build.ps1 run -Source examples\sqaure\main.neluaThe output ROM is written to build\<name>.min.
Build targets:
| Target | Description |
|---|---|
all |
Full build (default) |
run |
Build and launch in emulator |
clean |
Remove build artifacts |
rebuild |
Clean, then full build |
src/
pmhw.nelua Hardware abstraction layer (the library)
examples/
sqaure/
main.nelua Example application
tools/
build.ps1 Build script
c99_to_c89.ps1 C99 to C89 converter for TASKING cc88
toolchain/
crt0.asm Startup assembly (vectors, ROM header)
pokemini.dsc TASKING software description
s1c88_pokemini.cpu TASKING CPU description
s1c88.mem TASKING memory description
neluacfg.lua Nelua compiler configuration
The build process chains several tools:
- nelua -- Compile Nelua source to C99
- c99_to_c89.ps1 -- Convert C99 to C89 (TASKING cc88 only supports C89)
- as88 -- Assemble startup code (
crt0.asm) - cc88 -- Compile C89 to object files
- lk88 -- Link objects with the TASKING runtime library
- lc88 -- Locate code/data at target memory addresses
- srec_cat -- Convert S-record output to binary ROM
The hardware abstraction layer (src/pmhw.nelua) provides:
| Function | Description |
|---|---|
init_hw() |
Initialize hardware (clock, PRC, framebuffer) |
clear_screen() |
Clear the framebuffer |
fill_screen(pattern) |
Fill framebuffer with a byte pattern |
set_pixel(x, y, color) |
Set a single pixel (bounds-checked) |
get_pixel(x, y) |
Read a single pixel |
flip_buffer() |
Trigger LCD refresh from GDDRAM |
wait_vsync() |
Block until PRC frame complete |
| Function | Description |
|---|---|
draw_hline(x, y, w, color) |
Horizontal line |
draw_vline(x, y, h, color) |
Vertical line |
draw_rect(x, y, w, h, color) |
Rectangle outline |
fill_rect(x, y, w, h, color) |
Filled rectangle |
| Function | Description |
|---|---|
poll_input() |
Returns bitmask of pressed keys |
Key constants: KEY_A, KEY_B, KEY_C, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_POWER.
Two fixed-point types are provided for arithmetic without floating point:
- Fixed8_8 -- 8.8 format (8 integer bits, 8 fractional bits). Supports add, sub, mul, div, comparison.
- Fixed12_4 -- 12.4 format (12 integer bits, 4 fractional bits). Supports add, sub, mul.
Create a new .nelua file (or modify examples/demo/main.nelua):
## pragma{nogc = true, nochecks = true}
require 'pmhw'
local function main(): void <entrypoint>
init_hw()
clear_screen()
fill_rect(10, 10, 20, 20, 1)
while true do
wait_vsync()
end
endUpdate the $NeluaSource path in tools/build.ps1 to point to your file, then run the build.
- No garbage collector. All Nelua files must include
## pragma{nogc = true}. - No static initializers. The
__copytableroutine is stubbed. Initialize data at runtime. - C89 target. The TASKING cc88 compiler does not support C99. The converter script handles the translation automatically.
- 16-bit int. The S1C88 has 16-bit
intand 32-bitlong.
| Address | Size | Description |
|---|---|---|
| 0x0000--0x0FFF | 4 KB | BIOS (reserved) |
| 0x1000--0x12FF | 768 B | GDDRAM (framebuffer, 96x64 1bpp) |
| 0x1300--0x1FFF | 3.25 KB | General-purpose RAM |
| 0x2000--0x20FF | 256 B | I/O registers |
| 0x2100+ | up to 2 MB | Cartridge ROM |
The TASKING as88 assembler uses different mnemonics than standard S1C88 documentation:
| TASKING | Standard S1C88 | Description |
|---|---|---|
LD |
MOV |
Load/move |
CARL |
CALL |
Call (relative long) |
JRL |
JMP |
Jump (relative long) |
RETE |
RETI |
Return from interrupt |
MIT