;COPYRIGHT 1989 RONALD E. JACOBS ;NEWMON.MAC: ROM monitor program. Uses no RAM !! ;BEGUN 01/09/88 RONALD E. JACOBS ;latest work done 08/22/89 lf equ 00Ah ;ASCII line feed character cr equ 00Dh ;ASCII carriage return character true equ 001h false equ 000h .Z80 ;use Z80 nmenonics org 100H ;************************************************************************ ;* * ;* USER SETTABLE EQUATES: * ;* * ;************************************************************************ ;*CONSOLE PORT INFORMATION: Only one may be true.* MD3 equ true ;Morrow MD2 OR MD3 MicroDecision WB14 equ FALSE ;Morrow Wunderbus or Mult/IO board MDHD equ false ;Morrow hard disk MicroDecision KPRO EQU false ;KAYPRO 4 SERIAL PRINTER PORT ;*PROMPT SELECTION: A printing character of your choice.* PROMPT equ ']' ;select the character to be the prompt MONITOR equ TRUE ;include monitor portion of program? ALIGNMENT equ true ;include fstep portion of program? ;************************************************************************ ;* END OF USER SETTABLE EQUATES * ;************************************************************************ oncrt macro dum1,dum2 ;for showing info on CRT at assembly .printx dum1=dum2 ;dum1='text', dum2=variable endm if WB14 ;Morrow Wunderbus or Mult/IO board status equ 04Dh ;port status register rdreg equ 048h ;port input register (read) wrreg equ 048h ;port output register (write) rdbit equ 001h ;port data ready to read (1 if ready) wrbit equ 020h ;port ready to output data (1 if ready) endif if MD3 ;Morrow MD2 or MD3 MicroDecision status equ 0FDh ;port status register rdreg equ 0FCh ;port input register (read) wrreg equ 0FCh ;port output register (write) rdbit equ 002h ;port data ready to read (1 if ready) wrbit equ 001h ;port ready to output data (1 if ready) s1stat equ 0FDh ;for initialization of status port 1 s2stat equ 0FFh ;for initialization of status port 2 fdcstat equ 0FAh ;NEC 765 disk controller status port fdcdata equ 0FBh ;NEC 765 disk controller data port fdc2tc equ 0F7h ;FDC terminal count port (rev. 2 board) fdc1tc equ 0F8h ;FDC terminal count port (rev. 1 board) endif if KPRO ;KAYPRO 4(TERMINAL TO SER. PRINT. PORT) status equ 006h ;port status register rdreg equ 004h ;port input register (read) wrreg equ 004h ;port output register (write) rdbit equ 001h ;port data ready to read (1 if ready) wrbit equ 004h ;port ready to output data (1 if ready) s1stat equ 0h ;?for initialization of status port 1 s2stat equ 0h ;?for initialization of status port 2 fdcstat equ 0h ;?FUJI 1793 disk controller status port fdcdata equ 0h ;?FUJI 1793 disk controller data port fdctc equ 0h ;?FUJI 1793 controller terminal count port endif if MDHD ;Morrow hard disk MicroDecision status equ 061h ;port status register rdreg equ 060h ;port input register (read) wrreg equ 060h ;port output register (write) rdbit equ 001h ;port data ready to read (1 if ready) wrbit equ 004h ;port ready to output data (1 if ready) ;*Morrow hard disk MicroDecision serial port I/O registers.* s1data equ 60h ;serial port 1 data(dart1=console port) s1stat equ 61h ;serial port 1 status s2data equ 62h ;serial port 2 data(dart2=printer port) s2stat equ 63h ;serial port 2 status s3data equ 70h ;serial port 3 data (sio) s3stat equ 71h ;serial port 3 status (sio) $TxRdy equ 00000100b ;Uart Transmitter Ready Bit $RcvRdy equ 00000001b ;Uart Reciever Ready Bit ;*Morrow hard disk MicroDecision counter timer chip I/O registers.* baudset equ 53h ;ctc channel select/mode port baud0 equ 52h ;serial port 1 baud rate control(consol) baud1 equ 51h ;serial port 2 baud rate control baud2 equ 50h ;serial port 3 baud rate control $JBAUD equ 00100000b ;Console Baud Rate Jumper(1=19200,0=9600) DrvSts equ 0C0h ;Drive Status ;*Baud Rate Definitions for CTC initialization (see IntCtc)* b300 equ 342h ;300 Baud b1200 equ 0D0h ;1200 Baud b9600 equ 01Ah ;9600 Baud b19200 equ 00Dh ;19200 Baud endif ;end of hard disk MicroDecision equates ;************************************************************************ ;* * ;* BEGIN PROGRAM CODE * ;* * ;************************************************************************ serinit: ;begin port initialization code ;************************************************************************ ;* ROUTINE initialize KAYPRO 4 (483 board with one serial printer * ;* port and one Centronics parallel port.) Initialize the serial * ;* port for bidirectional 9600 baud 8 bit data length 2 stop bits. * ;* This port is a Zilog SIO (dual UART) chip. Also initialize the * ;* baud rate generator chip and the KAYPRO keyboard port, which is * ;* the other port run by the SIO chip. * ;************************************************************************ if KPRO ;KAYPRO 4(TERMINAL TO SER. PRINT. PORT) ld hl,inittab ;pointer to init data table ld c,7 ;port to output to (7 = keyboard port) ld d,2 ;make 2 passes: there are 2 ports to initialize initld: ld b,initlen ;init data table length otir ;send table out port c ld c,6 ;output to port 6 to initialize serial port dec d ;decrement pass count jr nz,initld ld a,0Eh ;determines serial printer port baud rate out (0),a ;send to I/O chip (set for 9600 baud) ld a,05h ;determines keyboard port baud rate out (0Ch),a ;send to I/O chip (set for 300 baud) endif ;if kpro ;************************************************************************ ;* ROUTINE INITUART: initialize MicroDecision MD2, MD3 UARTS * ;* * ;* This routine initializes both UARTS and the CTC (Clock Control * ;* Chip). The UARTS are set for 8 bits, no parity, x1 clock rate, * ;* and 2 stop bits. In addition, DTR and RTS are programmed to be * ;* on. The CTC is set for 9600 on the console UART, 9600 baud on * ;* the printer UART, and maximum delay on the drive time out * ;* counter. * ;* * ;************************************************************************ if MD3 ld hl,inittab ;pointer to init data table ld b,initlen ;init data table length initloop: ld c,(hl) ;port address inc hl ld a,(hl) ;data inc hl out (c),a ;output data to port djnz initloop ;loop until done endif ;end of MD2/MD3 port initialization code ;*Initialize the hard disk MicroDecision serial I/O devices.* ;************************************************************************ ;* This routine initializes both channels of the darts. * ;* they are set for 8 bits, no parity, x16 clock rate, and * ;* 2 stop bits. in addition, dtr, and rts, are programmed * ;* to be on. * ;************************************************************************ if MDHD ld a,18h ; send channel reset commands out (s1stat),a out (s2stat),a out (s3stat),a ld a,10h ;reset ext/status interrupts out (s1stat),a out (s2stat),a out (s3stat),a ;end of reset sequence ld a,04h ;select register 4 out (s1stat),a out (s2stat),a out (s3stat),a ld a,04ch ;no par, x16, 2 stops out (s1stat),a out (s2stat),a out (s3stat),a ld a,03h ;select register 3 out (s1stat),a out (s2stat),a out (s3stat),a ld a,0c1h ;rx 8 bits, auto off, rx enabled out (s1stat),a out (s2stat),a out (s3stat),a ld a,05h ;select register 5 out (s1stat),a out (s2stat),a out (s3stat),a ld a,0EAh ;tx 8 bits, dtr/rts on tx enabled out (s1stat),a out (s2stat),a out (s3stat),a ld a,10h ;reset ext/status interupts again out (s1stat),a out (s2stat),a out (s3stat),a ld a,01h ;select register 1 out (s1stat),a out (s2stat),a out (s3stat),a ld a,0h ;disable all interrupts here out (s1stat),a out (s2stat),a out (s3stat),a ;************************************************************************ ;* * ;* For the hard disk MicroDecision (MDHD): * ;* Initialize the Counter Timer Chip Baud Rates * ;* * ;* 1) This routine intializes the counter timer chip that serves * ;* as a baud rate generator for the serial ports. * ;* 2) Notice that the Console Device (channel_2) has its baud * ;* rate set as a function of a jumper (bit_5 of drvsts). If the * ;* jumper IS NOT present then the console will be set to 9600 * ;* baud. If the jumper IS present then the console will be set * ;* to 19200 baud. * ;* 3) Baud rate definitions (B...) are defined in the Local * ;* Equates section at the beginning of this module (following * ;* the index). * ;* * ;* Device Baud Rate CTC Channel * ;* Con 9600/19200 2 * ;* Lst 1200 1 * ;* Aux 1200 0 * ;* * ;************************************************************************ ld a,0BEh ;Console:= Mode 3 (Channel 2) out (baudset),a in a,(drvsts) ;If (Baud Rate Jumper is IN) and $JBAUD jr z,IcSk1 ld a,LOW B19200 out (baud0),a ld a,HIGH B19200 out (baud0),a ;Console_Baud_Rate:= 19200 Baud jr IcSk2 IcSk1: ld a,LOW B9600 ;Else out (baud0),a ld a,HIGH B9600 out (baud0),a ;Console_Baud_Rate:= 9600 Baud IcSk2: ld a,7Eh ;List:= Mode 3 (Channel 1) out (baudset),a ld a,LOW B1200 out (baud1),a ld a,HIGH B1200 out (baud1),a ;List_Baud_Rate:= 1200 Baud ld a,3Eh ;Aux:= Mode 3 (Channel 0) out (baudset),a ld a,LOW B1200 out (baud2),a ld a,HIGH B1200 out (baud2),a ;Aux_Baud_Rate:= 1200 Baud ENDIF ;End of hard disk MicroDecision port init. code ;************************************************************************ ;** Directory of routines (Command, routine label, description) ** ;* * ;*^C Comand: enter alignment tool without repainting screen display * ;* C Curr: display Current location * ;* D Dump: Dump memory from,to * ;* F Fill: Fill memory from,to,with * ;* G Go: Go to memory location and execute code * ;* H Hex: add/subtract two Hex numbers * ;* I In: Input from a port * ;* L Loop: Loop routines In, Out, Read, Write * ;* M Move: Move memory starting,ending,to * ;* O Out: Output to a port * ;* R Reloc: Relocate the monitor program to a new memory page * ;* S Set: examine and optionally Set a new memory value * ;* T Test: Test memory from,to * ;* V Verify: Verify memory from,to * ;************************************************************************ strt: ;contraction of "start" if monitor ld ix,conout3 ld iy,crlf jp (iy) ;send a carriage return/line feed ;** SEND A PROMPT ** conout3:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conout3 ;loop if not ready ld a,prompt ;monitor prompt character out (wrreg),a ;output to transmitter buffer ld ix,loop jr getchr ;get character from console, echo it back ;************************************************************************ ;* L PERFORM A VERY TIGHT LOOP FOR SIGNAL TRACING * ;* COMMAND L: LOOP. WITH AN OSCILLOSCOPE. THERE IS NO EXIT FROM * ;* L THESE LOOPS EXCEPT BY RESET. * ;************************************************************************ ;** GET A CHARACTER FROM THE CONSOLE ** loop: CP 'L' jr nz,curr ld ix,loop1 jr getchr ;get a character from the console, echo back loop1: ld c,2 ;initialize to get 2 parameters cp 'O' jr z,loopo cp 'W' jr z,loopw ld c,1 ;set to get 1 parameter for I or R commands cp 'I' jr z,loopi cp 'R' jr z,loopr ld ix,error ;if not O, W, I, R then error jp (ix) ;**************************** ;* Read a memory location * ;**************************** loopr: ld ix,loopr1 jr expr16 loopr1: ld a,(hl) ;read from a memory address jr loopr1 ;************************* ;* Input a port address * ;************************* loopi: ld ix,loopi1 expr16: jr expr15 loopi1: ld c,l loopi2: in a,(c) ;input from a port jr loopi2 ;******************** ;* Write to memory * ;******************** loopw: ld ix,loopw1 expr15: jr expr14 loopw1: exx ;DE=address, L=data ld a,l ;a <-- data loopw2: ld (de),a jr loopw2 ;********************* ;* Output to a port * ;********************* loopo: ld ix,loopo1 expr14: jr expr13 loopo1: exx ;E=port, L=data ld a,l ;A=data ld c,e ;C=port loopo2: out (c),a ;output data to port jr loopo2 ;************************************************************************ ;* * ;* ROUTINE GETCHR: Get a character from the console. Echo it * ;* back to the console. * ;* * ;************************************************************************ ;** GET A CHARACTER FROM THE CONSOLE ** getchr: in a,(status) ;read status register and rdbit jr z,getchr ;no character ready, loop in a,(rdreg) ;read character and 07Fh ;strip parity ;** SEND THE CHARACTER BACK TO THE CONSOLE ** ld b,a ;temporarily store the character conout4:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conout4 ;loop if not ready ld a,b ;retrieve the character out (wrreg),a ;output to transmitter buffer and 0DFh ;convert character to upper case jp (ix) ;return ;************************************************************************ ;* C * ;* COMMAND C: CURRENT. LIST CURRENT LOCATION OF MONITOR PROGRAM * ;* C * ;************************************************************************ ;** SEND A space ** curr: cp 'C' jr nz,dump curr1: in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,curr1 ;loop if not ready ld a,' ' out (wrreg),a ;output to transmitter buffer ld iy,byte0+1 ;IY<--pointer to location having starting addr ld a,(iy) ;high byte of first memory location of this mon ld ix,curr2 lbyte24:ld iy,lbyte jp (iy) ;list the first byte to the console curr2: ld iy,byte0 ;IY<--pointer to location having starting addr ld a,(iy) ;low byte of first memory location of this mon ld ix,strt ;no need to return to this routine:ret to start byte0 equ $-2 ;label for addressing first byte (for Relocate) jr lbyte24 ;************************************************************************ ;* D * ;* COMMAND D: DUMP. DISPLAY MEMORY FROM XXXX TO XXXX * ;* D * ;************************************************************************ dump: cp 'D' jr z,isdump ld iy,fill jp (iy) isdump: ld ix,dumpr ld c,2 ;set to get 2 parameters expr13: ld iy,expr ;get start address (D'E') and end addr (H'L') jp (iy) dumpr: exx ;start addr=DE, end addr=HL ld b,d ;save a copy of start address for ASCII dump ld c,e ; BC<--DE dump1: ld ix,dump7 crlf08: ld iy,crlf ;print a carriage return and line feed jp (iy) dump7: ld ix,dump2 ld iy,abort ;test to see if ^C has been typed, abort if so jp (iy) dump2: ld a,d ;send high byte of start address to console ld ix,dump3 lbyte21:ld iy,lbyte jp (iy) dump3: ld a,e ;send low byte of start address to console ld ix,dmemhex lbyte22:jr lbyte21 ;******************************** ;* PRINT IN HEX * ;******************************** ;** PRINT A SPACE ** dmemhex:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,dmemhex ;loop if not ready ld a,' ' ;space out (wrreg),a ;output to transmitter buffer ld a,e ;low byte of memory pointer and 7 ;low nybble of memory pointer jr z,conout5 ;insert space if 8 bytes printed cp 4 ;insert space if 4 or 12 bytes printed jr nz,dump4 ;don't insert space if not 4 or 12 ;** PRINT A SPACE ** conout5:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conout5 ;loop if not ready ld a,' ' ;space out (wrreg),a ;output to transmitter buffer dump4: ld a,(de) ;get contents of the current memory location ld ix,dump5 ;convert the a register to ascii and print jr lbyte21 dump5: inc de ;next successive memory location ld a,e and 0Fh jr nz,dmemhex ;loop ;******************************** ;* PRINT IN ASCII * ;******************************** ;** PRINT A SPACE ** conout9:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conout9 ;loop if not ready ld a,' ' ;space out (wrreg),a ;output to transmitter buffer nop ;delay for Morrow Microdecision hardware ;** PRINT A SPACE ** conoute:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conoute ;loop if not ready ld a,' ' ;space out (wrreg),a ;output to transmitter buffer nop ;delay for Morrow Microdecision hardware ;** PRINT AN ASTERIX ** conouth:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conouth ;loop if not ready ld a,'*' ;space out (wrreg),a ;output to transmitter buffer ;** DETERMINE IF A GROUP OF 4 CHARACTERS HAS BEEN PRINTED YET ** dmemasc:ld a,c ;low byte of memory pointer and 0Fh jr z,dump6 and 07h ;low nybble of memory pointer jr z,conoutf cp 4 jr nz,dump6 ;** PRINT A '|' to seperate groups of 4 ASCII characters ** conoutf:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conoutf ;loop if not ready ld a,'|' ;space out (wrreg),a ;output to transmitter buffer ;** TURN THE CHARACTER INTO ASCII AND PRINT IT ** nop ;delay for Morrow Microdecision hardware dump6: in a,(status) ;Get communications port status and wrbit ;test if ready to send a character jr z,dump6 ;loop if not ready ld a,(bc) ;Get contents of memory location cp ' ' jr c,mkspace ;Iæ lesó thaî á spacå (i.e® nonprintinç char) cp 07Fh jr c,charok ;If a printing character mkspace:ld a,' ' ;prepare to print a space charok: out (wrreg),a ;Output to transmitter buffer inc bc ;next successive memory location ld a,c ;low byte of current address and 0Fh ;16 bytes per line of display jr nz,dmemasc ;loop to print out next memory location content ;** PRINT AN ASTERIX because 16 bytes have been printed ** conoutg:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conoutg ;loop if not ready ld a,'*' ;asterix out (wrreg),a ;output to transmitter buffer ;** SEE IF END OF DUMP REACHED ** ld a,b or c jr nz,NOTYET ;THIS IS A LOUSEY LABEL NAME:FIND A BETTER ONE strt02: ld iy,strt jp (iy) NOTYET: ld a,l sub c ld a,h sbc a,b jr c,strt02 ld iy,dump1 jp (iy) ;************************************************************************ ;* F * ;* COMMAND F: FILL. FILL MEMORY FROM XXXX TO XXXX WITH XX * ;* F * ;************************************************************************ fill: cp 'F' jr nz,go ld ix,fill1 ld c,3 ;set to get 3 parameters expr11: jr expr10 ;get start address, end address, and fill byte fill1: exx ;after exx: BC=start adr,DE=end adr,L=fill byte ld a,l ;register A has fill byte ld h,b ;HL<--BC (start addr ends up in HL) ld l,c ld c,a ;register C has fill byte fill2: ld (hl),c ;store fill byte to memory ld a,l ;compare a byte of end addr with current addr sub e jr nz,bump ;if different ld a,h ;compare 2nd byte of end addr with current addr sub d bump: inc hl ;increment start addr toward end address jr nz,fill2 jr strt02 ;finished filling, go get another command ;************************************************************************ ;* G * ;* COMMAND G: GO. GOTO (EXECUTE) XXXX * ;* G * ;************************************************************************ go: cp 'G' jr nz,hex ld ix,go1 ld c,1 ;set to get 1 parameter expr10: jr expr09 go1: jp (hl) ;************************************************************************ ;* H * ;* COMMAND H: HEX. HEXIDECIMAL ARITHMETIC * ;* H * ;************************************************************************ hex: cp 'H' jr nz,in ld ix,hex1 ld c,2 ;set to get 2 parameters expr09: jr expr08 ;Get first number in D'E', 2nd number in H'L' hex1: exx ;first number in DE, second number in HL ld ix,hex2 crlf05: jr crlf04 ;print a carriage return and line feed hex2: ld b,h ;BC<--HL ld c,l ;save a copy of HL in BC add hl,de ;SUM ld a,h ;prepare to print the high byte of the sum ld ix,hex3 lbyte18:ld iy,lbyte ;print the high byte jp (iy) hex3: ld a,l ;prepare to print the low byte of the sum ld ix,conoutp jr lbyte18 ;** PRINT A SPACE to separate the sum from the difference ** conoutp:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conoutp ;loop if not ready ld a,' ' ;space out (wrreg),a ;output to transmitter buffer ld h,b ;HL<--BC ld l,c ;Get a fresh copy of the second parameter ex de,hl or a sbc hl,de ld a,h ;prepare to print the high byte of difference ld ix,hex4 lbyte16:jr lbyte15 ;print the high byte hex4: ld a,l ;prepare to print the low byte of the sum ld ix,strt ;finished after print difference, get next cmd lbyte15:jr lbyte14 ;************************************************************************ ;* I * ;* COMMAND I: INPUT. INPUT DATA FROM I/O PORT * ;* I * ;************************************************************************ in: cp 'I' jr nz,move ld ix,in1 ld c,1 ;set to get 1 parameter expr08: jr expr07 ;get the 1 parameter (the port number) in1: ld c,l ;port to input from is in register L ld ix,conoutj crlf04: jr crlf03 ;** PRINT A SPACE to separate port number from hexidecimal data ** conoutj:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conoutj ;loop if not ready ld a,' ' ;space out (wrreg),a ;output to transmitter buffer in e,(c) ;get data from port in a,(c) ;get data from port for use with lbyte ld ix,in2 lbyte14:ld iy,lbyte jp (iy) ;print port data in hexidecimal in2: ld b,08 ;count=8 bits to display ;** PRINT A SPACE to separate hexidecimal from binary display ** conoutk:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conoutk ;loop if not ready ld a,' ' ;space out (wrreg),a ;output to transmitter buffer in3: nop ;delay for Morrow Microdecision hardware conoutL:in a,(status) ;Get communications port status and wrbit ;test if ready to send a character jr z,conoutL ;loop if not ready sla e ;shift port data high bit into carry bit ld a,018h ;(18h)x2='0' adc a,a ;(18h)x2+carry bit --> '0' or '1' out (wrreg),a ;output '0' or '1' to transmitter buffer djnz in3 ;decrement count, go print next bit strt06: ld iy,strt jp (iy) ;finished with I command, go get another commnd ;************************************************************************ ;* M * ;* COMMAND M: MOVE. MOVE DATA STARTING XXXX AND ENDING XXXX, TO XXXX * ;* M * ;************************************************************************ move: cp 'M' jr nz,out ld ix,move1 ld c,3 ;set to get 3 parameters expr07: jr expr06 move1: exx ;start=BC, end=DE, destination=HL move2: ld a,(bc) ;get a byte from the source ld (hl),a ;put the byte into the destination ld a,c ;low byte of current source cp e ;low byte of end source jr nz,minc ;if not equal, go prepare to move next byte ld a,b ;high byte of current source cp d ;high byte of end source jr nz,minc ;if not equal, go prepare to move next byte strt07: jr strt06 ;end of move reached, go get another command minc: inc bc ;increment source location inc hl ;increment destination location jr move2 ;go move next byte ;************************************************************************ ;* O * ;* COMMAND O: OUTPUT. OUTPUT TO PORT XX THE DATA XX * ;* O * ;************************************************************************ out: cp 'O' jr nz,reloc ld ix,out1 ld c,2 ;set to get 2 parameters expr06: jr expr05 ;get port (register E') and data (register L') out1: exx ;port is in register E, data is in register L ld c,e ;port is in register c out (c),l ;output data to port strt08: jr strt07 ;finished outputing, go get another command ;************************************************************************ ;* R * ;* COMMAND R: RELOCATE. RELOCATE ROM CODE TO ANY PAGE BOUNDARY XXXX * ;* R * ;************************************************************************ reloc: cp 'R' jr nz,set ld ix,reloc1 ld c,1 ;set to get 1 parameter expr05: jr expr04 ;returns destination address XXXX in HL & H'L' crlf03: jr crlf ;relative jump station reloc1: ld a,low strt ;>>>low byte must be same as first low byte<<<< cp l ;>following port initialization code<<<<<<<<<<< jr z,reloc3 ld ix,error ;if not zero (meaning not a page boundary) jp (ix) reloc3: ld iy,byte0 ;IY<--pointer to location having starting addr ld e,(iy) ;low byte of first memory location of this mon ld d,(iy+1) ;high byte of first memory location of this mon ex de,hl ;DE=destination, HL=source ld bc,mvlen ;BC=count: length of relocating code to move ld a,d ;high byte of destination address sub h ;high byte of source address--->offset exx ld d,a ;D=offset exx reloc4: ld a,b ;BC register pair = count of bytes to move or c ;test to see if count has reached zero jr z,exreloc ;if all code relocated,jump into relocated code ld a,(hl) ;get a byte from source ldi ;copy source byte to destination,dec count cp 0DDh ;0DDh=1st of 2 bytes of LD IX,data instruction jr z,endtest ;if was 0DDh cp 0FDh ;0FDh=1st of 2 bytes of LD IY,data instruction jr nz,reloc4 ;if was not LD IX or IY,data instruction endtest:ld a,(hl) ;get a byte from source cp 021h ;021h=2nd byte of LD IX OR IY,data instructions ldi ;relocate(possible)2nd of 2 bytes of instruct'n jr nz,reloc4 ;if not LD IX or IY,data instruction ;*THIS CODE EXECUTES IF A LD IX,DATA OR LD IY,DATA INSTRUCTION IS BEING COPIED* ldi ;relocate low byte of 2 bytes of data exx ld a,d ;put the offset into the A register exx addoff: add a,(hl) ;add source byte to offset ld (de),a ;store byte (with offset added) in destination dec bc ;decrement count inc de ;increment destination pointer inc hl ;increment source pointer jr reloc4 EXRELOC:exx jp (hl) ;jump to START: in new location ;************************************************************************ ;* * ;* "SUBROUTINE" to send a carriage return and a line feed. * ;* * ;************************************************************************ ;** SEND A CARRIAGE RETURN ** crlf: in a,(status) ;Get communications port status and wrbit ;test if ready to send a character jr z,crlf ;loop if not ready ld a,cr out (wrreg),a ;output to transmitter buffer nop ;delay for Morrow Microdecision MD3 hardware ;** SEND A LINE FEED ** conout2:in a,(status) ;Get communications port status and wrbit ;test if ready to send a character jr z,conout2 ;loop if not ready ld a,lf out (wrreg),a ;output to transmitter buffer jp (ix) ;return ;************************************************************************ ;* S * ;* COMMAND S: SET. EXAMINE AND (OPTIONALLY) CHANGE MEMORY DATA * ;* S * ;************************************************************************ set: cp 'S' jr nz,test ld ix,set1 ld c,1 ;set to get 1 parameter expr04: jr expr03 set1: cp cr ;was a carriage return typed following the addr jr nz,set2 ;if not a carriage return strt09: ld iy,strt jp (iy) ;if a carriage return, exit this set command set2: ld a,(hl) ld ix,conouti lbyte12:ld iy,lbyte jp (iy) ;convert register A to ASCII and print it ;** PRINT A '-' ** conouti:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conouti ;loop if not ready ld a,'-' ;seperate and prompt for optional memory change out (wrreg),a ;output to transmitter buffer ;** GET A CHARACTER FROM THE CONSOLE ** conin3: in a,(status) ;read status register and rdbit jr z,conin3 ;no character ready, loop in a,(rdreg) ;read character and 07Fh ;strip parity ;************************************************************************ ;* * ;* CHARACTER CHECK: check for space or comma or carriage return. * ;* Return with carry set if a carriage return, clear if anything * ;* else. Return with zero set if a space or comma. * ;* * ;************************************************************************ cp ' ' ;is it a space jr z,eval1 ;return zero set, carry cleared if ' ' cp ',' ;is it a comma jr z,eval1 ;return zero set, carry cleared if ',' cp 00DH ;is it a carriage return scf jr z,eval1 ;return carry and zero set if a carriage return ccf ;ret carry and zero cleared if not cr, ',', ' ' eval1: jr c,strt09 ;exit from set routine if a CR typed jr z,su1 ;if it was space or comma ld d,h ;save memory location in de ld e,l ; DE<--HL ld hl,0 ;initialize ld c,001h ;count of bytes to get ld ix,change ld iy,get1 ;returns new value for memory location in reg L jp (iy) change: ex de,hl ;HL=memory location E=new value in hexidecimal ld (hl),e ;change value of memory location ;ex1 also returns a next character in reg. A cp CR ;was it a carriage return? jr z,strt09 ;exit from set routine if a CR typed su1: inc hl ld ix,sendh crlf1: jr crlf sendh: lä a,è ;senä thå È bytå tï thå console ld ix,lbyter lbyte11:jr lbyte10 ;CALL LBYTE lbyter: ld a,l ;send the L byte to the console ld ix,conoutb lbyte10:jr lbyte09 ;CALL LBYTE ;*ª SENÄ Á SPACÅ ** conoutB:in a,(status) ;Get communications port status and wrbit ;test if ready to send a character jr z,conoutb ;loop if not ready ld a,' ' ;ASCII space out (wrreg),a ;output to transmitter buffer jr set1 ;loop (print new location value, etc.) strt10: jr strt09 ;relative jump station ;************************************************************************ ;* T * ;* COMMAND T: TEST. TEST MEMORY FROM XXXX TO XXXX * ;* T * ;************************************************************************ test: cp 'T' jr nz,verify ld ix,test1 ld c,2 ;set to get 2 parameters expr03: jr expr02 ;get two parameters, return them in aux. regs. test1: exx ; HL=start addr, DE=end addr ex de,hl ; DE=end addr, HL=start addr t1: ld ix,t3 abort8: jr abort7 ;see if ^S (stop scrolling) or ^C typed (abort) t3: ld a,(hl) ;get contents of memory location ld b,a ;temporarily save contents of memory location cpl ;compliment value of memory location ld (hl),a ;store complimented value in memory location xor (hl) ;make a bit display of bad bits (1=bad) ld (hl),b ;restore originally read contents of memory jò z,t² ;iæ nï error ld c,a ;register C=bit display ld a,h ;send the H byte to the console ld ix,tbyte lbyte09:jr lbyte08 ;call lbyte tbyte: ld a,l ;send the L byte to the console ld ix,conoutc lbyte08:jr lbyte07 ;call lbyte ;*ª SENÄ Á SPACÅ ** conoutc:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conoutc ;loop if not ready ld a,' ' ;ASCII space out (wrreg),a ;output to transmitter buffer ld b,008h ;count 8 bits ;*ª SENÄ Á "bit" ** conoutd:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conoutd ;loop if not ready sla c ;move bit 7 to carry ld a,018h ;2 times 18h=30h=ASCII 0 adc a,a ;reg. A='0'if no carry, '1' if carry out (wrreg),a ;Output to transmitter buffer djnz conoutd ;if all 8 bits not printed yet ld ix,t2 crlf2: jr crlf1 ;send a carriage return/line feed t2: ld a,l ;compare a byte of end addr with current addr sub e jr nz,bump1 ;if different ld a,h ;compare 2nd byte of end addr with current addr sub d bump1: inc hl ;increment start addr toward end address jr nz,t1 strt11: jr strt10 ;finished testing, go get another command ;************************************************************************ ;* V * ;* COMMAND V: VERIFY. VERIFY MEMORY XXXX TO XXXX WITH XXXX * ;* V * ;************************************************************************ verify: cp 'V' IF ALIGNMENT jr nz,alnmnt else jr nz,error endif ld ix,ver1 ld c,3 ;set to get 3 parameters expr02: ld iy,expr jp (iy) ver1: exx ;from=BC, to=DE, with=HL vertst: ld ix,ver2 ABORT7: LD IY,ABORT ;see if ^S (stop scrolling) or ^C typed (abort) JP (IY) ver2: ld a,(bc) ;get a byte from the "from" block cp (hl) ;compare with a byte from the "with" block jr z,vadcmp ;if the bytes are the same ld ix,vererr jr crlf2 ;print a carriage return-line feed vererr: ld a,b ;high byte of "from" byte address ld ix,ver3 ;CALL LBYTE lbyte07:JR lbyte06 ver3: ld a,c ;low byte of "from" byte address ld ix,conoutn ;CALL LBYTE lbyte06:jr lbyte05 ;*ª SENÄ Á SPACÅ ** conoutn:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conoutn ;loop if not ready ld a,' ' ;ASCII space out (wrreg),a ;output to transmitter buffer ld a,(bc) ;data byte of "from" block ld ix,conouto ;CALL LBYTE lbyte05:JR lbyte04 ;*ª send Á space ** conouto:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conouto ;loop if not ready ld a,' ' ;ASCII space out (wrreg),a ;output to transmitter buffer ld a,h ;high byte of "with" byte address ld ix,ver4 ;call lbyte lbyte04:jr lbyte03 ver4: ld a,l ;low byte of "with" byte address ld ix,conoutm ;CALL LBYTE lbyte03:jr lbyte02 ;*ª SENÄ Á SPACÅ separating "with" address and "with" byte ** conoutm:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conoutm ;loop if not ready ld a,' ' ;ASCII space out (wrreg),a ;output to transmitter buffer ld a,(hl) ;data byte of "with" block ld ix,vadcmp ;call LBYTE lbyte02:ld iy,lbyte jp (iy) vadcmp: ld a,e ;low byte of finish address cp c ;low byte of current "from" address JR nz,verinc ;if current address not equal final address ld a,d ;high byte of finish address cp b ;high byte of current "from" address jr z,strt11 ;if current address equal final address, done verinc: inc bc ;next address to get a byte from inc hl ;next address to compare a byte to jr vertst ;go compare the next two bytes ;************************************************************************ ;* * ;* At this point the character entered following the monitor * ;* prompt has been checked to see if it is a valid command for * ;* any of the routines in the monitor. * ;* * ;************************************************************************ IF ALIGNMENT alnmnt: ld iy,strt ;alignmnt pgm uses jp (iy) to return to monitor cp 03h ;03h is ^C enter ALIGNMENT tool jr nz,error ;if character has not matched any command LD HL,STACK ld sp,HL;;;;;;;stack ;starting address of stack ld a,(hasrun) ;step puts a data byte into data RAM to show... cp runchr ; ...that step has run so don't repaint screen jp nz,align ;enter step,repaint screen(note:not relocatable call resbuf ;enter from MON if align has: reset cmd buffer jp comand ;enter step, don't destroy screen display ENDIF ;** send a question mark ** error: in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,error ;loop if not ready ld a,'?' out (wrreg),a ;output to transmitter buffer strt12: ld iy,strt ;invalid character, loop back to get another jp (iy) ;************************************************************************ ;* * ;* GET PARAMETERS 1,2,OR 3 (enter with register C=1,2,or 3) * ;* These parameters are returned in the alternate registers as * ;* follows: * ;* Most recently received parameter goes to H'L'. * ;* Second most recently received parameter goes to D'E'. * ;* Third most recently received parameter goes to B'C'. * ;* Additionally, the most recently received parameter is also * ;* returned in the primary HL register. This routine expects * ;* parameters to be seperated by a comma or a space and the * ;* final parameter to be followed by a carriage return. * ;* Parameters are checked to see if each character of the * ;* parameter is a valid hex digit. If an invalid character is * ;* typed this routine jumps to the "?" error printing routine. * ;* * ;************************************************************************ expr: ld hl,0 ;initialize the HL register;if entered here get 2 parms ex0: ;** GET A CHARACTER FROM THE CONSOLE ** conin2: in a,(status) ;Read status register and rdbit jr z,conin2 ;no character ready, loop in a,(rdreg) ;read character and 07Fh ;strip parity get1: ld b,a ;temporarily save the character ;** ECHO THE CHARACTER BACK TO THE CONSOLE ** conout7:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conout7 ;loop if not ready ld a,b ;get character from temporary storage out (wrreg),a ;output to transmitter buffer ;************************************************************************ ;* * ;* UNIBBLE: CONVERT ASCII CHARACTER IN REGISTER A TO A BINARY * ;* DIGIT. RETURN WITH CARRY SET IF CHARACTER IS INVALID (NOT * ;* 0-9 OR A-F) * ;* * ;************************************************************************ nibble: cp 'a' ;is it less than lower case 'a'? jr c,nibok ;take jump if so cp 'z'+1 ;less than a lower case 'z'? ccf ;set carry and return if > 'z' jr c,inst5 ;ret c sub ' ' ;convert to upper case nibok: sub 030H ;'0' jr c,inst5 ;return if less than '0' cp 017h ;was it greater than 'F' (before conversion) ? ccf jr c,inst5 ;ret c cp 00AH ;is it 0-9? ccf jr nc,inst5 ;ret nc ;RETURN IF 0-9 sub 007H ;convert to Ah to Fh cp 00AH inst5: jr c,ex2 ;returns carry set if not a valid digit (0-Fh) ; jump if a valid digit not returned add hl,hl ;on first pass HL is 0 as initialized above add hl,hl ;on successive passes each nybble is shifted add hl,hl ; into next higher nybble add hl,hl or l ;add nybble from register A to register L ld l,a ;save in register L jr ex0 ;go get another character (nybble) from console ;************************************************************************ ;* * ;* received parameters are saved by "pushing" them into the * ;* alternate secondary registers. * ;* * ;* Most recently received parameter goes to H'L'. * ;* Second most recently received parameter goes to D'E'. * ;* Third most recently received parameter goes to B'C'. * ;* * ;************************************************************************ ex2: exx ld C,E ;B'C'<--D'E' C'<--E' ld B,D ; B'<--D' ld E,L ;D'E'<--H'L' E'<--L' ld D,H ; D'<--H' exx ;H'L'<--HL ld A,H ; GET H exx ld H,A ; H'<--H exx ld A,L ; GET L exx ld L,A ; L'<--L exx ;************************************************************************ ;* * ;* CHARACTER CHECK: check for space or comma or carriage return. * ;* Return with carry set if a carriage return, clear if anything * ;* else. Return with zero set if a space or comma. * ;* * ;************************************************************************ ld a,b ;get the original unconverted character cp ' ' ;is it a space jr z,call39 ;zero set, carry cleared if ' ' cp ',' ;is it a comma jr z,call39 ;zero set, carry cleared if ',' cp cr ;is it a carriage return scf jr z,call39 ;carry and zero set if a carriage return ccf ;carry and zero cleared if not cr, ',', ' ' call39: jr nc,ex3 ;if not a carriage return jr z,exend ;return if all parameters gotten ex3: jr nz,error ;if not a space, comma, or carriage return dec c ;decrement count of parameters jr nz,expr ;if not all parameters received, get more exend: jp (ix) ;RETURN ;************************************************************************ ;* * ;* ROUTINE LBYTE: convert register A to ASCII and print it * ;* alternate registers B,C, and D are corrupted * ;* * ;************************************************************************ lbyte: exx ;PRESERVE BC,DE,HL FOR THE CALLING ROUTINE ld c,2 ;count 2 nybbles ld d,a ;store a copy of the byte being printed ;** CONVERT REGISTER A TO ASCII AND PRINT IT ** rrca ;get the high nybble first rrca rrca rrca ;** CONVERT HEX TO ASCII ** uconv: and 00fh ;convert the low nybble to an ASCII character add a,090H daa adc a,040H daa ;** SEND TO CONSOLE THE NYBBLE WHICH HAS BEEN CONVERTED TO ASCII ** ld b,a ;temporary storage of character to output conout8:in a,(status) ;get communications port status and wrbit ;test if ready to send a character jr z,conout8 ;loop if not ready ld a,b ;get character from temporary storage out (wrreg),a ;output to transmitter buffer ld a,d ;get another copy of the byte to print dec c ;count of nybbles converted jr nz,uconv ;convert and print the second nybble exx jp (ix) ;return ;************************************************************************ ;* * ;* ROUTINE ABORT: check to see if a ^C has been typed at the * ;* console and do not return to the calling routine if * ;* so. Instead, go get another command. * ;* If ^S was typed loop in this routine waiting * ;* for any other character before returning to caller. * ;* * ;************************************************************************ abort: in a,(status) ;read status register and rdbit jr nz,abort1 ;if character has been typed jp (ix) ;no character has been typed, return to caller abort1: in a,(rdreg) ;Read character and 07Fh ;strip parity cp 03 ;03=^C jr nz,abort4 ;if not ^C strt13: ld iy,strt ;^C has been typed, abort the calling routine jp (iy) abort4: cp 013h ;13h=^S jr nz,abort3 ;no ^C or ^S typed so return to caller abort2: in a,(status) ;read status register and rdbit jr z,abort2 ;no character typed, loop and wait for char. in a,(rdreg) ;input the character cp 03 ;03=^C jr z,strt13 ;if ^C, else fall thru to return to caller abort3: jp (ix) ;no ^C typed so return to caller endmon: mvlen equ endmon-strt ;length of code to move endif ;endif of if monitor