Presenting zealasm: a Z80 assembler entirely written in Z80 assembly, for Zeal 8-bit OS
The goal of zealasm is to provide a way to assemble Z80 code directly in Zeal 8-bit OS, without the need for another computer.
zealasm is still in alpha, here are the features implemented:
- Less than 6KB of code once compiled!
- Use Zeal 8-bit OS API for file reading and writing, so completely portable
- Support
ORG
to relocate the final binary - Support a final binary up to 40KB
- Support labels up to 16 characters, forward usage before declaration supported
- Support all official instructions from Z80 User Manual
- Support directives:
dm
,ds
,db
,dw
- Support comments starting with
;
- Support upper or lower case instructions and operands
Regarding the current limitations:
- Doesn't support memory paging, so the maximum output file size is limited by the amount of RAM mapped at once: around 40KB
- No support for macros/defines
- No support for constant calculation (
label1
-label2
)
At the moment, the project has only been assembled on Linux (Ubuntu 20.04 and 22.04), it should be compatible with Mac OS and Windows as long as you have:
- bash
- git (to clone this repo)
- make
- Zeal 8-bit OS source code. Only the
kernel_headers
directory is required - z88dk v2.2 (or later). Only its assembler,
z80asm
, is strictly required. The latest version ofz80asm
must be used as earlier versions don't have support forMACRO
.
To install z88dk, please check out their Github project.
To build the program, define the path to Zeal 8-bit OS, this will let us find the header files used to assemble zealasm
:
export ZOS_PATH=/your/path/to/Zeal8bitOS
Then simply use the command:
make
After compiling, the folder bin/
should contain the binary zealasm.bin
. This file can be then loaded to Zeal 8-bit OS through UART thanks to the load
command.
The binary can also be embedded within the romdisk
that will contain both the OS and a read-only file system. For example:
cd $ZOS_PATH
export EXTRA_ROMDISK_FILES="/path/to/zealasm/bin/zealasm.bin"
make
More info about compiling Zeal 8-bit OS here.
The resulting ROM image can then be provided to an emulator or directly flashed to the computer's ROM that will use it.
To assemble source file source.asm
into binary.bin
, use:
zealasm.bin source.asm binary.bin
An example program is provided below, in the section Example program.
If you are using Zeal 8-bit OS default romdisk, you can use exec
command to execute zealasm.bin
or directly use ./
, followed by the source/destination file:
A:/>exec zealasm.bin source_file.asm B:/final_binary.bin
or
A:/>./zealasm.bin source_file.asm B:/final_binary.bin
Make sure you specify a destination disk that is write-read! (A:/
disk isn't by default)
zealasm supports several directives that can be used in the source file to assemble:
org
to set the origin address of the assembled binary. Make sure you use this directive before any instruction. This directive can only be used once per file. For example:
org 0x4000
_start:
; HL will contain the value 0x4000
ld hl, _start
; Rest of the code
label:
.dm
to define a string in the final binary. Escape characters are supported. For example:
ld hl, my_str
; Rest of the code
my_str: .dm "Hello world, this is a message\n"
.db
to define a single byte in the final binary. The value must not be greater than0xFF
. A hexadecimal value can start with0x
or$
, else it will be considered a decimal value. For example:
.db 0x4f
.db $8f
.db 19
.dw
to define a 16-bit word in the final binary. It will be written as a little-endian value. The value must not be greater than0xFFFF
. A hexadecimal value can start with0x
or$
, else it will be considered a decimal value. For example:
.dw 0x4f2a
.dw $f1fe
.dw 1337
.ds
to define a (zero-initialized) space in the final binary. The parameter is the size of the space, which can also be a decimal or a hexadecimal value. For example:
.ds 10 ; defines a space of 10 bytes
.db 0x20 ; defines a space of 32 bytes
.db $20 ; defines a space of 32 bytes
Despite the fact that the following instructions are described (in the official Z80 User Manual) as taking A as the first operand, zealasm
will also accept that the second operand is given:
add
. For example, bothadd a, b
andadd b
will be acceptedadc
. For example, bothadc a, b
andadc b
will be acceptedsbc
. For example, bothsbc a, b
andsbc b
will be accepted
The following instructions will only accept a single operand:
sub
. For example,sub b
is valid, butsub a,b
isn'tand
or
xor
cp
As the add
, adc
and sbc
instructions will refer to A
if only a single operand is given, HL
must be specified to refer to a 16-bit operation.
For example, add hl, bc
is a valid instruction, but add bc
is not.
The following example program prints "Hello, world!" and then exits. It can be assembled with zealasm
, it shall then be run on Zeal 8-bit OS:
ORG 0x4000
; Load the message defined below
ld de, hello_msg
ld bc, 14
; Standard output number
ld h, 0
; Invoke WRITE syscall manually
ld l, 1
rst 8
; Invoke EXIT syscall
ld l, 15
rst 8
hello_msg:
.dm "Hello, world!\n"
As macros are not supported yet, invoking syscalls must be done manually with rst 0x8
instruction, as described in Zeal 8-bit OS documentation.
For any suggestion or request, you can contact me at contact [at] zeal8bit [dot] com
Or, you can join Zeal 8-bit projects Discord server.
For feature requests, you can also open an issue or a pull request.
Contributions are welcome! Feel free to fix any bug that you may see or encounter, or implement any feature that you find important.
To contribute:
- Fork the Project
- Create your feature Branch (optional)
- Commit your changes. Please make a clear and concise commit message (*)
- Push to the branch
- Open a Pull Request
(*) A good commit message is as follows:
Module: add/fix/remove a from b
Explanation on what/how/why
For example:
Flash: add the possibility to flash programs bigger than 48KB
Distributed under the Apache 2.0 License. See LICENSE
file for more information.
You are free to use it for personal and commercial use, the boilerplate present in each file must not be removed.