514 lines
16 KiB
Text
514 lines
16 KiB
Text
== Getting Started
|
|
|
|
=== Setting Up the Toolchains
|
|
|
|
JoeyLib cross-compiles for five machines. It builds on Linux x86-64, and on
|
|
Windows inside WSL2. One script installs every cross toolchain, pinned to a
|
|
known-good version and checked against a published checksum, into
|
|
`toolchains/` in the repository. The only things it installs anywhere else
|
|
are ordinary packages from your distribution (apt on Debian and Ubuntu, dnf
|
|
on Fedora), and only when you ask it to.
|
|
|
|
Two commands set up a new machine:
|
|
|
|
[source,console]
|
|
----
|
|
$ ./install.sh deps toolchains --install
|
|
$ ./install.sh install toolchains
|
|
----
|
|
|
|
The first installs the distribution packages the toolchains need; it runs
|
|
`sudo` once. The second downloads or builds every cross toolchain. The first
|
|
run takes about an hour, almost all of it compiling the Apple IIgs and Amiga
|
|
compilers. To start working sooner, install only the ports you need:
|
|
|
|
[source,console]
|
|
----
|
|
$ ./install.sh install toolchain:dos toolchain:atarist
|
|
----
|
|
|
|
Running `install` again is cheap. Components that are already current are
|
|
skipped, and a component is rebuilt only when its pinned version changes.
|
|
|
|
No environment setup is needed afterwards. `make` reads the tool paths the
|
|
installer records in `toolchains/config.mk`, and the scripts in
|
|
`scripts/` load the same settings themselves. To use a cross compiler by hand
|
|
in a shell, `source toolchains/env.sh` sets the same variables.
|
|
|
|
If a port's toolchain is missing, its build stops at once and says what to
|
|
install:
|
|
|
|
[source,console]
|
|
----
|
|
$ make amiga
|
|
make/amiga.mk:5: *** toolchain:amiga is not installed; run: ./install.sh install toolchain:amiga. Stop.
|
|
----
|
|
|
|
Check what the build can see:
|
|
|
|
[source,console]
|
|
----
|
|
$ make status
|
|
Toolchain availability:
|
|
iigs: yes
|
|
amiga: yes
|
|
atarist: yes
|
|
dos: yes
|
|
x68000: yes
|
|
----
|
|
|
|
==== Installer reference
|
|
|
|
`./install.sh [options] COMMAND [TARGETS...]`, run from the top of the
|
|
repository.
|
|
|
|
[cols="1,3"]
|
|
|===
|
|
| Command | What it does
|
|
|
|
| `list`
|
|
| Every component, the groups it belongs to, and whether it is current,
|
|
outdated or missing.
|
|
|
|
| `install TARGETS`
|
|
| Installs or updates the targets and everything they depend on, and
|
|
smoke-tests each one it installs. A failure does not stop the rest; the
|
|
failures are listed at the end.
|
|
|
|
| `deps TARGETS`
|
|
| Lists the distribution packages the targets need and which are missing.
|
|
With `--install`, installs the missing ones.
|
|
|
|
| `doctor`
|
|
| Checks the host, then smoke-tests every installed component (each cross
|
|
compiler compiles a file, and every prebuilt program must find its shared
|
|
libraries, for example). It reports anything out of date, any component
|
|
whose files have gone, and any part of a port you installed only partly,
|
|
such as FS-UAE without a Kickstart.
|
|
|
|
| `import PATH...`
|
|
| Installs the files that are not downloaded (see <<Firmware that is not
|
|
downloaded>>) from files, folders, `.zip` archives or Amiga `.adf` disk
|
|
images, matched by checksum.
|
|
|
|
| `bundle FILE`
|
|
| Packs those files, as present on this machine, into `FILE` (a `.tar.gz`)
|
|
for a project to host.
|
|
|===
|
|
|
|
A target is a component name from `list`, or a group:
|
|
|
|
[cols="1,3"]
|
|
|===
|
|
| Target | Means
|
|
|
|
| `toolchain:PORT`
|
|
| Everything needed to build for one port: `iigs`, `amiga`, `atarist`, `dos`
|
|
or `x68000`.
|
|
|
|
| `emulator:PORT`
|
|
| Everything needed to run that port's programs: the emulator and its
|
|
firmware.
|
|
|
|
| `PORT`
|
|
| Both of the above.
|
|
|
|
| `toolchains`
|
|
| Every port's toolchain.
|
|
|
|
| `emulators`
|
|
| Every port's emulator.
|
|
|
|
| `all`
|
|
| Everything except optional components (such as `staxiData`, Space Taxi's
|
|
level source), which are installed by name.
|
|
|===
|
|
|
|
[cols="1,3"]
|
|
|===
|
|
| Option | Effect
|
|
|
|
| `-y`, `--yes`
|
|
| Install missing distribution packages without stopping to ask.
|
|
|
|
| `--install`
|
|
| With `deps`: install the missing packages.
|
|
|
|
| `--force`
|
|
| Reinstall components even when they are current.
|
|
|
|
| `--jobs N`
|
|
| Parallel build jobs. The default is every core.
|
|
|
|
| `--keep-build`
|
|
| Keep the scratch build trees (normally deleted after a successful install).
|
|
|
|
| `--llvm816-dir PATH`
|
|
| Use an existing checkout of llvm816, the IIgs compiler, instead of cloning
|
|
it. For working on the compiler and JoeyLib together. The setting is
|
|
remembered; `--llvm816-dir clone` goes back to a managed clone.
|
|
|===
|
|
|
|
Everything the installer creates stays inside `toolchains/`:
|
|
|
|
[cols="1,3"]
|
|
|===
|
|
| Path | Contents
|
|
|
|
| `toolchains/opt/`
|
|
| The installed components, one directory each.
|
|
|
|
| `toolchains/firmware/`
|
|
| ROM and system-disk images for the emulators.
|
|
|
|
| `toolchains/cache/`
|
|
| Downloads, kept and re-verified by checksum on reuse, and scratch build
|
|
trees.
|
|
|
|
| `toolchains/state/`
|
|
| Which version of each component is installed, and settings such as
|
|
`--llvm816-dir`.
|
|
|
|
| `toolchains/config.mk`, `toolchains/env.sh`
|
|
| The tool paths, for `make` and for shells.
|
|
|===
|
|
|
|
Nothing in `toolchains/` is part of the repository: delete the whole folder
|
|
to return the machine to a clean state, and `./install.sh` re-creates it. The
|
|
installer itself lives in `install.sh` and `installer/` (its component
|
|
recipes, patches and package lists), and the build helpers the makefiles call
|
|
live in `make/support/`.
|
|
|
|
=== Building
|
|
|
|
[source,console]
|
|
----
|
|
$ make # every target whose toolchain is installed
|
|
$ make iigs # Apple IIgs only
|
|
$ make amiga # Commodore Amiga only
|
|
$ make atarist # Atari ST only
|
|
$ make dos # MS-DOS only
|
|
$ make x68000 # Sharp X68000 only
|
|
$ make clean # remove all build outputs
|
|
----
|
|
|
|
Built programs land under `build/<platform>/bin/`. The IIgs additionally
|
|
produces a bootable disk image:
|
|
|
|
[source,console]
|
|
----
|
|
$ make iigs-disk # build/iigs/bin/joey.2mg
|
|
----
|
|
|
|
Space Taxi's levels come from the original Commodore 64 game, which is not
|
|
part of the repository. Without `stuff/spacetaxi/raw.bin` the build still
|
|
compiles the STAXI program, skips only its data files, and says so:
|
|
|
|
[source,console]
|
|
----
|
|
note: Space Taxi data skipped: stuff/spacetaxi/raw.bin is not present
|
|
----
|
|
|
|
[TIP]
|
|
====
|
|
Never judge a retro build by its exit status alone. Check that the file you
|
|
expect actually appeared and has a recent timestamp. `make iigs` builds the
|
|
library but *no examples* -- `make iigs-disk` is what builds and packages them.
|
|
====
|
|
|
|
=== Hello, JoeyLib
|
|
|
|
The smallest complete program. This is `examples/hello/hello.c`:
|
|
|
|
[source,c]
|
|
----
|
|
#include <stdio.h>
|
|
#include <joey/joey.h>
|
|
|
|
int main(void) {
|
|
jlConfigT config;
|
|
|
|
config.codegenBytes = 8 * 1024;
|
|
|
|
if (!jlInit(&config)) {
|
|
fprintf(stderr, "jlInit failed: %s\n", jlLastError());
|
|
return 1;
|
|
}
|
|
|
|
printf("JoeyLib %s\n", jlVersionString());
|
|
printf("Platform: %s\n", jlPlatformName());
|
|
printf("Hello from JoeyLib.\n");
|
|
|
|
jlShutdown();
|
|
return 0;
|
|
}
|
|
----
|
|
|
|
Three things to notice, because they apply to every JoeyLib program:
|
|
|
|
. *One header.* `#include <joey/joey.h>` pulls in everything except the
|
|
optional serial add-on.
|
|
. *`jlInit` can fail*, and when it does `jlLastError()` tells you why. Always
|
|
check it.
|
|
. *`jlShutdown` is not optional.* It restores the display mode, releases the
|
|
Memory Manager blocks or DOS memory the library took, and on several ports
|
|
un-hooks interrupt vectors. Skipping it can leave the machine in an unusable
|
|
state.
|
|
|
|
=== Something on the Screen
|
|
|
|
`hello.c` prints text but never draws. Here is the smallest program that puts
|
|
graphics on screen and waits for a keypress:
|
|
|
|
[source,c]
|
|
----
|
|
#include <joey/joey.h>
|
|
|
|
int main(void) {
|
|
jlConfigT config;
|
|
jlSurfaceT *stage;
|
|
uint16_t colors[SURFACE_COLORS_PER_PALETTE];
|
|
uint8_t i;
|
|
|
|
config.codegenBytes = 8 * 1024;
|
|
if (!jlInit(&config)) {
|
|
return 1;
|
|
}
|
|
|
|
stage = jlStageGet(); // the library-owned back buffer
|
|
|
|
// Build palette 0. Entry 0 is forced black whatever we put here.
|
|
for (i = 0; i < SURFACE_COLORS_PER_PALETTE; i++) {
|
|
colors[i] = 0x000;
|
|
}
|
|
colors[1] = 0xFFF; // white
|
|
colors[2] = 0xF00; // red
|
|
colors[3] = 0x00F; // blue
|
|
jlPaletteSet(stage, 0, colors);
|
|
|
|
// Every scanline uses palette 0 (this is also the default).
|
|
jlScbSetRange(stage, 0, SURFACE_HEIGHT - 1, 0);
|
|
|
|
jlSurfaceClear(stage, 0);
|
|
jlFillRect(stage, 40, 30, 240, 140, 3);
|
|
jlDrawRect(stage, 40, 30, 240, 140, 1);
|
|
jlDrawLine(stage, 0, 0, SURFACE_WIDTH - 1, SURFACE_HEIGHT - 1, 2);
|
|
|
|
jlStagePresent(); // nothing is visible until this runs
|
|
jlWaitForAnyKey();
|
|
|
|
jlShutdown();
|
|
return 0;
|
|
}
|
|
----
|
|
|
|
The critical line is `jlStagePresent()`. All drawing goes to an off-screen
|
|
back buffer called the *stage*; nothing reaches the display until you present.
|
|
|
|
=== Running What You Built
|
|
|
|
`joey-run`, at the top of the repository, starts a built program in the right
|
|
emulator. The emulators, and the firmware they boot, come from the installer:
|
|
|
|
[source,console]
|
|
----
|
|
$ ./install.sh install emulators # every machine
|
|
$ ./install.sh install emulator:dos # or just one
|
|
----
|
|
|
|
MAME (for the IIgs and X68000) is always built from source, because the test
|
|
gates need JoeyLib's patches to it. DOSBox Staging is upstream's own Linux
|
|
release. Hatari and FS-UAE are distribution packages on Debian and Ubuntu;
|
|
Fedora does not ship the versions the gates expect, so there the installer
|
|
builds both from source.
|
|
|
|
Point `joey-run` at a program, or name an example together with `--port`:
|
|
|
|
[source,console]
|
|
----
|
|
$ ./joey-run build/dos/bin/DRAW.EXE
|
|
$ ./joey-run build/amiga/bin/Draw
|
|
$ ./joey-run --port atarist draw
|
|
$ ./joey-run build/iigs/bin/STAXI.2mg
|
|
----
|
|
|
|
It recognises the machine from the file itself. Interactive runs use the
|
|
program's own folder or disk image, so saves and logs persist from one run to
|
|
the next. Nothing is written to your home directory.
|
|
|
|
[cols="1,3"]
|
|
|===
|
|
| Option | Effect
|
|
|
|
| `--port PORT`
|
|
| The machine, when naming an example rather than a file.
|
|
|
|
| `--data DIR`
|
|
| Copy `DIR`'s files into the program's `DATA` folder for this run, for
|
|
example an AGI game's files.
|
|
|
|
| `--headless`
|
|
| No window and no sound, for scripts and continuous integration. Stops after
|
|
60 seconds unless `--seconds` says otherwise.
|
|
|
|
| `--seconds N`
|
|
| Stop after `N` seconds.
|
|
|
|
| `--snapshot FILE`
|
|
| Save a PNG of the screen when the run stops.
|
|
|
|
| `--machine rom01`
|
|
| Apple IIgs: the ROM 01 machine instead of ROM 03.
|
|
|
|
| `--ram SIZE`
|
|
| Apple IIgs: MAME's memory size. The default is `4M`; AGI wants `8M`.
|
|
|
|
| `--debug`
|
|
| Apple IIgs and X68000: start MAME's debugger.
|
|
|
|
| `--serial HOST:PORT`
|
|
| Connect the machine's serial port to the TCP server at `HOST:PORT`. See
|
|
<<Serial Ports>>.
|
|
|
|
| `--serial-listen PORT`
|
|
| The machine's serial port waits for a TCP connection on `PORT` instead.
|
|
|
|
| `--serial-baud N`
|
|
| Apple IIgs and X68000: the rate MAME's end of the wire runs at. The
|
|
default is 9600.
|
|
|
|
| `-- ARGS`
|
|
| Pass `ARGS` to the program. DOS only: the other machines' autostart cannot
|
|
pass arguments.
|
|
|===
|
|
|
|
A headless run with a snapshot is the quickest way to check a change:
|
|
|
|
[source,console]
|
|
----
|
|
$ ./joey-run --headless --seconds 30 --snapshot draw.png --port dos draw
|
|
----
|
|
|
|
==== The Apple IIgs
|
|
|
|
The IIgs runs programs from disk images. `make -f make/iigs.mk iigs-game-disk
|
|
GAME=DRAW` builds a bootable one, `build/iigs/bin/DRAW.2mg`, which is also how
|
|
a game ships. Given a data disk instead, such as `joey.2mg`, `joey-run` boots
|
|
GS/OS beside it and you open the program in the Finder. Given a bare program,
|
|
`build/iigs/bin/DRAW`, it builds both disks itself, which needs the IIgs
|
|
toolchain.
|
|
|
|
==== Serial Ports
|
|
|
|
`--serial HOST:PORT` plugs the emulated machine's serial port into a TCP
|
|
connection: to a BBS, a program of your own, `nc -l PORT`, or another
|
|
`joey-run` started with `--serial-listen PORT`, which waits for the
|
|
connection instead. `HOST` is a name or an IPv4 address, and a listening
|
|
port accepts connections on every network interface. The link carries raw
|
|
bytes, with no telnet negotiation. `examples/sertest` sends a banner and then
|
|
echoes whatever it receives, which makes it a quick test of a link:
|
|
|
|
[source,console]
|
|
----
|
|
$ nc -l 2323 # in one terminal
|
|
$ ./joey-run --serial localhost:2323 --port dos sertest
|
|
----
|
|
|
|
The port is each machine's usual one:
|
|
|
|
[cols="1,2,3",options="header"]
|
|
|===
|
|
| Machine | Port | How the link is made
|
|
|
|
| Apple IIgs
|
|
| The modem port
|
|
| MAME connects by itself. To listen, `socat` holds the TCP port and MAME
|
|
connects to it. The printer port and a Super Serial Card are not connected.
|
|
|
|
| X68000
|
|
| The RS-232C port
|
|
| As on the IIgs.
|
|
|
|
| Atari ST
|
|
| The Modem port
|
|
| Hatari's serial port can only be a device, so `socat` joins a
|
|
pseudo-terminal to the network both ways.
|
|
|
|
| Amiga
|
|
| `serial.device` unit 0
|
|
| FS-UAE listens by itself, and holds the whole machine until the connection
|
|
arrives. To connect out, `socat` joins a pseudo-terminal to the network.
|
|
|
|
| DOS
|
|
| COM1
|
|
| DOSBox does both by itself.
|
|
|===
|
|
|
|
`socat` comes from your distribution: `./install.sh deps host --install`
|
|
fetches it with the other host tools, and `joey-run` says so when a run needs
|
|
it and it is missing.
|
|
|
|
A few differences are worth knowing:
|
|
|
|
* On the IIgs and X68000 MAME's null modem clocks the wire, at 9600 baud,
|
|
8N1, unless `--serial-baud` says otherwise. A program that opens the port at
|
|
another rate receives garbage. The other emulators pass bytes at whatever
|
|
rate the program sets.
|
|
* When nothing answers at `HOST:PORT`, `joey-run` stops, except on the IIgs
|
|
and X68000, where MAME prints `Unable to load image` and runs with the port
|
|
unplugged.
|
|
* While a port is listening, what the program sends waits for the connection,
|
|
except on DOS, which drops it just as a cable with nothing on the other end
|
|
would. `examples/sertest` sends its banner at once, so on DOS a client that
|
|
connects late sees only the echo.
|
|
|
|
==== Firmware that is not downloaded
|
|
|
|
Almost everything the emulators need is downloaded: EmuTOS for the Atari ST,
|
|
the Apple IIgs ROMs, GS/OS 6.0.4 and the CFFA2 card's firmware, and Sharp's own
|
|
free release of the X68000 IPL-ROM and Human68k 3.02. Four files are not,
|
|
because they were never released for free: the Amiga Kickstart 3.1 ROM, the
|
|
Amiga `serial.device` from Workbench 3.1 (Kickstart 3.1 has none in ROM, and
|
|
a program cannot open the serial port without it), the X68000 CG (font) ROM,
|
|
and the memory image of the original Space Taxi that its levels are extracted
|
|
from. Supply your copies once:
|
|
|
|
[source,console]
|
|
----
|
|
$ ./install.sh import ~/my-roms
|
|
----
|
|
|
|
`import` takes files, folders, `.zip` archives and Amiga `.adf` disk images
|
|
(point it at your Workbench 3.1 disk for `serial.device`), identifies each
|
|
file by its checksum (the list is `installer/files.sha1`) and puts it in
|
|
place.
|
|
|
|
A project that hands its setup to testers can host these files instead:
|
|
`./install.sh bundle joeylib-private.tar.gz` packs the ones present on
|
|
a machine that has them, and setting `JOEY_BUNDLE_URL` to where it is hosted,
|
|
in `installer/bundle.conf`, makes every `install` fetch it automatically.
|
|
|
|
=== The Example Programs
|
|
|
|
The `examples/` directory is the best available reference, and every example is
|
|
built for every platform:
|
|
|
|
[cols="1,4", options="header"]
|
|
|===
|
|
|Example |What it shows
|
|
|
|
|`hello` |Minimal init, version query, shutdown.
|
|
|`draw` |Every drawing primitive, laid out in four quadrants.
|
|
|`pattern` |Palette and per-scanline palette (SCB) work.
|
|
|`keys` |Typed-character input and the key predicates.
|
|
|`joy` |Joystick axes, buttons and recalibration.
|
|
|`sprite` |Sprite loading, compiling, save-under and restore.
|
|
|`audio` |Tracker music, `.MOD` playback and digital sound effects.
|
|
|`save` |Save files and the disk-space query.
|
|
|`tilebank` |Loading a baked tile bank both ways, and a bank for another machine refused.
|
|
|`serial` |The optional RS-232 add-on.
|
|
|`adventure` |A small complete game.
|
|
|`agi` |A Sierra AGI interpreter, showing the library under real load.
|
|
|`spacetaxi` |A full port of Space Taxi: the largest example.
|
|
|`uber` |The validation and benchmark harness.
|
|
|===
|