Archive de la Version 3.03 (ROM, DSK, chrmap7.bin)
NOTICE TEXTE n° 1 (249.31 Ko)
nolist
;**********************************************************
;* C H A M P *
;**********************************************************
; Home Computer Advanced Course/PSS Assembler/Monitor
;
; Ported from ZX Spectrum to CPC664 by Bruce Abbott in 1987
;
;------------------ Recent Changes -----------------------
; 2013-12-10 V2.0
; - Source code recovered from erased files on 3" disc,
; ported to WinApe.
; - Key for switching from assembler to debugger changed
; from 'M' to 'D'.
;
; 2013-12-20 V2.01
; - Changed several Debug command keys. Added C (catalog)
; and Q (quit).
;
; 2013-12-22 V2.02
; - Using custom font
; - Put into ROM
;
; 2013-12-26 V2.03
; - Added help screens
; - Faster source code scrolling in assemble mode
; - Faster symbol table display (not sorting entries!)
; - Automatically convert commands to upper case (no
; more forcing keyboard into Caps Lock!)
;
; 2013-12-29 V2.04
; - Some single key debug commands performed immediately
; 2013-12-31 V2.05
; - Accept lower case Hex digits
; 2014-01-01 V2.06
; - more Info
; - |RSX command
; - Dump memory command can show up to 12 bytes per row,
; not showing ASCII if more than 8 bytes per row (no
; room to display it!)
; 2014-01-03 V2.07
; - Debug commands don't print newline unless they want to.
; - Opcodes and register names automatically converted to
; uppercase. Now you can type everything in lowercase!
; - < debug > prompt not sent to printer.
; 2014-01-05 V2.08
; - single quote allowed inside string
; 2014-01-07 V2.09
; - All breakpoint functions now accessed via 'B'.
; - Added N (upper ROM select), X (RAM bank select).
; 2014-01-12 V2.10
; - new symbols reuse spare space in symbol table
; - Added < CLR > key (clears character under cursor)
; 2014-01-16 V2.10b
; - fixed corruption after load/save src with no filename
; - src code is checksummed on exit and re-entry. If code
; is corrupt then it will be wiped!
; 2014-01-17 V2.10c
; - for TFM; show alternate registers in debugger
; 2014-01-19 V3.00
; - Label size changed from 6 to 8 chars
; - Insert editing in comment and operand areas (overwrite
; editing still applied to label and opcode areas)
; - Cursor stops at opcode and operand columns when going
; left as well as right.
; 2014-01-28 V3.00b
; - No error when hitting < ESC > on blank line in < edit >
; - < ESC > from < insert > returns to < assemble >
; - Refactored to allow additinal directives
; - Added ENT directive (set code execution address)
; - Added INCB directive (load binary data from file)
; 2014-01-29 V3.00c
; - Command 'A' in < debug > switches immediately to < assemble >
; 2014-01-30 V3.00d
; - Added math operators *, /, and % (MOD)
; - Added directive WRI "filename"
; 2014-02-01 V3.00e
; - Register Display includes ASCII dump for regs BC~IY
; - Added directive STR (string with bit 7 set in last char)
; - Added directives REPT (repeat) and REND (repeat end)
; - Added directive '=' (assign temporary value to label)
; 2014-02-02 V3.01
; - Insert editing in comments only
; - CTRL-I inserts < space > at cursor
; - CTRL-X/C/V = cut/copy/paste line
; 2014-02-03 V3.01a
; - Fixed stack corruption when using CTRL-X
; 2014-02-03 V3.01b
; - showing paste buffer contents on bottom line
; 2014-02-05 V3.01d
; - IF, ELSE, ENDF
; 2014-02-06 V3.01e
; - extra symbol flag to track labels found in inactive
; code
; - nested IF statements
; 2014-02-07 V3.02
; - IFD
; - added logical math operators "< ", " >" and "="
;
; 2014-02-15 V30.2a
; - fixed bug that appeared in V3.00; breakpoints 2~8
; not working.
; - Removed CTRL-I (insert space). Replaced with insert/
; overwrite edit mode toggle.
; - < COPY > toggles between overwrite and insert editing.
; - Insert editing indicated by fast flashing cursor.
; - CTRL-Z, CTRL-W = CTRL-U; undo changes on edit line.
;
; 2014-02-26 V3.03
; - Plain text (ASCII) src code files can now be loaded,
; and are automatically translated into CHAMP tokenized
; asm format. Any line that doesn't pass syntax checking
; will be converted to a comment.
; - Asm source code is saved as plain text (ASCII, AMSDOS
; type A) if the filename extension is ".a" or ".i".
; - Import txt file; inserts ASCII text file into src code.
; - Both & and # are accepted when entering Hex numbers.
; - Hex numbers can be shown starting with # instead of &.
; - Decimal numbers may be typed into the src code (they
; are converted to Hexadecimal as each line is entered)
; - ORG can take a symbolic address argument
; - Tweaks to improve compatibility with foreign src code
;
; ------------------------ to do --------------------------
; - Implement fast scrolling in edit mode.
; - Run-time memory allocation.
;
;-------------------- Assembly Options --------------------
;HASH EQU 1 ; Hex numbers start with #
; ------------------------ Macros -------------------------
; undocumented opcodes!
; Shift Left and Set bit 0
MACRO SLLH
DB &CB,&34
ENDM
MACRO SLLC
DB &CB,&31
ENDM
;----------------------- constants ------------------------
;
LAB_SIZE EQU 8 ; length of label (symbol name)
SYM_SIZE EQU LAB_SIZE+2 ; size of symbol in symbol table
LINE_SIZE EQU 40 ; length of line on screen
;==========================================================
; MEMORY ALLOCATION
;==========================================================
; defines memory areas used for source code, symbol table,
; file buffer.
; Himem at &07FF, for large src code files! (28k, 5000+ lines)
SRCBUF EQU &0800 ; source code
SYMBUF EQU &5000 ; symbol table
SYMEND EQU &77FF ; end of symbol table
FILBUF EQU &7800 ; 2k buffer for CAS_CAT
FILEND EQU &7FFF
; Himem at &3FFF, for medium size src code files (< 10k).
; Fits inside a single 16k RAM page, so it can be BANK
; switched out when not using the assembler!
;SRCBUF EQU &4000 ; source code
;SYMBUF EQU &6800 ; symbol table
;SYMEND EQU &77FF ; end of symbol table
;FILBUF EQU &7800 ; 2k buffer for CAS_CAT
;FILEND EQU &7FFF
; memory from &8000 to &9FFF is free for use by machine
; code programs etc.
ORG &A000
;----------------------------------------------------------
; Code in RAM
;
ram_start
IRAM
PRTCHR DS 3 ; JP _prtchr
PEEK DS 3 ;; JP _peek or LD A,(HL) : RET
; Breakpoint code
L8CE0 DS 1 ; CALL xxxx ("." = proceed)
L8CE1 DS 2 ; target address of CALL xxxx
L8CE3 DS 3 ; CALL Break
TraceOp DS 1 ; Opcode being traced
L8CE7 DS 3 ; "" ""
TraceBrk DS 3 ; CALL Break
L8CED DS 3 ; JP Debug
; code to select and read a ROM
ReadROM DS 6
;-----------------------------------------------------------
; Variables in RAM
;
; option bits (IY+1)
; 7 = write object code to file after assembly
; 3 = asm/debug printer on/off
; 2 = assembler symbol table listing
; 1 = assembler object code write to RAM
; 0 = assembler output listing
;
;; NOTE: some (IY+nn) are temporary variables, so documented
; usage may not apply to all code!
;
Variables DS 1 ; IY+0 asm flags,
DS 1 ; IY+1 assembly option bits
DS 1 ; IY+2
DS 1 ; IY+3 number of hex bytes in listing
DS 1 ; IY+4
DS 1 ; IY+5
DS 1 ; IY+6 opcode (eg. CB,DD,FD)
DS 1 ; IY+7 opcode length
DS 1 ; IY+8
DS 1 ; IY+9 opcode offset
DS 1 ; IY+&0A
DS 1 ; IY+&0B
DS 1 ; IY+&0C highest active IF/ENDF nesting level
DS 1 ; IY+&0D current IF/ENDF nesting level
DS 1 ; IY+&0E asm IF flags, edit
DS 1 ; IY+&0F edit flags (bit 0 = < edit >/< insert >)
DS 1 ; IY+&10 temp
ArgC DS 1 ; IY+&11 number of arguments found
Arg1 DS 2 ; IY+&12,13 command line argument #1
Arg2 DS 2 ; IY+&14,15 command line argument #2
Arg3 DS 2 ; IY+&16,17 command line argument #3
Digits DS 1 ; IY+&18 digits in 16 bit number
Number DS 2 ; IY+&19,1A 16 bit number (hex/dec)
TXT_POS DS 1 ; IY+&1B text position, column (0-39)
TXT_ROW DS 1 ; IY+&1C '' ,row (0-25)
TXT_STYLE DS 1 ; IY+&1D text rendering styles
L69A7 DS 2 ; object code address offest
SymTab DS 2 ; start of symbol table memory
Temp1 DS 2 ; temp
src_code DS 2 ; start of source code memory
asm_PC DS 2 ; asm program counter / code address
asm_line DS 2 ; asm src code line number
Temp2 DS 2 ; temp
SrchStrEnd DS 2 ; end of search string
sym_end DS 2 ; end of symbol table memory
PrtStrAddr DS 2 ; current address in 'print to string' buffer
SrchLen DS 2 ; asm search phrase length
Temp3 DS 2 ; temp
CodeAddr DS 2 ; opcode address in asm src line
Temp4 DS 2 ; temp
SrcAddrDe DS 2 ; src code address - update line
SrcAddrEd DS 2 ; src code address - edit line
SlotNum DS 2 ; index number of spare symbol slot
BrkAddr DS 2 ; address of current breakpoint
Alt_regs ; alternate registers
AF_alt DS 2 ; AF'
BC_alt DS 2 ; BC'
DE_alt DS 2 ; DE'
HL_alt DS 2 ; HL'
CPU_Regs ; CPU register values
AF_reg DS 2 ; AF
BC_reg DS 2 ; BC
DE_reg DS 2 ; DE
HL_reg DS 2 ; HL
IX_reg DS 2 ; IX
IY_reg DS 2 ; IY
SP_reg DS 2 ; SP
PC_reg DS 2 ; PC
RAM_Bank DS 1 ; current RAM bank selection
Bug_Bank DS 1 ; Debug RAM bank selection
Upper_ROM DS 1 ; Selected uppper ROM
CHAMP_ROM DS 1 ; CHAMP's ROM number
STACK DS 2 ; Stack Pointer at entry/exit
ASM_CMD DS 1 ; current < assemble > command
SCROLL DS 1 ; asm src text needs scrolling
KeyCode DS 1 ; 'cooked' code of key pressed
src_sum DS 2 ; 16 bit checksum of src code and symbols
EntAddr DS 2 ; object code entry address
WritAddr DS 2 ; object code file write start address
ObjName DS 2 ; pointer to object code filename
reptaddr DS 2 ; address of line with REPT
reptnum DS 2 ; number of repeats
;
; Buffers
;
LineBuffer DS LINE_SIZE ; command line input
LineBufEnd DS 1 ; null
EditBuffer DS LINE_SIZE ; asm edit/insert input
EditBufEnd DS 1 ; null
SymBuff DS 2 ; symbol buffer (value field)
SymName DS LAB_SIZE ; '' (name field)
Breakpoints DS 8*6 ; 8 breakpoints (addr + code)
SearchStr DS LINE_SIZE ; search string input
SearchStrEnd DS 1 ; null
line_buf3 DS LINE_SIZE+1 ; temporary line buffer
line_buf3End DS 1 ; null
PasteBuffer DS LINE_SIZE ; buffer for cut/copy/paste
PastebufEnd DS 1 ; null
; --- line_buf3 usage ---
; (asm) stores src code when parsing edit line
; (debug) search buffer
ram_end
; Breakpoint structure
; offset function
; 0 = status (1=active, 0=inactive)
; 1~2 = code address
; 3~5 = original code (overwritten by CALL Break)
;-----------------------------------------------------------
; Code in ROM
;
; WRITE DIRECT -1,1 ; write code to emulator memory, ROM #1
WRITE "CHAMP.ROM" ; write code to disk
ORG &C000
DB 1 ; 1 = background ROM
DB 3,0,2 ; version, mark, revision
DW _rsx_names
JP _init
JP _cold
JP _warm
JP _bug
_rsx_names
STR "CHAMP ROM" ; ROM name
STR "CHAMP" ; main entry
STR "CHA" ; re-enter assembler (retains data)
STR "CHD" ; re-enter debugger (retains data)
DB 0
_init SCF
RET
;
;- COLD START -
;
_cold LD HL,Variables
LD DE,Variables+1
LD BC,ram_end-ram_start-1
LD (HL),0
LDIR ; clear all RAM used
LD HL,SYMBUF
LD (SymTab),HL
LD HL,SRCBUF
LD (HL),3 ; src code length = 3 bytes
INC HL
LD (HL),0
INC HL
LD (HL),0 ; 1st line is empty
LD (src_code),HL
INC HL
LD (asm_line),HL ; src code line #1
LD HL,SYMEND
LD (sym_end),HL
LD HL,IDATA
LD DE,IRAM
LD BC,_idata_end-IDATA
LDIR ; copy initilization data to RAM
CALL &B912 ; KL_CURR_SELECTION
LD (CHAMP_ROM),A ; remember what ROM we are!
LD A,-1 ; -1 = no upper ROM selected
LD (Upper_ROM),A ; select upper ROM to view
LD HL,(SymTab)
CALL MarkSymEnd ; clear symbol table
CALL ChkSrc ; init source code checksum
LD (src_sum),DE
;
;- WARM START -
;
_warm LD (STACK),SP
CALL &BB48 ; KM_DISARM_BREAK
CALL InitScreen
_asm LD HL,asm_help_txt
CALL ShowHelp ; show help text in r/h window
LD HL,&0119 ; window cursor below help text
CALL &BB75 ; TXT_SET_CURSOR
LD HL,(src_code)
DEC HL
LD A,(HL)
OR A ; src code length > 256 bytes?
JR NZ,_check_src ; yes, check it
DEC HL
LD A,(HL)
OR A ; src code length = 0?
JP Z,_cold ; yes, memory wiped!
_check_src
CALL ChkSrc ; calculate source code checksum
LD HL,(src_sum)
OR A
SBC HL,DE ; compare to saved checksum
LD A,H
OR L
JP Z,ASSEMBLER ; if match then OK so < Assemble >
LD HL,&1600
LD (TXT_POS),HL
CALL PRTMSG
DB "Source code corrupted!!!",&0D
DB "Press any key to restart",0
CALL Waitkey
JP _cold ; cold start
_bug LD (STACK),SP
CALL &BB48 ; KM_DISARM_BREAK
CALL InitScreen
JP DEBUGGER
;
; ASM commands
;
asm_commands
DB &0A ; CTRL+J = DOWN
DW ASM_CSR_DOWN
DB &0B ; CTRL+K = UP
DW ASM_CSR_UP
DB &0D ; < CR >
DW EDIT
DB &F8 ; CTRL+UP
DW CTRL_UP
DB &F9 ; CTRL+DOWN
DW CTRL_DOWN
DB &F5 ; SHIFT+DOWN
DW PAGE_DOWN
DB &F4 ; SHIFT+UP
DW PAGE_UP
DB "D" ; Debug
DW Debug
DB "A" ; Assemble < option >
DW Assemble
DB "F" ; Find < string >
DW FindText
DB "N" ; Next (find)
DW NextText
DB "P" ; Print < expression >
DW PrintExpr
DB "S" ; Save < filename >
DW SAVE_ASM
DB "L" ; Load < filename >
DW LOAD_ASM
DB "C" ; Catalog disc/tape
DW CAT
DB "I" ; Import ASCII src code
DW IMPORT_ASM
DB "Q" ; Quit < Y >
DW QUIT
DB &00
;
; DEBUG commands
;
debug_commands
DB "A" ; switch to Assembler
DW _asm
DB "E" ; Edit memory one byte at a time
DW EditMem
DB "@" ; synonym for E
DW EditMem
DB "D" ; Dump memory in Hex and ASCII
DW DumpMem
DB "I" ; Information
DW Info
DB "N" ; Upper ROM Number
DW SetROM
DB "H" ; Hex, decimal, binary representation of expr
DW HexExp
DB "X" ; eXtended RAM bank selection
DW SetRAM
DB "B" ; View/Set/Kill breakpoint
DW SetBreak
DB "U" ; Unasassemble
DW Unassemble
DB "F" ; Fill memory with byte value
DW FillMem
DB "M" ; Move memory (copy block)
DW MoveMem
DB "R" ; Display/Edit CPU Registers
DW Registers
DB "S" ; Search
DW SearchMem
DB "." ; Proceed (call subroutine)
DW Proceed
DB "G" ; Goto address (non-returning)
DW Go
DB "T" ; Trace instructions (single step)
DW Trace
DB "W" ; Write memory to file
DW DebugWrite
DB "P" ; printer on/off
DW PrinterOnOff
DB "L" ; Load memory from file
DW DebugLoad
DB "C" ; Catalog disc/tape
DW CAT
DB "|" ; RSX command
DW RSX
DB "Q" ; Quit
DW _quit
DB &00
;----------------------------------------------------------
; Checksum Source Code and Symbol Table
;
;; out: DE = checksum
;
ChkSrc LD HL,(Src_Code)
DEC HL
LD B,(HL) ; B = src code length high byte
DEC HL ; HL = start of source code memory
LD C,(HL) ; C = src code length low byte
LD DE,0 ; DE = checksum
CALL _checksum
; check symbol table
CALL SymTabEnd ; HL - > end of symbol table
LD BC,(SymTab)
OR A
SBC HL,BC ; subtract end from start
LD C,L
LD B,H ; BC = length of symbol table
LD HL,(SymTab)
CALL _checksum
RET
;----------------------------------------------------------
; Calculate 16 bit Checksum of Memory Block
;
;; in: HL- > start address
; BC = count
; DE = initial checksum
;
;; out: DE = new checksum
; HL - > next byte
;
_checksum
LD A,C
OR A ; low count = zero?
JR Z,_cka ; no, adjust high count
INC B
_cka LD A,E ; A = checksum low byte
_ckloop
ADD A,(HL) ; add byte to checksum
JR NC,_ckc
INC D ; 16 bit add
_ckc INC HL ; next byte
DEC C
JR NZ,_ckloop ; next count (low)
DJNZ _ckloop ; "" (high)
LD E,A ; E = checksum low byte
RET
;----------------------------------------------------------
; Set screen mode, window, colours
;
InitScreen
LD A,2
CALL &BC0E ; SCR_SET_MODE
LD A,0
LD B,1
LD C,1
CALL &BC32 ; SCR_SET_INK
LD A,1
LD B,26
LD C,26
CALL &BC32 ; SCR_SET_INK
LD B,0
LD C,0
CALL &BC38 ; SCR_SET_BORDER
LD H,40
LD L,0
LD D,80
LD E,25
JP &BB66 ; TXT_WIN_ENABLE
;----------------- This Code in RAM! ----------------------
;ReadROM
; OUT (C),A ; select ROM
; LD A,(HL) ; read ROM
; OUT (C),C ; restore original selection
; RET
;----------------------------------------------------------
; Read Byte from memory (Base RAM, Expanded RAM, ROM)
;
_peek PUSH HL
PUSH BC
LD A,(RAM_Bank) ; get bank read selection
AND &0F
JR NZ,peek1 ; if expanded RAM then bank switch
LD A,H ; else reading base memory
CP &C0 ; in ROM area?
LD A,(HL) ; read RAM or CHAMP ROM
JR C,_peek0done ; if RAM then all done
LD A,(CHAMP_ROM)
LD C,A ; C = current ROM selected (CHAMP)
LD A,(Upper_ROM) ; get ROM selection
CP 16 ; valid upper ROM?
JR C,_read_upper_rom
CALL &0020 ; no, read screen via RAM_LAM
JR _peek0done
_read_upper_rom ; yes, select and read the ROM
LD B,&DF ; B = port for ROM selection
DI
CALL ReadROM ; read ROM from code in RAM
EI
_peek0done
POP BC
POP HL
RET
;
peek1 RLCA ; skip 'special' bank selections
SLA H
RLA ; banksel bit 1 = addr bit 15
SLLH ; bit 0 set (&4000~&7FFF)
RLA ; banksel bit 0 = addr bit 14
RRC H
RRC H
ADD A,&C0-4 ; bank 2 = &CC, bank 3 = &D4 etc.
LD BC,&7FC0
DI
OUT (C),A ; select RAM bank at &4000~&7FFF
LD A,(HL) ; get byte
OUT (C),C ; select base RAM
EI
POP BC
POP HL
RET
;----------------------------------------------------------
; - POKE - Write byte to Memory Bank
;
POKE PUSH HL
PUSH BC
PUSH AF
LD A,(RAM_Bank)
RRCA
RRCA
RRCA
RRCA ; get bank write selection
AND &0F
JR NZ,poke1 ; if not base RAM then bank switch
POP AF
LD (HL),A ; else just poke byte into base RAM
POP BC
POP HL
RET
;
poke1 RLCA ; * 2 to skip 'special' banks
SLA H ; shift left and reset bit 0
RLA ; addr bit 15 - > A
SLLH ; shift left and set bit 0
RLA ; addr bit 14 - > A
RRC H
RRC H ; HL = &4000 + addr bits 13~0
ADD A,&C0-4 ; bank 2 = CC, bank 3 = D4 etc.
LD BC,&7FC0
DI
OUT (C),A ; select page of expansion RAM
POP AF ; (appears at &4000~&7FFF)
LD (HL),A ; poke byte into expansion RAM
OUT (C),C ; restore bank select to base RAM
EI
POP BC
POP HL
RET
;----------------------------------------------------------
; - Show Help Screen -
;
;; input: HL = pointer to text
;
ShowHelp
LD DE,&C028 ; DE = screen position
LD BC,MATRIX ; BC = character matrix
JR _sh_line
_sh_chr
CP "~"
JR NZ,_notdot ; change "~" to graphic dot
LD A,&10
_notdot
PUSH HL
CALL txt2scr ; display char on screen
POP HL
INC DE ; screen addr = next char on row
INC HL ; next char
LD A,(HL) ; A = char
OR A ; null?
JR NZ,_sh_chr ; no, show it
POP DE ; restore position at start of row
LD A,E
ADD 80 ; + 80 = next row
LD E,A
JR NC,_sh_dwn
INC D
_sh_dwn
INC HL
_sh_line
PUSH DE ; save position at start of row
LD A,(HL) ; get 1st char in string
OR A ; null?
JR NZ,_sh_chr ; no, show string
POP DE ; yes, quit
RET
;----------------------------------------------------------
; - Show Character Matrix on Screen -
;
;; input: A = char, BC = matrix array, DE = screen address
;
txt2scr
LD H,0
LD L,A
ADD HL,HL
ADD HL,HL ; HL = char * 8 (bytes in matrix)
ADD HL,HL
ADD HL,BC ; HL = address of matrix for this char
repeat 7
LD A,(HL) ; get byte from matrix
LD (DE),A ; copy to screen
INC HL ; next matrix byte
LD A,D
ADD 8
LD D,A ; next screen address (1 row down)
rend
LD A,(HL) ; get last matrix byte
LD (DE),A ; copy to screen
LD A,D
SUB 8*7
LD D,A ; restore screen address
RET
;----------------------------------------------------------
; - RSX -
;
RSX CALL Prt_CR
LD DE,LineBuffer
CALL Get_Alpha
INC DE ; skip "|"
LD H,D
LD L,E
LD A,(HL)
CP " "+1 ; rsx name present?
RET C
rloop INC HL
LD A,(HL) ; get next character of name
CP " "+1
JR NC,rloop ; unti end
DEC HL
SET 7,(HL) ; set bit of last char
LD H,D
LD L,E ; HL - > rsx name
XOR A
CALL &BCD4 ; KL_FIND_COMMAND
RET NC
XOR A
JP &001B ; KL_FAR_PCHL
;----------------------------------------------------------
; - Fill Memory -
;
FillMem
CALL Prt_CR
LD A,(ArgC)
CP 3
JP NZ,ErrorMsg
CALL GetArgs ; HL= start, DE = end, BC = fillbyte
PUSH HL
OR A
EX DE,HL
SBC HL,DE
EX DE,HL
POP HL
INC DE
fill LD A,C
CALL POKE
INC HL
DEC DE
LD A,D
OR E
JR NZ,fill
RET
;----------------------------------------------------------
; - Move Memory -
;
MoveMem
CALL Prt_CR
LD A,(ArgC)
CP 3 ; must have 3 args!
JP NZ,ErrorMsg
LD HL,(Arg2) ; end
LD DE,(Arg1) ; start
OR A
SBC HL,DE
LD B,H
LD C,L ; BC = length
INC BC
LD HL,(Arg3) ; dest
EX DE,HL
OR A
SBC HL,DE
ADD HL,DE
JR NC,ldir0 ; if dest < start then LDIR
DEC BC
lddr0 EX DE,HL ; else LDDR
ADD HL,BC
EX DE,HL
ADD HL,BC
INC BC
lddr1 CALL PEEK
EX DE,HL
CALL POKE
EX DE,HL
DEC HL
DEC DE
DEC BC
LD A,B
OR C
JR NZ,lddr1
RET
ldir0 CALL PEEK
EX DE,HL
CALL POKE
EX DE,HL
INC HL
INC DE
DEC BC
LD A,B
OR C
JR NZ,ldir0
RET
;-------------------------------------------------
; - Wait for Key Press -
;
WaitKey
CALL InKey
JR NC,WaitKey
RET
;-------------------------------------------------
; - Convert Lowercase to Uppercase -
;
; in-out; A = char
;
ToUpper
CP 97 ; >='a'?
RET C
CP 123 ; < ='z'?
RET NC
SUB &20 ; a-z - > A-Z
RET
;------------------------------------------------
; Print String to Screen
;
_prtstr
LD A,(HL) ; get char
INC HL ; point to next char
OR A ; end of string?
RET Z ; yes
CALL _prtchr ; no, print the char
JR _prtstr ; next char
;
; ---------------- Print Message ----------------
;
; Literal string embedded in code, directly after
; call to this function!
;
PRTMSG EX (SP),HL ; HL = return address
L6D00 LD A,(HL) ; get char
INC HL ; point to next char
OR A ; end of string?
JR Z,L6D0A ; yes
CALL PRTCHR ; no, print the char
JR L6D00 ; next char
L6D0A EX (SP),HL ; skip over message
RET ; and return
;-----------------------------------------------
; - Print Word in HL as 4 Hex digits -
;
PrtsHexWord
CALL prt_space ; leading space
PrtHexWord
LD A,H
CALL prt_byte ; upper byte
LD A,L
CALL prt_byte ; lower byte
prt_space
LD A," "
JP PRTCHR ; trailing space
;-----------------------------------------------
; - Print Byte in A as 2 Hex digits -
;
prt_byte
PUSH AF
RRA
RRA ; get upper nybble
RRA
RRA
CALL prt_hex ; print it
POP AF ; get lower nybble
prt_hex
AND &0F ; select nybble
ADD A,&30
CP &3A ; A-F ?
JR C,_prt_hex_done
ADD A,7 ; yes,
_prt_hex_done
JP PRTCHR
;----------------------------------------------------------
; Get symbol name and value
;
; in; HL = symbol
; out; HL - > name
; DE = value
; Z = end of table
;
GetSymbol
LD D,(HL)
INC HL
LD E,(HL) ; DE = value
INC HL
LD A,D
AND E ; combine D & E & First letter of name
AND (HL)
INC A ; Z if all 3 bytes are $FF
RET
;----------------------------------------------------------
; - Calculate Address of Symbol in Table -
;
;; in: HL = symbol number (0~1023)
;; out: HL = address of symbol in array
;
ifnot SYM_SIZE-8
IndexSym
PUSH DE
LD DE,(SymTab)
ADD HL,HL
ADD HL,HL ; * 8
ADD HL,HL
ADD HL,DE ; + base address
POP DE
RET
endif
ifnot SYM_SIZE-10
IndexSym
PUSH DE
LD D,H
LD E,L
ADD HL,HL
ADD HL,HL ; * 4
ADD HL,DE ; * 5
ADD HL,HL ; * 10
LD DE,(SymTab)
ADD HL,DE ; + base address
POP DE
RET
endif
;----------------------------------------------------------
; Decode Opcode
;
;; in: HL- > code memory
;
;; out: C bit 7 set = has 16 bit number
; 6 set = has 8 bit number
; 5 set = has 8 bit PC-relative offset
; 4
; 3
; 2~0 = number of opcode bytes
;
;
Decode LD C,2 ; assume no args, 2 bytes
CALL PEEK ; get opcode byte
CP &FD
JP Z,L6DA0
CP &DD
JP Z,L6DA0
CP &ED
JR NZ,L6D60
; ED
INC HL
CALL PEEK ; get next opcode byte
AND &C7
CP &43 ; LD (nn)rr, LD rr,(nn)
RET NZ
LD C,&84 ; 16 bit number, 4 bytes
RET
; not FD/DD/ED
L6D60 CP &CB ; CB
RET Z
; base opcode
LD C,&42 ; 8 bit number, 2 bytes
CP &D3 ; OUT(n),A
RET Z
CP &DB ; IN A,(n)
RET Z
AND &C7
CP 6 ; LD r,n
RET Z
CP &C6 ; ADDA n
RET Z
LD C,&83 ; 16 bit number, 3 bytes
CALL PEEK ; get opcode byte again
CP &C3 ; JP
RET Z
CP &CD ; CALL nn
RET Z
AND &E7
CP &22 ; LD (nn),HL etc.
RET Z
CALL PEEK ; get opcode byte again
AND &CF
CP 1 ; LD BC,nn
RET Z
AND &C7
CP &C2 ; JP CC,nn
RET Z
CP &C4 ; CALL CC,nn
RET Z
LD C,&22 ; 8 bit offset, 2 bytes
CALL PEEK ; get opcode byte again
CP &10 ; DJNZ d
RET Z
CP &18 ; JR d
RET Z
AND &E7
CP &20 ; JR CC, d
RET Z
LD C,1 ; else no number, 1 byte
RET
; FD/DD
L6DA0 LD C,&43 ; 8 bit number, 3 bytes
INC HL
CALL PEEK ; get next opcode byte
CP &34 ; INC (IX+d)
RET Z
CP &35 ; DEC(IX+d)
RET Z
AND &C7
CP &46 ; LD r,(IX+d)
RET Z
CP &86 ; ADD A,(IX+d)
RET Z
CALL PEEK ; get opcode byte again
AND &F8
CP &70 ;
RET Z
LD C,&44 ; 8 bit number, 4 bytes
CALL PEEK ; get opcode byte again
CP &36 ; LD (IX+d),n
RET Z
CP &CB ; CB
RET Z
LD C,&84 ; 16 bit number, 4 bytes
CP &21 ; LD IX,nn
RET Z
AND &E7
CP &22 ; LD (nn),IX etc.
RET Z
LD C,2 ; no number, 2 bytes
RET
;----------------------------------------------------------
; Goto End of Symbols
;; in: HL - > start of symbols
;; out: HL - > next byte after end of table marker
; HL not set
SymTabEnd
LD HL,(SymTab)
; HL already pointing to symbols
EndSym LD BC,SYM_SIZE ; BC = bytes per symbol
INC HL
INC HL ; skip value
LD A,&FF
JR _es_start
_es_nxt ADD HL,BC
_es_start
CP (HL) ; 1st char of name = &FF?
JR NZ,_es_nxt ; no, test next symbol name
INC HL ; yes, point past end
RET
;----------------------------------------------------------
; - Info -
;
Info CALL Prt_CR
CALL CmdLine
CALL PRTMSG
DB "Source Code ",&00
LD HL,(src_code)
DEC HL
DEC HL
CALL PrtsHexWord
LD HL,(SymTab)
DEC HL
CALL PrtHexWord
CALL calc_src_end
CALL PrtHexWord
CALL Prt_CR
CALL PRTMSG
DB "Symbol Table ",&00
LD HL,(SymTab)
CALL PrtsHexWord
LD HL,(sym_end)
CALL PrtHexWord
CALL SymTabEnd
CALL PrtHexWord
CALL Prt_CR
CALL PRTMSG
DB "File Buffer ",&00
LD HL,FILBUF
CALL PrtsHexWord
LD HL,FILEND
CALL PrtHexWord
CALL Prt_CR
CALL PRTMSG
DB "Variables ",&00
LD HL,ram_start
CALL PrtsHexWord
LD HL,ram_end-1
CALL PrtHexWord
CALL Prt_CR
CALL PRTMSG
DB "HIMEM ",&00
LD HL,(&AE5E)
CALL PrtsHexWord
CALL Prt_CR
;
PRTBNK CALL PRTMSG
DB "64k bank write ",&00
LD A,(RAM_Bank)
PUSH AF
RRA
RRA
RRA
RRA
AND &0F
CALL prt_hex
CALL PRTMSG
DB ", read ",&00
POP AF
AND &0F
CALL prt_hex
JP Prt_CR
;-------------------------------------------------------
; - Print Carriage Return (newline) -
;
Prt_CR LD A,&0D
JP PRTCHR
;-------------------------------------------------------
; - Calculate End of Source Code -
;
;; out: HL = end of source code
;
calc_src_end
PUSH DE
LD HL,(src_code)
DEC HL
LD D,(HL)
DEC HL
LD E,(HL) ; DE = length of source code
ADD HL,DE ; HL = end of source code
POP DE
RET
;--------------------------------------------------------
; Update Source Code Length
;
;; in: HL - > end of source code
;
; Source code starts with a 16 bit variable which specifies
; the length of the following code. The variable 'src_code'
; points to the start of the following source code.
;
UpdateSrcLen
PUSH DE
PUSH AF
LD DE,(src_code)
DEC DE
DEC DE ; get length of source code
OR A
SBC HL,DE ; src code end - src code start
EX DE,HL
LD (HL),E ; update code length (low byte)
INC HL
LD (HL),D ; update code length (high byte)
POP AF
POP DE
RET
;---------------------------------------------------------
; Determine if byte should be shown as a char or hex
;
;; in: A = char/byte, D = directive (bit 6 set = string)
;; Out: C if hex, NC if ascii
;
;; NOTE: called only if directive is DB or STR
;
ASC_HEX BIT 5,D ; STR?
JR NZ,_nots
AND &7F ; yes, 7 bit ASCII
_nots CP '"' ; show quote as hex byte
SCF
RET Z
BIT 6,D ; bit 6 set = string, else hex bytes
RET Z
CP " " ; show control code as hex byte
RET C
CP &7F ; show 8 bit char as hex byte
CCF
RET
;---------------------------------------------------------
; - Print Label -
; in; HL = label number
;
Prt_Label
CALL IndexSym ; get label's address in symbol table
INC HL
INC HL
Prt_Symbol_Name
PUSH BC
LD B,LAB_SIZE ; B = number of chars in name
_psnxt LD A,(HL)
INC HL
AND &7F
CALL PRTCHR ; print label name
DJNZ _psnxt
POP BC
RET
;----------------------------------------------------------
; Print Symbol Name
;
; if symbol is math function then
; print symbol/number +/- symbol/number
;
PrtSymbol
CALL IndexSym ; get address of symbol
INC HL
INC HL ; skip over value
PrtSymbolName
LD A,(HL) ; get 1st char of name
INC HL
AND &7F
CP "A" ; math function?
JP C,_ps_math ; yes,
; named symbol
LD B,LAB_SIZE ; B = number of chars to print
_prt_sym_name
CP " "
CALL NZ,PRTCHR ; print char, absorbing spaces
LD A,(HL) ; get next char
INC HL
DJNZ _prt_sym_name
RET
; two symbols and/or constants added or subtracted
_ps_math
OR A
RET Z ; return if null (no math)
PUSH AF
CALL _ps_arg ; print 1st label/constant
POP AF
CALL PRTCHR ; print math operator
_ps_arg
PUSH DE
LD A,(HL) ; get type (symbol/constant)
INC HL
LD D,(HL)
INC HL ; get value
LD E,(HL)
INC HL
OR A ; symbol?
JR Z,_ps_c ; no,
EX DE,HL
CALL PrtSymbol ; print symbol name (recursive!)
EX DE,HL
JR _ps_done
_ps_c CALL PrtNum ; print constant value
_ps_done
POP DE
RET
;
; Page Down
;
PAGE_DOWN
LD A,21 ; 21 lines
ADD A,E
LD E,A
LD A,D ; src line number + A
ADC A,0
LD D,A
RET
; ASM Cursor Down
ASM_CSR_DOWN
LD B,1
CALL SCROLL_SRC ; scroll up
LD A,1
LD (SCROLL),A ; we have scrolled up!
;
; Cursor Down
;
CSR_DOWN
INC DE
RET
;----------------------------------------------------------
; - Scroll Source Code Window Up or Down by One Line -
;
; Input; B = direction, 1 = up, 0 = down
;
; The last/first line will be blanked, and so must be
; refreshed when displaying the page. Other lines do
; not have to be refreshed.
;
; Compared to the original code (which always refreshed
; the entire page) using SCR_SW_ROLL is twice as fast.
;
SCROLL_SRC
PUSH HL
PUSH DE
LD HL,0 ; left/top = 0/0
LD DE,&2715 ; right/bottom = 39/21
LD A,0
CALL &BC50 ; SCR_SW_ROLL
POP DE
POP HL
RET
;
; Page Up
;
PAGE_UP
LD A,21 ; subtract 21 from src line number
JR _csr_up
; ASM Cursor Up
ASM_CSR_UP
LD A,D
CP 0
JR NZ,_not1st
LD A,E
CP 2
JR C,_firstline
_not1st
LD B,0
CALL SCROLL_SRC ; scroll src window down
LD A,2
LD (SCROLL),A ; we have scrolled down!
;
; Cursor Up
;
CSR_UP DEC DE ; src line number -1
LD A,D
OR E
JR Z,_firstline
RET
_csr_up
LD C,A
LD A,E
SUB C
LD E,A
LD A,D ; subtract A from DE
SBC A,0
LD D,A
JP M,_firstline
OR E
RET NZ
_firstline
LD DE,1
RET
;-----------------------------------------------------------
; Line Number - > Source Code Address
;
; Input; DE = target line number
; Output; HL = source code address
; DE = number of lines found
;
line2addr
PUSH BC
LD B,D ; BC = line number
LD C,E
LD DE,0 ; DE = line number 0
LD HL,(src_code); HL = start of src code
_l2a_nextline
INC DE ; DE = next line number
LD A,(HL)
OR A ; end of src code?
JR Z,_l2a_done ; yes, quit
LD A,E
CP C ; at target line number?
JR Z,_l2a_cmp ; maybe,
_l2a_skip
LD A,(HL) ; no, get length of this line
AND &3F
ADD A,L
LD L,A ; add to HL (skips to next line)
JR NC,_l2a_nextline
INC H ; 16 bit add
JR _l2a_nextline
_l2a_cmp
LD A,D
CP B
JR NZ,_l2a_skip
_l2a_done
POP BC
RET
; compare HL - BC
CmpHL2BC
PUSH HL
OR A
SBC HL,BC
POP HL
RET
;----------------------------------------------------------
; get address of next src code line
;
;; in: HL = address of src code line
;; out: HL = address of next src code line
;
; 1st byte holds flags (bits 7~6) and length (bits 5~0).
; Line can be up to 63 bytes long.
;
; Length 0 = end of src code.
;
next_src
LD A,(HL) ; get length of this line
AND &3F
ADD A,L
LD L,A ; add to pointer (skip to next line)
RET NC
INC H ; 16 bit add
RET
;----------------------------------------------------------
; Show Bytes and/or ASCII String
;
;; in: B = number of bytes/chars
; D = directive, bit 6 set if ascii string
;
bs_nextb
LD A,","
CALL PRTCHR ; print comma between hex bytes
ByteString
LD A,(HL) ; get byte
CALL ASC_HEX ; ascii or hex?
JR NC,bs_ascii ; if NC then ascii
CALL PrtHexByte ; else print hex byte
INC HL
DJNZ bs_nextb ; next byte
JR bs_done ; done
bs_ascii
LD A,'"'
CALL PRTCHR ; print opening quote
bs_nextc
LD A,(HL)
CALL ASC_HEX ; ascii or hex?
JR C,bs_hex ; if C then hex
CALL PRTCHR ; else print ascii char
INC HL
DJNZ bs_nextc ; next char
bs_hex LD A,'"' ; print closing quote
CALL PRTCHR
XOR A
OR B ; loop until all done
JR NZ,bs_nextb
bs_done
JP prt_space
;----------------------------------------------------------
; Print One Line of Source Code
;
;; in: HL - > source code line
;
PrintSrcLine
LD C,(HL) ; C = 1st header byte (flags/length)
LD (IY+7),C ; save flags/length
INC HL ; HL - > 2nd byte
LD (CodeAddr),HL ; save opcode address
DEC C ; 1 less byte to go
BIT 7,C ; 2nd header byte present?
JP Z,_psl_opcode ; no = skip to opcode column
LD A,(HL) ; yes = get 2nd header byte
LD B,A ; B = 2nd header byte
BIT 7,B ; label present?
JR Z,_psl_nolabl ; no, skip to opcode column
; labeled
AND 3
LD D,A ; D = label number bits 9~8
INC HL
LD E,(HL) ; E = label number bits 7~0
EX DE,HL
CALL Prt_Label ; show the label
EX DE,HL
CALL prt_space ; < space > to opcode column
LD A,B
AND &FC ; has label so cannot be ORG or comment!
LD B,A
DEC C ; 1 less byte to go
JR _psl_directive
; directive without label
_psl_nolabl
BIT 0,B ; if not comment then
CALL Z,BlankLabel ; print spaces to opcode column
; directive
_psl_directive
INC HL
DEC C ; 1 less byte to go
BIT 0,B ; if bit 0 set then comment
JR Z,_not_comment
; comment
LD A,";"
CALL PRTCHR
LD A,C ; get 1st header byte
AND &3F ; bits 5~0 = length of line
RET Z ; if empty comment then done
LD B,A ; B = char count
_show_comment
LD A,(HL) ; get next comment char
INC HL
CALL PRTCHR ; print comment char
DJNZ _show_comment ; until end of line
RET
_not_comment
BIT 1,B ; if bit 1 then ORG
JR Z,_not_org
; ORG
CALL PRTMSG
DB "ORG ",&00
JR _directive_arg ; print address
_not_org
LD D,B ; D = 2nd header byte
LD A,B
AND &3C
JP Z,do_opcode
RRCA
RRCA
LD B,A
; CP 1
DJNZ _not_ds
; DS
CALL PRTMSG
DB "DS ",&00
JR _directive_arg
_not_ds
; CP 2
DJNZ _not_equ
; EQU
CALL PRTMSG
DB "EQU ",&00
JR _directive_arg
_not_equ
; CP 3
DJNZ _not_equals
; =
CALL PRTMSG
DB "= ",0
JR _directive_arg
_not_equals
; CP 4
DJNZ _not_dw
; DW
CALL PRTMSG
DB "DW ",&00
JR _directive_arg
_not_dw
; CP 5
DJNZ _not_if
; IF
CALL PrtMsg
DB "IF ",0
; directive arg = constant or symbol
_directive_arg
BIT 6,C ; symbol present?
JR Z,prt_const ; no, constant value
LD A,(HL)
INC HL ; yes, get symbol number
LD H,(HL)
LD L,A
JP PrtSymbol ; print symbol name
; get and show constant value
prt_const
LD E,(HL)
INC HL ; next 2 bytes = 16 bit constant
LD D,(HL)
JP PrtNum
_not_if
; CP 6
DJNZ _not_ifd
; IFD
CALL PrtMsg
DB "IFD ",0
LD A,C
AND &3F
LD B,A
_prt_chrs
LD A,(HL) ; get next char
INC HL
CALL PRTCHR ; print char
DJNZ _prt_chrs ; until all done
RET
_not_ifd
; CP 7
DJNZ _not_str
; STR
CALL PrtMsg
DB "STR ",0
JR _bytestring
_not_str
; CP 8
DJNZ _not_db
; DB
CALL PRTMSG
DB "DB ",&00
_bytestring
LD A,C
AND &3F ; B = number of bytes or chars
LD B,A
JP ByteString
_not_db
; CP 9
DJNZ _not_else
; ELSE
CALL PrtMsg
DB "ELSE ",0
RET
_not_else
; CP 10
DJNZ _not_endf
; ENDF
CALL PrtMsg
DB "ENDF ",0
RET
_not_endf
; CP 11
DJNZ _not_ent
; ENT
CALL PRTMSG
DB "ENT ",&00
JR _directive_arg
_not_ent
; CP 12
DJNZ _not_wr
CALL PrtMsg
DB "WRI ",0
JR _prt_filename
_not_wr
; CP 13
DJNZ _not_incb
; INCB
CALL PRTMSG
DB "INCB ",&00
_prt_filename
LD A,C
AND &3F
RET Z
LD B,A
INC B
LD A,'"'
JR _pfnq
_pfnxt LD A,(HL)
INC HL
CP " "
JR C,_ibend
_pfnq CALL PRTCHR
DJNZ _pfnxt
_ibend LD A,'"'
JP PRTCHR
_not_incb
; CP 14
DJNZ _not_rept
; REPT
CALL PrtMsg
DB "REPT ",0
JP _directive_arg
_not_rept
; REND 15
CALL PrtMsg
DB "REND ",0
RET
; opcode only
_psl_opcode
CALL BlankLabel ; pad with spaces to opcode field
;----------------------------------------------------------
; Print Opcode & args
;
; Examine the opcode to determine its length and
; what args (if any) follow it
;
do_opcode ; decode and print opcode
PUSH HL
CALL Decode ; C = arg flags, length
POP HL
prt_opcode ; print decoded opcode
LD (IY+8),C ; IY+8 = C
XOR A
LD (IY+5),A ; ???
LD (IY+6),A ; ???
CALL PEEK ; get opcode
CP &ED ; ED prefix?
JR NZ,L7EFD ; no,
INC HL
CALL PEEK ; get opcode 2nd byte
CP &A0
LD DE,L6C63 ; ED 00~9F table
JR C,L7EF6 ; < &A0?
CP &B0
JR C,L7EF1 ; < &B0?
LD (IY+5),A
RES 4,A
L7EF1 LD DE,L6CDE ; ED A0~FF table
SUB &60 ; opcodes &60~
L7EF6 EX DE,HL
SUB &40 ; opcodes &40~&9F
L7EF9 CALL L7E17 ; print opcode
RET
L7EFD CP &FD
L7EFF LD B,"Y"
JR Z,L7F09 ; FD
LD B,"X"
CP &DD
JR NZ,L7F14
L7F09 LD (IY+6),B ; DD
INC HL
INC HL
CALL PEEK
LD (IY+9),A
DEC HL
CALL PEEK
L7F14 CP &CB ; CB
JR NZ,L7F54
LD A,(IY+6) ; get index register name (X/Y)
OR A
JR Z,L7F1F ; if indexed then
INC HL ; skip DD/FD
L7F1F INC HL ; skip CB
CALL PEEK ; get CB opcode
CP &40
JR C,L7F46 ; if >= &40
L7F25 LD DE,srl_names ; "SRL",...
RLCA
RLCA
AND 3 ; opcode name #
CALL L7EAE ; print name
CALL PRTMSG
DB " ",&00
L7F36 CALL L7EA7 ; get bit number
ADD A,"0"
CALL PRTCHR ; print bit number
LD A,","
CALL PRTCHR
JP L7FCA ; print register
; CB opcode < &40
L7F46 LD DE,rlc_names ; "RLC",...
CALL L7EA7 ; get opcode name #
CALL L7EAE ; print opcode name
CALL Pad_6
JR L7FCA ; print register
L7F54 CP &40
LD DE,L6B5F
JR C,L7FA6 ; &00~&3F
CP &80
JR NC,L7F85 ; &80~&FF
CP &76
JR NZ,L7F6C
CALL PRTMSG ; HALT
DB "HALT",&00
RET
L7F6C CALL PRTMSG
DB "LD ",&00 ; LD r,r
CALL L7EA7
PUSH HL
CALL L7FCB ; 1st r
POP HL
LD A,","
CALL PRTCHR
JR L7FCA ; 2nd r
L7F85 CP &C0
JR C,L7FAB
LD D,A
AND &C7
CP &C7
LD A,D
JR NZ,L7FA1
CALL PRTMSG
DB "RST ",&00
L7F9B LD A,D
AND &38
JP PrtByteA
L7FA1 LD DE,L6BE2
SUB &C0
L7FA6 EX DE,HL
CALL L7E17
RET
L7FAB LD DE,add_names ; ADD...
CALL L7EA7 ; get ADD opcode
CALL L7EAE ; print ADD opcode
CALL Pad_6
CALL PEEK ; get register
AND &38
JR Z,L7FC4 ; if 0 then A,
CP 8
JR Z,L7FC4 ; if 8 then A,
L7FC0 CP &18
JR NZ,L7FCA
L7FC4 CALL PRTMSG
DB "A,",&00
L7FCA CALL PEEK ; get 2nd r
L7FCB LD HL,r_names
AND 7
INC A
INC A
CP 8
JR NZ,L7FDE ;
BIT 3,(IY+6)
JR Z,L7FDE
LD A,1
L7FDE CALL L7E8D
RET
;----------------------------------------------------------
; Print spaces to make label field blank
;
BlankLabel
PUSH BC
LD B,LAB_SIZE+1
L6FBC CALL prt_space
DJNZ L6FBC
POP BC
RET
;----------------------------------------------------------
; symbol table full error
SymTabFull
CALL PRTMSG
DB "SYMBOL ",&0D
DB &00
JR Overflow
; source code full error
SrcCodeFull
CALL PRTMSG
DB &0D,"SOURCE "
DB &0D,&00
OverFlow
CALL PRTMSG
DB "OVERFLOW"
DB &0D,&00
CALL calc_src_end
DEC HL
LD (HL),0
JP _asm_restart
;----------------------------------------------------------
; Open/Close Gap in Source Code
;
;; in: HL = gap start, DE = gap end
;
AddDelSrc
EX DE,HL ; HL = end, DE = start
OR A
SBC HL,DE
LD B,H
LD C,L ; BC = gap size
ADD HL,DE
PUSH HL ; save gap end
CALL calc_src_end
PUSH HL ; save src end
ADD HL,BC
PUSH BC ; save gap size
LD BC,(SymTab)
CALL CmpHL2BC ; will src overflow into symtab?
POP BC ; BC = gap size
CALL NC,SrcCodeFull ; yes, crash out!
CALL UpdateSrcLen ; no, set new length
POP HL ; HL = src end
OR A
SBC HL,DE
LD B,H
LD C,L ; BC = tail size -1
POP HL ; HL = gap end
EX DE,HL ; HL = gap start, DE = gap end
INC BC ; BC = tail size
LDIR_LDDR
OR A
SBC HL,DE
ADD HL,DE ; dest < start?
JR NC,_LDIR ; yes, LDIR
_LDDR DEC BC
EX DE,HL
ADD HL,BC
EX DE,HL ; goto end
ADD HL,BC
INC BC
LDDR ; LDDR = move memory up
RET
_LDIR LDIR ; LDIR = move memory down
RET
;----------------------------------------------------------
; Move Symbol Table
;
;; in: DE = start, HL = end, Arg1 = dest
;
MoveSymbols
OR A
SBC HL,DE
LD B,H
LD C,L
LD HL,(Arg1)
EX DE,HL
JP LDIR_LDDR
;----------------------------------------------------------
; Get next non-space char and point DE to it
;
;; in: DE = address of string
;; out: DE = address of char in string
; A = char
Get_Alpha
LD A,(DE)
CP " "
RET NZ
INC DE
JR Get_Alpha
;----------------------------------------------------------
; Get next non-space char and point DE past it
;
; in; DE = address of string
; out; DE = address of next char in string
; A = char
Next_Alpha
LD A,(DE)
INC DE
CP " "
JR Z,Next_Alpha
RET
;----------------------------------------------------------
; Find Symbol by Name
;
; Finds symbol whose name field matches SymName
; 'name' may include binary numbers!
;
;; out: found = C, HL- >symbol name, BC = symbol number
; else NC, HL- > end of symtab, BC = new symbol number
;
; Also gets number of last spare symbol slot (if present)
; If spare slot exists then SlotNum = spare slot number,
; else SlotNum = -1
;
FindSymbol
LD BC,&FFFF ; -1 = no spare slot
LD (SlotNum),BC
INC BC ; symbol number = 0
LD HL,(SymTab)
_fsnxt CALL GetSymbol ; HL = symbol name
RET Z ; return if end of symbol table
LD A,(HL)
OR A ; 1st char = null?
JR NZ,_fscmp ; no,
LD (SlotNum),BC ; yes, record spare slot number
_fscmp PUSH BC
PUSH HL
LD DE,SymName ; DE = name to search for
LD BC,LAB_SIZE ; BC = number of bytes to compare
CALL StrCmp ; compare strings
POP HL
POP BC
SCF ; Carry set
RET Z ; found it
LD DE,LAB_SIZE
ADD HL,DE ; advance to next symbol
INC BC
JR _fsnxt ; test next symbol
;----------------------------------------------------------
; Compare String to Symbol Name
;
;; in: DE - > string, HL - > symbol name
;; out: Z if equal
;
; Note! only matches valid alphanumeric symbol names
; compare name may end with space
;
CmpSym LD BC,LAB_SIZE ; BC = number of chars in name
_csnxt LD A,(DE) ; get char of compare name
CALL ChkSymN ; valid symbol char?
JR C,_csxit ; no, quit
INC DE ; point to next char
CPI ; compare to next char in symbol name
RET NZ ; return if not the same
RET PO ; return if all chars compared
JR _csnxt ; compare next char
_csxit LD A,(HL)
CP " " ; Z if end of symbol name
RET
;----------------------------------------------------------
; Find Named Symbol in Table
;
;; in: DE = symbol name to search for
;; out: Carry set = found, BC = symbol number
; Carry clear = not found
;
Find_Sym
LD BC,0
LD HL,(SymTab)
fn_nxt PUSH DE
CALL GetSymbol ; HL- > symbol name
POP DE
RET Z ; return NC if end of table
PUSH BC
PUSH DE
PUSH HL
CALL CmpSym ; compare to our name
POP HL
POP DE
POP BC
SCF
RET Z ; return C if found
PUSH BC
LD BC,LAB_SIZE
ADD HL,BC ; advance to next symbol
POP BC
INC BC ; symbol number + 1
JR fn_nxt ; next symbol
;----------------------------------------------------------
; Find/Create Symbol
;
; Search for existing symbol. If not found then create it.
;
;; out: BC = symbol number
;
_createsym
CALL Find_Sym ; find symbol
RET C ; return if found
PUSH BC ; save symbol number
CALL FindSlot ; spare slot available?
JR C,_cs_add ; no, add to end of symbol table
POP AF ; yes,
PUSH BC ; update symbol number
CALL InitSymbol ; reuse spare slot
JR _cs_done
_cs_add
LD BC,(sym_end)
CALL CmpHL2BC ; symbol table full?
JP NC,SymTabFull ; yes, crash out!
CALL InitSymbol ; create symbol at end of table
CALL MarkSymEnd ; mark new end of table
SET 1,(IY+&0E) ; symbol table extended
_cs_done
POP BC ; BC = symbol number
RET
;----------------------------------------------------------
; Initialize Symbol in Symbol Table
;
;; in: DE - > name string
; HL - > symbol name field in symbol table
;
InitSymbol
DEC HL
DEC HL ; HL - > value
XOR A
LD (HL),A
INC HL ; initial value = 0
LD (HL),A
INC HL
LD B,LAB_SIZE ; 6 chars in name
; Copy name to symbol
is_nxt CP " " ; inserting trailing spaces?
JR Z,is_cpy ; yes,
LD A,(DE) ; get char from source string
INC DE
CALL ChkSymN ; valid symbol name char?
JR NC,is_cpy ; yes, copy it
LD A," " ; no, replace with space
is_cpy LD (HL),A ; copy char to field
INC HL
DJNZ is_nxt ; next char
RET
;----------------------------------------------------------
; - Mark End of Symbol Table
; = &FF,&FF,&FF
MarkSymEnd
LD A,&FF
LD (HL),A
INC HL
LD (HL),A
INC HL
LD (HL),A
RET
;----------------------------------------------------------
; Try to Find Spare Slot in Symbol Table
;
; If an unused space is found then we can put a new symbol
; in it, rather than having to add the new symbol to the end
; of the table. This reduces wasted space in the table.
;
;; out: Carry clr = HL - > symbol name, BC = symbol number
; Carry set = no slot found
FindSlot
PUSH DE
LD DE,SYM_SIZE ; DE = bytes per symbol
LD HL,(symtab)
LD BC,-1 ; start count at -1
INC HL ; HL - > name field
INC HL
JR _ss_start
_ss_loop
ADD HL,DE ; next symbol
_ss_start
INC BC ; next symbol number
LD A,(HL) ; get 1st char of name
OR A
JR Z,_ss_done ; null = unused symbol
CP &FF ; &FF = end of table
JR NZ,_ss_loop
SCF
_ss_done
POP DE
RET
;----------------------------------------------------------
; Find/Create Symbol and point past end of name
;
CreateSymbol
PUSH DE
PUSH HL
CALL _createsym ; Find/Create symbol
POP HL
POP DE
; skip over symbol name
SkipSymName
INC DE
LD A,(DE) ; get next char of symbol name
CALL ChkSymN ; valid symbol character?
JR NC,SkipSymName ; yes, get next char
RET
;----------------------------------------------------------
; Valid Symbol Character?
;
;; in: A = char
;; out: Carry clear if valid (0~9 or A~z)
;
;
ChkSymN ; check for 0~9
CP "0"
RET C
CP "9"+1
JR C,csc_x
ChkSymA ; check for A~z
CP "A"
RET C
CP "z"+1
csc_x CCF
RET
;----------------------------------------------------------
; Create 2nd Header Byte (directive/label)
;
;; in: C = header byte, IX - > src code buffer
;
StoreHead2
BIT 7,C ; already created?
RET NZ ; yes, return
INC IX ; create 2nd header byte
SET 7,C ; and flag its presence
INC C ; count this byte
RET
;----------------------------------------------------------
; Parse Edited Line
;
; Translates plain text into CHAMP tokenized source code.
;
;; in: IX - > source code buffer
;
;; out: C = header byte, or 0 if syntax error
;
ParseEditLine
LD DE,EditBuffer
CALL MsgLine ; cursor at start of message line
LD BC,1 ; C, B = 1st, 2nd header bytes
RES 1,(IY+&0E) ; symbol table not extended
LD (IY+6),B ; IY+6 = 2nd header byte
LD A,(DE) ; get 1st char from edit buffer
CP ";" ; comment?
JR Z,_pe_comment
CP " " ; < SPACE >?
JR Z,L7129
CALL ChkSymA ; valid 1st char of label?
JP C,LabelError ; no,
; label
CALL StoreHead2 ; create 2nd header byte
PUSH BC
CALL CreateSymbol ; find/create symbol from label
LD (IX+1),C ; insert label number bits 7~0
LD H,B ; H = label number bits 9~8
SET 7,H ; bit 7 set = label present
POP BC
INC C ; count label number
CP " " ; end of label?
JP NZ,LabelError ; no, error
INC IX ; yes, skip over label number
LD B,H ; B = 2nd header byte
; instruction
L7129 CALL Get_Alpha ; get next non-space char
OR A ; error if empty line!
JP Z,InstructionError
CP ";" ; comment?
JR NZ,L7150 ; no,
_pe_comment
CALL StoreHead2 ; yes, create 2nd header byte
L713C INC DE ; next char
LD A,(DE) ; get char
CALL StoreSrcByte ; append char to src code buffer
INC C ; next count
OR A ; end of line?
JR NZ,L713C ; no,
SET 0,B ; yes, set 'comment' bit
L7148 DEC DE
DEC C ; remove null
LD A,(DE) ; get last char
CP " " ; < SPACE >?
JR Z,L7148 ; yes, remove trailing spaces
RET
; not comment
L7150 LD (IY+8),C ; IY+8 = header byte
PUSH BC
CALL L7A33 ; search for directive
LD A,C ; A = directive number 1~15
POP BC
JP NC,L71AE ; if directive then parse it
; find and parse opcode
PUSH BC
CALL L7A3C ; find opcode
CALL NC,ParseOpcode ; parse opcode
POP BC
JR NC,L7170 ; skip if OK
BIT 0,(IY+&10) ; error, opcode or operand?
JP Z,InstructionError ; opcode error
JP OperandError ; operand error
; store opcode + operand constant/label (if present)
L7170 BIT 0,(IY+0)
CALL Z,StoreSrcByte ; if JR offset then store it
LD A,(IY+6)
OR A ; NOP?
JR Z,L71AA ; yes,
CALL DecodeA ; no, A = decoded opcode
BIT 7,A ; has 16 bit numeric operand?
JR NZ,L71AA ; yes,
AND &0F
CP 4 ; opcode length = 4?
LD H,(IY+9)
JR NZ,L71A2 ; no,
LD A,(IX+0)
BIT 6,(IY+8) ; operand is symbol?
JR Z,L719D ; no,
LD L,(IX-1)
LD (IX-1),H ; swap byte order
LD H,L
L719D LD (IX+0),H
JR L71A7
L71A2 CP 3 ; length = 3?
JR NZ,L71AA ; no,
LD A,H ; byte = 8 bit constant
L71A7 CALL StoreSrcByte ; store opcode byte
L71AA LD C,(IY+8) ; C = header byte
RET
;----------------------------------------------------------
; Parse Directive
;
;; in: directive keyword index
;; out: C = 1st header byte (includes src code line length)
; B = 2nd header byte (includes directive number)
;
L71AE CALL StoreHead2 ; store 2nd header byte
DEC A ; ORG
JR Z,_org
DEC A ; DB
JR Z,_db
DEC A ; DW
JP Z,_dw
DEC A ; DS
JR Z,_ds
DEC A ; EQU
JR Z,_equ
DEC A ; ENT
JR Z,_ent
DEC A ; INCB
JR Z,_incb
DEC A ; STR
JR Z,_str
DEC A ; WRI
JR Z,_wri
DEC A ; REPT
JR Z,_rept
DEC A ; REND
JR Z,_rend
DEC A ; '='
JR Z,_equals
DEC A ; IF
JR Z,_if
DEC A ; IFD
JR Z,_ifd
DEC A ; ELSE
JR Z,_else
JR _endf ; ENDF
; ORG < address >
_org LD A,C
CP &82 ; header byte correct?
JP NZ,LabelError
SET 1,B ; set directive to ORG
; LD C,&84 ; 4 bytes total
JP Parse_Expr ; parse expr
; DS < size >
_ds LD A,1*4 ; set directive to DS
JR _expr
; EQU < expr >
_equ BIT 7,B ; labeled?
JP Z,LabelError ; no, error
LD A,2*4 ; set directive to EQU
JR _expr ; parse expr
_equals
BIT 7,B ; labeled?
JP Z,LabelError ; no, error
LD A,3*4 ; set directive to '='
JR _expr ; parse expr
_dw LD A,4*4 ; set directive to DW
_expr OR B
LD B,A
JP Parse_Expr ; parse word expr
; STR string
_str LD A,7*4 ; set directive to STR
SET 6,B ; force string mode
JR _dbstr
; DB bytes/string
_db LD A,8*4 ; set directive to DB
_dbstr OR B
LD B,A
JP ParseDBSTR
; ENT < entry address >
_ent BIT 7,B
JP NZ,LabelError
LD B,11*4 ; set directive to ENT
JP Parse_Expr ; parse address
; INCB "filename"
_incb LD A,13*4
OR B ; set directive to INCB
LD B,A
JR ParseString
; REPT expr
_rept LD A,14*4 ; directive = REPT
JR _expr
; REND
_rend LD A,15*4 ; directive = REND
OR B
LD B,A
RET
; IF expr
_if LD A,5*4 ; directive = IF
JR _expr
; IFD expr
_ifd LD A,6*4 ; directive = IFD
OR B
LD B,A
JR ParseSymName
; ELSE
_else LD A,9*4 ; directive = ELSE
OR B
LD B,A
RET
; ENDF
_endf LD A,10*4 ; directive = ENDF
OR B
LD B,A
RET
; WRI "filename"
_wri BIT 7,B
JP NZ,LabelError
LD B,12*4 ; set directive to WRI
ParseString
LD A,(DE) ; get next char from edit line
INC DE
CP " " ; skip leading spaces
JR Z,ParseString
CP '"' ; should be opening quote
JR Z,_ps_copy
JP OperandError ; anything else is an error!
_ps_copy
LD A,(DE) ; get next char from edit line
INC DE
CP " "
JP C,OperandError
CP '"' ; if closing quote then done
JR Z,_ps_end
CALL StoreSrcByte ; append char to src code buffer
INC C ; next count
JR _ps_copy
_ps_end
XOR A
CALL StoreSrcByte ; append NULL
INC C
RET
; operand is label name
ParseSymName
LD A,(DE)
CALL ChkSymA ; 1st char of label name valid?
JP C,OperandError
PUSH BC
LD B,LAB_SIZE
_psn_char
LD A,(DE)
INC DE
CP "0" ; end of label name?
JR C,_psn_done
CALL ChkSymN ; valid label char?
JP C,OperandError
CALL StoreSrcByte ; append char to src code buffer
INC C
DJNZ _psn_char
_psn_done
LD A,C
POP BC
LD C,A
RET
;----------------------------------------------------------
; Parse numeric expression
;
;; in: DE- > input text
; C = header byte
; IX- > src code buffer
;
Parse_Expr
CALL Next_Alpha ; skip to start of next word
DEC DE ; DE- > 1st char of word
INC C
INC C ; 2 bytes in src code
CALL Num2BinHL ; try to get number
JR Z,pa_chksym ; if not number may be synbol
; number
LD (IX+1),L
LD (IX+2),H ; store number in src code
LD (Temp3),HL ; number for math
JR Parse_Expr2 ; check for math and 2nd number
pa_chksym
CALL ChkSymA ; is it a symbol?
JR C,OperandError ; no, error
; symbol
PUSH BC
CALL CreateSymbol ; find/create symbol
LD (IX+1),C
LD (IX+2),B ; store symbol number in src code
LD (Temp3),BC ; number for math
POP BC
SET 6,C ; bit 6 set = is symbol
Parse_Expr2
CALL Get_Alpha ; get next non-space char
CP " " ; end of text?
RET C ; yes, return
CP ";" ; comment?
RET Z ; yes, return
LD (IY+8),C ; save header byte
CALL ParseMath ; math with 2nd number
LD C,(IY+8) ; restore header byte
LD HL,(Temp3) ; get result
LD (IX+1),L
LD (IX+2),H ; store result in src code
RET
;----------------------------------------------------------
; Convert Numeric string to 16 bit Binary Number
;
;; in: DE- > numeric string
;; out: HL = number
Num2BinHL
LD A,(DE) ; get char
CP "&" ; Hex number?
JP Z,n2b_hex ; yes, get Hex number
CP "#" ; Hex number?
JP Z,n2b_hex ; yes, get Hex number
CP "0"
JR C,n2b_nan ; if < "0" then not a number
CP "9"+1 ; decimal?
JR C,n2b_dec ; yes, get decimal number
n2b_nan
CP A
RET ; no, ret Z
n2b_dec
CALL Dec2BinHL ; get decimal number
JR Z,OperandError ; error if not valid number
RET
n2b_Hex
CALL Hex2BinHL ; get Hex number
JR Z,OperandError ; error if not valid hex
RET
;----------------------------------------------------------
; Error Messages
;
LabelError
CALL PRTMSG
DB "label",&00
JR DoError ; cursor on col 0
InstructionError
CALL PRTMSG
DB "instruction",&00
LD A,LAB_SIZE+1 ; cursor on col 7
JR DoError
OperandError
CALL PRTMSG
DB "operand",&00
LD A,LAB_SIZE+7 ; cursor on col 13
DoError
LD (IY+&10),A ; set cursor pos
CALL Z,Say_Error ; print 'error' and beep!
XOR A
LD C,A
BIT 1,(IY+&0E) ; was the symbol table extended?
RET Z ; no, done
CALL SymTabEnd ; yes, goto end of symbol table
LD BC,0-3-SYM_SIZE
ADD HL,BC ; Reverse over last symbol
CALL MarkSymEnd ; remove last symbol
LD C,0 ; failed!
RET
; print "error" and beep
;
Say_Error
CALL PRTMSG
DB " error",&00
CALL PadToEOL
BIT 2,(IY+&0F) ; error beep enabled?
RET NZ
LD A,7 ; < BELL >
JP &BB5A ; TXT_OUTPUT
;----------------------------------------------------------
; Parse DB/STR
;
ParseDBSTR
BIT 5,B ; STR?
JP NZ,L7286 ; no,
SET 6,B ; yes, set bit 6 = string mode
L7286 CALL Next_Alpha
CP '"' ; start of string?
JR NZ,L729D ; no,
L728D LD A,(DE) ; yes, get string chr
AND A ; end of line?
JR Z,L72AA ; yes,
INC DE ; no, point to next char
CP '"' ; end of string?
JR Z,L72AA ; yes,
LD (IX+1),A ; no, store char in src line
INC IX ; point to next src code char
INC C ; next count
SET 6,B ; bit 6 set = "string"
JR L728D ; next char
L729D DEC DE
CALL Num2binHL ; get number
JP Z,OperandError
LD (IX+1),L ; store 8 bit number
INC IX
INC C ; next count
L72AA CALL Next_Alpha ; get next char from buffer
CP ","
JR Z,L7286 ; if "," then get next operand
OR A ; end of line?
JR Z,_pdb_done ; yes,
CP ";" ; comment?
JP NZ,OperandError ; no, bad operand
_pdb_done
BIT 5,B ; STR?
RET NZ
SET 7,(IX+0) ; yes, set bit 7 on last byte
RET
;----------------------------------------------------------
; - ASSEMBLER OBJECT CODE POKE -
;
;; in: HL- > src code, IX- >object code
;
PokeObjByte
LD A,(HL) ; A = object code byte in src code
INC HL ; next src code address
PokeObjA
BIT 1,(IY+1) ; Writing object code to RAM?
JR Z,_po_list ; no,
PUSH HL
PUSH IX ; yes, HL = object code address
POP HL
CALL POKE ; write byte to RAM
POP HL
INC IX ; next object code address
_po_list
BIT 0,(IY+1) ; Listing enabled?
RET Z ; no, done
JP ListObjByte ; yes, print Hex byte
;----------------------------------------------------------
; Poke One Line of Object Code
;
;; in: HL- > source code
; C = number of bytes to poke
;
PokeObjBytes
BIT 0,(IY+1) ; listing enabled?
PUSH BC
CALL NZ,ListObjAddr ; yes, print address
POP BC
LD A,C ; any code to poke?
OR A
RET Z ; no, return
LD IX,(asm_PC)
LD DE,(L69A7) ; get object code address offset
ADD IX,DE ; add offset to PC
BIT 6,(HL) ; operand symbol present?
JP NZ,PokeOperand ; yes, poke code with symbol's value
; poke literal bytes
L731F BIT 7,(HL) ; 2nd header byte present?
INC HL ; yes, skip over it
JR Z,L732B ; no,
LD A,(HL) ; get 2nd header byte
INC HL ; skip over it
BIT 7,A ; label present?
JR Z,L732B ; no,
INC HL ; yes, skip over it
L732B LD B,C ; B = byte count
L732C CALL PokeObjByte ; poke object code byte into RAM
DJNZ L732C ; next byte
RET
;----------------------------------------------------------
; Output One Line of Object Code
;
;; in: C = number of object code bytes
;
OutputObjCode
LD A,(IY+1) ; save listing status
PUSH AF
LD (IY+3),0 ; init byte counter
CALL PokeObjBytes ; write object code bytes to RAM
POP AF
LD (IY+1),A ; restore listing status
RET
;----------------------------------------------------------
; List Object Code Byte
;
ListObjByte
CALL prt_byte ; list object code byte
INC (IY+3) ; byte counter +1
LD A,(IY+3)
CP 4 ; more than 4 bytes?
RET C
RES 0,(IY+1) ; yes, listing off
RET
;----------------------------------------------------------
; List Object Code Address on New Line
;
ListObjAddr
CALL Prt_CR
PUSH HL
LD HL,(asm_PC)
CALL PrtHexWord
POP HL
RET
;----------------------------------------------------------
; Get Symbol Value
;
;; in: DE = symbol number
;; out: DE = value
;
GetSymVal
PUSH AF
EX DE,HL
CALL IndexSym ; HL- > symbol
LD D,(HL)
INC HL ; DE = symbol value
LD E,(HL)
INC HL ; HL- > symbol name
INC HL ; HL- > 2nd char
LD A,(HL) ; A = 2nd char
RES 7,(HL) ; symbol is now defined
BIT 7,A ; was symbol defined?
DEC HL
LD A,(HL) ; A = 1st char
JR Z,_gsvdef ; yes, check defined symbol type
_gsvundef
AND &7F ; remove 'found' flag
CP "A" ; math symbol?
JP NC,Error_LabelUndefined ; no,
JR _gsvmath ; yes, do math to get value
_gsvdef
AND &7F ; remove 'found' flag
CP "A" ; math symbol?
JR NC,_gdone ; no, done
_gsvmath
PUSH HL
CALL DoMath ; do math calculation
POP HL
DEC HL
LD (HL),E
DEC HL ; value = DE
LD (HL),D
_gdone POP AF
RET
;
; do symbol math
;
;; return: DE = value
;
DoMath INC HL ; HL- > 2nd char in symbol name
RES 7,(HL) ; symbol now defined
PUSH AF
CALL GetMathArg ; get 1st arg value
PUSH DE
CALL GetMathArg ; DE = 2nd arg value
POP HL ; HL = 1st arg value
POP AF
CP "+"
JR Z,_add
CP "-"
JR Z,_sub
CP "*"
JR Z,_mult
CP "/"
JR Z,_div
CP "%"
JR Z,_mod
CP " >"
JR Z,_greater_than
CP "< "
JR Z,_less_than
CP "="
JR Z,_equal_to
RET
_equal_to
OR A
SBC HL,DE
JR NZ,_math_false
_math_true
LD DE,&FFFF
RET
_greater_than
EX DE,HL
_less_than
OR A
SBC HL,DE
JR C,_math_true
_math_false
LD DE,0
RET
_mod CALL DIV16
EX DE,HL
RET
_div JR Div16
_mult CALL Mult16
EX DE,HL
RET
_sub SBC HL,DE
EX DE,HL
RET
_add ADD HL,DE
EX DE,HL
RET
; DE.HL = HL / DE
Div16 PUSH BC
LD A,H
LD C,L
LD HL,0
LD B,16
_divm SLLC
RLA
ADC HL,HL
SBC HL,DE
JR NC,_divp
ADD HL,DE
DEC C
_divp DJNZ _divm
LD D,A
LD E,C
POP BC
RET
; HL = HL * DE
Mult16 PUSH BC
LD A,H
LD C,L
LD B,16
_multl ADD HL,HL
SLA C
RLA
JR NC,_multn
ADD HL,DE
_multn DJNZ _multl
POP BC
RET
; get math arg from math symbol 'name'
GetMathArg
LD A,(HL) ; A = arg flags
INC HL
LD D,(HL)
INC HL ; DE = value
LD E,(HL)
INC HL
RRA ; Carry set if symbol
PUSH HL
CALL C,GetSymVal ; if symbol then get its value
POP HL
RET
;----------------------------------------------------------
; Poke Operand Symbol Value into Object Code
;
PokeOperand
PUSH HL
CALL next_src ; goto end of src code line+1
DEC HL
LD D,(HL)
DEC HL ; DE = symbol number (at end of line)
LD E,(HL)
CALL GetSymVal ; DE = symbol value
POP HL ; restore src code address
DEC C
DEC C ; bytes to copy -2
CALL NZ,L731F ; poke opcode byte(s)
BIT 2,(IY+0) ; offset?
JR Z,po_poke_word ; no, poke constant word
LD A,C
OR A ; word value?
JR Z,po_byte ; no,
LD D,E
LD E,(HL) ; swap byte order
JR po_poke_word ; poke word
po_byte
INC C ; 1 byte to poke
CALL L731F ; poke byte
BIT 0,(IY+0) ; jump relative offset?
JR NZ,po_offset ; yes,
LD D,E
JR po_poke_byte ; no, poke byte
po_offset
PUSH HL
LD HL,(asm_PC)
EX DE,HL
OR A
SBC HL,DE ; JR offset = dest addr - current addr
DEC HL
DEC HL ; -2 to compenste for 2 byte opcode
LD D,L
LD A,H
CP &FF ; less than 0?
JR Z,po_back ; yes, jumping backwards
OR A ; greater than +127?
JR NZ,po_jr_error ; yes, jump out of range
po_back
XOR L
AND &80 ; less than -127?
JR Z,po_poke_offset ; no,
po_jr_error
SET 1,(IY+0) ; jump out of range
po_poke_offset
POP HL ; restore src code addr
JR po_poke_byte ; poke Byte
po_poke_word
LD A,E
CALL PokeObjA ; poke E into object code RAM
po_poke_byte
LD A,D
CALL PokeObjA ; poke D into object code RAM
RET
;----------------------------------------------------------
; assemble 1 line of src code
;
; HL- > src code
;
Assemble_Line
LD A,(HL) ; get header byte
AND &C0 ; isolate flags
LD (IY+0),A ; store header flags
LD A,(HL)
AND &3F ; isolate length
RET Z ; return if 0 (end of source code)
PUSH HL ; save src code pointer
LD C,A
DEC C ; C = number of object code bytes to copy
BIT 7,(HL) ; 2nd header byte present?
INC HL
JP Z,_opcode ; no, must be opcode
LD A,(HL) ; yes, get 2nd header byte
INC HL
DEC C
BIT 7,A ; label present?
JR Z,_ad_nolabel ; no,
; process label
DEC C
PUSH AF ; save 2nd header byte
AND 3
LD D,A ; D = bits 9~8 of label number
LD E,(HL) ; E = bits 7~0 of label number
INC HL
EX DE,HL
CALL IndexSym ; HL - > label in symbol table
LD (Temp3),HL ; save label pointer
INC HL
INC HL ; HL- > 1st char of label name
RES 7,(HL) ; label found
POP AF ; A = 2nd header byte
AND &FC ; isolate label/directive bits
CP &8C ; is directive '='?
JR Z,_al_labled ; yes, don't define label
BIT 0,(IY+&0E) ; inactive code?
JR NZ,_al_labled ; yes, don't define label
PUSH BC
LD HL,(Temp3) ; HL- > symbol
LD BC,(asm_PC) ; BC = object code PC
LD (HL),B
INC HL ; store PC in symbol
LD (HL),C
POP BC ; restore C (number of object code bytes)
INC HL
INC HL ; HL- > 2nd char of symbol name
BIT 7,(HL) ; was symbol defined?
RES 7,(HL) ; symbol now defined
DEC HL
JR NZ,_al_labled ; no, not a duplicate
BIT 0,(IY+&10) ; pass 1?
JP Z,ErrorDupLabel ; yes, duplicate label error
_al_labled
EX DE,HL ; HL - > src code (after header/label)
JR _ad_op ; process opcode/directive
_ad_nolabel
BIT 0,A ; comment?
JR NZ,_al_none ; yes, ignore it
BIT 1,A ; ORG?
JR Z,_ad_op ; no, must be opcode or directive
; - ORG -
CALL GetValue
LD (asm_PC),DE ; set new PC
_al_none
LD C,0
POP HL
RET
_ad_op AND &3C ; isolate directive number
JR NZ,_directive
; opcode
_opcode
BIT 0,(IY+&0E) ; inactive code?
JR NZ,_al_none ; yes, do nothing!
LD A,C
CP 3
JR C,_opcode_done
LD E,C
CALL Decode
LD A,C
BIT 5,A
JR Z,_opcode_offset
SET 0,(IY+0) ; Relative jump offset
_opcode_offset
AND 7
LD C,A
SUB E
JR NC,_opcode_done
SET 2,(IY+0) ; flag offset
;L7477
_opcode_done
POP HL
RET
; > > > > > > > > directives < < < < < < < <
;; entry:
; HL- > src code
; C = number of bytes to copy
; IX- > object code
;
;; exit:
; C = number of bytes still to copy
; POP HL (back to start of this src code line)
; RET
;
_directive
RRCA
RRCA ; A = directive 1~15
LD E,A
BIT 0,(IY+&0E) ; inactive code?
JP NZ,_ad_inactive ; yes,
LD D,0
PUSH HL ; save HL
LD HL,_ad_jr_table-1
ADD HL,DE ; calculate table index
LD E,(HL) ; get relative jump value
ADD HL,DE ; calculate absolute address
EX (SP),HL ; set jump address, restore HL
RET ; jump to code
_ad_jr_table
DB _ad_ds-$ ; 1 DS
DB _ad_equ-$ ; 2 EQU
DB _ad_equals-$ ; 3 =
DB _ad_done-$ ; 4 DW
DB _ad_if-$ ; 5 IF
DB _ad_ifd-$ ; 6 IFN
DB _ad_done-$ ; 7 STR
DB _ad_done-$ ; 8 DB
DB _ad_else-$ ; 9 ELSE
DB _ad_endf-$ ; 10 ENDF
DB _ad_ent-$ ; 11 ENT
DB _ad_wr-$ ; 12 WRI
DB _ad_incb-$ ; 13 INCB
DB _ad_rept-$ ; 14 REPT
DB _ad_rend-$ ; 15 REND
; - DS -
_ad_ds CALL GetValue ; get storage size
LD HL,(asm_PC)
ADD HL,DE ; add value to PC
LD (asm_PC),HL ; set new PC
POP HL
RET
; - EQU -
_ad_equ
; - '=' -
_ad_equals
CALL GetValue ; get constant/symbol value
LD HL,(Temp3) ; HL - > symbol
LD (HL),D
INC HL ; put value into symbol
LD (HL),E
INC HL
INC HL
RES 7,(HL) ; symbol now defined
POP HL
RET
; - ENT -
_ad_ent
BIT 0,(IY+&10) ; pass 2?
JR Z,_ad_none ; no
CALL GetValue
LD (EntAddr),DE ; store entry address
LD (PC_reg),DE ; set debugger PC
JR _ad_none
; - WRIT -
_ad_wr LD (ObjName),HL ; store pointer to filename
LD HL,(asm_PC)
LD (WritAddr),HL; store start address
SET 7,(IY+1) ; flag for write object code
JR _ad_none
; - INCB -
_ad_incb
EX DE,HL ; DE- > filename
CALL FILENAME1
CALL &BC77 ; CAS_IN_OPEN
JR NC,_incb_close
LD HL,(asm_PC)
PUSH HL
ADD HL,BC ; PC + file length
LD (asm_PC),HL
POP HL ; HL = load address
SCF
BIT 0,(IY+&10) ; pass 2?
JR Z,_incb_close
BIT 1,(IY+1) ; yes, writing to RAM?
JR Z,_incb_close
CALL ReadFile ; yes, read file into RAM
_incb_close
CALL C,&BC7A ; CAS_IN_CLOSE
CALL &BC7D ; CAS_IN_ABANDON
JR _ad_none
; - REPT -
_ad_rept
CALL GetValue
LD A,D
OR E
JR NZ,_rept_init
INC DE ; minimum passes = 1
_rept_init
DEC DE ; rept count = rept number -1
LD (reptnum),DE ; remember REPT count
POP HL
LD (reptaddr),HL ; remember REPT src code address
LD C,0
RET
; - REND -
_ad_rend
LD HL,(reptnum)
LD A,H
OR L ; count = 0?
JR Z,_ad_none ; yes, do next line
DEC HL
LD (reptnum),HL ; no, count - 1
POP HL
LD HL,(reptaddr); back to do REPT src code again!
LD C,0
RET
_ad_none
LD C,0 ; no bytes to copy
_ad_done
POP HL
RET
; inactive code so only respond to IF, IFD, ELSE, ENDF
_ad_inactive
CP 5
JR Z,_ad_if
CP 6
JR Z,_ad_ifd
CP 9
JR Z,_ad_else
CP 10
JR Z,_ad_endf
LD C,0
POP HL
RET
; - IFD -
_ad_ifd
INC (IY+&0D) ; IF level +1
BIT 0,(IY+&0E) ; code already inactive?
JR NZ,_ad_ifd_q ; ignore IF statement
LD A,(IY+&0D)
LD (IY+&0C),A ; set active IF level
EX DE,HL
CALL Find_Sym ; symbol defined?
CCF ; carry set if false
RL (IY+&0E) ; set IF status flag
_ad_ifd_q
POP HL
LD C,0
RET
; - IF -
_ad_if INC (IY+&0D) ; IF level +1
BIT 0,(IY+&0E) ; code already inactive?
JR NZ,_ad_if_done ; ignore IF statement
LD A,(IY+&0D)
LD (IY+&0C),A ; set active IF level
CALL GetValue
LD A,D
OR E ; value = TRUE?
JR NZ,_ad_if_true ; yes,
SCF ; no, make code inactive
_ad_if_true
RL (IY+&0E) ; set this level's IF status
_ad_if_done
POP HL
LD C,0
RET
; - ELSE -
_ad_else
LD A,(IY+&0C) ; A = active IF level
CP (IY+&0D) ; current level above it?
JR C,_ad_elsed ; yes, ignore ELSE statement
LD A,(IY+&0E)
XOR 1 ; toggle this level's IF status
LD (IY+&0E),A
_ad_elsed
POP HL
LD C,0
RET
; - ENDF -
_ad_endf
LD A,(IY+&0D) ; A = current IF/IFD level
OR A
JR Z,_endf0 ; don't go below zero!
DEC A ; level -1
LD (IY+&0D),A
CP (IY+&0C) ; above active IF level?
JR Z,_endf0
JR NC,_endfd ; yes, ignore ENDF statement
RRC (IY+&0E) ; select previous level's IF status
_endf0 LD (IY+&0C),A ; active level = previous level
_endfd POP HL
LD C,0
RET
;----------------------------------------------------------
; Get Directive Operand value (constant/symbol)
;
;; in: HL- > src code (16 bit constant or symbol number)
;
GetValue
LD E,(HL)
INC HL ; DE = constant/symbol
LD D,(HL)
INC HL
BIT 6,(IY+0) ; symbol?
CALL NZ,GetSymVal ; yes, get symbol value
LD C,0 ; end of line
RET
; duplicate label error
ErrorDupLabel
CALL MsgLine ; cursor at start of message line
CALL Prt_Symbol_Name
CALL PRTMSG
DB " duplicate label"
DB &00
JP Abort_Assembly
;----------------------------------------------------------
; add offset to PC
;
Next_PC PUSH HL
LD HL,(asm_PC)
LD B,0
ADD HL,BC
LD (asm_PC),HL
POP HL
RET
;
; - ASSEMBLE -
;
Assemble
CALL PRTMSG
DB "ssemble = >",&00
CALL InputLine
CALL Hex2binHL ; get option number
JR Z,L750B
LD A,L
CP 16 ; looks like 2 digit decimal?
JR C,_asmopt
SUB 6 ; convert 16~21 to 10~15 (A~F)
_asmopt
LD (IY+1),A ; store assemble option
CALL Prt_CR
CALL Prt_CR
CALL ClearBreaks ; clear all breakpoints
LD HL,prt_redirect
LD (PRTCHR+1),HL ; prtchr vector for printer/screen
CALL Asm2 ; assemble all source code (2 pass)
CALL TouchMath ; reference all math symbols in src
CALL KillOldSymbols ; kill all unreferenced symbols
CALL Prt_CR
BIT 2,(IY+1) ; show symbols?
CALL NZ,ListSymbols ; yes, list defined symbols
CALL ClrSymFlags ; remove flags from symbol names
CALL Prt_CR
BIT 7,(IY+1) ; writing object code to file?
JR Z,L74E8 ; no,
BIT 1,(IY+1) ; creating object code?
JR Z,L74E8 ; no,
_asm_save_object ; yes, save object code to file
LD HL,(EntAddr)
LD (Number),HL ; set entry address
LD BC,(WritAddr) ; BC = start address
LD DE,(ObjName) ; DE = object code filename
LD HL,(asm_PC) ; HL = end address + 1
LD A,2 ; type = binary
CALL WriteFile ; save file to disc/tape
L74E8 CALL PRTMSG
DB "Assembly complete no errors",&0D,&00
CALL WaitKey
L750B LD DE,(Temp4) ; DE = src code line number
RES 3,(IY+1) ; printer off
RET
;----------------------------------------------------------
; Initialize asm variables for next pass
;
InitAsm
LD HL,0
LD (IY+&0C),L ; active IF/ENDF level 0
LD (IY+&0D),L ; nesting IF/ENDF level 0
LD (IY+&0E),L ; IF/IFD code active
LD (EntAddr),HL ; no entry address
LD (ObjName),HL ; no object code filename
LD (reptnum),HL ; no code repetition
LD (asm_PC),HL ; object code PC = 0
INC HL ; src code line #1
LD (asm_line),HL
LD HL,(src_code) ; HL - > start of src code
RET
;----------------------------------------------------------
; Assemble all Source Code
;
Asm2 CALL SetSymFlags ; set all symbols to undefined
CALL InitAsm ; initialize assembler variables
LD (IY+&10),A ; pass 1
; ----- pass 1 -----
_asm1 LD A,(HL) ; get 1st byte on line (type/len)
OR A ; end of src?
JR Z,_asm11 ; yes,
CALL Assemble_Line ; assemble one line of src code
CALL Next_PC
CALL NextSrcLineHL ; next src code addr, line number
JR _asm1 ; do next line
_asm11 CALL InitAsm ; initialize variables for pass 2
INC (IY+&10) ; pass 2
; ----- pass 2 -----
_asm2 LD A,(HL) ; get 1st byte on line (type/len)
OR A ; end of src?
JR Z,_asm21 ; yes
CALL Assemble_Line ; assmble one line of src code
PUSH HL
PUSH BC
CALL OutputObjCode ; create and/or list object code
POP BC
CALL Next_PC ; next object code address
POP HL
BIT 1,(IY+0) ; jump out of range?
JR NZ,Error_JR ; yes, abort
CALL NextLineNum ; next line number
BIT 0,(IY+1) ; list option set?
CALL NZ,ListAsmSrc ; yes, show the assembled line
CALL next_src ; next src code addr
JR _asm2 ; do next line
_asm21 RET
; jump out of range error
Error_JR
CALL MsgLine ; cursor at start of message line
CALL BlankLine
CALL PRTMSG
DB "Jump out of range",&00
JR Abort_Assembly
;----------------------------------------------------------
; clear all symbol flags
;
ClrSymFlags
LD HL,(SymTab)
LD BC,LAB_SIZE ; BC = number of chars in symbol name
csd_next
CALL GetSymbol
RET Z ; return if end of symbol table
RES 7,(HL) ; reset symbol found flag
INC HL
RES 7,(HL) ; reset symbol defined flag
DEC HL
ADD HL,BC ; skip to next symbol
JR csd_next ; next symbol
;----------------------------------------------------------
; set all symbol flags
;
SetSymFlags
LD HL,(SymTab)
LD BC,LAB_SIZE-1
ssd_next
CALL GetSymbol
RET Z
SET 7,(HL) ; set 'found' flag (= not found)
INC HL
SET 7,(HL) ; set 'defined' flag (= not defined)
ADD HL,BC
JR ssd_next
;----------------------------------------------------------
; Undefined Label Error
;
Error_LabelUndefined
RES 7,(HL)
CALL MsgLine ; cursor at start of message line
CALL BlankLine
CALL Prt_Symbol_Name
CALL PRTMSG
DB " undefined label"
DB &00
Abort_Assembly
CALL ClrSymFlags ; reset symbol flags
LD DE,(asm_line)
JP _asm_goto_line ; show line with error
;----------------------------------------------------------
; Touch all math symbols found in source code
;
; Ensures that active math symbols will not be killed!
;
TouchMath
LD HL,(src_code)
_tm_loop
LD A,(HL) ; get src code line header
OR A
RET Z ; return if end of source code
LD D,A
AND &3F
LD C,A ; BC = length of line
LD B,0
ADD HL,BC ; HL- > start of next ine
BIT 6,D ; symbol present?
JR Z,_tm_loop; no, check next line
PUSH HL ; yes, save next line address
DEC HL ; back to end of current line
LD A,(HL)
DEC HL
LD L,(HL) ; HL = symbol number
LD H,A
CALL IndexSym ; HL- > symbol (in symbol table)
INC HL
INC HL ; HL- > 1st char of symbol name
LD A,(HL)
RES 7,A
CP "A" ; math operator?
JR NC,_tm_next ;no,
LD (HL),A ; bit 7 clr = symbol found
_tm_next
POP HL ; restore next line addr
JR _tm_loop
;----------------------------------------------------------
; Kill Unreferenced Symbols
;
KillOldSymbols
LD HL,(SymTab)
INC HL
INC HL ; HL - > symbol name
LD BC,SYM_SIZE ; BC = bytes per sysmbol
ko_next
LD A,(HL) ; get 1st char of name
CP &FF ; end of symbol table?
RET Z ; yes, quit
BIT 7,A ; label found during assembly?
JR Z,ko_def ; yes,
AND &7F ; no, isolate 7 bit char
; CP "A" ; math symbol?
; JR C,ko_def ; yes, leave it alone
LD (HL),B ; null 1st char of symbol name
ko_def ADD HL,BC
JR ko_next ; next symbol
;----------------------------------------------------------
; List one Line of Assembly Listing
;
;; in: C = number of object code bytes
; HL- > source code
;
ListAsmSrc
LD A,5
SUB C
LD B,A ; calculate number of spaces
DEC A ; needed to pad out src column
JP P,las_pad
LD B,1
las_pad
CALL PRTMSG
DB " ",&00 ; 2 spaces per byte
DJNZ las_pad
L764E PUSH HL
BIT 0,(IY+&0E) ; inactive code?
JR Z,las_prtsrc
SET 0,(IY+&1D) ; yes, ghosted
las_prtsrc
CALL PrintSrcLine ; print source code
RES 0,(IY+&1D) ; not ghosted
POP HL
RET
;----------------------------------------------------------
; go to next src code line address & number
;
NextSrcLineDE
LD H,D ; address in DE
LD L,E
NextSrcLineHL
CALL next_src ; address in HL
;----------------------------------------------------------
; goto next src code line number
;
NextLineNum
LD DE,(asm_line)
INC DE ; next src line number
LD (asm_line),DE
RET
;----------------------------------------------------------
; - F - find text in source code
;
;; out: DE = line on which src code text was found
; if not found then DE = line at end of src code
FindText
LD HL,1
LD (Arg1),HL
CALL PRTMSG
DB "ind",&00
JR _findtext
;
; Next= > (string previously set with Find)
;
NextText
CALL PRTMSG
DB "ext",&00
LD A,(SearchStr)
OR A ; if no search string then abort
RET Z
LD HL,(Arg1)
INC HL ; start 1 line after last line found
LD (Arg1),HL
_findtext
CALL PRTMSG
DB " = >",&00
LD HL,(Arg1)
LD (asm_line),HL ; set edit line number
EX DE,HL
CALL line2addr ; get address of src code line
LD (Temp2),HL
LD A,(ASM_CMD)
CP "F"
JR NZ,_find_next
CALL InputLine ; user must type in search phrase
CALL LineStartEnd ; get start and end of input line
OR A
SBC HL,DE ; subtract end from start
JR Z,_find_done ; if zero then nothing on the line
LD (SrchLen),HL ; store search string length
LD B,H
LD C,L
EX DE,HL
LD DE,SearchStr ; copy search phrase to search buffer
LDIR
LD (SrchStrEnd),DE ; save end of buffer (will be used to hold expanded src code line)
_find_next
CALL MsgLine ; cursor at start of message line
CALL PRTMSG
DB "searching",&00
LD HL,(Temp2) ; HL = src code address
CALL FindSrcText ; find next line with search phrase
_find_done
CALL MsgLine
CALL BlankLine ; erase command line
LD DE,(asm_line) ; update src code line number
RET
;--------------------------------------------------------
; find (next) text in source code
;
FindSrcText
LD (Temp2),HL ; save src code address
LD A,(HL)
OR A ; abort if end of src code
RET Z
LD HL,(PRTCHR+1)
PUSH HL
LD HL,prt_to_string
LD (PRTCHR+1),HL ; redirect print vector
LD HL,(SrchStrEnd); end of search phrase is
LD (PrtStrAddr),HL; start of 'printed' src code
LD HL,(Temp2) ; get address of src code line
CALL PrintSrcLine ; 'print' src code to string
CALL Prt_CR
POP HL
LD (PRTCHR+1),HL ; restore print vector
LD DE,(SrchStrEnd)
_searchline
LD BC,(SrchLen) ; BC = search phrase length
LD HL,SearchStr ; HL = search phrase string
CALL StrCmp ; search inside line
RET Z ; return if text found
LD HL,(PrtStrAddr); HL = end of search phrase string
SCF
SBC HL,DE ; string end - start
JR NC,_searchline ; search until end of string
LD HL,(Temp2) ; get address of src code line
CALL NextSrcLineHL ; next src code addr, line number
JR FindSrcText ; search next line
;----------------------------------------------------------
; - Compare Strings -
;
;; in: DE = string to compare to
; HL = string to be compared
; BC = number of bytes to compare
;
;; out: Z = strings are identical
;
; Note! string bytes can be any value, including 0 (null)
;
StrCmp
LD A,(DE)
INC DE
CPI
RET NZ
RET PO
JR StrCmp
;----------------------------------------------
; - PRINT EXPR (ASM) -
;
PrintExpr
PUSH DE
CALL _print_expr
POP DE
RET
;----------------------------------------------
; - H -
;
HexExp CALL Prt_CR
LD DE,LineBuffer
CALL Next_Alpha
LD (IY+&0E),&0D
CALL _pe_nextarg
RLC C
JR Z,L776F
CALL PRTMSG
DB " ",&00
CALL PrtBinary
L776F JP Prt_CR
;---------------------------------------------
; - Print expr in Hex, Dec -
;
_print_expr
CALL PRTMSG
DB "rint = >",&00
CALL InputLine
PUSH DE
LD B,&0E
LD (IY+&0E),B
CALL MsgLine ; cursor at start of message line
_pe_prt_arg
L778A LD A,(DE)
L778B INC DE
CALL PRTCHR
DJNZ _pe_prt_arg
POP DE
_pe_nextarg
CALL Get_Alpha
CP "&"
JR Z,_pe_is_hex
CP "#"
JR Z,_pe_is_hex
CALL HEXorDEC
JR C,_pe_1stsym
CALL Dec2BinHL
JR _pe_got_arg1
_pe_is_hex
CALL Hex2binHL
JP Z,OperandError
_pe_got_arg1
LD (Arg1),HL
JR _pe_op ; L77C7
_pe_1stsym
CALL ChkSymA ; valid 1st char of symbol?
JP C,OperandError
PUSH DE
CALL Find_Sym ; find named symbol
POP DE
JP NC,LabelError
DEC HL
LD C,(HL)
DEC HL ; store symbol number
LD B,(HL)
CALL SkipSymName ; skip over symbol name
LD (Arg1),BC
_pe_op CALL Next_Alpha
OR A ; end of text?
JR Z,_pe_math ; yes,
CP "+" ; + operator?
JR Z,_pe_2ndarg ;L77D6
CP "-" ; - operator?
JP NZ,InstructionError
_pe_2ndarg
LD B,A
LD A,(IY+&0E)
CP " "
JP NC,InstructionError
LD (IY+&0E),B ; = "+" or "-"
LD HL,(Arg1)
LD (Arg2),HL ; arg2 = arg1
JR _pe_nextarg ; get next arg
_pe_math
LD DE,(Arg1)
LD HL,(Arg2)
LD A,(IY+&0E)
CP "+"
JR C,_pe_prtresultHL ; if no operator
JR NZ,_pe_sub ; if "-" then subtract
ADD HL,DE ; else add arg1 to arg2
JR _pe_prtresult ; print result
_pe_sub
OR A
SBC HL,DE ; subract arg1 from arg2
_pe_prtresult
EX DE,HL
L7801
_pe_prtresultHL
CALL PRTMSG
DB "= &",&00
_pe_prthexdec
LD H,D
LD L,E
CALL PrtHexWord ; print 16 bit Hex number
CALL PRTMSG
DB " ",&00
PUSH DE
CALL PrtDec ; print decimal number
POP DE
LD C,&FF
RET
;----------------------------------------------------------
; Print Number in Decimal
;
;; in: DE = number
;
PrtDec LD HL,10
EX DE,HL
CALL Div16 ; divide number by 10
PUSH HL
LD A,D ; if result not 0 then
OR E
CALL NZ,PrtDec ; do next digit (recursive!)
POP HL
LD A,L
ADD A,"0"
JP PRTCHR ; print decimal digit
;----------------------------------------------------------
; print number in binary
;
PrtBinary
LD B,16 ; 16 bits
EX DE,HL
_pb_nextbit
ADD HL,HL ; rotate bit into carry
LD A,"0"
JR NC,_pb01 ; bit = 1?
INC A ; yes, A = "1"
_pb01 CALL PRTCHR ; print bit as "0" or "1"
DJNZ _pb_nextbit
RET
;----------------------------------------------------------
; Hex or Decimal?
;
;; in: A = char to test
;; out: Z = Hex
; NC = decimal
; C = neither
;
HEXorDEC
CP "&"
RET Z ; Z = Hex
CP "#"
RET Z ; Z = Hex
CP "0"
RET C
CP "9"+1
CCF ; NC = decimal
RET
;----------------------------------------------------------
; 'print' char to string buffer
;
prt_to_string
PUSH HL
LD HL,(PrtStrAddr) ; HL = position in buffer
LD (HL),A ; store char in buffer
INC HL ; position +1
LD (PrtStrAddr),HL ; update position
LD (HL),0 ; null end of string
POP HL
RET
;----------------------------------------------------------
; Convert Hexadecimal String to Binary Number
;
;; in: DE - > text buffer
;; out: HL - > number, Number = number, Digits = digit count
;
Hex2bin
LD A,(DE)
CP " "
INC DE ; skip leading spaces
JR Z,Hex2bin
CP "&"
JR Z,L7889 ; skip "&"
CP "#"
JR Z,L7889 ; skip "#"
DEC DE
L7889 LD HL,Digits ; Digits = digit count
XOR A
LD (HL),A ; no digits
INC HL
LD (HL),A ; Number = 16 bit number = 0
INC HL
LD (HL),A
L7892 LD A,(DE) ; get char
CALL ToUpper ; accept lower case
DEC HL
DEC HL ; HL = digit count
SUB "0" ; convert "0"~"9" to 0~9
RET M ; if less than "0" then done
CP 10
JR C,_gothex
SUB 7 ; "A"~"F" - > 10~15
CP 10
RET M ; done if less then 10
CP 16
RET P ; done if greater then 15
_gothex
INC DE
INC (HL) ; digit count +1
INC HL
RLD ; number *16 + digit
INC HL
RLD
JR L7892 ; next char
;----------------------------------------------------------
; Convert Hex string to number in HL, A = digit count
;
Hex2binHL
CALL Hex2bin
LD HL,(Number) ; HL = number
LD A,(Digits) ; A = number of digits
OR A ; Z if no digits
RET
;----------------------------------------------------------
; Convert Decimal string to number in HL
;
;; in: DE- > decimal string
;; out: HL = 16 bit number
; A = number of digits
; Z = no digits
;
Dec2BinHL
PUSH BC
LD HL,0
LD (IY+&18),0 ; digits = 0
d2b_loop
LD A,(DE) ; get char
CALL HEXorDEC
JR C,_d2b_end ; end of number if not decimal
INC (IY+&18) ; digit count +1
INC DE ; DE- > next char
SUB "0" ; digit - > 0~9
ADD HL,HL
LD B,H
LD C,L
ADD HL,HL
ADD HL,HL
ADD HL,BC ; HL = HL*10
LD C,A
LD B,0
ADD HL,BC ; add digit
JR d2b_loop
_d2b_end
LD (Number),HL
LD A,(IY+&18) ; A = digit count
OR A
POP BC
RET
;----------------------------------------------------------
; - Execute Key Command -
;
;; in: HL = command table, A = command key
;
DoCommand
LD C,A
L78BD LD A,(HL) ; end of table?
INC HL
OR A
RET Z ; RET Z if command not found
CP C
JR Z,L78C8 ; found command?
INC HL
INC HL ; no, keep looking
JR L78BD
L78C8 LD A,(HL)
INC HL
LD H,(HL) ; HL = command address
LD L,A
CALL _execute ; execute the command
SCF ; Carry Set = command executed
RET
_execute
JP (HL)
;
; CTRL+UP = goto 1st line (beginning of asm source)
;
CTRL_UP
LD DE,1
RET
;
; CTRL+DOWN = goto last line (end of asm source)
;
CTRL_DOWN
LD DE,&3000
RET
;
; - CLS -
;
ClearScreen
LD HL,0
LD DE,&2718
LD A,0
CALL &BC44
LD HL,&0A00
LD (TXT_POS),HL
RET
;----------------------------------------------------------
; - LOAD DIRECT -
;
;; in: (Arg1) = load address
;; out: C = OK,
; NC = error, A = error code
;; error codes: 0 = open failed, 1 = read failed
;
LOAD_D CALL FILENAME
CALL &BC77 ; CAS_IN_OPEN
LD A,0
RET NC
LD HL,(Arg1)
CALL &BC83 ; CAS_IN_DIRECT
PUSH AF
CALL C,&BC7A ; CAS_IN_CLOSE
CALL &BC7D ; CAS_IN_ABANDON
POP AF
LD A,1
RET
;----------------------------------------------------------
; - SAVE DIRECT -
;
SAVE_D OR A
SBC HL,BC
PUSH BC
PUSH HL
CALL FILENAME
CALL &BC8C ; CAS_OUT_OPEN
POP DE
POP HL
LD A,2 ; A = file type (binary)
CALL C,&BC98 ; CAS_OUT_DIRECT
CALL C,&BC8F ; CAS_OUT_CLOSE
JP &BC92 ; CAS_OUT_ABANDON
;----------------------------------------------------------
; - CATALOG -
;
CAT CALL PRTMSG
DB "atalog..."
DB &00
Catalog
PUSH DE
LD DE,FILBUF ; buffer
CALL &BC9B ; CAS_CATALOG
POP DE
RET
;----------------------------------------------------------
; - QUIT -
;
QUIT CALL PRTMSG
DB "uit? = >",&00
CALL CursorAddr
PUSH DE
LD (HL)," "
CALL Get_Key
CALL ToUpper ; accept "Y" or "y"
POP DE
CALL PRTCHR
CP "Y"
RET NZ
CALL ChkSrc ; checksum source code
LD (src_sum),DE
_quit
LD SP,(STACK) ; restore system stack
RET ; exit to BASIC
;----------------------------------------------------------
; - Assemble Mode -
;
ASSEMBLER
CALL ClearScreen
_asm_restart
LD SP,(STACK)
CALL ClearBreaks
LD DE,1
_asm_goto_line
LD (Arg1),DE
LD IY,Variables
LD SP,(STACK)
; printer off
LD HL,_prtchr
LD (PRTCHR+1),HL
; set RAM bank
LD A,(Bug_Bank)
LD (RAM_Bank),A ; write to same bank as debugger
LD HL,&C97E ;; peek = LD A,(HL) : RET
LD (PEEK),HL
CALL SHOW_PAGE ; show page of src code
_asm_prompt
CALL CmdLine
CALL BlankLine
CALL PRTMSG
DB "< assemble >",&00
_asm_wait_cmd
LD HL,LineBuffer
LD (HL)," "
RES 1,(IY+&0F) ; overwrite editing
CALL Get_Key
CALL ToUpper
LD (ASM_CMD),A
LD DE,(Arg1)
LD (Temp4),DE ; remember line number
CALL MsgLine ; cursor at start of message line
CALL BlankLine
LD HL,&170A ; command line, column 10
LD (TXT_POS),HL
LD HL,asm_commands
LD A,(ASM_CMD)
CP &20 ; printable key?
CALL NC,PRTCHR ; yes, show it
CALL DoCommand ; execute command
JR NC,_asm_prompt ; NC = invalid commamd
LD A,(ASM_CMD)
CP &0A
JR Z,_pageupdn ; don't prompt if csr up/down
CP &0B
JR NZ,_asm_goto_line ; goto line (DE = line number)
_pageupdn
LD (Arg1),DE ; update line number
CALL Show_Page ; show page of src
LD HL,&170A
LD (TXT_POS),HL
JR _asm_wait_cmd ; wait for next key press
;----------------------------------------------------------
; - Debug -
;
Debug CALL ChkSrc
LD (src_sum),DE ; checksum source code
DEBUGGER
LD HL,debug_help_txt
CALL ShowHelp
LD HL,&0119
CALL &BB75 ; TXT_SET_CURSOR
DebugLoop
LD SP,(STACK)
LD IY,Variables
; bank select
LD A,(Bug_Bank)
LD (RAM_Bank),A ; restore RAM bank selection
LD A,&C3
LD (PEEK),A
LD HL,_peek ; PEEK = JP _peek
LD (PEEK+1),HL
Debug_Prompt
CALL CmdLine
CALL BlankLine ; clear the command line
LD B,(IY+1)
RES 3,(IY+1) ; make sure printer is off
CALL PRTMSG ; show < debug > prompt
DB "< debug >",&00
LD (IY+1),B ; restore printer state
CALL InputCommand ; get command line input
CALL Get_Alpha ; get command letter
OR A
JR Z,Debug_Prompt
CALL ToUpper ; accept lower case commands
PUSH AF
INC DE
LD C,0
CALL Hex2binHL ; get arg1
JR Z,_dbg_args
INC C
LD (Arg1),HL
CALL Hex2binHL ; get arg2
JR Z,_dbg_args
INC C
LD (Arg2),HL
CALL Hex2binHL ; get arg3
JR Z,_dbg_args
INC C
LD (Arg3),HL
_dbg_args
LD A,C ; get number of args
LD (ArgC),A
POP AF
_call_cmd
LD HL,debug_commands
CALL DoCommand ; execute command
JR C,_debug_done
CALL ErrorMsg ; bad command!
_debug_done
JP DebugLoop
;-----------------------------------------------
; Position Cursor at row 22, column 0
;
MsgLine
PUSH HL
LD HL,&1600
LD (TXT_POS),HL
POP HL
RET
;-----------------------------------------------
; Position Cursor at row 23, column 0
;
CmdLine
LD HL,&1700
LD (TXT_POS),HL
RET
;-----------------------------------------------
; Get asm Directive id
;
L7A33 LD HL,directive_names
LD C,0 ; start at id 0
CALL Identify ; get directive id
RET
;----------------------------------------------------------
; Get Opcode id, operand id's
;
L7A3C LD HL,opcode_names
LD C,&80 ; start at 128
CALL Identify ; get opcode id
RES 7,C
LD (IY+5),C ; store opcode id
LD BC,0
LD (IY+&10),C
RET Z ; return if no opcode
INC (IY+&10)
LD HL,cc_names
CALL Identify ; get 1st arg id
LD B,C ; B = first arg id
LD C,0
RET Z ; return if end of line
CP ","
SCF
RET NZ ; return if no comma (error)
INC DE
CALL Get_Alpha
PUSH BC
LD HL,cc_names
CALL Identify ; get 2nd arg id
POP HL
LD B,H ; B = 1st arg id, C = 2nd arg id
RET
;----------------------------------------------------------
; Identify Opcode, Operand, Register, or Directive
;
;; in: DE - > arg to identify, HL - > list of id names
;; out: C = id, DE- > next arg, A = 1st char of next arg
; Carry = not found, Z = last arg
;
Identify
INC C ; next id
PUSH DE
CALL L7ACC ; compare to our name
JR Z,L7A89 ; found?
POP DE
CALL L7AC5 ; no, next name
CP &80 ; end of names?
JR NZ,Identify ; no, continue searching
SCF ; Carry set = name not found
RET
L7A89 POP HL
CALL Get_Alpha ; A = next non-space char
OR A ; Z = end of line
RET Z
CP ";" ; Z = end of args
RET NC
CCF
RET
;----------------------------------------------------------
;
;
L7A8F CP &0C
LD D,&0A ; if 0c then D = 0a
JR Z,L7A9E
CP &0E ; if 0e then D = 15
LD D,&15
JR Z,L7A9E
CP &19 ; if 19
RET NZ
L7A9E LD A,(IY+6)
CALL StoreSrcByte ; store opcode byte
LD A,D
RET
;----------------------------------------------------------
;
;
L7AA6 CP &1F ; &1f ???
RET NZ
LD HL,(Temp3)
L7AAC LD A,H
OR A
RET NZ
BIT 6,(IY+8) ; 8 bit constant?
LD A,L
RET
;----------------------------------------------------------
; Store Byte in Source Code Buffer
;
;; in: IX- > source code buffer
;
StoreSrcByte
LD (IX+1),A ; store src code byte
INC IX
INC (IY+8) ; another byte in the src code line
RET
;----------------------------------------------------------
; Goto next name in list
;
;; in: HL - > current position in name list
;; out: HL - > start of next name
;
; next name starts with bit 7 set
; &80 = end of list
;
L7AC5 LD A,(HL)
BIT 7,A
RET NZ
INC HL
JR L7AC5
;----------------------------------------------------------
; Parse Opcode and Operands
;
;; in: HL- >name in list, DE- >text to compare
;; out: Z if match, HL- > next name in list
;
L7ACC LD A,(HL) ; get next char of register name
AND &7F ; remove start-of-name marker
LD B,A
CP &10 ; < 16 = substitute X/Y/+d etc.
INC HL
LD A,(DE) ; get char from buffer
JR C,L7AEA
INC DE
CALL ToUpper ; convert to upper case
CP B ; compare to name
L7AD8 RET NZ ; return NZ if not equal
BIT 7,(HL) ; hit next name?
JR Z,L7ACC ; no, continue comparing
BIT 7,C
JR Z,L7AE3
XOR A
RET
L7AE3 LD A,(DE) ; get next char from buffer
CP " "
RET Z ; space = OK
CP ","
RET Z ; "," = OK
CP ";"
RET Z ; ";" = OK
OR A
RET ; Null = OK, else error
; B = substitution identifier
; 1 = +d eg. (IX+d)
; 2 = nnnn eg. (&4000)
; 3 = X/Y eg. IX
L7AEA LD A,B
CP 1 ; +d?
JR NZ,L7AF9 ; no,
; +d
LD A,(DE) ; get char from buffer
INC DE
PUSH BC
LD C,A ; C = "+" or "-"
CALL ParseNum ; get offset
POP BC
JR L7AD8 ; check for terminator or ","
L7AF9 CP 2 ; nnnn?
JR NZ,L7B1F
; nnnn
LD A,(DE)
CALL HEXorDEC ; number?
JR C,L7B08 ; no, must be symbol
CALL ParseNum ; get constant
JR L7B32
L7B08 CALL ChkSymA ; valid 1st char of symbol name?
RET C ; no, return
LD A,B
CP 2 ; IX or IY?
RET NZ ; no, return
PUSH BC
CALL CreateSymbol ; find/create symbol
LD (Temp3),BC ; store symbol number
POP BC
SET 6,(IY+8) ; arg is symbol
JR L7B32
; IX/Y
L7B1F LD B,&DD ; &DD = IX prefix
LD A,(DE)
CALL ToUpper
INC DE
CP "X" ; next char = "X"?
JR Z,L7B2C
LD B,&FD ; &FD = IY prefix
CP "Y"
RET NZ
L7B2C LD (IY+6),B ; set opcode prefix
XOR A
JR L7AD8
L7B32 CALL ParseMath ; evaluate math
XOR A
JR L7AD8 ; parse next arg
;----------------------------------------------------------
; Parse Math Operation
;
; eg., LD HL,sym1+&1234
;
; A symbol will be created whose 'name' contains the
; operator (+, -, * etc), the first value of symbol
; number, and the second value or symbol number.
;
; name 0 = "+", "-", "*" etc.
; 1 = 1st arg type (0= constant, 1 = symbol)
; 3,4 = 1st arg constant value or symbol number
; 5 = 2nd arg type (0= constant, 1 = symbol)
; 6,7 = 2nd arg constant value or symbol number
;
ParseMath
LD A,(DE)
CP "+"
JR Z,MathOp
CP "-"
JR Z,MathOp
CP "*"
JR Z,MathOp
CP "/"
JR Z,MathOp
CP "%"
JR Z,MathOp
CP " >"
JR Z,MathOp
CP "< "
JR Z,MathOp
CP "="
CP " "
RET NZ ; return if invalid operator
INC DE ; skip spaces
JR ParseMath
MathOp PUSH HL
PUSH BC
LD HL,SymName ; HL - > symbol name buffer
LD (HL),A ; store operator
INC HL
XOR A
BIT 6,(IY+8) ; is 1st arg a symbol?
JR Z,L7B4D ; no,
INC A ; yes, type = 1
L7B4D LD (HL),A ; store 1st arg type in name buffer
INC HL
LD BC,(Temp3) ; get 1st number
LD (HL),B
INC HL ; store 1st arg in name buffer
LD (HL),C
INC HL
PUSH HL
_pm_skp_space
INC DE
LD A,(DE) ; get next char (start of 2nd arg)
CP " "
JR Z,_pm_skp_space
CALL ChkSymA ; valid 1st char of symbol name?
JR C,L7B66 ; no, must be number
CALL CreateSymbol ; find/create symbol
XOR A
INC A ; type = symbol
JR L7B6D
L7B66 CALL Num2binHL ; convert Hex/Dec to 16 bit number
LD B,H
LD C,L ; BC = number
LD A,0 ; type = constant
L7B6D POP HL
JR Z,L7BA9 ; abort if invalid arg
LD (HL),A ; store type
INC HL
LD (HL),B
INC HL ; store value in name buffer
LD (HL),C
PUSH DE
CALL FindSymbol ; get symbol by name
JR C,L7B9C ; Carry clr = found symbol
DEC HL ; else past end of symbol table, so
DEC HL ; HL-2 = end of table
LD DE,(SlotNum) ; get number of spare symbol
LD A,D
CP &FF ; got a spare symbol?
JR Z,L7B8C ; no, add symbol at end of table
EX DE,HL
LD B,H ; yes, BC = spare symbol number
LD C,L
CALL IndexSym ; HL = address of spare symbol
L7B8C PUSH BC
EX DE,HL ; DE - > symbol name in table
LD BC,SYM_SIZE
LD HL,SymBuff ; HL - > symbol buffer
LDIR ; copy buffer to symbol
EX DE,HL ; HL = end of symbol
INC A ; if A was &ff then symbol added,
CALL Z,MarkSymEnd ; so re-terminate symbol table
POP BC
L7B9C POP DE
LD (Temp3),BC ; save symbol number
SET 6,(IY+8) ; arg is a symbol
XOR A
L7BA6 POP BC
POP HL
RET
L7BA9 INC A
JR L7BA6
;----------------------------------------------------------
; Get numeric opcode arg (constant or offset)
;
;; in: B = type (2 = IX/IY+d 3 = constant)
;; out: Z if valid number
;
ParseNum
PUSH HL
CALL Num2binHL ; convert numeric string to binary
LD A,B
CP 2 ; IX+d or IY+d?
JR Z,_pco_const ; no
LD A,C
CP "-" ; negative offset?
JR NZ,_pco_p
LD A,L
NEG ; yes, convert to unsigned
LD L,A
_pco_p LD (IY+9),L ; store the offset
LD A,H
OR A ; Z if 8 bits
POP HL
RET
_pco_const
LD (Temp3),HL ; store the number
POP HL
XOR A ; Z for any size
RET
;----------------------------------------------------------
;
;
L7BCE SUB &0F
RET C
CP 8
CCF
RET C
LD H,A
LD A,E
RLCA
RLCA
RLCA
OR H
RRC D
RRC D
OR D
RET
;----------------------------------------------------------
; Create Opcode and return class, length
;
;; in: HL- >opcode table, BC = required attributes
; A = base opcode-1
;; out: A = opcode class, length
; Carry set if found
;
L7BE1 LD (IY+7),A ; opcode base
L7BE4 INC (IY+7) ; opcode+1
LD D,(HL)
INC HL
LD E,(HL) ; DE = attributes
INC HL
LD A,E
AND D
INC A
RET Z ; abort if end of table
EX DE,HL
SBC HL,BC ; compare attributes to BC
EX DE,HL
JR NZ,L7BE4 ; until attributes = BC
LD A,(IY+7) ; get opcode
CALL StoreSrcByte ; store opcode in src code
LD HL,Temp1 ; temporary buffer for opcode
LD (HL),A ; store opcode
CALL Decode ; get opcode class, length
LD A,C
SCF ; Carry set = success
RET
;----------------------------------------------------------
; Decode asm Opcode into Class and Length
;
;; out A: bits 7~4 = eg. 16 bit const, 8 bit offset
; bits 3~0 = opcode length
;
DecodeA
LD HL,(asm_PC)
CALL Decode
LD A,C
RET
L7C09 LD HL,(Temp3) ; get operand value
LD A,L ; low byte only
CALL StoreSrcByte ; store opcode byte
LD A,H
OR A ; high byte = 0?
RET
L7C13 LD A,C
CP &1F ; ???
RET C
L7C17 BIT 6,(IY+8) ; arg is symbol?
JR NZ,L7C09
LD HL,(Temp3) ; get number
LD A,H
OR A ; signed negative?
LD A,L ; A = low byte
RET Z
SCF ; carry set if negative
RET
;----------------------------------------------------------
; Parse Opcode
;
ParseOpcode
LD (IY+0),0 ; clear asm flags
PUSH IX
POP HL
INC HL ; next PC
LD (asm_PC),HL
LD A,B
CALL L7A8F
LD B,A
LD A,C
CALL L7A8F
LD C,A
LD A,(IY+5)
CP &34
JR NZ,L7C49
LD A,B
OR C
LD A,&76
RET Z
SCF
RET
L7C49 CP &20
JR C,L7C7D
CP &2B ; if &20~&2A
JR NC,L7C7D
LD D,A
LD A,&CB
CALL StoreSrcByte ; store CB prefix
LD A,D
SUB &20
CP 8 ; if < &28
JR NC,L7C6A
LD D,0
LD E,A
LD A,C
OR A
SCF
RET NZ
LD A,B
CALL L7BCE
RET
L7C6A SUB 7
LD D,A
LD A,B
CALL L7AA6
SCF
RET NZ
AND &F8
SCF
RET NZ
LD E,L
LD A,C
CALL L7BCE
RET
L7C7D AND &3F
RLCA
RLCA
LD E,A
XOR A
PUSH BC
SRL B
RRA
SRL B
RRA
SRL B
RRA
OR C
LD C,A
LD A,B
OR E
LD B,A
LD HL,L6B5F
LD A,&FF ; opcodes starting at 0 (NOP+)
CALL L7BE1 ; create opcode
JR NC,L7CB0
POP BC
BIT 7,A
L7C9F JP NZ,L7C09
BIT 6,A
L7CA4 JP NZ,L7C13
OR A
BIT 5,A
JP Z,L7CFE
L7CAD JP L7C17
L7CB0 LD HL,L6BE2
LD A,&BF
CALL L7BE1 ; opcode starting at &C0 (RETZ+)
JR NC,L7D03
POP BC
BIT 7,A
JR NZ,L7C9F
BIT 6,A
JR Z,L7CE2
CALL PEEK
CP &DB
JR Z,L7CDA
CP &C6
L7CCA JP Z,L7C13
CP &CE
JR Z,L7CCA
CP &DE
JR Z,L7CCA
LD C,B
CP &D3
JR NZ,L7CA4
L7CDA LD A,C
CP &1E
SCF
RET NZ
JP L7C17
L7CE2 BIT 5,A
JR NZ,L7CAD
CALL PEEK
CP &C7
SCF
CCF
JR NZ,L7CFE
LD A,B
CALL L7AA6
SCF
RET NZ
AND &C7
SCF
RET NZ
LD A,L
OR (IX+0)
LD (IX+0),A
L7CFE SET 0,(IY+0) ; Relative Jump offset
RET
L7D03 LD HL,L6C63 ; table
LD A,&3F ; opcodes starting at &40 (LD B,B+)
CALL L7BE1 ; create opcode
JR NC,L7D29
LD A,(IY+6)
OR A
SCF
RET NZ
LD (IX+0),&ED ; store ED prefix
LD A,(IY+7)
CALL StoreSrcByte ; store opcode byte
CALL DecodeA ; get opcode class, length
BIT 7,A ; has 16 bit const?
POP BC
JP NZ,L7C09 ; yes,
OR A ; Z if no numeric operand
JR L7CFE
L7D29 LD A,B
AND &FC
LD B,A
LD A,&9F ; opcodes starting at &A0 (AND B+)
LD HL,L6CDE ; table
CALL L7BE1
JR NC,L7D50
LD A,(IY+6)
OR A
SCF
RET NZ
LD (IX+0),&ED ; store ED opcode
POP BC
LD A,B
OR A
JR Z,L7D4C
CP &18
SCF
RET NZ
LD A,&10
L7D4C OR (IY+7)
RET
L7D50 LD A,(IY+5)
CP 3
POP BC
JR NZ,L7D60
LD D,1
LD A,B
SUB &0F
LD L,C
JR L7D7D
L7D60 LD D,2
LD L,B
LD H,A
CP &10
JR Z,L7D70
CP &11
JR Z,L7D70
CP &13
JR NZ,L7D76
L7D70 LD A,B
CP &16
LD L,C
JR L7D78
L7D76 LD A,C
OR A
L7D78 SCF
RET NZ
LD A,H
SUB &10
L7D7D RET C
CP 8
CCF
RET C
LD E,A
LD A,L
CALL L7BCE
RET
;----------------------------------------------------------
; Print opcode character, expanding ctrl codes;
; code
; 1 = index egister offset (IX+d)
; 2 = 16 bit number (nnnn)
; 3 = index register (IX,IY)
;
PrtOpChar
CP &10 ; printable char?
JP NC,PRTCHR ; yes, print it
; control code
CP 3 ; index register?
; 3 = IX or IY
JR NZ,L7D97
LD A,(IY+6) ; 'X' or 'Y'
JP PRTCHR
L7D97 CP 1 ; index register offset?
JR NZ,L7DB0
; 1 = (IX+-d)
LD A,(IY+9) ; A = offset
LD B,"+"
OR A ; + or -?
JP P,L7DA8
LD B,"-"
NEG ; negate negative offset
L7DA8 PUSH AF
LD A,B
CALL PRTCHR ; print "+" or "-"
POP AF
JR PrtByteA ; print offset
; 2 = nnnn
L7DB0 PUSH HL
LD HL,(CodeAddr) ; HL- > opcode
LD A,(IY+7) ; A = header byte
AND &3F ; isolate line length
DEC A ; - 1 to exclude header byte
LD C,A
LD B,0 ; BC = opcode length
ADD HL,BC
DEC HL ; HL- > end of opcode
CALL PEEK
LD D,A
DEC HL ; get word at end of opcode
CALL PEEK
LD E,A
LD A,(IY+8) ; A = opcode flags/length
LD C,(IY+7) ; C = header byte
BIT 5,A ; 16 bit value?
JR Z,L7DE2
BIT 6,C ; arg is symbol?
JR NZ,L7DF2
BIT 4,A ; relative jump?
JR Z,L7DEA ; no,
LD E,D ; yes, E = offset
RL D
SBC A,A ; sign extend to 16 bits
LD D,A
LD HL,(CodeAddr) ; HL- > opcode
INC HL
INC HL ; skip opcode bytes
ADD HL,DE
EX DE,HL ; DE = destination PC
JR L7DF8 ; print dest address
L7DE2 BIT 6,C ; arg is symbol?
JR NZ,L7DF2 ; yes, print symbol
BIT 6,A ; no, constant byte?
JR Z,L7DF8 ; no, quit
L7DEA LD A,D ; A = byte
POP HL
JR PrtByteA ; print it
L7DF2 EX DE,HL
CALL PrtSymbol ; print symbol name
POP HL
RET
L7DF8 POP HL
;----------------------------------------------------------
; Print 16 bit number in hex, prepending "&" if > 10
;
;; in: DE = number
;
PrtNum LD A,D
OR A
JR Z,PrtByteE ; if < 256 then print low byte
PrtHexDE
LD A,D
CALL PrtHexByte ; print "&" or "#" + high byte
LD A,E
JP prt_byte ; print low byte in hex
;----------------------------------------------------------
; Print Byte in Hex, or decimal if 0~9
;
PrtByteE
LD A,E
PrtByteA
CP 10 ; if > 9 then print "&" + byte
JR NC,PrtHexByte
ADD A,"0" ; print 0~9
JP PRTCHR
;----------------------------------------------------------
; print "&" + byte in hex
;
PrtHexByte
PUSH AF
IFDEF HASH
LD A,"#"
ELSE
LD A,"&"
ENDIF
CALL PRTCHR ; print "&"
POP AF
JP prt_byte ; print byte in Hex
;----------------------------------------------------------
; Print Opcode
;
;; in: HL = opcode table, A = index, C = flags/length
;
L7E17 ADD A,A ; index * 2
ADD A,L
LD L,A
LD A,H
ADC A,0
LD H,A
LD D,(HL)
INC HL ; D,E = opcode attributes
LD E,(HL)
LD A,D
RRA
RR C
RRA
RR C ; C bits 7,6 = D bits 1,0
AND &3F
LD B,A ; B bits 5~0 = D bits 7~2
RLC C
RLC C ; C bits 1,0 = D bits 1,0
LD A,E
RLA
RL C
RLA
RL C ; C bits 2~0 = E bits 2~0
RLA ;(C bits 4,3 = D bits 1,0)
RL C
LD A,C
AND &1F
LD D,A ; D = 1st operand
LD A,E
AND &1F
LD E,A ; E = 2nd operand
LD A,B
OR A ; if B < > 0 then
JR NZ,L7E47
OR &40 ; set bit 6
L7E47 LD HL,opcode_names
CALL L7E8D ; print opcode
LD A,(IY+5)
OR A ; if ?? < > 0 then
JR Z,L7E5A
LD A,"R" ; print "R"
CALL PRTCHR
XOR A ; A = 0
INC C ; C + 1
L7E5A CP D ; = D?
RET Z ; yes, done
CALL Pad_6
LD A,D ; A = 1st operand number
CALL L7E6C ; print 1st operand
LD A,E ; have a 2nd operand?
OR A
RET Z ; no, done
LD A,","
CALL PRTCHR
LD A,E ; A = 2nd operand number
; print operand
L7E6C LD HL,cc_names ; operand names
BIT 3,(IY+6) ; if ??? then
JR Z,L7E8D
CP &0A ; if < 10 then
LD C,&0C ; name = 12
JR Z,L7E8C
CP &15 ; if 21 then
JR NZ,L7E8D
LD A,(IY+7) ; A = ???
AND &0F ; 0~15
CP 3 ; if not 3 then
LD C,&0E ; name = 14
JR NZ,L7E8C ; else
LD C,&19 ; name = 25
L7E8C LD A,C ; A = name count
; get name
L7E8D DEC A ; count down
JR Z,L7E97 ; until target name reached
L7E90 INC HL ; skip name char
BIT 7,(HL) ; start of next name?
JR Z,L7E90 ; no, keep skipping
JR L7E8D ; yes, next name
; print name
L7E97 LD C,A ; char count = 0
L7E98 LD A,(HL) ; get char of opcode name
AND &7F ; reset bit 7
PUSH DE
CALL PrtOpChar ; expand and print opcode char
POP DE
INC HL ; point to next char
INC C ; char count + 1
BIT 7,(HL) ; until start of next name
JR Z,L7E98 ; do next char
RET
;----------------------------------------------------------
; get opcode bits 5~3 (register number)
;
L7EA7 CALL PEEK ; get byte from RAM
RRA
RRA
RRA
AND 7
RET
;----------------------------------------------------------
;
;; in: A = name#, DE = namelist
;
L7EAE PUSH HL
EX DE,HL
INC A
CALL L7E8D
POP HL
RET
;----------------------------------------------------------
; pad with spaces to 6 chars
Pad_6 LD A,5
SUB C
LD B,A
L7EBA CALL prt_space
DJNZ L7EBA
RET
;----------------------------------------------------------
; - Print Character to Screen+Printer -
;
prt_redirect
CALL _prtchr ; print to screen
BIT 3,(IY+1) ; printer output turned on?
RET Z ; no, done
PUSH AF
CALL prtprt ; print to printer
POP AF
CP &0D ; < CR >?
RET NZ ; no, done
BIT 3,(IY+1) ; printer output turned on?
RET Z ; no, done
PUSH AF
LD A,&0A
CALL prtprt ; yes, print < LF > to printer
POP AF
RET
prtprt CALL &BD2B ; MC_PRINT_CHAR
RET C ; return if successful
CALL InKey
CP 27 ; user hit < ESC > key?
JR NZ,prtprt ; no, retry
RES 3,(IY+1) ; yes, turn printer output off
RET
;----------------------------------------------------------
; Read 16 bit word at addr, addr+1
;
;; in: HL - > address
;; out: DE = Word
;
DEEK PUSH AF
CALL PEEK
LD E,A
INC HL
CALL PEEK
LD D,A
POP AF
RET
;----------------------------------------------------------
; Merge Source Code and Symbol Table
;
; Symbol table is attached to end of source code, so that
; they can be saved to disc/tape as a single file.
;
;; out: BC = beginning of source code memory
;
MergeSrc
PUSH DE
CALL calc_src_end
LD (Arg1),HL ; dest addr = end of src code
CALL SymTabEnd ; HL = end of symbols
LD DE,(SymTab) ; DE = start of symbols
CALL MoveSymbols ; move symbols to end of src code
EX DE,HL ; HL = end of src+symbols+1
LD BC,(src_code) ; BC = 1st line of src code
DEC BC
DEC BC ; include src code length
POP DE
RET
;----------------------------------------------------------
; Extract Symbol Table from merged Source code file
;
Load_SymTab LD HL,(SymTab)
LD (Arg1),HL ; dest addr for symbols
CALL calc_src_end ; point to end of source
LD D,H ; (= start of symbols)
LD E,L
CALL EndSym ; point to end of symbols
CALL MoveSymbols ; move symbols to symbol table
RET
;----------------------------------------------------------
; Save Source Code
;
SAVE_ASM
CALL PRTMSG ; show "SAVE= >" prompt
DB "ave = >",&00
CALL InputLine ; get filename
CP 27 ; < ESC >?
JP Z,_save_asm_done
CALL Get_Alpha ; skip spaces before filename
LD A,(DE)
OR A ; anything on the line?
JP Z,_save_asm_done
LD H,D
LD L,E
_save_asm_t
INC HL
LD A,(HL) ; get next char on line
OR A ; end of buffer?
JR Z,_save_asm_d ; yes,
CP "." ; filename extension?
JR NZ,_save_asm_t ; no, get next char
INC HL
LD A,(HL) ; get next char
CP " "+1 ; end of name?
JR C,_save_asm_d ; yes, save binary
CALL ToUpper
CP "A" ; extension = ".a??"?
JR Z,_save_asm_x ; yes
CP "I" ; extension = ".i??"?
JR NZ,_save_asm_d ; no, save binary
_save_asm_x
INC HL
LD A,(HL) ; extension = ".a" or ".i"?
CP " "+1
JR NC,_save_asm_d ; no, save binary
_save_asm_a
CALL FILENAME
CALL &BC8C ; CAS_OUT_OPEN
LD HL,(PRTCHR+1)
PUSH HL ; remember prtchr vector
JR NC,_save_asm_abandon
LD HL,prt_to_string
LD (PRTCHR+1),HL ; redirect print vector
LD HL,EditBuffer
LD (PrtStrAddr),HL ; set print string address
LD HL,(src_code) ; HL- > start of src code
_save_asm_line
LD A,(HL)
OR A ; end of src code?
JR Z,_save_asm_close
LD (Temp2),HL ; remember src code address
CALL PrintSrcLine ; 'print' src code to string
LD HL,EditBuffer ; HL- > edit buffer
LD (PrtStrAddr),HL ; reset print string address
_save_asm_nxtchr
LD A,(HL) ; get 1st char
INC HL
OR A
JR Z,_save_asm_nxtline
CALL &BC95 ; CAS_OUT_CHAR
JR NC,_save_asm_abandon
JR _save_asm_nxtchr
_save_asm_nxtline
LD A,&0D ; < CR > at end of line
CALL &BC95 ; CAS_OUT_CHAR
JR NC,_save_asm_abandon
LD HL,(Temp2) ; HL- > src code address
LD A,(HL)
AND &3F
ADD A,L
LD L,A ; HL- > next src code addr
JR NC,_save_asm_line
INC H
JR _save_asm_line
_save_asm_close
CALL &BC8F ; CAS_OUT_CLOSE
_save_asm_abandon
CALL &BC92 ; CAS_OUT_ABANDON
POP HL
LD (PRTCHR+1),HL ; restore print vector
JR _save_asm_done
_save_asm_d
CALL MergeSrc ; yes, combine src and symbols
CALL SAVE_D ; save src code to file
CALL Load_SymTab ; separate symbols from src
_save_asm_done
LD DE,1 ; goto src code line
RET
;----------------------------------------------------------
; Import ASCII file and insert into asm source
;
IMPORT_ASM
SET 3,(IY+&0F) ; 'insert file' mode
CALL PRTMSG
DB "mport = >",&00
JR _load_asm
;----------------------------------------------------------
; Load Source Code
;
LOAD_ASM
RES 3,(IY+&0F) ; 'load file' mode
CALL PRTMSG
DB "oad = >",&00
_load_asm
CALL InputLine ; get user input
CP 27 ; < ESC >?
JP Z,_la_done
LD A,(DE)
CP " " ; got a filename?
JP Z,_la_done
LD BC,(src_code)
DEC BC
DEC BC ; set load address
LD (Arg1),BC
CALL FILENAME
CALL &BC77 ; CAS_IN_OPEN
JP NC,_la_abandon
PUSH HL
POP IX
LD A,(IX+18) ; file type = ASCII?
CP &16
JR Z,_la_ascii ; yes,
BIT 3,(IY+&0F) ; 'insert file' mode?
JP NZ,_la_close ; can't insert binary!
LD HL,(Arg1)
CALL &BC83 ; CAS_IN_DIRECT
JR NC,_la_error
CALL Load_SymTab ; separate symbols from src
JP _la_close
_la_error
CALL kill_src ; bad load so wipe src code
JP _la_abandon
; load ASCII source code file
_la_ascii
RES 4,(IY+&0F) ; not end of file
LD HL,(SrcAddrEd) ; HL- > editline src code addr
BIT 3,(IY+&0F) ; 'insert file' mode?
JR NZ,_la_nextline ; yes, insert into src code
CALL kill_src ; delete current src code
LD HL,(src_code) ; HL- > start of source code
_la_nextline
LD (SrcAddrEd),HL ; set editline src code addr
LD (SrcAddrDe),HL ; set dest src code addr
_la_getline
LD HL,EditBuffer
LD B,40 ; B = chars per line
CALL &BC80 ; CAS_IN_CHAR
JR NC,_la_close ; end of file?
CP "." ; 1st char = "."?
JR NZ,_la_gotchr ; no, process it
_la_readline ; yes, absorb it
CALL &BC80 ; CAS_IN_CHAR
JR NC,_la_eof ; end of file?
_la_gotchr
OR A
JR Z,_la_eof ; NULL = end of file
CP &1A
JR Z,_la_eof ; soft eof = end of file
CP &0D
JR Z,_la_eol ; CR = end of line
CP &0A
JR Z,_la_eol ; LF = end of line
CP &09
JR NZ,_la_notab ; convert TAB to SPACE
LD A," "
_la_notab
DEC B ; line buffer full?
JP M,_la_full ; yes,
LD (HL),A ; no, store char in buffer
INC HL
JR _la_readline
_la_full
INC B
JR _la_readline
_la_eof
SET 4,(IY+&0F) ; end of file
_la_eol
LD (HL),0 ; null end of line
LD A,B
CP 40 ; anything on the line?
JR Z,_la_getline ; no, get next line
SET 0,(IY+&0F) ; < insert > mode
_la_storeline
CALL StoreEditLine ; parse line and store in src
JR NZ,_la_gotline
_la_badline
SET 2,(IY+&0F) ; don't beep on error
LD HL,EditBuffer
LD BC,39
ADD HL,BC ; HL = last char on line
LD D,H
LD E,L
DEC HL ; move string right 1 char
LDDR
INC HL ; insert ";"
LD (HL),";"
JR _la_storeline ; try again as comment
_la_gotline
LD HL,(SrcAddrEd)
CALL NextSrcLineHL ; HL- > next src addr, line
BIT 4,(IY+&0F) ; end of file?
JR Z,_la_nextline ; no, read next line
_la_close
CALL &BC7A ; CAS_IN_CLOSE
_la_abandon
CALL &BC7D ; CAS_IN_ABANDON
_la_done
RES 2,(IY+&0F) ; beep on error
LD DE,(asm_line) ; DE = current line number
BIT 3,(IY+&0F) ; 'insert file' mode?
JR NZ,_la_ret
LD DE,10 ; no, goto line 10
_la_ret
RET
;----------------------------------------------------------
; Wipe source code and symbol table
;
kill_src
LD HL,(src_code)
XOR A
LD (HL),A
DEC HL
LD (HL),A
DEC HL
LD A,3
LD (HL),A
LD HL,(Symtab)
JP MarkSymEnd
;----------------------------------------------------------
; - PARSE FILENAME -
;
;; in: DE - > filename
;; out: HL - > filename
; DE - > 2k file buffer
; B = filename length
;
FILENAME1
LD C,&FF ; default no extension
JR _name
FILENAME
LD C,0 ; default .ASM extension
_name PUSH DE
LD B,0
_namelen
INC DE
INC B ; count chars in name
LD A,(DE)
CP "." ; found a "."?
JR NZ,_noext
LD C,A ; yes, C = "."
_noext CP " "+1
JR NC,_namelen
LD A,C
CP "." ; need to add extension?
JR NC,_n1done ; no,
EX DE,HL
LD (HL),"."
INC HL
LD (HL),"A" ; yes, append ".ASM"
INC HL
LD (HL),"S"
INC HL
LD (HL),"M"
INC B
INC B
INC B
INC B ; filename is now 4 chars longer
_n1done
POP HL
LD DE,FILBUF ; DE - > 2k file buffer
RET
;----------------------------------------------------------
; - WRITE FILE -
;
DebugWrite
CALL Prt_CR
LD DE,LineBuffer
CALL Next_Alpha
CALL Get_Alpha
PUSH DE
wloop LD A,(DE)
INC DE ; skip over name
CP " "+1
JR NC,wloop
CALL Hex2binHL
LD B,H ; BC = start address
LD C,L
CALL Hex2binHL ; HL = end address
LD A,(Digits)
AND A
JR NZ,_entry
POP DE
JP ErrorMsg ; error if no end address
_entry PUSH HL
CALL Hex2bin ; Number = entry address (optional)
POP HL
CALL Get_Alpha ; A = type (optional)
CP "0"
JR C,_type2
CP "3"
JR C,_type
_type2 LD A,"2" ; default to type 2 (binary)
_type AND &03 ; type = 0-2
POP DE ; DE = filename
INC HL ; HL = end+1
;
; ---- Write memory to File ----
;
;; in: DE=filename, BC=start, HL=end, A=type
;
WriteFile
OR A
SBC HL,BC ; HL = length
PUSH BC
PUSH HL
PUSH AF
CALL FILENAME1
CALL &BC8C ; CAS_OUT_OPEN
POP DE
LD A,D ; A = type
PUSH HL
POP IX ; IX = file header
POP DE ; DE = length
POP HL ; HL = start
JR NC,L8103 ; if error opening then abandon
LD (IX+&12),A ; set type
LD (IX+&18),E
LD (IX+&19),D ; set entry
LD (IX+&15),L
LD (IX+&16),H ; set length
LD BC,(Number)
LD (IX+&1A),C ; set entry
LD (IX+&1B),B
L80F4 CALL PEEK ; get byte from RAM/ROM
CALL &BC95 ; CAS_WRITE_CHAR
JR NC,L8103
INC HL ; next address
DEC DE
LD A,D ; count-1
OR E
JR NZ,L80F4 ; until done
CALL &BC8F ; CAS_OUT_CLOSE
L8103 JP &BC92 ; CAS_OUT_ABANDON
;----------------------------------------------------------
; - Load File into Memory -
;
DebugLoad
CALL Prt_CR
LD DE,LineBuffer
CALL Next_Alpha
CALL Get_Alpha ; DE - > filename
PUSH DE ; save filename point
CALL Get_Alpha
_dl_skp
LD A,(DE)
INC DE ; skip over filename
CP " "+1
JR NC,_dl_skp
CALL Hex2bin ; HL = destination address
POP DE
CALL FILENAME1
CALL &BC77 ; CAS_IN_OPEN
JR NC,_dl_close
PUSH HL ; save pointer to file header
EX HL,DE ; DE- > filename
LD A,(Digits) ; got a user dest addr?
CP 0
JR Z,_dl_read
LD HL,(Number) ; yes, override dest addr in file
_dl_read
CALL ReadFile ; read file into memory
_dl_close
PUSH AF
CALL C,&BC7A ; CAS_IN_CLOSE
CALL &BC7D ; CAS_IN_ABANDON
POP AF
POP IX ; IX = file header
JR NC,_dl_error
LD L,(IX+&15)
LD H,(IX+&16)
CALL PRTMSG
DB "Strt",&00
CALL PrtsHexWord ; show file load address
LD L,(IX+&18)
LD H,(IX+&19)
CALL PRTMSG
DB "Len",&00
CALL PrtsHexWord ; show file length
LD L,(IX+&1A)
LD H,(IX+&1B)
CALL PRTMSG
DB "Ent",&00
CALL PrtsHexWord ; show file entry address
CALL PRTMSG
DB " Type ",&00
LD A,(IX+&12)
ADD A,"0"
CP "9"+1
JR C,_dl_typ
LD A,"A"
_dl_typ
CALL PRTCHR ; show file type
JP Prt_CR
_dl_error
JP ErrorMsg
;----------------------------------------------------------
; Read Contents of File into RAM
;
;; in: HL = dest address, BC = length
;
;; out: HL = end address + 1
;; C = OK, NC = error (A = error code)
;
ReadFile
CALL &BC80 ; CAS_IN_CHAR
JR C,_rf_poke
CP &1A ; soft EOF?
RET NZ
_rf_poke
CALL POKE ; poke byte into RAM
INC HL
DEC BC
LD A,B ; count-1
OR C
JR NZ,ReadFile
SCF ; read completed OK
RET
;----------------------------------------------------------
; compare string in bank x to string in bank 0
;
strcmpx
CALL PEEK ; read byte from 64k RAM bank
EX DE,HL
CP (HL) ; compare to byte in bank 0
EX DE,HL
INC DE
INC HL ; point to next byte
RET NZ
DEC C
JR NZ,strcmpx ; compare next byte
RET
;----------------------------------------------------------
; - O - printer on/off
;
PrinterOnOff
CALL PrtMsg
DB " Printer O",0
LD HL,_prtchr
LD (PRTCHR+1),HL ; prtchr vector = screen only
LD A,(ArgC)
CP 1 ; got on/off arg?
JR Z,_prt_set ; yes,
BIT 3,(IY+1) ; is printer on?
JR NZ,_prt_on ; yes, keep it on
_prt_off
CALL PrtMsg ; no,
DB "FF",&0d,0
RES 3,(IY+1) ; printer off
RET
_prt_set
LD A,(Arg1)
CP 1 ; 1 = on, 0 = off
JR NZ,_prt_off
_prt_on
CALL PrtMsg
DB "N",&0d,0
LD HL,prt_redirect ; prtchr vector = printer/screen
LD (PRTCHR+1),HL
SET 3,(IY+1) ; printer on
RET
;----------------------------------------------------------
; - SCROLL -
;
SCROLL_UP
LD B,1 ; 1 = scroll up
LD HL,0 ; from column 0, row 0
LD DE,&2718 ; to column 39, row 24
LD A,0 ; fill with ink 0
JP &BC50 ; SCR_SW_ROLL
;----------------------------------------------------------
; Delete Line of Source Code
;
DeleteSrcLine
LD HL,(SrcAddrEd) ; start position
LD DE,(SrcAddrDe) ; end position (before start)
JP AddDelSrc ; close up gap
;----------------------------------------------------------
; Blank line of text on screen
;
BlankLine
LD BC,(TXT_POS)
BlankLineB
PUSH DE
PUSH HL
LD C,0
CALL ScrnAddr ; HL = screen address
LD DE,2048-40 ; DE = distance to next screen row
LD C,8 ; chars are 8 pixels high
XOR A
L81A4 LD B,40 ; 40 bytes to clear per row
L81A6 LD (HL),A ; screen byte = 0
INC HL ; HL = next byte in screen row
DJNZ L81A6
ADD HL,DE ; HL = next screen row
DEC C
JR NZ,L81A4 ; loop back to clear screen row
POP HL
POP DE
RET
;----------------------------------------------------------
; move text cursor down to start of next line
NEXT_LINE
PUSH HL
LD HL,(TXT_POS)
INC H
LD L,0
LD (TXT_POS),HL
POP HL
RET
;----------------------------------------------------------
; print 11 lines of src code (above_to / below edit line)
;
; if text has been scrolled up/down by 1 line then
; just print the one line (top/bottom) that needs
; to be refereshed.
;
; input; HL = text row, column
; DE = source code line number
;
Show11Lines
LD B,11 ; 11 rows to do
ShowLinesAt
LD (TXT_POS),HL ; set text row, column
_shownextline
LD A,D
CP &30 ; at or above src line &3000?
JR NC,_nosrc ; yes, show blank row
OR E ; at src line 0?
JR Z,_nosrc ; yes, show blank row
CALL line2addr ; HL = src code address
ShowSrcLines
PUSH BC
PUSH HL
LD A,(SCROLL)
CP 1 ; scrolling up?
JR Z,_scrollup
CP 2 ; scrolling down?
JR NZ,_blankline ; no, show the line
_scrolldown
LD A,(TXT_ROW)
CP 0 ; at first row?
JR Z,_showline ; yes, show the line
JR _nextline ; no, skip it
_scrollup
LD A,(HL)
OR A ; end of src code?
JR Z,_nextline ; yes, skip the line
LD A,(TXT_ROW)
CP 21 ; at last text row?
JR NZ,_nextline ; no, skip the line
JR _showline ; show the line
_blankline
CALL BlankLine ; blank the row
_showline
LD A,(HL)
OR A ; anything to show?
JR Z,_nextline
CALL PrintSrcLine ; show source code
_nextline
POP HL
LD (Temp4),HL ; save src code address
CALL next_src ; HL = next src code address
CALL Next_Line ; move cursor to start of next row
POP BC
DJNZ ShowSrcLines ; loop back to show next line
RET
; no src code to show, so just blank the row
_nosrc PUSH BC
CALL BlankLine ; blank the text row
CALL Next_Line ; move cursor to start of next row
INC DE ; next source code line
POP BC
DJNZ _shownextline ; loop back to show next row
RET
;----------------------------------------------------------
; - Show Page of Source Code -
;
Show_Page
LD A,E
SUB 10
LD E,A ; src code line - 10
JR NC,_sp_sub10
DEC D
_sp_sub10
LD HL,0 ; cursor at top/left
CALL Show11Lines ; show upper 11 lines of src code
LD (SrcAddrEd),HL ; HL = edit line src code address
LD BC,(Temp4) ; get current src code address
LD (SrcAddrDe),BC ; save it
LD A,(BC)
OR A ; if not end of src then
JR NZ,_show_lower ; show lower 11 lines
LD DE,&3000 ; else DE = beyond last line
CALL line2addr ; get last line number + 1
DEC DE ; -1 = last line in src
LD A,D
OR E ; if numlines = 0 then
JR Z,_show_lower ; show lower 11 lines
XOR A
LD (SCROLL),A ; else scroll off
LD (Arg1),DE ; update edit line number
JR SHOW_PAGE ; show upper 11 lines again!
_show_lower
LD B,11 ; 11 lines to show
CALL ShowSrcLines ; show lower 11 lines
XOR A
LD (SCROLL),A ; scroll off
RET
;----------------------------------------------------------
; Get Next TAB Position
;
;; out: A = position of next tab stop
;
GetTab LD A,(TXT_POS)
SUB LAB_SIZE+1 ; before opcode tab?
JR NC,_it_opchk
LD A,LAB_SIZE ; yes
RET
_it_opchk
SUB 5 ; before operand tab?
JR NC,_it_oprnd
LD A,LAB_SIZE+5 ; yes
RET
_it_oprnd
LD A,40 ; no
RET
;----------------------------------------------------------
; Test for Blank Line
;
TestLine
PUSH HL
LD HL,EditBuffer
LD B,40 ; 40 chars in buffer
_tl_loop
LD A,(HL)
CP " " ; anything on line?
JR NZ,_tl_done ; yes, return NZ
INC HL
DJNZ _tl_loop
XOR A ; return Z
_tl_done
POP HL
RET
;----------------------------------------------------------
; Print line of src code to edit buffer
;
PrtSrcToBuffer
LD HL,(PRTCHR+1) ; remember old PRTCHR vector
PUSH HL
LD HL,EditBuffer
LD (PrtStrAddr),HL
LD HL,prt_to_string
LD (PRTCHR+1),HL ; PRTCHR goes to edit buffer
LD DE,(Arg1) ; DE = src code line number
CALL line2addr ; get src code line address
LD A,(HL)
OR A
CALL NZ,PrintSrcLine ; 'print' code to edit buffer
POP HL
LD (PRTCHR+1),HL ; restore old PRTCHR vector
LD BC,(PrtStrAddr) ; BC- > last char in buffer
RET
;----------------------------------------------------------
; - Edit Line of Asm Source -
;
EditDE LD (Arg1),DE ; update line number
EDIT CALL CmdLine
CALL PRTMSG
DB "< edit > ",&00
LD DE,(Arg1) ; DE = line number
RES 0,(IY+&0F) ; not in < insert > mode
CALL SHOW_PAGE ; show page of src code
CALL PrtSrcToBuffer ;'print' src code to edit buffer
LD HL,EditBufEnd ; end of buffer
LD (HL),0 ; null end of buffer
_ed_trim
DEC HL ; previous char
CALL CmpHL2BC ; end of string?
JR C,edit_line ; no,
LD (HL)," " ; fill with spaces back to
JR _ed_trim ; last character
edit_line
LD HL,EditBuffer
edit_loop
CALL ShowEditChar ; display character being edited
CALL Get_Key
LD (KeyCode),A
PUSH HL ; save edit buffer pointer
LD HL,(TXT_POS)
EX DE,HL
CALL MsgLine ; cursor at start of message line
CALL BlankLine ; erase message line area on screen
LD (TXT_POS),DE
POP HL ; HL - > position in edit buffer
LD A,(KeyCode)
CP 9 ; < RIGHT >?
JP Z,_ed_right ; yes,
CP &0C ; < DEL >?
JR NZ,_ed_clr ; no,
; < DEL > (backspace)
LD A,(TXT_POS)
OR A ; at column 0?
JR Z,edit_loop ; yes, nothing to delete
_ed_bk DEC A
LD (TXT_POS),A ; cursor left 1 char
DEC HL
JR _clr
_ed_clr
CP &10 ; < CLR >?
JR NZ,_ed_mode
; < CLR > = delete char under cursor
_clr LD A,(EditBuffer)
CP ";" ; comment?
LD A,(TXT_POS)
JR Z,_clr2eol ; yes, ignore tabs
LD B,LAB_SIZE ; B = label field size
CP B
JR Z,_clr_chr ; if between label and opcode
JR C,_clr2tab
LD B,LAB_SIZE+5 ; B = opcode field size
CP B
JR Z,_clr_chr ; if between opcode and operand
JR C,_clr2tab
_clr2eol
LD B,39 ; B = line size
_clr2tab
NEG
ADD A,B
LD B,A ; B = count to next tab/eol
PUSH HL
_clrm INC HL ; save cursor position in buffer
LD A,(HL) ; get next char
DEC HL
LD (HL),A ; move chars left
INC HL
DJNZ _clrm ; until next tab
LD (HL)," " ; space at end of field
POP HL ; back to cursor position in buffer
JR _clrshow
_clr_chr
LD (HL)," "
_clrshow
CALL ShowToEOL ; show changes
JR edit_loop
_ed_mode
CP 2 ; < COPY >? (also CTRL-B)
JR NZ,_ed_csr_left
; < COPY > = switch editing mode overwrite< - >insert
LD A,(IY+&0F)
XOR 2 ; toggle insert/overwrite flag
LD (IY+&0F),A
JP edit_loop
_ed_csr_left
CP 8 ; < LEFT >?
JR NZ,_ed_update ; no,
; < LEFT > = move cursor left
_ed_bs DEC HL ; move cursor left
DEC (IY+&1B) ; TXT_POS - 1
JP M,_lbump ; if before column 0 then bump right
LD A,(EditBuffer)
CP ";"
JR Z,_lstop ; if comment then no tab action
LD A,(HL)
CP " " ; space?
JR NZ,_lstop ; no,
CALL GetTab ; in label or opcode area?
JR C,_ltab ; yes,
PUSH HL ; no, in operand field
LD A,(HL)
CP " " ; spaces only to the left?
DEC HL ; and right?
POP HL ; back to cursor position
JR _lstop
_ltab DEC HL
DEC (IY+&1B) ; TXT_POS - 1
JR Z,_lstop ; if hit column 0 then stop
LD A,(IY+&1B)
CP LAB_SIZE+1 ; hit opcode column?
JR Z,_lstop ; yes, stop
LD A,(HL) ; get char under cursor
CP " " ; space?
JR NZ,_lbump ; no, bump right and stop
JR _ltab ; continue going left
_lbump INC HL ;
INC (IY+&1B) ; TXT_POS + 1
_lstop JP edit_loop
;
; check for keys that update the src code
_ed_update
LD DE,(Arg1)
CP &1B ; < ESC >?
JR NZ,_ed_undo ; no,
; < ESC >
_ed_escape
CALL UpdateEditLine ; store edited line
JP Z,edit_loop ; if error then continue editing
BIT 0,(IY+&0F) ; in Insert mode?
JR Z,_esc2 ; no,
INC DE ; yes, next line
_esc2 LD (PasteBuffer),A ; clear the paste buffer
LD B,24
CALL BlankLineB ; remove paste buffer display
XOR A
RET ; back to < assemble >
_ed_undo
CP &17 ; < CTRL-W >?
JR Z,_ed_do_undo
CP &1A ; < CTRL-Z >?
JR Z,_ed_do_undo
CP &15 ; < CTRL-U >?
_ed_do_undo
JP Z,EditDE ; reload current line
_ed_csr_down
CP &0A ; < DOWN >?
JR NZ,_ed_csr_up
;< DOWN > = edit next line
CALL UpdateEditLine
JP Z,edit_loop
JR NC,_ecd_done ; skip if already on next line
INC DE ; next src line
_ecd_done
JP EditDE ; edit next line
_ed_csr_up
CP &0B ; < UP >?
JR NZ,_ed_pagedown
; < UP > = edit previous line
CALL UpdateEditLine
JP Z,edit_loop
BIT 0,(IY+&0F) ; in < edit > mode?
CALL Z,CSR_UP ; yes, go up to previous line
JP EditDE
_ed_pagedown
CP &F5 ; < SHIFT-DOWN >?
JR NZ,_ed_pageup
CALL UpdateEditLine
JP Z,edit_loop
CALL PAGE_DOWN
JP EditDE
_ed_pageup
CP &F4 ; < SHIFT-UP >?
JR NZ,_ed_cutline
CALL UpdateEditLine
JP Z,edit_loop
CALL PAGE_UP
JP EditDE
_ed_cutline
CP &18 ; < CTRL-X >? (cut line)
JR NZ,_ed_copy
; CTRL-X (cut line)
_ed_do_cut
PUSH DE
LD HL,EditBuffer
LD DE,PasteBuffer
LD BC,LINE_SIZE
LDIR ; copy line to paste buffer
CALL ShowPasteBuf ; display buffer on status line
POP DE
BIT 0,(IY+&0F) ; in Insert mode?
JP NZ,EditDE ; yes, no line to delete
_ed_deleteline
PUSH DE
CALL DeleteSrcLine ; delete line being edited
POP DE
CALL CSR_UP ; back up to last line
JP EditDE
_ed_copy
CP 3
JR NZ,_ed_paste
; CTRL-C (copy line)
PUSH HL
PUSH DE
LD HL,EditBuffer
LD DE,PasteBuffer
LD BC,LINE_SIZE
LDIR ; copy line to paste buffer
CALL ShowPasteBuf ; show buffer on status line
POP DE
POP HL
JP edit_loop
_ed_paste
CP &16 ; < CTRL-V >?
JR NZ,_ed_top
; CTRL-V = paste line
LD A,(PasteBuffer)
OR A ; anything to paste?
JP Z,edit_loop ; no,
JR _ed_newline ; yes,
_ed_top
CP &F8 ; < CTRL-UP >?
JR NZ,_ed_bottom
CALL UpdateEditLine
JP Z,edit_loop
LD DE,1 ; goto start of src code
JP EditDE
_ed_bottom
CP &F9 ; < CTRL-DOWN >?
JR NZ,_ed_enter
CALL UpdateEditLine
JP Z,edit_loop
LD DE,&3000 ; goto end of src code
JP EditDE
_ed_enter
CP &0D ; < CR >?
JP NZ,_ed_ascii
; < CR > or < ENTER > = insert new line
_ed_newline
BIT 0,(IY+&0F) ; already in < insert >?
JR NZ,_ed_insert ; yes,
CALL TestLine ; blank line?
JR Z,_ed_deleteline ; yes, delete it, stay in < edit >
; switching to < insert >
CALL UpdateEditLine ; try to store edited line
JP Z,edit_loop ; if error then stay in < edit >
CALL CmdLine
CALL PRTMSG ; show < insert > prompt
DB "< insert >"
DB &00
SET 0,(IY+&0F) ; flag < insert >
JR show_ins_page
_ed_insert
CALL TestLine ; blank line?
JR NZ,insert_line ; no,
LD A,(KeyCode)
CP &16 ; CTRL-V? (paste line)
JR Z,show_ins_page ; yes, stay in < insert >
JP EDIT ; no, switch to < edit >
insert_line
CALL UpdateEditLine ; try to insert line
JR Z,_il_done ; if error then stay on line
LD DE,(Arg1)
INC DE ; next src line
LD (Arg1),DE
; display upper half of src code page with inserted line
show_ins_page
LD DE,(Arg1)
LD A,E
SUB 9
LD E,A
LD A,D
SBC A,0
LD D,A
LD HL,0 ; cursor at 0,0
LD B,10
CALL ShowLinesAt ; show 10 lines starting at 0,0
LD (SrcAddrDe),HL
LD (SrcAddrEd),HL
CALL BlankLine ; blank edit line on screen
LD HL,EditBuffer
LD B,40 ; 40 chars in buffer
LD A,(KeyCode) ; CTRL-V?
CP &16
JR NZ,_il_clrbuf
EX DE,HL
LD HL,PasteBuffer
LD C,B
LD B,0
LDIR ; copy paste buffer to edit buffer
LD HL,EditBuffer
CALL ShowToEOL
JR _il_done
_il_clrbuf
LD (HL)," "
INC HL ; clear the edit buffer
DJNZ _il_clrbuf
_il_done
JP edit_line
; ASCII keys
_ed_ascii
CP " " ; low control code?
JR C,_ea_done ; yes, abort
CP &7F ; high control code?
JR NC,_ea_done ; yes, abort
LD B,A ; B = char
LD A,(EditBuffer)
CP ";" ; comment?
JR Z,_ed_inchr ; yes, no tabs
LD A,(TXT_POS)
CP LAB_SIZE ; end of label?
JR Z,_ea_blank
CP LAB_SIZE+5 ; end of opcode?
JR NZ,_ed_inchr
_ea_blank
LD B," " ; space at end of label/opcode
JR _ed_inchr
_ea_done
JP edit_loop
; insert char typed into edit line
_ed_inchr
PUSH BC
PUSH DE
LD A,(TXT_POS)
LD C,A
OR A ; at column 0?
JR NZ,_in_chr ; no,
; at column 0
LD A,B ; A = typed char
CP ";" ; making a comment?
JR Z,_in_com ; yes, insert to eol
; at column 0, making instruction
JR _in_tab
; not at column 0
_in_chr
LD A,(EditBuffer)
CP ";" ; comment?
JR NZ,_in_tab ; no, apply tabs
_in_com
LD A,39 ; yes, insert to eol
JR _in_move
_in_tab
CALL GetTab ; get next tab position
DEC A
_in_move
BIT 1,(IY+&0F) ; insert editing?
JR Z,_in_done ; no, done
SUB C ; A = number of chars to move
JR Z,_in_done ; if no chars to move then insert done
LD C,A
LD B,0
PUSH HL
ADD HL,BC ; calculate end of field address
LD D,H
LD E,L
DEC HL
LDDR ; move rest of field right 1 char
POP HL
_in_done
CALL ShowToEOL ; show changes
POP DE
POP BC
; store char in edit buffer, move cursor right
LD (HL),B ; store key char
CALL ShowEditChar ; show it on the edit line
_ed_right
LD A,(HL) ; A = current char
INC HL ; point to next char
INC (IY+&1B) ; move text cursor right
CP " " ; char = space?
JR NZ,_et_end ; no, done
CP (HL) ; yes, next char = space?
JR NZ,_et_end ; yes, continue moving right
LD A,(EditBuffer)
CP ";" ; comment line?
JR Z,_et_end ; yes, done
LD A,(IY+&1B)
CP LAB_SIZE+1 ; cursor at opcode tab?
JR Z,_et_end ; yes, done
CP LAB_SIZE+6 ; cursor in operand field?
JR C,_ed_right ; no, continue moving right
_et_end
LD A,(HL)
OR A ; end of buffer?
JR NZ,_et_done ; no,
DEC HL ; yes, don't go past last char
_et_done
JP edit_loop ; continue editing line
;----------------------------------------------------------
; Parse Edit Line and Store in Source Code
;
;; in: EditBuffer = plain text
;
;; out: NZ = success
; Z = failed
;
StoreEditLine
LD IX,line_buf3 ; buffer to hold src code line
PUSH IX
CALL ParseEditLine ; tokenize text in edit buffer
POP IX
BIT 7,C ; got 2nd header byte?
JR Z,_se_set1st ; no
LD (IX+1),B ; set 2nd header byte
_se_set1st
LD (IX+0),C ; set 1st header byte
LD A,C
AND &3F ; isolate line length
RET Z ; return if length = 0 (no line)
LD C,A ; C = length
XOR A
BIT 0,(IY+&0F) ; in < insert > mode?
JR NZ,_se_insert ; yes,
LD HL,(SrcAddrDe); no, HL- > src code being edited
LD A,(HL) ; get src code line type/len
AND &3F ; isolate length
_se_insert
SUB C ; subtract edit/insert line length
CALL NZ,L846E ; if not 0 then open/close gap to fit
LD DE,(SrcAddrDe); DE- > src code insert address
PUSH IX
POP HL ; HL- > line to insert
LD B,0
LDIR ; copy line into src code
INC C ; C = 1, NZ
RET
;----------------------------------------------------------
; Udpate Edited Line
;
;; out: Z = error, move cursor to error position
; NZ = no error, C = on same line
; NC = on next line (line deleted)
UpdateEditLine
PUSH HL
PUSH DE
CALL TestLine ; anything on the line?
JR NZ,_upds ; yes, store it
BIT 0,(IY+&0F) ; no, in < insert > mode?
JR NZ,_updc
CALL DeleteSrcLine ; no, delete the line
OR 1 ; NZ, NC
JR _updn ; done
_upds CALL StoreEditLine ; parse line and store in src code
_updc SCF
_updn POP DE
POP HL
RET NZ ; return if OK
LD B,0
LD HL,EditBuffer
LD C,(IY+&10) ; C = cursor pos
ADD HL,BC ; HL - > cursor pos in buffer
RET ; return error at cursor
;----------------------------------------------------------
; Add or Delete line of source code
;
;; in: A = bytes to add/delete (negative = delete)
;
;
L846E PUSH BC
LD B,0
JP P,_negateB ; if negative then B = -1
DEC B
_negateB
LD HL,(SrcAddrEd) ; HL = src code address
OR A
LD C,A ; BC = length of gap
LD D,H
LD E,L ; start = end
SBC HL,BC ; end = start + length
EX DE,HL
CALL AddDelSrc ; open/close gap in source code
POP BC
RET
;----------------------------------------------------------
; Show Paste Buffer Contents on Status Line
;
ShowPasteBuf
LD (IY+&1C),24 ; status line
LD HL,PasteBuffer
SET 0,(IY+&1D) ; ghosted text style
CALL _prtstr ; show buffer contents
RES 0,(IY+&1D) ; normal text style
LD (IY+&1C),10 ; edit line
RET
;----------------------------------------------------------
; Show Symbol Table
;
ListSymbols
LD HL,(SymTab)
CALL GetSymbol ; any symbols to show?
RET Z
CALL PRTMSG
DB &0D,"Symbol table:",&00
JR _list_symbols
;----------------------------------------------------------
; - List all Defined Symbols and their Values -
;
_list_symbols
LD HL,(SymTab)
_ls_nxtrow
LD B,2 ; 2 symbols per row
CALL Prt_CR
_ls_nxtsym
LD D,(HL)
INC HL ; get value
LD E,(HL)
INC HL
LD A,(HL) ; get 1st char of name
CP &FF
RET Z ; return if end of symbol table
BIT 7,A ; referenced in src code?
JR NZ,_ls_skip ; no,
CP "A" ; named symbol?
JR C,_ls_skip ; no,
INC HL ; get 2nd char of name
BIT 7,(HL) ; symbol defined?
DEC HL
JR NZ,_ls_skip ; no,
PUSH HL
CALL Prt_Symbol_Name ; print name
EX DE,HL
CALL PrtsHexWord ; print value
CALL PRTMSG
DB " ",&00
POP HL
DEC B ; 1 less symbol to print on this line
_ls_skip
LD DE,LAB_SIZE ; advance to next symbol
ADD HL,DE
INC B ; if B > 0 then
DJNZ _ls_nxtsym ; show 2nd symbol for this line
JR _ls_nxtrow ; next row
;-------------------------------------------------------------
; - Calculate Screen Address from Text Row and Column -
;
;; in: BC = row, column
;; out: HL = screen address
ScrnAddr
PUSH BC
LD H,0
LD L,B
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
LD B,H
LD C,L
ADD HL,HL
ADD HL,HL
ADD HL,BC
POP BC
LD B,&C0
ADD HL,BC
RET
;-------------------------------------------------------------
; - Display Character on Screen -
;
; Renders directly to screen memory, using custom
; character matrix table. Mode 2 only!
;
TextOut
LD BC,(TXT_POS)
AND &7F ; 7 bit ASCII
LD H,A
LD A,C ; don't print past column 40
CP 40
JP NC,txt_done
LD A,H
CALL ScrnAddr ; calculate screen address
EX HL,DE
LD BC,MATRIX ; BC = character matrix table
LD H,0
LD L,A
ADD HL,HL
ADD HL,HL ; L = char * 8
ADD HL,HL
ADD HL,BC ; HL = address of pattern
LD BC,&0855
BIT 0,(IY+&1D) ; ghosted?
JR NZ,_txtout_ghost
; BIT 1,(IY+&1D) ; inverse?
; JR NZ,_txtout_inv
_txtout_plain
LD A,(HL) ; get pattern byte from our ROM
LD (DE),A ; copy to screen
INC HL ; next pattern byte
LD A,D
ADD A,8
LD D,A ; next screen address
DJNZ _txtout_plain
RET
;_txtout_inv
; LD A,(HL) ; get pattern byte from our ROM
; XOR &FF ; invert pixels
; LD (DE),A ; copy to screen
; INC HL ; next pattern byte
; LD A,D
; ADD A,8
; LD D,A ; next screen address
; DJNZ _txtout_inv
; RET
_txtout_ghost
LD A,(HL) ; get pattern byte from our ROM
AND C ; mask off alternate pixels
RRC C ; rotate mask
LD (DE),A ; copy to screen
INC HL ; next pattern byte
LD A,D
ADD A,8
LD D,A ; next screen address
DJNZ _txtout_ghost
txt_done
RET
;-------------------------------------------------------------
; - Print Character to Screen -
;
_prtchr
PUSH AF
PUSH BC
PUSH DE
PUSH HL
CP &0C ; DELETE?
JR NZ,_prt_not_del
LD A,&20 ; yes, show < space >
CALL TextOut
JR _prt_left ; move cursor left
_prt_not_del
CP &20 ; control code?
JR C,_prt_ctrl ; yes, do control code function
CALL TextOut ; show character on screen
LD HL,(TXT_POS) ; HL = text cursor position
INC L ; move cursor right
JR _prt_pos
; control code
_prt_ctrl
LD HL,(TXT_POS)
CP 9 ; cursor right?
JR NZ,_prt_not_r
INC L ; yes, next column
JR _prt_pos
_prt_not_r
CP 8 ; cursor left?
JR NZ,_prt_not_l
_prt_left
LD HL,(TXT_POS)
DEC L ; yes, prev column
JR _prt_pos
_prt_not_l
CP &0D ; < CR >?
JR NZ,_prt_pos
_prt_enter
LD L,0 ; column 0
INC H ; next line down
LD A,H
CP 24 ; below last line?
JR C,_prt_pos ; no
CALL SCROLL_UP ; yes, scroll screen up 1 line
LD HL,&1700 ; text cursor at line 23, column 0
_prt_pos
LD (TXT_POS),HL ; update text cursor position
POP HL
POP DE
POP BC
POP AF
RET
;----------------------------------------------------------
; Show Character at Cursor Position in Edit Buffer
;
; Character displayed on edit line (line 10)
;
;; in: HL - > cursor pos in edit buffer
;
ShowEditChar
PUSH HL
LD BC,EditBuffer
LD A,(HL) ; get char
OR A
SBC HL,BC ; L = column
LD H,10 ; H = row 10
LD (TXT_POS),HL ; set cursor pos
CALL TextOut ; show char
POP HL
RET
;----------------------------------------------------------
; Show to End of Line in Edit Buffer
;
ShowToEOL
PUSH HL
PUSH HL
LD BC,EditBuffer
OR A
SBC HL,BC ; L = column
LD H,10 ; H = row 10
LD (TXT_POS),HL ; set cursor pos
_seloop
POP HL
LD A,(HL) ; get char
INC HL
OR A
JR Z,_sedone ; until end of string
PUSH HL
CALL TextOut ; show char
LD HL,TXT_POS
INC (HL)
JR _seloop
_sedone
LD H,10 ; H = row 10
LD (TXT_POS),HL ; set cursor pos
POP HL
RET
;-------------------------------------------------------------
; - Wait 16/25 Frames for Keypress -
;
; Return immediately if keypress detected, else return after
; 10 or 25 frames (0.16 or 0.5 seconds)
;
;; output: A = key
; NC = no key
;
waitkey16
BIT 1,(IY+&0F)
LD E,8 ; check 8 times (fast flash)
JR NZ,_wk_loop
LD E,25 ; check 25 times (slow flash)
_wk_loop
CALL InKey ; A = key pressed (waits 1 frame)
RET C ; return if got a key
DEC E
JR NZ,_wk_loop ; check again
RET
;-------------------------------------------------------------
; - Get Keyboard Input -
;
; flashes cursor while waiting for keypress
;
Get_Key
PUSH HL
LD BC,(TXT_POS); get cursor position (row, column)
CALL ScrnAddr ; calculate screen address
LD BC,&3800 ; advance to bottom line of character
ADD HL,BC
LD (HL),&7E ; draw cursor (overlays character)
CALL waitkey16 ; wait 16 frames for key press
POP HL
PUSH AF
LD A,(HL) ; get character at cursor pos
AND &7F
CP " "
JR NC,_noctrl ; don't show ctrl chars
LD A," "
_noctrl
PUSH HL
CALL TextOut ; redraw character (erases cursor)
POP HL
POP AF
RET C
CALL waitkey16 ; wait 16 frames for key press
JR NC,Get_Key
RET
;-------------------------------------------------------
; clear input line
;
ClearLineBuff
LD HL,LineBuffer
LD B,40 ; 40 char buffer
_clr_line_buff
LD (HL)," " ; fill buffer with spaces
INC HL
DJNZ _clr_line_buff
LD (HL),0 ; null end of buffer
RET
;--------------------------------------------------------
; - LINE INPUT -
;
InputCommand
CALL ClearLineBuff ; nothing typed so far
LD A,(TXT_POS)
LD (IY+0),A ; save starting cursor position
CALL CursorAddr ; HL = cursor address on input line
CALL Get_Key
CP "A" ; 'A' = return to assembler
JR Z,_ic_hot
CP "a"
JP NZ,_il_got_key
_ic_hot
LD (HL),A
CALL _prtchr ; show key on screen
INC HL
LD A,&0D ; insert < return > key
JR _il_got_key
InputLine
CALL ClearLineBuff ; nothing typed so far
LD A,(TXT_POS)
LD (IY+0),A ; save starting cursor position
_il_getkey
CALL CursorAddr ; HL = cursor address on line
CALL Get_Key
_il_got_key
CP &0D ; < CR > = line entered
JR Z,LineStartEnd ; return with DE,HL = start,end
CP 27 ; < ESC > = line entry aborted
RET Z
CP 12 ; < DEL > = delete char
JR NZ,_il_chkctrl
LD (HL)," "
_il_chkctrl
CP " " ; space or higher?
JR C,_il_prtchr ; no, don't store control chars
LD (HL),A ; yes, store char in buffer
_il_prtchr
CALL _prtchr ; show char on screen
LD A,(TXT_POS)
LD E,(IY+0) ; E = starting position
CP 40 ; past end of line?
JR C,_il_chkst
LD A,39 ; back to end of line
_il_chkst
CP E ; before start?
JR NC,_il_next ; no,
LD A,E ; yes, goto start position
_il_next
LD (TXT_POS),A ; update cursor position
JR _il_getkey ; continue getting line input
;----------------------------------------------------------
; calculate Line input Start and End addresses
;
;; Out: DE = start, HL = end
;
LineStartEnd
LD HL,LineBuffer
LD B,0
LD C,(IY+0) ; C = leftmost cursor position
ADD HL,BC
EX DE,HL ; DE- > leftmost cursor address
; calculate address of cursor on line
CursorAddr
LD BC,LineBuffer
LD HL,(TXT_POS)
LD H,0
ADD HL,BC ; HL points to last char
RET
;-----------------------------------------------------
; - Get Key Pressed on Keyboard -
;
; control codes converted to 7 bit ASCII equivalents
;
;; out: A = key or 0
; C = got a key
; NC = no key
InKey CALL &BD19 ; MC_WAIT_FLYBACK
CALL &BB09 ; KM_READ_CHAR
JR C,ik_got_key
XOR A ; no key = 0 (NULL)
JR ik_done
ik_got_key
CP 9 ; TAB ?
JR NZ,ik_copy
LD A,1 ; move to tab stop = 1 (SOH, CTRL-A)
JR ik_done
ik_copy
CP &E0 ; COPY ?
JR NZ,ik_rt
ik_ins LD A,2 ; insert char = 2 (STX, CTRL-B)
JR ik_done
ik_rt CP &F3
JR NZ,ik_lft
LD A,9 ; cursor right = 9 (HT)
JR ik_done
ik_lft CP &F2
JR NZ,ik_up
LD A,8 ; cursor left = 8 (BS, CTRL-H)
JR ik_done
ik_up CP &F0
JR NZ,ik_dn
LD A,11 ; cursor up = 11 (VT, CTRL-K)
JR ik_done
ik_dn CP &F1
JR NZ,ik_del
LD A,10 ; cursor down = 10 (LF, CTRL-J)
JR ik_done
ik_del CP &7F
JR NZ,ik_esc
LD A,12 ; < DELETE > = 12 (FF, CTRL-L)
JR ik_done
ik_esc CP &FC
JR NZ,ik_done
LD A,27 ; < ESC > = 27 (ESC)
ik_done
CP 1
CCF
RET
;----------------------------------------------------------
; - Edit memory -
;
EditMem
CALL Prt_CR
LD HL,(Arg1) ; HL = address
_em_next_line
CALL PrtHexWord ; print address
CALL PEEK ; get byte at address
PUSH AF
CALL prt_byte ; print byte in Hex
CALL prt_space
POP AF
CALL prt_ascii ; print byte as char
CALL prt_space
PUSH HL
CALL InputLine ; type in hex byte(s) or string
POP HL
CP 27 ; < ESC > = quit
JP Z,Prt_CR
CALL Prt_CR
LD B,0 ; B = number of bytes written
_em_next_byte
PUSH HL
CALL Hex2binHL ; convert Hex byte to binary
JR Z,_em_string ; if not Hex then may be string
; hex byte(s)
LD A,L
POP HL
CALL POKE ; write byte to RAM
INC HL
INC B
JR _em_next_byte ; loop until all bytes done
; ascii string
_em_string
POP HL
LD A,(DE) ; get char
INC DE
CP '"' ; opening quote?
JR NZ,_em_cmd ; no,
_em_nxtchr
LD A,(DE) ; yes, get next char
INC DE
CP '"' ; closing quote?
JR Z,_em_next_byte ; yes switch to getting bytes
CALL POKE ; no, write char to RAM
INC HL
INC B
OR A ; null?
JR NZ,_em_nxtchr ; no, continue writing string
RET
; inline command
_em_cmd
CP "?" ; skip byte?
JR NZ,_em_addr ; no,
INC HL ; skip to next address
JR _em_next_byte ; get next input byte
_em_addr
CP "@" ; entering new address?
JR NZ,_em_enter ; no,
CALL Hex2binHL ; yes, convert hex to binary
JR _em_next_line ; do next input line
_em_enter
RLC B ; any bytes written?
JR NZ,_em_next_line ; yes, do another line
INC HL ; next adddress
OR A ; end of input?
JR Z,_em_next_line ; yes, do another line
RET
;----------------------------------------------------------
; Get command line args
;
GetArgs
LD HL,(Arg1)
LD DE,(Arg2)
LD BC,(Arg3)
RET
;----------------------------------------------------------
; - D - Dump Memory
;
DumpMem
CALL Prt_CR
CALL GetArgs ; HL = start, DE = end, BC = bytes per row
LD A,(ArgC)
CP 2 ; end address specified?
JR NC,_got_end
LD DE,&FFFF ; no, set to top of memory
LD C,8 ; 8 bytes per row
LD A,10 ; 10 rows to dump
JR _dump_row
_got_end
CP 3
JR NZ,_no_bpr ; if no bytes per row then set to default
LD A,C
OR A
RET Z ; if bpr = 0 then quit
CP 10
JR C,_got_bpr
CP &10 ; bpr entered as 2 decimal digits?
JR C,_hex_bpr
SUB 6 ; yes, adjust to hex value
LD C,A
_hex_bpr
CP 13
JR C,_got_bpr
LD C,12 ; max 12 bytes per row
JR _got_bpr
_no_bpr
LD C,8 ; default 8 bytes per row
_got_bpr
LD A,255 ; dump continuously until end address
_dump_row
PUSH HL
SCF
SBC HL,DE ; if end_addr < start_addr then quit
POP HL
RET NC
PUSH AF ; row count -- > stack
CALL PrtHexWord ; show address
PUSH HL
LD B,C ; B = bytes per row
_dump_hex
CALL PEEK ; get byte from RAM bank
CALL prt_byte ; show as Hex bytes
CALL prt_space
INC HL ; next address
LD A,H
OR L ; if wrapped to 0000 then done
JR Z,_done_hex
DJNZ _dump_hex ; next hex byte
_done_hex
POP HL ; restore memory address
LD B,C ; restore bytes per row
_dump_asc
LD A,C
CP 9 ; if >8 bpr then don't show ASCII
JR NC,_skip_asc
CALL PEEK
CALL prt_ascii ; show as ASCII chars
_skip_asc
INC HL ; next address
LD A,H
OR L
JR NZ,_next_ascii
POP AF ; if wrapped to 0000 then done
JR _dump_done
_next_ascii
DJNZ _dump_asc ; next ascii char
_done_ascii
CALL Prt_CR
POP AF ; row count < -- stack
CALL next_row ; decrement row count, get key input
OR A ; all rows done?
JR NZ,_dump_row ; no, loop back to do next row
_dump_done
JP Prt_CR ; print < CR > at end of dump
;-------------------------------------------------------------
; - Next Listing Row -
;
; - Check for key pressed while listing. If C then
; continue. If < ESC > then pause.
;
; - If paused or no more rows to list then wait for key,
; then set new number of rows according to key pressed.
;
;; in: A = previous number of rows to list
;
;; out: A = new number of rows to list
; 0 = end listing
; 255 = list continuously
;
;; used by:- Unassemble, Dump.
;
next_row
LD B,A ; B = number of rows to do
CALL InKey ; check for key pressed while listing
CALL ToUpper
CP "C" ; if key = "C" then list continuously
JR NZ,_chk_space
_list_cont
LD B,255
JR _list_next
_chk_space
CP " " ; if key = < SPACE > then do 20 rows
JR NZ,_chk_cr
LD B,20
JR _list_next
_chk_cr
CP &0D ; if key = < CR > then do 1 row
JR NZ,_chk_esc
LD B,1
JR _list_next
_chk_esc
CP &1B ; if key = < ESC > then pause
JR Z,_dump_waitkey
LD A,B
CP 128 ; else if continuous then keep going
JR NC,_list_cont
DEC B ; else decrement row count
JR NZ,_list_next
_dump_waitkey ; all rows done or paused, so...
CALL WaitKey ; wait for keypress
CALL ToUpper
LD B,255
CP "C" ; if key = "C" then list continuously
JR Z,_list_next
LD B,20
CP " " ; if key = < SPACE > then do 20 rows
JR Z,_list_next
LD B,1
CP &0D ; if key = < CR > then do 1 row
JR Z,_list_next
LD B,0
CP &1B ; if key = < ESC > then no rows to do
JR Z,_list_next
LD B,10 ; else do 10 rows
_list_next
LD A,B
RET
;----------------------------------------------------------
; Show ASCII equivalent of byte
;
prt_ascii
AND &7F ; 7 bit ASCII
CP " "
JR NC,_prta ; show control codes as '.'
LD A,"."
_prta JP PRTCHR
;----------------------------------------------------------
; - U - unassemble
;
Unassemble
CALL Prt_CR
CALL GetArgs ; HL = start addr, DE = end addr
LD A,(ArgC)
CP 1
JR C,_u_no_arg ; no start or end specified
JR Z,_u_no_end ; start address only
_uend LD A,255 ; list continuously
JR _uloop
_u_no_arg
LD HL,0 ; start addr = 0000
_u_no_end
LD DE,&FFFF ; end addr = last memory location
LD A,8 ; list 8 rows
_uloop
CALL unasm ; unassemble an opcode
RET NC
CALL next_row
OR A
RET Z ; if all done then quit
JR _uloop
;----------------------------------------------------------
; Unassemble an Opcode
;
;; in: HL = start address, DE = end address
;
;; out: Carry Set = OK
; Carry clr = past end addr
;
unasm PUSH HL
SCF
SBC HL,DE ; quit if start addr > end addr
POP HL
RET NC
PUSH DE ; end addr -- > stack
PUSH AF ; list rows -- > stack
PUSH HL
CALL Decode ; decode the opcode
POP HL
LD A,C
AND 7
LD D,A ; D = number of bytes in opcode
INC A
LD (IY+7),A
CALL PrtHexWord ; print address
LD B,D ; B = number of bytes in opcode
PUSH HL
L8802 CALL PEEK ; read byte from memory
INC HL
CALL prt_byte ; show opcode byte
DJNZ L8802 ; next byte
LD A,4
SUB D ; if < 4 bytes then
JR Z,L8817
LD B,A
L880F CALL prt_space
CALL prt_space ; pad with spaces
DJNZ L880F
L8817 CALL prt_space ; trailing space
POP HL
LD (CodeAddr),HL ; opcode addr-1 (for prt_opcode)
SET 4,C ; not source code
PUSH HL
CALL prt_opcode ; print decoded opcode
CALL PadToEOL ; pad with spaces to end of line
POP HL
CALL PEEK ; get opcode 1st byte
CP &C9 ; RET?
JR Z,_hrule
CP &C3 ; JP?
JR NZ,_udone
_hrule LD B,37
LD A,"-"
_hrloop
CALL PRTCHR ; print "-"s (horizontal rule)
DJNZ _hrloop
CALL PRTMSG
DB " ",0 ; print " "
CALL Prt_CR
POP AF ; list rows < -- stack
CP 128 ; listing continously?
JR NC,_umod
DEC A ; no, modify row count
JR NZ,_umod
INC A ; don't go below 1!
_umod PUSH AF ; list rows -- > stack
_udone LD B,0
LD C,(IY+7) ; C = opcode length
DEC C
ADD HL,BC ; HL = next opcode
POP AF ; list rows < -- stack
POP DE ; end addr < -- stack
SCF
RET
;
; - Input Error -
;
ErrorMsg
CALL Say_Error
JP Prt_CR
;----------------------------------------------------------
; set Breakpoint
; B< number >=< address >
;
; if no '=' then show breakpoints
; if '=' but no address then kill breakpoint
;
SetBreak
CALL Prt_CR
LD A,(DE)
CP "="
JR NZ,Show_Breakpoints
INC DE
CALL Hex2binHL ; get address
LD B,0 ; to kill
JR Z,_set_brk
EX DE,HL
LD B,1 ; to set
_set_brk
LD HL,(Arg1) ; HL breakpoint number
LD A,H
OR A
JR NZ,ErrorMsg
LD A,L
DEC A ; index = 0~7
CP 8
JR NC,ErrorMsg
ADD A,A ; * 2
LD C,A
ADD A,A ; * 4
ADD A,C
LD C,A ; C = index * 6
LD HL,Breakpoints
LD A,B
LD B,0
ADD HL,BC ; index into breakpoint array
LD (HL),A ; set (1) or clear (0)
INC HL
LD (HL),D ; breakpoint address
INC HL
LD (HL),E
RET
;----------------------------------------------------------
; Clear All Breakpoints
;
ClearBreaks
LD HL,Breakpoints
LD BC,&3000 ; B = 48, C = 0
_clr_brk
LD (HL),C ; clear byte in breakpoint array
INC HL
DJNZ _clr_brk ; next byte
LD HL,&BF80
LD (SP_reg),HL ; set SP for breakpoints
RET
;----------------------------------------------------------
; Print a Breakpoint Number
;
;; in: C = "1"~"8"
;
PrtBreakpoint
CALL PRTMSG
DB "Breakpoint ",&00
LD A,C
JP PRTCHR
;----------------------------------------------------------
; Show All Breakpoints
;
Show_Breakpoints
LD HL,Breakpoints
LD BC,&0831 ; B = 8 breakpoints, C = "1"
_sbs_loop
CALL PrtBreakpoint
CALL prt_space
LD A,(HL) ; get status
OR A
JR NZ,_sbs_active ; 1 = active
CALL PRTMSG
DB "unused",&00 ; 0 = inactive
LD DE,6 ; distance to next entry
JR _sbs_next
_sbs_active
INC HL
LD D,(HL)
INC HL ; get address
LD E,(HL)
EX DE,HL
CALL PRTMSG
DB "=",&00
CALL PrtsHexWord ; print address
EX DE,HL
LD DE,4
_sbs_next
ADD HL,DE ; advance to next entry
INC C ; next breakpoint number
CALL Prt_CR
DJNZ _sbs_loop
RET
;----------------------------------------------------------
; Register Display Map
;
L88C9 DB &16,&01,&0F,&03
DB &10,&02,&11,&05
DB &12,&04,&13,&07
DB &14,&06,&0D,&80
DB &08,&82,&09,&84
DB &0A,&86,&0C,&88
DB &0B,&8C,&FF
L8B78 DB "AFBCDEHL"
DB "IXIYSPPC"
L8B88 DB "SZ H PNC"
;----------------------------------------------------------
; Find Register
;
L7A62 CALL Get_Alpha
PUSH BC
LD HL,cc_names
CALL Identify
POP HL
LD B,H
RET
;----------------------------------------------------------
; - SHOW REGISTERS / EDIT REGISTER -
;
Registers
LD DE,LineBuffer
CALL Next_Alpha
LD C,0
CALL L7A62 ; get register id
JP C,ShowRegs
;edit register
CALL Prt_CR
LD HL,L88C9 ; register display map
L88FF LD A,(HL)
CP &FF ; end of map?
JP Z,ErrorMsg
CP C
INC HL
JR NZ,L88FF
LD B,(HL)
CP &0C
JR NZ,L891A
LD A,(IY+6)
CP &DD
LD A,"X"
JR Z,L891A
INC A
INC B
INC B
L891A LD (IY+6),A
PUSH BC
LD HL,cc_names
CALL L7E8C ; print register
POP BC
LD E,B
RES 7,E
LD D,0
LD HL,CPU_Regs ; CPU register values
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL)
BIT 7,B ; 16 bit register?
CALL Z,prt_space ; no, pad out with space
CALL PrtMsg
DB " = ",0
BIT 7,B ; 16 bit register?
LD A,D
CALL NZ,prt_byte ; yes, show upper reg contents
LD A,E
CALL prt_byte ; show lower reg contents
CALL prt_space
PUSH BC
PUSH HL
CALL InputLine ; input new value
CALL Prt_CR
CALL Hex2binHL
POP DE
POP BC
RET Z
EX DE,HL
BIT 7,B
JR Z,L8955
LD (HL),D
L8955 DEC HL
LD (HL),E
RET
;--------------------------------------------------------
; - N -
;
; Sets which Upper ROM will be active when reading memory
;
SetROM LD A,(ArgC)
CP 1 ; if no rom specified then
JP C,_prt_rom ; show current selection
LD HL,(Arg1)
LD A,H
OR A
JR nz,_no_rom
LD A,L
CP 16
JR C,_got_rom_number
_no_rom
LD A,&FF
_got_rom_number
LD (Upper_ROM),A
_prt_rom
CALL PrtMsg
DB " Upper ROM ",0
LD A,(Upper_ROM)
CP 16
JR NC,_no_rom_msg
LD A,(Upper_ROM)
CALL prt_byte
CALL PrtMsg
DB " selected",&0D,0
RET
_no_rom_msg
CALL PrtMsg
DB "disabled",&0D,0
RET
;--------------------------------------------------------
; - X -
;
; Sets which 64k RAM bank will be used for writing and/or
; reading memory. A single digit specifies the bank number
; for both writing and reading. 2 digits specify separate
; Write and Read banks.
;
; Bank 0 is base 64k RAM.
; Bank 1 is 2nd 64k.
;
;Relates to;
; assembler - writing object code to memory
; debugger - load/save/move/fill/dump/unassemble/search
;
SetRAM CALL Prt_Space
LD A,(ArgC)
CP 1
JR C,_prt_bank ; if no arg then show current selection
CP 2 ; separate 'bank read' number?
JR Z,_sr_arg2 ; yes,
LD DE,LineBuffer
CALL Next_Alpha ; skip over command letter
CALL Get_Alpha ; find arg1
CALL GetHexDigit
LD L,A ; L = 1st digit
LD H,L ; assume read bank = write bank
CALL GetHexDigit
JR C,_sr_got1 ; Carry Set = no 2nd digit
JR _sr_got2 ; else 2 digits
_sr_arg2
LD HL,(Arg1) ; get 'bank write' number
LD A,(Arg2) ; get 'bank read' number
_sr_got2
LD H,A ; H = 2nd digit (bank read)
_sr_got1
LD A,L ; A = 1st digit (bank write)
RLCA
RLCA
RLCA
RLCA
OR H ; bank w/r = (write*16)+read
_setram
LD (Bug_Bank),A
LD (RAM_Bank),A
_prt_bank
JP PRTBNK ; show RAM bank selection
;----------------------------------------------------------
; Get next Hexadecimal Digit from Buffer
;
;; in: DE - > char in Hexadecimal string
;; out: DE - > next char
; A = number 0~15 (0~9,A~F)
; Carry set if not Hex
;
GetHexDigit
LD A,(DE) ; get digit (ASCII char)
INC DE ; point to next char
CP "a"
JR C,_ghdu ; convert lower case to upper case
AND &DF
_ghdu SUB "0" ; convert "0"~"9" to 0~9
RET C
CP 10 ; if 9 or less then done
JR C,_ghd1
SUB 7 ; convert "A"~"F" to 10~15
RET C
_ghd1 CP 16
CCF
RET
;----------------------------------------------------------
; - S -
;
; Search Memory for Byte pattern or ASCII text string
;
SearchMem
LD HL,0
LD (Arg1),HL
LD DE,LineBuffer
CALL Next_Alpha
LD BC,line_buf3
L8984 CALL Hex2binHL
JR Z,L8997
LD A,H
OR A
JR Z,L8992
LD (Arg1),HL
JR L8984
L8992 LD A,L
LD (BC),A
INC BC
JR L8984
L8997 LD A,(DE) ; get char
CP '"' ; quote?
JR NZ,_gotstr ; no
INC DE
_s_ch LD A,(DE) ; get next char
INC DE
CP '"' ; ending quote?
JR Z,L8984 ; yes
OR A ; end of line?
JR Z,_gotstr ; yes
LD (BC),A ; store char
INC BC
JR _s_ch ; next char
_gotstr
LD H,B
LD L,C
LD DE,line_buf3
OR A
SBC HL,DE
LD B,H
LD C,L
LD HL,(Arg1)
_search_next
CALL PRTMSG
DB &0D,"searching...",&00
_searchm
LD DE,line_buf3
PUSH BC
PUSH HL
CALL strcmpx ; compare in bank x
POP HL
POP BC
JR Z,_found_string
INC HL ; no match, try next location
LD A,H
OR L
JR NZ,_searchm ; unless end of memory
JR _search_done
_found_string
XOR A
LD (TXT_POS),A
CALL PrtMsg
DB "found at",0
CALL PrtsHexWord ; print location of string found
INC HL
CALL WaitKey
CP &0D
JR Z,_search_next
_search_done
JP Prt_CR
;-----------------------------------------------------------
; - Proceed -
;
; Execute code as subroutine
;
; equivalent to CALL xxxx, break
;
Proceed
CALL Prt_CR
XOR A
LD (RAM_BANK),A ; force to bank 0
LD A,(ArgC)
DEC A ; address specified?
JP NZ,ErrorMsg
LD HL,(Arg1)
LD (L8CE1),HL ; poke address to xxxx
LD HL,L8CE0 ; HL- > our CALL xxxx code
JR goHL ; execute our code, then break
;-----------------------------------------------------------
; - Go -
;
; execute code with no return
;
; equivalent to JP xxxx
;
Go CALL Prt_CR
XOR A
LD (RAM_BANK),A ; force to bank 0
LD A,(ArgC)
OR A ; address specified?
JR NZ,_go_addr ; yes,
LD HL,(PC_reg)
LD A,H ; no, is current PC valid?
OR L
JR NZ,_got_PC ; yes,
_go_err
JP ErrorMsg ; no, invalid PC!
_go_addr
DEC A ; too many args?
JR NZ,_go_err
LD HL,(Arg1)
goHL LD (PC_reg),HL ; set PC
_got_PC
CALL SetBreakpoints ; set all breakpoints
go2brk DI
LD SP,CPU_Regs ; SP = register values
POP AF
POP BC
POP DE
POP HL ; load all other registers
POP IX
POP IY
LD SP,(SP_reg) ; SP = SP_reg
PUSH HL ; push HL_reg onto stack
LD HL,(PC_reg) ; HL = PC_reg
EX (SP),HL ; PC on stack, HL = HL_reg
EI
RET ; jump to address
;------------------------------------------------------
; Save CPU Registers after hitting breakpoint
;
Break DI
EX (SP),HL ; get return address
DEC HL
DEC HL
DEC HL ; back up over breakpoint
LD (PC_reg),HL ; save PC
EX (SP),HL ; restore HL
INC SP
INC SP ; discard return address
LD (SP_reg),SP ; save SP
LD SP,SP_reg ; point stack to register save area
PUSH IY
PUSH IX
PUSH HL
PUSH DE ; save all other registers
PUSH BC
PUSH AF
EXX
PUSH HL
PUSH DE
PUSH BC
EXX
EX AF,AF'
PUSH AF
EX AF,AF'
LD IY,Variables
LD SP,(STACK) ; restore stack position
EI
LD BC,TraceBrk
LD HL,(PC_reg)
CALL CmpHL2BC ; breakpoint at Trace Break?
LD HL,(BrkAddr)
JP Z,TraceAddr ; yes, trace next instruction
CALL ClrBreakpoints ; no, hide breakpoints
CALL ShowBreak ; show our breakpoint
JP DebugLoop
;----------------------------------------------------------
; Compare breakpoint to our address
;
;; in: HL- > element in breakpoint array
;; out: Z = equal, HL- > addr to save code in breakpoint array
; NZ = not our address
;
CmpBrk LD BC,Break
INC HL ; skip status
LD D,(HL)
INC HL ; get code address
LD E,(HL)
LD (BrkAddr),DE ; save address
INC HL ; HL- > code save in breakpoint array
LD A,(DE) ; get opcode at address
CP &CD ; CALL?
RET NZ ; no, not us!
INC DE
LD A,(DE)
CP C ; Low address byte = Break vector?
RET NZ ; no, not us!
INC DE
LD A,(DE) ; High address byte = Break vector?
CP B
RET ; Z = it's us, NZ = not us
;----------------------------------------------------------
; Restore Breakpoint Code
;
; Copies original code over breakpoint
;
;; in: HL- > copy of original code in breakpoint array
; DE- > code address after breakpoint
;
ClrBreak
DEC DE ; back to start of breakpoint code
DEC DE
LD BC,3 ; 3 bytes to copy
LDIR ; copy original code over CALL Break
RET
;----------------------------------------------------------
; - Restore Original Code at all Breakpoints -
;
ClrBreakPoints
LD B,8
LD HL,Breakpoints
_rb_loop
PUSH BC
LD A,(HL) ; status
OR A
JR Z,_rb_next ; skip breakpoint if inactive
PUSH HL
CALL CmpBrk ; is it pointing to CALL Break?
CALL Z,ClrBreak ; yes, restore original code
POP HL
_rb_next
LD BC,6
ADD HL,BC ; skip to next breakpoint
POP BC
DJNZ _rb_loop ; do next breakpoint
RET
;----------------------------------------------------------
; Set Breakpoint
;
;; in: DE = code address
;
;; NOTE: breakpoint will not be set if it will overwrite
; part of an existing breakpoint!
;
SetBrk EX DE,HL
LD HL,(BrkAddr)
LD BC,(PC_reg)
LD A,3 ; 3 addresses to check
_sbk_prev
CALL CmpHL2BC ; breakpoint already set?
RET Z ; yes, abort
DEC BC ; address -1
DEC A
JR NZ,_sbk_prev ; check previous address
LD BC,3
PUSH HL
LDIR ; copy breakpoint into code
POP DE
LD HL,TraceBrk
LD C,3 ; set breakpoint vector
LDIR
RET
;----------------------------------------------------------
; Set All Active Breakpoints
;
SetBreakpoints
LD B,8 ; 8 breakpoints
LD HL,Breakpoints ; HL- > 1st breakpoint
_sbp_loop
PUSH BC
LD A,(HL)
OR A
JR Z,_sbp_next ; skip if inactive
PUSH HL
CALL CmpBrk ; is it our address?
CALL NZ,SetBrk ; yes, set breakpoint
POP HL
_sbp_next
LD BC,6
ADD HL,BC ; skip to next breakpoint
POP BC
DJNZ _sbp_loop ; check next breakpoint
RET
;----------------------------------------------------------
; Show our breakpoint
;
;; in: DE = address of our code
;
ShowBreak
LD HL,Breakpoints
LD BC,&0831 ; B = 8 breakpoints , C = "1"
_shb_loop
PUSH BC
LD BC,(PC_reg) ; BC = code address
LD A,(HL) ; breakpoint active?
OR A
LD DE,6
JR Z,_shb_next ; no, skip it
INC HL
LD D,(HL) ; yes, get breakpoint address
INC HL
LD E,(HL)
EX DE,HL
CALL CmpHL2BC ; is it our code?
EX DE,HL
JR Z,_shb_done ; yes,
LD DE,4
_shb_next
ADD HL,DE ; no, skip to next breakpoint
POP BC
INC C
DJNZ _shb_loop ; next breakpoint
RET
_shb_done
POP BC
CALL PrtBreakpoint
CALL Prt_CR
;----------------------------------------------------------
; Show registers
ShowRegs
XOR A
LD (RAM_BANK),A ; force to bank 0
LD HL,0
LD (TXT_POS),HL
LD C,0 ; register index
L8AFF LD A,0 ; normal registers
CALL ShowRegPair ; show register and its contents
LD A,C
OR A ; AF?
JR NZ,L8B3B ; no,
; show AF, contents of A, flag states
L8B18 CALL prt_space
LD A,D
CALL prt_ascii ; print contents of A as char
CALL prt_space
LD A,E
LD DE,L8B88 ; DE = flag names
LD B,8 ; 8 flag bits
L8B2B RLA ; Carry = flag bit
PUSH AF
LD A,(DE) ; get flag name
JR C,L8B32 ; flag bit set?
LD A,"-" ; no,
L8B32 CALL PRTCHR ; print flag name or space
POP AF
INC DE
DJNZ L8B2B ; next flag bit
CALL PrtMsg
DB " ",0
JR ShowAltReg
; other registers
L8B3B LD B,5 ; bytes of memory dump
LD A,C
CP 4
JR C,reg_dump
LD B,7 ; bytes if IX,IY
CP 6
JR C,reg_dump
LD B,10 ; bytes if SP,PC
reg_dump
PUSH BC
PUSH DE
reg_dump_bytes
LD A,(DE)
INC DE
CALL prt_byte ; show target memory as hex bytes
CALL prt_space
DJNZ reg_dump_bytes
POP DE
POP BC
LD A,B
CP 8
JR NC,L8B47 ; no ascii if > 7 hex bytes
reg_dump_asc
LD A,(DE)
INC DE
CALL prt_ascii ; show target memory as ascii chars
DJNZ reg_dump_asc
CALL prt_space
LD A,C
CP 4 ; has an alternate register?
JR NC,L8B47
ShowAltReg
LD A,1 ; alternate registers
CALL ShowRegPair ; show alt register and its contents
L8B47 CALL PadToEOL
INC C
LD A,C
CP 8
JR NZ,L8AFF ; next register
CALL PadToEOL
LD DE,&FFFC
LD HL,(PC_reg)
LD A,12 ; 12 lines to show
_uline CALL unasm ; show 1 line of unassembled code
DEC A
JR NZ,_uline
_blank LD A,(TXT_ROW)
CP 23
JR NC,_showreg_done
CALL BlankLine ; clear lines below unassembly
CALL Next_Line
JR _blank
_showreg_done
CALL CmdLine
RET
;----------------------------------------------------------
; Show 16 bit Register and its contents
;
;; in: DE = name array, C = index, A = register set
;; out: DE = register contents
;
ShowRegPair:
LD DE,L8B78 ; register names
LD HL,CPU_regs ; register contents
CP 1
JR NZ,_srp_altr
LD HL,Alt_regs ; alt register contents
_srp_altr
LD B,0
RLC C ; 2 bytes per index
ADD HL,BC ; index into register contents
EX HL,DE
ADD HL,BC ; index into register names
EX HL,DE
RRC C
LD B,A ; B = register set
LD A,(DE)
INC DE
CALL PRTCHR ; print upper register name
LD A,(DE)
INC DE
CALL PRTCHR ; print lower register name
DJNZ _srp_n
LD A,"'" ; print "'" if alt reg
CALL PRTCHR
_srp_n
LD E,(HL) ; E = lower register contents
INC HL
LD D,(HL) ; D = upper register contents
INC HL
EX DE,HL
CALL PrtsHexWord ; print register contents
EX DE,HL
RET
;----------------------------------------------------------
; Spaces to End of Line
;
_pte_space
CALL prt_space
PadToEOL
LD A,(TXT_POS)
CP 40
JR C,_pte_space
JP Prt_CR
;----------------------------------------------------------
; - Trace -
;
Trace XOR A
LD (RAM_BANK),A ; force to bank 0
LD A,7
LD (TXT_POS),A
LD A,(ArgC)
OR A ; if no address arg then use PC
JR Z,TraceShow
LD HL,(Arg1)
JR TraceAddr ; use address arg
_trace_next
LD DE,TraceBrk
LD HL,(PC_reg) ; HL = code address
LD B,4
XOR A
_trclr DEC DE
LD (DE),A ; clear trace buffer
DJNZ _trclr
PUSH HL
CALL Decode ; get opcode class and length
POP HL
LD B,C
LD A,C
AND &0F
LD C,A ; BC = opcode length
LD A,B
LD B,0
LDIR ; copy opcode to trace buffer
LD (BrkAddr),HL ; set breakpoint address
BIT 6,A
JR NZ,L8BDC ; class = (bit 6)?
BIT 2,A
JR NZ,L8BDC ; clase = (bit 2)?
CALL L8BE5
JR NZ,L8BDC
TraceAddr
LD (PC_reg),HL ; store address
TraceShow
CALL ShowRegs ; show registers and unassembled code
_tr_waitkey
CALL CmdLine
CALL BlankLine ; clear the command line
CALL PrtMsg
DB "< trace >",0 ; show trace prompt
LD HL,LineBuffer
LD (HL)," "
CALL Get_Key ; key input with flashing cursor
CP " "
JR C,_tr_ctrl ; don't print control codes
CALL _prtchr
_tr_ctrl
CALL ToUpper
LD (KeyCode),A
CP &0D ; < CR >?
JR Z,_trace_next ; yes, trace next instruction
CP " " ; < SPACE >?
JR Z,_trace_next ; yes, trace next instruction
CP "." ; "."?
JR Z,_trace_next ; yes, execute next instruction
LD B,&40
CP "Z" ; "Z"? (toggle Zero flag)
JR Z,ToggleFlags
LD B,&01
CP "C" ; "C"? (toggle Carry flag)
JR Z,ToggleFlags
LD B,&04
CP "P" ; "P"? (toggle Parity/overflow flag)
JR Z,ToggleFlags
CP "V" ; "V"? (toggle Parity/overflow flag)
JR Z,ToggleFlags
LD B,&80
CP "S" ; "S"? (toggle Sign flag)
JR Z,ToggleFlags
CP 27 ; < ESC >?
JP Z,DebugLoop ; yes, exit trace mode
JR _tr_waitkey ; else wait for next key press
ToggleFlags
LD HL,AF_Reg
LD A,B
XOR (HL)
LD (HL),A
JR TraceShow
L8BDC LD HL,TraceOp ; HL- > our code
LD (PC_reg),HL ; PC = our code
JP go2brk ; execute our code, then break
; trap dangerous instructions
L8BE5 LD DE,TraceOp
LD A,(DE) ; get opcode
CP &76 ; 76 = HALT
DEC HL
RET Z
INC HL
CP &FB ; FB = EI
RET Z
CP &ED ; ED instruction?
INC DE ; next addr
JR NZ,L8C07 ; no,
LD A,(DE) ; yes, get next opcode byte
CP &46 ; ED46 = IM0
RET Z
CP &5E ; ED5E = IM2
RET Z
CP &4D
JR Z,L8C03 ; ED4D = RETI
CP &45
L8C03 JP Z,L8CA0 ; ED45 = RETN
RET
L8C07 CP &E9 ; E9 = JP (HL)
JR NZ,L8C0F
LD HL,(HL_reg)
RET
L8C0F CP &DD ; DD instruction?
JR NZ,L8C1C ; no,
LD A,(DE) ; yes get next opcode byte
CP &E9 ; DDE9 = JP(IX)
JR NZ,L8C29 ; no,
LD HL,(IX_reg) ; yes, PC = IX
RET
L8C1C CP &FD ; FD instruction?
JR NZ,L8C29 ; no,
LD A,(DE) ; yes, get next opcode byte
CP &E9 ; FDE9 = JP (IY)
JR NZ,L8C29 ; no,
LD HL,(IY_reg) ; yes, PC = IY
RET
L8C29 LD C,A
AND &C7
CP &C7 ; RST xx?
LD A,C
JR NZ,L8C3A ; no,
AND &38
LD (DE),A ; yes, change to JR
INC DE
XOR A
LD (DE),A ; JR +00
JP L8CB2
L8C3A CP &C9 ; RET
JR Z,L8CA0
CP &C3 ; JP
JR Z,L8C7C
CP &CD ; CALL
JP Z,L8CB2
CP &18 ; JR
JR Z,L8C87
LD B,3
CP &38 ; JR C
JR Z,L8C81
DEC B
CP &30 ; JR NC
JR Z,L8C81
DEC B
CP &28 ; JR Z
JR Z,L8C81
DEC B
CP &20 ; JR NZ
JR Z,L8C81
CP &10 ; DJNZ
JR Z,L8C8F
RLA
RET NC
RLA
RET NC
DEC DE
LD A,(DE)
RRA
RET C
RRA
JR C,L8C75
RRA
JP C,L8CAD
JR L8C9B
L8C75 RRA
RET C
CALL L8CC0
JR NC,L8C7F
L8C7C LD HL,(L8CE7)
L8C7F XOR A
RET
; JR CC
L8C81 LD A,B
CALL L8CC0
JR NC,L8C7F
L8C87 LD A,(DE)
LD C,A
RLA
SBC A,A
LD B,A
ADD HL,BC
XOR A
RET
; DJNZ
L8C8F LD BC,(BC_reg)
DEC B
LD (BC_reg),BC
JR NZ,L8C87
RET
; RET CC
L8C9B CALL L8CC0 ; condition met?
JR NC,L8C7F ; no, trace next
; RET
L8CA0 LD HL,(SP_reg)
LD E,(HL)
INC HL
LD D,(HL)
INC HL
LD (SP_reg),HL
EX DE,HL
L8CAB XOR A
RET
; CALL CC
L8CAD CALL L8CC0 ; conditon met?
JR NC,L8CAB ; no, trace next
L8CB2 LD A,(KeyCode)
CP "." ; yes, proceeding?
JR NZ,trace_in ; no, trace into subroutine
AND A
RET ; yes, return NZ = proceeding
trace_in:
EX DE,HL
LD HL,(SP_reg)
DEC HL
LD (HL),D ; push return addr onto trace stack
DEC HL
LD (HL),E
LD (SP_reg),HL
JP L8C7C ; trace next
;----------------------------------------------------------
; Process Condition Code
;
;; in: A = Condition Code
;; out: Carry set = Condition met
;
L8CC0 LD BC,(AF_Reg) ; C = Flags
AND 7 ; 3 bits in CC
LD B,A ; B = CC
LD A,C ; A = Flags
LD C,B
SRL C ; CC bits 2~1 = 00?
JR Z,L8CD4 ; yes,
DEC C ; = 01?
JR Z,L8CDA ; yes,
DEC C ; = 10?
JR Z,L8CD8 ; yes,
RRCA ; CC = 11x, test S flag (bit 7)
L8CD4 RRCA ; CC = 00x, test Z flag (bit 6)
RRCA
RRCA
RRCA
L8CD8 RRCA ; CC = 10x, test P/V flag (bit 2)
RRCA
L8CDA RRCA ; CC = 01x, test C flag (bit 0)
BIT 0,B ; CC bit 0 = 1?
RET NZ ; yes, CC (eg. Z)
CCF ; else NOT CC (eg. NZ)
RET
;----------------------------------------------------------
; Initializated Data (copied to RAM at startup)
;
IDATA JP _prtchr ; print char redirect
JP _peek ; read memory redirect
CALL 0 ; proceed?
CALL Break
DB 0 ; trace?
DB 0,0,0
CALL Break ; breakpoint?
JP DebugLoop
;ReadROM
OUT (C),A ; select ROM
LD A,(HL) ; read ROM
OUT (C),C ; restore original selection
RET
_idata_end
;
; keyword name lists
;
directive_names
DB &80+"O","R","G" ; 0
DB &80+"D","B" ; 1
DB &80+"D","W" ; 2
DB &80+"D","S" ; 3
DB &80+"E","Q","U" ; 4
DB &80+"E","N","T" ; 5
DB &80+"I","N","C","B" ; 6
DB &80+"S","T","R" ; 7
DB &80+"W","R","I" ; 8
DB &80+"R","E","P","T" ; 9
DB &80+"R","E","N","D" ; 10
DB &80+"=" ; 11
DB &80+"I","F" ; 12
DB &80+"I","F","D" ; 13
DB &80+"E","L","S","E" ; 14
DB &80+"E","N","D","F" ; 15
DB &80
opcode_names
DB &80+"L","D","I"
DB &80+"L","D","D"
DB &80+"L","D"
DB &80+"P","U","S","H"
DB &80+"P","O","P"
DB &80+"R","E","T","I"
DB &80+"R","E","T","N"
DB &80+"C","P","L"
DB &80+"C","A","L","L"
DB &80+"J","R"
DB &80+"J","P"
DB &80+"I","N","C"
DB &80+"D","E","C"
DB &80+"C","P","I"
DB &80+"C","P","D"
add_names
DB &80+"A","D","D"
DB &80+"A","D","C"
DB &80+"S","U","B"
DB &80+"S","B","C"
DB &80+"A","N","D"
DB &80+"X","O","R"
DB &80+"O","R"
DB &80+"C","P"
DB &80+"R","L","C","A"
DB &80+"R","L","A"
DB &80+"R","L","D"
DB &80+"E","X","X"
DB &80+"E","X"
DB &80+"R","R","C","A"
DB &80+"R","R","A"
DB &80+"R","R","D"
rlc_names
DB &80+"R","L","C"
DB &80+"R","R","C"
DB &80+"R","L"
DB &80+"R","R"
DB &80+"S","L","A"
DB &80+"S","R","A"
DB &80+"S","L","L"
srl_names
DB &80+"S","R","L"
DB &80+"B","I","T"
DB &80+"R","E","S"
DB &80+"S","E","T"
DB &80+"D","J","N","Z"
DB &80+"R","S","T"
DB &80+"R","C","A","L"
DB &80+"R","S","C","L"
DB &80+"N","O","P"
DB &80+"R","E","T"
DB &80+"N","E","G"
DB &80+"C","C","F"
DB &80+"S","C","F"
DB &80+"H","A","L","T"
DB &80+"D","I"
DB &80+"E","I"
DB &80+"I","M","0"
DB &80+"I","M","1"
DB &80+"I","M","2"
DB &80+"D","A","A"
DB &80+"I","N","I"
DB &80+"I","N","D"
DB &80+"I","N"
DB &80+"O","U","T"
DB &80+"O","T","I"
DB &80+"O","T","D"
DB &80
cc_names
DB &80+"Z"
DB &80+"N","Z"
DB &80+"N","C"
DB &80+"M"
DB &80+"P","O"
DB &80+"P","E"
DB &80+"P"
DB &80+"B","C"
DB &80+"D","E"
DB &80+"H","L"
DB &80+"S","P"
DB &80+"I",3 ; 3 = IX/IY
DB &80+"A","F"
r_names
DB &80+"(","I",3,1,")" ; 3 = IX/IY, 1 = +d
DB &80+"B"
DB &80+"C"
DB &80+"D"
DB &80+"E"
DB &80+"H"
DB &80+"L"
DB &80+"(","H","L",")"
DB &80+"A"
DB &80+"I"
DB &80+"R"
DB &80+"(","I",3,")" ; 3 = IX/IY
DB &80+"(","C",")"
DB &80+"(","S","P",")"
DB &80+"(","B","C",")"
DB &80+"(","D","E",")"
DB &80+"(",2,")" ; 2 = nnnn
DB &80+2 ; 2 = nnnn
DB &80
; opcode syntax tables
L6B5F DB &BC, &00 ; NOP
DB &0D, &1F ; LD BC,nn
DB &0F, &96 ; LD (BC),A
DB &31, &00 ; INC BC
DB &31, &E0 ; INC B
DB &35, &E0 ; DEC B
DB &0D, &FF ; LD B,n
DB &60, &00 ; RLCA
DB &71, &AD ; ...
DB &41, &48 ;
DB &0E, &DC ;
DB &35, &00 ;
DB &32, &00 ;
DB &36, &00 ;
DB &0E, &1F ;
DB &74, &00 ;
DB &AF, &E0 ;
DB &0D, &3F ;
DB &0F, &B6 ;
DB &31, &20 ;
DB &32, &20
DB &36, &20
DB &0E, &3F
DB &64, &00
DB &2B, &E0
DB &41, &49
DB &0E, &DD
DB &35, &20
DB &32, &40
DB &36, &40
DB &0E, &5F
DB &78, &00
DB &28, &5F
DB &0D, &5F
DB &0F, &CA
DB &31, &40
DB &32, &60
DB &36, &60
DB &0E, &7F
DB &E8, &00
DB &28, &3F
DB &41, &4A
DB &0D, &5E
DB &35, &40
DB &32, &80
DB &36, &80
DB &0E, &9F
DB &20, &00
DB &28, &7F
DB &0D, &7F
DB &0F, &D6
DB &31, &60
DB &32, &A0
DB &36, &A0
DB &0E, &BF
DB &CC, &00
DB &2A, &1F
DB &41, &4B
DB &0E, &DE
DB &35, &60
DB &32, &C0
DB &36, &C0
DB &0E, &DF
DB &C8, &00
DB &FF, &FF
L6BE2
DB &C0, &40, &15
DB &00, &2C, &5F
DB &2F, &E0, &24
DB &5F, &11, &00
DB &42, &DF, &B3
DB &E0, &C0, &20
DB &C0, &00, &2C
DB &3F, &BC, &00
DB &24, &3F, &27
DB &E0, &46, &DF
DB &B3, &E0, &C0
DB &60, &15, &20
DB &2C, &7F, &FB
DB &D6, &24, &7F
DB &11, &20, &4B
DB &E0, &B7, &E0
DB &C2, &00, &6C
DB &00, &2E, &1F
DB &F6, &DE, &26
DB &1F, &BC, &00
DB &4E, &DF, &BB
DB &E0, &C0, &A0
DB &15, &40, &2C
DB &BF, &73, &6A
DB &24, &BF, &11
DB &40, &53, &E0
DB &B3, &E0, &C0
DB &C0, &2E, &A0
DB &2C, &DF, &71
DB &2A, &24, &DF
DB &BC, &00, &57
DB &E0, &B3, &E0
DB &C0, &E0, &15
DB &A0, &2C, &FF
DB &D4, &00, &24
DB &FF, &11, &A0
DB &5B, &E0, &B3
DB &E0, &C0, &80
DB &0D, &6A, &2C
DB &9F, &D8, &00
DB &24, &9F, &BC
DB &00, &5F, &E0
DB &FF, &FF, &FF
L6C63
DB &F5, &FA, &FB
DB &4F, &4D, &48
DB &0F, &C8, &C4
DB &00, &1C, &00
DB &DC, &00, &0E
DB &F6, &F6, &1A
DB &FB, &50, &45
DB &48, &0D, &1E
DB &BC, &00, &18
DB &00, &BC, &00
DB &0F, &16, &F6
DB &3A, &FB, &51
DB &4D, &49, &0F
DB &C9, &BC, &00
DB &BC, &00, &E0
DB &00, &0E, &D7
DB &F6, &5A, &FB
DB &52, &45, &49
DB &0D, &3E, &BC
DB &00, &BC, &00
DB &E4, &00, &0E
DB &D8, &F6, &7A
DB &FB, &53, &4D
DB &4A, &0F, &CA
DB &BC, &00, &BC
DB &00, &BC, &00
DB &7C, &00, &F6
DB &9A, &FB, &54
DB &45, &4A, &0D
DB &5E, &BC, &00
DB &BC, &00, &BC
DB &00, &68, &00
DB &BC, &00, &BC
DB &00, &4D, &4B
DB &0F, &CB, &BC
DB &00, &BC, &00
DB &BC, &00, &BC
DB &00, &F6, &DA
DB &FB, &56, &45
DB &4B, &0D, &7E
DB &FF, &FF, &FF
L6CDE
DB &04, &00, &38
DB &00, &EC, &00
DB &FC, &00, &BC
DB &00, &BC, &00
DB &BC, &00, &BC
DB &00, &08, &00
DB &3C, &00, &F0
DB &00, &00, &00
DB &FF, &FF, &FF
;
asm_help_txt
DB &16,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A
DB &1A,&1A, " C H A M P " ,&1A,&1A,&1A
DB &1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1c,0
DB &15," ZX Spectrum version (c) P.S.S. 1984 ",&15,0
DB &15," CPC6128 V3.03 by Bruce Abbott 2014 ",&15,0
DB &15," - Assembler Commands - ",&15,0
DB &15,"< RETURN >~~~~~~~~~~~~~~edit/insert line",&15,0
DB &15,"< CTRL-X/C/V >~~~~~~~cut/copy/paste line",&15,0
DB &15,"< CTRL-Z/W >~~~~~~~~undo changes on line",&15,0
DB &15,"< COPY >~~~~~~~~~toggle insert/overwrite",&15,0
DB &15,"< ESC >~~~~~~~~~~~~~~~~~~~~~~exit editor",&15,0
DB &15,"Assemble < option >~~~~assemble src code",&15,0
DB &15,"Find < string >~~~~~~~~~find text in src",&15,0
DB &15,"Next~~~~~~~~~~~~~~~~~~~~find next text",&15,0
DB &15,"Print < expr >~~~~~show expr in Hex, Dec",&15,0
DB &15,"Catalog~~~~~~~~~~~~~list files on disc",&15,0
DB &15,"Load < filename >~~~~~~~~~~load src code",&15,0
DB &15,"Import < filename >~~~~~~import src code",&15,0
DB &15,"Save < filename >~~~~~~~~~~save src code",&15,0
DB &15,"Debug~~~~~~~~~~~~~~~~~~~~~~~~~Debugger",&15,0
DB &15,"Quit < Y >~~~~~~~~~~~~~~~~~quit to BASIC",&15,0
DB &15," - Assemble options - ",&15,0
DB &15," 0 = Check syntax 1 = List to screen ",&15,0
DB &15," 2 = Write to RAM 4 = Show symbols ",&15,0
DB &15," 8 = Copy to printer ",&15,0
DB &15," options can be combined eg. 3=2+1+0 ",&15,0
DB &13,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A
DB &1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A
DB &1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A
DB &1A,&1A,&1A,&19,0
DB 0
debug_help_txt
DB &16,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A
DB &1A,&1A, " C H A M P ",&1A,&1A,&1A
DB &1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1c,0
DB &15," - Debug Commands - ",&15,0
DB &15,"A~~~~~~~~~~~~~~~~~~~~~~~~~~~~Assembler",&15,0
DB &15,"D start[end[width]]~~~~~~~~Dump memory",&15,0
DB &15,"E or @ addr~~~~~~~~~~~~~~~~Edit memory",&15,0
DB &15,"F start end fillbyte~~~~~~~Fill memory",&15,0
DB &15,"M start end dest~~~~~~~~~~~Move memory",&15,0
DB &15,'S bytes or "string"~~~~~~Search memory',&15,0
DB &15,"U start[end]~~~~~~~~~~~Unassemble code",&15,0
DB &15,"B[n=addr]~~~~~~~~~~show/set Breakpoint",&15,0
DB &15,"R[reg]~~~~~~~~~~~~~show/edit Registers",&15,0
DB &15,"T[addr]~~~~~~~~~~~~Trace (single step)",&15,0
DB &15,". addr~~~~proceed (execute subroutine)",&15,0
DB &15,"G addr~~~Go (execute until breakpoint)",&15,0
DB &15,"C~~~~~~~~~~~~~~~~~~~~~~~~~Catalog disc",&15,0
DB &15,"W name start end[type]~~~Write to file",&15,0
DB &15,"L name[addr]~~~~~~~~~~~~Load from file",&15,0
DB &15,"P 1/0~~~~~~~~~~~~~~~~~~~Printer On/Off",&15,0
DB &15,"H expr~~~~~~show expr in Hex, dec, bin",&15,0
DB &15,"N [ROM Number]~~~~~Upper ROM selection",&15,0
DB &15,"X bank[bank]~~~eXpanded RAM write,read",&15,0
DB &15,"|rsxname~~~~~~~~execute an RSX command",&15,0
DB &15,"I~~~~~~~~~~~~~~~~~~~~~~~~~~Information",&15,0
DB &15,"Q~~~~~~~~~~~~~~~~~~~~~~~~Quit to BASIC",&15,0
DB &13,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A
DB &1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A
DB &1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A,&1A
DB &1A,&1A,&1A,&19,0
DB 0
zz_end
DS &FC00-zz_end,&ff
MATRIX incbin "chrmap7.bin"
END