If a computer can’t compile and deploy its own software then it’s not a general purpose computer, it's an appliance.
v80 is an 8-bit native, multi-platform, multi-CPU cross-assembler that runs on real 8-bit hardware, but also on PC (via NTVCM or RunCPM). v80's goal is to ensure reproducability of 8-bit software on real 8-bit hardware, both modern and retro, whilst never excluding PC-based development.
"v80" refers to the Z80 assembler, but versions that target different CPUs and/or run on different host CPUs are available, or are planned:
v80 assembles Z80 code ".v80"
v65 assembles 6502 code ".v65", currently running on Z80
v69* assembles 6809 code ".v69"
v83* assembles GameBoy (SM83) code ".v83"
*(coming in a future release)
If you would like to see v80 on your favourite CPU / system consider raising an issue at https://github.com/kroc/v80
It currently runs on CP/M and can assemble itself with plans to port it to Agon Light, Zeal 8-bit OS and other Z80-based systems. v80 can assemble 6502 code via its pluggable ISA support and a native 6502 port is planned.
If you feel like you could write a C version of v80, your help would be appreciated as it would remove the need to simulate CP/M to assemble on PC, with the no-directories limit that imposes.
- No linker, we have linker at home → includes
(the stdout of v80 is a symbol file!) - No Macros! Copy + Paste is your friend or re-use includes
- $FFFF/65'535 is the largest number in the universe
- No floating point numbers. Have you tried coding floats on an 8-bit CPU??
- No shift operators. Multiply/divide by powers of 2
- No comparison operators -- we use the zero-flag here
- No commas. Commas were a mistake
v80 uses a non-standard syntax designed for parsing simplicity / speed, not compatibility with existing source code.
The basic principle is that v80 can only recognise a word by the first character, so everything must be prefixed with a sigil or otherwise be easily categorizable, e.g. a
-z
= instruction.
; v80: ................ ; zilog:
; ;
add $ff ; add A, $ff
adc.c ; adc A, C
sub*hl ; sub A, [HL]
sbc.hl.bc ; sbc HL, BC
ld.a*ix $00 ; ld A, [IX+$00]
bit7.a ; bit 7, A
jr?nz :label ; jr nz, :label
; ...
; (see "release/z80.txt" for full list)
#true $1 ; constant define
; constants can be redefined, but the value
; must be constant (no forward-references)
;
#true $0
; a hex number at the start of a line
; sets the program-counter
;
$c000
; or use `$` to set program-counter
; using an expression
;
$ #base + $0100
; other number types supported:
;
#bin %10000001 ; binary (1-16 digits)
#dec 65535 ; decimal
#chr 'A ; character literals
:label ; label define
; local labels are appended to the
; last defined non-local label
;
_local ; i.e. :label_local
; keywords begin with `.`
;
.b <bytes>
.w <words>
; in expressions, `$` returns
; current program-counter
;
.b :label - $
; no string escapes, just use numbers
;
.b "line 1" $0a "line 2"
; unary operators:
; (before value)
;
; < = lo (bottom byte of word)
; > = hi (top byte of word)
; ! = not (flip all bits)
; - = neg (flip all bits and +1)
; infix operators:
;
; + - * / = add sub mul div
; ^ & | \ = xor and or mod
; file includes
;
.i "file.v80"
; condition markers: the expression is evaluated and
; the condition passes / skips based on equality with 0
;
?= <expr> ; only 0 passes
?! <expr> ; only not-0 passes
?+ <expr> ; only positive (sign+) passes
?- <expr> ; only negative (sign-) passes
; if the condition fails,
; indented lines are skipped
?! <expr>
; this allows for nested conditions
; align: skip bytes until the program-counter
; modulo the expression is zero
;
.a $100 ; align to next page
; or fill a specific number of bytes,
; with a given value
;
.f '! 10 ; emit "!", 10 times
A full guide on the syntax is included in "release/readme.txt". If you're using VSCode, there's an extension for v80 syntax highlighting in the marketplace under v80-vscode.
If you just want to use v80 to write and assemble Z80 (or 6502) software, just download a release. If you want to build v80 from source, everything needed to build v80 on Windows is included in the repository. Building on Mac, Linux and UNIX-likes can be done, but will require you to source / compile your own binaries of WLA-DX & NTVCM.
Just run "build.bat" to assemble v80 and related cross-assemblers -- the binary is placed in the "releases" folder.
v80 is assembled as a generic CP/M binary that should run on any Z80-based, CP/M v2.2 (or above) system -- no hardware or system-specific calls are used. For now, v80 does not provide any system-specific floppy-disk images for loading v80 on to real hardware, but you can use tools like Disk Image Manager (Amstrad / Sinclair) or cpmtools to make disk-images. If you would like a specific system to have pre-loaded v80 disk images, please consider submitting an issue.
- v80 can assemble itself via a v80-syntax version of v80!
- v65 is a 6502 cross-assembler version of v80, self-assembled by v80 using pluggable ISAs. Support for more CPU ISAs will come in the future
An off-by-one error with defining constants was corrupting the linked-list leading to constants appearing undefined later on. I have NO IDEA how this bug went untriggered this whole time despite v80 being able to assemble itself!
In a spectacular case of not seeing the woods for the trees, the expression parser wasn't evaluating anything more than a single operator and ignoring the rest of the expression. Unary operators were also not working due to expected registers changing at some point.
v80 now assembles itself byte-for-byte compared to the WLA-DX version meaning there should be no more surprise bug-fix releases, and a v80 version of v80 will be coming with v1.0!
- Square brackets allowed as alternatives to parenthesis
Many fixes realised whilst working on v80 assembling itself:
- Expression parsing was sometimes returning carry-set if not deferred
- Multiplication was straight-up broken!
- Decimals not being recognised in
.b
/.w
lists - 2nd pass not reporting the correct line/col number for errors
- Fixed defining labels after setting program-counter with expression not working as intended and an issue with closing parenthesis
- Decimal numbers!
- Binary literals (
%
) - Character literals (
'
) - Local labels (
_
) - Fill keyword (
.f
) - Disk full error (CP/M)
First release, v80 includes:
- Z80, CP/M v2.2. binary < 8KB
- Constants (
#
) and labels (:
) - Expression parsing with deferred expressions for forward-references to labels
- Conditional assembly markers
- Alignment / padding of binary
- Z80 instruction set