DEV-Assem

Date: 1983
Type: Program
Platform(s): TS 2068

DEV-Assem is a full-featured Z80 assembler and source-code editor, implemented entirely in BASIC with a small machine code routine for text insertion. The editor supports append, insert, delete, and replace operations on a line-numbered source buffer stored in a string array, and saves and loads source files to tape using a packed binary format. The two-pass assembler resolves up to 99 forward-reference labels, handles all standard Z80 mnemonics including extended ED-prefix instructions, and outputs byte values in decimal or hexadecimal. Opcode decoding is driven by a large DATA table accessed via a hash of the four-character mnemonic, and pseudo-opcodes DEFB, DEFW, DEFS, DEFL, and TEXT are also supported. The machine code insertion routine (19 bytes, POKEd into memory at startup via line 2000–2006) uses the LDIR instruction to shift buffer contents efficiently.


Program Analysis

Program Structure

The program is organized into distinct functional regions identified by line number ranges:

  • Lines 1–5: Initialization and user-defined functions (FN r, FN a, FN q$, FN c).
  • Lines 10–52: Buffer traversal subroutine (line 10), and editor operations: insert (20–29), display/print (30–34), delete (40–45), append (50–52).
  • Lines 80–130: Input/error handling, including the mnemonic parser and operand input loop.
  • Lines 200–270: Two-pass assembler: pass 1 builds the label table (line 205–210), pass 2 emits bytes (lines 220–262).
  • Lines 300–530: Operand-matching subroutines used as a dispatch table driven by DATA.
  • Lines 600–616: Machine-word output formatters (f0–f8), each constructing m$ and jumping to op at line 125.
  • Lines 699–797: Main menu: edit, assemble, save, load, print, control.
  • Lines 800–806: Startup/restart: allocates buffer, sets all symbolic constants.
  • Lines 812–1379: Opcode DATA tables (Z80 mnemonics).
  • Lines 2000–2006: Machine code installer for the buffer insert routine.
  • Line 9998: Development save/verify line (not part of normal execution).

Buffer Organization

The source text is stored in a single large string q$, dimensioned at startup. Each source line is a fixed-header record of 8 bytes followed by variable-length opcode and machine code fields:

OffsetContent
0Label number (0 = none), accessed via FN c(k0)
1–4Mnemonic string (4 chars), accessed via FN q$(k1,4)
5Length of operand text field, FN c(5)
6Length of machine code bytes field, FN c(6)
7Condition/flag byte, FN c(7)
8+Operand text string (l1 bytes) then machine code bytes (l2 bytes)

The variable ptr tracks the current read position within q$, and last tracks the end of used buffer space. The subroutine at line 10 advances ptr by iterating over a given number of records, simultaneously accumulating the machine code byte count in a.

Machine Code Insertion Routine

Lines 2000–2006 install a 19-byte machine code routine into memory just above the system variable area. The DATA values decode as a Z80 routine that uses LD BC, LD HL, and LDIR to shift the portion of the buffer above the insertion point upward, making room for a new record. The address is calculated at line 2000 using FN a(23637)+5 (targeting an area above the PROG pointer). This routine is invoked at line 26 via USR insert inside a RANDOMIZE statement, which passes the shift length as the BC register pair via PEEK 23670/23671.

Symbolic Constants and GO TO Variables

Rather than hard-coding line numbers in GO TO and GO SUB statements, the program stores target line numbers in variables set at lines 804–806. For example, ri=400, v1=410, op=125, error=90, f0=600 through f8=616, etc. This makes the DATA-driven dispatch loop reusable and the jump targets readable. Similarly, boolean constants k0 (= 0) and k1 (= 1) and hi (= 255) replace magic numbers throughout.

Opcode Dispatch via Hashed DATA Lookup

At line 110, the 4-character mnemonic string e$ is hashed by the expression 2*CODE e$+5*CODE e$(2)+6*CODE e$(3)+4*CODE e$(4), and RESTORE a seeks to that DATA line. The DATA at that line begins with the expected mnemonic string for verification. Each opcode entry in the DATA tables encodes:

  1. Number of operands expected (0, 1, or 2)
  2. A sequence of (operand-matcher line, …, byte-value, formatter-line) triplets
  3. A terminal nn (= line 395) on match failure

Operand matchers are subroutines at lines 300–530: sv (literal string match), vv (variable dispatcher), ri (register), v1 (8-bit value), v2 (16-bit/label value), cf (condition flag), da/ds/di/dd (register pair variants), bn (bit number 0–7), im (interrupt mode 0–2), ra (RST address), bv/bv1 (parenthesized forms). The variable x is set to 0 on a successful match, non-zero on failure.

