Simple8

The Simple8 Environment

Before you write your first line of code, this chapter introduces the tools: what the compiler does, the machines it knows, its libraries, how to install and run it, and then how to set up Simple8 IDE.

1.1What Simple8 is

Simple8 is both a language and a compiler. The language looks like Java and C: blocks between braces, types (byte, int, uint…), functions, for and while loops. The compiler translates this code into native assembly for the chosen machine, assembles it, and produces the file you load into an emulator or onto the real machine: a PC Engine ROM, a Commodore 64 .prg, an Amiga floppy disk…

In its current version, Simple8 was designed for small 8-bit processors: the 6502 and its derivatives (HuC6280, 6510, 2A03), the Z80, and the Game Boy's SM83. Its types, its memory management and its generated code are tailored for machines that have few registers, a zero page and a few kilobytes of RAM. The 68000 machines are supported on an experimental basis (see the architectures).

A Simple8 program always states, on its first line, which machine it is written for:

architecture nec.pce;      // this program is for the PC Engine

Everything else follows from it: the target processor, how memory is organized, the available libraries and the format of the output file.

The complete environment is made of:

1.2How the compiler works

The compiler starts from the main file (main.s8p) and ends with a file ready to run. In between, the program goes through a chain of steps:

From Simple8 code to the machine: parsing, intermediate representation, optimization, assembly generation, assembling, then the ROM running in an emulator or on the machine Simple8 code main.s8p Lexer + parser Intermediate representation IR Optimizer dead code Assembly generation 6502 · Z80 SM83 · 68000 Built-in assembler ROM · PRG floppy disk Emulator or real machine
The mental model: from the source file to the machine.

In detail:

  1. ReadingThe main file, its libraries (addlib) and its units (addunit) are read and split into a syntax tree.
  2. AnalysisTypes, variables, scopes and function calls are checked; errors are reported with their line number.
  3. Intermediate representationThe program is rewritten as simple instructions that are still independent of the processor.
  4. Dead codeFunctions that are never called, including those in libraries, are discarded.
  5. GenerationThe processor's generator (6502, Z80, SM83, 68000) writes the assembly, then optimizes it.
  6. AssemblingThe built-in assembler produces the final file, the listings and the reports.

Everything happens in the same program: there is no external tool to install, neither an assembler nor a linker. The compiler writes its output into an asm/ folder, next to the compiled file:

FileContents
main.asmthe generated assembly, readable, with the code of the libraries used
main.lstthe listing: each instruction with its address and its bytes
main.symthe symbol table, read by debugging emulators
main_report.htmlthe compilation report: memory used, functions, discarded code
main.pce, main.prg…the program to run, in the machine's format

Reading the generated assembly is the best way to understand what a line of Simple8 costs. The following chapters will come back to it often.

When abstraction is not enough, the language lets you go down to the hardware level: an _asm { … } block inserts assembly in the middle of the code, and the compiler checks the instructions against the machine's processor.

1.3The architectures

An architecture designates a specific machine. Its name is written manufacturer.machine, and it is what follows the architecture keyword at the top of the program.

ArchitectureProcessorMachineOutput file
nec.pceHuC6280PC Engine / TurboGrafx-16.pce
nec.sgxHuC6280PC Engine SuperGrafX.pce and .sgx
commodore.c64MOS 6510Commodore 64.prg, .d64
nintendo.nesRicoh 2A03NES / Famicom.nes
mos.6502MOS 6502Generic 6502raw binary
amstrad.cpc6128Z80AAmstrad CPC 464 / 664 / 6128.bin, .dsk
zilog.z80Z80Generic Z80 (MSX, Master System, Spectrum).bin
nintendo.dmgSharp SM83Game Boy.gb
sega.megadrive68000Mega Drive / Genesis (experimental).md
commodore.amiga68000Amiga 500 PAL / OCS (experimental).adf (floppy disk)

