Description of the page content
Disassembling of SamForth.
Project developed from 2012-12-22 to 2013-06.
The goal of this disassembling project was to reuse the code of SamForth as the base of a new Forth for the SAM Coupé, focused on cross development with SimCoupe. That was the unfinished project ForthCoupe.
- Word headers.
- SamForth internal variables.
- Data zones: data stack, return stack, TIB and pad.
- RST calls and their vectors.
- Main routines.
- Addon routines.
- Investigate and label the remaining routines.
- Document the memory paging.
- Document the SAM BASIC file interface.
Among several Z80 disassemblers available for GNU/Linux, I choosed z80dasm (version 1.1.3).
Unfortunately, z80dasm doesn't provide a way to mark
defs blocks. It also creates one comment and two bound symbols for every defined block, what sometimes is inconvenient. The assembler also converts literal numbers to address labels when their values are equal. That had to be fixed. Beside those issues, other specific changes were required in the final source. In order to solve all issues get a tidy and definitive Z80 source, a post-processing tool was written in the Vim language: z80dasm2tidySamForth.
A shell wrapper is provided in the download section. It calls all tools step by step with the requried arguments.
SamForth[-A] and SamForth-B
There are two versions of SamForth:
- SamForth runs at 0000h and pages the ROM in when needed.
- SamForth-B runs at 4000h with the ROM paged in.
There are more details about both SamForth versions in the SamForth documentation.
Reverse engineered information
SamForth word headers
- 2 bytes: Name Link Address: the address of previous word name in the dictionary.
- 1 byte: bits 0-5 are the word name length (so the maximum word length is 63 characters); bit 6 is the precedence bit; bit 7 is the compile-only bit.
- n bytes: the word name, pointed by the name link address of the next word in the dictionary.
- Code Field Address: the Z80 code, finished by
retor a jump to a subroutine.
SamForth is a STC (Subroutine Threaded Code) Forth (see a detailed description on threading techniques by Brad Rodriguez). Thus the Z80 return stack is used as Forth return stack. This has the advantage the inner Forth interpreter is much simpler and Z80 code can be more easily mixed with Forth code.
The data stack is managed with routines (SamForth-A uses
rst calls). In both SamForth variants the data stack code is identical and at first sight it's quite heavy, because a copy of SP is restored just to do the task and then saved back. A more usual aproach would be to use a Z80 register as data stack pointer, but some timings revealed that the John Avis' original code is already the fastest option.
SamForth uses the Z80 return stack as Forth return stack.
The Forth data stack's bounds and pointer are kept in the SamForth variables:
SP. The data stack is manipulated with the Z80 stack commands, but first the Z80's
SP is copied into the SamForth's
RSTACK variable, and restored at the end.
YI register points to SamForth's
DE are used to pop from and push to the data stack.
There's a variables list included in the documentation, but some descriptions are vague.
For example, the
FLAGS variable holds several control bits. In SamForth-A bits 1, 5 and 7 of
FLAGS are used; in SamForth-B only bits 1 and 7 are used. The meaning of the bits will be finally discovered when the last routines will be understood.
Both BASIC loaders poke two short routines at 50000 (0c350h) and 50020 (c364h). The first one is used to start SamForth from BASIC. The last one is identical in both versions
SamForth-A also loads a third routine from disk, at 50040.
- dasm_samforth.sh (3.41 KiB), a simple wrapper for the whole process.
- samforth2z80dasm.fs (48.10 KiB), the SamForth2z80dasm tool.
- samforth2z80dasm.fs.gz (12.17 KiB), the SamForth2z80dasm tool, gzipped.
- z80dasm2tidysamforth.vim (34.25 KiB), the z80dasm2tidySamForth tool.
- samforth-a.bin (16.00 KiB), the SamForth-A binary code.
- samforth-a.bin_blocks.txt (24.40 KiB), its blocks file, required by z80dasm and created by SamForth2z80dasm.
- samforth-a.bin_symbols.z80s (25.59 KiB), its symbols file, required by z80dasm and created by SamForth2z80dasm.
- samforth-a.z80s.gz (15.91 KiB), the SamForth-A disassembled code.
- samforth-a_50000.z80s (687 B), the SamForth-A routines at 50000 and 50020, disassembled.
- samforth-a_50040.z80s (3.25 KiB), the SamForth-A routine at 50040, disassembled.
- samforth-b.bin (16.00 KiB), the SamForth-B binary code.
- samforth-b.bin_blocks.txt (26.52 KiB), its blocks file, required by z80dasm and created by SamForth2z80dasm.
- samforth-b.bin_symbols.z80s (25.79 KiB), its symbols file, required by z80dasm and created by SamForth2z80dasm.
- samforth-b.z80s.gz (15.81 KiB), the SamForth-B disassembled code.
- samforth-b_50000.z80s (657 B), the SamForth-B routines at 50000 and 50020, disassembled.
Original SamForth by John Avis (1991), ready to be used on SimCoupe:
- SamForth.mgt.gz (29.09 KiB), SamForth disk image.
- SamForthDocs.mgt.gz (26.90 KiB), disk image with the original SamForth documentation.