Two-Pass Label Resolution

Pass 1 (line 205–210) scans all records, storing the current origin address into l(n) for any record with a non-zero label field, and advancing org by the stored machine code length (FN c(6)) for each record. DEFS is handled specially to advance org by the operand value. Pass 2 (lines 220–262) re-scans, retrieves label values from l(), and resolves relative jump offsets (2-byte operand) and absolute addresses (3+-byte operand). Range checking for relative jumps is performed at line 240, and undefined labels cause a run-time error via GO TO run.

Key BASIC Idioms

  • AND used as a conditional string selector: (CHR$ i) AND i produces the IX/IY prefix byte only when i is non-zero (line 602 etc.).
  • RANDOMIZE n before USR insert loads BC with n for the machine code routine (lines 26, 737, 800).
  • FN a(addr) reads a 16-bit little-endian value from two consecutive PEEK bytes (line 3).
  • NOT a and NOT k0 generate 1 and 0 respectively for k1 and k0 initialization (line 801).
  • User-defined FN q$(x,y) (line 4) slices the buffer relative to ptr, avoiding repeated long expressions.
  • The OPEN #2,"S" / OPEN #2,"P" calls redirect stream 2 to screen or printer for the print-to-printer feature.

Pseudo-Opcodes

MnemonicFunction
DEFBDefine byte — emits a single byte (line 229)
DEFWDefine word — emits two bytes little-endian (line 226)
DEFSDefine space — advances origin by n bytes (line 228)
DEFLDefine label — assigns a value to a label (line 227)
TEXTEmbed text string; bytes not printed in hex/binary output (line 250–251)
TRATransparent — passes machine code through unchanged (line 1096)
REMRemark — no output (line 1099)

Save and Load Format

On save (line 737), the line count (lns), machine code byte count (mc), and last-used buffer position (last) are packed into the first 8 bytes of q$ before the entire array is written to tape with SAVE a$ DATA q$(). The low and high bytes of lns and mc are extracted by storing the value in RANDOMIZE and reading back PEEK 23670/PEEK 23671 (the SEED system variable). On load (line 740), these fields are decoded from q$ to restore the assembler state.

Notable Anomalies

  • Line 1026’s DATA includes the string "~" (rendered as the tilde character in the listing) in the SBC entry. Given the preprocessing rules, this may represent the FREE keyword token in the source file, though in context it is used as a literal operand string for pattern matching — likely a typo intended to match "A".
  • The hash function at line 110 does not guard against mnemonics shorter than 4 characters; accessing e$(2), e$(3), e$(4) on a 2- or 3-character mnemonic would cause a “Subscript out of range” error — but in practice all valid Z80 mnemonics stored in the buffer are padded to 4 characters by the input routine.
  • Line 350 uses RESTORE 817+((LEN b$-5) AND (LEN b$<5)) to select between the two LD DATA blocks at lines 813 and 817, exploiting the fact that boolean expressions evaluate to 0 or 1.
  • Line 1096 (TRA) and line 1099 (REM) both target op (line 125) directly without emitting any bytes, effectively making them no-ops in the output stream.

Image Gallery