The language is the same everywhere. What changes from one machine to another is the libraries (a PC Engine and an Amstrad CPC do not have the same hardware sprites), the available memory and the size of the numbers the processor handles effortlessly.

The 68000 architectures are experimental. Today, Simple8 is designed for 8-bit processors. The Mega Drive and the Amiga 500 work, but their support is still experimental: the language and the generated code do not yet take advantage of a 16/32-bit processor. A future version of Simple8 should improve development on the 68000.

motorola.68000, for its part, is recognized but produces no code: for the 68000, you choose a concrete machine, sega.megadrive or commodore.amiga.

1.4The libraries

Libraries are .s8l files, written in Simple8 (often with a bit of assembly). They are stored in the libs8/ folder, one branch per machine:

libs8/
├── nec/pce/              PC Engine
│   ├── boot/boot.asm     machine startup
│   ├── system/           the system library
│   ├── config.json       the machine's memory map
│   ├── vdc/              display: tiles, sprites, scrolling
│   ├── vce/              colors
│   ├── psg/              sound
│   └── io/               the joypad
├── commodore/c64/
├── nintendo/nes/
├── …
└── math/                 libraries shared by all machines

A program loads a library with addlib, followed by the folder and the file name, separated by a dot:

architecture nec.pce;

addlib vdc.base;      // libs8/nec/pce/vdc/base.s8l
addlib io.base;       // libs8/nec/pce/io/base.s8l

The compiler looks for the file in this order, and takes the first one it finds:

  1. the machine's folder: libs8/nec/pce/vdc/base.s8l;
  2. the shared libraries: libs8/vdc/base.s8l;
  3. your personal libraries, in the folder given by the S8_USER_LIBS variable;
  4. the project's libraries, in its userlibs/ folder.

Thanks to dead code elimination, loading a library costs nothing: only the functions that are actually called end up in the ROM.

1.5Installing Simple8

What you need

ToolWhat it is for
Java (JDK 21)building and running the compiler
Gitgetting the sources
Maven or Antbuilding the compiler

Getting and building the compiler

  1. Get the repository:

    git clone https://github.com/beddy70/Simple8.git
    cd Simple8
  2. Build the compiler, with either Ant or Maven:

    # Ant: the file is written to dist/
    ant compile jar
    
    # Maven: the file is written to target/, and the tests are run
    mvn package
  3. Check that it responds:

    java -jar dist/LitleCompilator.jar --help

Telling it where the libraries are

The compiler needs to know where the libs8/ folder is. The simplest way is to declare it once and for all in the S8_LIBS_PATH environment variable:

# macOS, Linux: add to ~/.zshrc or ~/.bashrc
export S8_LIBS_PATH=/chemin/vers/Simple8/libs8
export S8_USER_LIBS=~/mes_libs_simple8        # optional

# Windows
setx S8_LIBS_PATH C:\Simple8\libs8

Without S8_LIBS_PATH or the -l option, the compiler does not look for the libraries in the current folder: it cannot find them, and reports Library not found.

1.6Compiling from the command line

You run the compiler with Java, giving it the project's main file:

java -jar LitleCompilator.jar -f main.s8p
OptionEffect
-f, --file filethe .s8p file to compile (you can also give it on its own, without -f)
-l, --libs folderthe libs8/ folder; takes precedence over S8_LIBS_PATH
-d, --debugshows the internal steps: tree, intermediate representation, assembly
-h, --helphelp

Run the command from the project folder. The asm/ folder is created in the current folder: compiling from somewhere else would put the generated files there.

Trying an example

The repository contains example programs, sorted by machine in Examples/. To compile the first NES program:

cd Examples/nintendo/nes/HelloNES
java -jar ../../../../dist/LitleCompilator.jar -l ../../../../libs8 main.s8p

If all goes well, the compilation finishes without errors and the asm/ folder contains main.nes, a cartridge that runs directly in Mesen, FCEUX or Nestopia.

1.7Simple8 IDE

