Zunk Assembler

Products: Assembler
Developer(s): Larry Zunk
Date: 1987
Type: Program
Platform(s): TS 2068

A Z80 assembler for people who would rather not work in hex. Type mnemonics with decimal numbers and each line is assembled into memory as you enter it, with labels, a live disassembly, insert and fill, block moves between banks, CALL and JP relocation and a hex/decimal/binary converter.

A short program at 57344, with the label LOOP shown beside the line it marks.

Loading

The whole assembler is one BASIC program, ASSEMBLER (27,705 bytes). Its machine code is held in a REM at line 0.

  1. Insert Zunk Assembler.tap.
  2. Type LOAD "" and press ENTER.
  3. The program sets RAMTOP to 57343 and starts the assembler. The listing opens at address 0, a disassembly of the ROM.

It runs on a standard 2068 with no extra hardware.

Memory

AddressUsed for
26710–55300The assembler (BASIC plus its machine code)
49209–51597Label table, inside the assembler; saved by Save Labels
57344–65367Free for your machine code, above RAMTOP
65368–User-defined graphics, as normal

Assemble your code at 57344 or higher. Below that it would overwrite the assembler or BASIC’s workspace.

The assembler as it starts: ROM address 0, with system variable names such as CHADD in place of numbers.

The screen

The top 20 lines are a listing of memory. The highlighted line at the top is the current location. While you are assembling, the magenta address marks the end of your code, and a bar shows ORG (where the program starts), END and LEN. A line the assembler can’t understand is shown in red. The three rows at the bottom are the menu: press the highlighted first letter of a command.

Moving through memory

KeyDoes
ENTERScrolls the listing up a line
arrow keysStep the current location
CAPS SHIFT with an arrowFast scroll
G GotoAsks for an address and lists from there
O OrigBack to the start (ORG) of the program you’re assembling
R ReclBack to the last address you gave Goto
J JibAsks for a DISPLAYED OFSET ADDR. and lists from it. The help calls it “changes displayed address”.

Display options

KeyDoes
M ModeSwitches between disassembly and a byte listing: address, decimal value, and the character or keyword that byte would be
SYMBOL SHIFT+B (*)Names on or off: LD HL,(CHADD) or LD HL,(23645)
SYMBOL SHIFT+M (.)Relative jumps shown as a target address (JR NZ,57346) or as the raw byte (JR NZ,251)
SYMBOL SHIFT+N (,)In byte mode, show values as 1 or 2 bytes
SYMBOL SHIFT+Z (:)Sends the listing, starting at the top of the screen, to the 2040 printer, scrolling until you press a key
Byte mode: the same program as decimal values. 62 is the LD A opcode; the column on the right shows each byte as a character or keyword.

Writing code

  1. Press G and type the address to start at, for example 57344.
  2. Press A (Asem). The screen says BEGIN NEW ASSEMBLY PROGRAM and the prompt MNEMONIC-> 57344, shows where the next instruction goes.
  3. Type one instruction and press ENTER. It is assembled into memory at once and the prompt moves on.
  4. Press ENTER on an empty line to get the menu back.

C (Cont) picks up at the end of the program and adds more lines (CONTINUE ASSEMBLY PROGRAM).

Assembling. The red bar shows ORG, END and LEN; the prompt shows the next address.

Rules for what you type

WriteMeaningExample
NumbersDecimal, and at least three characters long. Pad with zeros or add .0.LD A,007 · LD B,5.0 · OUT (254),A
£NAMEDefines a label, 3 to 10 letters, at the current address. Type it on its own line before the instruction it marks. The £ is SYMBOL SHIFT+X.£LOOP then JR NZ,LOOP
LETGives a label a valueLET POOP=16384
BYTPuts one byte into the codeBYT 230
NUMPuts a 16-bit number into the codeNUM 16384
RSVReserves n bytes; useful when editing a blockRSV 032
TBLA table of 16-bit numbers or labelsTBL 003,465,DEFIL,5436,LOOP
IX; IY;Turns the HL instruction that follows into its IX or IY formIX;LD HL,(DEFILE)
"Puts text into the code"HIT ENTER
ExpressionsSimple arithmetic on labels and numbersLD A,(POOP+5.0)

Give JR and DJNZ the label of the target and the assembler works out the offset.

Typing the NOT keyword (SYMBOL SHIFT+S) at the prompt throws away the last entry.