Source Code

    1 CLEAR 54999:BORDER 1:PAPER 6:POKE 23609,10:LET a=2000:GO TO 801
    2 DEF FN r(x,y,z$)=(CODE z$ >= CODE STR$ x) AND (CODE z$ <= CODE STR$ y)
    3 DEF FN a(x)= PEEK x+256* PEEK (x+1)
    4 DEF FN q$(x,y)=q$(ptr+x TO ptr+y)
    5 DEF FN c(x)= CODE q$(ptr+x)
   10 FOR x=k1 TO l-k1:LET a=a+ FN c(6):LET ptr=ptr+8+ FN c(5)+ FN c(6):NEXT x:RETURN 
   20 IF l1>lns OR l1<k1 THEN LET z$="Range error":GO TO 700
   22 PRINT BRIGHT k1;"Inserting":LET l=l1:LET ptr=9:GO SUB 10
   24 GO SUB 100:LET l=l+k1:LET len= LEN p$:IF NOT len THEN GO TO 28
   25 IF last+len> LEN q$ THEN LET z$="No more room":GO TO run
   26 RANDOMIZE last-ptr+k1:LET q$(ptr TO ptr+len-k1)=p$ AND USR insert:LET ptr=ptr+ LEN p$:LET mc=mc+ LEN m$:LET last=last+len:LET lns=lns+k1:GO TO 24
   28 LET l1=l-10:LET l2=lns:IF l1>lns-32 THEN LET l1=lns-21
   29 IF l1 <=k0 OR lns <=22 THEN LET l1=k1
   30 PAUSE k1:LET ptr=9:LET l=l1:GO SUB 10:CLS :IF NOT lns THEN PRINT "Empty":GO TO 701
   32 POKE scc,hi:LET l= FN c(k0):LET l$=("L"+ STR$ l) AND l:PRINT l1; TAB 3;L$; TAB 8; FN q$(k1,4); TAB 13;:LET l= FN c(5):PRINT FN q$(8,7+l):LET ptr=ptr+8+l+ FN c(6):LET l1=l1+k1:IF l1 <=l2 AND INKEY$="" THEN GO TO 32
   34 GO TO 701
   40 IF l1<k1 OR l2>lns OR l1>l2 THEN LET z$="Range error":GO TO run
   42 LET l=l1:LET ptr=9:GO SUB 10:LET p1=ptr:LET l=l2-l1+2:LET a=k0:GO SUB 10:LET len=ptr-p1
   44 FOR x=p1 TO last-len-31 STEP 32:LET y=x+len:LET q$(x TO x+31)=q$(y TO y+31):NEXT x:LET q$(x TO last-len)=q$(x+len TO last):LET mc=mc-a:LET last=last-len:LET lns=lns-l2+l1-k1:LET len=k0:IF z$ <>"R" THEN GO TO 28
   45 PRINT "Replacing ";l1;" to ";l2:LET ptr=p1:LET l=l1:IF ptr<last THEN GO TO 24
   50 LET l=lns+k1:GO SUB 100:LET len= LEN p$:IF NOT len THEN GO TO 701
   51 IF last+len> LEN q$ THEN LET z$="No more room":GO TO run
   52 LET q$(last+k1 TO last+len)=p$:LET mc=mc+ LEN m$:LET last=last+len:LET lns=lns+k1:GO TO 50
   80 BEEP .1,k0:POKE 23658,8:INPUT "Error"' FLASH (x=1);(l$); TAB 7; FLASH (x=2);(a$); TAB 14; FLASH (x>2);(b$);" ";(c$); FLASH k0; TAB 30; LINE z$:RETURN 
   90 IF x=3 THEN RETURN 
   94 GO SUB 80:IF x>k1 THEN GO TO 104
  100 LET m$="":LET x=k1:INPUT (d$)' LINE l$:IF l$="" THEN LET l1=k0:GO TO 104
  102 IF CODE l$ <> CODE "L" OR NOT FN r(k0,9,l$(2 TO )) THEN GO TO error
  103 LET l1= VAL l$(2 TO ):IF STR$ l1 <>l$(2 TO ) OR ABS (l1-50)>49 THEN GO TO error
  104 LET b$="":LET c$="":LET len=k0:LET x=2:INPUT (d$)'(l$); TAB 7; LINE a$
  106 IF a$="" THEN LET p$="":RETURN 
  110 LET e$=a$:LET a=2* CODE e$+5* CODE e$(2)+6* CODE e$(3)+4* CODE e$(4):RESTORE a:READ t$:IF t$ <>a$ THEN GO TO error
  112 LET d=k0:LET n=k0:LET l2=k0:LET i=k0:READ a:IF NOT a THEN READ b,f:GO TO f
  114 INPUT (d$);" 1st"'(l$); TAB 7;(a$); TAB 14; LINE b$
  115 IF a>k1 THEN INPUT (d$); TAB 15+ LEN b$;"2nd"'(l$); TAB 7;(a$); TAB 14;(b$);" "; LINE c$
  116 LET a=(b$ <>"")+(c$ <>"")
  120 LET x=3:LET i=k0:LET d=k0:LET n=k0:LET l2=k0:READ g:GO TO g
  125 LET b$=b$+("," AND (c$ <>""))+c$:PRINT l; TAB 3;l$; TAB 8;a$; TAB 13;b$
  126 LET p$= CHR$ l1+e$+ CHR$ LEN b$+ CHR$ LEN m$+ CHR$ l2+b$+m$
  129 POKE 23658,8
  130 RETURN 
  200 OPEN #2,s$:LET help=780
  202 INPUT "Assemble at ";(adr);". Origin at ?"; LINE z$:LET org=adr:IF z$ <>"" THEN LET org= VAL z$
  204 LET dif=adr-org:DIM l(99):LET ptr=9:CLS :PRINT BRIGHT k1;"1st Pass - Labels"
  205 FOR x=k1 TO lns:LET l= FN c(k0):IF l <>k0 THEN LET l(l)=org:POKE scc,hi:PRINT "L";l; TAB 4;" = ";org," line ";x
  207 IF FN q$(k1,4)="DEFS" THEN LET org=org+ VAL FN q$(8,7+ FN c(5))
  210 LET org=org+ FN c(6):LET ptr=ptr+8+ FN c(5)+ FN c(6):NEXT x
  220 LET org=adr-dif:LET ptr=9:PRINT ' BRIGHT k1;"2nd Pass - Assembly"
  223 FOR x=k1 TO lns:LET l$="":PRINT org;:LET a$= FN q$(k1,4):LET l= FN c(7):LET l1= FN c(5):LET l2= FN c(6):LET m$= FN q$(8+l1,7+l1+l2):IF FN c(k0) <>k0 THEN LET l$="L"+ STR$ FN c(k0)
  224 IF org>65535 THEN LET z$="Address too large - Line "+ STR$ x:GO TO run
  225 IF INKEY$ <>"" THEN GO TO 225
  226 POKE scc,hi:IF l=hi THEN LET n= VAL FN q$(8,7+ FN c(5)):LET l=k0:LET n2= INT (n/256):LET n1=n-256*n2:LET n2=n2+256*(n2<k0):IF a$="DEFW" THEN LET m$= CHR$ n1+ CHR$ n2
  227 IF a$="DEFL" THEN LET l(FN c(k0))=n
  228 IF a$="DEFS" THEN LET org=org+n
  229 IF a$="DEFB" THEN LET m$= CHR$ n1
  230 PRINT TAB 6;l$; TAB 11;a$; TAB 16; FN q$(8,7+l1);" ";:LET ptr=ptr+8+l1+l2:IF NOT l THEN GO TO 250
  235 LET a=k1:IF l(l)=k0 THEN LET z$="Undefined label - Line "+ STR$ x:GO TO run
  240 IF l2=2 THEN LET z$="Jump too far":LET f=l(l)-org-2:IF f >=-127 AND f <=128 THEN LET a=k0:LET f=256*(f<k0)+f:LET m$(2)= CHR$ f
  245 IF l2>2 THEN LET z$="Label too large":LET n2= INT (l(l)/256):LET n1=l(l)-256*n2:IF n2 >=k0 AND n2 <=hi THEN LET a=k0:LET m$(l2-k1)= CHR$ n1:LET m$(l2)= CHR$ n2
  248 IF a THEN LET z$=z$+" - Line "+ STR$ x:GO TO run
  250 LET z$="":FOR y=k1 TO l2:IF b$="B" THEN IF a$ <>"TEXT" THEN PRINT TAB 27; BRIGHT 1; CODE m$(y);:LET v= CODE m$(y):LET v= LEN STR$ v:PRINT BRIGHT 1;"    "(1 TO 4-v);
  251 IF b$="H" THEN IF a$ <>"TEXT" THEN LET v= CODE m$(y):LET n$=h$(v/16+.5):LET v=v- INT (v/16)*16+.5:LET n$=n$+h$(v):PRINT TAB 28; BRIGHT 1;" ";n$;" ";
  255 POKE org+dif, CODE m$(y):LET org=org+k1:NEXT y:PRINT :NEXT x:LET len=org-adr+dif:PRINT '"  Origin = ";adr;" Len = ";len
  260 PRINT ' BRIGHT 1;"Label values"
  261 FOR z=1 TO 99:IF l(z) THEN PRINT "L";z; TAB 4;" = ";l(z)
  262 NEXT z
  270 GO TO 750
  300 READ v$,g:IF b$=v$ THEN LET s$=c$:GO SUB g:IF NOT x THEN READ b,f:GO TO f
  302 READ b,f:GO TO rd
  310 READ g,g1:LET s$=b$:GO SUB g:IF NOT x THEN LET s$=c$:LET x=3:GO SUB g1:IF NOT x THEN READ b,f:GO TO f
  312 READ b,f:GO TO rd
  320 READ g:IF c$="" THEN LET s$=b$:GO SUB g:IF NOT x THEN READ b,f:GO TO f
  322 READ b,f:GO TO rd
  330 READ v$:IF (b$+c$)=v$ THEN READ b,f:GO TO f
  332 READ b,f:GO TO rd
  340 READ g,v$:IF c$=v$ THEN LET s$=b$:GO SUB g:IF NOT x THEN READ b,f:GO TO f
  342 READ b,f:GO TO rd
  350 RESTORE 817+((LEN b$-5) AND (LEN b$<5)):READ s$:GO TO rd
  360 READ g,g1:LET s$=b$:GO SUB g:IF NOT x THEN LET r1=r:LET s$=c$:LET x=3:GO SUB g1:IF NOT x AND (r1 <>6 OR r <>6) THEN READ b,f:GO TO f
  362 READ b,f:GO TO rd
  370 LET x=4:LET org= VAL b$:LET l2=hi:LET m$="":GO TO op
  372 LET x=4:LET n= VAL b$:LET l2=hi:LET m$=" ":GO TO op
  374 LET x=4:LET n= VAL b$:LET l2=hi:LET m$="  ":GO TO op
  376 LET m$=b$:GO TO op
  378 LET x=4:IF l1>k0 AND l1<100 THEN LET n= VAL b$:LET l2=hi:LET m$="":GO TO op
  379 LET x=k1:LET z$="No label":GO TO error
  395 LET x=4:GO TO error
  400 LET r=(s$="B")+(2 AND s$="C")+(3 AND s$="D")+(4 AND s$="E")+(5 AND s$="H")+(6 AND s$="L")+(7 AND s$="(HL)")+(8 AND s$="A"):IF r THEN LET r=r-k1:LET x=k0:RETURN 
  402 IF CODE s$= CODE "(" THEN LET i=221*(s$(2 TO 3)="IX")+253*(s$(2 TO 3)="IY"):IF i THEN LET r=6:LET d= VAL s$:IF d >=-128 AND d <=127 THEN LET d=d+256*(d<k0):LET x=k0:RETURN 
  404 RETURN 
  410 IF CODE s$= CODE """" THEN LET n= CODE s$(2 TO ):LET x=k0:RETURN 
  411 IF CODE s$= CODE "-" OR FN r(0,9,s$) OR CODE s$=196 THEN LET n= VAL s$:IF ABS n <=255 THEN LET n=n+256*(n<k0):LET x=k0:RETURN 
  412 RETURN 
  420 LET r=(s$="BC")+2*(s$="DE")+4*(s$="AF"):IF r THEN LET r=r-k1:LET x=k0:RETURN 
  422 GO TO 440
  430 LET r=(s$="BC")+2*(s$="DE")+4*(s$="SP"):IF r THEN LET r=r-k1:LET x=k0:RETURN 
  440 LET i=(s$="HL")+222*(s$="IX")+254*(s$="IY"):IF i THEN LET r=2:LET i=i-k1:LET x=k0:RETURN 
  442 RETURN 
  450 LET r=(s$="BC")+2*(s$="DE")+3*(s$=b$)+4*(s$="SP"):IF r THEN LET r=r-k1:LET x=k0:RETURN 
  460 LET r=(s$="NZ")+2*(s$="Z")+3*(s$="NC")+4*(s$="C")+5*(s$="PO")+6*(s$="PE")+7*(s$="P")+8*(s$="M"):IF r THEN LET r=r-k1:LET x=k0:RETURN 
  461 RETURN 
  470 IF CODE s$= CODE "-" OR FN r(k0,9,s$) OR CODE s$=196 THEN LET n= VAL s$:IF ABS n <=65535 THEN LET n=n+65536*(n<k0):LET x=k0:RETURN 
  471 IF CODE s$= CODE "L" THEN LET l2= VAL s$(2 TO ):LET x=k0:RETURN 
  472 IF CODE s$= CODE """" THEN LET n=256* CODE s$(2 TO )+ CODE s$(3 TO ):LET x=k0:RETURN 
  473 RETURN 
  480 IF FN r(k0,9,b$) THEN LET n= VAL b$:IF n >=k0 AND n <=56 AND 8* INT (n/8)=n THEN LET x=k0:RETURN 
  481 RETURN 
  490 IF FN r(k0,7,b$) AND LEN b$=k1 THEN LET r1= VAL b$:LET x=k0:RETURN 
  491 RETURN 
  500 IF FN r(k0,2,b$) AND LEN b$=k1 THEN LET n= VAL b$:LET n=n+(n>k0):LET x=k0:RETURN 
  501 RETURN 
  510 GO SUB cf:IF NOT x AND r<4 THEN LET x=k0:RETURN 
  511 LET x=3:RETURN 
  520 IF CODE s$= CODE "(" THEN IF CODE s$(LEN s$)= CODE ")" THEN LET s$=s$(2 TO LEN s$-k1):GO TO v2
  521 RETURN 
  530 IF CODE s$= CODE "(" THEN IF CODE s$(LEN s$)= CODE ")" THEN LET s$=s$(2 TO LEN s$-k1):GO TO v1
  531 RETURN 
  600 LET n2= INT (n/256):LET n1=n-256*n2:LET m$= CHR$ 237+ CHR$ b+ CHR$ n1+ CHR$ n2:GO TO op
  602 LET m$=((CHR$ i) AND i)+ CHR$ b:GO TO op
  604 LET m$=((CHR$ i) AND i)+ CHR$ b+((CHR$ d) AND i):GO TO op
  606 LET m$=((CHR$ i) AND i)+ CHR$ 203+((CHR$ d) AND i)+ CHR$ b:GO TO op
  608 LET n2= INT (n/256):LET n1=n-256*n2:LET m$=((CHR$ i) AND i)+ CHR$ b+ CHR$ n1+ CHR$ n2:GO TO op
  610 LET m$= CHR$ b+ CHR$ n:GO TO op
  612 LET m$= CHR$ b+ CHR$ 0:GO TO op
  614 LET m$= CHR$ 237+ CHR$ b:GO TO op
  616 LET m$=((CHR$ i) AND i)+ CHR$ b+((CHR$ d) AND i)+ CHR$ n:GO TO op
  620 STOP 
  699 GO SUB 80:GO TO 701
  700 BEEP .1,30:POKE 23658,8:INPUT "Error"'(z$); TAB 30; LINE z$
  701 OPEN #2,"S":INPUT AT k0,k0;"Append Insert Delete Replace"'"Print  Save   Load   Control "; LINE z$
  705 IF z$="I" THEN INPUT "Before ";l1:GO TO 20
  710 IF z$="A" THEN PRINT BRIGHT k1;"Appending":GO TO 50
  715 IF z$="D" THEN INPUT "From ";l1;" to ";l2:GO TO 40
  717 IF z$="R" THEN INPUT "Replace ";l1;" to ";l2:GO TO 40
  719 IF z$="PR" THEN OPEN #2,"P"
  720 IF z$="P" OR z$="PR" AND lns<23 THEN LET l1=k1:LET l2=lns:GO TO 30
  725 IF z$="P" OR z$="PR" THEN INPUT "From ";l1:LET l2=lns:GO TO 30
  730 IF z$="C" THEN GO TO 780
  737 IF z$="S" THEN INPUT "File name ";a$:RANDOMIZE lns:LET q$(k1)= CHR$ PEEK 23670:LET q$(2)= CHR$ PEEK 23671:RANDOMIZE mc:LET q$(3)= CHR$ PEEK 23670:LET q$(4)= CHR$ PEEK 23671:LET q$(5 TO 8)= STR$ last:SAVE a$ DATA q$():PRINT FLASH k1;"Verify":VERIFY a$ DATA q$()
  740 IF z$="L" THEN INPUT "File name ";a$:LOAD a$ DATA q$():LET a$="":LET lns= CODE q$(1)+256* CODE q$(2):LET mc= CODE q$(3)+256* CODE q$(4):LET last= VAL q$(5 TO 8):GO TO 780
  745 GO TO 701
  750 OPEN #2,"S":INPUT "Save Run Control Edit "; LINE z$
  755 IF z$="E" THEN LET l1=k1:LET l2=lns:GO TO 30
  758 IF z$="C" THEN GO TO 780
  760 IF z$="S" AND len THEN INPUT "Name of Mcode ";a$:SAVE a$ CODE adr,len
  765 IF z$="R" AND NOT dif AND len THEN INPUT "Origin= ";(adr);". Enter at "; LINE a$:LET org=adr:IF a$ <>"" THEN LET org= VAL a$
  766 IF z$="R" AND NOT dif AND len THEN CLS :PRINT #2; AT k0,k0;:RANDOMIZE USR org
  770 GO TO 750
  780 CLS :PRINT BRIGHT K1;" ZX SPECTRUM EDITOR/ASSEMBLER       DAVID HAWKINS  FEB 1983",'''
  781 PRINT "TEXT FILE"''" LENGTH = "; LEN q$'"   USED = ";last'" UNUSED = "; LEN q$-last'"  LINES = ";lns'"  MCODE = ";mc''"SPARE"''" LENGTH = "; FN a(23730)- FN a(23653)''"CODE"''"  START = ";adr'" LENGTH = ";len
  785 INPUT "EDIT  ASSEMBLE  CODE  RESTART "; LINE z$
  786 IF z$="C" THEN GO TO 750
  788 IF z$="R" THEN GO TO 800
  790 IF z$="A" THEN GO TO 795
  792 IF z$="E" THEN LET l1=k1:LET l2=lns:GO TO 30
  793 IF z$="QUIT" THEN STOP 
  794 GO TO 785
  795 INPUT "Screen or Printer "; LINE s$:IF s$ <>"S" AND s$ <>"P" THEN GO TO 795
  796 INPUT "Bytes or Nobytes "; LINE b$:IF b$ <>"B" AND b$ <>"N" AND b$ <>"H" THEN GO TO 796
  797 GO TO 200
  800 INPUT AT 0,0;"File Length = ";a;" Code Start = ";z:RANDOMIZE a:CLEAR z-1:LET a= FN a(23670)
  801 DIM q$(a):LET k0= NOT a:LET k1= NOT k0:GO SUB 2000:LET a$="":LET b$="":LET c$="":LET l$="":LET lns=k0:LET last=8:LET mc=k0:LET scc=23692:LET hi=255:LET dif=k0:LET h$="0123456789ABCDEF"
  802 LET adr= FN a(23730)+1:LET len=k0:POKE 23658,8:DIM e$(4):DIM l(99):LET ptr=9:LET rd=120:LET op=125:LET error=90:LET help=699:LET org=adr:LET len=k0
  804 LET r1=k0:LET ps=370:LET ldr=360:LET load=350:LET bv1=530:LET bv=520:LET ix=k0:LET iy=k0:LET sv=300:LET vv=310:LET vn=320:LET ss=330:LET vs=340:LET nn=395:LET ri=400:LET v1=410:LET da=420:LET ds=430:LET di=440:LET dd=450:LET cf=460:LET v2=470:LET ra=480:LET bn=490:LET im=500:LET cs=510
  806 LET run=700:LET f0=600:LET f1=602:LET f2=604:LET f3=606:LET f4=608:LET f5=610:LET f6=612:LET f7=614:LET f8=616:LET d$="Label  Opcode":GO TO 780
  812 DATA "LD",2,load
  813 DATA "",ldr,ri,ri,64+8*r1+r,f2,vv,ri,v1,6+8*r,f8,sv,"A",bv,58,f4,ss,"A(BC)",10,f1,ss,"A(DE)",26,f1,ss,"AI",87,f7,ss,"AR",95,f7,ss,"IA",71,f7,ss,"RA",79,f7,nn
  814 DATA "",sv,"BC",bv,75,f0,sv,"DE",bv,91,f0,vv,di,bv,42,f4,vv,ds,v2,1+16*r,f4,sv,"HL",v2,33,f4,sv,"SP",bv,123,f0,sv,"SP",di,249,f1,nn
  817 DATA "",ss,"(BC)A",2,f1,ss,"(DE)A",18,f1,ldr,ri,ri,64+8*r1+r,f2,vv,ri,v1,6+8*r,f8,vs,bv,"A",50,f4,vv,bv,di,34,f4,vv,bv,ds,67+16*r,f0,nn
  821 DATA "DI",k0,243,f1
  823 DATA "EI",k0,251,f1
  851 DATA "IM",k1,vn,im,70+8*n,f7,nn
  854 DATA "CP",k1,vn,ri,184+r,f2,vn,v1,254,f5,nn
  856 DATA "IN",2,sv,"A",bv1,219,f5,vs,ri,"(C)",64+8*r,f7,nn
  864 DATA "RL",k1,vn,ri,16+r,f3,nn
  868 DATA "JP",2,vv,cf,v2,194+8*r,f4,ss,"(HL)",233,f1,vn,402,233,f1,vn,v2,195,f4,nn
  878 DATA "JR",2,vv,cs,v2,32+8*r,f6,vn,v2,24,f6,nn
  888 DATA "OR",k1,vn,ri,176+r,f2,vn,v1,246,f5,nn
  894 DATA "RR",k1,vn,ri,24+r,f3,nn
  898 DATA "EX",2,sv,"(SP)",di,227,f1,ss,"AFAF'",8,f1,ss,"DEHL",235,f1,nn
  979 DATA "DAA",k0,39,f1
 1000 DATA "ADC",2,sv,"A",ri,136+r,f2,sv,"A",v1,206,f5,sv,"HL",dd,74+16*r,f7,nn
 1006 DATA "ADD",2,sv,"A",ri,128+r,f2,sv,"A",v1,198,f5,vv,di,dd,9+16*r,f1,nn
 1011 DATA "DEC",k1,vn,ri,5+8*r,f2,vn,ds,11+16*r,f1,nn
 1017 DATA "CCF",k0,63,f1
 1026 DATA "SBC",2,sv,"A",ri,152+r,f2,sv,"~",v1,222,f5,sv,"HL",dd,66+16*r,f7,nn
 1028 DATA "LDD",k0,168,f7
 1049 DATA "SCF",k0,55,f1
 1055 DATA "NEG",k0,68,f7
 1056 DATA "AND",k1,vn,ri,160+r,f2,vn,v1,230,f5,nn
 1058 DATA "LDI",k0,160,f7
 1062 DATA "RLA",k0,23,f1
 1064 DATA "SLA",k1,vn,ri,32+r,f3,nn
 1066 DATA "INC",k1,vn,ri,4+8*r,f2,vn,ds,3+16*r,f1,nn
 1070 DATA "CPD",k0,169,f7
 1072 DATA "IND",k0,170,f7
 1074 DATA "RLC",k1,vn,ri,r,f3,nn
 1080 DATA "RLD",k0,111,f7
 1092 DATA "RRA",k0,31,f1
 1094 DATA "SRA",k1,vn,ri,40+r,f3,nn
 1096 DATA "TRA",k1,op
 1099 DATA "REM",k1,op
 1100 DATA "CPI",k0,161,f7
 1102 DATA "INI",k0,162,f7
 1104 DATA "RRC",k1,vn,ri,8+r,f3,nn
 1110 DATA "RRD",k0,103,f7
 1115 DATA "SUB",k1,vn,ri,144+r,f2,vn,v1,214,f5,nn
 1118 DATA "CPL",k0,47,f1
 1129 DATA "BIT",2,vv,bn,ri,64+8*r1+r,f3,nn
 1135 DATA "RES",2,vv,bn,ri,128+8*r1+r,f3,nn
 1141 DATA "RET",k1,ss,"",201,f1,vn,cf,192+8*r,f1,nn
 1143 DATA "SET",2,vv,bn,ri,192+8*r1+r,f3,nn
 1159 DATA "NOP",k0,k0,f1
 1160 DATA "SRL",k1,vn,ri,56+r,f3,nn
 1163 DATA "POP",k1,vn,da,193+16*r,f1,nn
 1165 DATA "DEFB",k1,ps+2
 1191 DATA "XOR",k1,vn,ri,168+r,f2,vn,v1,238,f5,nn
 1205 DATA "DEFL",k1,ps+8
 1206 DATA "RLCA",k0,7,f1
 1211 DATA "RST",k1,vn,ra,199+n,f1,nn
 1215 DATA "OUT",2,vs,bv1,"A",211,f5,sv,"(C)",ri,65+8*r,f7,nn
 1219 DATA "CALL",2,vv,cf,v2,196+8*r,f4,vn,v2,205,f4,nn
 1228 DATA "LDDR",k0,184,f7
 1233 DATA "DEFS",k1,ps
 1234 DATA "EXX",k0,217,f1
 1236 DATA "RRCA",k0,15,f1
 1249 DATA "DEFW",k1,ps+4
 1258 DATA "LDIR",k0,176,f7
 1261 DATA "HALT",k0,118,f1
 1270 DATA "CPDR",k0,185,f7
 1272 DATA "INDR",k0,186,f7
 1300 DATA "CPIR",k0,177,f7
 1302 DATA "INIR",k0,178,f7
 1305 DATA "RETI",k0,77,f7
 1314 DATA "OTDR",k0,187,f7
 1325 DATA "RETN",k0,69,f7
 1334 DATA "DJNZ",k1,vn,v2,16,f6,nn
 1344 DATA "OTIR",k0,179,f7
 1359 DATA "OUTD",k0,171,f7
 1371 DATA "PUSH",k1,vn,da,197+16*r,f1,nn
 1377 DATA "TEXT",k1,ps+6
 1379 DATA "OUTI",k0,163,f7
 2000 LET insert= FN a(23637)+5
 2001 REM GO SUB Kv\*M\+FOR *r\FOR GO SUB LN <>x
 2004 RESTORE 2006:FOR z=insert TO insert+18:READ a:POKE z,a:NEXT z
 2005 RETURN 
 2006 DATA 237,75,118,92,42,77,92,9,43,235,42,114,92,25,235,237,184,3,201
 2010 REM spectrum assembler from Your Computer November   1983. Entered by F. Chrysler
 9998 CLEAR :SAVE "DEV-Assem" LINE 1:BEEP .2,0:PRINT FLASH 1;"VERIFY":VERIFY "":BEEP .2,0:PRINT "OK"

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