home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
beehive
/
os
/
super8.arc
/
MON.S8
< prev
next >
Wrap
Text File
|
1990-09-21
|
177KB
|
7,766 lines
;-------------------------------------------------------
; SUPER8 Monitor Firmware, for the S8 contest board
; This version altered for META assembler
;
;
;
; init.s8:
; (1) Entry point for monitor.
; (2) Initialization routines for monitor.
; (3) Interrupt routines for Serial Input.
; (4) Console I/O routines
;
;
; 3/1/87 Start fixing things up
;
; 1) Clean up binary to ascii routines
; 2) Disable HOST_DELAY
; 3) CLean up breakpoint stuff
; 4) TRACE
; 5) Clean up op table
;
; Things that would be nice to do:
;
; a) Shift some of the montor registers & stack to RAM
; b) Preserve ALL user registers in monitor
;
;*****************************************************
;*
;* Constants and register usage used by
;* all or some of the software modules.
;*
;******************************************************;
; register allocation
WORKREGS equ $80 ; working registers
ALT_PC equ $90 ; used by TRACE
TX_MODE equ $92 ; X_ON/X_OFF mode
USER_RP0 equ $93 ; user RP0
USER_RP1 equ $94 ; user RP1
USER_FLAGS equ $95 ; user flag reg
USER_PC equ $96 ; user PC
USERPC_HI equ $96 ; user PC high
USERPC_LO equ $97 ; user PC low
REG_MODE equ $98 ; current reg disp. mode
ERR_CODE equ $99 ; error code
ECHO_MODE equ $9A ; echo on/off mode
SIO_MODE equ $9B ; mode register
CFLAG equ $9C ; CFLAG register
OUTPTR equ $9D ; offset in output buff.
OUTLEN equ $9E ; length of output str.
INPTR equ $9F ; offset in input buff.
PUTCHRPTR equ $A0 ; output offset
GETCHRPTR equ $A1 ; output offset
RETRY equ $A2 ; load record retries
USER_EI equ $A3 ; user EI status
REGBUF equ $A4 ; temp reg buffer
; 4 registers long
OUT_CHR1 equ $A8 ; char output reg
OUT_CHR2 equ $A9 ; char output reg
D_MEMFLAG equ $AA ; data/prog. memory
STX_ETX equ $AB ; STX_ETX mode
HOSTGET equ $AC ; host input offset
HOSTPUT equ $AD ; host output offset
USER_IMR equ $AE ;
; registers used by ZAP command
DIS_CT equ $AE ; instructon count
BYTE_1 equ $AF ; 1st byte
BYTE_2 equ $B0 ; 2nd byte
BYTE_3 equ $B1 ; 3rd byte
BYTE_4 equ $B2 ; 4th byte
AD_IN_HI equ $B3 ; instruction addr
AD_IN_LO equ $B4
AD_OUT_HI equ $B5 ; output pointer
AD_OUT_LO equ $B6
AD_TBL_HI equ $B7 ; table pointer
AD_TBL_LO equ $B8
TYPE_ equ $B9 ; instruction type
USER_SP equ $BA ; two bytes
; Monitor Ram locations
;
;relocated interrupt vectors
INTV0: equ $E000 ; interrupt vector 0
INTV1: equ $E003 ; interrupt vector 1
INTV2: equ $E006 ; interrupt vector 2
INTV3: equ $E009 ; interrupt vector 3
INTV4: equ $E00C ; interrupt vector 4
INTV5: equ $E00F ; interrupt vector 5
INTV6: equ $E012 ; interrupt vector 6
INTV7: equ $E015 ; interrupt vector 7
INTV8: equ $E018 ; interrupt vector 8
INTV9: equ $E01B ; interrupt vector 9
INTV10: equ $E01E ; interrupt vector 10
INTV11: equ $E021 ; interrupt vector 11
INTV12: equ $E024 ; interrupt vector 12
INTV13: equ $E027 ; interrupt vector 13
INTV14: equ $E02A ; interrupt vector 14
INTV15: equ $E02D ; interrupt vector 15
;
;
USER_STACK equ $FB00 ; one is required for GO to work
INBUF equ $FB00 ; 256 byte Serial input buffer
HOSTBUF equ $FC00 ; 256 byte Host buffer
CONIBF equ $FD00 ; 256 byte console input buffer
CONOBF equ $FE00 ; 256 byte console output buffer
T_CODE equ $FF00 ; 7 bytes used by TRACE
BP1_SAVE equ $FFF0 ; 3 byte save for breakpointed inst.
BP1_ADDR equ $FFF3 ; Addres of breakpted intruction.
I_CODE equ $FFF5 ; I_CODE execute location (4 bytes max)
ECHO_STAT equ $FFF6 ; 1 byte saved echo status
REG_READ equ $FFF7 ; 1 byte pass location for register reads
WARMSTART equ $FFF8 ; 4 byte warm start pattern location
; RAM CONSTANTS
BUF_LGTH equ $46 ; ZAP output buff. size
; transmit mode
X_ON equ $01 ; X_ON mode
X_OFF equ $00 ; X_OFF mode
; register display mode flags
S_FLAG equ $01 ; systems registers
C_FLAG equ $02 ; control registers
GEN_FLAG equ $04 ; gen. purpose registers
ZERO_FLAG equ $08 ; bank zero flag
ONE_FLAG equ $10 ; bank one flag
; serial line mode
NORMAL_MODE equ $01 ; command mode
LOAD_MODE equ $02 ; load mode
EXT_MODE equ $80 ; load extension
; area
; echo mode
ECHO_ON equ $01 ; echo on
ECHO_OFF equ $00 ; echo off
; CFLAG
LOAD_SEND equ $20 ; BIT 5 LOAD/SEND
GETMEMFLG equ $40 ; BIT 6 GETMEMFLG
LASTCMD equ $80 ; BIT 7 LASTCMD
CLSTCMD equ $7F ; COMPLEMENT OF LASTCMD. FIX OF ASSEMBLER BUG
; error codes
BAD_CMD equ $01 ; invalid command
MIS_PARAM equ $02 ; missing parameter
BAD_HEX equ $03 ; bad hex value
BAD_OPT equ $04 ; bad option
LOADABORT equ $05 ; load aborted by host
ABSEND equ $06 ; load aborted by EM
FILE_ERR equ $07 ; file error
BAD_PARAM_VAL equ $08 ; value out of range
BAD_EXT_ADDR equ $09 ; bad extension load addr
ASCIICR equ $0D ; ASCII char. vlaues
ASCIISP equ $20
ASCIILF equ $0A
ASCIIESC equ $1B
ASCBKSP equ $08
ASCIIQ equ $51
ASCIIUP equ $5E
ASCIIDOT equ $2E
ASCIISTAR equ $2A
ASCIIEQ equ $3D
ASCIIDEL equ $7F
ASCIITAB equ $09
ASCIIDSH equ $2D
ASCIICTLS equ $13
ASCIICTLQ equ $11
ASCIISTX equ $02
ASCIIETX equ $03
;-----------------------------------
; Some constants that control things
CHR_DELAY equ $25 ; character output delay variable
; use $0E for 12.0 MHz crystal
; use $05 for 7.37 MHz crystal
CRLF_DELAY equ $08 ; initialize CRLF output delay variable
; use $03 for 12.0 MHz crystal
; use $02 for 7.37 MHz crystal
SYS_EMT equ %00101011 ; INternal stack for monitor
USR_EMT equ %00101011 ; external stack for user
SYS_STACK equ $FFEF ; sys. stack base
;----------------------------------------------------------------------
;
; Interrupt vectors
;
ORG $000
dw INTV0 ;
dw INTV1 ;
dw INTV2 ;
dw INTV3 ;
dw INTV4 ;
dw INTV5 ;
dw INTV6 ;
dw INTV7 ;
dw INTV8 ;
dw INTV9 ;
dw INPUTINT ; Serial input interrupt routine
dw INTV11 ;
dw INTV12 ;
dw INTV13 ;
dw INTV14 ;
dw INTV15 ;
INITS8:
;*********************************************************
;*
;* INITS8 Initailize the monitor S8 processor and
;* registers
;*
;**********************************************************;
; org $0020
EI ; enable writes to IMR
DI ; disable interrupts
; initialize ports and control registers
ld IPR,#$18 ; Priority: B>A>C
ld IMR,#$00 ; IRQ6 (Serial input) polled mode
ld IRQ,#$00 ; clear IRQ6
; initialize ports
ld P2AM,#%10001010 ; Outputs: P31,P20,P21, INPUTS: P30
ld P2BM,#%00000010 ; : P22 : P33,P32,P23
ld P2CM,#%00001000 ; : P25 : P35,P34,P24
ld P2DM,#%00000010 ; : P26 : P37,P36,P27
; Enable the address/data bus, 16 address lines & internal stack
ld PM,#%00110000 ; Port 1 AD0 - AD7
ld P0M,#%11111111 ; Port 0 A8 - A15
ld EMT,#SYS_EMT ; Internal stack
; internal stack during initialization, self test
ldw SP,#SYS_STACK ; Init stack to top
SRP #$C0 ; set reg. pointer to temp value
; Set baud rate to 9600 bps
sb1
ld UMA,#%01110000 ; X16 clock, 8 bit/char, no parity
ldw UBG,#7 ; set up for bit rate of
; 9600, continuous mode
; For XTAL = 12.0 MHz use 0009
; XTAL = 19.6 MHz use 0015
ld UMB,#%00011110 ; P21 data, no clock out
; auto echo disabled, use BRG for
; TxC and RxC, Enable BRG
sb0 ;
ld UTC,#%10001000 ; P31 - TxD out, no break, 1 stop bit
; No wake-up, transmitter enabled
ld URC,#%00000010 ; Enable the reciver
ld UIE,#%00000000 ; disable all interrupts
; Clear register file (registers $00 thru $BF)
ld R4,#$00 ; R4 points to $00
ld R5,#$BF ; r5 has count
CLEAR_VAR:
CLR @R4 ; clear it
INC R4 ; point to next register
DJNZ R5,CLEAR_VAR ; Loop till done
ld TX_MODE,#X_ON ; initialize transmit mode
ld SIO_MODE,#NORMAL_MODE ; set input mode
ld STX_ETX,#ECHO_ON ; set STX_ETX to echo
ld ECHO_MODE,#ECHO_ON ; initialize echo mode on for terminal
AND CFLAG,#CLSTCMD ; clear the go
; initialize the interrupt table in ram
call INT_TAB_REL
; Wait for a <CR> from Host or terminal
WAIT: TM URC,#%00000001 ; Wait for recieved char
jr z,WAIT ; 1=char received
ld r0,UIO ; Get char
and r0,#$7F ; Mask off upper bit
cp r0,#$0D ; Is it a <CR> ?
jr eq,WAIT1 ; if so, continue
cp r0,#$0A ; some systems transmit <LF>
jr ne,WAIT ; Keep waiting if not
; Clear the screen
WAIT1:
call SEND_STX
ld R8,#$20 ; clear screen
CLEAR_LOOP: ; with 32 CRs
call CRLF
DJNZ R8,CLEAR_LOOP
call SEND_ETX
; check for warm start
call IS_WARM ; set C if warm start
JR C,WARM_START ; yes
call COLD_START ; no, cold start
WARM_START:
ldw rr6,#^LB BP1_ADDR ; Clear any breakpoint set
ld r0,#$00
ldc @rr6,r0
incw rr6
ldc @rr6,r0
ldw USER_SP,#USER_STACK
READ_SIZE:
; initialize system, control registers for monitor
SRP #WORKREGS ; set reg. pointer
ld FLAGS,#$00 ; clear flags
ld IPR,#$18 ; B>A>C
ld IMR,#$40 ; enable IRQ6 - Serial input
ld IRQ,#$00 ; nothing pending
ld UIE,#%00000001 ; Enable RxChar INT
HDR_DISP:
EI ; enable interrupts
;
;
; Display sign-on header message.
;
;
; delay and let host catch up
call HOST_DELAY
; if echoing, request "e -0" from host
CP ECHO_MODE,#ECHO_OFF ; echoing?
JR EQ,MAIN ; no, skip request
call SEND_STX ; leading STX
; nothing in between
call SEND_ETX ; trailing ETX
; delay and let host catch up
call HOST_DELAY
call SEND_STX
call CRLF
call CRLF
call CRLF
call SEND_ETX
; delay before output of header to host
call HOST_DELAY
call SEND_STX
LDW RR6,#STRT_MSG ; output header
call OUTMSG
LDW RR6,#REV_MSG
call OUTMSG
call SEND_ETX
call HOST_DELAY
call SEND_STX
LDW RR6,#DATE_MSG
call OUTMSG
call SEND_ETX
call HOST_DELAY
ld R8,#$06 ; center header
call SEND_STX
CENTER_SCR:
call CRLF
DJNZ R8,CENTER_SCR
call SEND_ETX
; delay and let host catch up
call HOST_DELAY
; if echoing, request "e -0" from host
CP ECHO_MODE,#ECHO_OFF ; echoing?
JR EQ,MAIN ; no, skip request
call SEND_STX ; leading STX
; nothing in between
call SEND_ETX ; trailing ETX
; delay and let host catch up
call HOST_DELAY
;------------------------------------------------------------------------------
; Main program loop
; Loop here for commands to execute
;
MAIN:
AND CFLAG,#CLSTCMD ; clear the GO flag
call CMD_STATUS ; indicate cmd mode
CLR D_MEMFLAG ; reset D_MEMFLAG
call SEND_STX ; start msg
ld R4,#'S' ; issue "S8>"
call OUTCHR
ld R4,#'8'
call OUTCHR
ld R4,#'>'
call OUTCHR
call SEND_ETX ; end msg
GET_RESPONSE:
ld STX_ETX,#ECHO_ON ; enable echo
call GETLINE ; get the response
PROCESS_CMD:
CP R4,#ASCIICR ; a CR?
JR EQ,MAIN ; yes, ignore
CLR ERR_CODE
call MATCH_CMD ; match the command
CP ERR_CODE,#0 ; command error?
JR EQ,CHECK_ETX ; no
call OUT_ERROR ; yes, output message
CHECK_ETX:
CP STX_ETX,#ECHO_OFF ; invisible last cmd?
JR NE,MAIN ; no
JR GET_RESPONSE ; yes, no new promt
JR MAIN ; re-enter main
HOST_DELAY
;*********************************************************
; Delay for Host Package to catch up
;
; Deleted for CP/M
; ld R5,#$20
;CATCH_UP:
; ld R4,#$ff
; call DELAY
; DJNZ R5, CATCH_UP
RET
IS_WARM:
;***************************************************
;*
;* IS_WARM Read warm start pattern location.
;* If pattern is valid set carry flag.
;* Otherwise reset carry flag.
;*
;***************************************************;
LDW RR6,#WARMSTART ; point to warm start location
; look for pattern 00 FF A5 5A
LDC R4,@RR6 ; read 1st mem byte
CP R4,#0 ; 0 ?
JR NE,RESET_C ; no, cold start
INCW RR6
LDC R4,@RR6 ; read 2nd byte
CP R4,#$FF ; $FF ?
JR NE,RESET_C ; no, cold start
INCW RR6
LDC R4,@RR6 ; read 3rd byte
CP R4,#$A5 ; $A5 ?
JR NE,RESET_C ; no, cold start
INCW RR6
LDC R4,@RR6 ; read 4th byte
CP R4,#$5A ; $5A ?
JR NE,RESET_C ; no, cold start
SCF ; pattern matches
RET
RESET_C:
RCF ; no match
RET
COLD_START:
;***************************************************
;*
;* COLD_START Read warm start pattern location.
;* If pattern is valid set carry flag.
;* Otherwise reset carry flag.
;*
;***************************************************;
ld R5,#$04
VERIFY_DELAY:
ld R4,#$FF
call DELAY
DJNZ R5,VERIFY_DELAY
call VERIFY ; self test
; write out warm start pattern to memory
LDW RR6,#WARMSTART ; point to warm start location
; write pattern 00 FF A5 5A
ld R4,#0 ; 0
LDC @RR6,R4 ; write 1st mem byte
INCW RR6
ld R4,#$FF ; $FF
LDC @RR6,R4 ; write 2nd byte
INCW RR6
ld R4,#$A5 ; $A5
LDC @RR6,R4 ; write 3rd byte
INCW RR6
ld R4,#$5A ; $5A
LDC @RR6,R4 ; write 4th byte
ld ECHO_MODE,#ECHO_ON ; initialize echo mode on for terminal
LDW RR6,#ECHO_STAT ; and save in monitor RAM for warm reset read
ld R4,#ECHO_OFF
LDC @RR6,R4
RET
MATCH_CMD:
;********************************************************
;*
;* MATCH_COMMAND call the appropriate routine given the
;* first letter in the command.
;*
;* input: R4 has the first letter of the command.
;*
;********************************************************;
OR R4,#$20 ; force to low case
CP R4,#'x' ; an 'x' command?
JR NE,GO_ON ; no
ld D_MEMFLAG,#$FF ; yes, set flag for
; extern. data mem
ld R7,INPTR ; RR6 points to input
ld R6,#^HB CONIBF ; buffer
GO_BACK:
INC R7 ; look at next char.
LDC R4,@RR6 ; in CONIBUF
CP R4,#ASCIICR ; is it a CR?
jp EQ,OUT_MATCH_CMD ; yes, no command
CP R4,#ASCIISP ; no, is it a space?
JR EQ,GO_BACK ; yes, ignore spaces
OR R4,#$20 ; no, force low case
CP R4,#'x' ; multiple 'x's ?
JR EQ,GO_BACK ; yes, ignore them
ld INPTR,R7 ; no, RR6 points to
; command letter
; match the command
GO_ON:
CP R4,#'b'
jp EQ,BREAK ; set a breakpoint
CP R4,#'c'
jp EQ,COMPARE ; compare memory
CP R4,#'d'
jp EQ,MEMORY ; display/alter mem
CP R4,#'e'
jp EQ,EXTENSION ; echo off/on
CP R4,#'f'
jp EQ,FILL ; fill memory
CP R4,#'g'
jp EQ,GO ; start user execution
CP R4,#'i'
jp EQ,INTERRUPT_ENABLE ; user interrupts
CP R4,#'j'
jp EQ,PC_SET ; change user pc
CP R4,#'k'
jp EQ,KILL ; kill a breakpoint
CP R4,#'l'
jp EQ,LOAD ; load a file
CP R4,#'m'
jp EQ,MOVE ; move a memory block
CP R4,#'p'
jp EQ,PHIL_REGISTERS ; fill registers
CP R4,#'q'
jp EQ,QUIT ; quit host
CP R4,#'r'
jp EQ,REGISTERS ; register display/write
CP R4,#'s'
jp EQ,SET ; set memory
CP R4,#'t'
jp EQ,TRACE ; set memory
CP R4,#'u'
jp EQ,UPLOAD ; upload a file
CP R4,#'v'
jp EQ,VERIFY ; self test
CP R4,#'w'
jp EQ,WORKING_REGS ; working registers
CP R4,#'z'
jp EQ,ZAP ; disassembler
ld ERR_CODE,#BAD_CMD ; invalid command
OUT_MATCH_CMD:
RET
ZAP:
;************************************************************
;*
;* ZAP Prepare for and call disassembler.
;*
;************************************************************;
call GETADDR ; get address parameter
JR C,ERR3 ; an error? yes
ld AD_IN_HI,R10 ; no, load hi address
ld AD_IN_LO,R11 ; load low address
call GETADDR ; count supplied?
JR C,NO_NUM1 ; no
ld DIS_CT,R11 ; yes, load it
JR DIS_LOOP ; and go on
;**************************************************
;* NO_NUM is called by routines that need a *
;* single line disassembled after a halt, *
;* breakpoint, or single step. *
;**************************************************;
NO_NUM:
ld AD_IN_HI,USERPC_HI ; load saved breakpoint
ld AD_IN_LO,USERPC_LO ; address
NO_NUM1:
ld DIS_CT,#$01 ; disassemble one inst.
CLR ERR_CODE ; clear error flag
DIS_LOOP:
ld AD_OUT_HI,#^HB HOSTBUF ; address of output
ld AD_OUT_LO,#^LB HOSTBUF ; buffer for inst.
; mnemonics.
call DIS_ASM ; disassemble
ld R6,#^HB HOSTBUF ; print output buffer
ld R7,#^LB HOSTBUF
call OUTMSG
DEC DIS_CT ; repeat "DIS_CT" times
JR NZ,DIS_LOOP
ERR3:
RET
INPUTINT:
;************************************************
;*
;* INPUTINT Serial Input Interrupt handler.
;*
;***********************************************;
PUSH R15 ; transparent
PUSH R6 ; don't interfere
PUSH R7 ;
ld R15,UIO ; get the input
AND R15,#$7F ; mask off high bit
; convert LINE FEED into CARRIAGE RETURN
CP R15,#$0A
JR NE,CHECK_ESC
ld R15,#ASCIICR
JR CHECK_MODE
CHECK_ESC:
; ESC character means halt emulation, or reset monitor
CP R15,#ASCIIESC ; ESC char?
JR NE,CHECK_CTLS
ld R4,#$FF
call DELAY
TM CFLAG,#LASTCMD ; are we executing?
JR Z,RESET_MONITOR ; no, reset the monitor
ld TX_MODE,#X_ON ; transmit on
jp WARM_START ; Go do a warm start
; We are not executing (GO mode) so return to monitor
RESET_MONITOR:
AND CFLAG,#CLSTCMD ; clear the go
ldw SP,#SYS_STACK ; point back on stack
ld SIO_MODE,#NORMAL_MODE ; set mode
ld TX_MODE,#X_ON ; transmit on
; terminate previous output
ld R4,#ASCIICR
call OUTCHR
; delay for CRLF output
ld R4,#$20
call DELAY
call CRLF
ld R4,#$20
call DELAY
ld FLAGS,#$00 ; clear flags
ld IPR,#$18 ;
ld IMR,#$40 ; enable SIO IRQ
ld IRQ,#$00 ; nothing pending
EI ; enable interrupts
jp MAIN ; in monitor mode
; check for CTLQ/CTLS
CHECK_CTLS:
CP R15,#ASCIICTLS ; CTLS ?
JR NE,CHECK_CTLQ ; no
ld TX_MODE,#X_OFF
JR XECUTE_ON
CHECK_CTLQ:
CP R15,#ASCIICTLQ ; CTLQ ?
JR NE,CHECK_MODE ; no
ld TX_MODE,#X_ON
JR XECUTE_ON
CHECK_MODE:
CP SIO_MODE,#NORMAL_MODE ; which buffer?
JR NE,HOSTINPUT
TM CFLAG,#LASTCMD ; if 'go',can't use the
JR Z,INTO_RAM ; (jump if not in GO mode) data bus
; hence can't store
CP R15,#ASCIIESC ; ESC char is a halt
; JR NE,PASS_TO_USER ; not ESC char, pass interrupt to user
JR NE,XECUTE_ON ; if not ESC just ignore it & IRET
jp WARM_START ; Was ESC, so restart monitor
INTO_RAM:
ld R6,#^HB INBUF ; keyboard input
ld R7,GETCHRPTR ;
INC GETCHRPTR ; move pointer
JR DATA_IN ;
HOSTINPUT:
ld R6,#^HB HOSTBUF ; put into buffer for host
ld R7,HOSTGET ;
INC HOSTGET ; update pointer
DATA_IN:
LDC @RR6,R15 ; put in I/O buffer
XECUTE_ON:
POP R7 ; restore
POP R6 ;
POP R15 ;
IRET ;
PASS_TO_USER:
POP R7 ; restore registers before...
POP R6
POP R15
jp INTV10 ; pass ram interrupt vector
OUT_ERROR:
;*************************************************************
;*
;* OUT_ERROR Output error code and error message
;*
;* input: ERR_CODE has the error code.
;*
;*************************************************************;
PUSH R5 ; save registers
PUSH R8
PUSH R9
CP ERR_CODE,#8 ; bad error code?
JR LE,FIND_MSG ; no
ld ERR_CODE,#0 ; yes
FIND_MSG:
ld R5,ERR_CODE ; save error code
ld R8,#^HB ERR_MSG_LIST
ld R9,#^LB ERR_MSG_LIST
LOOP_MSG:
CP R5,#0 ; at the right address?
JR EQ,AT_BEGIN ; yes
INCW RR8 ; no, point to next
INCW RR8
DEC R5
JR LOOP_MSG
AT_BEGIN:
; RR8 now points to the address of the error message
LDC R6,@RR8 ; load low byte of address
INCW RR8
LDC R7,@RR8 ; load hi byte of address
call OUTMSG ; write the error message
POP R9 ; restore registers
POP R8
POP R5 ; save registers
RET
BTOHEXADDR
;***********************************************
;*
;* BTOHEXADDR Convert an address to hex
;*
;* input: Registers R10-R11 hold address
;* to be converted.
;*
;* output: R6 points to next location in REGBUF
;* after last digit of address.
;* Converted address is returned in REGBUF.
;*
;***********************************************;
ld R4,R10 ; convert hi byte
call BTOHEXDAT ;
ld R4,R11 ; convert lo byte
; fall through
BTOHEXDAT
;***********************************************
;*
;* BTOHEXDAT Convert a byte to hex
;*
;* input: R4 contains byte to be converted.
;* R6 points to location convert
;* byte will go.
;*
;* output: R6 is incremented twice
;*
;***********************************************;
PUSH R4 ; save
SWAP R4 ; do up nibble
call NIBBLE ;
POP R4 ; fall through
call NIBBLE
RET
NIBBLE
;***********************************************
;*
;* NIBBLE Convert a nibble to hex
;*
;* input: R4 has nibble to be converted
;* in the lower nibble.
;* R6 points to where convert goes.
;*
;* output: R6 is incremented once.
;*
;***********************************************;
and R4,#$0F ; isolate nibble
add r4,#$90
da r4
adc r4,#$40
da r4
ld @R6,R4 ; put into buffer
inc R6 ; point to next register
ret ;
OUTSTR
;*******************************************************
;*
;* OUTSTR Write a string out to the screen
;*
;* input: RR6 points to string to be output to
;* to the screen. The string is terminated
;* with a <CR>.
;*
;* output: Each character is output to the screen.
;*
;*******************************************************;
NEXT_CHR:
LDC R4,@RR6 ; get contents
CP R4,#ASCIICR ; stop if <CR> data
JR EQ,DONE_STR ;
call OUTCHR ; write the char @RR6
INCW RR6 ; increment pointer
JR NEXT_CHR ; but continue til then
DONE_STR:
RET
OUTMSG
;*******************************************************
;*
;* OUTMSG Write a string out to the screen
;* followed by <LF> <CR>.
;*
;* input: RR6 points to string to be output to
;* to the screen. The string is terminated
;* with a <CR>.
;*
;* output: Each character is output to the screen.
;* Send a <CR> <LF> at the end of the string.
;*
;*******************************************************;
call OUTSTR ; write string RR6
call CRLF ; move cursor to next line
RET
OTMSG
;********************************************************
;*
;* OTMSG Write a string in CONOBF out to the screen.
;*
;* input: R6 is hi byte of buffer, string at beginning
;* of the buffer.
;* OUTLEN is length of string.
;*
;* output: Each character in the string is output to
;* the screen.
;*
;* R4,R5,R6,R7 destroyed
;*
;********************************************************;
CLR R7 ; string at begin of CONOBF
ld R5,OUTLEN ;
OUTR5:
LDC R4,@RR6 ; get into R4 for output
call OUTCHR ;
INC R7 ; move pointer
DJNZ R5,OUTR5 ; until length
RET ;
CRLF
;*******************************************************
;*
;* CRLF Output a <LF> <CR>
;*
;* input: none
;*
;* output: output a <LF><CR> to the screen
;*
;*******************************************************;
ld R4,#ASCIILF
call OUTCHR
ld R4,#ASCIICR
call OUTCHR
RET
BACKSPACE
;*******************************************************
;*
;* BACKSPACE Process a backspace character
;*
;* input: none
;*
;* output: Write a <BKSP> <SP> <BKSP> to terminal
;*
;********************************************************;
call OUTCHR ; output the backspace
ld R4,#ASCIISP ; space
call OUTCHR ;
ld R4,#ASCBKSP ; backspace
call OUTCHR ;
RET ;
GETLINE
;*******************************************************
;*
;* GETLINE Fill CONIBF with string in INBUF
;*
;* input: none
;*
;* output Place string terminated by <CR> in INBUF
;* into CONIBF.
;* R4 holds the first letter in the string.
;* INPTR is offset to first char in CONIBF.
;*
;*******************************************************;
CLR R7 ; using R7 as ptr
ld R6,#^HB CONIBF ;
INLOOP: call GETCHR ; get from INBUF to CONIBF
CP R4,#ASCIICR ; <CR> stops input
JR NE,INLOOP ; end of input
CLR R7 ; get pointer
ld R6,#^HB CONIBF ;
FIRSTCHR:
LDC R4,@RR6 ; get first character
CP R4,#ASCIISP ; ignore spaces
JR NE,GOTFIRST ;
INC R7 ; increment pointer
JR FIRSTCHR ; wait for nonspace
GOTFIRST:
ld INPTR,R7 ;
RET ; back with command string
OUTADDR
;*******************************************************
;*
;* OUTADDR Convert an address to hex and display it.
;*
;* input: R10-R11 hold address to be converted
;* and displayed.
;*
;* output: Hex address is displayed on the screen.
;*
;*******************************************************;
ld R6,#REGBUF ; converted output into REGBUF
call BTOHEXADDR ; convert
ld R5,#$04 ; display four bytes
DISPLAY:
ld R6,#REGBUF ; start at beginning
DISP_NUM:
ld R4,@R6 ; get character for output
call OUTCHR ;
INC R6 ; point to next character
DJNZ R5,DISP_NUM ; display
ld R4,#ASCIISP ; follow with a space
call OUTCHR ;
RET ;
OUTDAT
;******************************************************
;*
;* OUTDAT Convert a byte to hex and display it.
;*
;* input: R4 has data to convert.
;*
;* output: Write a hex byte value to the screen
;* followed by a space.
;*
;******************************************************;
call OUTHEX ; Print hex byte
ld R4,#ASCIISP ; follow with a space
call OUTCHR ;
RET ;
OUTHEX
;******************************************************
;*
;* OUTHEX Convert a byte to hex and display it.
;*
;* input: R4 has data to convert.
;*
;* output: Write a hex byte value to the screen
;*
;******************************************************;
ld R6,#REGBUF ; register buffer
call BTOHEXDAT ; convert
ld R5,#$02 ; two characters
ld R6,#REGBUF ; start at beginning
DISP_NIB:
ld R4,@R6 ; get character for output
call OUTCHR ;
INC R6 ; point to next character
DJNZ R5,DISP_NIB ; display
RET ;
OUTCHR
;*****************************************************
;*
;* OUTCHR Output a character to the screen
;*
;* input: R4 contains the character to be
;* written.
;*
;* output: The character in R4 is written to the
;* screen.
;*
;*****************************************************;
; delay on output if not echoing
CP ECHO_MODE,#ECHO_ON
JR NE,OUTPUT_DEL
JR CHECK_TX
OUTPUT_DEL:
; delay
PUSH R4 ; save R4
ld R4,#CHR_DELAY
call DELAY
POP R4 ; restore R4
; check for X_OFF
CHECK_TX:
CP TX_MODE,#X_OFF
JR EQ,CHECK_TX
ld UIO,R4 ;
TEST_OUT:
TM UTC,#$02 ; wait for output finished
JR Z,TEST_OUT ;
RET ;
GETCHR
;***************************************************
;*
;* GETCHR Get a character from INBUF and place
;* in CONIBF.
;*
;* input: none
;*
;* output: Process backspace and line delete.
;* Other characters are put into CONIBF
;* for parsing.
;*
;***************************************************;
call GETDAT ;
CP R4,#ASCIIDEL ; is it a line delete?
JR NE,NOT_DEL ;
CP R7,#$00 ; not at beginning
JR EQ,END_GETCHR ;
ld R4,#ASCBKSP ; R7 backspaces
LINE_BACK:
call BACKSPACE ; back to begining
DJNZ R7,LINE_BACK ;
JR END_GETCHR ; new input
NOT_DEL:
CP R4,#ASCIISP ; is it printable?
JR C,NOT_PRINTING ;
ECHO:
CP R7,#$FF ; end of buffer
JR NE,BUFOK ;
ld R4,#ASCIICR ; insert carriage return
BUFOK:
CP ECHO_MODE,#ECHO_ON ; are we echoing ?
JR NE,FILL_BUF ; no, no echo
CP STX_ETX,#ECHO_ON ; echo enabled?
JR NE,FILL_BUF ; no, no echo
call OUTCHR ; yes, echo
FILL_BUF:
LDC @RR6,R4 ; put into CONIBF
INC R7 ; move pointer
JR END_GETCHR ; return
NOT_PRINTING:
CP R4,#ASCIISTX ; STX?
JR NE,CHECK_TAB ; no
ld STX_ETX,#ECHO_OFF ; yes
JR END_GETCHR
CHECK_TAB:
CP R4,#ASCIITAB ; change tab to space
JR NE,NOT_TAB ;
ld R4,#ASCIISP ;
JR ECHO ;
NOT_TAB:
CP R4,#ASCBKSP ; process backspace
JR NE,NOT_BKSP ; not a backspace
CP R7,#$00 ; forget backspace at begin
JR EQ,END_GETCHR ;
call BACKSPACE ; do the backspace
DEC R7 ; backup pointer
JR END_GETCHR ;
NOT_BKSP:
CP R4,#ASCIICR ; preface CR with LF
JR NE,END_GETCHR ;
CP ECHO_MODE,#ECHO_OFF ; are we echoing?
JR EQ,FILL_BUF ; no
CP STX_ETX,#ECHO_OFF ; echo enabled?
JR EQ,FILL_BUF ; no
call CRLF ;
JR ECHO ; echo and put in CONIBF
END_GETCHR:
RET ;
GETDAT
;****************************************************
;*
;* GETDAT Get a byte from INBUF
;*
;* input: none
;*
;* output: First byte in INBUF is placed in R4
;*
;****************************************************;
PUSH R6 ; save
PUSH R7 ; save
ld R6,#^HB INBUF ; get pointer
ld R7,PUTCHRPTR ;
GETDAT1:
CP GETCHRPTR,PUTCHRPTR ; wait for character
JR EQ,GETDAT1 ;
LDC R4,@RR6 ; get it from output
INC PUTCHRPTR ; increment ptr
POP R7 ;
POP R6 ; restore
RET ; end of input
FINDNEXT
;*******************************************************
;*
;* FINDNEXT
;*
;* input: INPTR is offset for current character in
;* CONIBF.
;*
;* output: INPTR is offset again to the first character
;* of next token in CONIBF. on input line
;* R4 contains that first character.
;* Returns a zero if char is <CR>
;*
;*******************************************************;
ld R6,#^HB CONIBF ; get pointer
ld R7,INPTR ; into input buffer
FINDNEXT1:
LDC R4,@RR6 ; wait for a space
INC R7 ; point ahead
CP R4,#ASCIICR ; if a CR no param
JR EQ,NO_PARAM ; no parameter
CP R4,#ASCIISP ;
JR NE,FINDNEXT1 ;
SKPSPCE:
LDC R4,@RR6 ; wait for nonspace
INC R7 ;
CP R4,#ASCIISP ;
JR EQ,SKPSPCE ;
DEC R7 ; point to first character
CP R4,#ASCIICR ; end of line if <CR>
NO_PARAM:
ld INPTR,R7 ; update pointer
RET ;
FINDOPT
;*******************************************************
;*
;* FINDOPT
;*
;* input: INPTR is offset for current character in
;* CONIBF.
;*
;* output: Locate next token in input line. Clear R10
;* if token does not begin with "-". Place
;* first character of token in R10. Place
;* second character of token in R11. If token
;* begins with "-", remove it from input buffer
;* by replacing with spaces.
;*
;*******************************************************;
CLR R10 ; clear output reg.
CLR R11
ld R6,#^HB CONIBF ; get pointer
ld R7,INPTR ; into input buffer
FINDOPT1:
LDC R4,@RR6 ; wait for a space
INC R7 ; point ahead
CP R4,#ASCIICR ; if a CR no param
JR EQ,END_FIND ; no parameter
CP R4,#ASCIISP ;
JR NE,FINDOPT1 ;
SKIPSP:
LDC R4,@RR6 ; wait for nonspace
INC R7 ;
CP R4,#ASCIISP ;
JR EQ,SKIPSP ;
CP R4,#ASCIIDSH ; is 1st char a "-" ?
JR NE,END_FIND
LDC R10,@RR6 ; load 1st char of token
INC R7
LDC R11,@RR6 ; load 2nd char of token
DEC R7 ; point back to "-"
DEC R7
CLR_TOKEN:
ld R4,#ASCIISP
LDC @RR6,R4 ; clear token
INC R7
LDC R4,@RR6 ; check for token end
CP R4,#ASCIICR
JR EQ,END_FIND
CP R4,#ASCIISP ; continue until we hit
JR NE,CLR_TOKEN ; a space.
END_FIND:
RET ;
GETADDR
;*******************************************************
;*
;* GETADDR Get an address value from input line
;*
;* input: INPTR is offset from CONIBF to last parameter
;*
;* output: address is stored in R10 R11
;*
;* R6,R7,R12,R4 destroyed
;*
;*******************************************************;
CLR R10 ; clear the temp
CLR R11 ;
call FINDNEXT ; R4 has first char
JR Z,PARA_CR ; it is a <CR>
CON_BYTE:
call CONVERT ; convert to 4 bit bin
JR C,INV_HEX ; invalid hex
SWAP R4 ; get into upper nibble
ld R12,#$04 ; must SHIFT all
; four bits
SHIFTIT:
RLC R4 ; SHIFT msb into carry
RLC R11 ; from carry to lsb low byte
RLC R10 ; msb low byte -> lsb hi byte
DJNZ R12,SHIFTIT ;
INC R7 ; point to next digit
LDC R4,@RR6 ; get into working register
CP R4,#ASCIISP ; space is end
JR EQ,LAST_NUM ;
CP R4,#ASCIICR ; so is <CR>
JR EQ,LAST_NUM ;
JR CON_BYTE ; convert next digit
PARA_CR:
ld ERR_CODE,#MIS_PARAM ; type 2 error --
; missing param
SCF ; set flag
RET
INV_HEX:
ld ERR_CODE,#BAD_HEX ; type 3 error --
; bad hex value
SCF ; set flag
RET
LAST_NUM:
DEC R7 ;
ld INPTR,R7 ; update pointer
RCF ; reset flag
RET
CONVERT
;*******************************************************
;*
;* CONVERT convert ASCII char to hex
;*
;* input: ASCII char is in R4, INPTR points one
;* byte ahead of location where the char
;* was taken from.
;*
;* output: The value is returned in R4.
;*
;******************************************************;
CP R4,#'0' ; less than ascii 0 is bad
JR LT,BAD_HEX_VAL ;
CP R4,#'9' ; if a numeric, mask hi nib
JR LE,UPMASK ;
CP R4,#'A' ; if > '9', be at least 'a'
JR LT,BAD_HEX_VAL ;
CP R4,#'F' ; can't be gt
JR LE,UP_CASE ; unless it is lower case
CP R4,#'a' ; lower case must be at least
JR LT,BAD_HEX_VAL ; an 'a'
CP R4,#'f' ; but no greater than an 'f'
JR GT,BAD_HEX_VAL ;
UP_CASE:
SUB R4,#$07 ; change alpha character
UPMASK:
AND R4,#$0F ; mask off upper nibble
RCF ; reset carry for good exit
RET ;
BAD_HEX_VAL:
SCF
RET
SEND_STX
;********************************************************
;*
;* SEND_STX Send the character $02 (STX) to the
;* host. It will be ignored if an ASCII
;* terminal is connected.
;*
;*********************************************************;
ld R4,#ASCIISTX ; send the STX character
call OUTCHR
; delay on output if not echoing
CP ECHO_MODE,#ECHO_ON ; echoing?
JR EQ,DONE_STX ; yes
ld R4,#CRLF_DELAY ; no, so delay
call DELAY
DONE_STX:
RET
SEND_ETX
;********************************************************
;*
;* SEND_ETX Send the character $03 (ETX) to the
;* host. It will be ignored if an ASCII
;* terminal is connected.
;*
;*********************************************************;
ld R4,#ASCIIETX ; send the ETX character
call OUTCHR
; now delay for a moment
ld R4,#CRLF_DELAY
call DELAY
RET
CMD_STATUS
;********************************************************
;*
;* CMD_STATUS Send the command status (<STX> I <ETX>)
;* to the host if we are not echoing characters.
;*
;*********************************************************;
CP ECHO_MODE,#ECHO_ON ; echoing ?
JR EQ,DONE_CMD_STAT ; yes, just ret
call SEND_STX ; STX
ld R4,#'I' ; I
call OUTCHR
call SEND_ETX ; ETX
DONE_CMD_STAT:
RET
EDIT_STATUS
;********************************************************
;*
;* EDIT_STATUS Send the edit status (<STX> T <ETX>)
;* to the host if we are not echoing characters.
;*
;*********************************************************;
CP ECHO_MODE,#ECHO_ON ; echoing ?
JR EQ,DONE_EDIT_STAT ; yes, just ret
call SEND_STX ; STX
ld R4,#'T' ; T
call OUTCHR
call SEND_ETX ; ETX
DONE_EDIT_STAT:
RET
GO
;*********************************************************
;*
;* GO
;*
;* syntax G [<ADDRESS>]
;*
;* defaults <ADDRESS> = current PC
;*
;*********************************************************;
call PC_SET ; optional jump
OR CFLAG,#LASTCMD ; mark user is executing
DI ; change imr
ld IMR,#$40 ; Enable SIO int only
EI ;
; CP USER_EI,#$FF ; go with interrupts
; JR NE,GO_AHEAD ;
; call FORCE_EI ;
GO_AHEAD:
ld RP0,USER_RP0 ;
ld RP1,USER_RP1 ;
sb0
ld EMT,#USR_EMT ; set up external stack for user
ld FLAGS,USER_FLAGS ;
ld IMR,USER_IMR ;
ldw sp,USER_SP
push USERPC_LO ; low byte
push USERPC_HI ; Get high address byte
ret ; GO !!!
; We will return through the
; SOFTWARE_BREAK routine or
; by a RESET only
PC_SET
;******************************************************
;*
;* PC_SET (but don't go)
;*
;* syntax J [<ADDRESS>]
;*
;* defaults <ADDRESS> = current PC value
;*
;******************************************************;
call GETADDR ; get go address
JR NC,NEW_PC ; jump if new address parameter
ld R10,USERPC_HI ; get user PC
ld R11,USERPC_LO ; into RR10
NEW_PC:
CLR ERR_CODE ; no error
ld USERPC_HI,R10 ; change internal copy
ld USERPC_LO,R11 ;
RET ; done
TRACE
;******************************************************
;*
;* Sets breakpoint at the next op code,
;* then executes GO. This is smart
;* about program branches.
;*
;******************************************************
ldw rr10,USER_PC
ldci r12,@rr10 ; fetch opcode
ldc T_CODE,r12 ; save opcode for branch handler
cp r12,#$0F ; next?
jr nz,trc_1
ldw rr12,IP
jr trc_x ; share some code
trc_1: cp r12,#$F6 ; call #addr ?
jr z,trc_1a
cp r12,#$1F ; enter?
jr nz,trc_2 ; if not
trc_1a: ldw rr12,rr10
trc_x ldci r10,@rr12 ; fetch next pc from the word list
ldc r11,@rr12
jp trc_0 ; go set BP
trc_2: cp r12,#$2F ; Exit?
jr nz,trc_3
ldw rr10,sp
ldci r12,@rr10
ldc r13,@rr10
jr trc_x
trc_3: cp r12,#$AF ; return?
jr nz,trc_4
pop r10 ; get pc off stack
pop r11
push r11 ; restore stack
push r10
jp trc_0 ; go set BP
trc_4: cp r12,#$F4 ; CALL @R ?
jr z,trc_4a ; if so
cp r12,#$30 ; JP @R ?
jr nz,trc_5
trc_4a: ld r14,#$C4 ; ldw opcode
ldc T_CODE,r14
ldci r14,@rr10 ; get des. field from opcode (@R)
ldc T_CODE+1,r14 ; = source for LDW
ld r14,#ALT_PC
ldc T_CODE+2,r14 ; ldw ALT_PC,R; R is destination
ld r14,#$AF
ldc T_CODE+3,r14 ; ret
ld FLAGS,USER_FLAGS ; we need user flags for condx. jump
ld RP0,USER_RP0 ; user registers are needed for djnz, etc.
ld RP1,USER_RP1
call T_CODE ; get the destination to ALT_PC
srp #WORKREGS ; Point to monitor reg. set
ldw rr10,ALT_PC
jp trc_0
;-----
trc_5:
inc r12
ldw rr4,#OP_TAB-1 ; get starting
nxt_2: incw rr4 ; find next
ldc r13,@rr4 ; control byte
TM r13,#$80 ; bit 7 set?
jr z,nxt_2 ; loop 2 till
nxt_3: djnz r12,nxt_2 ; if not there, get next
swap r13
rr r13
and r13,#3
add r11,r13
adc r10,#0 ; Next addr now in rr10
;------------------------------------------------
; Now look at the opcode, & take care of branches
ldw ALT_PC,rr10 ; save next intruction address
ldw rr8,USER_PC
ldci r14,@rr8 ; fetch opcode
ldc T_CODE,r14 ; save opcode just in case
cp r14,#$d2 ; cpijne?
jr z,tbr4a
cp r14,#$C2 ; cpije?
jr z,tbr4a
tbr4: cp r14,#$37 ; btjrf/t?
jr nz,trb3
tbr4a: ldci r14,@rr8
ldc T_CODE+1,r14
ld r14,#3
ldc T_CODE+2,r14
ldc r13,@rr8 ; get displacement to r13
ld r12,r13
add r12,r12 ; sign bit to carry
clr r12
sbc r12,#0 ; extend sign bit into r12
add r13,r11
adc r12,r10 ; destination to rr12
jr tbr1b
trb3: and r14,#$F
cp r14,#$0A ; DJNZ?
jr z,trb2 ; if so, use same code as JR
cp r14,#$0B ; jump relative?
jr nz,tbr1 ; if not
trb2: ldc r13,@rr8 ; get displacement to r13
ld r12,r13
add r12,r12 ; sign bit to carry
clr r12
sbc r12,#0 ; extend sign bit into r12
add r13,r11
adc r12,r10 ; destination to rr12
jr tbr1a ; go do it
tbr1 cp r14,#$0D ; jump?
jr nz,trc_0 ; if not, get out of here
ldci r12,@rr8 ;
ldc r13,@rr8
ldc r14,T_CODE
sub r14,#2 ; turn JP into JR
ldc T_CODE,r14
tbr1a: ld r14,#4 ; displacement for jr cc
ldc T_CODE+1,r14
ld r14,#$ff
ldc T_CODE+2,r14 ; throw in a nop
tbr1b: ldw USER_PC,rr12 ; assume a jump
ld r14,#$C4 ; ldw opcode
ldc T_CODE+3,r14
ld r14,#ALT_PC ; if branch not taken,
ldc T_CODE+4,r14 ; ALT_PC --> USER_PC
ld r14,#USER_PC
ldc T_CODE+5,r14 ; ldw rr12,rr10 if branch not taken
ld r14,#$AF
ldc T_CODE+6,r14 ; ret
ld FLAGS,USER_FLAGS ; we need user flags for condx. jump
ld RP0,USER_RP0 ; user registers are needed for djnz, etc.
ld RP1,USER_RP1
call T_CODE
srp #WORKREGS ; Point to monitor reg. set
ld R4,#'J' ; output a 'J' for jump
jp BRK_2 ; fake a break
.xlist
;-----
trc_0: call SET_BREAK_ADDR
jp GO
BREAK
;*******************************************************
;*
;* BREAK
;*
;* syntax B display breakpoints
;* syntax B <ADDRESS> set one breakpoint
;*
;*******************************************************;
call GETADDR ; check for parameters
JR C,DISP_BRK ; jump if no parameters
CP R10,#$80 ; Break range must be > ROM space
JR ULT, BAD_RANGE
jr SET_BREAK_ADDR ;
; Display the breakpoints set
DISP_BRK:
ldw rr10,#BP1_ADDR ; Point to Break point save location
ldc r12,@rr10 ; Get high byte of breakpoint address
cp r12,#$80 ; Check if in ROM space
jr uge,CHK_BRK ; Jump if not
clr ERR_CODE ; No breakpoint set
ret
CHK_BRK:
ld r6,#^HB BRK_MES ; Print
ld r7,#^LB BRK_MES ; breakpoint
call OUTSTR ; header
ldc r4,@rr10 ; Get High address byte
call OUTHEX ; Print high byte
incw rr10 ; Point to Low address byte
ldc r4,@rr10 ; Get Low address byte
call OUTHEX ; Print low byte
call CRLF
CLR ERR_CODE ; clear errors
RET
BAD_RANGE:
ld ERR_CODE,#BAD_PARAM_VAL
ret
; Set a breakpoint
; "BREAK_ADDR" can be called to set a breakpoint
; if RR10 has the breakpoint address
SET_BREAK_ADDR:
CLR ERR_CODE ; clear errors
; Make sure the address is not in ROM space
CP R10,#$80 ; Is it in lower 16K? (ROM Space)
JR UGE,INT_ADDR ; no
ld ERR_CODE,#BAD_PARAM_VAL ; Opps! It is
RET ; Send back error code
; Get the three bytes we need to replace with the call instruction
INT_ADDR:
push r0 ; save
push r2 ; some
push r3 ; registers
ldw rr2,#BP1_ADDR ; pt to save address of breakaddress
ldc @rr2,r10 ; Save High byte of break address
incw rr2 ; Point to next location
ldc @rr2,r11 ; Save Low byte of break address
ldw rr2,#BP1_SAVE ; Point to save address of breakaddress
ldc r0,@rr10 ; Get first byte
ldc @rr2,r0 ; Save 1st byte
ld r0,#$F6
ldc @rr10,r0 ; Insert call opcode
incw rr10 ; Point to next byte
incw rr2 ; & next save location
ldc r0,@rr10 ; Get 2nd byte
ldc @rr2,r0 ; Save it
ld r0,#^HB SOFTWARE_BREAK
ldc @rr10,r0
incw rr10 ;
incw rr2 ;
ldc r0,@rr10 ; Get 3rd byte
ldc @rr2,r0 ; save it
ld r0,#^LB SOFTWARE_BREAK ;
ldc @rr10,r0
pop r3
pop r2
pop r0
ret
KILL
;*******************************************************
;*
;* KILL
;*
;* syntax K
;*
;*******************************************************;
ld ERR_CODE, #0
ldw rr10,#BP1_ADDR ; Point to saved address
ldci r0,@rr10 ; Load break address
ldc r1,@rr10 ; into rr0
clr r3
ldw rr10,#BP1_ADDR ; Point to saved address
ldc @rr10,r3 ; Clear break address
incw rr10
ldc @rr10,r3
ldw rr10,#BP1_SAVE ; Load pointer to save area
ldci r2,@rr10 ; Get 1st byte
ldc @rr0,r2 ; Restore 1st byte
incw rr0
ldci r2,@rr10 ; get 2nd byte
ldc @rr0,r2 ; Restore 2nd byte
incw rr0
ldci r2,@rr10 ; Get 3rd byte
ldc @rr0,r2 ; Restore 3rd byte
ret
SOFTWARE_BREAK
;**********************************************************
;*
;* Software breakpoint reached
;*
;* This routine is the call location for a software
;* breakpoint.
:*
;**********************************************************
DI
ld USER_FLAGS,FLAGS ; Save USER FLAGS
ld USER_IMR,IMR ;
ld USER_RP0,RP0 ; RP0
ld USER_RP1,RP1 ; RP1
srp #WORKREGS ; Point to correct reg set
pop r0 ; Get USER PC
pop r1 ; off of stack
ldw USER_SP,SP
decw rr0 ; Break
decw rr0 ; address is
decw rr0 ; 3 less
ld USERPC_HI,r0 ; Save high address
ld USERPC_LO,r1 ; & low address
; Restore removed instruction
ldw rr10,#BP1_ADDR ; Point to saved address
ldci r0,@rr10 ; Load break address
ldc r1,@rr10 ; into rr0
clr r3
ldw rr10,#BP1_ADDR ; Point to saved address
ldc @rr10,r3 ; Clear break address
incw rr10
ldc @rr10,r3
ldw rr10,#BP1_SAVE ; Load pointer to save area
ldci r2,@rr10 ; Get 1st byte
ldc @rr0,r2 ; Restore 1st byte
incw rr0
ldci r2,@rr10 ; get 2nd byte
ldc @rr0,r2 ; Restore 2nd byte
incw rr0
ldci r2,@rr10 ; Get 3rd byte
ldc @rr0,r2 ; Restore 3rd byte
; We hit a breakpoint
BREAK_1:
ld IMR,#$40 ; Reset the IMR (Enable SIO IRQ)
EI ; enable other interrupts
ld R4,#'B' ; output a 'B' for break
BRK_2: call OUTCHR ;
ld R4,#ASCIISP ; followed by a space
call OUTCHR ;
call NO_NUM ; Disassemble instruction
HALTED:
AND CFLAG,#CLSTCMD ; clear the go
sb0
ld EMT,#SYS_EMT
ldw SP,#SYS_STACK ; point back on stack
jp MAIN ; in monitor mode
INT_TAB_REL:
;************************************************************
;*
;* INTERRUPT TABLE RELOCATION ROUTINE
;* MOVES DUMMY INTERRUPT TABLE TO RAM LOCATION
;* E000H FOR USER ACCESS. ALL VECTORS POINT TO AN
;* INTERRUPT RETURN.
;*
;************************************************************
ldw rr4,#$E000 ;beginning location of interrupt vector table
;in ram
ldw rr6,#IVECT0 ;beginning location of table data in ROM
ld r8,#IVECLEN ;get length of table
IVLOOP: ldci r0,@rr6 ;get the byte
ldc @rr4,r0 ;put the byte
incw rr4 ;bump pointer
djnz r8,IVLOOP ;loop till done
ret
;************************************************************
;*
;* TABLES and MESSAGE STRINGS
;*
;************************************************************;
ERR_MSG_LIST dw ERR_0_MSG, ERR_1_MSG, ERR_2_MSG, ERR_3_MSG, ERR_4_MSG
dw ERR_5_MSG, ERR_6_MSG, ERR_7_MSG, ERR_8_MSG
ERR_0_MSG .ascii '? INVALID ERROR CODE\r'
ERR_1_MSG .ascii '? 01 INVALID COMMAND\r'
ERR_2_MSG .ascii '? 02 MISSING PARAMETER\r'
ERR_3_MSG .ascii '? 03 BAD HEX NUMBER\r'
ERR_4_MSG .ascii '? 04 BAD COMMAND OPTION\r'
ERR_5_MSG .ascii '? 05 LOAD ABORTED BY HOST\r'
ERR_6_MSG .ascii '? 06 LOAD ABORTED BY SUPER8 MONITOR\r'
ERR_7_MSG .ascii '? 07 FILE ERROR MESSAGE\r'
ERR_8_MSG .ascii '? 08 PARAMETER VALUE OUT OF RANGE\r'
STRT_MSG .ascii ' SUPER8 Monitor\r'
REV_MSG .ascii ' Version 1.02.07\r'
DATE_MSG .ascii ' March 9, 1987\r'
BRK_MES .ascii 'Breakpoint set at: \r'
WARM_PATTERN db $00,$FF,$A5,$5A
;
; interrupt handlers
; null return will terminate improperly initialized interrupt
;
NULIRET: IRET
;
; null vector table to be relocated into ram beginning at location E000H
;
IVECT0: jp NULIRET
IVECT1: jp NULIRET
IVECT2: jp NULIRET
IVECT3: jp NULIRET
IVECT4: jp NULIRET
IVECT5: jp NULIRET
IVECT6: jp NULIRET
IVECT7: jp NULIRET
IVECT8: jp NULIRET
IVECT9: jp NULIRET
IVECT10: jp NULIRET
IVECT11: jp NULIRET
IVECT12: jp NULIRET
IVECT13: jp NULIRET
IVECT14: jp NULIRET
IVECT15: jp NULIRET
IVECLEN equ $-IVECT0 ;LENGTH OF TABLE TO BE RELOCATED
;************************************************
;*
;* mem.s : all the memory command
;* routines except low-level routines.
;*
;* ** This version doctored for META assembler
;*
;*****************************************************
;*
;* Constants and register usage used by
;* all or some of the software modules.
;*
;******************************************************;
; register allocation
FILL
;*****************************************************
;*
;* FILL
;*
;* syntax F <START ADDR> <LENGTH> {<DATA>}
;*
;* defaults none
;*
;* action the pattern input as {<DATA>}
;* is written into memory beginning
;* at <START ADDR> and is copied
;* in as many times as necessary to
;* fill <LENGTH> bytes of memory
;*
;*****************************************************;
PUSH R15
CALL GETADDR ; get the address
JR C,BADHX5 ; no good
LD R0,R10 ; use RR0
LD R1,R11 ;
CALL GETADDR ; get length
JR C,BADHX5 ; no good
LD R2,R10 ; put length into RR2
LD R3,R11 ;
CLR OUTPTR ; use the input buffer
CLR R13 ; count # of data bytes
ACCUM:
CALL GETADDR ; get data
JR C,DO_FILL ; stop input and fill
LD R7,OUTPTR ; get pointer
LDC @RR6,R11 ; one byte of data
INC R13 ; keep count
INC OUTPTR ; increment pointer
JR ACCUM ;
DO_FILL:
CP R13,#$00 ; if no data,don't fill
JR EQ,BADHX5 ; didn't get any data
RE_PEAT:
LD R9,R13 ; get length of pattern
CLR R7 ; pointer not shared
R9LOOP:
LDC R15,@RR6 ; get data from pattern
PUSH R8
PUSH R9
LD R8,R0
LD R9,R1
CALL PUTMEM ; LDE @RR8,R15
POP R9
POP R8
INCW RR0 ; increment memory ptr
INC R7 ; increment buffer ptr
DECW RR2 ; decrement length of memory
JR Z,FILL_END ;
DJNZ R9,R9LOOP ; DJNZ R9,R9loop
JR RE_PEAT ; repeat the pattern
FILL_END:
CLR ERR_CODE ; normal ending,clear error
BADHX5:
POP R15
RET ; stop this
MOVE
;******************************************************
;*
;* MOVE
;*
;* syntax M <DEST ADDR> <SOURCE ADDR> [<LENGTH>]
;*
;* defaults <LENGTH> = 1
;*
;******************************************************;
PUSH R8
PUSH R9
PUSH R15
CALL GETADDR ; get first address
JR C,BADHX6 ; no good
LD R2,R10 ; first address
LD R3,R11 ; into RR2
CALL GETADDR ; second address
JR C,BADHX6 ; no good
LD R0,R10 ; second address into
LD R1,R11 ; RR0
CALL GETADDR ; get move length
JR NC,DO_MOVE ; default is 1
CLR R10 ; clear high order
LD R11,#$01 ; get default into R11
DO_MOVE:
PUSH R2 ; save from pointer
PUSH R3 ;
SUB R3,R1 ; subtract word
SBC R2,R0 ; in two steps
POP R3 ; restore pointer
POP R2 ;
JR C,BKWARD ; carry indicates back move
FORWARD:
LD R8,R2
LD R9,R3
CALL GETMEM ; LDE R15,@RR8
; data is now in R15
LD R8,R0
LD R9,R1
CALL PUTMEM ; LDE @RR8,R15
INCW RR0 ; increment pointers
INCW RR2 ;
DECW RR10 ; decrement count
JR NZ,FORWARD ;
JR END_MOVE ; stop
BKWARD:
ADD R1,R11 ; point to back end
ADC R0,R10 ; word add
ADD R3,R11 ; point to back end
ADC R2,R10 ;
BACKWD:
DECW RR0 ; decrement pointers
DECW RR2 ;
LD R8,R2
LD R9,R3
CALL GETMEM ; LDE R15,@RR8
; data is now in R15
LD R8,R0
LD R9,R1
CALL PUTMEM ; LDE @RR8,R15
DECW RR10 ; decrement counter
JR NZ,BACKWD ;
END_MOVE:
BADHX6:
POP R15
POP R9
POP R8
RET ; stop
SET
;*****************************************************
;*
;* SET memory
;*
;* syntax S <ADDR> {<DATA>}
;*
;* defaults none
;*
;* Set memory at <ADDR> with <DATA> string.
;* Input is limited to 80 (decimal) characters
;* on the command line.
;*
;******************************************************;
PUSH R15
CALL GETADDR ; get the start address
JR C,BADHX2A ; bad hex
LD R8,R10 ; use reg's RR8
LD R9,R11 ;
SETVAL:
CALL GETADDR ;
JR C,BADHX2 ;
LD R15,R11 ; data
PUSH R8 ; hi addr
PUSH R9 ; lo addr
CALL PUTMEM ; LDE @RR8,R15
POP R9 ;
POP R8 ;
INCW RR8 ;
JR SETVAL ; get next value
BADHX2:
CLR ERR_CODE ; clear error
BADHX2A:
POP R15
RET ;
MEMORY
;*******************************************************
;*
;* MEMORY
;*
;* syntax D [<START ADDR> [<LENGTH>]]
;*
;* defaults <length> = 1,and the user is given
;* the opportunity to
;* change the contents
;* <start addr> = 0 (user_zero)
;*
;* action (full syntax)
;* memory is displayed $10 locations to
;* a line (unless less is specified)
;* each line has two addresses, the first
;* location displayed and the 8th location.
;* following each line and on the same line
;* is the ascii conversion when possible
;* and a dot when value not an ascii character.
;* the ascii conversion is offset by '*'
;*
;* (partial syntax)
;* each memory location is displayed, first
;* the address then the contents, and a prompt
;* is issued to the user for input.
;* possible inputs are:
;* [^|.|q] <cr>
;* or
;* <data> [^|.|q] <cr>
;* <data> replaces previous contents
;* <cr> causes the next location to be displayed
;* ^ <cr> the previous location is displayed
;* . <cr> the current location is displayed again
;* q <cr> terminates the command
;*
;*******************************************************;
CALL GETADDR ; get first parameter
JP C,ZERO_START ; start display from zero
PUSH R10 ; save start address
PUSH R11 ;
CALL GETADDR ; get length parameter
JP C,DISP_ALT ; no parameter,display + alter
LD R0,R10 ; put total into RR0
LD R1,R11 ;
POP R11 ; recover start address
POP R10 ;
NEWLINE:
PUSH R10 ;
PUSH R11 ;
CP R0,#$00 ; any left to display ?
JR NZ,GO_AHEAD1 ; go ahead and display
CP R1,#$00 ;
JR Z,ALL_DONE ;
GO_AHEAD1:
CALL DISPMEMLINE ; display a line of memory
POP R13 ; get start of current line
POP R12 ; using RR12
CALL DISPASCII ; display
JR NEWLINE ; display next line
ALL_DONE:
POP R11 ; pop stack
POP R10 ;
ERR_EXIT:
RET ; errors exit here
DONE:
CLR ERR_CODE ; no error,a token
RET ; and exit
ZERO_START:
CALL EDIT_STATUS ; tell host edit mode
CLR R10 ;
CLR R11 ; start at user zero
JR DISP_1 ; display one at a time
DISP_ALT:
CALL EDIT_STATUS ; tell host edit mode
POP R11 ; recover parameter for
POP R10 ; the start address
DISP_1:
CALL OUTADDR ; output the address
PUSH R8
PUSH R9
PUSH R15
LD R8,R10 ; hi addr
LD R9,R11 ; lo addr
CALL GETMEM ; read byte from memory
LD R4,R15 ; get data
POP R15
POP R9
POP R8
CALL OUTDAT ;
; output prompt with leading STX and trialing ETX
; for host package
LD R4,#ASCIISTX
CALL OUTCHR
LD R4,#'+' ; prompt for response
CALL OUTCHR ;
LD R4,#ASCIIETX
CALL OUTCHR
CALL GETLINE ; get the response
DISP_TOKEN:
CP R4,#ASCIIQ ; is it quit ?
JR Z,DONE ;
CP R4,#'q' ; is it quit ?
JR Z,DONE ;
CP R4,#ASCIIUP ; is it an up ?
JR NZ,DOT ;
DECW RR10 ;
JR DISP_1 ;
DOT:
CP R4,#ASCIIDOT ; is it a dot ?
JR Z,DISP_1 ;
CP R4,#ASCIICR ; is it a <cr> ?
JR NZ,NUMERIC ;
INCW RR10 ;
JR DISP_1 ;
NUMERIC:
PUSH R10 ; save
PUSH R11 ; save
CLR R10 ; clear
CLR R11 ; for conversion
CALL CON_BYTE ; entry to getaddr
JR C,ALL_DONE ; error
LD R4,R11 ; low order byte important
POP R11 ; restore address
POP R10 ;
PUSH R8
PUSH R9
PUSH R15
LD R15,R4 ; data
LD R8,R10 ; hi addr
LD R9,R11 ; lo addr
CALL PUTMEM ; write byte to memory
POP R15
POP R9
POP R8
CALL FINDNEXT ; are there two tokens?
JR NZ,DISP_TOKEN ;
INCW RR10 ; move pointer
JR DISP_1 ; go again
COMPARE
;*****************************************************
;*
;* COMPARE memory
;*
;* syntax C <ADDR1> <ADDR2> [<LENGTH>]
;*
;* defaults <LENGTH> = 1
;*
;* action compares contents of addr1 with addr2
;* if values are unequal,the addresses
;* and contents are displayed on the console
;* <ADDR1> = <VAL1> <ADDR2> = <VAL2>
;* if values are equal,nothing is displayed
;* <ADDR1>=<ADDR2>+1 and <ADDR2>=<ADDR2>+1
;*
;*****************************************************;
PUSH R8
PUSH R9
CALL GETADDR ; get first parameter
JR C,BADHX3 ; bad hex
LD R0,R10 ; use RR0 for first adddress
LD R1,R11 ;
CALL GETADDR ; get second address
JR C,BADHX3 ;
LD R2,R10 ; use RR2 for second addr
LD R3,R11 ;
CALL GETADDR ; get length
JR NC,COMP ; got length in RR10
CLR R10 ; no good parameter
LD R11,#$01 ; just compare 1
COMP:
LD R8,R10 ; put length in RR8
LD R9,R11 ;
DO_COMP:
PUSH R8
PUSH R9
LD R8,R0 ; hi addr
LD R9,R1 ; lo addr
CALL GETMEM ; LDE R15,@RR8
LD R14,R15 ; get data
LD R8,R2 ; hi addr
LD R9,R3 ; lo addr
CALL GETMEM ; LDE R15,@RR8
POP R9
POP R8
; data is in R15
CP R14,R15 ; compare the values
JR EQ,NODISPLAY ; don't display if equal
CALL COMPDISP ; display
NODISPLAY:
INCW RR0 ; increment pointers
INCW RR2 ;
DECW RR8 ;
JR NZ,DO_COMP ;
BADHX3:
POP R9
POP R8
RET ; finished
;**********************************************
;*
;* sup.s : low level support routines for
;* the various commands.
;*
;* (1) memory read/write
;* (2) register read/write
;* (3) I-CODE execution
;*
;***********************************************;
READ_DIR_REG
;*****************************************************
;*
;* READ_DIR_REG Read register using Register
;* addressing mode. This will
;* read "set one" registers above
;* register address $BF
;*
;* input R9 has register number
;*
;* output R6,R7 point to reg_read,where
;* the register value is returned
;* R9 is unchanged,R4 = $00
;*
;*****************************************************;
push r0
push r4 ; Save some
push r5 ; registers
ldw rr6,#I_CODE ; Point to I_CODE buffer
ld r0,#$48 ; 1st byte of LD R4,REG#
ldc @rr6,r0 ; instruction
incw rr6 ; Point to next location
ldc @rr6,r9 ; 2nd byte is REG#
incw rr6 ; Point to next location
ld r0,#$AF ; Place a RET instruction
ldc @rr6,r0 ; at the end
call I_CODE ; Go execute the LD instruction
LDW rr6,#REG_READ ; leave RR6 pointing to place
; where reg val is returned
ldc @rr6,r4 ; Place value read into memory
pop r5
pop r4
pop r0
RET
READ_IR_REG
;*****************************************************
;*
;* READ_IR_REG Read general purpose register
;* using Indirect Register addressing mode.
;* This will read "set two" registers above
;* register address $BF.
;*
;* input R9 has register number and should
;* be in the range $C0 - $FF
;*
;* output R6,R7 point to reg_read,where
;* the register value is returned
;* R9 is unchanged,R4 = $00
;*
;*****************************************************;
PUSH R4
PUSH R5
ld r5,@r9 ; get register contents
LDW rr6,#REG_READ ; leave RR6 pointing to
; place reg val returned
ldc @RR6,r5 ; Write register value to memory
POP R5
POP R4
RET ;
WRITE_DIR_REG
;***************************************************
;*
;* WRITE_DIR_REG Write a value to general registers
;* $00 - $BF, or set one registers
;*
;* input R9 has register number
;* R11 has value to be written to it
;*
;* used R6,R7 used as pointers to I-CODE
;* R5 used to send opcode
;*
;* output R9 is unchanged,R11 = 0
;* R5,R6,R7 destroyed
;*
;***************************************************;
LDW RR6,#I_CODE ; Point to I_CODE execution buffer
LD R5,#$B9 ; 1st byte of LD REG#,R11 instruction
LDC @RR6,R5 ; first write opcode
INCW RR6 ;
LDC @RR6,R9 ; 2nd byte is REG# to write
INCW RR6 ;
ld r5,#$AF ; 3rd byte is a RET instruction
LDC @RR6,R5 ;
CALL I_CODE ; now execute I-CODE
RET ; it will happen
WRITE_IR_REG
;***************************************************
;*
;* WRITE_IR_REG Write a value to a register using
;* Indirect Register mode. This will access
;* set two registers $C0 - $FF.
;*
;* input R9 has register number to be written to and
;* should be in the range $C0 - $FF.
;* R11 has value to be written to it
;*
;* output R9 is unchanged,R11 = 0
;*
;***************************************************;
ld @r9,r11 ; Write register
clr r11
RET
GETMEM
;****************************************************************
;*
;* GETMEM
;*
;* Sets GETMEMFLG bit in CFLAG and calls GETPUTMEM
;* checks address for internal or external memory
;* internal 0 through (ROM_size -1), adds offset
;* external >= ROM_size forces user z8 to read
;*
;* input: RR8 contains address to be read from
;*
;* output: R15 contains data read
;*
;****************************************************************;
; Read from data memory?
CP D_MEMFLAG, #$ff ; X command ?
JR EQ, EXT_MEM
; doing prpgram memory
GM_INTERN:
PUSH R6 ; save registers
PUSH R7 ; use RR6 for LDC
LD R6,R8 ; high address byte
LD R7,R9 ; and low address byte
LDC R15,@RR6 ; Read byte from program memory
POP R7 ; restore
POP R6 ; registers
RET ; deliver the byte
; doing data memory
EXT_MEM:
PUSH R6 ; save registers
PUSH R7 ; use RR6 for LDC
LD R6,R8 ; high address byte
LD R7,R9 ; and low address byte
LDC R15,@RR6 ; Read byte from data memory
POP R7 ; restore
POP R6 ; registers
RET ; deliver the byte
PUTMEM
;***************************************************************
;*
;* PUTMEM
;*
;* resets GETMEMFLG bit in CFLAG and calls GETPUTMEM
;* checks address for internal or external memory
;* internal 0 through (ROM_size -1) , adds offset
;* external >= ROM_size forces user z8 to write
;*
;* input: RR8 contains address to be written to.
;* R15 contains data to be written.
;*
;****************************************************************;
; write to data memory ?
CP D_MEMFLAG, #$ff ;X command ?
JR EQ, EXT_MEM_PUT
; write to program memory
PM_INTERN:
PUSH R6 ; save
PUSH R7 ; use RR6 for LDE
LD R6,R8
LD R7,R9
LDC @RR6,R15 ; write byte to program memory
POP R7 ;
POP R6 ;
RET ; deliver the byte
; write to data memory
EXT_MEM_PUT:
PUSH R6 ; save
PUSH R7 ; use RR6 for LDE
LD R6,R8
LD R7,R9
LDC @RR6,R15 ; write byte to data memory
POP R7 ;
POP R6 ;
RET ; deliver the byte
PUTEXT
;*****************************************************
;*
;* PUTEXT Store downloaded data into extension area.
;* Makes sure that address is valid.
;* Address must be in $D000 - $DFFF range.
;*
;* input R4 has byte value to be stored
;* RR14 has address to store value in
;*
;* output LDC @RR14,R4
;*
;*
;********************************************************;
CP R14,#$D0 ; address below $D000?
JR LT,BAD_ADDR ; yes
CP R14,#$DF ; address above $DFFF?
JR GT,BAD_ADDR ; yes
LDC @RR14,R4
JR DONE_PUTEXT
BAD_ADDR:
LD ERR_CODE,#BAD_EXT_ADDR
DONE_PUTEXT:
RET
DISPMEMLINE
;*****************************************************
;*
;* DISPMEMLINE Display a line of memory
;*
;* input RR10 points to first address
;* RR0 has count of data to be displayed
;*
;* used R2 counts characters in half line segment
;* R3 to count half line segments
;* R4 to output data to console
;* R5,R10,R11 are used by OUTADDR
;*
;* output R2 = 0
;* R3 = 0
;* R5 = 0
;* RR10 = RR10 + # of locations displayed
;* RR0 = RR0 - # of locations displayed
;* R4 has last ASCII character output
;*
;*****************************************************;
PUSH R8
PUSH R9
PUSH R15
LD R3,#$02 ; disp 2 8-byte segments
A_LINE:
LD R2,#$08 ; assume full half lines
CP R0,#$00 ; how much left to display?
JR NZ,DO_LIN_SEG ; enough for a line seg
CP R1,#$08 ;
JR NC,DO_LIN_SEG ; ditto
CP R1,#$00 ; any left at all
JR Z,ALL_DISPED ; no,just exit
LD R2,R1 ; display partial line seg
DO_LIN_SEG:
SUB R1,R2 ; adjust count
SBC R0,#$00 ; subtract carry from hi byte
HALFLINE:
CALL OUTADDR ; line starts with address
LINESEG:
PUSH R4 ; data
PUSH R10 ; hi addr
PUSH R11 ; lo addr
LD R8,R10
LD R9,R11
CALL GETMEM ; LDE R15,@RR8
POP R11 ;
POP R10 ;
POP R4 ;
LD R4,R15
CALL OUTDAT ; display
INCW RR10 ; move pointer
DJNZ R2,LINESEG ; DJNZ R2,LINESEG
CP R3,#2 ; are we at midpoint?
JR NE,NOT_MID
LD R4,#ASCIISP ; yes, output 2 spaces
CALL OUTCHR
CALL OUTCHR
NOT_MID:
DJNZ R3,A_LINE ; DJNZ R3,A_LINE
ALL_DISPED:
POP R15
POP R9
POP R8
RET ; finished
DISPASCII
;*****************************************************
;*
;* DISPASCII Display ASCII portion memory dump
;*
;*
;* input RR12 point to segment to display
;* RR10 point to next segment
;*
;* used R4 for character output
;* R5 for counter
;*
;* output RR10 saved, ASCII displayed on console
;* RR12 = RR10
;* R4 = <LF>, and R5 = 0
;*
;*****************************************************;
PUSH R8
PUSH R9
PUSH R10 ; save pointer to next
PUSH R11 ; segment in memory
PUSH R15
LD R4,#ASCIISP ; tab one space
CALL OUTCHR
SUB R11,R13 ; how many were displayed?
CP R11,#$10 ; was it a full line ?
JR EQ,ASCOUT ; output the ASCII
CP R11,#$08 ; at least half a line ?
JR GT,MTHALF ; yes,more than half
LD R5,#$05 ; put out extra spaces
LD R4,#ASCIISP ;
SKIPHD:
CALL OUTCHR ;
DJNZ R5,SKIPHD ; DJNZ R5,SKIPHD
MTHALF:
PUSH R11 ; save numberr displayed
COM R11 ; get complement
AND R11,#$0F ; mask off upper nibble
INC R11 ; increment for correct count
; now have # not displayed
LD R4,#ASCIISP ; put out 3 spaces for each
OUT3SP:
LD R5,#$03 ; location in a line not displayed
SPACE_3:
CALL OUTCHR ;
DJNZ R5,SPACE_3 ; DJNZ R5,SPACE_3
DJNZ R11,OUT3SP ; DJNZ R11,OUT3SP
POP R11 ; get back number displayed
ASCOUT:
LD R4,#ASCIISTAR ; start displayed with a star
CALL OUTCHR ;
PRINT_IT:
PUSH R4 ; data
PUSH R12 ; hi addr
PUSH R13 ; lo addr
LD R8,R12
LD R9,R13
CALL GETMEM ; LDE R15,@RR8
POP R13 ;
POP R12 ;
POP R4 ;
; data is in R15
LD R4,R15
CP R4,#ASCIISP ; is it printable?
JR GE,MAY_PRINT ; maybe
UN_PRINT:
LD R4,#ASCIIDOT ; output a dot if not
JR CAN_PRINT ; a printable character
MAY_PRINT:
CP R4,#$7F ; it could be too large
JR GE,UN_PRINT ; so can't print it
CAN_PRINT:
CALL OUTCHR ; output the character
; be it a dot or ASCII
INCW RR12 ; increment pointer
DJNZ R11,PRINT_IT ; DJNZ R11,PRINT_IT
LD R4,#ASCIISTAR ; final star
CALL OUTCHR ;
CALL CRLF ; end of line
POP R15 ;
POP R11 ; restore pointer to nxt
POP R10 ; segment of memory
POP R9
POP R8
RET ;
COMPDISP
;*******************************************************
;*
;* COMPDISP
;*
;* input RR0 point to addr1
;* RR2 point to addr2
;* R14 has contents of RR0
;* R15 has contents of RR2
;*
;* used R8 (saved first) to point to R14,R15
;* R4 for character output
;* R5,R10,R11 for address output
;* R12 to point to registers RR0,RR2
;* R13 to count to 2
;*
;* output R8 preserved
;* R13 = 0
;* R5 = 0
;* R4 = <LF>
;* R12 points to R4
;* R10,R11 destroyed
;* RR0,RR2,R14,R15 unchanged
;*
;*****************************************************;
PUSH R8 ; used in calling routine
LD R12,RP0 ; point to R0 with R12
LD R8,R12 ; make R8 point to R14
ADD R8,#14 ; to get the values
LD R13,#$02 ; two values to display
DISP_COMP:
LD R10,@R12 ; display address
INC R12 ;
LD R11,@R12 ;
INC R12 ;
CALL OUTADDR ; line starts with address
LD R4,#ASCIIEQ ; connect with an equals
CALL OUTCHR ;
LD R4,#ASCIISP ; and space
CALL OUTCHR ;
LD R4,@R8 ; get contents into R4
INC R8 ;
CALL OUTDAT ;
DJNZ R13,DISP_COMP ; DJNZ R13,disp_comp
CALL CRLF ; new line
POP R8 ; restore
RET
DELAY
;*******************************************************
;*
;* DELAY kill time routine.
;*
;* input R4 has delay variable
;*
;*******************************************************;
PUSH R5
DELAY_LOOP:
LD R5,#$40
DELAY_R5:
DJNZ R5,DELAY_R5
DJNZ R4,DELAY_LOOP
POP R5
RET
;**********************************************
;*
;* reg.s : Register display and edit
;* routines.
;*
;**********************************************;
CONSTANT
RW equ $00 ; read/write register
WO equ $01 ; write only register
RO equ $02 ; read only register
UI equ $04 ; unimplemented register
REGISTERS
;******************************************************
;*
;* REGISTER display and alter
;*
;* syntax R [-S|C|SC] [<REG NUMBER> [<REG VALUE>]]
;*
;* defaults *
;******************************************************;
CLR REG_MODE
; look for SC option in command line
; GET_SC_OPT sets REG_MODE accordingly
CALL GET_SC_OPT ; look for SC options
CP ERR_CODE,#BAD_OPT
JR EQ,DONE_REGISTER
CALL GETADDR ; are there parameters?
JR C,DISP_REGS ; no, display all
PUSH R11 ; save register number
CALL GETADDR ; is it a single command?
JP C,EDIT_REG ; no,scroll thru registers
POP R9 ; get the reg number into R9
CALL WRITE_1_REG ; write value in R11 into
; reg pointed to by R9
RET
DISP_REGS
CP ERR_CODE,#BAD_HEX ; was there a bad reg# ?
JR EQ,DONE_REGISTER
; Display system registers
TM REG_MODE,#S_FLAG ; display sys regs?
JR Z,CNTRL_MODE ; no
CALL SYS_REG ; yes
TM REG_MODE,#C_FLAG ; displaying control
JR Z,DONE_REGISTER ; also? no
CALL CRLF ; yes, so put an extra CR
; Display control registers
CNTRL_MODE
TM REG_MODE,#C_FLAG ; display ctl regs?
JR Z,GEN_MODE ; no
CALL CNTR_REG ; yes
; Display general purpose registers
GEN_MODE
TM REG_MODE,#S_FLAG+C_FLAG ; display gen. regs?
JR NZ,DONE_REGISTER ; no
CALL GEN_PURPOSE ; yes
RET
EDIT_REG
CALL EDIT_STATUS ; indicate to host edit mode
POP R9 ; get the reg number into R9
CP ERR_CODE,#BAD_HEX ; was there a bad reg value?
JR EQ,DONE_REGISTER ; yes
TM REG_MODE,#S_FLAG ; edit sys regs?
JP NZ,EDIT_SYS ; yes, JP to edit
; sys regs procedure
TM REG_MODE,#C_FLAG ; edit ctl regs?
JP NZ,EDIT_CTL ; yes, JP to edit
; ctl reg procedure
; edit gen. regs?
TM REG_MODE,#S_FLAG+C_FLAG
JR NZ,DONE_REGISTER ; no
CALL EDIT_GEN ; yes
DONE_REGISTER
RET ; stop the command
WRITE_1_REG
;*****************************************************************
;*
;* WRITE_1_REG Write the value in R11 into the user
;* register pointed to by R9.
;*
;* input: R9 has the user register number to be written to.
;* R11 has the value to be written.
;* REG_MODE has the appropriate flags set for the
;* '-S' and '-C' options.
;*
;* output: If no errors are found, the value is written to
;* the user register.
;*
;*******************************************************************;
TM REG_MODE,#C_FLAG+S_FLAG
; is it a sys or ctl register?
JR NZ,WRITE_SC ; yes
; it's a general purpose register
CP R9,#$C0 ; is register < $C0 ?
JR ULT,WRITE_R ; yes, write direct
JR WRITE_IR ; no, write indirect
WRITE_SC
CP R9,#$C0 ; is it < $C0 ?
JR ULT,ERR_WR1 ; yes, error
CP R9,#$CF ; is it > $CF ?
JR UGT,WRITE_R ; yes, write it
; it's a "set one" Cx register
LD D_MEMFLAG,#$FF ; indicate a write
CALL RD_WR_CX ; to a Cx register
CLR D_MEMFLAG
JR DONE_WR_1
WRITE_IR
CALL WRITE_IR_REG ; write indirect
JR DONE_WR_1
WRITE_R
; check for control register
CP R9,#$E0 ; is it >= $E0?
JR ULT,NO_BANK ; no, a sys register
; check for bank 0
TM REG_MODE,#ZERO_FLAG ; bank zero ?
JR Z,CHECK_BANK1 ; no
; its a bank 0 register write
PUSH R2 ; save R2
CLR R2 ; a bank 0 register
LD D_MEMFLAG,#$FF ; a write
CALL RD_WR_BANK ; write it
POP R2 ; restore R2
CLR D_MEMFLAG
JR DONE_WR_1
CHECK_BANK1
; check for bank 1
TM REG_MODE,#ONE_FLAG ; bank ONE ?
JR Z,NO_BANK ; no
; its a bank 1 register write
PUSH R2 ; save R2
LD R2,#1 ; a bank 1 register
LD D_MEMFLAG,#$FF ; a write
CALL RD_WR_BANK ; write it
POP R2 ; restore R2
CLR D_MEMFLAG
JR DONE_WR_1
NO_BANK
CALL WRITE_DIR_REG ; write direct
DONE_WR_1
RET
ERR_WR1
LD ERR_CODE,#BAD_PARAM_VAL
JR DONE_WR_1
GET_SC_OPT
;***********************************************************
;*
;* GET_SC_OPT Look at the command line for the
;* [-S | -C | -SC | -C0 | -C1] options. Set
;* REG_MODE with the appropriate flags.
;*
;************************************************************;
AND REG_MODE,#GEN_FLAG ; assume no option
CALL FINDOPT ; look for option in command
CP R10,#0 ; is there no option
JR EQ,DONE_SC
CP R10,#ASCIISP ; just a " " following "-" ?
JR EQ,SC_ERROR
CP R10,#ASCIICR ; just a <CR> following "-" ?
JR EQ,SC_ERROR
; check for option in R10
CP R10,#'s' ; check R10 for 's' opt
JR NE,R10_NOT_S
OR REG_MODE,#S_FLAG
JR CHECK_R11
R10_NOT_S
CP R10,#'c' ; if its not a 'c' and
JR NE,SC_ERROR ; not an 's', its an error
OR REG_MODE,#C_FLAG
CHECK_R11
; check for option in R10
CP R11,#ASCIISP ; check for a space
JR EQ,DONE_SC
CP R11,#ASCIICR ; check for a CR
JR EQ,DONE_SC
CP R11,#'s' ; check R11 for 's' opt
JR NE,R11_NOT_S
OR REG_MODE,#S_FLAG
JR DONE_SC
R11_NOT_S
CP R11,#'c' ; check for 'c' option
JR NE,R11_NOT_C ; not an 's'
OR REG_MODE,#C_FLAG
JR DONE_SC
R11_NOT_C
CP R11,#'0' ; a 0 ?
JR NE,R11_NOT_0 ; not a '0'
CP R10,#'c' ; was 1st opt a 'c'?
JR NE,SC_ERROR ; no, error
OR REG_MODE,#ZERO_FLAG ; yes, set flag
JR DONE_SC
R11_NOT_0
CP R11,#'1' ; a 1 ?
JR NE,SC_ERROR ; not a '1'
CP R10,#'c' ; was 1st opt a 'c'?
JR NE,SC_ERROR ; no, error
OR REG_MODE,#ONE_FLAG ; yes, set flag
DONE_SC
RET
SC_ERROR
CLR REG_MODE
LD ERR_CODE,#BAD_OPT
JR DONE_SC
EDIT_GEN
;*************************************************************
;*
;* EDIT_GEN Edit the general purpose registers
;*
;* input: starting register number is in R9
;*
;*
;***************************************************************;
CLR ERR_CODE ; NOT AN ERROR
DISP_1_REG
LD R4,R9 ; display the register value
CALL OUTDAT ;
PUSH R9 ; save reg number
CP R9,#$C0 ; set two register?
JR UGE,IR_READ ; yes
CALL READ_DIR_REG ; read reg. number R9
JR READ_RESULT
IR_READ
CALL READ_IR_REG ; read set two reg. number R9
READ_RESULT
LDC R4,@RR6 ; display the register contents
CALL OUTDAT ;
POP R9 ; restore reg number
; prompt for a new value, package STX and ETX around
; prompt for the host package
LD R4,#ASCIISTX
CALL OUTCHR
LD R4,#'+' ; prompt for a new value
CALL OUTCHR ;
LD R4,#ASCIIETX
CALL OUTCHR
CALL GETLINE ; input response up to <CR>
REG_TOKEN
CP R4,#ASCIIQ ; is it a quit?
JR Z,END_REG ; stop the command sequence
CP R4,#'q' ; is it a quit?
JR Z,END_REG ; stop the command sequence
CP R4,#ASCIIUP ; is it an ^
JR NZ,REG_DOT ; if not check for dot
DEC R9 ; it is a ^,do previous
JR DISP_1_REG ; display previous register
REG_DOT
CP R4,#ASCIIDOT ; dot displays same
JR Z,DISP_1_REG ;
CP R4,#ASCIICR ; just display next?
JR NZ,NEW_REG_VAL ; no, convert the number
JR MORE_REG ;
NEW_REG_VAL
CLR R10 ;
CLR R11 ;
CALL CON_BYTE ; convert
JR C,END_REG ; error
CP R9,#$C0 ; a set two register?
JR UGE,WRITE_IND ; yes
CALL WRITE_DIR_REG ; no, write R11 into R9
JR WROTE_REG
WRITE_IND
CALL WRITE_IR_REG ; write R11 into R9
; (set two)
WROTE_REG
CALL FINDNEXT ; is there a token also?
JR NZ,REG_TOKEN ; yes,there is more on the line
MORE_REG
INC R9 ; increment register pointer
JP DISP_1_REG ; display the nest register
END_REG
RET ; stop the command
EDIT_SYS
;*************************************************************
;*
;* EDIT_SYS Edit the system registers
;*
;*
;* input: starting register number is in R9
;*
;***************************************************************;
CLR ERR_CODE ; NOT AN ERROR
CP R9,#$D0 ; too low for a sys reg.?
JR UGE,CHK_SYS_HI ; no
LD ERR_CODE,#BAD_PARAM_VAL ; yes
JR END_SYS_ED
CHK_SYS_HI
CP R9,#$DE ; too high for a sys reg.?
JR ULE,DISP_1_SYS ; no
LD ERR_CODE,#BAD_PARAM_VAL ; yes
JR END_SYS_ED
DISP_1_SYS
LD R4,R9 ; display the register value
CALL OUTDAT ;
CALL READ_DIR_REG ; read reg pointed to by R9
LDC R4,@RR6 ; display the register contents
CALL OUTDAT ;
; prompt for a new value, package STX and ETX around
; prompt for the host package
LD R4,#ASCIISTX
CALL OUTCHR
LD R4,#'+' ; prompt for a new value
CALL OUTCHR ;
LD R4,#ASCIIETX
CALL OUTCHR
CALL GETLINE ; input response up to <CR>
SYS_TOKEN
CP R4,#ASCIIQ ; is it a quit?
JR Z,END_SYS_ED ; stop the command sequence
CP R4,#'q' ; is it a quit?
JR Z,END_SYS_ED ; stop the command sequence
CP R4,#ASCIIUP ; is it an ^
JR NZ,SYS_DOT ; if not check for dot
DEC R9 ; it is a ^,do previous
CP R9,#$CF ; at boundry?
JR UGT,DISP_1_SYS ; no
LD R9,#$DE ; yew
JR DISP_1_SYS ; display previous register
SYS_DOT
CP R4,#ASCIIDOT ; dot displays same
JR Z,DISP_1_SYS ;
CP R4,#ASCIICR ; just display next?
JR NZ,NEW_SYS_VAL ; no, convert the number
JR MORE_SYS ;
NEW_SYS_VAL
CLR R10 ;
CLR R11 ;
CALL CON_BYTE ; convert
JR C,END_SYS_ED ; error
CALL WRITE_DIR_REG ; write R11 into R9
CALL FINDNEXT ; is there a token also
JR NZ,SYS_TOKEN ; yes,there is more on the line
MORE_SYS
INC R9 ; indrement pointer to reg
CP R9,#$DF ; at boundry ?
JP ULT,DISP_1_SYS ; no
LD R9,#$D0 ; yes
JP DISP_1_SYS ; display the next register
END_SYS_ED
RET ; stop the command
EDIT_CTL
;*************************************************************
;*
;* EDIT_CTL Edit the control registers
;*
;*
;* input: starting register number is in R9
;*
;***************************************************************;
PUSH R2
; check for start bank
TM REG_MODE,#ONE_FLAG ; bank one?
JR Z,ITS_BANK2 ; no
LD R2,#1 ; yes, set number
JR CLEAR_ERR
ITS_BANK2
CLR R2 ; bank number starts with 0
CLEAR_ERR
CLR ERR_CODE ; not an error
; check for reg number between $C0 and $CF
CP R9,#$C0 ; reg number < $C0 ?
JP ULT,CTL_BAD_PARAM ; yes
CP R9,#$CF ; reg number <= $CF ?
JR ULE,DISP_1_CTL ; yes
; check for reg number between $E0 and $CF
CP R9,#$E0 ; reg number < $E0 ?
JP ULT,CTL_BAD_PARAM ; yes
DISP_1_CTL
LD R4,R9 ; display the register number
CALL OUTHEX ;
; display the bank number if in range $E0 - $FF
CP R9,#$CF ; a control register?
JR ULE,CX_REG ; no, a Cx register
LD R4,#'/' ; display bank number
CALL OUTCHR
LD R4,R2 ; save bank # in R4
LD R6,#REGBUF
CALL BTOHEXDAT ; convert to ASCII
LD R4,REGBUF+1 ; get least sig. digit
CALL OUTCHR ; print it
LD R4,#ASCIISP
CALL OUTCHR
CLR D_MEMFLAG ; indicate a read
CALL RD_WR_BANK ; read reg pointed to by R9
LD R4,R10 ; R10 has the value
JR OUT_REG
CX_REG
LD R4,#ASCIISP ; write out a space
CALL OUTCHR
CALL RD_WR_CX ; Cx reg pointed to by
; R9 and load its value
; into R4
OUT_REG
CALL OUTDAT ; display register vlaue
; prompt for a new value, package STX and ETX around
; prompt for the host package
LD R4,#ASCIISTX
CALL OUTCHR
LD R4,#'+' ; prompt for a new value
CALL OUTCHR ;
LD R4,#ASCIIETX
CALL OUTCHR
CALL GETLINE ; input response up to <CR>
CTL_TOKEN
CP R4,#ASCIIQ ; is it a quit?
JP Z,END_CTL_ED ; stop the command sequence
CP R4,#'q' ; is it a quit?
JP Z,END_CTL_ED ; stop the command sequence
CP R4,#ASCIIUP ; is it an ^
JR NZ,CTL_DOT ; if not check for dot
DEC R9 ; it is a ^,do previous
CP R9,#$DF ; past $E0 boundry?
JR EQ,TO_CF ; yes, skip to $CF
CP R9,#$BF ; past $C0 boundry?
JP NE,DISP_1_CTL ; no, display previous
; wrap around and change bank numbers
LD R9,#$FF ; start at $FF again
CP R2,#0 ; bank 0?
JR EQ,TO_BANK1 ; yes
LD R2,#0 ; no, set to 0
JP DISP_1_CTL
TO_BANK1
LD R2,#1 ; set to 1
JP DISP_1_CTL
TO_CF
LD R9,#$CF ; start at $CF
JP DISP_1_CTL
CTL_DOT
CP R4,#ASCIIDOT ; dot displays same
JP Z,DISP_1_CTL ;
CP R4,#ASCIICR ; just display next?
JR NZ,NEW_CTL_VAL ; no, convert the number
JR MORE_CTL ;
NEW_CTL_VAL
CLR R10 ;
CLR R11 ;
CALL CON_BYTE ; convert
JR C,END_CTL_ED ; error
; write value in R11 into register pointed to by R9
CP R9,#$CF ; a Cx register?
JR ULE,WR_CX_REG ; yes
LD D_MEMFLAG,#$FF ; indicate a write
CALL RD_WR_BANK ; no, normal write
CLR D_MEMFLAG
JR NEXT_FIND
WR_CX_REG
LD D_MEMFLAG,#$FF ; indicate a write
CALL RD_WR_CX ; to a Cx reg.
CLR D_MEMFLAG
NEXT_FIND
CALL FINDNEXT ; is there a token also
JR NZ,CTL_TOKEN ; yes,there's more on the line
MORE_CTL
CP R9,#$CF ; at $CF boundry ?
JR EQ,TO_E0 ; yes, next is $E0
CP R9,#$FF ; at $FF boundry ?
JR ULT,INC_CTL_ED ; no
; wrap around and change bank number
LD R9,#$C0 ; yes, prepare for $C0
CP R2,#1 ; bank 1?
JR EQ,TO_BANK0 ; yes
LD R2,#1 ; no, set to 1
JP DISP_1_CTL
TO_BANK0
LD R2,#0 ; set to 0
JP DISP_1_CTL
INC_CTL_ED
INC R9 ; indrement register pointer
JP DISP_1_CTL ; display the next register
TO_E0
LD R9,#$E0 ; new register is $E0
JP DISP_1_CTL
END_CTL_ED
; restore user flag register
PUSH R9
PUSH R11
LD R9,#$D5 ; flag reg number
LD R11,USER_FLAGS ; flag reg value
CALL WRITE_DIR_REG ; write it
POP R11
POP R9
POP R2
RET
CTL_BAD_PARAM
LD ERR_CODE,#BAD_PARAM_VAL
JR END_CTL_ED
RD_WR_CX
;*************************************************************
;*
;* RD_WR_CX Read/write a "set one" register in the
;* range $C0 - $CF.
;*
;* input: R9 has the register number to be read.
;* D_MEMFLAG is 0 for a read and $FF for a write.
;* R11 has the value to be written for a write.
;*
;* output: R4 has the register value for a read.
;*
;*************************************************************;
PUSH R9 ; save reg number
PUSH R11 ; save value
; read RP0 and RP1 and save them
LD R9,#$D6 ; RP0
CALL READ_DIR_REG ; read it
LDC R4,@RR6
LD USER_RP0,R4 ; save it
LD R9,#$D7 ; RP1
CALL READ_DIR_REG ; read it
LDC R4,@RR6
LD USER_RP1,R4 ; save it
; write $C0 and $C8 to RP0 and RP1
LD R9,#$D6 ; RP0
LD R11,#$C0 ; gets $C0
CALL WRITE_DIR_REG ; write it
LD R9,#$D7 ; RP1
LD R11,#$C8 ; gets $C8
CALL WRITE_DIR_REG ; write it
; now read/write the register
POP R11 ; restore reg value
POP R9 ; restore reg number
CP D_MEMFLAG,#0 ; is it a read?
JR EQ,READ_CX ; yes
CALL WRITE_DIR_REG ; write it
JR RESTORE_CX
READ_CX
CALL READ_DIR_REG ; read it
LDC R4,@RR6 ; save it
; restore RP0 and RP1
RESTORE_CX
PUSH R9 ; save reg number
PUSH R11 ; save value
LD R9,#$D6 ; RP0
LD R11,USER_RP0
CALL WRITE_DIR_REG ; write it
LD R9,#$D7 ; RP1
LD R11,USER_RP1
CALL WRITE_DIR_REG ; write it
POP R11 ; restore reg value
POP R9 ; restore reg number
RET
SYS_REG
;*************************************************************
;*
;* SYS_REG Display all system registers
;*
;***************************************************************;
CLR ERR_CODE ; clear errors
; display 1st row of PC and system registers
LD R6,#^HB SYS1_H_REG ; print 1st nmemonic
LD R7,#^LB SYS1_H_REG ; header for system
CALL OUTMSG ; registers
LD R6,#^HB SYS1_N_REG ; print the register
LD R7,#^LB SYS1_N_REG ; numbers
CALL OUTMSG ;
ld r10,USERPC_HI ; Print
ld r11,USERPC_LO ; user
call OUTADDR ; PC
LD R4,#ASCIISP ; tab 1 space
CALL OUTCHR
LD R9,#$D0 ; display start
LD R10,#$D6 ; display end
CALL SYS_OUT ; display the regs
CALL CRLF ;
CALL CRLF ; one blank line
; display 2nd row of system registers
LD R6,#^HB SYS2_H_REG ; print 2nd nmemonic
LD R7,#^LB SYS2_H_REG ; header for system
CALL OUTMSG ; registers
LD R6,#^HB SYS2_N_REG ; print the register
LD R7,#^LB SYS2_N_REG ; numbers
CALL OUTMSG ; for input
LD R9,#$D7 ; display start
LD R10,#$DE ; display end
CALL SYS_OUT ; display the regs
CALL CRLF ;
RET
GEN_PURPOSE
;*************************************************************
;*
;* GEN_PURPOSE Display all general purpose registers
;*
;***************************************************************;
PUSH R6
PUSH R7
PUSH R9
PUSH R10
PUSH R11
PUSH R12
; R12 has the leading character, a 'R' (working register)
; or ' '. Space is the default
LD R12,#' '
CLR R9 ; register counter
LD R6,#^HB GEN_REG_H ; print the register
LD R7,#^LB GEN_REG_H ; numbers header
CALL OUTMSG ; for input
GEN_LOOP
PUSH R9 ; save reg number
CP R9,#$C0 ; set two register?
JR UGE,GEN_READ_IR ; yes
CALL READ_DIR_REG ; read (direct) reg. number R9
JR GEN_GET_RESULT
GEN_READ_IR
CALL READ_IR_REG ; read set two (indirect) reg. number R9
GEN_GET_RESULT
; RR6 now points to result register
LDC R10,@RR6 ; save register value
; in R10
POP R9 ; restore reg number
TM R9,#$0F ; R9 = x0 ?
JR NZ,CHECK_RP ; no
; write out high nibble for row
CALL CRLF
LD R4,#'r' ; write 'r'
CALL OUTCHR
LD R6,#OUT_CHR1 ; destination of NIBBLE
LD R4,R9 ; load reg number
SWAP R4 ; put upper nibble in lower
CALL NIBBLE ; convert to ASCII
LD R4,OUT_CHR1 ; write it
CALL OUTCHR
LD R4,#'x' ; write 'x'
CALL OUTCHR
LD R4,#ASCIISP ; write ' '
CALL OUTCHR
CALL OUTCHR
CALL OUTCHR ; 3 times
CHECK_RP
TM R9,#$07 ; are we at an 8th reg?
JR NZ,WRITE_IT ; no
CP R9,USER_RP0 ; equal to RP0 ?
JR NE,CHECK_RP1 ; no, check RP1
CP R9, #$C0 ; are we still in register area?
JR UGE, CHECK_RP1
LD R12,#'R' ; yes, output leading 'R'
JR WRITE_IT
CHECK_RP1
CP R9,USER_RP1 ; equal to RP1 ?
JR NE, NOT_RP ; no
CP R9, #$C0 ; are we still in register area?
JR UGE, NOT_RP
LD R12,#'R' ; yes, output leading 'R'
JR WRITE_IT
NOT_RP
LD R12,#' ' ; yes, output leading 'R'
WRITE_IT
LD R4,R12 ; output a leading
CALL OUTCHR ; 'R' or ' '
LD R4,R10 ; register value in R4
LD R6,#OUT_CHR1 ; dest of BTOHEXDAT
CALL BTOHEXDAT
LD R4,OUT_CHR1 ; print high nibble
CALL OUTCHR
LD R4,OUT_CHR2 ; print low nibble
CALL OUTCHR
LD R4,#ASCIISP ; a trailing ' '
CALL OUTCHR
INC R9 ; next register
CP R9,#0 ; are we done?
JR EQ,DONE_GEN ; yes
JP GEN_LOOP ; no, continue
DONE_GEN
CALL CRLF
CLR ERR_CODE
POP R12
POP R11
POP R10
POP R9
POP R7
POP R6
RET
CNTR_REG
;*************************************************************
;*
;* CNTR_REG Display all control and mode registers
;*
;***************************************************************;
CLR ERR_CODE ; clear errors
AND CFLAG,#$F8 ; clear errors
; display 1st row of control and mode registers
LD R6,#^HB CTL1_H_REG ; print 1st nmemonic
LD R7,#^LB CTL1_H_REG ; header for control
CALL OUTMSG ; registers
LD R6,#^HB CTL1_N_REG ; print the register
LD R7,#^LB CTL1_N_REG ; numbers
CALL OUTMSG ;
LD R9,#$E0 ; display start
LD R10,#$F0 ; display end
LD R11,#0 ; bank 0
CALL CNTRL_OUT ; display the regs
CALL CRLF
CALL CRLF ; one blank line
; display 2nd row of control and mode registers
LD R6,#^HB CTL2_H_REG ; print 2nd nmemonic
LD R7,#^LB CTL2_H_REG ; header for control
CALL OUTMSG ; registers
LD R6,#^HB CTL2_N_REG ; print the register
LD R7,#^LB CTL2_N_REG ; numbers
CALL OUTMSG ;
LD R9,#$F6 ; display start
LD R10,#$FF ; display end
LD R11,#0 ; bank 0
CALL CNTRL_OUT ; display the regs
; last 4 regs of row 2 are bank 1 registers
LD R9,#$E0 ; display start
LD R10,#$E3 ; display end
LD R11,#1 ; bank 1
CALL CNTRL_OUT ; display the regs
CALL CRLF
CALL CRLF ; one blank line
; display 3rd row of control and mode registers
LD R6,#^HB CTL3_H_REG ; print 3rd nmemonic
LD R7,#^LB CTL3_H_REG ; header for control
CALL OUTMSG ; registers
LD R6,#^HB CTL3_N_REG ; print the register
LD R7,#^LB CTL3_N_REG ; numbers
CALL OUTMSG ;
LD R9,#$E4 ; display start
LD R10,#$FF ; display end
LD R11,#1 ; bank 1
CALL CNTRL_OUT ; display the regs
CALL CRLF
CALL CRLF ; one blank line
; display 4th row (Cx) registers
LD R6,#^HB CTL4_N_REG ; print 3rd register
LD R7,#^LB CTL4_N_REG ; numbers
CALL OUTMSG ;
LD R9,#$C0 ; display start
LD R10,#$CF ; display end
CALL SYS_OUT ; display the regs
CALL CRLF
RET
SYS_OUT
;*******************************************************
;*
;* SYS_OUT Print out system or Cx registers.
;*
;* input R9 contains 1st register to be displayed.
;* R10 contains last register to be displayed.
;* R9 and R10 are in the range $C0 to $DE.
;* R9 <= R10.
;*
;*************************************************************;
SYS_LOOP
CALL READ_DIR_REG ; read S8 reg. @R9
; RR6 now points to result register
LDC R4,@RR6 ; save the value
LD R6,#OUT_CHR1 ; dest of BTOHEXDAT
CALL BTOHEXDAT
LD R4,OUT_CHR1 ; print high nibble
CALL OUTCHR
LD R4,OUT_CHR2 ; print low nibble
CALL OUTCHR
LD R4,#ASCIISP ; 2 trailing ' 's
CALL OUTCHR ; for rCx regs.
CALL OUTCHR
CP R9,#$D0 ; rCx registers?
JR LT,CHECK_DONE ; yes
CALL OUTCHR ; 4 trailing ' 's
CALL OUTCHR ; for sys regs.
CHECK_DONE
CP R9,R10 ; are we through
JR EQ,SYS_DONE
INC R9 ; next register
JR SYS_LOOP
SYS_DONE
RET
CNTRL_OUT
;*******************************************************
;*
;* CNTRL_OUT Print out control registers.
;* Skip over unimplemented or
;* write only registers.
;*
;* input R9 contains 1st register to be displayed.
;* R10 contains last register to be displayed.
;* R9 and R10 are in the range $E0 to $FF.
;* R9 <= R10.
;* R11 contains bank number to be displayed.
;*
;*************************************************************;
PUSH R8
PUSH R12
PUSH R13
LD R8,R9 ; save start reg.
; Now, do we want Bank 0 or 1 registers ?
CP R11,#0
JR NE,BANK_1
; Bank 0
LD R12,#^HB BANK_0_TAB ; point to proper table
LD R13,#^LB BANK_0_TAB
JR FIND_ENTRY
; Bank 1
BANK_1
LD R12,#^HB BANK_1_TAB ; point to proper table
LD R13,#^LB BANK_1_TAB
; Find correct location in lookup table for first register requested
FIND_ENTRY
SUB R8,#$E0 ; find offset from $E0
LOOP_FIND
CP R8,#0 ; are we through ?
JR EQ,CNTRL_LOOP ; yes
DEC R8 ; decrement counter
INCW RR12 ; point to next byte in table
JR LOOP_FIND
; check for unimplemented or write-only
; control registers
CNTRL_LOOP
LDC R4,@RR12 ; get value from table
CP R4,#UI
JR EQ,NEXT_CNTRL
CP R4,#WO
JR EQ,NEXT_CNTRL
START_READ
; Fisrt save the current user flag register
; so we know which bank (0 or 1) to return to
push FLAGS ; save it
; set correct bank number
CP R11,#0 ; bank 0 ?
JR NE,SET_BANK_1 ; no
sb0
JR WRITE_FLAG
SET_BANK_1
sb1
WRITE_FLAG
; now read the correct control register
CALL READ_DIR_REG ; read S8 reg. @R9
; Restore flag register so we back to the correct bank (0 or 1)
pop FLAGS
; RR6 now points to result register
LDC R4,@RR6 ; save the value
LD R6,#OUT_CHR1 ; dest of BTOHEXDAT
CALL BTOHEXDAT
LD R4,OUT_CHR1 ; print high nibble
CALL OUTCHR
LD R4,OUT_CHR2 ; print low nibble
CALL OUTCHR
LD R4,#ASCIISP ; 4 trailing ' 's
CALL OUTCHR
CALL OUTCHR
CALL OUTCHR
CALL OUTCHR
NEXT_CNTRL
CP R9,R10 ; are we through ?
JR GE,DONE_CNTRL
INC R9 ; next register
INCW RR12
JR CNTRL_LOOP
DONE_CNTRL
POP R13
POP R12
POP R8
RET
RD_WR_BANK
;*******************************************************
;*
;* BANK_REG Read/write the correct control register
;* value for the given bank0/bank1 register.
;*
;* input R9 contains register number and must be
;* in the range $E0 through $FF.
;* R2 contains bank number.
;* R11 contains the value to be written.
;*
;* output R10 has the register value read.
;*
;*
;*******************************************************;
PUSH R4
PUSH R9 ; save reg number
LD R9,#$D5 ; read flag register
CALL READ_DIR_REG
LDC R4,@RR6
LD USER_FLAGS,R4
POP R9
; determine bank, R4 has bank value
CP R2,#0 ; bank 0 ?
JR EQ,SET_BANK0
OR R4,#$01 ; bank 1
JR WRITE_BANK
SET_BANK0
AND R4,#$FE ; bank 0
WRITE_BANK
PUSH R9 ; save used regs
PUSH R11
LD R11,R4
LD R9,#$D5 ; read flag register
CALL WRITE_DIR_REG
POP R11
POP R9
; check for a read or write
CP D_MEMFLAG,#0 ; a read?
JR NE,WR_BANK_REG
; now read the register, R9 has reg number
CALL READ_DIR_REG
LDC R10,@RR6 ; save in output reg
JR RESTOR_FLAG
WR_BANK_REG
CALL WRITE_DIR_REG
RESTOR_FLAG
; restore user flag register
PUSH R9 ; save used regs
PUSH R11
LD R9,#$D5 ; flag reg number
LD R11,USER_FLAGS ; flag reg value
CALL WRITE_DIR_REG ; write it
POP R11
POP R9
POP R4
RET
;*********************************************
;*
;* new.s : Misc. commands
;*
;* (1) Phill (fill) registers
;* (2) Interrupt enable/disable
;* (3) Working register display
;* (4) Echo on/off
;* (5) Verify (self test)
;*
;**********************************************;
PHIL_REGISTERS
;************************************************
;*
;* PHILL fill general registers just as memory
;* is filled.
;*
;* syntax P <REG NUM> <NUM OF REGS> {<DATA>}
;*
;************************************************;
CALL GETADDR ; get first reg num
JR C,BADHX_ ; no good
LD R9,R11 ; first register
CALL GETADDR ; number of registers
JR C,BADHX_ ; no good
LD R2,R11 ; put length in R2
CLR OUTPTR ; use input buffer to
CLR R13 ; store converted pattern
ACCUM_
CALL GETADDR ; get value
JR C,DO_FILL_ ; stop input and fill regs
LD R7,OUTPTR ;
LDC @RR6,R11 ; one byte of data
INC R13 ; keep count
INC OUTPTR ;
JR ACCUM_ ; get next data byte
DO_FILL_
CP R13,#$00 ; if no data, don't fill
JR EQ,BADHX_ ;
LD R0,R6 ; use RR0 to access pattern
RE_PEAT_
LD R8,R13 ; save pattern length
CLR R1 ; and start at begin of pattern
R8LOOP_
LDC R11,@RR0 ; get byte
CP R9,#$C0 ; set two register?
JR UGE,WRITE_IR1 ; yes
CALL WRITE_DIR_REG ; no, write R11 into @R9
JR WROTE_IT
WRITE_IR1
CALL WRITE_IR_REG ; write R11 into @R9
; (set two)
WROTE_IT
INC R9 ;
INC R1 ;
DEC R2 ; number of registers
JR Z,PHIL_END ; done
DJNZ R8,R8LOOP_ ;
JR RE_PEAT_ ;
PHIL_END
CLR ERR_CODE ; no errors
BADHX_
RET ;
INTERRUPT_ENABLE
;************************************************
;*
;* ENABLE USER INTERRUPTS in next 'go'
;*
;* syntax I [E|D]
;*
;* default E
;*
;************************************************;
DI ; must DI to change IMR
CALL FINDNEXT ; parameter?
JR C,DEFAULT_I ; allow interrupts
OR R4,#$20 ; upper or lower case
CP R4,#'e' ; enable is default
JR EQ,DEFAULT_I ;
CP R4,#'d' ; disable
JR NE,IN_ERROR ; invalid parameter
CLR USER_EI
JR ENABLE_GLOBAL ;
DEFAULT_I
CLR ERR_CODE ;
LD USER_EI,#$FF ; go with interrupts
JR ENABLE_GLOBAL ;
IN_ERROR
LD ERR_CODE,#BAD_OPT ; invalid parameter
ENABLE_GLOBAL
EI ;
RET ;
WORKING_REGS
;*************************************************
;*
;* WORKING register display/modify routine
;*
;* syntax W
;*
;*************************************************;
CALL GETADDR ; Check for register number
JP C,DISP_WREGS ; Jump if none found
PUSH R10 ; save
PUSH R11 ; it
CALL GETADDR ; Check for a new value?
JP C,EDIT_WREGS ; Jump if no value found to edit mode
; Write new value to working register
POP R13 ;
CP R13,#$a ;
JR LT,GET_WREG ;
SUB R13,#$6 ;
GET_WREG
POP R12 ; get register
CP R13,#$f ; valid register
JR GT,BADREG ;
LD R9,#$D6 ; get rp0
LD R12,R13 ;
CP R13,#8 ; which RP
JR LT,GET_RP
INC R9
SUB R12,#8
GET_RP
CALL READ_DIR_REG
LDC R9,@RR6
AND R9,#$F8
ADD R9,R12 ; R9 is register, R11 value
CALL WRITE_DIR_REG
CLR ERR_CODE
RET
BADREG
LD ERR_CODE,#BAD_PARAM_VAL
RET
; Edit working register set
EDIT_WREGS
CLR ERR_CODE
CALL EDIT_STATUS
POP R11
POP R10
CP R11,#$15
JR GT,BADREG
CP R11,#10 ; convert hex to decimal
JR LT,LOOP
SUB R11,#6
LOOP ; here we go editing
CALL SEND_STX
LD R4,#'R'
CALL OUTCHR
LD R4,R11 ; print register number
CP R4,#10
JR LT,LP1
ADD R4,#6
LP1
CALL OUTHEX
LD R4,#' '
CALL OUTCHR
LD R9,#$D6 ; get register pointers
LD R10,R11
CP R11,#8
JR LT,LP2
INC R9
SUB R10,#8
LP2
CALL READ_DIR_REG
LDC R9,@RR6
AND R9,#$F8
; get old value
ADD R9,R10
PUSH R9 ; save register
CALL READ_DIR_REG
LDC R4,@RR6
CALL OUTHEX
LD R4,#'+'
CALL OUTCHR
CALL SEND_ETX
CALL GETLINE
POP R13 ; register number
REG_TOKEN1
CP R4,#'Q' ; do we quit
JP EQ,ENDWEDIT
CP R4,#'q'
JP EQ,ENDWEDIT
CP R4,#ASCIIUP
JR NZ,REG_DOT1 ; ^ go back
DEC R11
CP R11,#0
JP GE,LOOP
LD R11,#$f ; wrap around
JP LOOP
REG_DOT1
CP R4,#'.'
JP EQ,LOOP ; same reg again
CP R4,#ASCIICR
JR EQ,MORE_REG1
NEW_REG_VALUE
; R13 should have register number
PUSH R11
CALL CON_BYTE ; convert byte
; R11 = byte
LD R9,R13 ; R9 = register
CALL WRITE_DIR_REG
POP R11
CALL FINDNEXT
JR NZ,REG_TOKEN1
MORE_REG1
INC R11 ; next register
CP R11,#16
JP LT,LOOP
LD R11,#0
JP LOOP
ENDWEDIT
RET
; ----- Display the working register set ------------------
DISP_WREGS
; Start by displaying the working register header, numbers are
; in decimal
LD R0,#0 ; counter
DISP_HDR
LD R4,#'R' ; Put a 'R'
CALL OUTCHR ; in front of each #
; print tens digit
LD R1,R0 ; save reg number
CP R0,#9 ; is R0 > 9 ?
JR GT,GT_9 ; yes
LD R4,#'0' ; no, print '0'
CALL OUTCHR
JR DIGIT_2
GT_9
LD R4,#'1' ; print '1'
CALL OUTCHR
SUB R1,#10 ; R1 has ones digit
DIGIT_2
ADD R1,#$30 ; make it ascii
LD R4,R1
CALL OUTCHR
CP R0,#$0F ; are we through?
JR EQ,DISP_WORKS ; yes
LD R4,#' ' ; no, print 2 spaces
CALL OUTCHR ;
CALL OUTCHR ;
INC R0 ; inc counter
JR DISP_HDR ; and repeat
; ------ Okay we finished with the header now move on ------------
; to displaying the working registers values
DISP_WORKS
CALL CRLF
LD R9,USER_RP0 ; get USER's RP0
and r9,#$F8 ; Mask off don't care bits
PUSH R9 ; save RP0
CALL DISP_REG ; Display the RP0 register set
GET_RP1
LD R9,USER_RP1 ; get USER_RP1
AND R9,#$F8 ; mask off don't cares
PUSH R9 ; save RP1
CALL DISP_REG ; Display the RP1 register set
; ------- Now print the reister pointer values themselves ----------
POP R11 ; Get the RP1
POP R10 ; and RP0 values off of stack
CALL CRLF
LD R4, #'R'
CALL OUTCHR
LD R4, #'P'
CALL OUTCHR
LD R4, #'0'
CALL OUTCHR
LD R4, #'='
CALL OUTCHR
LD R4,R10 ; print the RP0 value
CALL OUTHEX
LD R4, #' '
CALL OUTCHR
LD R4, #'R'
CALL OUTCHR
LD R4, #'P'
CALL OUTCHR
LD R4, #'1'
CALL OUTCHR
LD R4, #'='
CALL OUTCHR
LD R4,R11 ; print the RP1 value
CALL OUTHEX
LD R4, #' '
CALL OUTCHR
LD R4, #'S'
CALL OUTCHR
LD R4, #'P'
CALL OUTCHR
LD R4, #'='
CALL OUTCHR
ldw rr10,USER_SP ; Print SP
call OUTADDR
DISP_DONE
CALL CRLF
CLR ERR_CODE
RET ;
; ------ Display eight register set ------------------------
;
; Enter: R9 points to 8 register set
DISP_REG
LD R10, R9 ; get base register pointer
ADD R10, #7 ; set end pointer for displaying 8 registers
SYS_LOOP1
LD R4,#ASCIISP ; 1 leading ' '
CALL OUTCHR ; for rCx regs.
CALL READ_DIR_REG ; read S8 reg. @R9
; RR6 now points to result register
LDC R4,@RR6 ; save the value
CALL OUTDAT
LD R4,#ASCIISP ; 1 trailing ' '
CALL OUTCHR ; for rCx regs.
CP R9,R10 ; are we through
JR EQ,SYS_DONE1
INC R9 ; next register
JR SYS_LOOP1
SYS_DONE1
RET
EXTENSION
;************************************************************
;*
;* Echo command: E -O|1|0
;*
;* Options have the following meanings:
;*
;* O Toggle the "ECHO ON/ECHO OFF" mode.
;* 1 Turn echo on.
;* 0 Turn echo off.
;*
;*
;**************************************************************;
CALL FINDOPT ; look for the option
CP R10,#'o' ; is it an 'o'
JR NE,CHECK_0 ; no
; toggle the echo mode
CP ECHO_MODE,#ECHO_ON ; are we echoing?
JR EQ,RESET_ECHO ; yes, so stop echo
JR SET_ECHO ; no, start echo
CHECK_0
CP R10,#'0' ; '0' option ?
JR NE,CHECK_1 ; no
JR RESET_ECHO ; yes, turn echo off
CHECK_1
CP R10,#'1' ; '1' option ?
JR NE,NOT_VALID ; no, illegal option
JR SET_ECHO ; yes, turn echo o n
SET_ECHO
LD ECHO_MODE,#ECHO_ON ; no, start echoing
JR DONE_EXT
RESET_ECHO
LD ECHO_MODE,#ECHO_OFF ; stop echoing
JR DONE_EXT
NOT_VALID
LD ERR_CODE,#BAD_OPT
DONE_EXT
; save echo status in monitor RAM
LDW RR6,#ECHO_STAT ; point to echo save
LD R4,ECHO_MODE
LDC @RR6, R4 ; save the status
RET
VERIFY
;********************************************************
;*
;*
;* VERIFY Self test of S8 EM board
;*
;* tests:
;* (1) Performs checksum on Monitor
;*
;* (2) Performs simple test of Super8
;* registers & , User Internal, and Breakpoint RAM
;* by writing and reading 0 and 1 at each bit
;* location.
;*
;* (2) I-Code register interface by writing and
;* reading a SUPER8 register.
;*
;* (3) Emulation interface by the folowing steps:
;*
;* A. write a value to a SUPER8 register.
;*
;* B. put instructions into SUPER8 memory
;* to increment that register.
;*
;* c. set a breakpoint at the end of those
;* instructions.
;*
;* d. start emulation
;*
;* e. read the SUPER8 register after the break
;* occurs to verify execution.
;;*
;**********************************************************;
CLR ERR_CODE
CALL HOST_DELAY ; Wait for Host to catch up
CALL SEND_STX
LDW RR6,#TEST_MSG ; test message
CALL OUTMSG
CALL SEND_ETX
CALL HOST_DELAY ; Wait for host to catch up
CALL SEND_STX ; start message
CALL MON_RAM_TEST ; test monitor RAM
CP ERR_CODE,#$FF ; RAM test error ?
JR EQ,TEST_ICODE ; yes
LDW RR6,#RAM_OK_STR ; print RAM_OK message
CALL OUTMSG
CALL SEND_ETX ; end message
CALL HOST_DELAY ; Wait for host to catch up
TEST_ICODE
CLR ERR_CODE
RET
MON_RAM_TEST
;********************************************************
;*
;* MON_RAM_TEST Test monitor RAM with 1's and 0's
;* to all locations.
;*
;* Performs a non-destructive read/write test
;*********************************************************;
push r3
push r4
push r5
push r12
push r13
; First check if we have a 8K or 32K RAM out there
ld r4,#$AA ; Load test pattern
ld r12,#$80 ; Point to
ld r13,#$00 ; test location
ldc r3,@rr12 ; Save byte thats there
ldc @rr12,r4 ; Write test pattern to RAM
ldc r5,@rr12 ; Read back test pattern
ldc @rr12,r3 ; Restore byte that was there
cp r4,r5 ; Compare value read with test pattern
jr ne,RAM_8K ; If not equal must be 8K RAM
; Print test message
ld r6,#^HB RAM_MESS1
ld r7,#^LB RAM_MESS1
call OUTMSG
; Write a 1 to all locations for 32K RAM
LD R12,#$80 ; high byte of start address
LD R14,#$F0 ; high byte of end address
LD R15,#$FF ; write all 1's
CALL MEM_WRITE_READ
; Now write a 0 to all locations for 32K RAM
LD R12,#$80 ; high byte of start address
LD R14,#$F0 ; high byte of end address
LD R15,#$00 ; write all 0's
CALL MEM_WRITE_READ
jr RAM_EXIT
; Print test message
RAM_8K: ldw rr6,#RAM_MESS2
call OUTMSG
; Write a 1 to all locations for 8K RAM
LD R12,#$E0 ; high byte of start address
LD R14,#$F0 ; high byte of end address
LD R15,#$FF ; write all 1's
CALL MEM_WRITE_READ
; Now write a 0 to all locations for 8K RAM
LD R12,#$E0 ; high byte of start address
LD R14,#$F0 ; high byte of end address
LD R15,#$00 ; write all 0's
CALL MEM_WRITE_READ
RAM_EXIT:
pop r13
pop r12
pop r5
pop r4
pop r3
RET
MEM_WRITE_READ
;*************************************************
;*
;* Write a value to memory on the SUPER8 EM
;* board and read it back.
;* If error, print out message. Repeat for
;* specified range of memory.
;*
;* input: R12 -- hi byte of starting address
;* R14 -- hi byte of end address + 1
;* R15 -- data to be written and read
;*
;* Performs a non-destructive read/write test
;*************************************************;
PUSH R3 ; save used registers
PUSH R4
PUSH R5
PUSH R6
PUSH R7
PUSH R10
PUSH R11
PUSH R15
CLR R13
; main write - read loop
WRITE_READ_LOOP
LDC R3,@RR12 ; save value at location
; to be tested
LDC @RR12,R15 ; write data in R15
LDC R5,@RR12 ; read it back into R5
LDC @RR12,R3 ; restore original value
CP D_MEMFLAG,#0 ; is it BREAK memory?
JR EQ,NOT_BREAK ; no
AND R5,#$01 ; yes, only LSB is valid
NOT_BREAK
CP R5,R15 ; are values and equal ?
JR NE,NOT_EQUAL
NEXT_LOC
INCW RR12 ; inc. mem pointer
CP R12,R14 ; are we through?
JR ULT,WRITE_READ_LOOP ; no
JR DONE_WRITE_READ ; yes
NOT_EQUAL
PUSH R5 ; save data values
PUSH R15
LD R4,#$10
CALL DELAY
LDW RR6,#RAM_ERROR ; 'RAM FAILURE AT '
CALL OUTSTR
LD R4,#$10
CALL DELAY
LD R10,R12 ; put bad address in
LD R11,R13 ; RR10 for OUTADDR
CALL OUTADDR ; <ADDRESS>
LD R4,#$10
CALL DELAY
LD R6,#^HB WROTE_STR ; ' WROTE '
LD R7,#^LB WROTE_STR
CALL OUTSTR
LD R4,#$10
CALL DELAY
POP R15 ; <write value>
LD R4,R15
CALL OUTDAT
LD R4,#$10
CALL DELAY
LD R6,#^HB READ_STR ; ' READ '
LD R7,#^LB READ_STR
CALL OUTSTR
LD R4,#$10
CALL DELAY
POP R5
LD R4,R5 ; <read value>
CALL OUTDAT
LD R4,#$10
CALL DELAY
LD ERR_CODE,#$FF ; set error flag
CALL CRLF
; exit after first error
DONE_WRITE_READ
POP R15 ; restore used registers
POP R11
POP R10
POP R7
POP R6
POP R5
POP R4
POP R3
RET
QUIT
;****************************************************
;*
;* QUIT Send message to host to quit to MSDOS.
;*
;* SYNTAX: Q
;*
;****************************************************;
CP ECHO_MODE,#ECHO_ON ; are we echoing?
JR NE,SEND_QUIT ; no, send quit msg
; we are echoing, don't send message and flag error
LD ERR_CODE,#BAD_CMD ; bad command
RET
; send quit message: "<STX> Q <ETX>"
SEND_QUIT
CALL SEND_STX ; STX
LD R4,#'Q'
CALL OUTCHR ; 'Q'
CALL SEND_ETX ; ETX
RET
TEST_MSG .ascii 'Executing SELF TEST...\r'
RAM_MESS1 .ascii 'Testing 32K RAM at location 8000 - FFFF\r'
RAM_MESS2 .ascii 'Testing 8K RAM at location E000 - FFFF\r'
RAM_ERROR .ascii 'RAM Failure at \r'
WROTE_STR .ascii ' wrote \r'
READ_STR .ascii ' read \r'
RAM_OK_STR .ascii 'RAM test OK\r'
; mnemonic PC and register header for first row of system regs
SYS1_H_REG .ascii 'PC P0 P1 P2 P3 P4 FLAGS RP0\r'
; register numbers for first row of system regs
SYS1_N_REG .ascii ' rD0 rD1 rD2 rD3 rD4 rD5 rD6\r'
; mnemonic register header for second row of system regs
SYS2_H_REG .ascii 'RP1 SPH SPL IPH IPL IRQ IMR SYM\r'
; register numbers for second row of system regs
SYS2_N_REG .ascii 'rD7 rD8 rD9 rDA rDB rDC rDD rDE\r'
; mnemonic register header for first row of control/mode regs
CTL1_H_REG .ascii 'C0CT C1CT C0CH C0CL C1CH C1CL UTC URC UIE UIO P0M\r'
; register numbers for first row of control/mode regs
CTL1_N_REG .ascii 'rE0/0 rE1/0 rE2/0 rE3/0 rE4/0 rE5/0 rEB/0 rEC/0 rED/0 rEF/0 rF0/0\r'
; mnemonic register header for second row of control/mode regs
CTL2_H_REG .ascii 'P4D P4OD P2AIP P2BIP EMT IPR C0M C1M C0CTH C0CTL\r'
; register numbers for second row of control/mode regs
CTL2_N_REG .ascii 'rF6/0 rF7/0 rFC/0 rFD/0 rFE/0 rFF/0 rE0/1 rE1/1 rE2/1 rE3/1\r'
; mnemonic register header for third row of control/mode regs
CTL3_H_REG .ascii 'C1TCH C1TCL DCH DCL UBGH UBGL UMA UMB WUMCH WUMSK\r'
; register numbers for third row of control/mode regs
CTL3_N_REG .ascii 'rE4/1 rE5/1 rF0/1 rF1/1 rF8/1 rF9/1 rFA/1 rFB/1 rFE/1 rFF/1\r'
; register numbers for fourth row of control/mode regs
CTL4_N_REG .ascii 'rC0 rC1 rC2 rC3 rC4 rC5 rC6 rC7 rC8 rC9 rCA rCB rCC rCD rCE rCF\r'
; map of bank 0 control/mode registers:
; read/write(RW), write only(WO), read only(RO), unimplemented(UI)
BANK_0_TAB:
; E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
db RW, RW, RW, RW, RW, RW, UI, UI, UI, UI, UI, RW, RW, RW, UI, RW
; F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
db RW, WO, UI, UI, WO, WO, RW, RW, WO, WO, WO, WO, RW, RW, RW, RW
; map of bank 1 control/mode registers:
; read/write(RW), write only(WO), read only(RO), unimplemented(UI)
BANK_1_TAB:
; E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
db RW, RW, RW, RW, RW, RW, UI, UI, UI, UI, UI, UI, UI, UI, UI, UI
; F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
db RW, RW, UI, UI, UI, UI, UI, UI, RW, RW, RW, RW, UI, UI, RW, RW
; general register display header
GEN_REG_H .ascii ' x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF\r'
;************************************************
;*
;* load.s : Download and Upload functions
;*
;************************************************;
;*
;* Constants and register usage used by
;* all or some of the software modules.
;*
;******************************************************;
; register allocation
LOAD
;**************************************************
;*
;* LOAD Download a program
;*
;* syntax L [-E] <filename>
;*
;****************************************************;
LD SIO_MODE,#LOAD_MODE ; load input mode
CALL FINDOPT ; look for an option
CP R10,#0 ; an option?
JR EQ,LOADUP ; no
CP R10,'e' ; yes, is it an 'e'?
JR EQ,E_OPTION ; yes
LD ERR_CODE,#BAD_OPT ; no, bad option
LD SIO_MODE,#NORMAL_MODE
RET
E_OPTION:
LD SIO_MODE,#EXT_MODE
LOADUP:
OR SIO_MODE,#LOAD_MODE
CALL LODCMD ; do the load
LD SIO_MODE,#NORMAL_MODE
RET
UPLOAD
;***************************************************
;*
;* UPLOAD Upload a program image
;*
;* syntax U <FILENAME> <ADDRESS> <N>
;*
;*****************************************************;
LD SIO_MODE,#LOAD_MODE
CALL SEND ; send the records
LD SIO_MODE,#NORMAL_MODE
RET
LODCMD
;**************************************************
;*
;* load command expects records of data (ascii chars)
;* in the following tek hhex format:
;* <address(4)> <count(2)> <cksum1(2)> <data(2)> <data(2)>
;* <data(2)> ... <data(2)> <cksum2(2)>
;*
;* the two checksum values are verified before the data
;* is stored in memory (specified by <address>)
;* <cksum1> is the checksum for <address> & <count>
;* <cksum2> is the checksum for the data portion
;*
;* if the record is recieved with <count> = 0, this is
;* the end of the load data
;*
;* after each data record is recieved, either and acknowledge
;* (ascii 0 followed by cr) or a non-acknowledge (ascii 7
;* followed by a cr) will be sent.
;*
;* if the recieved record begins with //, the character string
;* will be sent instead to the terminal and the command aborted.
;*
;*************************************************************;
; send command to host to download file
GOTFILE:
OR CFLAG,#LOAD_SEND ; set bit for load
;***** JR NZ,NXXTR ***** all ok
;***** RET ***** ret z
NXXTR:
CALL LODREC ; fetch record in CONIBF
LD R6,#^HB CONIBF ;
CLR R7 ; pointing to CONIBF with RR6
LDC R0,@RR6 ; check for error (//)
CP R0,#'/' ;
JR NZ,RECOK ; the record is ok
OR CFLAG,#LOADABORT ; send error message
RET ; and forget characters
RECOK:
CALL REKCKS ; verify checksums
JR NC,LODOK ; good checksums
CALL BADCKS ; bad checksums send non-ack
JR NXXTR ; try again
; check if this is the last record (count = 0)
LODOK:
CP R5,#$00 ; data count in R5
JR NZ,STRED ; not 0, put data into memory
CALL GODCKS ; send acknowledge
RET ; back to main
STRED:
CALL GODCKS ; send acknowledge
CALL STREC ; store data in memory
JR NXXTR ; get next record
SEND
;***************************************************************
;*
;* send transfers data in memory to host system.
;* all data is converted to ascii characters before
;* they are sent. maximum is 30 bytes of data in one
;* record in the following format:
;*
;* /<address> <count> <cksum1> <data> <data> ... <data>
;* <cksum2> cr
;* where
;* <address> - the address of the first byte of data
;* <count> - # bytes of data in that record
;* <cksum1> - cksum of <address> & <count>
;* <data> - data byte of specified memory
;* <cksum2> - checksum of the data bytes
;*
;* after all data is sent, a record in the following format will
;* be sent at the end:
;*
;* /<entry address> 00 <cksum> cr
;* where cksum is the checksum of <entry address>
;*
;* send command will retry 10 times if a non-acknowledge is received.
;* then it will send //error cr to abort command.
;*
;*
;***************************************************************;
; reset host input buffer pointer, insure filename exists
CALL CKFNAM
JR Z,SENDER ; no parameter, filename
PUSH INPTR ; save pointer at filename
CALL GETADDR ; get start address
JR C,SENDER_POP ; error, send message
LD R14,R10 ; save start address
LD R15,R11 ; in RR12
CALL GETADDR ; get length
JR C,SENDER_POP ; error, send message
LD R8,R10 ; save length
LD R9,R11 ; in RR8
POP INPTR ; pointer at filename
AND CFLAG,#^C LOAD_SEND ; for send process
JR OPOK
; send command to host upload data
;**** JR NZ,OPOK **** send was loaded
SENDER:
RET ; not loaded
SENDER_POP:
POP INPTR ; syntax error,must
RET ; pop ptr to filename
OPOK:
NXTR:
LD RETRY,#10 ; retry 10 times max
CP R8,#$00 ; see if length < 30
JR NE,SET30 ; not if R8 > 0
CP R9,#30 ; check lower byte
JR NC,SET30 ; send 30
LD R0,R9 ; use R9 for count
CLR R9 ; clear the count to 0
JR COTT ;
SET30:
LD R0,#30 ; send 30 bytes each time
RCF ; clear carry for 2 reg sub
SUB R9,#30 ; RR8 has length,must sub 30
SBC R8,#$00 ; only subtract carry from R8
COTT:
LD R11,R0 ; save count for possible resend
; format address, checksum & data in record &
; send to host ;
RESEND:
; delay so that host can set up
PUSH R3
PUSH R4
LD R3,#$04
REC_DELAY:
LD R4,#$FF
CALL DELAY
DJNZ R3,REC_DELAY
POP R4
POP R3
CALL RECSND ; send data record to host
JR Z,LREC ; was last record
CALL WATACK ;
JR NZ,RECE79 ; got a 7 or 9 from host
JR NXTR ; z means ok, sendnext record
RECE79:
JR C,ABTS ; '9' means abort
; recieve non-acknowledge, resend same record
SUB R15,R11 ; set back address
SBC R14,#$00 ;
LD R0,R11 ; get back count
DEC RETRY ; 1 of 10 chances
JR Z,SNDABT ; that was last chance
JR RESEND ;
; send last record /<entry addr> 00 <cksum> cr
LREC:
CALL LASREC ; send last record
CALL WATACK ; wait for acknowledge
JR NZ,C2 ; not done
RET ; done
C2: JR NC,RESD ; nz,nc recieve 7,resend
ABTS: OR CFLAG,#ABSEND ; 9 is file error
RET ;
; got a '7', so send same data if not the 10th time
RESD: DEC RETRY ; try counter
JR NZ,RESEND ;
SNDABT:
CALL SNDERR ; format an error record for host
OR CFLAG,#ABSEND ; abort
RET ; with an error message
RECSND
;*********************************************************
;*
;* recsnd formats address, count, checksums & data in
;* tektronix format. it sends the data to the host
;* system or the terminal.
;* if the count = 0, just store '/' in buffer & don't
;* format the data
;*
;* input: R0 has count, RR12 has start address
;* output: RR14 increased by count (R0)
;* return z for last record
;* return nz when record is sent and
;* ready for acknowledge.
;*
;************************************************************;
LD R6,#^HB CONOBF ; pt to output buffer
CLR R7 ; with RR0
LD R4,#'/' ; first character
LDC @RR6,R4 ;
INCW RR6 ;
CP R0,#$00 ; any data ?
JR NE,SENDDATA ; yes
RET ; no data
SENDDATA:
CLR R3 ; checksum accumualtor
LD R5,R14 ; format address
CALL PUT1 ; and put into buffer
LD R5,R15 ;
CALL PUT1 ;
LD R5,R0 ; and count
CALL PUT1 ;
LD R5,R3 ; then checksum1
CALL PUT1 ;
; format <data> <data> ... <data> <checksum2>
CLR R3 ; clear checksum accumulator
MDATA:
PUSH R8
PUSH R9
PUSH R14 ; hi addr
PUSH R15 ; lo addr
LD R8,R14
LD R9,R15
CALL GETMEM ; lde R5,@RR14
LD R5,R15 ; data
POP R15 ;
POP R14 ;
POP R9 ;
POP R8 ;
CALL PUT1 ; add to checksum
INCW RR14 ; next data byte
DJNZ R0,MDATA ; until all data converted
LD R5,R3 ; and checksum
CALL PUT1 ;
LD R4,#ASCIILF ; end with a <LF>
LDC @RR6,R4 ;
INC R7 ; send <LF> also
LD OUTLEN,R7 ; into outlen
CALL OTMSG ; to send to host
INC R6 ; reset z flag
RET ;
LASREC
;*******************************************************
;* lasrec formats entry address with 0 count and
;* checksum in tektronix format for the last record
;* and sends it to the host
;*
;* input RR10 is entry address
;*
;*******************************************************;
CLR R3 ; clear accumulator
LD R5,#$00 ; address
CALL PUT1 ; put into buffer
LD R5,#$0C ; low byte
CALL PUT1 ;
CLR R5 ; 0 byte count
CALL PUT1 ;
LD R5,R3 ; the checksum
CALL PUT1 ;
LD R4,#ASCIILF ; read ascii on host side
LDC @RR6,R4 ;
INC R7 ; send <LF> also
LD OUTLEN,R7 ; into outlen
CALL OTMSG ; output to host
RET
PUT1
;*******************************************************
;* add each nibble of R5 to the checksum accumulator R3
;* convert contents of R5 to 2 ascii characters
;* enter characters into buffer pointed to by RR6
;* RR6 gets incremented in 'nibble'
;********************************************************;
LD R4,R5 ; do high byte first
SWAP R4 ;
AND R4,#$0F ; isolate nibble
ADD R3,R4 ; checksum
CALL NOOBLE ; puts it into buffer
; increments pointer ;
LD R4,R5 ; low nibble
AND R4,#$0F ; isolate nibble
ADD R3,R4 ; checksum
CALL NOOBLE ; into buffer
RET ;
NOOBLE
;***********************************************************
;*
;* convert hex to ASCII and put into memory @RR6
;*
;* input: R4 has hex value in lower nibble
;*
;************************************************************;
and R4,#$0F ; isolate lower nibble
add r4,#$90
da r4
adc r4,#$40
da r4
LDC @RR6,R4 ; put into buffer
inc r7 ; point to next location
ret
CKFNAM
;**************************************************************
;*
;* ckfname resets two pointers of the ram buffer before
;* starting the upload/download procedure. also checks
;* that the filename is included in the command.
;*
;* z flag on => no filename
;* z flag off => filename present
;*
;**************************************************************;
CLR HOSTGET ; these are offsets
CLR HOSTPUT ; not pointers
CALL FINDNEXT ; get the filename
JR NZ,GOTIT ; filename present
OR CFLAG,#$02 ; missing filename
GOTIT:
RET ; there is a filename
LODREC
;************************************************************
;*
;* lodrec reads in an input line into conibf from the host
;* and starts storing data once a '/' is recieved.
;* the input line is terminated by a carriage return.
;* it will read in a maximum of 80 characters (ascii)
;* and ignore the rest until a carriage return is recieved.
;* all control characters are skipped ( <20h)
;*
;* output: data in conibf
;***********************************************************;
CALL HOSTINP ; get the character
CP R4,#'/' ; wait for '/'
JR NZ,LODREC ;
LD R2,#^HB CONIBF ; start at beginning of conibf
CLR R3 ; use RR6
LD R8,#80 ; maximum character count
; start storing characters , ignore control characters
; also check for carriage return for end of record ;
LODRC0:
CALL HOSTINP ; get next character
LDC @RR2,R4 ; put into conibf
CP R4,#ASCIICR ; end of record?
JR EQ,DONE_LODREC
CP R4,#ASCIILF ; end of record?
JR EQ,DONE_LODREC
CKCT:
CP R4,#ASCIISP ; ignore control characters
JR C,LODRC0 ; was a control char
INCW RR2 ; increment pointer
DJNZ R8,LODRC0 ; next character
; have received 80 characters, skip over all characters
; until carriage return ;
LODRC2:
CALL HOSTINP ; ignore all but <CR>
CP R4,#ASCIICR ;
JR EQ,TERM_REC
CP R4,#ASCIILF ; and <LF>
JR EQ,TERM_REC
JR LODRC2 ;
TERM_REC:
LD R3,#80 ; put terminator here
LDC @RR2,R4 ; get <CR> into buffer
; returns z flag on
DONE_LODREC:
RET
REKCKS
;************************************************************
;*
;* rekcks verifies two checksums values in a record
;* stored in conibf. all ascii characters in conibf are
;* converted to 4-bit hex value to obtain checksum
;* which is the sum of all these 4 bit hex values.
;*
;* the format of the record is as follows:
;* <address(4)> <count(2)> <cksum1(2)> <data(2)>
;* ... <data(2)> <cksum2(2)> <CR>
;*
;* input: record in conibf
;* RR6 pointing to conibf
;*
;* output: R5 has count in byte value
;*
;* return c if checksum bad
;* return c if non-ascii found in conibf
;* return nc if ok
;*
;*************************************************************;
LD R5,#$03 ; chksum is for 3 pairs
CALL CHKCKS ; verify first checksum
JR C,REKCKS_END ; bad checksum
CP R5,#$00 ; this is the count
JR Z,REKCKS_END ; no data if count 0
PUSH R5 ; save count
CALL CHKCKS ; verify second check sum
POP R5 ; get count back
REKCKS_END:
RET ; all exits here
CHKCKS
;************************************************************
;*
;* chkcks verifies the checksum in the record. converts
;* each ascii character in the record to the hex value
;* and accumulates their values to obtain the checksum.
;* the checksum is then compared with the check sum in the
;* record following the character string. all characters
;* including the checksum are ascii characters
;*
;* input: RR6 pointer to the ascii string
;* R5 # of char pairs in this chksum calculation
;*
;* output: R5 count value of the record
;* R2 calculated checksum
;* R4 checksum in the record
;*
;* return c if cksum bad
;* return c if found non-ascii character
;* return nc if chksum is correct
;*
;***********************************************************;
; init cksum accumulator (R2), convert the
; next pair of characters to hex and sum their
;hex values. ;
CLR R2 ; checksum accumulator
CHKSM2:
CALL LODBYL ; convert next two characters
; to hex & add to chksm accum
JR C,CHKCKS_END ; bad ascii
DJNZ R5,CHKSM2 ; R3 is number of pairs
; save 8 bit hex value of last two characters
;(count of the data in the record). save calculated
;cksum then convert next two chars to get chksm in
;the record and compare the two chksum ;
LD R5,R4 ; get count into R5
PUSH R5 ; save count
PUSH R2 ; and checksum
CALL LODBYL ; convert next two characters
POP R2 ; get record checksum in R4
POP R5 ;
JR C,CHKCKS_END ; bad ascii
CP R4,R2 ; return nc if match
JR Z,CHKCKS_END ;
SCF ; return carry if no match
CHKCKS_END:
RET ; common exit
LODBYL
;*********************************************************
;*
;* convert two ascii characters to two 4-bit hex
;* and add the two hex values to an accumulator
;*
;* input: RR6 points to first ascii character
;* R2 is the accumulator
;*
;* output: RR6 updated
;* R2 updated
;* R4 8 bit hex result of conversion
;*
;* return c if any characters non-ascii
;* return nc if ok
;*
;********************************************************;
CALL HEXDCD ; convert char ptd by RR6
JR C,LODBYL_END ; bad ascii
ADD R2,R4 ; add to accumulator
LD R1,R4 ; save value in R1
SWAP R1 ; put in upper nibble
CALL HEXDCD ; convert next 4 bits
JR C,LODBYL_END ; common exit
ADD R2,R4 ; add to accumulator
OR R4,R1 ; 8 bit value in R4
RCF ; reset carry
LODBYL_END:
RET ; common exit
HEXDCD
;********************************************************
;*
;* convert ascii character pointed to by RR6 to
;* the 4 bit hex value. increment RR6 by one.
;*
;* input: RR6 pointer to ascii character
;*
;* output: RR6 advanced by one
;* R4 4-bit value of ascii char
;*
;* return c if character is non-ascii
;* return nc if ok
;*
;******************************************************;
LDC R4,@RR6 ; get the character
INCW RR6 ;
JP CONVERT ; convert to hex
STREC
;**********************************************************
;*
;* strec unpacks data in record & stores them into
;* memory location specified by address in record
;*
;* input: record in conibf
;* R5 # of bytes of data in record
;*
;************************************************************;
LD R8,R5 ; use R8 to count down data
; convert <address> & <count> to hex value.
;store byte data in memory. the number of bytes
;is specified by <count> ;
CALL RECADR ; calculate record address
LD R7,#$08 ; skip count and checksum
LODFR3:
CALL LODBYL ; convert next two char
PUSH R4 ;
PUSH R8 ;
PUSH R9 ;
PUSH R14 ;
PUSH R15 ;
LD R8,R14 ; save address
LD R9,R15
LD R15,R4 ; save data
TM SIO_MODE,#EXT_MODE ; extension load?
JR Z,NO_EXT ; no
CALL PUTEXT ; yes, store it
JR CLEAN_UP
NO_EXT:
CALL PUTMEM ; lde @RR8,R15
CLEAN_UP:
POP R15 ;
POP R14 ;
POP R9 ;
POP R8 ;
POP R4 ;
INCW RR14 ; increment memory pointer
DJNZ R8,LODFR3 ; next byte
RET ; done
RECADR
;***********************************************************
;*
;* convert the starting address in load record to
;* the hex value and put into RR0
;*
;***********************************************************;
LD R6,#^HB CONIBF ; point to begin of rec
CLR R7 ;
CALL LODBYL ; get first byte of address
LD R14,R4 ;
CALL LODBYL ; get lo byte of address
LD R15,R4 ;
RET ; got it
BADCKS
;************************************************************
;*
;* badcks sends non-acknowledge (ascii 7 (37h) & <CR> )
;* for receiving a non-ascii character or if the checksum
;* is incorrect.
;*
;* godcks sends an acknowledge (ascii 0 (30h) & <CR> ) for
;* valid record of data
;*
;*************************************************************;
LD R4,#'7' ; output to host
JR MSEND ;
GODCKS:
LD R4,#'0' ; output to host
MSEND:
; delay so that host has time to set up
PUSH R4
LD R4,#$80
CALL DELAY
POP R4
CALL OUTCHR ; output
; delay so that host has time to set up
LD R4,#$80
CALL DELAY
LD R4,#ASCIICR ; read ascii of rio
CALL OUTCHR ;
RET ;
WATACK
;**************************************************************
;* expects either acknowledge (ascii 0) or non-acknowledge
;* (ascii 7) from serial line. ignore other characters
;*
;* good-ack from host returns z, nc
;* non-ack from host returns nz,nc
;* abort-ack from host returns nz,c
;*
;***************************************************************;
CALL MCHAR ; get character
CP R4,#'0' ; good ack?
JR NZ,CK79 ; check for 7 or 9
CALL SKIP_EOL ; skip to end of line
RCF ; reset carry flag
XOR R4,R4 ; set z flag
JR END_ACK ; z,nc is good ack
CK79:
CP R4,#'7' ; check for non-ack
JR NZ,CK9 ; no
CALL SKIP_EOL ; skip to end of line
INC R4 ; reset the z flag
RCF ; reset the carry flag
JR END_ACK ; nz,nc is non-ack
CK9:
CP R4,#'9' ; check for abort acknowledge
JR Z,MATC ; yes
CALL HOSTINP ; advance pointer to get next
JR WATACK ; ignore character
MATC:
CALL SKIP_EOL ; skip to end of line
INC R4 ; reset the z flag
SCF ; set carry flag
END_ACK:
RET ; return nz,c for abort
SNDERR
;***********************************************************
;*
;* formats an error record to send to host
;*
;* error record is '//<CR>'
;*
;* this is an abort initiated by the 'send' command
;*
;* because of too many checksum errors detected by
;*
;* the host system on a single record
;*
;**********************************************************;
LD R6,#^HB CONIBF ; point to record buffer
CLR R7 ;
LD R4,#'/' ; put two '/'s in the buffer
LDC @RR6,R4 ;
INCW RR6 ;
LDC @RR6,R4 ;
INCW RR6 ;
LD R4,#ASCIICR ; and follow with a <CR>
LDC @RR6,R4 ;
INC R7 ; get count
LD OUTLEN,R7 ; and send over serial
JP OTMSG ; channel to host
SKIP_EOL
;************************************************************
;*
;* skip over input line until <CR> is recieved from host.
;*
;*************************************************************;
CALL HOSTINP ; input from the host
CP R4,#ASCIICR ; until <CR>
JR NE,SKIP_EOL ;
RET
HOSTINP
;************************************************************
;*
;* gets a character from the host input interrupt buffer.
;* if no character is in the buffer, it waits...
;*
;* hostput updated to point to next character
;* character returned in R4
;*
;*************************************************************;
CALL MCHAR ;
INC HOSTPUT ;
RET ;
MCHAR
;***********************************************************
;*
;* same as hostinp except don't update pointer
;*
;***********************************************************;
CP HOSTGET,HOSTPUT ; got a character
JR EQ,MCHAR ;
PUSH R6 ;
PUSH R7 ;
LD R6,#^HB HOSTBUF ; get full pointer
LD R7,HOSTPUT ;
LDC R4,@RR6 ;
POP R7 ;
POP R6 ;
RET ;
;********************************************************
;*
;* dasm.s : Super8 disassembler
;*
;* This version doctored for the META assembler
;*
;*********************************************************;
ONE_BYTE: equ $00 ; one-byte inst.
TWO_BYTES: equ $20 ; two-byte inst.
THREE_BYTES: equ $40 ; three-byte inst.
FOUR_BYTES: equ $60 ; four-byte inst.
HI_BIT: equ $80 ; most sig. bit
ONE_M: equ $00+$80 ; one-byte inst.
TWO_M: equ $20+$80 ; two-byte inst.
THREE_M: equ $40+$80 ; three-byte inst.
FOUR_M: equ $60+$80 ; four-byte inst.
COMMA: equ $2C ; ASCII comma
VARY_MNE: equ $00 ; var. mnemonics glag
AD_TYPE_0: equ $00 ; address mode types
AD_TYPE_1: equ $01
AD_TYPE_2: equ $02
AD_TYPE_3: equ $03
AD_TYPE_4: equ $04
AD_TYPE_5: equ $05
AD_TYPE_6: equ $06
AD_TYPE_7: equ $07
AD_TYPE_8: equ $08
AD_TYPE_9: equ $09
AD_TYPE_A: equ $0A
AD_TYPE_B: equ $0B
AD_TYPE_C: equ $0C
AD_TYPE_D: equ $0D
AD_TYPE_E: equ $0E
AD_TYPE_F: equ $0F
AD_TYPE_10: equ $10
AD_TYPE_11: equ $11
AD_TYPE_12: equ $12
AD_TYPE_13: equ $13
AD_TYPE_14: equ $14
AD_TYPE_15: equ $15
AD_TYPE_16: equ $16
AD_TYPE_17: equ $17
AD_TYPE_18: equ $18
AD_TYPE_19: equ $19
AD_TYPE_1A: equ $1A
AD_TYPE_1B: equ $1B
AD_TYPE_1C: equ $1C
DIS_ASM
;**********************************************************
;*
;* ZAP disassemble SUPER8 instructions
;*
;* syntax Z <address> [<n>]
;*
;* defaults <n> = 1
;*
;* Disassemble <n> instructions starting at <address>
;* Maximum value for <n> = $FF
;*
;* input: AD_IN_HI,AD_IN_LO point to memory location to be
;* disassembled.
;* AD_OUT_HI,AD_OUT_LO point to output buffer
;*
;* output: The output buffer is filled with the disassembled
;* instruction.
;*
;**************************************************************;
PUSH R0 ; save all regs
PUSH R1 ; except R6,R7
PUSH R2
PUSH R3
PUSH R4
PUSH R5
PUSH R8
PUSH R9
PUSH R10
PUSH R11
PUSH R12
PUSH R13
PUSH R14
PUSH R15
; write output buffer with 70 spaces
LD R10,#BUF_LGTH ; loop of 70
LD R11,#' ' ; ASCII space
LD R12,AD_OUT_HI ; output buffer
LD R13,AD_OUT_LO ; address
LP1A:
LDC @RR12,R11 ; write one space
INCW RR12 ; points to next
DJNZ R10,LP1A ; loop 80. times
LD R11,#$0D ; carrage return
LDC @RR12,R11 ; output
; initialize output buffer pointer
LD R2,AD_OUT_HI ; output buffer
LD R3,AD_OUT_LO ; address
; initialize memory pointer
LD R0,AD_IN_HI ; memory address
LD R1,AD_IN_LO ;
; tab in 4 spaces before writing
LD R15,#$04 ; tab 4 spaces
CALL TAB_SP
; write address in output buffer
LD R10,AD_IN_HI ; first hi addr
CALL HEX_ASCII ; inti buffer
LD R10,AD_IN_LO ; then lo addr
CALL HEX_ASCII ; into buffer
LD R15,#$04 ; tab 4 spaces
CALL TAB_SP
; get opcode and write first byte in out buf
CALL RD_MEM ; read first byte into R10
INCW RR0 ; point to next
LD R12,R10 ; save opcode
LD BYTE_1,R10 ; save first byte
CALL HEX_ASCII ; write out buffer
; find table entry that = hex mnemonic
LD R4,#^HB OP_TAB ; get starting
LD R5,#^LB OP_TAB ; addr of table
LDC R10,@RR4 ; read first control
AGN3:
CP R12,#$00 ; there yet ?
JR Z,DONE1 ; if zero yes
AGN2: INCW RR4 ; find next
LDC R10,@RR4 ; control byte
TM R10,#$80 ; bit 7 set
JR Z,AGN2 ; loop 2 till
DEC R12 ; bit 7 set
JR AGN3 ;test for zero
DONE1:
LD R8,R10 ; save control in R8
; get type of instruction from control byte
LD R11,R8 ; save control
AND R11,#$1F ;isolate least sig. 5 bits
LD TYPE_,R11 ; save in type_
; test for quantity of bytes in instruction
; encoded as (n - 1) in bits 5 and 6 of control byte
LD R9,R8 ; save size in R9
AND R9,#FOUR_BYTES ;isolate bits 5,6
CP R9,#ONE_BYTE ; test for one byte
JR NZ, BY_2 ; no - at least two
; one byte instruction -- pad with spaces
LD R15,#$12 ; tab 18. spaces
CALL TAB_SP
JR MNE ; ASCII mnemonic
BY_2:
INCW RR2 ; tab two spaces
INCW RR2
CALL RD_MEM ; read second byte
INCW RR0 ; point to third
LD BYTE_2,R10 ; save byte 2
CALL HEX_ASCII ; write to buffer
CP R9,#TWO_BYTES ; test for two bytes
JR NZ, BY_3 ; no - at least three
; two byte instruction -- pad with spaces
LD R15,#$0E ; tab 14. spaces
CALL TAB_SP
JR MNE ; ASCII mnemonic
BY_3:
INCW RR2 ; tab two spaces
INCW RR2
CALL RD_MEM ; read third byte
INCW RR0 ; point to fourth
LD BYTE_3,R10 ; save byte 3
CALL HEX_ASCII ; write to buffer
CP R9,#THREE_BYTES ; test for three bytes
JR NZ, BY_4 ; no - four bytes
; three byte instruction -- pad with spaces
LD R15,#$0A ; tab 10. spaces
CALL TAB_SP
JR MNE ; ASCII mnemonic
BY_4:
INCW RR2 ; tab two spaces
INCW RR2
CALL RD_MEM ; read fourth byte
INCW RR0 ; point to next
LD BYTE_4,R10 ; save byte 4
CALL HEX_ASCII ; write to buffer
LD R15,#$06 ; tab 6. spaces
CALL TAB_SP
; output mnemonic to buffer
MNE:
INCW RR4 ; first ASCII
LD R11,#$09 ; 6 ch +3 spaces
LDC R10,@RR4 ; read letter
LD R8,R10 ; check for varying
TM R8,#$F0 ; mnemonics
JR NZ,AGN4 ; not varying
CALL CHK_MNE ; varies
AGN4: ; letter of mnemonic
LDC R10,@RR4 ; read letter
TM R10,#$80 ; test next byte
JR NZ,SK_SP ; for control byte
LDC @RR2,R10 ; write letter
INCW RR2 ; point next wr
INCW RR4 ; point next rd
DEC R11
JR AGN4 ; do 2 to 6 times
SK_SP:
LD R15,R11 ; add remaining spaces
CALL TAB_SP
; call routine 0 through 15 as function type
CP TYPE_,#AD_TYPE_0
JP EQ, DONE_DASM
CP TYPE_,#AD_TYPE_1
JP EQ, TYPE_01
CP TYPE_,#AD_TYPE_2
JP EQ, TYPE_02
CP TYPE_,#AD_TYPE_3
JP EQ, TYPE_03
CP TYPE_,#AD_TYPE_4
JP EQ,TYPE_04
CP TYPE_,#AD_TYPE_5
JP EQ,TYPE_05
CP TYPE_,#AD_TYPE_6
JP EQ,TYPE_06
CP TYPE_,#AD_TYPE_7
JP EQ,TYPE_07
CP TYPE_,#AD_TYPE_8
JP EQ,TYPE_08
CP TYPE_,#AD_TYPE_9
JP EQ,TYPE_09
CP TYPE_,#AD_TYPE_A
JP EQ,TYPE_0A
CP TYPE_,#AD_TYPE_B
JP EQ,TYPE_0B
CP TYPE_,#AD_TYPE_C
JP EQ,TYPE_0C
CP TYPE_,#AD_TYPE_D
JP EQ,TYPE_0D
CP TYPE_,#AD_TYPE_E
JP EQ,TYPE_0E
CP TYPE_,#AD_TYPE_F
JP EQ,TYPE_0F
CP TYPE_,#AD_TYPE_10
JP EQ,TYPE_10
CP TYPE_,#AD_TYPE_11
JP EQ,TYPE_11
CP TYPE_,#AD_TYPE_12
JP EQ,TYPE_12
CP TYPE_,#AD_TYPE_13
JP EQ,TYPE_13
CP TYPE_,#AD_TYPE_14
JP EQ,TYPE_14
CP TYPE_,#AD_TYPE_15
JP EQ,TYPE_15
CP TYPE_,#AD_TYPE_16
JP EQ,TYPE_16
CP TYPE_,#AD_TYPE_17
JP EQ,TYPE_17
CP TYPE_,#AD_TYPE_18
JP EQ,TYPE_18
CP TYPE_,#AD_TYPE_19
JP EQ,TYPE_19
CP TYPE_,#AD_TYPE_1A
JP EQ,TYPE_1A
CP TYPE_,#AD_TYPE_1B
JP EQ,TYPE_1B
CP TYPE_,#AD_TYPE_1C
JP EQ,TYPE_1C
; common exit point from disassembler
DONE_DASM:
; update memory pointer
LD AD_IN_HI,R0 ; output buffer
LD AD_IN_LO,R1 ; address
POP R15 ; restore all regs
POP R14 ; except R6,R7
POP R13
POP R12
POP R11
POP R10
POP R9
POP R8
POP R5
POP R4
POP R3
POP R2
POP R1
POP R0
RET
TYPE_01
;*******************************************************
;*
;* Process and output operands for addressing mode:
;*
;* opcode r
;*
;*********************************************************;
L_TYPE_01:
LD R8,BYTE_1 ; get reg #
AND R8,#$F0 ; in hi nibble
SWAP R8 ; put in lo nibble
OR R8,#$C0 ; a working reg
CALL WR_REG
JP DONE_DASM ; done
TYPE_02
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode R
;* opcode IR
;*
;***********************************************************;
L_TYPE_02:
; get mode from byte #1
TM BYTE_1,#$01 ; even = direct addr
JR Z,DIR ; odd = indirect add
LD R10,#'@' ; indirect mode
CALL OUT_BUF ; put @ in out buf
DIR:
; test for working reg from byte #2
LD R10,BYTE_2 ; c0 to ef =
AND R10,#$F0
CP R10,#$C0
JR NE,END_EXC ; working regs
LD R10,#'R' ; yes working reg
CALL OUT_BUF
AND BYTE_2,#$0F ; delete c from wr
; two exceptions are 80 and a0 mnenomics
; which are word format not byte
CP BYTE_1,#$80 ; test for inst 80
JR NE,NO_EXC ; test next inst
EXCT:
LD R10,#'R' ; put r in out buf
CALL OUT_BUF
JR END_EXC ; done
NO_EXC:
CP BYTE_1,#$A0 ; test for inst a0
JR NE,END_EXC ; done
JR EXCT ; yes a0 out r
END_EXC:
LD R10,BYTE_2
CALL HEX_D_ASCII ; put reg # in out buf
JP DONE_DASM ; done
TYPE_03
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode IRR
;* opcode IR
;*
;***********************************************************;
L_TYPE_03:
LD R10,#'@' ;put @ in out buffer
CALL OUT_BUF
; test for working regs in byte #2
LD R8,BYTE_2
CALL WR_REG_PAIR
JP DONE_DASM ; done
TYPE_04
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode IM
;*
;***********************************************************;
LD R10,#'#' ; put # in out buffer
CALL OUT_BUF
LD R10,BYTE_2 ; save im value
AND R10,#$FC ; mask bank mode in
; bits 0-1
CALL HEX_D_ASCII
JP DONE_DASM ; done
TYPE_05
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode r,r
;* opcode r,Ir
;*
;***********************************************************;
; write dst operand
LD R8,BYTE_2 ; save dst in R8
SWAP R8 ; put in lo nibble
AND R8,#$0F ; isolate
OR R8,#$C0 ; make working reg
CALL WR_REG ; write it
CALL SEP_OPRNDS
; write src operand
; test for indirect
LD R10,BYTE_1 ; save opcode
TM R10,#$01 ; test: even = direct
JR Z, DIRRECT
; odd = indirect
LD R10,#'@' ; put @ in out buffer
CALL OUT_BUF
DIRRECT:
LD R8,BYTE_2 ; save src in R8
AND R8,#$0F ; isolate
OR R8,#$C0 ; make working reg
CALL WR_REG ; write it
JP DONE_DASM ; done
TYPE_06
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode r,Irr
;* opcode Ir,Ir
;*
;***********************************************************;
; get mode from byte #1
TM BYTE_1,#$10 ; even = direct
JR NZ,IDIR ; odd = indirect
N_OPC:
LD R8,BYTE_2 ; save reg# in high
AND R8,#$F0 ; nibble -- put in
SWAP R8 ; low nibble
OR R8,#$C0 ; a working reg
CALL WR_REG ; write it
CALL SEP_OPRNDS
LD R10,#'@' ;put '@' in out buffer
CALL OUT_BUF
LD R8,BYTE_2 ; save reg# in low
AND R8,#$0F ; nibble
OR R8,#$C0 ; a working reg
CALL WR_REG_PAIR ; write it
JP DONE_DASM ; done
IDIR:
LD R10,#'@' ;put @RR in out buffer
CALL OUT_BUF
LD R8,BYTE_2 ; save reg# in low
AND R8,#$0F ; nibble
OR R8,#$C0 ; a working reg
CALL WR_REG_PAIR ; write it
CALL SEP_OPRNDS
DIR2:
LD R8,BYTE_2 ; save reg# in high
AND R8,#$F0 ; nibble -- put in
SWAP R8 ; low nibble
OR R8,#$C0 ; a working reg
CALL WR_REG ; write it
JP DONE_DASM ; done
TYPE_07
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode r,R
;*
;***********************************************************;
LD R10,BYTE_1 ; opcode x8 or x9
TM R10,#$01
JR NZ,X9_
LD R10,#'R' ; opcode = x8
CALL OUT_BUF ; put r in out buffer
LD R10,BYTE_1 ; put reg# in out buf
AND R10,#$F0
SWAP R10
CALL HEX_D_ASCII
CALL SEP_OPRNDS
LD R8,BYTE_2
CALL WR_REG ; write working reg
JP DONE_DASM ; done
X9_:
; opcode = x9
LD R8,BYTE_2
CALL WR_REG ; write working reg
CALL SEP_OPRNDS
LD R10,#'R' ; put r in out buffer
CALL OUT_BUF
LD R10,BYTE_1 ;put reg# in out buf
AND R10,#$F0
SWAP R10
CALL HEX_D_ASCII
JP DONE_DASM ; done
TYPE_08
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode r,IM
;*
;***********************************************************;
LD R10,#'R' ; put r in out buffer
CALL OUT_BUF
LD R10,BYTE_1 ; put reg# in out buf
AND R10,#$F0
SWAP R10
CALL HEX_D_ASCII
CALL SEP_OPRNDS
LD R10,#'#' ; put # in out buffer
CALL OUT_BUF
LD R10,BYTE_2 ; put reg# in out buf
CALL HEX_D_ASCII
JP DONE_DASM ; done
TYPE_09
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode r,RA
;* opcode cc,RA
;*
;***********************************************************;
LD R10,BYTE_1 ; opcode xa or xb ?
TM R10,#$01
JR NZ,XB_
LD R10,#'R' ; opcode = xa
CALL OUT_BUF ; put r in out buffer
LD R10,BYTE_1 ; put reg# in out buf
AND R10,#$F0
SWAP R10
CALL HEX_D_ASCII
CALL SEP_OPRNDS
JR COMM ; same as opc xb
XB_:
LD R10,BYTE_1 ; get condition code
AND R10,#$F0
SWAP R10
LD R12,#^HB CC_TAB ; cc table addr
LD R13,#^LB CC_TAB
LUPE2:
LDC R11,@RR12 ; read cc table
CP R10,#$00 ; test for done
JR Z,COMP2
LLUP2:
INCW RR12 ; find next table flag
LDC R11,@RR12
TM R11,#$80
JR Z,LLUP2
INCW RR12 ; found flag
DEC R10 ; point to valid data
JR LUPE2
COMP2:
LD R10,R11 ; put cc in out buffer
AGNI2:
CALL OUT_BUF
INCW RR12
LDC R10,@RR12
TM R10,#$80
JR Z,AGNI2
COMM:
LD R10,#$25 ; put $ in out buf
CALL OUT_BUF
CLR R10 ; calculate address
TM BYTE_2,#$80 ; test for minus
JR Z,SKFF
LD R10,#$FF
SKFF:
LD R12,R1 ; lo input addr
ADD R12,BYTE_2 ; add relative addr
JR NC,SKK1
INC R10
SKK1:
ADD R10,R0
CALL HEX_ASCII ;put addr in out buf
LD R10,R12
CALL HEX_ASCII
JP DONE_DASM ; done
TYPE_0A
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode R,R
;* opcode IR,R
;*
;***********************************************************;
LD R8,BYTE_3
CALL WR_REG ; write working reg
CALL SEP_OPRNDS
; test mode from byte #1
LD R10,BYTE_1 ; even = direct
TM R10,#$01 ; odd = indirect
JR Z,DIRR
LD R10,#'@' ; indirect mode
CALL OUT_BUF ; put @ in out buffer
DIRR:
LD R8,BYTE_2
CALL WR_REG ; write working reg
JP DONE_DASM ; done
TYPE_0B
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode R,IM
;* opcode IR,IM
;*
;***********************************************************;
; check for ir,im
LD R10,BYTE_1 ; check for opcode
CP R10,#$D6 ; d6 -- indirect
JR NE,DIRR_
LD R10,#'@' ; indirect mode
CALL OUT_BUF ; put @ in out buffer
DIRR_:
LD R8,BYTE_2
CALL WR_REG ; write working reg
CALL SEP_OPRNDS
LD R10,#'#' ; put # in out buffer
CALL OUT_BUF
LD R10,BYTE_3 ; put reg# in out buf
CALL HEX_D_ASCII
JP DONE_DASM ; done
TYPE_0C
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode R,IR
;*
;***********************************************************;
LD R10,#'@' ; put @ in out buffer
CALL OUT_BUF
LD R8,BYTE_3
CALL WR_REG ; write working reg
CALL SEP_OPRNDS
LD R8,BYTE_2
CALL WR_REG ; write working reg
JP DONE_DASM ; done
TYPE_0D
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode r,x,R
;*
;***********************************************************;
LD R10,BYTE_1 ; test opcode for
CP R10,#$87 ; 87 or 97
JR EQ,OPC_87
LD R10,BYTE_3 ; opcode = 97
CALL HEX_D_ASCII ; put reg# in out buf
LD R10,#$28 ; put (r in out buf
CALL OUT_BUF
LD R10,#'R'
CALL OUT_BUF
LD R10,BYTE_2 ; put reg# in out buf
AND R10,#$0F
CALL HEX_D_ASCII
LD R10,#$29 ; put ) in out buffer
CALL OUT_BUF
CALL SEP_OPRNDS
LD R10,#'R' ; put r in out buffer
CALL OUT_BUF
LD R10,BYTE_2 ; put reg# in out buf
AND R10,#$F0
SWAP R10
CALL HEX_D_ASCII
JP DONE_DASM ; done
OPC_87:
LD R10,#'R' ; put r in out buffer
CALL OUT_BUF
LD R10,BYTE_2 ; put reg# in out buf
AND R10,#$F0
SWAP R10
CALL HEX_D_ASCII
CALL SEP_OPRNDS
LD R10,BYTE_3 ; put reg# in out buf
CALL HEX_D_ASCII
LD R10,#$28 ; put (r in out buf
CALL OUT_BUF
LD R10,#'R'
CALL OUT_BUF
LD R10,BYTE_2 ; put reg# in out buf
AND R10,#$0F
CALL HEX_D_ASCII
LD R10,#$29 ; put ) in out buffer
CALL OUT_BUF
JP DONE_DASM ; done
TYPE_0E
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode cc,DA
;*
;***********************************************************;
LD R10,BYTE_1 ; get condition code
AND R10,#$F0
SWAP R10
LD R12,#^HB CC_TAB ; cc table address
LD R13,#^LB CC_TAB
LUPE1:
LDC R11,@RR12 ; read table
CP R10,#$00
JR Z,COMP1 ; find table entry
LLUP1:
INCW RR12 ; find next table flag
LDC R11,@RR12
TM R11,#$80
JR Z,LLUP1
INCW RR12 ; point to next entry
DEC R10
JR LUPE1
COMP1:
LD R10,R11 ; put cc in out buffer
AGNI1:
CALL OUT_BUF
INCW RR12
LDC R10,@RR12
TM R10,#$80
JR Z,AGNI1
LD R10,#$25 ; put $ in out buffer
CALL OUT_BUF
LD R10,BYTE_2 ; put addr in out buf
CALL HEX_ASCII
LD R10,BYTE_3
CALL HEX_ASCII
JP DONE_DASM ; done
TYPE_0F
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode DA
;*
;***********************************************************;
LD R10,#$25 ; put $ in out buffer
CALL OUT_BUF
LD R10,BYTE_2 ; put addr in out buf
CALL HEX_ASCII
LD R10,BYTE_3
CALL HEX_ASCII
JP DONE_DASM ; done
TYPE_10
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode r,b
;* opcode r,b,R
;*
;***********************************************************;
LD R9,BYTE_2 ; save bit number in R8
RR R9 ; bits 0-2
AND R9,#$07
LD R10,BYTE_2 ; find mode
TM R10,#$01 ; even: dst(0) or src(b)
JR Z,DST0_ ; odd: dst(b) or src(0)
DSTb_: ; write out dst operand
LD R8,BYTE_3
CALL WR_REG ; write working reg
CALL SEP_OPRNDS
; write out bit number
LD R10,#'#' ; put '#' in out buffer
CALL OUT_BUF
LD R10,R9 ; put bit# in out buf
CALL HEX_D_ASCII
CALL SEP_OPRNDS
; write out src operand
LD R8,BYTE_2 ; save reg#
SWAP R8 ; put reg# in lo nibble
AND R8,#$0F ; clear upper nibble
OR R8,#$C0 ; working register
CALL WR_REG ; write src operand
JP DONE_DASM ; done
DST0_: ; write out dst operand
LD R8,BYTE_2 ; save reg#
SWAP R8 ; put reg# in lo nibble
AND R8,#$0F ; clear upper nibble
OR R8,#$C0 ; working register
CALL WR_REG ; write src operand
CALL SEP_OPRNDS
; write out src operand
LD R8,BYTE_3
CALL WR_REG ; write working reg
CALL SEP_OPRNDS
; write out bit number
LD R10,#'#' ; put '#' in out buffer
CALL OUT_BUF
LD R10,R9 ; put bit# in out buf
CALL HEX_D_ASCII
JP DONE_DASM ; done
TYPE_11
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode IR,R
;* opcode R,IR
;*
;***********************************************************;
; check for IR,R
LD R10,BYTE_1 ; save opcode
TM R10,#$10 ; test bit 4
JR Z, IR_R ; even = IR,R
R_IR: ; odd = R,IR
; write dst operand
LD R8,BYTE_3 ; save reg
CALL WR_REG ; write it
CALL SEP_OPRNDS
; write src operand
LD R10,#'@' ; write '@'
CALL OUT_BUF
LD R8,BYTE_2 ; save reg
CALL WR_REG ; write it
JP DONE_DASM ; done
IR_R:
; write dst operand
LD R10,#'@' ; write '@'
CALL OUT_BUF
LD R8,BYTE_2 ; save reg
CALL WR_REG ; write it
CALL SEP_OPRNDS
; write src operand
LD R8,BYTE_3 ; save reg
CALL WR_REG ; write it
JP DONE_DASM ; done
TYPE_12 ; r,b,ra
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode r,b,RA
;*
;***********************************************************;
LD R9,BYTE_2 ; save bit number in R8
RR R9 ; bits 0-2
AND R9,#$07
; write out relative address operand
LD R10,#$25 ; put $ in out buf
CALL OUT_BUF
CLR R10 ; calculate address
TM BYTE_3,#$80 ; test for minus
JR Z,SK12FF
LD R10,#$FF
SK12FF:
LD R12,R1 ; lo input addr
ADD R12,BYTE_3 ; add relative addr
JR NC,SK12K1
INC R10
SK12K1:
ADD R10,R0
CALL HEX_ASCII ;put addr in out buf
LD R10,R12
CALL HEX_ASCII
CALL SEP_OPRNDS
; write out src register
LD R8,BYTE_2 ; save reg#
SWAP R8 ; put reg# in lo nibble
AND R8,#$0F ; clear upper nibble
OR R8,#$C0 ; working register
CALL WR_REG ; write src operand
CALL SEP_OPRNDS
; write out bit#
LD R10,#'#' ; put '#' in out buffer
CALL OUT_BUF
LD R10,R9 ; put bit# in out buf
CALL HEX_D_ASCII
JP DONE_DASM ; done
TYPE_13 ; r,b
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode r,b
;*
;***********************************************************;
LD R9,BYTE_2 ; save bit number in R8
RR R9 ; bits 0-2
AND R9,#$07
; write out dst register
LD R8,BYTE_2 ; save reg#
SWAP R8 ; put reg# in lo nibble
AND R8,#$0F ; clear upper nibble
OR R8,#$C0 ; working register
CALL WR_REG ; write src operand
CALL SEP_OPRNDS
; write out bit#
LD R10,#'#' ; put '#' in out buffer
CALL OUT_BUF
LD R10,R9 ; put bit# in out buf
CALL HEX_D_ASCII
JP DONE_DASM ; done
TYPE_14
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode R,RR
;* opcode IR,RR
;*
;***********************************************************;
; write out dst operand
LD R8,BYTE_3
CALL WR_REG_PAIR
CALL SEP_OPRNDS
; write out src operand
LD R10,BYTE_1 ; even = direct
TM R10,#$01 ; odd = indirect
JR Z,DIRR14
LD R10,#'@' ; indirect mode
CALL OUT_BUF ; put @ in out buffer
DIRR14:
LD R8,BYTE_2
CALL WR_REG ; write out reg#
JP DONE_DASM ; done
TYPE_15
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode IM,RR
;*
;***********************************************************;
; write out dst operand
LD R8,BYTE_3
CALL WR_REG_PAIR
CALL SEP_OPRNDS
; write out src operand
LD R10,#'#' ; put # in out buffer
CALL OUT_BUF
LD R10,BYTE_2 ; put reg# in out buf
CALL HEX_D_ASCII
JP DONE_DASM ; done
TYPE_16
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode IR,r,RA
;*
;***********************************************************;
; write out dst operand
LD R8,BYTE_2
AND R8,#$0F
OR R8,#$C0
CALL WR_REG
CALL SEP_OPRNDS
; write out src operand
LD R10,#'@' ; write '@'
CALL OUT_BUF
LD R8,BYTE_2 ; save src
SWAP R8 ; put reg# in lo nibble
AND R8,#$0F ; clear upper nibble
OR R8,#$C0 ; working register
CALL WR_REG ; write it
CALL SEP_OPRNDS
; write out relative address operand
LD R10,#$25 ; put '$' in out buf
CALL OUT_BUF
CLR R10 ; calculate address
TM BYTE_3,#$80 ; test for minus
JR Z,SK16FF
LD R10,#$FF
SK16FF:
LD R12,R1 ; lo input addr
ADD R12,BYTE_3 ; add relative addr
JR NC,SK16K1
INC R10
SK16K1:
ADD R10,R0
CALL HEX_ASCII ;put addr in out buf
LD R10,R12
CALL HEX_ASCII
JP DONE_DASM ; done
TYPE_17
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode RR,RR
;*
;***********************************************************;
; write out dst operand
LD R8,BYTE_3
CALL WR_REG_PAIR
CALL SEP_OPRNDS
; write out src operand
LD R8,BYTE_2
CALL WR_REG_PAIR
JP DONE_DASM ; done
TYPE_18
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode RR,IML
;*
;***********************************************************;
; write out dst operand
LD R8,BYTE_2
CALL WR_REG_PAIR
CALL SEP_OPRNDS
; write out src operand
LD R10,#'#' ; put # in out buffer
CALL OUT_BUF
LD R10,#$25 ; put $ in out buffer
CALL OUT_BUF
LD R10,BYTE_3 ; put addr in out buf
CALL HEX_ASCII
LD R10,BYTE_4
CALL HEX_ASCII
JP DONE_DASM ; done
TYPE_19
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode IA
;*
;***********************************************************;
; write out dst operand
LD R10,#$23 ; put # in out buffer
CALL OUT_BUF
LD R10,#$25 ; put $ in out buffer
CALL OUT_BUF
LD R10,BYTE_2 ; put addr in out buf
CALL HEX_ASCII
JP DONE_DASM ; done
TYPE_1A
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode r,x(rr)
;* opcode x(rr),r
;*
;***********************************************************;
; determine mode - test bit 4
LD R10,BYTE_1
TM R10,#$10 ; if cleared then
JR Z, R_X ; r,x(irr) mode
X_R: ; otherwise x(irr),r
; write indexed (short or long) dst operand
LD R10,#$25 ; put $ in out buffer
CALL OUT_BUF
LD R10,BYTE_1 ; test for long offset
TM R10,#$40 ; bit 6 in opcode
JR NZ, NLX_R ; not long if cleared
LX_R:
LD R10,BYTE_4 ; output (hi) offset
CALL HEX_ASCII
NLX_R:
LD R10,BYTE_3 ; output (lo) offset
CALL HEX_ASCII
LD R10,#'(' ; output '('
CALL OUT_BUF
LD R8,BYTE_2 ; save reg #
AND R8,#$0F ; in lo nibble
OR R8,#$C0 ; make work reg
CALL WR_REG_PAIR ; write pair
LD R10,#')' ; output ')'
CALL OUT_BUF
CALL SEP_OPRNDS
; write src operand
LD R8,BYTE_2 ; save src
SWAP R8 ; put src in lo nibble
AND R8,#$0F ; isolate src reg
OR R8,#$C0 ; make work reg
CALL WR_REG ; write it
JP DONE_DASM ; done
R_X:
; write dst operand
LD R8,BYTE_2 ; save src
SWAP R8 ; put src in lo nibble
AND R8,#$0F ; isolate src reg
OR R8,#$C0 ; make work reg
CALL WR_REG ; write it
CALL SEP_OPRNDS
; write indexed (short or long) src operand
LD R10,#$25 ; put $ in out buffer
CALL OUT_BUF
LD R10,BYTE_1 ; test for long offset
TM R10,#$40 ; bit 6 in opcode
JR NZ, NLR_X ; not long if cleared
LR_X:
LD R10,BYTE_4 ; output (hi) offset
CALL HEX_ASCII
NLR_X:
LD R10,BYTE_3 ; output (lo) offset
CALL HEX_ASCII
LD R10,#'(' ; output '('
CALL OUT_BUF
LD R8,BYTE_2 ; save reg #
AND R8,#$0F ; in lo nibble
OR R8,#$C0 ; make work reg
CALL WR_REG_PAIR ; write pair
LD R10,#')' ; output ')'
CALL OUT_BUF
JP DONE_DASM ; done
TYPE_1B
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode r,DA
;* opcode DA,r
;*
;***********************************************************;
; test for indexed mode
LD R10,BYTE_2 ; test bits 1-3
TM R10,#$0E ; if nz then indexed
JP NZ,TYPE_1A ; mode
; test for order of operands
LD R10,BYTE_1 ; test opcode bit 1
TM R10,#$10 ; if cleared then
JR Z, r_DA ; r, da mode
DA_r: ; otherwise da,r
; write address operand
LD R10,#$25 ; output '$'
CALL OUT_BUF
LD R10,BYTE_4 ; output hi
CALL HEX_ASCII ; address byte
LD R10,BYTE_3 ; output lo
CALL HEX_ASCII ; address byte
CALL SEP_OPRNDS
; write src operand
LD R8,BYTE_2 ; save src
SWAP R8 ; put src in lo nibble
AND R8,#$0F ; isolate src reg
OR R8,#$C0 ; make work reg
CALL WR_REG ; write it
JP DONE_DASM ; done
r_DA:
; write dst operand
LD R8,BYTE_2 ; save src
SWAP R8 ; put src in lo nibble
AND R8,#$0F ; isolate src reg
OR R8,#$C0 ; make work reg
CALL WR_REG ; write it
CALL SEP_OPRNDS
; write address operand
LD R10,#$25 ; output '$'
CALL OUT_BUF
LD R10,BYTE_4 ; output hi
CALL HEX_ASCII ; address byte
LD R10,BYTE_3 ; output lo
CALL HEX_ASCII ; address byte
JP DONE_DASM ; done
TYPE_1C
;*********************************************************
;*
;* Process and output operands for addressing modes:
;*
;* opcode Ir,r
;*
;***********************************************************;
; write dst operand
LD R10,#'@' ; put @ in out buffer
CALL OUT_BUF
LD R8,BYTE_2 ; save dst in R8
SWAP R8 ; put in lo nibble
AND R8,#$0F ; isolate
OR R8,#$C0 ; make working reg
CALL WR_REG ; write it
CALL SEP_OPRNDS
; write src operand
LD R8,BYTE_2 ; save src in R8
AND R8,#$0F ; isolate
OR R8,#$C0 ; make working reg
CALL WR_REG ; write it
CALL SEP_OPRNDS
JP DONE_DASM ; done
CHK_MNE
;***************************************************************
;*
;* CHK_MNE Check for opcode mnemonics that vary.
;*
;* input RR4 points to current main table entry.
;* Lo nibble of R10 contains entry# for alternate
;* table. Use alternate table if bit 0 of byte_2
;* is cleared.
;*
;* output If bit 0 of byte_2 is cleared, then RR4 points
;* to the correct entry in the alternate table.
;*
;***************************************************************;
; check for opcode mnemonics that vary
; RR4 points to current table entry
; lo nibble of R10 contains entry# for alt. table
; use alt. table if bit 0 of byte_2 is cleared
LD R8,BYTE_2 ; save mode
TM R8,#$01 ; test bit 1
JR Z, VRY_TAB ; use other table
; if cleared
SAME_TAB:
; use the same table -- just inc pointer
INCW RR4
JR DONE_CHK
VRY_TAB:
; check for special case of srp
CP BYTE_1,#$31 ; test for srp
JR NE,NOT_SRP0 ; opcode
TM BYTE_2,#$02 ; test bit 1
JR Z,NOT_SRP0 ; for srp0
LD R10,#$08 ; load alt table
; index for srp0
NOT_SRP0:
; point RR4 to correct pos. in alt. table
LD R8,R10 ; save entry #
AND R8,#$0F ; isolate entry #
LD R4,#^HB ALT_TAB ; point RR4 to
LD R5,#^LB ALT_TAB ; alt table
ENTRY_LP:
CP R8,#$00 ; are we at right
JR EQ, AT_ENTRY ; entry ?
CHAR_LP: ; increment RR4 until we get to control byte
INCW RR4 ; get next char.
LDC R9,@RR4
TM R9,#$80 ; control byte?
JR Z,CHAR_LP ; no
DEC R8 ; yes
JR ENTRY_LP
AT_ENTRY:
INCW RR4 ; point RR4 to letter
DONE_CHK:
; if instruction is ldc/lde type,
; clear lsb of byte_2
LDC R10,@RR4 ; put letter in R10
CP R10,#'L' ; load inst. ?
JR NE,RET_CHK ; no
AND BYTE_2,#$FE ; yes -- clear bit
RET_CHK:
RET
HEX_ASCII
;**********************************************************
;*
;* HEX_ASCII Convert hex byte to ASCII char and output.
;*
;* input R10 has hex byte.
;* RR2 points to the current output buffer pos.
;*
;* output The byte value is converted to ASCII
;* and placed in the output buffer.
;*
;************************************************************;
LD R11,R10 ; save R10
AND R10,#$F0 ; isolate hi nibble
SWAP R10 ; first
add r10,#$90
da r10
adc r10,#$40
da r10
LDC @RR2,R10 ; write hi nibble
INCW RR2 ; into out buffer
AND R11,#$0F ; now lo nibble
add r11,#$90
da r11
adc r11,#$40
da r11
LDC @RR2,R11 ; write lo nibble
INCW RR2 ; into out buffer
RET
RD_MEM
;**********************************************************
;*
;* RD_MEM Read a byte of memory
;*
;* input: RR0 is the memory read address
;*
;* output: R10 contains the value read from
;* the address
;*
;**********************************************************;
PUSH R8
PUSH R9
PUSH R15
LD R8,R0
LD R9,R1
CALL GETMEM
LD R10,R15
POP R15
POP R9
POP R8
RET
OUT_BUF
;*****************************************************
;*
;* OUT_BUF Put a character into the output buffer.
;*
;* input: R10 has the character
;*
;*******************************************************;
LDC @RR2,R10
INCW RR2
RET
HEX_D_ASCII
;**********************************************************
;*
;* HEX_D_ASCII Convert hex to decimal and put in
;* output buffer.
;*
;* input: R10 has the value to be converted
;*
;**********************************************************;
; first convert hex to decimal ff to 255
CLR R15 ;unit decimal #
CLR R14 ;tens decimal #
CLR R13 ;hundreds dec #
LUP:
CP R10,#$00 ; test for done
JR EQ,ASCI ; yes then to sacii
DEC R10 ; decrement hex
INC R15 ; increment dec
CP R15,#$0A ; check for dec carry
JR NE,LUP ; no do again
CLR R15 ; yes carry to tens
INC R14 ; zero units
CP R14,#$0A ; check for dec carry
JR NE,LUP ; no do again
CLR R14 ; yes carry to hundreds
INC R13 ; clear tens
JR LUP ; do again
; now convert decimal to ASCII
; and delete leading zeros
ASCI:
CP R13,#$00 ; first hundreds
JR EQ,TENS_
ADD R13,#$30 ; add 30
LDC @RR2,R13 ; put in out buf
INCW RR2
JR SK8 ; no delete tens
TENS_:
CP R14,#$00 ; next tens
JR EQ,UNITS_
SK8:
ADD R14,#$30 ; add 30
LDC @RR2,R14 ; put in out buf
INCW RR2
UNITS_:
ADD R15,#$30 ; next units
LDC @RR2,R15 ; put in out buf
INCW RR2
RET
TAB_SP
;***********************************************************
;*
;* TAB_SP Tab over some spaces in the output buffer
;*
;* input: R15 has the number of spaces to tab.
;*
;***********************************************************;
ADD R3,R15
JR NC,SKP
INC R2
SKP:
RET
WR_REG
;*******************************************************
;*
;* WR_REG Write a register operand into the output
;* buffer.
;*
;* input: R8 has the register number.
;*
;*******************************************************;
; R8 must contain the register number
; test for working reg in R8
LD R10,R8
AND R10,#$F0 ; hi nibble =c wregs
CP R10,#$C0
JR NE,NWR
LD R10,#'R' ;put r in out buf
CALL OUT_BUF
AND R8,#$0F ; delete c
NWR:
LD R10,R8 ; put reg# in out buf
CALL HEX_D_ASCII
RET
WR_REG_PAIR
;*******************************************************
;*
;* WR_REG Write a register pair operand into the
;* output buffer.
;*
;* input: R8 has the register number.
;*
;*******************************************************;
; test for working reg in R8
LD R10,R8
AND R10,#$F0 ; hi nibble =c wregs
CP R10,#$C0
JR NE,NWR_PAIR
LD R10,#'R' ;put r in out buf
CALL OUT_BUF
CALL OUT_BUF
AND R8,#$0F ; delete c
NWR_PAIR:
LD R10,R8 ; put reg# in out buf
CALL HEX_D_ASCII
RET
SEP_OPRNDS
;******************************************************
;*
;* SEP_OPRNDS Write a ", " into the output buffer
;* to separate the operands.
;*
;******************************************************;
LD R10,#',' ; write out ", " to
CALL OUT_BUF ; separate operands
LD R10,#' '
CALL OUT_BUF
RET
; opcode table: each entry has a control byte followed by 2-6 characters
; of opcode mnemonics.
; control byte format:
; bit 7 : set to indicate control byte
; bit 5-6 : instruction size encoded as (n - 1)
; bit 0-4 : instruction type for operad mnemonics
OP_TAB:
; opcodes 0x
db TWO_M+AD_TYPE_2, 'DEC'
db TWO_M+AD_TYPE_2, 'DEC'
db TWO_M+AD_TYPE_5, 'ADD'
db TWO_M+AD_TYPE_5, 'ADD'
db THREE_M+AD_TYPE_A, 'ADD'
db THREE_M+AD_TYPE_A, 'ADD'
db THREE_M+AD_TYPE_B, 'ADD'
db THREE_M+AD_TYPE_10, 'BOR'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'NEXT'
; opcodes 1x
db TWO_M+AD_TYPE_2, 'RLC'
db TWO_M+AD_TYPE_2, 'RLC'
db TWO_M+AD_TYPE_5, 'ADC'
db TWO_M+AD_TYPE_5, 'ADC'
db THREE_M+AD_TYPE_A, 'ADC'
db THREE_M+AD_TYPE_A, 'ADC'
db THREE_M+AD_TYPE_B, 'ADC'
db THREE_M+AD_TYPE_10, 'BCP'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'ENTER'
; opcodes 2x
db TWO_M+AD_TYPE_2, 'INC'
db TWO_M+AD_TYPE_2, 'INC'
db TWO_M+AD_TYPE_5, 'SUB'
db TWO_M+AD_TYPE_5, 'SUB'
db THREE_M+AD_TYPE_A, 'SUB'
db THREE_M+AD_TYPE_A, 'SUB'
db THREE_M+AD_TYPE_B, 'SUB'
db THREE_M+AD_TYPE_10, 'BXOR'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'EXIT'
; opcodes 3x
db TWO_M+AD_TYPE_3, 'JP'
db TWO_M+AD_TYPE_4, VARY_MNE+7, 'SRP1'
db TWO_M+AD_TYPE_5, 'SBC'
db TWO_M+AD_TYPE_5, 'SBC'
db THREE_M+AD_TYPE_A, 'SBC'
db THREE_M+AD_TYPE_A, 'SBC'
db THREE_M+AD_TYPE_B, 'SBC'
db THREE_M+AD_TYPE_12, VARY_MNE+6, 'BTJRT'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'WFI'
; opcodes 4x
db TWO_M+AD_TYPE_2, 'DA'
db TWO_M+AD_TYPE_2, 'DA'
db TWO_M+AD_TYPE_5, 'OR'
db TWO_M+AD_TYPE_5, 'OR'
db THREE_M+AD_TYPE_A, 'OR'
db THREE_M+AD_TYPE_A, 'OR'
db THREE_M+AD_TYPE_B, 'OR'
db THREE_M+AD_TYPE_10, 'LDB'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'SB0'
; opcodes 5x
db TWO_M+AD_TYPE_2, 'POP'
db TWO_M+AD_TYPE_2, 'POP'
db TWO_M+AD_TYPE_5, 'AND'
db TWO_M+AD_TYPE_5, 'AND'
db THREE_M+AD_TYPE_A, 'AND'
db THREE_M+AD_TYPE_A, 'AND'
db THREE_M+AD_TYPE_B, 'AND'
db TWO_M+AD_TYPE_13, 'BITC'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'SB1'
; opcodes 6x
db TWO_M+AD_TYPE_2, 'COM'
db TWO_M+AD_TYPE_2, 'COM'
db TWO_M+AD_TYPE_5, 'TCM'
db TWO_M+AD_TYPE_5, 'TCM'
db THREE_M+AD_TYPE_A, 'TCM'
db THREE_M+AD_TYPE_A, 'TCM'
db THREE_M+AD_TYPE_B, 'TCM'
db THREE_M+AD_TYPE_10, 'BAND'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, '**'
; opcodes 7x
db TWO_M+AD_TYPE_2, 'PUSH'
db TWO_M+AD_TYPE_2, 'PUSH'
db TWO_M+AD_TYPE_5, 'TM'
db TWO_M+AD_TYPE_5, 'TM'
db THREE_M+AD_TYPE_A, 'TM'
db THREE_M+AD_TYPE_A, 'TM'
db THREE_M+AD_TYPE_B, 'TM'
db TWO_M+AD_TYPE_13, VARY_MNE+5,'BITS'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, '**'
; opcodes 8x
db TWO_M+AD_TYPE_2, 'DECW'
db TWO_M+AD_TYPE_2, 'DECW'
db THREE_M+AD_TYPE_11, 'PUSHUD'
db THREE_M+AD_TYPE_11, 'PUSHUI'
db THREE_M+AD_TYPE_14, 'MULT'
db THREE_M+AD_TYPE_14, 'MULT'
db THREE_M+AD_TYPE_15, 'MULT'
db THREE_M+AD_TYPE_D, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'DI'
; opcodes 9x
db TWO_M+AD_TYPE_2, 'RL'
db TWO_M+AD_TYPE_2, 'RL'
db THREE_M+AD_TYPE_11, 'POPUD'
db THREE_M+AD_TYPE_11, 'POPUI'
db THREE_M+AD_TYPE_14, 'DIV'
db THREE_M+AD_TYPE_14, 'DIV'
db THREE_M+AD_TYPE_15, 'DIV'
db THREE_M+AD_TYPE_D, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'EI'
; opcodes ax
db TWO_M+AD_TYPE_2, 'INCW'
db TWO_M+AD_TYPE_2, 'INCW'
db TWO_M+AD_TYPE_5, 'CP'
db TWO_M+AD_TYPE_5, 'CP'
db THREE_M+AD_TYPE_A, 'CP'
db THREE_M+AD_TYPE_A, 'CP'
db THREE_M+AD_TYPE_B, 'CP'
db FOUR_M+AD_TYPE_1B, VARY_MNE+0,'LDE'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'RET'
; opcodes bx
db TWO_M+AD_TYPE_2, 'CLR'
db TWO_M+AD_TYPE_2, 'CLR'
db TWO_M+AD_TYPE_5, 'XOR'
db TWO_M+AD_TYPE_5, 'XOR'
db THREE_M+AD_TYPE_A, 'XOR'
db THREE_M+AD_TYPE_A, 'XOR'
db THREE_M+AD_TYPE_B, 'XOR'
db FOUR_M+AD_TYPE_1B, VARY_MNE+0,'LDE'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'IRET'
; opcodes cx
db TWO_M+AD_TYPE_2, 'RRC'
db TWO_M+AD_TYPE_2, 'RRC'
db THREE_M+AD_TYPE_16, 'CPIJE'
db TWO_M+AD_TYPE_6, VARY_MNE+0,'LDE'
db THREE_M+AD_TYPE_17, 'LDW'
db THREE_M+AD_TYPE_14, 'LDW'
db FOUR_M+AD_TYPE_18, 'LDW'
db TWO_M+AD_TYPE_5, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'RCF'
; opcodes dx
db TWO_M+AD_TYPE_2, 'SRA'
db TWO_M+AD_TYPE_2, 'SRA'
db THREE_M+AD_TYPE_16, 'CPIJNE'
db TWO_M+AD_TYPE_6, VARY_MNE+0,'LDE'
db TWO_M+AD_TYPE_19, 'CALL'
db ONE_M+AD_TYPE_0, '**'
db THREE_M+AD_TYPE_B, 'LD'
db TWO_M+AD_TYPE_1C, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'SCF'
; opcodes ex
db TWO_M+AD_TYPE_2, 'RR'
db TWO_M+AD_TYPE_2, 'RR'
db TWO_M+AD_TYPE_6, VARY_MNE+1,'LDED'
db TWO_M+AD_TYPE_6, VARY_MNE+2,'LDEI'
db THREE_M+AD_TYPE_A, 'LD'
db THREE_M+AD_TYPE_A, 'LD'
db THREE_M+AD_TYPE_B, 'LD'
db THREE_M+AD_TYPE_1A, VARY_MNE+0,'LDE'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'CCF'
; opcodes fx
db TWO_M+AD_TYPE_2, 'SWAP'
db TWO_M+AD_TYPE_2, 'SWAP'
db TWO_M+AD_TYPE_6, VARY_MNE+3,'LDEPD'
db TWO_M+AD_TYPE_6, VARY_MNE+4,'LDEPI'
db TWO_M+AD_TYPE_3, 'CALL'
db THREE_M+AD_TYPE_C, 'LD'
db THREE_M+AD_TYPE_F, 'CALL'
db THREE_M+AD_TYPE_1A, VARY_MNE+0,'LDE'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_7, 'LD'
db TWO_M+AD_TYPE_9, 'DJNZ'
db TWO_M+AD_TYPE_9, 'JR'
db TWO_M+AD_TYPE_8, 'LD'
db THREE_M+AD_TYPE_E, 'JP'
db ONE_M+AD_TYPE_1, 'INC'
db ONE_M+AD_TYPE_0, 'NOP'
db HI_BIT
; mnenmonics that vary
ALT_TAB:
db HI_BIT, 'LDC'
db HI_BIT, 'LDCD'
db HI_BIT, 'LDCI'
db HI_BIT, 'LDCPD'
db HI_BIT, 'LDCPI'
db HI_BIT, 'BITR'
db HI_BIT, 'BTJRF'
db HI_BIT, 'SRP'
db HI_BIT, 'SRP0'
db HI_BIT
; condition code mnemonics
CC_TAB:
db 'F',COMMA,' ',$80
db 'LT',COMMA,' ',$80
db 'LE',COMMA,' ',$80
db 'ULE',COMMA,' ',$80
db 'OV',COMMA,' ',$80
db 'MI',COMMA,' ',$80
db 'Z/EQ',COMMA,' ',$80
db 'C/ULT',COMMA,' ',$80
db ' ',$80
db 'GE',COMMA,' ',$80
db 'GT',COMMA,' ',$80
db 'UGT',COMMA,' ',$80
db 'NOV',COMMA,' ',$80
db 'PL',COMMA,' ',$80
db 'NZ/NE',COMMA,' ',$80
db 'NC/UGE',COMMA,' ',$80
END