The command line is enough, but Simple8 IDE makes the work more comfortable: you write, compile and launch the emulator without leaving the application. Compilation errors are underlined in the code, and the generated assembly can be read in a neighboring tab.

Installing it

Ready-to-install versions coming soon. Compiled versions of Simple8 IDE for macOS, Windows and Linux will be available. An online version of the Simple8 suite that runs in a browser is also on the way. In the meantime, the IDE is built from source, as described below.

The IDE is built from the repository's ide/ folder. In addition to Java, it requires Rust (stable version) and Node.js 20 or later:

cd ide
npm install
npm run tauri build      # the application, ready to install
npm run tauri dev        # or: run the IDE directly from source

Opening a project

File → Open Project… (⌘O): choose the project's folder. The IDE then looks there for:

File → New Project… (⇧⌘N) asks for a name, an architecture and a folder, then creates a main.s8p ready to fill in.

On macOS, an application opened from the Finder or the Dock does not see the terminal's variables (S8_LIBS_PATH, S8_USER_LIBS). If you need them, launch the IDE from a terminal.

Essential shortcuts

ActionShortcut
Compile the main file⌘B
Compile, then run in the emulator⌘R
Open the generated assembly⌥⌘A
Open the listing⌥⌘L
Open the compilation report⌥⌘R
Configure the emulators⌘,

During compilation, the compiler's output scrolls in the Output tab. Errors and warnings are gathered in the Problems tab: a click opens the file at the offending line.

Git

Simple8 IDE also manages the project's Git repository, without going through the terminal. Everything is set up in Settings → Git…:

ActionShortcut
Commit all changes in the project (git commit)⇧⌘K
Push the branch to the chosen servers (git push)⇧⌘P

1.8Configuring the emulators

The ▶ Run button compiles the program and then, if the compilation succeeds, opens the output file in the chosen emulator. The list only shows the emulators compatible with the program's machine.

The IDE knows a default one for each machine:

MachineDefault emulatorOther supported choices
PC EngineGeargrafxares, Mednafen
SuperGrafXGeargrafxMednafen
Commodore 64VirtualC64VICE
Amstrad CPCCaprice32CPCemu
NESMesen
Game BoyGearboy
Mega Driveares
Amiga 500FS-UAE

The emulators themselves are installed separately. Then the Settings → Emulators… window (⌘,) shows for each one whether its executable was found (●) or not (○), and lets you choose its path and the default emulator for each machine.

The emulators.json file

To go further, the configuration is a JSON file, opened with Settings → Edit emulators.json. A project can also have its own simple8-emulators.json file, which overrides the general configuration entry by entry:

{
  "defaults": { "nec.pce": "ares-pce" },
  "emulators": {
    "ares-pce": {
      "name": "ares (PC Engine)",
      "command": "/Applications/ares.app/Contents/MacOS/ares",
      "args": ["--system", "PC Engine", "--no-file-prompt", "${rom}"],
      "architectures": ["nec.pce"],
      "rom": "${asmDir}/${name}.pce"
    }
  }
}
VariableValue
${projectDir}the folder of the compiled file
${name}its name, without the extension
${asmDir}the project's asm/ folder
${rom}the file to run
${sym}the symbol table, for debugging emulators

1.9How a project is organized

A Simple8 project is just a folder:

MonJeu/
├── main.s8p                  the main program
├── Joueur.s8u                other units, added with addunit (optional)
├── userlibs/                 libraries specific to the project (optional)
├── simple8-emulators.json    the project's emulators (optional)
└── asm/                      created by the compiler
ExtensionRole
.s8pthe program: it declares the architecture and contains the main unit, with main()
.s8ua unit in its own file, to split up a growing program
.s8la library, loaded with addlib

The asm/ folder is fully regenerated on every compilation: you can delete it safely, and it does not need to be kept in Git (the IDE's .gitignore template excludes it).

The environment is ready. In the next chapter, you will write your first program.