;NEWMON.MAC: ROM monitor program. Uses no RAM !! ;BEGUN 01/09/88 RONALD E. JACOBS ;latest work done 03/02/89 LF EQU 00Ah ;ASCII line feed character CR EQU 00Dh ;ASCII carriage return character TRUE EQU 001h FALSE EQU 000h .Z80 ;USE Z80 NMEMONICS org 0 ;************************************************************************ ;* * ;* USER SETTABLE EQUATES: * ;* CONSOLE PORT INFORMATION: Only one may be true * ;* PROMPT SELECTION: A printing character of your choice * ;* * ;************************************************************************ MD3 EQU true ;MORROW MD2 OR MD3 MICRODECISION WB14 EQU false ;MORROW WUNDERBUS OR MULT/IO BOARD MDHD EQU false ;MORROW HARD DISK MICRODECISION 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 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) ; I/O Registers - Serial Ports ;MORROW HARD DISK MICRODECISION ;----------------------------- ; 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 ; I/O Registers - Counter Timer Chip ;----------------------------------- ; 1) The labels baud0, baud1 and baud2 correspond to the schematic labels ; for the signals carrying the baud rate clocks to the dart/sio. baud0 ; is the clock for serial port 1. ; baudset equ 53h ;ctc channel select/mode port baud0 equ 52h ;baud rate control for serial port 1 (consol) baud1 equ 51h ;baud rate control for serial port 2 baud2 equ 50h ;baud rate control for serial port 3 $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: INITUART (INITIALIZE MICRODECISION MD2, MD3 UARTS) ;--------------------- ; ; Function: 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, 1200 baud on the printer ; UART, and maximum delay on the drive time out counter. ; IF MD3 inituart: ld hl,init_tab ;pointer to init data table ld b,init_len ;init data table length init_loop: ld c,(hl) ;port address inc hl ld a,(hl) ;data inc hl out (c),a ;output data to port djnz init_loop ;loop until done ENDIF ;end of MD2/MD3 port initialization code ;INTURT - Initialize the Serial I/O Devices(12_Nov_83)(HARD DISK MICRODECISION) ;------------------------------------------------------- ; function: 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 inturt: 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): ; INTCTC - Initialize the Counter Timer Chip Baud Rates (12_Jan_84) ;------------------------------------------------------------------ ; 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 ; IntCTC: 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 * ;* A Align: enter Alignment tool * ;* 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 jr crlf09 ;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 ; jr nz,error ;if not O, W, I, R then error 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 strt01: jr strt ;relative jump station crlf09: jr crlf08 ;relative jump station ;************************************************************************ ;* 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 lbyte25:jr lbyte24 ;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) lbyte24:jr lbyte23 ;************************************************************************ ;* D * ;* COMMAND D: DUMP. DISPLAY MEMORY FROM XXXX TO XXXX * ;* D * ;************************************************************************ dump: cp 'D' jr nz,fill3 ld ix,dumpr ld c,2 ;set to get 2 parameters expr13: jr expr12 ;get start address (D'E') and end addr (H'L') 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: jr crlf07 ;print a carriage return and line feed dump7: ld ix,dump2 jr abort14 ;test to see if ^C has been typed, abort if so dump2: ld a,d ;send high byte of start address to console ld ix,dump3 lbyte23:jr lbyte22 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 lbyte21:jr lbyte20 dump9: jr dump1 ;relative jump station fill3: jr fill ;relative jump station strt02: jr strt01 ;relative jump station expr12: jr expr11 ;relative jump station abort14:jr abort13 ;relative jump station crlf07: jr crlf06 ;relative jump station 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 ' ' JÒ 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 z,strt02 ld a,l sub c ld a,h sbc a,b jr nc,dump9 strt03: jr strt02 abort13:jr abort12 ;relative jump station lbyte20:jr lbyte19 ;relative jump station ;************************************************************************ ;* 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 lbyte19:jr lbyte18 ;relative jump station crlf06: jr crlf05 ;relative jump station 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 strt04: jr strt03 ;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:jr lbyte17 ;print the high byte hex3: ld a,l ;prepare to print the low byte of the sum ld ix,conoutp lbyte17:jr lbyte16 ;** 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 strt05: jr strt04 ;relative jump station abort12:jr abort11 ;relative jump station ;************************************************************************ ;* 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:jr lbyte13 ;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: jr strt05 ;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 abort11:jr abort10 ;relative jump station ;************************************************************************ ;* 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' lbyte13:jr lbyte12 ;relative jump station 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<<<<<<<<<<< ; xor a ;zero A ; or l ;L must be zero: XXXX must be a page boundary 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 ; ld de,byte0 ;initial address of block of ROM to move 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 strt09: jr strt08 ;relative jump station abort10:jr abort9 ;relative jump station ;************************************************************************ ;* 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 z,strt09 ;if a carriage return, exit this set command ld a,(hl) ld ix,conouti lbyte12:jr lbyte11 ;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 abort9: jr abort8 ;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: jr abort6 ;see if ^S (stop scrolling) or ^C typed (abort) 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:jr lbyte01 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 'A' ;enter ALIGNment tool and paint the screen jp z,align ; display (NOTE:not a relocatable address) cp 03h ;03h is ^C enter ALIGNMENT tool without des- jp z,comand ; troying screen display (not relocatable) 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) lbyte01:jr lbyte ;relative jump station abort6: jr abort5 ;relative jump station ;************************************************************************ ;* * ;* 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 abort5: jr abort ;relative jump station ;************************************************************************ ;* * ;* 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 z,strt13 ;^C has been typed, abort the calling routine 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 ;ENDIF ;ENDIF OF IF MONITOR ;IF MONITOR ENDMON: ;bitmap EQU ENDMON ;END OF MONITOR CODE ;IF (ENDMON-BYTE0) MOD 8 ;FALSE IF REMAINDER=0 TRUE IF REMAINDER NE 0 ;REMAIN EQU 1 ;ANOTHER (FRACTION OF A) BYTE IS NEEDED ;ELSE ;REMAIN EQU 0 ;CODE LENGTH IS DIVISABLE BY 8 FOR BITMAP ;ENDIF ;BITLEN EQU (ENDMON-BYTE0)/8+REMAIN ;length of bitmap MVLEN EQU ENDMON-strt ;length of code to move ;DS BITLEN ;BITMAP WILL BE PATCHED INTO THIS SPACE ENDIF ;ENDIF OF IF MONITOR