Not sure of the syntax?Press S (Sear) at the menu and type part of an instruction. The assembler lists every form it accepts that matches, with e standing for a number. LD A,( gives LD A,(BC), LD A,(DE), LD A,(e) and LD A,(HL). Z (Z80s) scrolls through the whole instruction set.

Keep entries shortType one instruction per entry. In testing, a very long line of junk (forty-odd characters that weren’t an instruction) overwrote part of the assembler’s own lookup routine, and good instructions assembled as nonsense afterwards. If that happens, reload the program.

Changing code

Insr: insert instructions

Goto the instruction you want to insert in front of and press I. A magenta bar marks the insertion point and the prompt says INSERT MNEMONICS AT CURSOR. Each instruction you type is placed there, and everything from that point to the end of the program moves down to make room.

When you press ENTER on an empty line, the assembler goes back over the program and corrects every relative jump (JR, DJNZ) whose distance has changed.

Check JP and CALL: Absolute JP and CALL targets are not changed by an insert. In testing, a JP 57346 still pointed at 57346 after a NOP was inserted at that address. Correct them by hand, or reassemble those lines.

After inserting a NOP at 57348 and pressing ENTER: the loop’s JR NZ has been corrected from 251 to 250.

Dele: fill a block

D asks for address to delete code, the number of bytes and a code, then fills the block with that value. Use 000 to blank it to NOPs. It doesn’t close up the gap.

Poke

P writes numbers at the current location. Each entry goes into the next address. Press ENTER on an empty line to stop. The help describes it as an 8- or 16-bit poker.

Xfer: move a block, between banks too

Xfer copies 10 bytes from 57344 to 60000 in home memory (chunks 0 and 0).

X asks for SOURCE CHUNKS, DEST. CHUNKS, SOURCE ADDRESS, DEST. ADDRESS and BYTES TO COPY, shows them all, and asks OK (Y/N).

The chunk numbers select memory banks in the same way as the 2068’s bank register (port 244). Each bit picks the dock bank for one 8 KB chunk: 1 for 0–8191, 2 for 8192–16383, and so on up to 128 for 57344–65535. Use 0 and 0 for ordinary memory.

Relocating CALLs and JPs

Press SYMBOL SHIFT+R (<), a key that isn’t on the menu. The prompt is RELOCATE CALLs & JPs (0=ABORT). Type the address the program will run at. Every JP and CALL in the program that points into it is changed to match, and the listing then shows the code with its new addresses. The bytes themselves stay where they are, so finish with Xfer to move them. In testing, relocating a program at 57344 to 57345 changed JP 57346 to JP 57347.

0 abortsAnswer 0 to back out. An address that makes no sense (we tried 1) drops you into the file menu. Press ENTER to go back in; your work is still there.

Enab: choose banks

E asks Enable (IN 244,n) TO and sets the 2068’s bank register, port 244, to your number (the help: “enable chunks”). The menu shows the current setting as Enab=. Set it back to 0 for normal memory.

Labels and variables

Labl

L asks for a name. Then NUMERIC POINTER asks for its value. This is the same as LET while assembling.

Type a space instead of a name to list all labels in alphabetical order, with the program’s ORG, END and length. The list then asks DELETE A LABEL ?. Type a name to delete it, or press ENTER to leave.

Deleting a label: The first label that begins with what you type is deleted. Typing L deleted LOOP, not a label named L. Type the full name and check the list afterwards.

Kil

K erases every label at once. There is no “are you sure”, so save your labels first.

The label list. Labels can hold addresses (LOOP) or any value (BORDER = 254).

Vars: a watch window

Vars opens a live list beside the listing. BORDCR has been added at the bottom.

V opens a window of memory locations with names and their current values. It starts with 19 system variables (VARS, E LINE, PROG, CHANS and so on). V again closes it.

While it is open, A (Assign) adds a variable: give a VARIABLE NAME, its VARIABLE LOCATION, and 1 OR 2 BYTE VAR. D deletes one.

Looking around

KeyCommandWhat it does
FFindSearches memory for a sequence of byte values. Enter one number per prompt (codes to search for), then ENTER on an empty line to start. The listing moves to the first match. It is slow: a two-byte search took about three minutes.
TTextShows memory as characters from the current location. ENTER continues and Q stops. Good for finding messages in code.
SSearSearches the assembler’s syntax table for instructions containing what you type.
ZZ80sScrolls the whole instruction set in two columns. Any key pauses; Q quits.
NNumcNumber converter. Type a decimal number, or add H for hex or B for binary. It shows the value in decimal, hex, binary, and as low and high bytes. ENTER on an empty line returns to the menu.
HHelpFive pages: input rules, the menu, and the scrolling keys.
Sear for LD A,(.
Text at 26715: the assembler’s own instruction table.

Testing code

U (UsrC) asks RANDOMIZE USR (0=bort). Type the address to call. When your code returns, the screen says RETURN from USR OK. Press ENTER to carry on.

No safety net: The help warns “tests code! no error traps!”. A routine that never returns, or one that overwrites the assembler, crashes the machine. Save your code and labels first.

SYMBOL SHIFT+U (the OR keyword), also missing from the menu, calls address 60000. That’s where Zunk’s ZEBU utilities live. Don’t press it unless something safe to call is there.

The test program ran and came back.

Saving and loading

Q (Quit) leaves the assembler for the file menu at the bottom of the screen. ENTER there goes back into the assembler, with your program, labels and settings as you left them.

KeyDoes
LLoad a CODE file from tape
SSave: opens the save menu
VVerify the next CODE file on tape against memory
QStop the program. GO TO 10 brings the menu back.
ENTERBack to the assembler
RNot shown on the menu: restarts the assembler as if freshly loaded
Load, second question: ENTER loads at the address the file was saved from.

The save menu

S shows SAVE Code Labels Prog File:”name”CODE loc,len. Each save shows the SAVE it is about to do and asks OK (Y/N). Tape names are cut to 10 characters.

KeySaves
C CodeAsks CODE LOC, LEN CODE and CODE NAME, then saves that block. The assembler remembers it for File.
F FileSaves the remembered block again under the same name, with no questions. Handy for saving each new version.
L LabelsSaves the label table, 2,389 bytes from 49209, which also records ORG and END. The first time it asks for a name. After that it offers the same name; answer N to choose another.
P ProgSaves the whole assembler as ASSEMBLER, set to start itself. Your labels are inside it, so this is a quick way to keep a working copy.

Loading

  1. At the file menu press L. Type the tape name, or press ENTER alone to load the next CODE file that comes along.
  2. The next question gives three choices: type NOT to abort, type an address to load there, or press ENTER to load at the address the file was saved from.

A label file loads straight back into the label table at 49209. Load your code file and its label file, press ENTER, and you are back where you left off.

Not SPACE: Answer “Start tape, then press any key” with a letter. SPACE is BREAK and stops the save.

Key reference

KeyMenuDoes
AAsemStart a new program at the current location
CContCarry on assembling at the end of the program
DDeleFill a block with a value
EEnabSet the bank register (port 244)
FFindSearch memory for byte values
GGotoList from an address
HHelpFive help pages
IInsrInsert instructions at the cursor
JJibChange the displayed address
KKilErase all labels
LLablAdd, list or delete labels
MModeDisassembly or byte listing
NNumcHex/decimal/binary converter
OOrigList from the program’s ORG
PPokeWrite values from the current location
QQuitTo the file menu
RReclList from the last Goto address
SSearSearch the instruction syntax
TTextShow memory as characters
UUsrCRun code at an address
VVarsWatch window on or off
XXferCopy a block, between banks too
ZZ80sScroll the instruction set
SYMBOL SHIFT+R—Relocate CALLs and JPs
SYMBOL SHIFT+B—Names in the listing on or off
SYMBOL SHIFT+M—JR shown as address or offset
SYMBOL SHIFT+N—1- or 2-byte values in byte mode
SYMBOL SHIFT+Z—Print the listing on a 2040
SYMBOL SHIFT+U—Call address 60000 (ZEBU)

Tips

  • Put your first instruction at 57344. Everything from there to 65367 is yours.
  • Give names to the addresses and values you use with L or LET before you start. The disassembly then reads like your source.
  • Use labels for jump targets rather than numbers. Insert keeps relative jumps right, but numeric JP and CALL targets need checking after an insert.
  • Leave a little RSV space at the ends of routines so you can add to them later without moving everything.
  • Save the code with Code once, then press F (File) after each change. Save the labels too; together they bring you back to exactly where you were.
  • Add your program’s own variables to the Vars window and check them after a test run with UsrC.
  • Forgot how an instruction is written? Sear it before you type it, rather than waiting for a red line.

Related Products

Decimal-based assembler that includes converter for hexadecimal/decimal/binary/2-byte values.

Image Gallery

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.