; http://www.moondew.com/z8000 SKIP 16 ; *************************************************** ; * * ; * Z 8 0 0 2 S Y S T E M M O N I T O R * ; * * ; * Z8002 System X1 Monitor Revision 4.5 * ; * By Tom Nelson Completed February 1981 * ; * * ; * Copyright (C) Tom Nelson, 1981 * ; * * ; *************************************************** TITLE "Symbol Definitions" EJECT ; Temporary EQU ; <> EPROMER: EQU '03A6'H ; Address of Eprom programmer EDITOR: EQU '1B46'H ; Start address of NC Editor ; Ascii characters BS: EQU 8 LF: EQU 10 FF: EQU 12 CR: EQU 13 CNTRL_P: EQU 16 CNTRL_Q: EQU 17 CNTRL_S: EQU 19 CNTRL_U: EQU 21 CNTRL_X: EQU 24 CNTRL_Y: EQU 25 CNTRL_Z: EQU 26 ESC: EQU 27 TILDE: EQU 126 RUBOUT: EQU 127 ; Misc symbols CANCEL: EQU CNTRL_X ; Cancel line character DELETE: EQU BS ; Delete character in line EOS: EQU 0 ; End of string NEWLN: EQU -1 ; Newline character in Printstr BRK: EQU CNTRL_P ; Character used as 'send break' MDRBUFLEN: EQU 128 ; Size of transparent mode buffers MDRBUFMOD: EQU MDRBUFLEN-1 ; Used to MOD buffer indexes MDLBUFLEN: EQU 2K ; Size of local buffer MDLBUFMOD: EQU MDLBUFLEN-1 ; Local buffer MOD MD_EXPNLO: EQU CNTRL_U ; For LP blank expansion MD_EXPNHI: EQU CNTRL_Y RAMBASE: EQU 'F000'H ; Start of Monitor RAM ; I/O channels LCLCHAN: EQU 0 ; Local terminal RMTCHAN: EQU 1 ; Modem LPCHAN: EQU 2 ; Printer ; I/O ports for X8250 X8250NUM: EQU 4 ; Number of X8250 ports X8250base: EQU 48 ; Address of first X8250 card DLLS: EQU 0+X8250base ; Divisor latch (LS) DLMS: EQU 1+X8250base ; Divisor latch (MS) DATA: EQU 0+X8250base ; Data register LCR: EQU 3+X8250base ; Line control register MCR: EQU 4+X8250base ; Modem control register LSR: EQU 5+X8250base ; Line status register MSR: EQU 6+X8250base ; Modem status register DEFAULT: EQU 15+X8250base ; Default settings dip switch ; I/O bits for LCR on 8250 SBITS: EQU 2 BREAK: EQU 6 DLAB: EQU 7 ; I/O bits for LSR on 8250 DR: EQU 0 ; Data ready BI: EQU 4 ; Break interrupt THRE: EQU 5 ; Transmitter holding register empty ; I/O bits for MCR on 8250 DSR: EQU 0 ; Data set ready CTS: EQU 1 ; Clear to send ; I/O bits for MSR on 8250 DTR: EQU 5 ; Data terminal ready RLSD: EQU 7 ; Received line signal detect ; Bit flags @NMI_FLAGS IN_SAVE: EQU 0 ; Tells NMI that NVI is in save routine IN_TISR: EQU 1 ; Tells NMI that PC was in NVI Routine ; Bit flags @BIT_FLAGS EXEFLG: EQU 0 ; OK to continue flag EXELAST: EQU 1 ; Last command was Execute EXELOAD: EQU 2 ; Load specified on Execute option LP_ONFLG: EQU 3 ; Echo to printer flag CONTFLG: EQU 5 ; Continue flag for NVI ; Misc. Flags ESCFLG: EQU 3 ; Saw Escape (Transparent mode) MDLP_ON: EQU 4 ; Printer enabled LP_TRYS: EQU 65535 ; Number of time to retry LP DIPSW: EQU '80'H ; Used in X8250 init table NEXTBYTE: EQU 0 ; " " " TITLE "Token definitions" EJECT ; Command Tokens TK_ADDR: EQU 0 TK_DEP: EQU 1 TK_DUMP: EQU 2 TK_FILL: EQU 3 TK_COPY: EQU 4 TK_SEARCH: EQU 5 TK_SET: EQU 6 TK_CLEAR: EQU 7 TK_SHOW: EQU 8 TK_CONF: EQU 9 TK_EXEC: EQU 10 TK_CONT: EQU 11 TK_MODEM: EQU 12 TK_HELP: EQU 13 TK_PREV: EQU 14 TK_NEXT: EQU 15 TK_COMP: EQU 16 TK_LOAD: EQU 17 TK_ECHO: EQU 18 TK_EPROM: EQU 19 ; <> TK_EDIT: EQU 20 ; <> ; FCW, NSP & PC tokens used by the Set and Clear options TK_HFLG: EQU 2 TK_DFLG: EQU 3 TK_PVFLG: EQU 4 TK_SFLG: EQU 5 TK_ZFLG: EQU 6 TK_CFLG: EQU 7 TK_NVIFLG: EQU 11 TK_VIFLG: EQU 12 TK_EPFLG: EQU 13 TK_SYSFLG: EQU 14 TK_SP: EQU 15 TK_NSP: EQU 16 TK_FCW: EQU 17 TK_PC: EQU 18 ; Keyword tokens for the show option TK_LIMITS: EQU 0 TK_BRKPTS: EQU 1 TK_TRACES: EQU 2 TK_REGS: EQU 3 TK_PSW: EQU 4 TK_HIST: EQU 5 TK_CHAN: EQU 6 ; Keywords for the ECHO Option TK_ECHON: EQU 0 TK_ECHOFF: EQU 1 EJECT ; Loader return codes LD_EOFNUM: EQU 0 LD_BRKNUM: EQU 1 LD_ERRNUM: EQU 2 ; Execute & Continue parameter tokens TK_ECLOAD: EQU 0 TK_ECDEB: EQU 11 TK_ECNODB: EQU -11 TK_ECVI: EQU 12 TK_ECNOVI: EQU -12 TK_ECEP: EQU 13 TK_ECNOEP: EQU -13 TK_ECSYS: EQU 14 TK_ECNORM: EQU -14 ; Keyword tokens for the configure TK_CFWLEN: EQU 0 TK_CFSBIT: EQU 1 TK_CFPRTY: EQU 2 TK_CFBAUD: EQU 3 TK_CFDIV: EQU 4 TK_CFPTCL: EQU 5 ; Parity tokens TK_CFNPTY: EQU 0 TK_CFOPTY: EQU 1 TK_CFEPTY: EQU 3 ; Device name tokens TK_TT: EQU 0 TK_MD: EQU 1 TK_LP: EQU 2 TK_PR: EQU 3 TITLE "Error number tokens" EJECT ; Error message tokens ER_NOPARM: EQU 0 ER_EXTRA: EQU 1 ER_NOTHEX: EQU 2 ER_NOTDEC: EQU 3 ER_BADKEY: EQU 4 ER_TWOKEY: EQU 5 ER_BADRNG: EQU 6 ER_NODEL: EQU 7 ER_TOOBIG: EQU 8 ER_BADOPT: EQU 9 ER_TWOOPT: EQU 10 ER_NOTFND: EQU 11 ER_CANTCN: EQU 12 ER_MATCH: EQU 13 ER_NOLP: EQU 14 TITLE "Version/Reset vector" EJECT ; Define version number of the Monitor. ; Any programs using the Monitor routines should test this ; value before executing. A different version may result in ; entry point address changes. DCB 4,5 ; Version number. (4.5) SKIP 8 ; Define Reset vector. ; On power-up or when the Cold Start button is pressed, ; the CPU will load the PSW with the values stored at these ; locations. The Cold Start button will cause a complete ; power-up initialization of the Monitor. RESET: DC '4000'H,START ; Define Reset vector TITLE "Jump table" EJECT ; The following jumps allow Monitor routines to be ; used without having to modify programs that use ; them everytime the monitor is revised. JP _ERRORMSG JP _FINDDEL JP _GETCHAR JP _GETDECLV JP _GETDECV JP _GETHEXR JP _GETHEXRV JP _GETHEXV JP _GETLINE JP _INCHAR JP _KEYWORDS JP _LOADER JP _NEXTPARM JP _NUMKEYS JP _OUTADDR JP _OUTCHAR JP _OUTDECW JP _OUTDECL JP _OUTHEX JP _PRINTSTR JP _PRTHEAD JP _PUTBLANK JP _PUTBRK JP _PUTCHAR JP _PUTCRLF JP _SSQ JP _OUTHEXB JP _OUTHEXW JP _ASKYES JP _PUTLCHAR JP _OUTMEM TITLE "Monitor Trap routines" EJECT ; Bad Opcode trap. ; If the CPU attemps to execute an unimplemented opcode, ; it will trap to this service routine. All CPU statuses ; and registers will be saved, the continue option will be ; disabled and an error message will be displayed before ; returning to the monitor. BADOP: LD NMI_FLAGS,#'FFFF'H ; Set all NMI flags RES BIT_FLAGS,#EXEFLG ; Now can't continue. LD RETADDR,#BADOP_RA ; Call without a stack JP SAVESTATS ; Save CPU statuses BADOP_RA: LDA R14,BADOPMSG ; Set-up message JR TRAPCOM ; Exit trap SKIP 4 ; Privileged Opcode trap. ; If execution of a System mode only instruction is attemped ; in Normal mode, it will cause a trap to this service routine. ; All CPU statuses and registers will be saved, the continue ; option will be disabled and an error message will be displayed ; before returning to the Monitor. PRIVOP: LD NMI_FLAGS,#'FFFF'H ; Set all NMI flags RES BIT_FLAGS,#EXEFLG ; Now can't continue. LD RETADDR,#PRIVOP_RA ; Call without a stack JP SAVESTATS ; Save CPU statuses PRIVOP_RA: LDA R14,PRIVOPMSG ; Set-up message JR TRAPCOM ; Exit trap EJECT ; System Call trap. ; When a System call instruction is executed it will trap ; to this service routine. Currently only SC zero is defined. ; Any SC other than zero will save all the CPU statuses and ; registers, disable the continue option and cause a message ; to be displayed before returning to the Monitor. A system ; call zero will re-entry to the Monitor without any message ; being displayed or any statuses getting saved. If the SC ; zero is encountered in a program invoked with the Execute ; option, continue will be disabled. Execute however, is ; currently the only way to invoke a loaded program. SYSCALL: TESTB 1(R15) ; Is it syscall 0? JR NZ,SYSUNDEF ; ..No SYSCALL0: BIT BIT_FLAGS,#EXELAST ; Was the last command Execute? JR ZER,SYS0_NO ; ..No, don't touch continue flag RES BIT_FLAGS,#EXEFLG ; Yes so no more continue! SYS0_NO: LDA R15,MONSTACK ; Re-init Monitor stack CALR _PUTCRLF JP TOMONITOR ; Back to the monitor SYSUNDEF: LD NMI_FLAGS,#'FFFF'H ; Set NMI flags RES BIT_FLAGS,#EXEFLG ; Bad bad! No more continue! LD RETADDR,#SYS_RA ; Call without a stack JP SAVESTATS ; Save users stats SYS_RA: LDA R14,SYSCALMSG ; Get undefined message ; Fall into Trapcom SKIP 10 ; Trapcom exit point. ; All trap routines returning to the Monitor with an error ; message jump to this point. The trap error message will be ; displayed and the trap status dump message will be set-up ; for "TOMON". TRAPCOM: DEC R9,#2 ; PC -> Address of trap cause CALR _PRINTSTR ; Print trap message LDA R14,TRAPPCMSG JP TOMONDUMP ; Back to monitor TITLE "Monitor Interrupt routines" EJECT ; Non-Maskable Interrupt. ; On the X System the restart button is an NMI which ; vectors to this service routine. Restart is used to ; return execution to certain points in the monitor without ; cold starting. Currently restart will return to trans- ; parent mode if you were in that mode or command mode if ; you were in command mode. If you were executing a loaded ; program, restart will save CPU statuses and display a ; message before returning to the Monitor. When saving the ; CPU statuses the NMI routine must check to see if the CPU ; was currently in another ISR and if it was, whether the ; other routine was in the process of saving statuses. This ; is done by the use of the NMI_FLAGS. Other ISR's set ; these flags at entry, then clear the "INSAVE" flag after ; saving statuses and the "IN_TISR" flag on IRET or return ; to Monitor. NMI_ISR: BIT BIT_FLAGS,#EXELAST ; 'Execute' was last command? JR NZ,NMI_SAVE ; ..No, go where you must. LDA R15,MONSTACK ; Re-init monitor stack CALR _PUTCRLF LD R1,RESTART ; Get Restart vector JP @R1 ; Jump to restart address ; NMI was returning from "Execute". NMI_SAVE: BIT NMI_FLAGS,#IN_SAVE ; Restarted out of "Savestats"? JR ZER,NMI_WHAT ; ..No, test other flag LD RETADDR,#NMI_LAST ; Change Save routine return address IRET ; Go back to save routine NMI_WHAT: BIT NMI_FLAGS,#IN_TISR ; Restarted out of Trap or Interrupt? JR NZ,NMI_LAST ; ..Yes, Don't save anything LD RETADDR,#NMI_LAST ; Call without a stack JP SAVESTATS ; Save processor statuses NMI_LAST: LDA R14,NMIMSG ; Ready for NMI message JR INTCOM EJECT ; Non-Vectored Interrupt. ; The X System uses NVI as a single-step debugging aid. ; When enabled, the CPU is interrupted with an NVI after ; every instruction. This service routine then tests the ; debugging parameters which are PC Limits, Breakpoints and ; PC Tracing. Depending on the values of these parameters, ; this routine will either display a trace message and IRET ; or display a breakpoint or limit message and return to the ; Monitor. A limit error will also disable the Continue option. ; As of V4.1, debug will save the last 8 PSW's and keep an ; instruction count. It will also test an instruction limit ; which, when reached, stops execution but does not disable ; continue. NVI_ISR: LD NMI_FLAGS,#'FFFF'H ; Set NVI flags LD RETADDR,#NVI_LIMS ; Call without a stack JR SAVESTATS ; Limits test NVI_LIMS: LDK R14,#2*TK_LIMITS ; Load limits address index CALR INRANGE ; PC within Limits? JR NC,NVI_BPTS ; ..Yes, Test breakpoints RES BIT_FLAGS,#EXEFLG ; No more continue LDA R14,LIMITERR ; Print limit message JR INTCOM ; Back to monitor ; Breakpoints test NVI_BPTS: BIT BIT_FLAGS,#CONTFLG ; This is first after Continue? JR NZ,NVI_HIST ; ..Yes, skip traps LDK R14,#2*TK_BRKPTS ; Load breakpoints address index CALR INRANGE ; PC within a breakpoint range? JR CAR,NVI_TRCS ; ..No, test trace LDA R14,BPTSERR ; Print breakpoint message JR INTCOM ; Back to monitor ; Trace test NVI_TRCS: LDK R14,#2*TK_TRACES ; Load traces address index CALR INRANGE ; PC within a trace range? JR CAR,NVI_HIST ; ..No, save PSW history LDA R14,TRCSERR ; Print trace message CALR _PRINTSTR LDA R14,INTPCMSG CALR PRINTSTAT ; Display saved status CALR _SSQ ; What does he want? JR CAR,NVI_ABORT ; Stop on BREAK char ; Instruction limits and PSW history NVI_HIST: LDL RR0,INST_RCNT ; Get instruction count TESTL INST_LIM ; Instruction limit set? JR ZER,NVI_HUPD ; ..No, don't test it CPL RR0,INST_LIM ; Hit limit? JR ULT,NVI_HUPD ; ..No, don't stop LDA R14,INSLIMMSG ; Print limit message JR INTCOM ; Back to the monitor NVI_HUPD: LDL RR2,INST_TCNT ; Get total count ADDL RR2,RR0 AND R3,#'07'H ; And into index SLL R3,#2 ; Make into long index LD SAVE_HIST(R3),R8 ; Save FCW LD SAVE_HIST+2(R3),R9 ; Save PC ADDL RR0,#1 ; Update Instruction count LDL INST_RCNT,RR0 ; Resave it ; RContinue execution... NVI_IRET: LDM R0,USERREGS,#16 ; Unsave regs RES BIT_FLAGS,#CONTFLG ; Reset continue flag CLR NMI_FLAGS ; Get rid of those flags! IRET ; Back to user pgm. ; Terminate execution by break character during trace. NVI_ABORT: CALR _PUTCRLF LDA R14,BREAKMSG ; Print abort message CALR _PRINTSTR JR TOMONSET ; Back to the monitor EJECT ; Vectored Interrupts. ; On power-up or Cold Start all vectored interrupts are ; set to undefined. Unless changed a VI will vector to this ; service routine, save CPU statuses and registers and display ; an error message before returning to the Monitor. VI_ISR: LD NMI_FLAGS,#'FFFF'H ; Set NMI flags LD RETADDR,#VI_RA ; Call without a stack JR SAVESTATS VI_RA: LDA R14,VIMSG CALR _PRINTSTR ; Print VI message LD R1,R7 CALR _OUTHEX ; Print VI. Id JR INTCOM2 SKIP 10 ; Intcom exit point. ; All interrupt routines returning to the Monitor with an ; error message jump to this point. The set-up message is ; printed and the interrupt status dump message will be set-up ; for "TOMON". INTCOM: CALR _PRINTSTR ; Print Interrupt message INTCOM2: LDA R14,INTPCMSG ; Fall into "Tomonitor" TITLE "Trap & Interrupt - Subroutines" EJECT ; Tomon exit point. ; Both Trapcom and Intcom jump to here to have the CPU ; statuses displayed and to return to the Monitor. Other ; trap and interrupt routines jump to different points in ; Tomon. TOMONDUMP: CALR PRINTSTAT ; Dump statuses on the way TOMONSET: LD CURADDR,R9 ; Make display address equal to saved PC TOMONITOR: RES BIT_FLAGS,#EXELAST ; Reset Execute last command flag CLR NMI_FLAGS ; Get rid of the NMI Flags INC USERREGS+30,#6 ; Remove Trap/Int junk from Stack JP COMMAND ; ..and back you go SKIP 6 ; Inrange Subroutine. ; This routine checks to see if the PC is within the ; the bounds of 8 saved ranges pointed to by DBG_ADDR ; indexed by R14. If it is within one of the ranges the ; C flag is set, otherwise it is reset. R9 is passed ; in with the PC value. If any range is 0/0, it is not ; tested and the PC is considered to be not within that ; range. INRANGE: LDK R3,#8 ; R3 is number of ranges LD R2,DBG_ADDR(R14) ; R2 gets address of ranges INRGE_TOP: TESTL @R2 ; Range off? (0,0) JR NZ,INR_TEST ; ..No, test range INC R2,#4 ; R2 -> next range JR INR_NEXT INR_TEST: CP R9,@R2 ; Is PC less than than 1st value? JR ULT,INR_BOT ; ..Yes, out of range. INC R2,#2 CP R9,@R2 ; Is PC Less than 2nd value? JR ULE,INR_IN ; ..Yes, in range. Stop searching INR_BOT: INC R2,#2 ; Next range to test INR_NEXT: DEC R3,#1 ; Tested all ranges? JR NZ,INRGE_TOP ; ..No, test next range SETFLG C ; Set out of range flag JR INR_RET INR_IN: RESFLG C ; Clear out of range flag INR_RET: RET EJECT ; Printstat Subroutine. ; This routine displays PC message pointed to by R14 ; then displays the saved PC contained in R9, the value ; at the PC and the FCW contained in R8. PRINTSTAT: CALR _PRINTSTR ; Print message LD R1,R9 ; R1 gets PC CALR _OUTMEM ; PRINT R1 & @R1 LDA R14,FCWMSG ; Flag message CALR _PRINTSTR ; Print FCW prompt LD R1,R8 ; R1 gets FCW CALR _OUTHEX ; Out FCW CALR _PUTCRLF RET SKIP 6 ; Savestats Subroutine. ; This routine saves all of the registers and the CPU ; statuses, meaning the PC and FCW placed on the stack ; after an interrupt or trap. It then re-inititalizes ; the stack for the Monitor and clears the NMI, IN_SAVE ; flag. Savestats must be called without using a stack ; since the Monitor stack is not yet set and the old SP ; hasn't been saved. This routine is used by storing the ; return address at RETADDR before jumping to Savestats. SAVESTATS: LDM USERREGS,R0,#16 ; Save regs LD R9,4(R15) ; Get PC LD GO_PC,R9 ; Save PC LD R8,2(R15) ; Get FCW LD GO_FCW,R8 ; Save FCW LD R7,@R15 ; Load trap ID. LDCTL R1,NSP ; Save NSP LD USERREGS+32,R1 LDA R15,MONSTACK ; Re-init stack RES NMI_FLAGS,#IN_SAVE ; Clear In save routine flag LD R1,RETADDR ; Get return address JP @R1 ; Return TITLE "Initializations; Cold Start" EJECT ; Program status area. Must be copied to even '100'H boundry. PSA_DEF: DS 2 ; Unused vector slot DC '4000'H,BADOP ; Bad opcode vector DC '4000'H,PRIVOP ; Privileged opcode vector DC '4000'H,SYSCALL ; System call vector DS 2 ; Seg Trap vector (Unused on Z8002) DC '4000'H,NMI_ISR ; Restart Vector DC '4000'H,NVI_ISR ; Break-point Vector DC '4000'H,VI_ISR ; First Vector Interrupt Vector ; X8250 inititalization table. (Read as words) ; First byte indicates where the default setting is ; found. X8250INIT: DCB DIPSW,DEFAULT,NEXTBYTE,'00110111'B DCB NEXTBYTE,'11011110'B,NEXTBYTE,'00110111'B INITPTCL: DC TK_TT,TK_MD,TK_LP,TK_PR ; Execution begins here! START: LD R1,#'8700'H ; Enable refresh (1 ms.) LDCTL REFRESH,R1 LDA R15,MONSTACK ; Setup stack pointer ; Copy PSA Definition to RAM LDA R1,PSA_DEF LDA R2,PSA LD R3,#16 ; Number of words to copy LDIR @R2,@R1,R3 ; Move those words! ; Fill VI vector table with default pc's LDA R1,PSA+30 ; R1 -> VI pc LDA R2,PSA+32 ; R2 -> second VI pc address LD R3,#255 ; R3 is number of VI pc's in PSA LDIR @R2,@R1,R3 ; Duplicate VI pc thru PSA ; Initialize PSA pointer LDA R1,PSA ; Get the PSA address LDCTL PSAP,R1 ; Tell the z8000 where it is. ; Initialize X8250s LDK R14,#(X8250NUM-1)*2 ; R14 indexes X8250 address tables X8SETTOP: LD R4,X8250LCR(R14) ; R4 get address of an 8250 LCR port LDB RL1,#'80'H ; Set Divisor latch access bit OUTB @R4,RL1 LD R1,X8250INIT(R14) ; R1 gets the default setting TESTB RH1 ; If High byte is not zero then JR ZER,X8250SET ; .. use low byte from table INB RL1,@R1 ; otherwise in default from dip sw. CLRB RH1 ; Clear high byte for indexing X8250SET: LDB RL0,RL1 ; Save default ANDB RL1,#'11100000'B ; Mask off all except baud index SRLB RL1,#4 ; shift for indexing LD R2,DIVISORS(R1) ; R2 gets the baud rate divisor value LD R3,X8250DLLS(R14) ; R3 -> DLLS port OUTB @R3,RL2 ; Set the LS byte of the DL INC R3 ; R3 -> DLMS port OUTB @R3,RH2 ; Set the MS byte of the DL ANDB RL0,#'00011111'B ; Mask off baud index OUTB @R4,RL0 ; Set other defaults LD R1,INITPTCL(R14) ; Get initial protocol LD X8250PTCL(R14),R1 ; Set protocol DEC R14,#2 ; Next 8250? JR PL,X8SETTOP ; ..Not neg so do it again ; Zero Break-points, Register & FCW savearea, Restart & Loader offset CLR SAVE_BPTS LDA R1,SAVE_BPTS ; R1 -> Zero word LDA R2,SAVE_BPTS+2 ; R2 -> Next word LD R3,#NUMTOZERO ; R3 is number of words to zero LDIR @R2,@R1,R3 ; Zero memory ; Other initializations LD CURADDR,#'6000'H ; Initial Display address LD DIRECTION,#2 ; Initialize next address direction LD USERREGS+32,#USERNORM ; Initialize user Normal stack LD USERREGS+30,#USERSYS ; Initialize user System stack LD GO_FCW,#'4000'H ; Default FCW on Execute is System mode TITLE "Command Input - Program Main" EJECT ; This routine prompts for command input and accepts the following: ; Next - Increments the display address ; Previous - Decrements the display address ; Address - Specifies the display address ; Deposit - Alters locations in memory ; Dump - Displays a section of memory ; Fill - Fills a section of memory ; Copy - Copy a section of memory to other location ; Compare - Compares memory with memory ; Search - Looks for a string of words in memory ; Set - Sets the FCW, Registers, Limits, Breakpoints & Traces. ; Clear - Clears any of the set parameters. ; Show - Allows you to display the value of the set parameters ; Execute - Run a loaded program ; Continue - Continue with execution after breakpoint ; Modem - Enters transparent mode ; Help or ? - Gives a list of the options available ; Register conventions: ; R14 - Parameter passage to subroutines ; R13 - Address of command input buffer ; R1 - Return value from subroutines ; All other registers used as needed ; NOTE : After scanning any symbol, R13 is left pointing to the ; next character to be scanned unless a fatal error has ; occured. New routines should follow this method to ; guarantee correctness. LDA R14,LC_MES ; Print 'Start message' CALR _PRINTSTR COMMAND: LD RESTART,#COMMAND ; Set Restart (NMI) to Command mode CMD_TOP: LD R1,CURADDR ; Print Display address CALR _OUTMEM ; Print R1 & @R1 LDA R13,LINBUF ; R13 -> Address of Input buffer CALR _GETLINE ; Read command into buffer JR CAR,CMD_TOP ; ..Cancelled line, re-prompt CALR _NEXTPARM ; Skip to first parameter JR NC,CMD_TRY ; Is not CR only, look for command CALR NEWADDR ; Go to next address JR CMD_TOP ; Look up command Keyword CMD_TRY: LDA R14,CMD_KEYS ; Set-up for Keywords CALR _KEYWORDS ; Find the command JR CAR,CMD_BAD ; Keyword not found or not unique SLL R1,#1 ; Make R1 into word index LD R1,CMD_ADDR(R1) ; Get command address CALL @R1 ; Do the command JR CAR,CMD_ERR ; ..Error in command CALR _NEXTPARM ; Any extra parms? JR CAR,CMD_TOP ; ..No, next command LDK R14,#ER_EXTRA ; Extra parm message JR CMD_ERR ; Change error numbers from ones returned from _KEYWORDS CMD_BAD: LDK R14,#ER_BADOPT ; Load bad option error TESTB RH1 ; Was it ambiguous? JR ZER,CMD_ERR ; ..No LDK R14,#ER_TWOOPT ; no it's ambiguous CMD_ERR: CALR _ERRORMSG ; Display error message JR CMD_TOP ; Try again ; Command address look_up table indexed by the ; keyword token found by _KEYWORDS. Changing ; the values of the Command tokens requires ; changing the order of this table. CMD_ADDR: DC ADDRESS,DEPOSIT,DUMP,FILL,COPY,SEARCH DC SET,CLEAR,SHOW,CONFIGURE,EXEC,CONTINUE DC MODEM,HELP,PREVIOUS,NEXT,COMPARE DC LOAD,ECHO,EPROMER,EDITOR ; <> TITLE "Monitor commands - Address modification" EJECT ; PREVIOUS Option. ; Decrements the current address by 2 PREVIOUS: DEC CURADDR,#2 ; Current address -2 RESFLG C ; Clear error flag RET SKIP 4 ; NEXT Option. ; Increments the current address by 2 NEXT: INC CURADDR,#2 ; Current address +2 RESFLG C ; Clear error flag RET SKIP 4 ; NEWADDR. (CR Option.) ; Updates current address at CURADDR to ; next address to be displayed on CR NEWADDR: LD R1,CURADDR ; Get current address ADD R1,DIRECTION ; Add increment to address LD CURADDR,R1 ; Save new address RESFLG C RET SKIP 4 ; ADDRESS Option. ; Sets the address to be displayed. ADDRESS: CALR _GETHEXV ; R1 gets new address JP CAR,ADDR_RET ; Missing address .. ERR RES R1,#0 ; Force to even address LD CURADDR,R1 ; Save new current address ADDR_RET: RET TITLE "Monitor Commands - Miscellaneous" EJECT ; HELP Option. ; Gives help on available commands. HELP: LDA R14,HELP_MSG CALR _PRINTSTR RET SKIP 6 ; ECHO Option. ; Enables and disables local channel echoing to ; the printer. ECHO: LDA R14,ECHO_KW ; Look-up parameter CALR _KEYWORDS JR CAR,ECH_RET ; ..No good RES BIT_FLAGS,#LP_ONFLG ; Turn LP off CP R1,#TK_ECHOFF ; Said LP off? JR EQ,ECH_RET ; ..Yes LDK R14,#LPCHAN*2 ; R14 indexs LP MSR LD R14,X8250MSR(R14) ; R14 -> LP MSR LD R3,#LP_TRYS ; Times to re-try LP ECH_WAIT: INB RL2,@R14 ; RL2 get lp MSR BITB RL2,#DTR ; LP DTR? JR NZ,ECH_ON ; ..Yes, turn LP on DJNZ R3,ECH_WAIT ; Try again if R3>0 LDK R14,#ER_NOLP ; Set LP not ready error JR ECH_RET ECH_ON: SET BIT_FLAGS,#LP_ONFLG ; turn LP on ECH_END: RESFLG C ; Clear error flag ECH_RET: RET TITLE "Monitor commands - Memory Dump" EJECT ; DUMP Option. ; Dumps memory from specified starting address to ending address ; dump does not change your current address. DUMP: CALR _GETHEXRV ; Get first address or range JR CAR,DP_RET ; Bad hex .. ERR CLRB RL6 ; Clear 'End address' flag DP_TOP: CALR _SSQ ; Start/Stop/Quit control JR CAR,DP_BRK ; End of dump if BRK char seen LDK R4,#8 ; 8 Words per displayed line LD R5,R2 ; Save R2 for ASCII Dump LD R1,R2 ; Print address & ":" CALR _OUTADDR DP_NEXT: LD R1,@R2 ; Print contents CALR _OUTHEX CP R2,R3 ; Hit end address? JR NE,DP_CONT ; ..No, keep going LDB RL6,#1 ; Set 'End address' flag DP_CONT: INC R2,#2 ; Go to next address DEC R4,#1 ; No.. dump next word JR NZ,DP_NEXT CALR DP_ASCII ; Dump ASCII CALR _PUTCRLF ; New line TESTB RL6 ; Stop dumping? JR NZ,DP_BOTTOM ; Yes .. quit JR DP_TOP ; Loop ; CTRL-P seen .. print msg & quit DP_BRK: LDA R14,BREAKMSG ; Print abort message CALR _PRINTSTR JR DP_END ; end of dump DP_BOTTOM: CALR _NEXTPARM ; Any more parms? JR NC,DUMP ; ..if any left DP_END: CALR _PUTCRLF RESFLG C ; Clear error flag DP_RET: RET EJECT ; Dump ASCII subroutine ; Dump in ASCII the memory starting at the address in R5 ; to the address in R2. The contents of R1 is lost. DP_ASCII: LDK R1,#2 ; Print two blanks CALR _PUTBLANK LDB RL4,#16 ; Characters to dump DPA_TOP: LDB RH1,@R5 ; Load char for print CPB RH1,#" " ; Is it a control char? JR LT,DPA_BAD ; ..Yes, use a different char CPB RH1,#TILDE ; Is it a RUBOUT or high bit char? JR LE,DPA_OK ; ..No, print it. DPA_BAD: LDB RH1,#"." ; Use a '.' for nonprintable chars DPA_OK: CALR _PUTLCHAR ; Print char INC R5,#1 ; Go to next address DBJNZ RL4,DPA_TOP ; Decrement char count RET TITLE "Monitor commands - Search" EJECT ; SEARCH Option. ; The search command locates a pattern of data in ; a specified section of memory. SEARCH: CALR _GETHEXR ; Get memory range to search in R2/R3 JR CAR,SRC_RET ; Err, return CLR R4 ; R4 is word count LDA R8,SCRBUF ; Get scratch space SRC_TOP: CALR _GETHEXV ; Get word to find JR CAR,SRC_RET LD R8(R4),R1 ; Save word in buffer INC R4,#2 ; Increment index CALR _NEXTPARM ; Any more words? JR CAR,SRC_CMP ; ..No, do the search CP R4,#60 ; At maximum number of words? JR NE,SRC_TOP ; ..No, get the next word SRC_CMP: SRL R4,#1 ; Make R4 index into count SRC_CMP2: LD R5,R2 ; Set-up CMP regs LD R6,R8 LD R7,R4 CPSIR @R5,@R6,R7,NE ; Inputed words equal to @R5 JR NZ,SRC_FOUND ; ..Yes, let us know INC R2,#2 ; Move ahead one word CP R2,R3 ; Passed end address? JR ULE,SRC_CMP2 ; ..No, compare at next address LDK R14,#ER_NOTFND ; Set error number SETFLG C JR SRC_RET ; That is all... SRC_FOUND: LDA R14,SRC_GOTIT ; Print found msg CALR _PRINTSTR LD R1,R2 ; Print address CALR _OUTHEX LD CURADDR,R2 ; Set prompt address INC R2,#2 ; move passed matched address LDA R14,CONT_MSG ; Message for continue CALR _ASKYES ; Continue the search? JR CAR,SRC_CMP2 ; ..Yes, do it again RESFLG C SRC_RET: RET TITLE "Monitor commands - Memory modifications" EJECT ; DEPOSIT Option. ; Sets memory to specified values starting at current address ; and following addresses until all values are deposited. DEPOSIT: CALR _GETHEXV ; R1 gets value JR CAR,DEP_RET ; ..Missing or bad value LD R2,CURADDR ; Get address LD @R2,R1 ; Set value INC CURADDR,#2 ; next address CALR _NEXTPARM ; Any more values? JR NC,DEPOSIT ; ..Yes RESFLG C ; Clear error flag DEP_RET: RET SKIP 6 ; FILL Option. ; Fills memory from specified start address to ending address ; with specified value. Fill does not change your current ; address. FILL: CALR _GETHEXR ; R2 is Start addr; R3 is End address JR CAR,FI_RET ; Bad hex .. ERR CALR _GETHEXV ; R1 gets fill-data value JR CAR,FI_RET ; Bad hex .. ERR FI_NEXT: LD @R2,R1 ; Deposit CP R2,R3 ; All filled ? JR EQ,FI_END ; Yes .. then quit INC R2,#2 ; Nope .. next address JR FI_NEXT ; and do it again FI_END: LDA R14,FI_MES ; Print END-OF-FILL msg CALR _PRINTSTR RESFLG C FI_RET: RET EJECT ; COPY Option. ; Block-moves memory contents between specified start and end ; addresses to specified destination address. Current address ; is not changed. COPY: CALR _GETHEXR ; R2 is start addr; R3 is end address JR CAR,CO_RET CALR _GETHEXV ; R1 gets dest address JR CAR,CO_RET RES R1,#0 ; Force to even address SUB R3,R2 ; Compute byte count SRL R3,#1 ; Make into word count INC R3,#1 ; R3 gets byte count LDIR @R1,@R2,R3 ; Do the copy LDA R14,MV_MES ; Print message CALR _PRINTSTR CO_RET: RET TITLE "Monitor commands - Compare memory" EJECT ; COMPARE memory. ; Compares the contents of memory between specified start and ; end address with the memory starting at the destination address. ; The current address is set to the mismatched address if ; a mismatch occurs. COMPARE: CALR _GETHEXR ; R2 is start addr; R3 is end address JR CAR,CM_RET CALR _GETHEXV ; R1 gets dest address JR CAR,CM_RET LD R4,R1 ; But use in R4 RES R4,#0 ; Force to even address SUB R3,R2 ; Compute byte count SRL R3,#1 ; Only half for words INC R3,#1 ; R3 gets byte count CM_TEST: CPSIR @R4,@R2,R3,NE ; Compare the memory JR NZ,CM_ERR ; Areas matched LDA R14,CM_NOT ; Print Not SAME message CALR _PRINTSTR LD R1,R4 ; Print Current Address DEC R1,#2 ; since already gone by... CALR _OUTMEM ; Print location LDK R1,#1 ; Print a blank CALR _PUTBLANK LD R1,R2 ; ..and other address DEC R1,#2 CALR _OUTMEM LDA R14,CONT_MSG ; Continue message CALR _ASKYES ; Continue? JR NC,CM_END ; ..Nope, that's all TEST R3 ; Any left? JR NZ,CM_TEST ; ..Yes CM_END: RESFLG C ; Clear error flag JR CM_RET CM_ERR: LDK R14,#ER_MATCH ; Match message SETFLG C ; Set error flag CM_RET: RET TITLE "Monitor commands - Load Intel binary" EJECT ; LOAD Option. ; Loads intel format binary from specified device to ; memory with optional offset. Load will continue to input ; from channel until an EOF record is seen, a loader error ; occurs or a break character is entered on the local channel. ; The format is: ; LOAD [] LOAD: LDA R14,CHAN_NAME ; Setup for _Numkeys CALR _NUMKEYS ; Get channel name JR CAR,LOA_RET ; ..Bad or missing LD R2,R1 ; R2 gets channel number CLR R1 ; Set default offset CALR _NEXTPARM ; Offset specified? JR CAR,LOA_TOP ; ..No, use default CALR _GETHEXV ; Get loader offset JR CAR,LOA_RET ; ..Bad offset, err! LOA_TOP: LD LD_OFFSET,R1 ; Set loader offset LD R3,R2 ; R3 gets channel number SLL R3,#1 ; Make into index LD R3,X8250MCR(R3) ; R3 -> MCR of channel INB RL4,@R3 ; Get MCR SETB RL4,#CTS ; Set CTS OUTB @R3,RL4 LOA_INTEL: LD R14,R2 ; R14 is load port CALR _INCHAR ; Try for character JR CAR,LOA_LCL ; ..None, test local channel CPB RH1,#":" ; Got a ":" JR NE,LOA_LCL ; ..No, test local channel CALR _LOADER ; Load an Intel record JR CAR,LOA_END ; ..Error or EOF record LOA_LCL: LD R14,#LCLCHAN ; R14 is local channel CALR _INCHAR ; Try for character JR CAR,LOA_INTEL ; ..None, back to the top CPB RH1,#BRK ; Is it a break char? JR NE,LOA_INTEL ; ..No, up you go LOA_END: RESFLG C ; Clear error flag RESB RL4,#CTS ; Reset CTS OUTB @R3,RL4 LOA_RET: RET TITLE "Monitor commands - Set" EJECT ; SET Option. ; This option allows you to set the FCW, the system SP ; the normal SP or the saved PC. You can also set any of ; the following FCW bits individually: System, VI, NVI, ; C, Z, S, PV, DA or H. Any register or debug parameter ; is also setable. Any combination of items may be set at ; one time. ; The format is: ; Set [] where is either a ; single FCW bit name or an assignment of a single hex ; value to the "FCW", the "PC", the "SP", the "NSP" or ; any register "R0" thru "R14". An may also be ; an assignment of a single value or range to any Debug ; parameter "L0" thru "L7", "B0" thru "B7" or "T0" ; thru "T7". SET: LDA R14,FCW_KW ; Look-up fcw flags CALR _KEYWORDS JR CAR,SET_ITM ; ..Not one of those LD R2,GO_FCW ; Get saved FCW SET R2,R1 ; Set bit according to the Keyword token LD GO_FCW,R2 ; Resave FCW JR SET_NEXT ; Do next parm SET_ITM: LDA R14,ITM_NAMES ; Look-up numbered items CALR _NUMKEYS JR CAR,SET_RET ; ..None found, ERR! LD R5,R2 ; R5 is Numkey index LD R4,R1 ; R4 is Item number LDK R1,#1 ; Find an "=" CALR _FINDDEL JR CAR,SET_RET ; ..Not found CP R5,#TK_REGS ; Is Numkey a single value item? JR NE,SET_DBG ; ..No, it's a debug parm CALR _GETHEXV ; Get value in R1 JR CAR,SET_RET ; ..Bad hex SET_REG: SLL R4,#1 ; Make item number into word index LD USERREGS(R4),R1 ; Save value JR SET_NEXT ; Get next item SET_DBG: CALR _GETHEXRV ; Get range or value JR CAR,SET_RET ; ..bad input SLL R4,#2 ; Make item number into 2 word index SLL R5,#1 ; Make item type into word index LD R5,DBG_ADDR(R5) ; R5 gets address of table LD R5(R4),R2 ; Save first value of range INC R4,#2 LD R5(R4),R3 ; Save second value SET_NEXT: CALR _NEXTPARM ; Any more parms? JR NC,SET ; ..Yes, do it again RESFLG C ; Clear error flag SET_RET: RET ; That's all! TITLE "Monitor commands - Clear" EJECT ; CLEAR Option. ; The clear option allows you to clear any flag settable ; by the Set option or any debug parameter or any register. ; The format is: ; Clear [] where item is defined under ; the Set option. CLEAR: LDA R14,FCW_KW ; Look-up fcw keywords CALR _KEYWORDS JR CAR,CLR_ITM ; ..Not an FCW keyword LD R2,GO_FCW ; Get saved FCW RES R2,R1 ; Clear bit LD GO_FCW,R2 ; Resave FCW JR CLR_NEXT ; Get next parameter CLR_ITM: LDA R14,ITM_NAMES ; Look-up numbered items CALR _NUMKEYS JR CAR,CLR_RET ; ..None found, ERR! CP R2,#TK_REGS ; Was it a register? JR NE,CLR_DBG ; ..No CLR_REG: SLL R1,#1 ; Make R1 into an index CLR USERREGS(R1) ; Clear register JR CLR_NEXT ; Get next parm CLR_DBG: SLL R1,#2 ; Make R1 into range index SLL R2,#1 ; Make type into index LD R2,DBG_ADDR(R2) ; R2 -> address of saved ranges ADD R2,R1 ; R2 -> address of item to clear CLR @R2 ; Clear first value INC R2,#2 CLR @R2 ; Clear second value CLR_NEXT: CALR _NEXTPARM ; Any more parms? JR NC,CLEAR RESFLG C ; Clear error flag CLR_RET: RET ; That's all TITLE "Monitor commands - Show" EJECT ; SHOW Option ; The show option lets you examine the saved FCW, ; the user registers or the debug parameters Limits, ; breakpoints and trace. The X8250 I/O channels ; may also be examined. ; The format is: ; SHOW [] SHOW: LDA R14,SHOW_KW ; Look-up parm name CALR _KEYWORDS JR CAR,SHW_RET ; ..Invalid name LD R2,SHW_TABLE(R1) ; Get address of Show routine SRL R1,#1 ; Change R1 to Byte index CALL @R2 ; Show whatever. CALR _PUTCRLF ; Newline CALR _NEXTPARM ; Any more parameters? JR NC,SHOW ; ..Yes, do it again RESFLG C ; Clear error flag SHW_RET: RET SHW_TABLE: DC SHW_DBG,SHW_DBG,SHW_DBG,SHW_REGS,SHW_PSW DC SHW_HIST,SHW_CHAN ; Dump the FCW SHW_PSW: LDA R14,PSWHEAD ; Print heading CALR _PRINTSTR LDK R2,#15 ; R2 is bit # in FCW LD R1,GO_FCW ; R1 gets saved FCW SHW_BTOP: LDA R14,ZERO_LIT ; Ready to print "0 " BIT R1,R2 ; Test FCW bit (R2) JR ZER,SHW_BIT ; ..Print "0 " LDA R14,ONE_LIT ; Change to Print "1 " SHW_BIT: CALR _PRINTSTR ; Print state DEC R2,#1 ; Go to next bit JR PL,SHW_BTOP ; ..Next bit if R2>=0 CALR _OUTHEX ; Now show FCW in hex LD R1,GO_PC ; Show the saved PC CALR _OUTHEX LD R1,USERREGS+30 ; Get user 'system' stack CALR _OUTHEX LD R1,USERREGS+32 ; Show the 'normal' stack CALR _OUTHEX CALR _PUTCRLF RET ; Dump the registers SHW_REGS: CALR _PRTHEAD ; Print Heading using R1 LDK R3,#15 ; RL3 is count CLR R2 ; R2 is index SHW_RTOP: LD R1,USERREGS(R2) ; Get value of register CALR _OUTHEX ; Print it INC R2,#2 ; go to next reg DBJNZ RL3,SHW_RTOP ; ..Until RL3=0 CALR _PUTCRLF RET ; Dump the specified Debug parameters SHW_DBG: CALR _PRTHEAD ; Print heading using R1 SLL R1,#1 ; Make R1 into word index LD R4,DBG_ADDR(R1) ; R4 is base address of Ranges LDK R3,#8 ; R3 is number to dump CLR R2 ; R2 is Dbg index SHW_DTOP: LDL RR6,R4(R2) ; Get start & end value in R6,R7 TESTL RR6 ; Is start & end zero? JR NZ,SHWDP_OK ; ..No, print it out LDA R14,DBG_DIS ; Print disabled message CALR _PRINTSTR JR SHWDP_BOT ; Do next range SHWDP_OK: LD R1,R6 CALR _OUTHEXW ; Outhex R1 LDB RH1,#"/" CALR _PUTLCHAR LD R1,R7 ; Display end value CALR _OUTHEXW ; Outhex R1 SHWDP_BOT: CPB RL3,#1 ; At end of list? JR EQ,SHWDP_TST ; ..Yes, no trailing blank LDK R1,#1 ; Print a blank CALR _PUTBLANK SHWDP_TST: INC R2,#4 ; R2 -> next range values DBJNZ RL3,SHW_DTOP ; Do again unless no more CALR _PUTCRLF ; Newline RET ; Show the PSW history, Instruction count and ; instruction count limit. SHW_HIST: LDA R14,HIST_HEAD+2 ; Print PSW history heading CALR _PRINTSTR ; R14 -> "FCW PC" LD R2,#7 ; Print heading 7 more times LDA R14,HIST_HEAD ; R14 -> " FCW PC" SHWH_HD: CALR _PRINTSTR ; Print it DJNZ R2,SHWH_HD ; ..seven times CALR _PUTCRLF CLR R2 ; Which to print first LDL RR6,INST_RCNT ; Get the count ADDL RR6,INST_TCNT ; Add in total count CPL RR6,#8 ; At least 9 executed? JR ULT,SHWH_DUMP ; ..No LD R2,R7 AND R2,#'07'H ; Which to print first SHWH_DUMP: SUBL RR4,RR4 ; Test for all printed SHWH_TOP: CPL RR4,RR6 ; printed all saved PSW's? JR ULT,SHWH_OK ; ..No, print this one LDA R14,DBG_DIS ; Print "...." CALR _PRINTSTR JR SHWH_BOT ; Next PSW SHWH_OK: LD R3,R2 ; R3 now gets which next AND R3,#'07'H SLL R3,#2 ; Make into Long index LD R1,SAVE_HIST(R3) ; Get fcw CALR _OUTHEXW ; Print it LDB RH1,#";" CALR _PUTLCHAR LD R1,SAVE_HIST+2(R3) ; Get Pc CALR _OUTHEXW ; Print PC INC R2,#1 ; Update whose next SHWH_BOT: CP R5,#7 ; End of PSW's? JR EQ,SHWH_TST ; ..Yes, no trailing blank LDK R1,#1 ; Print 1 blank CALR _PUTBLANK SHWH_TST: ADDL RR4,#1 ; Next PSW CP R5,#8 ; Showed all PSW's? JR ULT,SHWH_TOP ; ..No, do the next one CALR _PUTCRLF LDA R14,INSTCNTHD ; Print Instruction count Hd CALR _PRINTSTR LDL RR2,RR6 ; Print the total count CLR R0 ; Width of print field CALR _OUTDECL LDA R14,INSRCNTHD ; Print recent count CALR _PRINTSTR LDL RR2,INST_RCNT CALR _OUTDECL LDA R14,INSTLIMHD ; Print limit heading CALR _PRINTSTR LDL RR2,INST_LIM ; Print the limit TESTL RR2 ; Is it zero? JR NZ,SHWH_VAL ; ..no LDA R14,INSTLIMLB ; Print "no limit" message CALR _PRINTSTR JR SHWH_LLB SHWH_VAL: CALR _OUTDECL ; Print limit SHWH_LLB: CALR _PUTCRLF RET ; Show the configuration of the Channels SHW_CHAN: LDA R14,CHANHEAD ; Print the heading CALR _PRINTSTR CLR R2 ; R2 is the Channel index SHWCH_TOP: LD R14,CHANNAME(R2) ; Print channel name CALR _PRINTSTR LD R6,X8250LCR(R2) ; R2 -> LCR INB RL5,@R6 ; RL5 gets LCR SETB RL5,#DLAB ; Set DL access bit OUTB @R6,RL5 LD R14,X8250DLLS(R2) ; R14 -> DLLS port INB RL1,@R14 ; RL1 gets LS divisor byte INC R14,#1 ; R14 -> DLMS port INB RH1,@R14 ; RH1 gets MS divisor byte RESB RL5,#DLAB ; Clear DL access bit OUTB @R6,RL5 LDK R0,#6 ; Field width for _Outdec CALR _OUTDECW ; Print divisor in Decimal LDA R3,DIVISORS+14 ; R3 -> Known divisors LDK R4,#8 ; R4 is number of bauds CPDR R1,@R3,R4,EQ ; Look for divisor in Table JR NZ,SHWCH_HUH ; ..Not found SLL R4,#1 ; Count changed to word index LD R1,BAUDS(R4) ; R1 gets baud rate for print LDK R0,#7 ; Field width CALR _OUTDECW ; Print baud rate JR SHWCH_PTY SHWCH_HUH: LDA R14,BAUDBAD ; Print for unknown baud CALR _PRINTSTR SHWCH_PTY: CLRB RH1 LDB RL1,RL5 ; RL1 gets RL5 (Saves RL5) ANDB RL1,#'00011000'B ; Remove all but parity SRLB RL1,#2 ; R1 is index to parity LD R14,CHANPRTY(R1) ; Print parity CALR _PRINTSTR LDB RL1,#1 ; Stop bits default BITB RL5,#SBITS ; Two stop bits? JR ZER,SHWCH_SB ; ..No, one LDB RL1,#2 ; Two sbits SHWCH_SB: LDK R0,#6 ; Field width CALR _OUTDECW ; Print sbits ANDB RL5,#'00000011'B ; Remove all but wlen ADDB RL5,#5 ; Wlen of 5 when RL3 = 0 LDB RL1,RL5 ; Print Wlen LDK R0,#7 ; Field width CALR _OUTDECW LD R14,X8250PTCL(R2) ; R14 get protocol type SLL R14,#1 ; Make into word index LD R14,CHANPTCL(R14) ; R14 -> protocol literal CALR _PRINTSTR CALR _PUTCRLF INC R2,#2 ; Next channel CP R2,#X8250NUM*2 ; Passed last channel? JR ULT,SHWCH_TOP ; ..No, show the next RET TITLE "Monitor commands - Configure" EJECT ; CONFIGURE Option. ; This command allows the X8250 serial I/O channels ; to be reconfigured. The settable parameters are ; Divisor, Baud, Parity, Stop bits, Word length and ; Protocol for each channel. CONFIGURE: LDA R14,CHAN_NAME ; Get channel name to configure CALR _NUMKEYS JR CAR,CONF_RET ; ..Bad name, ERR LD R9,R1 ; R9 is channel number*2 SLL R9,#1 LD R6,X8250LCR(R9) ; R6 -> LCR of channel INB RL5,@R6 ; RL5 holds LCR value LD R8,X8250DLLS(R9) ; R8 -> DLLS of channel CONF_PARM: LDA R14,CONF_KW ; Parm Keywords CALR _KEYWORDS ; Look-up entered keyword JR CAR,CONF_RET ; Bad keyword, ERR LD R3,R1 ; R3 is action to take LDK R1,#1 ; Delimiter "=" CALR _FINDDEL ; Look for it JR CAR,CONF_RET ; ..Misssing "=", ERR CONF_WLEN: CP R3,#TK_CFWLEN ; Set word length? JR NE,CONF_SBIT ; ..No CALR _GETHEXV ; Get length JR CAR,CONF_RET ; ..Bad hex value DEC R1,#5 ; zero value is length 5... CP R1,#3 ; 3 is length 8 (max) JR UGT,CONF_BAD ; ..Bad length, ERR ANDB RL5,#'11111100'B ; Zero old length value ORB RL5,RL1 ; set new length JR CONF_NEXT CONF_SBIT: CP R3,#TK_CFSBIT ; Set stop bits? JR NE,CONF_PRTY ; ..No CALR _GETHEXV ; Get number of bits JR CAR,CONF_RET ; ..Bad hex value DEC R1,#1 ; Zero value is 1 bit CP R1,#1 ; Too big? JR UGT,CONF_BAD ; ..Yes SLL R1,#2 ; Move to correct field ANDB RL5,#'11111011'B ; Zero old bit number ORB RL5,RL1 ; Set new bit number JR CONF_NEXT CONF_PRTY: CP R3,#TK_CFPRTY ; Set parity? JR NE,CONF_BAUD ; ..No LDA R14,CONF_PYKW ; Look-up parity keyword CALR _KEYWORDS JR CAR,CONF_RET ; ..Bad parity, ERR SLL R1,#3 ; Move to correct field ANDB RL5,#'11100111'B ; Zero old parity value ORB RL5,RL1 ; Set new parity JR CONF_NEXT CONF_BAUD: CP R3,#TK_CFBAUD ; Set Baud? JR NE,CONF_DIV ; ..No CALR _GETDECV ; Get baud in decimal JR CAR,CONF_RET ; ..Bad value LDA R2,BAUDS+14 ; R2 -> known baud rate LDK R3,#8 ; number of known bauds CPDR R1,@R2,R3,EQ ; Look-up baud rate JR NZ,CONF_BAD ; Baud rate divisor is unknown SLL R3,#1 ; R3 indexes divisors LD R7,DIVISORS(R3) ; R7 gets divisor SETB RL5,#7 ; Set divisor access bit JR CONF_NEXT CONF_DIV: CP R3,#TK_CFDIV ; Set Divisor? JR NE,CONF_PTCL ; ..No CALR _GETDECV ; Get divisor in decimal JR CAR,CONF_RET ; ..Bad value, ERR LD R7,R1 ; R7 get divisor SETB RL5,#7 ; Set divisor access bit JR CONF_NEXT CONF_PTCL: LDA R14,CONF_PTKW ; Look-up protocal CALR _KEYWORDS JR CAR,CONF_RET ; ..Bad protocal LD X8250PTCL(R9),R1 ; Set protocal CONF_NEXT: CALR _NEXTPARM ; Any more parms? JR NC,CONF_PARM ; ..Yes RESFLG C ; No, clear error flag OUTB @R6,RL5 ; Set LCR in case of change BITB RL5,#7 ; Is divisor access bit set? JR ZER,CONF_RET ; ..No OUTB @R8,RL7 ; Set divisor latch INC R8,#1 OUTB @R8,RH7 RESB RL5,#7 ; Clear access bit OUTB @R6,RL5 ; Reset LCR JR CONF_RET CONF_BAD: LDK R14,#ER_BADKEY ; Bad parm error SETFLG C ; Set error flag CONF_RET: RET TITLE "Monitor commands - Execute & Continue" EJECT ; EXECUTE Option. ; Executes loaded object at the specified address. Other ; legal parameters are Load which specifies whether the ; saved FCW and registers should be unsaved before executing. ; System, Normal, VI, NoVI, Debug and No debug may also be ; specified which set or reset an FCW bit. If non of these ; parameters are entered, and load was not a parameter, the ; monitor will set the FCW to all zeros except the system bit. EXEC: CALR _GETHEXV ; Get Exec address JR CAR,EXE_RET ; ..Bad address, Err LD R4,R1 ; Save Exec address in R4 CALR ECPARMS ; Get Exec parms JR NC,EXE_OK ; ..No errors, go on. EXE_RET: RET EXE_OK: LD GO_PC,R4 ; Update PC for LDPS SET BIT_FLAGS,#EXEFLG ; Set OK to continue flag SET BIT_FLAGS,#EXELAST ; Set Execute done flag RES BIT_FLAGS,#CONTFLG ; Clear continue flag BIT BIT_FLAGS,#EXELOAD ; Said to LOAD? JR NZ,EXE_LOAD ; ..Yes LD R3,GO_FCW ; Get saved FCW AND R3,R2 ; Zero bits not specified BIT R2,#TK_SYSFLG ; Modified System bit? JR NZ,EXE_SVFCW ; ..Yes, don't touch it! SET R3,#TK_SYSFLG ; No, so force system mode. EXE_SVFCW: LD GO_FCW,R3 ; Save fixed FCW LD USERREGS+32,#USERNORM ; Init user 'user' stack LD USERREGS+30,#USERSYS ; Init user 'system' stack EXE_LOAD: SUBL RR0,RR0 ; Scr reg LDL INST_RCNT,RR0 ; Clear instruction count LDL INST_TCNT,RR0 LD R1,USERREGS+32 ; Load user normal stack LDCTL NSP,R1 LDM R0,USERREGS,#16 ; Unsave user registers LDPS GOPSW ; EXECUTE!!!! EJECT ; CONTINUE Option. ; Continue executing after a breakpoint or trap. ; The same parameters may be entered on Continue that ; are allowed on Execute. The difference being that ; continue always Loads the user savearea. CONTINUE: BIT BIT_FLAGS,#EXEFLG ; Allowed to continue? JR ZER,CNT_ERR ; ..Yes CALR ECPARMS ; Any parms? JR CAR,CNT_RET LDL RR0,INST_RCNT ; Add recent count to total ADDL RR0,INST_TCNT LDL INST_TCNT,RR0 SUBL RR0,RR0 ; Scr reg LDL INST_RCNT,RR0 ; Zero recent count LD R1,USERREGS+32 ; Load user normal stack LDCTL NSP,R1 LDM R0,USERREGS,#16 ; Restore user regs SET BIT_FLAGS,#EXELAST ; Set 'Execute' flag SET BIT_FLAGS,#CONTFLG ; Set continue flag LDPS GOPSW CNT_ERR: LDK R14,#ER_CANTCN ; Set can't continue error SETFLG C CNT_RET: RET TITLE "Monitor commands - Execute & Continue subroutines" EJECT ; ECPARMS internal subroutine. ; Sets or clears specified bits in the GO_FCW. Ecparms ; also sets a bit in R2 if the corrisponding bit was ; modified in the FCW. ECPARMS: CLR R2 ; Clear modified flags CALR _NEXTPARM ; Any parms? JR CAR,EC_END ; ..No, return RES BIT_FLAGS,#EXELOAD ; Clear Load flag EC_TOP: LDA R14,ECPARM_KW ; Look-up parm keywords CALR _KEYWORDS JR CAR,EC_RET ; ..Errors CPB RL1,#TK_ECLOAD ; Said LOAD? JR NZ,EC_DEBUG ; ..Not LOAD SET BIT_FLAGS,#EXELOAD ; Set LOAD flag JR EC_NEXT ; ..Next parm EC_DEBUG: CPB RL1,#TK_ECDEB ; Said DEGUG? JR NE,EC_FCWSET ; ..Not debug CALR _GETDECLV ; Try for instruction limit JR CAR,EC_DBGBAD ; ..Maybe LDL INST_LIM,RR2 ; Save limit JR EC_FCWSET EC_DBGBAD: CP R14,#ER_TOOBIG ; Number but too large? JR EQ,EC_BAD ; ..Yes, ERR SUBL RR2,RR2 ; No limit specified LDL INST_LIM,RR2 ; Zero instruction limit EC_FCWSET: LD R3,GO_FCW ; Get FCW TESTB RL1 ; Test returned token JR MI,EC_FCWCLR ; Minus token is Clear bit SET R3,R1 ; Set FCW bit JR EC_SAVE EC_FCWCLR: NEG R1 ; Make minus token positive RES R3,R1 ; Clear FCW bit EC_SAVE: SET R2,R1 ; Set Modified bit LD GO_FCW,R3 ; Save FCW EC_NEXT: CALR _NEXTPARM ; Any more parms? JR NC,EC_TOP ; ..Yes, get them EC_END: RESFLG C ; Clear error flag JR EC_RET EC_BAD: SETFLG C ; Set error flag EC_RET: RET ; Back to Exec or Cont TITLE "Modem; Transparent Mode" EJECT ; Transparent mode ; This command gets input from the local and remote ports ; and transfers it to the opposite port. ; Special characters: ; ESC ":" - Invokes intel loader for one record (Remote only) ; ESC "8" - Enables the printer on LPCHAN ; ESC "9" - Disables the printer ; CNTL P - Sends break to remote port (Local only) ; RUBOUT - Return to Command mode (Local only) ; Register usage: ; R14 - Linkage with Printstr, Inchar & Outchar ; R6 - Modem flags ; R5 - Buffer OUT pointer to remote port ; R4 - Buffer IN pointer to remote port ; R3 - Buffer OUT pointer to local port ; R2 - Buffer IN pointer to local port ; R1 - Scratch MODEM: LDA R15,MONSTACK ; Re-init stack. Modem JP's back MDRESTART: CALR MD_STATUS ; Modem available JP CAR,MD_UNAVAL ; ..No LD RESTART,#MDRESTART ; Set restart address LDA R14,MOD_MSG ; Print Modem message CALR _PRINTSTR LD RESTART,#MDRESTART ; Set Restart address SUBL RR2,RR2 ; Clr local In ptr & out ptr SUBL RR4,RR4 ; Clr remote In ptr & out ptr CLR R6 ; Clear flags ; Read character from modem (remote) MD_RRMT: CALR MD_STATUS ; Modem still there? JP CAR,MD_LOST ; ..No LDK R14,#RMTCHAN CALR _INCHAR ; Try to get a char on remote JR CAR,MD_WRMT ; ..none there CPB RH1,#ESC ; Got an ESC? JR NE,MD_RRB ; ..No BIT R6,#ESCFLG ; Was last char an ESC? JR NZ,MD_RRCLR ; ..Yes, buffer 2 ESC's SET R6,#ESCFLG ; No so set the 'saw ESC' flag JR MD_WRMT ; Now write remote MD_RRB: BIT R6,#ESCFLG ; Last char was ESC? JR ZER,MD_RRC ; ..No, buffer char CPB RH1,#":" ; Should loader be invoked. JR NE,MD_RRCLR ; ..No, buffer ESC & char CALR _LOADER ; Load Intel record JR NC,MD_LDOK ; ..No errors/No EOF record CP R0,#LD_EOFNUM ; EOF record? JR EQ,MD_LDOK ; ..Yes, don't send break CALR _PUTBRK ; Send break on error MD_LDOK: RES R6,#ESCFLG ; Clear ESC flag JR MD_WRMT MD_RRCLR: RES R6,#ESCFLG ; Clear ESC flag LDB MD_LBUF(R2),#ESC ; Buffer ESC that was delayed INC R2,#1 ; Update Local IN ptr AND R2,#MDLBUFMOD MD_RRC: LDB MD_LBUF(R2),RH1 ; Buffer char INC R2,#1 ; Update Local IN ptr AND R2,#MDLBUFMOD ; Write to modem (remote) MD_WRMT: CP R4,R5 ; Remote buffer empty? JR EQ,MD_RLCL ; ..Yes, read local LDB RH1,MD_RBUF(R5) ; Output char to remote CALR _OUTCHAR ; Try to send char JR CAR,MD_RLCL ; ..Couldn't INC R5,#1 ; Update Remote OUT ptr AND R5,#MDRBUFMOD ; Read from local port MD_RLCL: LDK R14,#LCLCHAN CALR _INCHAR ; Try to get a char JR CAR,MD_WLCL ; ..none there CPB RH1,#RUBOUT ; Return to Monitor? JR EQ,MD_RET ; ..Yes on a RUBOUT CPB RH1,#BRK ; Send Break? JR NE,MD_RLB ; ..No LDK R14,#RMTCHAN ; Channel to send break to CALR _PUTBRK ; Send break SUBL RR2,RR2 ; Kill local buffer RES R6,#MDLP_ON ; Disable the printer JR MD_WLCL ; Don't buffer break char MD_RLB: LDB MD_RBUF(R4),RH1 ; Buffer char INC R4,#1 ; Update Remote IN Ptr AND R4,#MDRBUFMOD ; Write to local port MD_WLCL: CP R2,R3 ; Local buffer empty? JR EQ,MD_RRMT ; ..Yes, read remote LDB RH1,MD_LBUF(R3) ; Output char to local BIT R6,#MDLP_ON ; Printer enabled? JR ZER,MD_WLCLO ; ..No, send to terminal CPB RH1,#CNTRL_Z ; LP toggle flag JR NE,MD_WLCLQ ; ..No RES R6,#MDLP_ON ; Disable LP JR MD_WLCLX ; Throw away CNTRL_Z MD_WLCLQ: CPB RH1,#CNTRL_Q ; Found a CNTRL Q? JR NE,MD_WLCLA ; ..No, send to LP LDB RH1,#CR ; Send CR to remote LDK R14,#RMTCHAN ; R14 is remote channel CALR _OUTCHAR ; Send CR JR CAR,MD_RRMT ; ..couldn't JR MD_WLCLX ; Throw CNTRL Q away MD_WLCLO: CPB RH1,#CNTRL_Z ; Printer toggle JR NE,MD_WLCLB ; ..No, try to print SET R6,#MDLP_ON ; Enable LP JR MD_WLCLX ; Throw CNTRL_Z away MD_WLCLA: LDK R14,#LPCHAN*2 LD R14,X8250MSR(R14) ; R14 -> MSR INB RH0,@R14 ; RH0 gets MSR BITB RH0,#DTR ; Printer ready? JR ZER,MD_RRMT ; ..No, forget it all! CALR MD_PREXPN ; Expand blanks LDK R14,#LPCHAN ; R14 -> LP channel CALR _OUTCHAR ; Try to put to LP JR CAR,MD_RRMT ; ..Lp not willing MD_WLCLB: LDK R14,#LCLCHAN CALR _OUTCHAR ; Try to send char JR CAR,MD_RRMT ; ..Couldn't MD_WLCLX: INC R3,#1 ; Update Local OUT ptr AND R3,#MDLBUFMOD JR MD_RRMT ; Do it all again... ; Expand compressed blank control letters for ; printer. (U,V,W,X,Y) to (2,4,8,16,32). MD_PREXPN: CPB RH1,#MD_EXPNLO ; If not a good one JR ULT,MD_PRXRET ; ..Nope CPB RH1,#MD_EXPNHI ; Well, good? JR UGT,MD_PRXRET ; ..No LDB RL1,RH1 ; Convert chr to " " count CLRB RH1 SUB R1,#MD_EXPNLO-1 ; Normalize to 1 CLR R0 SET R0,R1 ; R0 is blank count DEC R0,#1 LDB RH1,#" " LDB MD_LBUF(R3),RH1 ; Cover cntrl char MD_PRXLP: DEC R3,#1 ; Fill queue with blanks AND R3,#MDLBUFMOD LDB MD_LBUF(R3),RH1 DJNZ R0,MD_PRXLP MD_PRXRET: RET ; Subroutine MD_STATUS ; Tests the modem status register for a Received line signal ; detect. Sets the C flag if false, resets C if true. MD_STATUS: LDK R14,#RMTCHAN*2 LD R1,X8250MSR(R14) ; Get modem status INB RL1,@R1 BITB RL1,#RLSD ; Signal detected by modem? JR ZER,MDS_ERR ; ..No, err RESFLG C ; Clear error flag JR MDS_RET MDS_ERR: SETFLG C ; Set error flag MDS_RET: RET MD_LOST: CALR _PUTCRLF MD_UNAVAL: LDA R14,MOD_GONE ; Print modem not available Msg CALR _PRINTSTR MD_RET: CALR _PUTCRLF JP COMMAND ; Back to the top TITLE "_LOADER - Intel loader procedure" EJECT ; Procedure _LOADER ; Loads a single intel "paper tape" record ; This routine should not be invoked until the colon of the ; Intel record has been seen. This loader then inputs the ; remaining Intel record from the channel number specified ; in R14. The loader will set a return flag and a return code ; before returning. If the return flag is cleared, the code ; is not defined. ; The return codes are: ; 0 - EOF encountered ; 1 - Break character on Local channel ; 2 - Loader error ; If A) A bad hex digit is found in the load record, ; or B) A checksum error occurs ; then loader aborts by ; 1) Sending break to the remote port to halt the host program, ; and 2) Printing an error message at the local port. ; The format of an Intel record is as follows: ; :LLAAAARRDDDDDD ... DDCC ; Where LL is the number of data bytes in the line. ; AAAA is a word address field. ; RR is the byte record type. ; DD is a data byte (in data records only). ; and CC is the byte checksum of the complete record. ; All items in a record are in printable Hex. ; Valid records type are: ; 00 is a data record with the address field containing ; the address of the first byte. ; 01 is an End Of Record with the address field containing ; either zero or a "GO" address. ; 02 is an offset record with the address field containing ; the offset. The offset is cleared during a hardware ; Reset or after an EOF record. ; Register Usage: ; R14 - Channel pointer ; R6 - Channel kept here ; R5 - Offset address ; R4 - Checksum counter ; R3 - Address of record ; R2 - Byte counter. (Number of data bytes in a record) ; R1 - Parameter passage ; R0 - Return code _LOADER: PUSH @R15,R14 ; save 'em PUSH @R15,R13 DEC R15,#12 LDM @R15,R1,#6 LD R6,R14 ; Save Channel number ; Load start .. beginning of record found LD_START: LD R5,LD_OFFSET ; Get loader offset CLR R4 ; Clear checksum ; Data-byte count CALR LD_HEX ; R1 gets data byte count JR CAR,LD_ERR LD R2,R1 ; Data byte counter ; Load address CALR LD_HEX ; R1 gets high address JR CAR,LD_ERR LDB RH3,RL1 ; Set high address CALR LD_HEX ; R1 gets low address JR CAR,LD_ERR LDB RL3,RL1 ; Addr complete in R3 ; Record type CALR LD_HEX ; R1 gets intel record type JR CAR,LD_ERR TESTB RL1 ; Test for Data record JR ZER,LD_DATA ; ..Was a data record CPB RL1,#1 ; Is it an EOF record? JR EQ,LD_EOF ; ..Yes CPB RL1,#2 ; Is it a relocation record? JR EQ,LD_OFF ; ..Yes, set offset LDA R14,LD_TYPMSG ; Ready bad record type message JR LD_ERR2 ; Set loader offset LD_OFF: CALR LD_HEX ; Get checksum byte JR CAR,LD_ERR ; ..Bad hex chars LD LD_OFFSET,R3 ; Save record address as offset JR LD_EXIT ; That's all! ; Act upon EOF record LD_EOF: CALR LD_HEX ; Get checksum for EOF JR CAR,LD_ERR CLR LD_OFFSET ; Clear loader offset on EOF LDA R14,LD_EOFMSG CALR _PRINTSTR TEST R3 ; Valid exec address ? JR ZER,LD_EOFB ; No .. trans mode LDA R14,LD_GOMSG ; Yes .. message & go CALR _PRINTSTR LD R1,R3 CALR _OUTHEX LD_EOFB: CALR _PUTCRLF LDK R0,#LD_EOFNUM ; Set EOF return code JR LD_EXITX ; Back to transparent mode ; Load-data loop .. byte count in R2 .. load address in R3 LD_DATA: TEST R2 ; Do while R2 > 0 JR ZER,LD_CKSUM CALR LD_HEX ; R1 gets data JR CAR,LD_ERR LDB R5(R3),RL1 ; Load a byte into memory INC R3,#1 ; Next address DEC R2,#1 ; Byte count ; Test for Break char from local port LDK R14,#LCLCHAN CALR _INCHAR ; Character on local port? JR CAR,LD_DATA ; ..No CPB RH1,#BRK ; Is it the break char? JR NE,LD_DATA ; ..No, continue loading LDK R0,#LD_BRKNUM ; Set return code JR LD_EXITX ; Leave this loader! ; Data-load complete .. read and verify checksum LD_CKSUM: CALR LD_HEX ; R1 gets checksum JR CAR,LD_ERR TESTB RL4 ; Good checksum = 0 JR ZER,LD_EXIT ; Good checksum .. quit LDA R14,LD_CKSERR ; Error .. ERR msg address JR LD_ERR2 ; Loader errors .. print message & quit LD_ERR: LDA R14,LD_ERRMSG ; Msg address LD_ERR2: CALR _PUTCRLF ; New line CALR _PRINTSTR ; Msg to local port CALR _PUTCRLF LDK R0,#LD_ERRNUM ; Set return code LD_EXITX: SETFLG C ; Set return flag JR LD_RET LD_EXIT: RESFLG C ; Clear return flag LD_RET: LDM R1,@R15,#6 ; get 'em back INC R15,#12 POP R13,@R15 POP R14,@R15 RET TITLE "Intel loader - subroutines" EJECT ; Internal loader proc ; Get 2 hex digits from remote line & return value in R1 LD_HEX: LD R14,R6 ; R14 -> Intel channel CALR _GETCHAR ; 1ST digit in RH1 LDB SCRBUF,RH1 ; Store in buffer CALR _GETCHAR ; 2ND digit in RH1 LDB SCRBUF+1,RH1 ; 2ND digit to buffer LDB SCRBUF+2,#" " ; Mark end of ascii hex LDA R13,SCRBUF CALR _GETHEXV ; Hex value in R1 JR CAR,LDH_RET ; ..return on bad hex ADD R4,R1 ; Add byte to checksum LDH_RET: RET ; Done TITLE "_GETLINE Procedure" EJECT ; Procedure _GETLINE (Buffer ) ; Getline inputs characters from the local port and saves ; them in a buffer pointed to by R13. The buffer is assumed ; to be 64 bytes long. Getline prompts with a '> ' before ; excepting input. A delete character and cancel line function ; are also supported. The delete character causes one character ; to be deleted from the buffer and a backspace-space-backspace ; to be printed. The cancel deletes all characters in the input ; buffer by placing a carriage return at the beginning of the ; buffer. Cancel then sets the C flag and returns so that the ; calling routine may re-prompt and re-call Getline. The Break ; character also acts as a cancel line. Getline returns when ; a carriage return is received. The CR is saved in the input ; buffer as an end-of-buffer mark and the C flag cleared ; before returning. ; All registers are returned unmodified. ; Register usage: ; R1 - Used in Getchar/Putchar ; R2 - Current location in buffer ; R3 - Buffered character counter ; R13 - Buffer address passed to Getline ; R14 - Subroutine linkage _GETLINE: DEC R15,#6 ; Save Regs LDM @R15,R1,#3 LDA R14,GETPROMPT ; Print prompt CALR _PRINTSTR LD R2,R13 ; R2 -> Input buffer LD R3,#64 ; Buffer-left count GETLINCHR: LDK R14,#LCLCHAN ; Local port CALR _GETCHAR ; RH1 gets char CPB RH1,#DELETE ; Delete character? JR EQ,BACKSP ; Yes .. Backspace buffer CPB RH1,#CANCEL ; Cancel line? JR EQ,KILL ; Yes .. Kill line CPB RH1,#BRK ; Break character JR EQ,KILL ; ..Yes, cancel line CP R3,#1 ; Buffer full? JR EQ,GETLINOVL ; Yes.. So beep 'em CALR _PUTLCHAR ; Echo the character CPB RH1,#CR ; Carriage return ? JR EQ,GETLIN_CR ; Yes .. Wrap up CPB RH1,#" " ; Some other control letter? JR LT,GETLINCHR ; Yes .. Ignore ; Printable character seen .. Buffer it LDB @R2,RH1 ; Buffer the char INC R2,#1 ; New buffer position DEC R3,#1 ; Dec buffer-left count JR GETLINCHR ; Next character ; Backspace function BACKSP: CP R3,#64 ; Buffer empty ? JR EQ,GETLINCHR ; Yes .. So don't backspace LDA R14,GETLINBS ; Physical backspace CALR _PRINTSTR DEC R2,#1 ; Logical backspace .. Prev buf position INC R3,#1 ; Buffer size JR GETLINCHR ; Line-kill function KILL: LDA R14,GETLINKIL ; Physical line-kill CALR _PRINTSTR LDB @R13,#CR ; Make a CR the first char in buffer SETFLG C ; Set re-prompt flag JR GETLN_RET ; Buffer full .. Ring bell GETLINOVL: LDB RH1,#7 ; BELL CALR _PUTLCHAR JR GETLINCHR ; and carry on ; CR seen .. Wrap up GETLIN_CR: LDB @R2,RH1 ; Buffer CR LDB RH1,#LF ; New line CALR _PUTLCHAR RESFLG C ; Clear re-prompt flag GETLN_RET: POP R1,@R15 ; Restore regs POP R2,@R15 POP R3,@R15 RET ; Done TITLE "_KEYWORDS Procedure" EJECT ; Function _KEYWORDS (Keytable ,Literal )(Token ,Flag ) ; Keyword finds the literal @R13 in keytable @R14. The ; literal must be less than 255 chars in length and be ; terminated with a blank character found by "Findblank". The ; Keytable many contain up to 127 keywords, each consisting ; of <"keyword"> where ; Length, Minlen & Token are byte values. The table is terminated ; with a zero byte. Keywords in the table must be in uppercase. ; The Min len is the minimum number of characters long the ; literal must be to match the keyword. If the literal does ; not meet this requirement, the keyword is ignored. ; The literal may be in upper or lowercase. ; Returns: ; All registers are returned unchanged with the following ; exceptions: ; ; Literal Not Found: RL1 returns 0; RH1 returns 0; C flag ; is set. R13 is unchanged. R14 contains error #ER_BADKEY ; Literal Found: R1 returns token; R13 points to char ; following literal. The C flag is cleared. ; Register R14 -> zero byte at end of table. ; Literal is Ambiguous: RL1 returns token of first matched; ; RH1 returns 1; R13 is unchanged. The C flag is set ; and R14 contains error #ER_TWOKEY. ; No literal found: RL1 returns zero, RH1 returns zero. ; R13 -> CR at end of buffer. The C flag is set and ; R14 contains missing parameter error number. ; Register usage: ; R14 - Address of keytable ; R13 - Address of literal ; R6-R8 - Scratch ; R5 - Minimum chars in literal need to match ; R4 - Keyword length ; R3 - Length of literal ; R2 - Holds keyword token ; RH1 - Keyword 'matched' flag ; RL1 - Return value _KEYWORDS: DEC R15,#14 ; Save Regs. LDM @R15,R2,#7 CLR R1 ; Set RH1 to not found; Zero RL1 CALR _NEXTPARM ; Any parms? JR CAR,KW_RET ; ..No, error LD R3,R13 ; R3 -> input buffer ; Find end delimiter on literal KW_DELIM: CPB @R3,#" " ; Found a blank? JR EQ,KW_DELFND ; ..Yes CPB @R3,#"=" ; Found an = JR EQ,KW_DELFND ; ..Yes CPB @R3,#CR ; Found a CR JR EQ,KW_DELFND ; ..Yes INC R3,#1 ; No delimiter found, next char JR KW_DELIM ; Look again ; Delimiter found @R3 so get on with it. KW_DELFND: SUB R3,R13 ; R3 is literal length CLR R2 CLRB RH5 ; Clear upper byte of R5 CLRB RH4 ; Clear upper byte of R4 KW_TOP: LDB RL4,@R14 ; R4 contains keyword length TESTB RL4 ; At end of keytable? JR ZER,KW_DONE ; ..Yes, wrap-it-up ; Set-up for compare INC R14,#1 ; R14 -> Min length LDB RL5,@R14 ; R5 get min length INC R14,#1 ; R14 -> Keyword token LDB RL2,@R14 ; RL2 gets Keyword token INC R14,#1 ; R14 -> Keyword CP R3,R4 ; Literal longer than keyword? JR UGT,KW_NEXT ; ..Yes CP R3,R5 ; Is literal length < Min length? JR ULT,KW_NEXT ; ..Yes, go to next keyword LD R6,R14 ; Move values to scr regs for compare LD R7,R13 LD R8,R3 ; Compare literal with keyword KW_LOOP: CPB @R7,#"a" ; Check for lowercase JR LT,KW_CMP ; Less than "a" CPB @R7,#"z" JR GT,KW_CMP ; Greater than "z" RESB @R7,#5 ; Upcase char KW_CMP: CPSIB @R6,@R7,R8,NE ; Chars equal? JR ZER,KW_NEXT ; ..No, go to next keyword JR NOV,KW_LOOP ; Not done, next char TESTB RH1 ; Any previous match? JR NZ,KW_AMBIG ; ..Yes, ambiguous! LDB RL1,RL2 ; otherwise set RL1 to keyword token INCB RH1 ; Set 'Matched' flag ; Go to next keyword KW_NEXT: ADD R14,R4 ; R14 -> Next length value JR KW_TOP ; Compare next keyword ; Comparing completed KW_DONE: TESTB RH1 ; Any matches? JR ZER,KW_NOPE ; ..No, that's it EXTSB R1 ; Make all of R1 the token ADD R13,R3 ; R13 -> char after literal RESFLG C ; Clear return flag JR KW_RET ; Only one was found. KW_NOPE: LDK R14,#ER_BADKEY ; Set not found Error number JR KW_BAD KW_AMBIG: LDK R14,#ER_TWOKEY ; Set Ambiguous Error number KW_BAD: SETFLG C ; Ambiguous or not found KW_RET: LDM R2,@R15,#7 ; Restore regs INC R15,#14 RET TITLE "_NUMKEYS Procedure" EJECT ; Function _NUMKEYS (#Number,Letters,Largest)(Number,Index) ; This routine looks for a keyword @R13 of the format ; . Passed in is R14 ; pointing at 3 words (,
,
). The letters and ; the values are stored as bytes. ; Returns: ; If letter @R13 matches and number in range, C is ; cleared with R2=Index of the letter and R1=number ; following. R14 is unchanged. ; If letter not found or number out of range, C is ; set. R14 contains an error # _NUMKEYS: DEC R15,#10 ; Save regs. LDM @R15,R3,#5 CALR _NEXTPARM ; Any parms? JR CAR,NK_RET ; ..No, err! LD R7,R13 ; Save buffer pointer incase error LD R2,@R14 ; R2 gets number of letters LD R3,2(R14) ; R3 -> Letters LD R4,4(R14) ; R4 -> Max values LDB RL5,@R13 ; RL5 is letter to find RESB RL5,#5 ; Cheap upcase CPIRB RL5,@R3,R2,EQ ; Look for letter JR NZ,NK_OTHER ; ..No match SUB R2,@R14 ; Make R2 into letter index COM R2 INC R13,#1 ; R13 -> number CALR _GETHEXV ; Get number in R1 JR CAR,NK_OTHER ; Bad number! CP R1,#10 ; Cheap Dec to Hex fix JR LT,NK_NUMOK ; ..Number <10 hex DEC R1,#6 NK_NUMOK: CLRB RH6 ; Clear upper byte of RH6 LDB RL6,R4(R2) ; Get max number in R6 CP R1,R6 ; Is number > max? JR ULE,NK_END ; ..No, that's all NK_OTHER: LD R13,R7 ; Restore R13 pointer LDA R14,MISC_KW ; Look-up SP, NSP or FCW CALR _KEYWORDS JR CAR,NK_RET ; ..Not found, return bad parm LDK R2,#TK_REGS ; Return Register token NK_END: RESFLG C ; Clear error flag NK_RET: LDM R3,@R15,#5 ; Unsave regs. INC R15,#10 RET TITLE "_GETHEXRV Procedure" EJECT ; Function _GETHEXRV (Buffer)(Type,Values) ; This procedure attemps to get a range parm from ; the command buffer at R13. If it fails it tries for ; a single value parm. If that fails, it returns an ; error. ; Returns: ; All registers as sent except the following. ; Range found: R2 is start value, R3 is end value, ; R0 is cleared, C is cleared. ; Single value: R1,R2,R3 contain value, R0 equals 1, ; C is cleared. ; Neither found: R14 contains error #, C is set. ; ; R13 points to the char after the parm in the first 2 cases, ; but is not changed if neither is found. _GETHEXRV: PUSH @R15,R14 ; Save R14 incase No error PUSH @R15,R13 ; Save R13 for range try CALR _GETHEXV ; Try for single parameter. POP R13,@R15 JR CAR,GRS_ERR ; ..No good CALR _GETHEXR ; Try for range parm CLR R0 ; Set type range JR NC,GRS_GOOD ; ..Got a range parm CP R14,#ER_NODEL ; Missing / delimiter? JR NE,GRS_ERR ; ..No, but it was a range type CALR _GETHEXV ; Reset R13 for single parm RES R1,#0 ; Force even LD R0,#1 ; Set type single LD R2,R1 LD R3,R1 GRS_GOOD: RESFLG C ; Clear range error POP R14,@R15 ; Restore R14 JR GRS_RET GRS_ERR: INC R15,#2 ; Remove R14 from stack SETFLG C ; Set error flag GRS_RET: RET TITLE "_GETHEXR Procedure" EJECT ; Funtion _GETHEXR (Buffer)(Start,End) ; Gets a word address range from the command buffer. ; A range consists of two hex values separated with ; a slash '/'. If either value is not hex or is missing ; or is not a slash, an error number is returned. R13 ; points to the command buffer. ; Returns: ; All registers returned unchanged except the following ; Range ok: R13 point to char after end value, C is cleared, ; R2 contains start value, R3 contains end value. ; Range bad: R13 unchanged, R14 contain error #, C is set. ; Forces addresses to be even by resetting bit 0 ; Registers: ; R1 - Scratch ; R2 - Starting address ; R3 - Ending address _GETHEXR: PUSH @R15,R4 ; Save reg PUSH @R15,R1 LD R4,R13 ; Save R13 incase error CALR _GETHEXV ; Get first value in R1 JR CAR,GR_BADV ; ..Not good! LD R2,R1 ; R2 is begining value RES R2,#0 ; Force even LDK R1,#0 ; Look for "/" CALR _FINDDEL ; Look for delimiter JR CAR,GR_ERR ; ..Not found CALR _GETHEXV ; Get second value JR CAR,GR_BADV ; ..No good! LD R3,R1 ; R3 is end value RES R3,#0 ; Force even RESFLG C ; Clear error flag JR GR_RET GR_BADV: LDK R14,#ER_BADRNG ; Bad value error # GR_ERR: LD R13,R4 ; Restore R13 SETFLG C ; Set error flag GR_RET: POP R1,@R15 ; Unsave regs POP R4,@R15 RET TITLE "_GETHEXV Function" EJECT ; Function _GETHEXV (Buffer) (Value) ; The character string should consist of valid hex characters ; terminated with a blank or delimiter. The result is returned ; in R1 and the C flag is set to determine success or failure. _GETHEXV: DEC R15,#8 ; Save regs. LDM @R15,R2,#4 CALR _NEXTPARM ; Any parms? JR CAR,GTV_RET ; ..No, return errors LD R5,R13 ; Save R13 for non-zero length check CLR R1 ; Clear result reg. GTV_TOP: LDA R2,HEXCHARS+15 ; R2 -> Ascii hex LD R3,#16 ; R3 = Number of valid chars LDB RL4,@R13 ; RL4 = Char to convert CPB RL4,#"a" ; Test for lowercase JR ULT,GTV_CMP ; Already uppercase RESB RL4,#5 ; Uppercase it GTV_CMP: CPDRB RL4,@R2,R3,EQ ; Loop through hex chars JR NE,GTV_ECHAR ; Non-hex char found LD R2,R1 AND R2,#'F000'H ; Test upper nibble for zero JR NZ,GTV_TOBIG ; ..wasn't zero SLL R1,#4 ; Move last digit over OR R1,R3 ; Add in current digit INC R13,#1 ; Move to next char JR GTV_TOP ; Convert next char ; Test break char for valid delimiter GTV_ECHAR: CP R5,R13 ; Was anything converted? JR EQ,GTV_BAD ; ..No, ERR! LDK R3,#DELIM_END-DELIMITS; R3 is number of valid delimiters LDA R2,DELIMITS ; R2 -> delimiters CPIRB RL4,@R2,R3,EQ ; Test for valid end char. JR EQ,GTV_END ; ..Found a good one GTV_BAD: LDK R14,#ER_NOTHEX ; Set Bad hex error JR GTV_ERR GTV_TOBIG: LDK R14,#ER_TOOBIG ; Set number to big error GTV_ERR: LD R13,R5 ; Restore R13 for bad exit SETFLG C ; Set error flag JR GTV_RET ; and exit GTV_END: RESFLG C ; Clear ERR flag GTV_RET: LDM R2,@R15,#4 ; Restore registers INC R15,#8 RET ; Done TITLE "_GETDECV Function" EJECT ; Function _GETDECV (Buffer) (Value) ; The function converts the ASCII decimal number ; in the buffer pointed to by R13, to an integer ; returned in R1. If no decimal number is encountered ; in the buffer or the number is not terminated with ; a valid delimiter, the C flag is set otherwise it ; is cleared. _GETDECV: PUSH @R15,R0 ; Save regs DEC R15,#8 LDM @R15,R2,#4 CALR _NEXTPARM ; Anything in buffer? JR CAR,GDV_RET ; ..No, ERR LD R5,R13 ; Save R13 incase error CLR R1 ; Clear result register GDV_TOP: LDA R2,HEXCHARS+9 ; R2 -> Ascii decimal chars LD R3,#10 ; R3 is number of chars LDB RL4,@R13 ; RL4 is char to convert CPDRB RL4,@R2,R3,EQ ; Test for decimal char JR NE,GDV_ECHAR ; ..Non-decimal char found MULT RR0,#10 ; Decimal shift previous result TEST R0 ; Number to big? JR NZ,GDV_TOBIG ; ..Yes, ERR ADD R1,R3 ; And in new digit JR CAR,GDV_TOBIG ; ..No good, ERR INC R13,#1 ; Next character JR GDV_TOP ; Convert next character GDV_ECHAR: CP R5,R13 ; Anything converted? JR EQ,GDV_BAD ; ..No, ERR LDK R3,#DELIM_END-DELIMITS; R3 is number of delimiters LDA R2,DELIMITS ; R2 -> delimiters CPIRB RL4,@R2,R3,EQ ; Test for valid delimiter JR EQ,GDV_END ; ..Found a good one GDV_BAD: LDK R14,#ER_NOTDEC ; Set bad decimal error JR GDV_ERR GDV_TOBIG: LDK R14,#ER_TOOBIG ; Set number to big error GDV_ERR: LD R13,R5 ; Restore R13 for bad exit SETFLG C ; set error flag JR GDV_RET GDV_END: RESFLG C ; Clear error flag GDV_RET: LDM R2,@R15,#4 ; Restore regs INC R15,#8 POP R0,@R15 RET TITLE "_GETDECVL Function" EJECT ; Function _GETDECVL (Buffer) (Value) ; This proceedure converts the ASCII decimal number ; in the buffer pointed to by R13, to a long integer ; returned in RR2. If no decimal number is encountered ; in the buffer or the number is not terminated with ; a valid delimiter, the C flag is set otherwise it ; is cleared. _GETDECLV: PUSHL @R15,RR0 ; Save regs DEC R15,#10 LDM @R15,R4,#5 CALR _NEXTPARM ; Anything in buffer? JR CAR,GDL_RET ; ..No, ERR LD R8,R13 ; Save R13 in case of error SUBL RR2,RR2 ; Clear result register CLR R4 ; Clear MS half of RR4 GDL_LOOP: LDA R6,HEXCHARS+9 ; R6 -> ASCII decimal chars LD R5,#10 ; Number of chars LDB RL7,@R13 ; Character to convert CPDRB RL7,@R6,R5,EQ ; Character valid decimal? JR NE,GDL_BADCH ; ..No, test as a delimiter MULTL RQ0,#10 ; Decimal shift previous RR2 TESTL RR0 ; Number to big? JR NZ,GDL_TOBIG ; ..Yes, ERR ADDL RR2,RR4 ; Add in new digit JR CAR,GDL_TOBIG ; ..Result to large, ERR INC R13,#1 ; Next char JR GDL_LOOP GDL_BADCH: CP R8,R13 ; Anything converted? JR EQ,GDL_BAD ; ..No, ERR LDK R5,#DELIM_END-DELIMITS; Number of delimiters LDA R6,DELIMITS ; R6 -> valid delimiters CPIRB RL7,@R6,R5,EQ ; Valid delimiter? JR EQ,GDL_END ; ..Yes, that's all GDL_BAD: LDK R14,#ER_NOTDEC ; Not decimal error JR GDL_ERR GDL_TOBIG: LDK R14,#ER_TOOBIG ; Number to large error GDL_ERR: LD R13,R8 ; Restore R13 on error SETFLG C ; Set error flag JR GDL_RET GDL_END: RESFLG C ; Clear error flag GDL_RET: LDM R4,@R15,#5 ; Unsave regs INC R15,#10 POPL RR0,@R15 RET TITLE "_FINDDEL Procedure" EJECT ; Procedure _FINDDEL (Buffer,#Delimiter) ; Finds a delimiter in the buffer pointed to by R13. ; R1 contains the index in 'DELIMITS:' of the delimiter ; to be found. The search for the delimiter stops when it ; it is found or a non-blank is encountered. ; Returns: ; All register returned as sent except the following ; ; Delimiter found: R13 points to char after delimiter. ; C Flag is cleared. ; Delimiter not found: R13 is unchanged. C Flag set. ; R14 contains an error number. _FINDDEL: PUSH @R15,R3 PUSH @R15,R2 LD R3,R13 ; Save R13 incase not found CALR _NEXTPARM ; Find non blank JR CAR,FND_BAD ; Found CR. LDB RL2,DELIMITS(R1) ; Get delimiter to find CPB RL2,@R13 ; delimiter @R13? JR NE,FND_BAD ; ..No, ERR! INC R13,#1 ; Bump R13 past the delimiter RESFLG C ; Found delimiter! JR FND_RET FND_BAD: LDK R14,#ER_NODEL ; Set missing delimiter error SETFLG C ; Set error flag LD R13,R3 ; Restore R13 FND_RET: POP R2,@R15 ; Unsave regs. POP R3,@R15 RET TITLE "_NEXTPARM Procedure" EJECT ; Procedure _NEXTPARM (Buffer) ; If R13 points to a byte containing a blank, it is incr'd until ; it points to a non-blank. If the non-blank is CR, then the ; overflow flag is set, otherwise it is reset. ; All registers except R13 are returned as sent. _NEXTPARM: CPB @R13,#" " ; Look for blank JR NE,NPM_ERR INC R13,#1 ; Next char JR _NEXTPARM ; Delete them all NPM_ERR: CPB @R13,#CR ; Look for CR JR NE,NPM_END ; ..Not found, no error LDK R14,#ER_NOPARM ; set missing parm error # SETFLG C ; Set error flag JR NPM_RET NPM_END: RESFLG C ; Clear error flag NPM_RET: RET TITLE "_OUTMEM, _OUTADDR & _OUTHEX Procedures" EJECT ; Prcocedure _OUTMEM (#Address) ; Outputs the address in R1 followed by the value ; pointed to by R1. _OUTMEM: PUSH @R15,R1 CALR _OUTADDR ; Print R1 followed by ":" LD R1,@R1 ; Get value @R1 CALR _OUTHEX ; Print R1 followed by " " POP R1,@R15 RET SKIP 6 ; Procedure _OUTADDR (#Address) ; Converts value in R1 to printable hex and outputs with ; trailing blank and ": " _OUTADDR: PUSH @R15,R14 ; Save reg CALR _OUTHEX LDA R14,ADDR_DEL ; Print ": " CALR _PRINTSTR POP R14,@R15 ; Unsave regs RET ; Done SKIP 6 ; Procedure _OUTHEX (#Integer) ; Prints in hex, the value in R1 followed by a blank. _OUTHEX: PUSH @R15,R1 ; Save R1 CALR _OUTHEXW ; Print (R1) in hex LDK R1,#1 ; Print a blank CALR _PUTBLANK POP R1,@R15 ; Restore R1 RET TITLE "_OUTHEXW & _OUTHEXB Procedures" EJECT ; Procedure _OUTHEXW (#Integer) ; Prints in HEX the integer contained in R1 to the ; local channel. _OUTHEXW: PUSH @R15,R1 ; Save R1 LDB RL1,RH1 ; Print RH1 first CALR _OUTHEXB ; Print hex byte RH1 POP R1,@R15 ; Restore R1 CALR _OUTHEXB ; Print hex byte RL1 RET SKIP 6 ; Procedure _OUTHEXB (#Integer) ; Prints the HEX value of RL1 to the local channel, right ; justified in a two character field. _OUTHEXB: DEC R15,#8 LDM @R15,R1,#4 LDK R4,#2 ; Number of digits LDB RH3,RL1 ; RH3 gets integer OHB_LOOP: CLR R2 ; Clear digit receiver SLLL RR2,#4 ; Move digit into R2 LDB RH1,HEXCHARS(R2) ; Get ASCII character CALR _PUTLCHAR ; Print character DJNZ R4,OHB_LOOP ; ..Until R4 = 0 LDM R1,@R15,#4 ; Restore regs INC R15,#8 RET TITLE "_OUTDECW Procedure" EJECT ; Procedure _OUTDECW (#Integer,#Width) ; Convert integer in R1 to decimal and print to ; channel zero, right justified in a field of specified ; width. ; Register usage: ; R5 - Decimal character count ; R4 - Range Index ; RR2 - Conversion register ; R1 - Integer On entry/Parameter passage ; R0 - Field width _OUTDECW: DEC R15,#8 ; Save regs LDM @R15,R1,#4 CLR R4 ; Clear digit count LD R3,R1 ; Put integer in RR2 OD_LOOP: CLR R2 ; Clear upper half of RR2 DIV RR2,#10 ; Divide for LS Digit ; R2: Remainer; R3 Quotient ORB RL2,#'30'H ; Change to ASCII PUSH @R15,R2 ; Save character INC R4,#1 ; Update save count TEST R3 ; Quotient is zero? JR NZ,OD_LOOP ; ..No, not done OD_PRINT: CP R0,R4 ; Number width > Field width? JR ULE,OD_PRTNUM ; ..Yes, skip blank filler LD R1,R0 ; Move width to R1 for Putblanks SUB R1,R4 ; Subtract number width CALR _PUTBLANK ; Print blanks OD_PRTNUM: POP R1,@R15 ; Get character off stack EXB RL1,RH1 ; Put char in RH1 for print CALR _PUTLCHAR ; Print char DEC R4,#1 ; Done printing? JR NZ,OD_PRTNUM ; ..More left, do again LDM R1,@R15,#4 INC R15,#8 RET TITLE "_OUTDECL Procedure" EJECT ; Proceedure _OUTDECL (#Integer,#Width) ; _Outdecl converts an unsigned long integer in RR2 ; to decimal and outputs the result to the Local channel. ; The integer is right justified in a field of specified ; width in R0. _OUTDECL: DEC R15,#10 ; Save regs LDM @R15,R0,#5 LD R5,R0 ; Save R0 for print CLR R4 ; Clear digit count ODL_LOOP: SUBL RR0,RR0 ; Clear MS half of RQ0 DIVL RQ0,#10 ; Divide for LS digit ; RR2 remainder; RR0 Quotient ORB RL1,#'30'H ; Convert digit to ASCII PUSH @R15,R1 ; Save digit INC R4 ; Update digit count TESTL RR2 ; Quotient is zero? JR NZ,ODL_LOOP ; ..No, not done ODL_FIELD: CP R5,R4 ; Integer width > Field width? JR ULE,ODL_PRT ; ..Yes, skip blank filler LD R1,R5 ; R1 is number of blanks SUB R1,R4 ; Subtract integer width CALR _PUTBLANK ; Print blanks ODL_PRT: POP R1,@R15 ; Get char off stack EXB RH1,RL1 ; Move char into RH1 CALR _PUTLCHAR ; Print it DEC R4 ; One less char, Done? JR NZ,ODL_PRT ; ..No, do it again LDM R0,@R15,#5 INC R15,#10 RET TITLE "_ASKYES Procedure" EJECT ; Procedure _ASKYES . ; This routine prompt with the message pointed to by R14 ; then waits for a response. A "Y" will cause a RET with ; the C flag set, anthing else RETs with C cleared. _ASKYES: PUSH @R15,R14 PUSH @R15,R1 CALR _PRINTSTR ; R14 -> Message LDK R14,#LCLCHAN ; Input from local channel CALR _GETCHAR ; Get response CALR _PUTLCHAR ; Echo response CALR _PUTCRLF RESB RH1,#5 ; Upcase CPB RH1,#"Y" ; A "Y"? RESFLG C ; ..Not yes JR NE,ASKRET SETFLG C ; Set yes flag ASKRET: POP R1,@R15 POP R14,@R15 RET TITLE "_SSQ Procedure" EJECT ; Procedure _SSQ. ; This routine check to see if the local terminal port ; has received a character. If no character has been ; received, it returns. If a CNTRL-S has been received, ; execution is suspended until a CNTRL-Q is received. If ; a CNTRL-Q is recieved when not waiting it is ignored. ; On CNTRL-P it sets the C flag and returns. CNTRL-P ; also performs the function of a CNTRL-Q. All other ; characters are ignored. _SSQ: PUSH @R15,R1 ; Save Regs PUSH @R15,R14 LDK R14,#LCLCHAN ; Channel for _INCHAR CALR _INCHAR ; Try to get a char JR CAR,SSQ_END ; ..none there, forget this CPB RH1,#BRK ; Break char? JR EQ,SSQ_BRK ; ..Yes, return ERR CPB RH1,#CNTRL_S ; ..got one, CTRL-S? JR NE,SSQ_END ; ..No, leave _SSQ ; CTRL-S seen .. Wait for CTRL-Q, CTRL-P or Break SSQ_WAIT: CALR _GETCHAR ; Wait for char CPB RH1,#BRK ; Break char? JR EQ,SSQ_BRK ; ..Yes, Abort CPB RH1,#CNTRL_Q ; Continue char? JR NE,SSQ_WAIT ; ..No, wait for next char SSQ_END: RESFLG C ; Clear BREAK char flag JR SSQ_RET SSQ_BRK: SETFLG C ; Set Break flag SSQ_RET: POP R14,@R15 ; Restore regs POP R1,@R15 RET TITLE "_ERRORMSG Procedure" EJECT ; _ERRORMSG Subroutine. ; Errormsg displays the error message whose number is ; passed to this routine in R14, to the local port. Before ; each message the 'ERR_LABEL' is printed and a CR LF is ; generated after the message. The address of each error ; Register usage: ; R14 - Passes error number to routine ; R1 - Holds error number _ERRORMSG: PUSH @R15,R1 ; Save reg LD R1,R14 ; Save R14 LDA R14,ERR_LABEL ; Address of lable CALR _PRINTSTR ; Print lable SLL R1,#1 ; Make error number word index LD R14,ERR_TABLE(R1) ; Address of message CALR _PRINTSTR ; print message CALR _PUTCRLF ; newline POP R1,@R15 ; Unsave regs. RET TITLE "_PRTHEAD Procedure" EJECT ; Procedure _PRTHEAD (Index) ; This routine prints the heading for Registers, Limits, ; breakpoints and traces. At entry, R1 contains the token ; of the heading to be printed. ; Register usage: ; R4 - Label count ; RL3 - Number of labels ; RH2 - Character in label ; RL2 - Number of blanks between labels ; R1 - Token of heading type on entry. Later used for Putchar _PRTHEAD: DEC R15,#8 LDM @R15,R1,#4 LDB RH2,ITM_LIT(R1) ; Get char in heading LDB RL2,ITM_BLANK(R1) ; Get number of blanks LDB RL3,ITM_MAX(R1) ; Get number of labels in heading CLR R4 ; Clear index PRTH_TOP: LDB RH1,RH2 ; Print char CALR _PUTLCHAR CPB RL4,#9 ; Is the count <= 9? JR ULE,PRTH_NO ; ..Yes, so no leading "1" LDB RH1,#"1" ; no so print a zero CALR _PUTLCHAR PRTH_NO: LDB RH1,RL4 ; Make decimal ASCII in RH1 ADDB RH1,#"0" CPB RH1,#"9" ; Greater than 9? JR ULE,PRTH_OK ; ..No DECB RH1,#10 ; Back it up PRTH_OK: CALR _PUTLCHAR ; Print it INCB RL4,#1 ; Decrement label count CPB RL4,RL3 ; Done yet? JR EQ,PRTH_END ; That's all, no blanks please! LDB RL1,RL2 ; Print blanks CPB RL4,#10 ; Is count > 10? JR UGT,PRTH_BNK ; ..Yes INCB RL1,#1 ; no so one more blank PRTH_BNK: CALR _PUTBLANK JR PRTH_TOP ; Do the next one PRTH_END: CALR _PUTCRLF ; New line ya fool! LDM R1,@R15,#4 ; Unsave regs INC R15,#8 RET EJECT ; Procedure _PRINTSTR (Literal) ; Printstr prints a zero terminated byte characters string ; pointed to by R14, to the local terminal port. If a byte ; containing a negative value is encountered, the number of ; blanks equal to it's Negated value is printed. In the case ; of a negative one, a CR LF is printed instead of a blank. ; Register usage: ; R14 - Pointer (Points to string on entry) ; RH1 - Byte to be printed _PRINTSTR: PUSH @R15,R1 ; Save registers PUSH @R15,R14 PRT_TOP: LDB RH1,@R14 ; Get char to print CPB RH1,#EOS ; At end of string? JR EQ,PRT_RET ; ..Yes, return JR MI,PRT_NEG ; ..Negative, print blanks CALR _PUTLCHAR JR PRT_NEXT PRT_NEG: CPB RH1,#NEWLN ; Is it the newline char? JR NE,PRT_BLNKS ; ..No, print blanks CALR _PUTCRLF ; Go to new line JR PRT_NEXT PRT_BLNKS: NEGB RH1 ; Make into positive value LDB RL1,RH1 ; Putblanks wants count in RL1 CALR _PUTBLANK ; Print blanks PRT_NEXT: INC R14,#1 ; Next char JR PRT_TOP PRT_RET: RESFLG C ; Clear error flag POP R14,@R15 ; Restore regs POP R1,@R15 RET ; EXit TITLE "_PUTBLANK & _PUTCRLF Procedures" EJECT ; Procedure _PUTBLANK (#blanks) ; Prints a passed number of blanks to the local ; channel. ; Registers: ; RL1 - Number of blanks to print _PUTBLANK: PUSH @R15,R1 ; Save reg LDB RH1,#" " PTBLK_LP: CALR _PUTLCHAR ; Print blank DBJNZ RL1,PTBLK_LP ; As needed POP R1,@R15 ; Unsave regs RET SKIP 8 ; Procedure _PUTCRLF ; Outputs a cariage return & linefeed to the ; local channel. _PUTCRLF: PUSH @R15,R14 ; Save Regs. LDA R14,CRLFDEF ; Print _PUTCRLF CALR _PRINTSTR POP R14,@R15 RET TITLE "_PUTBRK Procedure" EJECT ; Procedure _PUTBRK (#Channel) ; Outputs a Break to the channel specified ; in R14. _PUTBRK: PUSH @R15,R14 PUSH @R15,R2 PUSH @R15,R1 SLL R14,#1 ; Make Channel into index LD R14,X8250LCR(R14) ; R14 gets LCR port address INB RL1,@R14 ; Get current value of LCR SETB RL1,#BREAK ; Set break bit in LCR OUTB @R14,RL1 ; Set LCR LD R2,#40000 ; Delay 200ms for break PBRK_WAIT: DEC R2 NOP JR NZ,PBRK_WAIT RESB RL1,#BREAK ; Clear break bit OUTB @R14,RL1 ; Reset LCR POP R1,@R15 POP R2,@R15 POP R14,@R15 RET TITLE "_PUTLCHAR, _PUTCHAR & _GETCHAR -- Input & output with wait" EJECT ; Procedure _PUTLCHAR (#Char) ; Putlchar outputs a character to the local channel ; and the printer if the LP_ON flag is set. The character ; to be printed is sent to putlchar in RH1. Putlchar will ; not return until the character is sent. _PUTLCHAR: PUSH @R15,R14 ; Save those regs! PUSH @R15,R2 LDK R14,#LCLCHAN ; Output to local channel CALR _PUTCHAR BIT BIT_FLAGS,#LP_ONFLG ; Is printer enabled? JR ZER,PLC_END ; ..No, that's all LDK R14,#LPCHAN*2 ; R14 index to LP MSR LD R14,X8250MSR(R14) ; Get Modem status reg. PLC_PRT: INB RL2,@R14 BITB RL2,#DTR ; Printer ready? JR ZER,PLC_PRT ; ..No, hurry and wait LDK R14,#LPCHAN ; R14 -> LP channel CALR _PUTCHAR PLC_END: POP R2,@R15 POP R14,@R15 RET SKIP 8 ; Procedure _PUTCHAR (Channel,#Char) ; Putchar outputs a character to the data port whose ; channel number is contained in R14. The character to ; be outputed is sent to Getchar in RH1. Getchar will ; not return until the character can be sent. _PUTCHAR: CALR _OUTCHAR ; Try to output char JR CAR,_PUTCHAR ; ..Couldn't, try again RET SKIP 8 ; Function _GETCHAR (Channel): #Char ; Getchar inputs a character from the data port whose ; channel number is contained in R14. Getchar will not ; return until a character is available. The character ; is returned in RH1. _GETCHAR: CALR _INCHAR ; Try to get char from port JR CAR,_GETCHAR ; ..None there, try again RET TITLE "_OUTCHAR Procedure" EJECT ; Procedure _OUTCHAR (Channel,#Char) ; Outchar attempts to output a character to the ; channel whose number is contained in R14. The ; character to be sent is in RH1. If outchar is unable ; to output the character, the C flag is set on return ; otherwise the C flag is reset. _OUTCHAR: PUSH @R15,R1 ; Save regs PUSH @R15,R2 PUSH @R15,R14 SLL R14,#1 ; Make R14 into word index LD R2,X8250LSR(R14) ; R2 -> Line status register INB RL1,@R2 ; input status BITB RL1,#THRE ; holding register empty? JR ZER,OCR_ERR ; ..No, return with err set LD R2,X8250DATA(R14) ; R2 -> data port OUTB @R2,RH1 ; output character RESFLG C ; Clear error flag JR OCR_RET OCR_ERR: SETFLG C ; Set error flag OCR_RET: POP R14,@R15 POP R2,@R15 POP R1,@R15 RET TITLE "_INCHAR Function" EJECT ; Function _INCHAR (Channel): #Char ; Inchar attempts to get a character from the ; channel whose number is contained in R14. If a ; character is not available, the C flag is set on ; return otherwise the C flag is cleared and the ; character received is in RH1. _INCHAR: PUSH @R15,R2 ; Save regs PUSH @R15,R14 SLL R14,#1 ; Change R14 into word index LD R2,X8250LSR(R14) ; R2 -> Line status register INB RL1,@R2 ; input status BITB RL1,#DR ; character available? JR ZER,ICR_ERR ; ..No, return with err set LD R2,X8250DATA(R14) ; R2 -> data register INB RH1,@R2 ; input char RESFLG C ; clear error flag JR ICR_RET ICR_ERR: SETFLG C ; Set error flag ICR_RET: POP R14,@R15 POP R2,@R15 RET TITLE "Error messages" EJECT ; Error message constants used in '_ERRORMSG' ERR_TABLE: DC ERR00,ERR01,ERR02,ERR03,ERR04,ERR05,ERR06,ERR07 DC ERR08,ERR09,ERR10,ERR11,ERR12,ERR13,ERR14 ERR_LABEL: DCB "* ",EOS ERR00: DCB "Missing parameter",EOS ERR01: DCB "Extra parameter(s)",EOS ERR02: DCB "Parameter not hex",EOS ERR03: DCB "Parameter not decimal",EOS ERR04: DCB "Unrecognized parameter",EOS ERR05: DCB "Ambiguous parameter",EOS ERR06: DCB "Bad range",EOS ERR07: DCB "Missing delimiter",EOS ERR08: DCB "Numeric value to large",EOS ERR09: DCB "No such option",EOS ERR10: DCB "Ambiguous option",EOS ERR11: DCB "Not found",EOS ERR12: DCB "Can't continue!",EOS ERR13: DCB "Matched",EOS ERR14: DCB "LP not ready",EOS TITLE "Literal Definitions" EJECT ; Litterals for Interrupts & Traps BADOPMSG: DCB NEWLN,"* Bad opcode",EOS PRIVOPMSG: DCB NEWLN,"* Privileged opcode",EOS SYSCALMSG: DCB NEWLN,"* System call",EOS TRAPPCMSG: DCB " PC was ",EOS NMIMSG: DCB NEWLN,"* Return by restart.",EOS INSLIMMSG: DCB NEWLN,"* Instruction limit.",EOS LIMITERR: DCB NEWLN,"* PC out of bounds.",EOS BPTSERR: DCB NEWLN,"* Breakpoint.",EOS TRCSERR: DCB NEWLN,"* Trace ",EOS VIMSG: DCB NEWLN,"* Undefined VI. ID=",EOS INTPCMSG: DCB -2,"Next PC is ",EOS FCWMSG: DCB -3,"FCW: ",EOS ; Data & literals for Command mode LC_MES: DCB NEWLN,"DSC Z8002 Monitor V4.5",NEWLN,LF,EOS MOD_MSG: DCB "< Modem available >",NEWLN,EOS MOD_GONE: DCB "* Modem unavailable",EOS FI_MES: DCB "Fill completed",NEWLN,EOS MV_MES: DCB "Copy completed",NEWLN,EOS SRC_GOTIT: DCB "Found at ",EOS CM_NOT: DCB "Mismatch. ",EOS CONT_MSG: DCB "; More? ",EOS DBG_DIS: DCB ".........",EOS BREAKMSG: DCB "* Aborted",NEWLN,EOS PSWHEAD: DCB "-",-2,"SY EP VI NV -",-2,"-",-2,"-",-2 DCB "C",-2,"Z",-2,"S",-2,"PV DA H",-2,"-",-2,"-",-2 DCB "FCW",-2,"PC",-3,"SP",-3,"NSP",NEWLN,EOS HIST_HEAD: DCB " FCW PC",EOS INSTCNTHD: DCB "Instructions executed; Total: ",EOS INSRCNTHD: DCB ";",-2,"Recent: ",EOS INSTLIMHD: DCB ";",-2,"Limit: ",EOS INSTLIMLB: DCB "none",EOS ZERO_LIT: DCB "0",-2,EOS ONE_LIT: DCB "1",-2,EOS ADDR_DEL: DCB ": ",EOS HELP_MSG: DCB "Next",-8 DCB "Previous",-4 DCB "Address",NEWLN DCB "Dump",-8 DCB "DEposit",-5 DCB "FIll",NEWLN DCB "COpy",-8 DCB "SEArch",-6 DCB "COMpare",NEWLN DCB "SET",-9 DCB "CLear",-7 DCB "SHow",NEWLN DCB "EXEcute",-5 DCB "CONTinue",-4 DCB "CONFigure",NEWLN DCB "LOad",-8 DCB "Modem",-7 DCB "LP",NEWLN DCB "EPromer",-5 ; <> DCB "EDitor",NEWLN ; <> DCB LF,EOS DCB "SET",-9,"CLear",-7,"SHow",NEWLN ; Loader Litterals LD_ERRMSG: DCB 7,"* Non Hex characters",EOS LD_CKSERR: DCB 7,"* Checksum error",EOS LD_TYPMSG: DCB 7,"* Undefined record type",EOS LD_EOFMSG: DCB NEWLN,"* Load file at EOF ",EOS LD_GOMSG: DCB "Exec address is ",EOS ; Data for getline GETPROMPT: DCB "> ",EOS ; Command prompt GETLINBS: DCB BS," ",BS,EOS ; Physical backspace GETLINKIL: DCB "***",NEWLN,EOS ; Physical line-kill ALIGN EJECT ; Set, Clear, Show constants DBG_ADDR: DC SAVE_LIMS,SAVE_BPTS,SAVE_TRCS ITM_NAMES: DC 4,ITM_LIT,ITM_MAX ITM_LIT: DCB "LBTR" ITM_MAX: DCB 8,8,8,15 ITM_BLANK: DCB 7,7,7,2 ; Show channels constants CHANHEAD: DCB "Channel Divisor Baud Parity " DCB "SBits WLen Protocol",NEWLN,EOS CHANNAME: DC CHAN0,CHAN1,CHAN2,CHAN3 CHAN0: DCB -2,"C0",-5,EOS CHAN1: DCB -2,"C1",-5,EOS CHAN2: DCB -2,"C2",-5,EOS CHAN3: DCB -2,"C3",-5,EOS BAUDBAD: DCB -3,"....",EOS BAUDS: DC 110,300,600,1200,2400,4800,9600,19200 CHANPRTY: DC PRTYNONE,PRTYODD,PRTYNONE,PRTYEVEN PRTYNONE: DCB -3,"NONE",EOS PRTYODD: DCB -3,"ODD ",EOS PRTYEVEN: DCB -3,"EVEN",EOS CHANPTCL: DC PTCL_TT,PTCL_MD,PTCL_LP,PTCL_PR PTCL_TT: DCB -6,"TT",EOS PTCL_MD: DCB -6,"MD",EOS PTCL_LP: DCB -6,"LP",EOS PTCL_PR: DCB -6,"PR",EOS CHAN_NAME: DC 1,CHAN_LIT,CHAN_MAX CHAN_LIT: DCB "C" CHAN_MAX: DCB X8250NUM ; Other Definitions HEXCHARS: DCB "0123456789ABCDEF" CRLFDEF: DCB CR,LF,EOS ; CR LF Constant. Can't be NEWLN DELIMITS: DCB "/= ",CR DELIM_END: EQU $ ALIGN ; X8250 Baud rate divisors ; 110,300,600,1200,2400,4800,9600,19200 DIVISORS: DC 1047,384,192,96 ; Divisor values for X8250 DC 48,24,12,6 ; with 1.8432 MHZ crystal. ; Address tables for X8250 ports X8250DATA: DC DATA,DATA+8,DATA+16,DATA+24 ; Data ports X8250DLLS: DC DLLS,DLLS+8,DLLS+16,DLLS+24 ; Divisor access latch (LS) X8250LCR: DC LCR,LCR+8,LCR+16,LCR+24 ; Line control registers X8250LSR: DC LSR,LSR+8,LSR+16,LSR+24 ; Line status registers X8250MCR: DC MCR,MCR+8,MCR+16,MCR+24 ; Modem control register X8250MSR: DC MSR,MSR+8,MSR+16,MSR+24 ; Modem status registers TITLE "Keyword definitions" EJECT ; Option keywords CMD_KEYS: DCB 9,3,TK_CONF,"CONFIGURE" DCB 8,1,TK_PREV,"PREVIOUS" DCB 8,3,TK_CONT,"CONTINUE" DCB 8,2,TK_EDIT,"NCEDITOR" ; <> DCB 7,1,TK_ADDR,"ADDRESS" DCB 7,2,TK_DEP,"DEPOSIT" DCB 7,3,TK_EXEC,"EXECUTE" DCB 7,2,TK_EPROM,"EPROMER" ; <> DCB 7,2,TK_COMP,"COMPARE" DCB 6,2,TK_SEARCH,"SEARCH" DCB 6,2,TK_EDIT,"EDITOR" ; <> DCB 5,1,TK_MODEM,"MODEM" DCB 5,2,TK_CLEAR,"CLEAR" DCB 4,1,TK_NEXT,"NEXT" DCB 4,1,TK_DUMP,"DUMP" DCB 4,2,TK_FILL,"FILL" DCB 4,2,TK_COPY,"COPY" DCB 4,2,TK_LOAD,"LOAD" DCB 4,1,TK_HELP,"HELP" DCB 4,2,TK_SHOW,"SHOW" DCB 3,3,TK_CLEAR,"CLR" DCB 3,2,TK_SET,"SET" DCB 2,2,TK_SET,"ST" DCB 2,2,TK_ECHO,"LP" DCB 1,1,TK_HELP,"?" DCB 0 ; End of keywords ALIGN ; Execute & continue parameter keywords ECPARM_KW: DCB 6,2,TK_ECSYS,"SYSTEM" DCB 6,2,TK_ECNORM,"NORMAL" DCB 7,3,TK_ECNODB,"NODEBUG" DCB 5,2,TK_ECDEB,"DEBUG" DCB 4,2,TK_ECLOAD,"LOAD" DCB 4,2,TK_ECNOVI,"NOVI" DCB 4,4,TK_ECNOEP,"NOEP" DCB 2,2,TK_ECEP,"EP" DCB 2,2,TK_ECVI,"VI" DCB 0 ; FCW keywords FCW_KW: DCB 6,2,TK_SYSFLG,"SYSTEM" DCB 2,2,TK_EPFLG,"EP" DCB 2,2,TK_VIFLG,"VI" DCB 3,2,TK_NVIFLG,"NVI" DCB 1,1,TK_CFLG,"C" DCB 1,1,TK_ZFLG,"Z" DCB 1,1,TK_SFLG,"S" DCB 2,1,TK_PVFLG,"PV" DCB 2,1,TK_DFLG,"DA" DCB 1,1,TK_HFLG,"H" DCB 0 EJECT ; Misc. Keywords used with Set & Clear MISC_KW: DCB 3,2,TK_FCW,"FCW" DCB 3,2,TK_NSP,"NSP" DCB 2,2,TK_SP,"SP" DCB 2,2,TK_PC,"PC" DCB 0 ; Show Keywords SHOW_KW: DCB 11,1,TK_BRKPTS*2,"BREAKPOINTS" DCB 9,1,TK_REGS*2,"REGISTERS" DCB 8,1,TK_CHAN*2,"CHANNELS" DCB 7,1,TK_HIST*2,"HISTORY" DCB 6,1,TK_LIMITS*2,"LIMITS" DCB 6,1,TK_TRACES*2,"TRACES" DCB 3,1,TK_PSW*2,"PSW" DCB 3,1,TK_PSW*2,"FCW" DCB 0 ; Keywords used in the Echo option ECHO_KW: DCB 2,2,TK_ECHON,"ON" DCB 3,2,TK_ECHOFF,"OFF" DCB 0 ; Keywords used in the Configure option CONF_KW: DCB 8,1,TK_CFPTCL,"PROTOCOL" DCB 7,1,TK_CFDIV,"DIVISOR" DCB 6,1,TK_CFPRTY,"PARITY" DCB 5,1,TK_CFSBIT,"SBITS" DCB 4,1,TK_CFBAUD,"BAUD" DCB 4,1,TK_CFWLEN,"WLEN" DCB 0 ; Configure 'parity' CONF_PYKW: DCB 4,1,TK_CFNPTY,"NONE" DCB 4,1,TK_CFEPTY,"EVEN" DCB 3,1,TK_CFOPTY,"ODD" DCB 0 ; Configure 'protocol' CONF_PTKW: DCB 2,2,TK_TT,"TT" DCB 2,2,TK_MD,"MD" DCB 2,2,TK_LP,"LP" DCB 2,2,TK_PR,"PR" DCB 0 TITLE "Miscellaneous" EJECT ; Monitor RAM definitions ; Monitor ram buffers ORG RAMBASE LINBUF: DSB 64 ; CMD buffer & sentinel SCRBUF: ; Scratch buffer (here to PSA) MD_RBUF: DSB MDRBUFLEN ; Char buffer to remote MD_LBUF: DSB MDLBUFLEN ; Char buffer to local ; Stack pointer initial value ORG RAMBASE+'0A00'H ; Stack locations USERNORM: EQU $+'0100'H ; User normal stack USERSYS: EQU $+'0200'H ; User system stack MONSTACK: EQU $+'0300'H ; Monitor stack ORG $+'0300'H ; Must be at even 100h addr PSA: DS 271 CURADDR: DS 1 ; Currend display address DIRECTION: DS 1 ; Value added to Address on CR RETADDR: DS 1 ; Return address for Call without stack X8250PTCL: DS X8250NUM ; X8250 channel protocols ; The follow locations are cleared during Cold Start. FIRSTZERO: EQU $+2 ; Address of first word to zero SAVE_BPTS: DS 16 ; Break points SAVE_TRCS: DS 16 ; Trace ranges SAVE_LIMS: DS 16 ; Limit ranges SAVE_HIST: DS 16 ; Saved PSW's in Debug mode RESTART: DS 1 NMI_FLAGS: DS 1 BIT_FLAGS: DS 1 USERREGS: DS 17 ; User register area GOPSW: ; GO Command status area GO_FCW: DS 1 ; GOPSW must follow Userregs GO_PC: DS 1 INST_RCNT: DSL 1 ; Instruction count recent INST_TCNT: DSL 1 ; Instruction count total INST_LIM: DSL 1 ; Instruction limit in DEBUG LD_OFFSET: DS 1 ; Loader offset NUMTOZERO: EQU ($-FIRSTZERO)/2 ; Number of words to zero on RESET END START