;NEWMON.MAC: ROM monitor program. Uses no RAM !! ;BEGUN 01/09/88 RONALD E. JACOBS ;latest work done 10/11/88 LF EQU 00Ah ;ASCII line feed character CR EQU 00Dh ;ASCII carriage return character TRUE EQU 001h FALSE EQU 000h .Z80 ;USE Z80 NMEMONICS ;************************************************************************ ;* * ;* 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 * ;* * ;************************************************************************ BYTE0: ;label for addressing first byte (for Relocate) ;---------------------------------------------------------------------- ; 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 START: IF MONITOR LD IX,CONOUT3 JP CRLF ;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,FIND JP GETCHR ;Get character from console, echo it back find: LD C,2 ;INITIALIZE TO GET 2 PARAMETERS ;** TEST IF CHARACTER IS A VALID COMMAND ** IF ALIGNMENT CP 'A' ;enter ALIGNment tool JP Z,ALIGN ENDIF CP 'C' JP Z,CURR ;display CURRent location CP 'D' JP Z,DUMP CP 'F' JP Z,FILL CP 'G' JP Z,GO CP 'H' JP Z,HEX CP 'I' JP Z,IN CP 'L' JP Z,LOOP CP 'M' JP Z,MOVE CP 'O' JP Z,OUT CP 'R' JP Z,RELOC ;RELOCate ROM code to RAM CP 'S' JP Z,SET CP 'T' JP Z,TEST CP 'V' JP Z,VERIFY ;** 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 JP START ;INVALID CHARACTER, LOOP BACK TO GET ANOTHER ;************************************************************************ ;* C * ;* COMMAND C: CURRENT. LIST CURRENT LOCATION OF MONITOR PROGRAM * ;* C * ;************************************************************************ ;** SEND A space ** CURR: IN A,(STATUS) ;Get communications port status AND WRBIT ;test if ready to send a character JR Z,CURR ;loop if not ready LD A,' ' OUT (WRREG),A ;Output to transmitter buffer ld a,high byte0 ;high byte of first memory location of this mon LD IX,curr1 jp lbyte ;list the first byte to the console curr1: ld a,low byte0 ;low byte of first memory location of this mon. ld ix,start ;no need to return to this routine jp lbyte ;************************************************************************ ;* D * ;* COMMAND D: DUMP. DISPLAY MEMORY FROM XXXX TO XXXX * ;* D * ;************************************************************************ DUMP: ld ix,dumpr jp expr ;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 jp crlf ;print a carriage return and line feed dump7: ld ix,dump2 jp abort ;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 jp lbyte dump3: ld a,e ;send low byte of start address to console ld ix,dmemhex jp lbyte ;******************************** ;* 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 jp lbyte 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 jp 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 jp z,start ld a,l sub c ld a,h sbc a,b jp nc,dump1 jp start ;************************************************************************ ;* F * ;* COMMAND F: FILL. FILL MEMORY FROM XXXX TO XXXX WITH XX * ;* F * ;************************************************************************ FILL: ld ix,fill1 jp expr3 ;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 jp 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 jp nz,fill2 jp start ;finished filling, go get another command ;************************************************************************ ;* G * ;* COMMAND G: GO. GOTO (EXECUTE) XXXX * ;* G * ;************************************************************************ GO: LD IX,GO1 JP EXPR1 go1: jp (hl) ;************************************************************************ ;* H * ;* COMMAND H: HEX. HEXIDECIMAL ARITHMETIC * ;* H * ;************************************************************************ HEX: LD IX,HEX1 JP EXPR ;Get first number in D'E', 2nd number in H'L' hex1: exx ;first number in DE, second number in HL ld ix,hex2 jp crlf ;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 jp lbyte ;print the high byte hex3: ld a,l ;prepare to print the low byte of the sum ld ix,conoutp jp lbyte ;** 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 jp lbyte ;print the high byte hex4: ld a,l ;prepare to print the low byte of the sum ld ix,start ;finished after print difference, get next cmd jp lbyte ;************************************************************************ ;* I * ;* COMMAND I: INPUT. INPUT DATA FROM I/O PORT * ;* I * ;************************************************************************ IN: LD IX,IN1 JP EXPR1 ;get the 1 parameter (the port number) in1: ld c,l ;PORT TO INPUT FROM IS IN REGISTER L ld ix,conoutj jp crlf ;** 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 jp lbyte ;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 jp start ;finished with I command, go get another commnd ;************************************************************************ ;* 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: ld ix,loop1 jp getchr ;get a character from the console, echo back loop1: LD C,2 ;INITIALIZE TO GET 2 PARAMETERS cp 'O' jp z,loopo cp 'W' jp z,loopw cp 'I' jp z,loopi cp 'R' jp nz,error ;if not O, W, I, R then error ;**************************** ;* Read a memory location * ;**************************** loopr: ld ix,loopr1 jp expr1 loopr1: ld a,(hl) ;read from a memory address jr loopr1 ;************************* ;* Input a port address * ;************************* loopi: ld ix,loopi1 jp expr1 loopi1: ld c,l loopi2: in a,(c) ;input from a port jr loopi2 ;******************** ;* Write to memory * ;******************** loopw: ld ix,loopw1 jp expr 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 jp expr 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 ;************************************************************************ ;* M * ;* COMMAND M: MOVE. MOVE DATA STARTING XXXX AND ENDING XXXX, TO XXXX * ;* M * ;************************************************************************ MOVE: LD IX,MOVE1 JP EXPR3 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 jp start ;end of move reached, go get another command minc: inc bc ;increment source location inc hl ;increment destination location jp move2 ;go move next byte ;************************************************************************ ;* O * ;* COMMAND O: OUTPUT. OUTPUT TO PORT XX THE DATA XX * ;* O * ;************************************************************************ OUT: LD IX,OUT1 JP EXPR ;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 jp start ;finished outputing, go get another command ;************************************************************************ ;* R * ;* COMMAND R: RELOCATE. RELOCATE ROM CODE TO ANY PAGE BOUNDARY XXXX * ;* R * ;************************************************************************ RELOC: LD IX,RELOC1 JP EXPR1 ;returns destination address XXXX in HL & H'L' reloc1: xor a ;zero A or l ;L must be zero: XXXX must be a page boundary P jp nz,error ;if not zero (meaning not a page boundary) P ; P ld de,byte0 ;initial address of block of ROM to move P ex de,hl ;DE=destination, HL=source P ld bc,mvlen ;BC=count: length of RELOCATING code to move P ld a,d ;high byte of destination address P sub h ;high byte of source address--->offset P exx ld e,h ; E=high byte of initial destination address S ld d,a ;D=offset S ld c,08 ; C=initial bit count S ld hl,bitmap ;HL=initial address byte of bit map S ld b,(hl) ;get byte from bit map S ifoff: srl b ;prepare next byte from bit map S ld a,d ;put the offset into the D register S exx jr c,addoff ;if this byte gets an offset P xor a ;no offset, so zero register A P addoff: add a,(hl) ;add source byte to offset if any P ld (de),a ;store byte in destination P exx dec c ;bit count <-- bit count-1 S jr nz,reloc2 ;if 8 bits from this byte are not done yet S set 3,c ;set bit count to eight again S inc hl ;(hl)=byte of bit map S ld b,(hl) ;get another byte from bit map S reloc2: exx inc hl ;source <-- source + 1 P inc de ;destination <-- destination + 1 P dec bc ;length of code count <-- len of code count-1 P ld a,b ; P or c ;if bc=0, done relocating code P exx jr nz,ifoff ; S exx ld c,low bitlen ;B already was 0: C=length of bitmap P ldir ;move the bit map (it need not be relocated) P exx ld l,low start ; S ld h,e ;high byte of initial destination address S jp (hl) ;jump to START: in new location ;************************************************************************ ;* S * ;* COMMAND S: SET. EXAMINE AND (OPTIONALLY) CHANGE MEMORY DATA * ;* S * ;************************************************************************ SET: LD IX,SET1 JP EXPR1 set1: CP CR ;was a carriage return typed following the addr jp z,start ;if a carriage return, exit this set command ld a,(hl) ld ix,conouti jp lbyte ;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, ',', ' ' ;RET EVAL1: jp c,start ;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 jp get1 ;returns new value for memory location in reg L 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? jp z,start ;exit from set routine if a CR typed su1: inc hl ld ix,sendh jp crlf SENDH: lä a,è ;senä thå È bytå tï thå console ld ix,lbyte1 jp lbyte ;CALL LBYTE lbyte1: ld a,l ;send the L byte to the console ld ix,conoutb jp lbyte ;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.) ;************************************************************************ ;* T * ;* COMMAND T: TEST. TEST MEMORY FROM XXXX TO XXXX * ;* T * ;************************************************************************ TEST: ld ix,test1 jp expr ;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 jp abort ;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 jp lbyte ;CALL LBYTE tbyte: ld a,l ;send the L byte to the console ld ix,conoutc jp lbyte ;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 JP CRLF ;SEND A CARRIAGE RETURN/LINE FEED T2: ld a,l ;compare a byte of end addr with current addr sub e jp 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 jp nz,t1 jp start ;finished testing, go get another command ;************************************************************************ ;* V * ;* COMMAND V: VERIFY. VERIFY MEMORY XXXX TO XXXX WITH XXXX * ;* V * ;************************************************************************ VERIFY: LD IX,VER1 JP EXPR3 ver1: exx ;from=BC, to=DE, with=HL vertst: ld ix,ver2 jp abort ;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 jp crlf ;print a carriage return-line feed vererr: ld a,b ;high byte of "from" byte address ld ix,ver3 ;CALL LBYTE jp lbyte ver3: ld a,c ;low byte of "from" byte address ld ix,conoutn ;CALL LBYTE JP LBYTE ;*ª 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 jp lbyte ;*ª SENÄ Á 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 jp lbyte ver4: ld a,l ;low byte of "with" byte address ld ix,conoutm ;CALL LBYTE JP LBYTE ;*ª 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 jp lbyte vadcmp: ld a,e ;low byte of finish address cp c ;low byte of current "from" address jp 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 jp z,start ;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 JP vertst ;go compare the next two bytes ;************************************************************************ ;* * ;* GET PARAMETERS 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. * ;* * ;************************************************************************ EXPR3: INC C ;on entry c was 2, this makes it 3 parameters JP EXPR EXPR1: LD C,001H ;on entry c was 2, this makes it one parameter 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 I,A ;TEMPORARILY SAVE THE CHARACTER<<< 'z' jp c,inst5 ;ret c sub ' ' ;convert to upper case nibok: SUB 030H ;'0' jp c,inst5 ;RET C ;RETURN IF LESS THAN '0' cp 017h ;WAS IT GREATER THAN 'F' (BEFORE CONVERSION) ? ccf jp c,inst5 ;RET C CP 00AH ;IS IT 0-9? CCF jp 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,I ;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 DEC C ;decrement count of parameters <<highest allowed track inc a ;increment track number by 1 jr step ;**************************************************************** ;* * ;* STEPO ROUTINE * ;* * ;* DECREMENT THE ASCII REPRESNTATION OF THE CURRENT TRACK * ;* NUMBER BY ONE (IF NOT ALREADY LOWEST TRACK). PRINT IT * ;* ON THE CRT AND INSERT IT IN THE DJDMA READ SECTOR * ;* COMMAND STRING. * ;* * ;**************************************************************** stepo: call pcn ;get pointer to present drive's PCN in hl ld a,(hl) ;present drive's present track number cp 0 ;lowest allowed track number jp z,comand ;don't step out if already at track 0 dec a ;decrement track number by 1 step: ld (curtrb),a ;save the track number call mkasci ;convert track number to ascii characters call trkstr ;print the new track number on crt jp mdseek ;go do the seek ;**************************************************************** ;* * ;* SUBROUTINE MKASCI * ;* * ;* 1. ON ENTRY, A CONTAINS THE HEX TRACK NUMBER THAT WAS * ;* STORED BY NEC 765 RESULT COMMAND. * ;* 2. CONVERT IT TO TWO ASCII DIGITS AND STORE THEM FOR * ;* USE BY THE TRKCRT ROUTINE (WHICH PRINTS THEM TO THE * ;* CRT. * ;* * ;**************************************************************** MKASCI: LD B,10 ;PREPARE TO SUBTRACT 10s FROM THE HEX NUMBER LD HL,DIGIT1 ;HL POINTS TO STORAGE IN MEMORY FOR TENS DIGIT CALL ASC INC HL ;HL POINTS TO STORAGE IN MEMORY FOR ONES DIGIT ADD A,B ;ADD THE 10 THAT WAS SUBTRACTED TO MAKE NEG. # LD B,1 ;PREPARE TO SUBTRACT 1s FROM THE HEX NUMBER ASC: LD (HL),'0' ;INITIALIZE THE STORED ASCII DIGIT TO '0' ASCSUB: SUB B ;FIND THE NUMBER OF 10s OR 1s IN THE HEX NUMBER RET C ;IF LESS THEN 10 OR 1 REMAINS IN THE HEX NUMBER INC (HL) ;BUMP THE STORED ASCII DIGIT HIGHER JR ASCSUB ;**************************************************************** ;* * ;* TRACK ROUTINE * ;* * ;* This routine is entered when a digit (within allowable * ;* range of track number) is typed when the program is * ;* waiting for a command. This routine stores that digit, * ;* gets another digit (range check is performed), displays * ;* the digits on the screen, and sends the head to the * ;* selected track. * ;* * ;**************************************************************** track: ld (digit1),a ;save the first digit (in ASCII) ld BC,292Ah ;B=COLUMN ADDRESS W/OFFSET,C=ROW ADDR W/OFFSET call curadd ;move cursor to track number position ld a,(digit1) call outchrA ;print the first digit (from register a) get2nd: call inchr ;get the 2nd digit of track number ld (digit2),a ;save the second character cp '0' jr c,get2nd ;if typed character < '0' CP '9'+1 JR nc,get2nd ;if typed character < or = '9' ld HL,digit1 ;HL points to memory storage of hi ASCII digit call calctr ;calculate current track in binary (HL points) ld a,(maxtrb) ;maximum allowed track number in binary sub (HL) ;HL points to current track in binary jr c,get2nd ;2nd digit was too large dec HL ;HL points to track number low digit in ASCII ld A,(HL) ;A=track number low digit in ASCII call outchra ;print the second digit (from register A) jp mdseek ;go do the seek ;************************************************************************ ;* * ;* MAXTRK ROUTINE * ;* * ;* Get two digits from the console. These two digits are the * ;* maximum track number beyond which the drive is not allowed * ;* to step. Save these digits in ASCII in MAXTRH and MAXTRL. * ;* * ;************************************************************************ maxtrk: ld BC,2B24h ;B=column address w/offset,C=row addr w/offset call curadd ;cursor address subroutine maxtr1: call inchr ;get 1st digit of the maximum track number ld HL,maxtrh ;point to memory storage for max track hi digit ld (HL),a ;save the first ASCII digit (DIGIT1) cp '0' ;is the character is a digit (ASCII 0-9)? jr c,maxtr1 ;error: character is less then '0' cp '9'+1 jr nc,maxtr1 ;error: character is greater then '9' ;*NOTE: registers HL must be preserved across these calls* call outchra ;print the first digit (from register a) maxtr2: call inchr ;get 2nd digit of the maximum track number INC HL ;save the second ASCII digit ld (HL),a ;save the ASCII digit cp '0' ;is the character is a digit (ASCII 0-9)? jr c,maxtr2 ;error: character is less then '0' cp '9'+1 jr nc,maxtr2 ;error: character is greater then '9' call outchra ;print the second digit (from register a) dec HL ;point to DIGIT1 (needed by CALCTR) call calctr ;calculate and store maximum track in binary jp comand cylstr: ld bc,2B24h ;B=column address w/offset,C=row addr w/offset call curadd ;cursor address subroutine ld a,(maxtrh) call outchra ;print the first digit (from register a) ld a,(maxtrl) call outchra ;print the second digit (from register a) ret ;************************************************************************ ;* * ;* FORMAT ROUTINE * ;* Formats a microdecision drive track over and over again for * ;* troubleshooting purposes. * ;* * ;************************************************************************ format: LD BC,3136h ;B=COLUMN ADDRESS W/OFFSET,C=ROW ADDR W/OFFSET CALL CURADD ;CURSOR ADDRESS SUBROUTINE CALL CMDNEW ;IS DATA PORT READY TO RECEIVE A NEW COMMAND LD A,4Dh ;NEC 765 format a track COMMAND CODE OUT (0FBh),A ;SEND format a track cmd TO NEC 765 DATA PORT CALL CMDRDY ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE EXX ;ACCESS SECONDARY REGISTERS LD A,E ;GET THE E REGISTER INFORMATION EXX ;RETURN TO PRIMARY REGISTERS and 00000100B ;MASK ALL BUT SIDE SELECT BIT LD E,A ;SAVE SIDE SELECT BIT IN REGISTER E LD A,(MOTDRV) ;BIT 0=US0, BIT 1=US1 FOR DRIVE SELECTION OR E ;MERGE HEAD SELECT BIT WITH DRIVE SELECT BITS OUT (0FBh),A ;BYTE 2 OF format a track COMMAND CALL CMDRDY ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE LD A,03 ;N: bytes per sector (03=1024 selected) OUT (0FBh),A ;SEND SECOND COMMAND BYTE TO NEC 765 DATA PORT CALL CMDRDY ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE LD A,04 ;SC: sectors per track OUT (0FBh),A ;SEND SECOND COMMAND BYTE TO NEC 765 DATA PORT CALL CMDRDY ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE LD A,0f0h ;GPL: gap three OUT (0FBh),A ;SEND SECOND COMMAND BYTE TO NEC 765 DATA PORT CALL CMDRDY ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE LD A,99h ;D: filler byte OUT (0FBh),A ;SEND SECOND COMMAND BYTE TO NEC 765 DATA PORT ld a,0 ld (sectr),a ;initialize sector number call chrn ;supply C, H, R, N for each sector on the track call chrn ; there are five sectors call chrn call chrn call chrn ;************************************************************************ ;* * ;* SUBROUTINE INDATA * ;* * ;************************************************************************ indata: LD HL,DATBUF ;7 memory bytes for temporary result storage ld b,7 ;there are 7 result bytes to be read indat9 calì rdrdù ;is NEC 765 ready to send another result byte IN A,(0FBh) ;read a result byte ld (hl),a ;temporarily store this result byte inc hl ;point to next temoprary storage location dec b ;one less result byte remains to be read jr nz,indat9 ;if more result bytes remain to be read LD BC,5523h ;B=column address w/offset,C=row addr w/offset ld a,(datbuf+5) ;datbuf+3=record (sector) number byte of result add c ;add row number to cylinder number ld c,a ;prepare bc register pair for call to curadd call curadd ;move cursor to data display position ld hl,datbuf-1 ;7 result bytes are stored in datbuf ld b,7 ;7= count (number of bytes in result) INDAT: INC HL push bc PUSH HL LD A,(HL) ;GET A RESULT BYTE FRM TEMPORARY MEMORY STORAGE ld ix,indat1 jp lbyte ;convert the a register to ascii and print indat1: ld a,' ' ;ascii space call outchra ;print a space POP HL pop bc ;get count dec b ;decrement count jr nz,indat ;if all 7 bytes not yet printed jp comand ;done if all 7 bytes have been printed ;************************************************************************ ;* * ;* SUBROUTINE CHRN * ;* Gets the cylinder number, head, sector number, and bytes per * ;* sector that is needed as part of some of the NEC 765 commands, * ;* including the format a track command. * ;* * ;************************************************************************ chrn: CALL intsts ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE LD A,05h ;C: cylinder number OUT (0FBh),A ;SEND BYTE TO NEC 765 DATA PORT CALL intsts ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE LD A,00h ;H: head number OUT (0FBh),A ;SEND BYTE TO NEC 765 DATA PORT CALL intsts ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE ld a,(sectr) ;old sector number inc a ;add 1 to make new sector number ld (sectr),a OUT (0FBh),A ;SEND BYTE TO NEC 765 DATA PORT CALL intsts ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE Ld A,03 ;03 = 1024 bytes per sector code number OUT (0FBh),A ;SEND BYTE TO NEC 765 DATA PORT ret ;**************************************************************** ;* * ;* INTSTS SUBROUTINE * ;* * ;* Perform the NEC 765 sense interrupt status command. * ;* Loop until an interrupt is generated. * ;* * ;**************************************************************** intsts: ld a,08h ;NEC 765 sense interrupt status command code ;THIS ROUTINE NEEDS MORE WORK! out ( ;**************************************************************** ;* * ;* CURADD SUBROUTINE * ;* * ;* DIRECT CURSOR ADDRESSING SUBROUTINE: upon entry * ;* to CURADD reg. B should contain COLUMN address with * ;* offset. Reg. C should contain ROW address with offset. * ;* * ;**************************************************************** CURADD: LD A,B LD (COL),A ;STORE COLUMN (ADDR+OFFSET) LD A,C LD (ROW),A ;STORE ROW (ADDRESS+OFFSET) LD A,1Bh ;esc character-TERMINAL DEPENDENT CALL outchrA ;PRINT THE CHARACTER IN REGISTER A LD A,'=' ;= character-TERMINAL DEPENDENT CALL outchrA ;OUTPUT CHARACTER IN REGISTER A exx bit 3,e ;cursor addressing order bit exx JP NZ,COLOUT ROWOUT: LD A,(COL) ;OUTPUT COLUMN ADDRESS CALL outchrA ;print the character that is in reg A ret NZ ;IS COLUMN NEXT OR ARE WE DONE ? COLOUT: LD A,(ROW) ;OUTPUT ROW ADDRESS CALL outchrA ;print the character that is in reg A JR NZ,ROWOUT ;is row next or are we done ? RET ;************************************************************************ ;* * ;* SUBROUTINE CALCTR * ;* * ;* Enter with hl pointing to memory location of a high order * ;* ASCII digit of a 2 digit decimal number. The next memory * ;* location is the low order ASCII digit. This routine * ;* calculates a binary byte out of the two ASCII digits. This * ;* byte is stored in the memory location following the low order * ;* ASCII digit. Also returns: * ;* A=binary byte * ;* HL=points to memory storage of binary byte * ;* * ;************************************************************************ calctr: ld a,(hl) ;maximum high decimal track digits in ASCII sub '0' ;maximum high decimal track digit in binary add a,a ;A=2*high decimal track digit ld b,a ;B=2*high decimal track digit add a,a ;A=4*high decimal track digit add a,a ;A=8*high decimal track digit add a,b ;A=10*high decimal track digit inc hl ;HL points to low order ASCII digit add a,(hl) ;A now=number+30h in binary sub '0' ;A now=number in binary inc hl ;point to memory storage for binary number ld (hl),a ;store binary number ret ;**************************************************************** ;* * ;* INCHR SUBROUTINE * ;* * ;* FETCHES A CHARACTER FROM THE CONSOLE. * ;* RETURNS IT IN REGISTER A. AND SINCE THIS ROUTINE IS * ;* NEARLY ALWAYS RUNNING, IT KEEPS THE MOTOR RUNNING BY * ;* CALLING MOTRUN. * ;* * ;**************************************************************** ;*use microdecision sense drive status command to get status byte 3 (st3) and ;*to select the side INCHR: CALL CMDNEW ;IS DATA PORT READY TO RECEIVE A NEW COMMAND? LD A,04 ;SENSE DRIVE STATUS COMMAND OUT (0FBh),A ;ISSUE THE COMMAND CALL CMDRDY ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE EXX LD A,(MOTDRV) ;BIT 0=US0, BIT 1=US1 FOR DRIVE SELECTION OR E ;MERGE HEAD SELECT BITS WITH DRIVE SELECT BITS EXX OUT (0FBh),A ;BYTE 2 OF DRIVE STATUS COMMAND ;*NOTE: reading the result is delayed until later in the INCHR routin in order ;*to keep side one selected (if it is) as long as possible ;** GET A CHARACTER FROM THE CONSOLE ** CHARIN: Call motrun IN A,(STATUS) ;Read status register AND RDBIT JR Z,CHARIN ;No character ready, loop IN A,(RDREG) ;Read character and 07Fh ;strip parity PUSH AF ;preserve the character and the flag CALL RDRDY ;IS DATA PORT READY TO SEND A RESULT BYTE? IN A,(0FBh) ;READ STATUS 3 POP AF ;retrieve the character and the flag RET ;**************************************************************** ;* * ;* SUBROUTINE MOTRUN * ;* * ;* KEEP MOTOR RUNNING IF MOTOR ON (MOTOGL=0FFh) SELECTED * ;* * ;* THIS ROUTINE RUNS ONCE BEFORE EACH CHECK FOR A * ;* CHARACTER FROM THE TERMINAL. THIS MAKES THE MOTOR * ;* RUN. * ;* * ;**************************************************************** ;run the microdecision controlled motor MOTRUN: LD C,00000001b ;MOTOR ON BIT: PREPARED IF MOTDRV IS 0(DRIVE 0) ld a,(motdrv) ;get the drive number (0-3) ld b,00010000b ;upper four bits will drive drive select lines jr drvtst ;see if the drive is drive 0 or not mddrv1: ld c,00000010b ;MUST BE DRIVE 1, 2,OR 3 (MD WANTS ONLY 1 OR 2) dec a ;try the next drive rlc b ;select next drive higher drive bit drvtst: or a ;see if correct drive has been reached jr nz,mddrv1 ;if haven't reached correct drive ld a,(motogl) ;see if motor has been selected to be on or a ; 0=off 1=on jp z,drivon ;if motor is not supposed to be on LD A,C ;A<--MOTOR LINE;BIT1=DRIVE 0 MOTOR;2=DRIVE1,2,3 drivon: or b ;add in the drive select line to the motor line out (0F7h),a ;turn on selected microdecision drive (RV2 BDS) OUT (0F8h),A ;FOR REV. 1 MICRODECISION BOARDS ret ;**************************************************************** ;* * ;* SUBROUTINE TRKSTR * ;* * ;* 1. MOVE CURSOR TO TRACK NUMBER DISPLAY ON CRT * ;* 2. PRINT THE TWO ASCII TRACK DIGITS ON CRT * ;* * ;**************************************************************** trkstr: LD BC,292Ah ;B=COLUMN ADDRESS W/OFFSET,C=ROW ADDR W/OFFSET CALL CURADD ;MOVE CURSOR TO TRACK NUMBER POSITION LD A,(DIGIT1) ;LOAD THE FIRST DIGIT CALL outchrA ;print the character that is in register A LD A,(DIGIT2) ;LOAD THE SECOND DIGIT CALL outchrA ;print the character that is in register A RET ;************************************************************************ ;* * ;* SUBROUTINE MDSEEK * ;* * ;* STEPS THE MICRODECISION CONTROLLED DRIVE HEAD TO THE TRACK * ;* SPECIFIED IN BYTE MDTRK. THE SEEK COMMAND IS A THREE BYTE * ;* COMMAND. * ;* * ;************************************************************************ MDSEEK: CALL CMDNEW ;IS DATA PORT READY TO RECEIVE A NEW COMMAND? LD A,0Fh ;NEC 765 SEEK COMMAND CODE OUT (0FBh),A ;SEND SEEK COMMAND TO NEC 765 DATA PORT CALL CMDRDY ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE EXX LD A,(MOTDRV) ;BIT 0=US0, BIT 1=US1 FOR DRIVE SELECTION OR E ;MERGE HEAD SELECT BITS WITH DRIVE SELECT BITS EXX OUT (0FBh),A ;BYTE 2 OF SEEK COMMAND CALL CMDRDY ;IS DATA PORT READY TO RECEIVE A COMMAND BYTE LD A,(curtrb) ;BYTE 3 SELECTS THE CYLINDER NUMBER (0-39) OUT (0FBh),A CALL RESULT ;SENSE INTERRUPT STATUS (TO TERMINATE COMMAND) jp comand ;************************************************************************ ;* * ;* SUBROUTINE RESULT * ;* THIS ROUTINE PERFORMS THE SENSE INTERRUPT STATUS COMMAND OF * ;* THE NEC 765 DISK CONTROLLER. IT IS NECESSARY TO PERFORM THIS * ;* COMMAND FOLLOWING SEEK AND RECALIBRATE COMMANDS IN ORDER TO * ;* PROPERLY TERMINATE THEM. * ;* * ;************************************************************************ result: CALL CMDNEW ;IS DATA PORT READY TO RECEIVE A NEW COMMAND? LD A,08 ;SENSE INTERRUPT STATUS COMMAND(CLEARS FDD0-3) OUT (0FBh),A ;ISSUE THE COMMAND CALL RDRDY ;IS DATA PORT READY TO SEND A RESULT BYTE? IN A,(0FBh) ;READ STATUS 0 and 11100000b ;save interrupt code (7,6)and seek end bits (5) cp 10000000b ;bit 7=1, 6=0 --> invalid command-never started jp z,result ;if invalid command or not done, start over CALL RDRDY ;IS DATA PORT READY TO SEND A RESULT BYTE? CALL PCN ;RETURNS POINTER IN HL TO PRESENT DRIVES PCN IN A,(0FBh) ;READ PRESENT CYLINDER NUMBER LD (HL),A ;STORE PCN IN APPROPRIATE BYTE FOR PRESENT DRIV RET ;************************************************************************ ;* * ;* SUBROUTINE PCN * ;* * ;* FOR THE MICRODECISION, RETURNS A POINTER IN HL TO THE PRESENT * ;* DRIVES PRESENT CYLINDER NUMBER. THE TABLE IS FILLED BY STORING * ;* THE RESULTS OF THE NEC 765 SENSE INTERRUPT STATUS COMMAND * ;* (RESULT SUBROUTINE). * ;* * ;************************************************************************ PCN: LD HL,PCNTBL-1 ;TABLE OF EACH OF 4 DRIVES PRESENT CYLINDER #s LD A,(MOTDRV) ;PRESENT DRIVES NUMBER INC A NEXTDR: INC HL ;DEVELOP A POINTER (IN HL) TO BYTE FOR PRESENT DEC A ; CYLINDER NUMBER FOR PRESENT DRIVE JP NZ,NEXTDR RET ;************************************************************************ ;* * ;* SUBROUTINE CMDNEW * ;* * ;* READS MICRODECISION PORT 0FAh TO GET THE STATUS OF THE NEC 765 * ;* CONTROLLER CHIP. THIS IS A CHECK TO SEE IF THE CHIP IS READY * ;* FOR THE NEXT BYTE OF A COMMAND WHICH IS ALREADY IN PROGRESS. * ;* * ;************************************************************************ CMDNEW: CALL MDDLY ;DELAY 12.5 uS IN A,(0FAh) ;READ NEC 765 STATUS PORT AND 11110000b ;MASK OUT SOME BITS CP 10000000b ;IS DATA PORT READY FOR A NEW COMMAND? JP NZ,CMDNEW ;LOOP UNTIL READY RET ;************************************************************************ ;* * ;* SUBROUTINE CMDRDY * ;* * ;* READS MICRODECISION PORT 0FAh TO GET THE STATUS OF THE NEC 765 * ;* CONTROLLER CHIP. THIS IS A CHECK TO SEE IF THE CHIP IS READY * ;* FOR THE NEXT BYTE OF A COMMAND WHICH IS ALREADY IN PROGRESS. * ;* * ;************************************************************************ CMDRDY: CALL MDDLY ;DELAY 12.5 uS IN A,(0FAh) ;READ NEC 765 STATUS PORT AND 11010000b ;MASK OUT SOME BITS CP 10010000b ;IS DATA PORT READY FOR MORE BYTES OF COMMAND? JP NZ,CMDRDY ;LOOP UNTIL READY RET ;************************************************************************ ;* * ;* SUBROUTINE RDRDY * ;* * ;* READS MICRODECISION PORT 0FAh TO GET THE STATUS OF THE NEC 765 * ;* CONTROLLER CHIP. THIS IS A CHECK TO SEE IF THE CHIP IS READY * ;* FOR THE NEXT BYTE OF THE RESULT. * ;* * ;************************************************************************ RDRDY: CALL MDDLY ;DELAY 12.5 uS IN A,(0FAh) ;READ NEC 765 STATUS PORT anä 11100000b ;savå DATÁ INPUT/OUTPUT,REQUESÔ FOÒ MASTEÒ BITS CP 11000000b ;IS DATA PORT READY TO SEND DATA? JP NZ,RDRDY ;LOOP UNTIL READY RET ;************************************************************************ ;* * ;* SUBROUTINE MDDLY * ;* * ;* DELAYS 12 uS. 12uS IS THE MINIMUM TIME REQUIRED BETWEEN BYTES * ;* BEING OUTPUT TO THE NEC 765. * ;* 12.5uS = (50 CYCLES)/(4 MHZ) * ;* * ;************************************************************************ MDDLY: EX (SP),IX ;23 CLOCK CYCLES TO EXECUTE THIS INSTRUCTION EX (SP),IX ;23 MORE CLOCK CYCLES RET ; 1 CLOCK CYCLE FOR RET (3 CYCLES FOR CALL) OUTSTR: LD a,(de) ;GET A CHARACTER OF THE STRING TO BE PRINTED CP '$' ;END OF STRING MARKER ret z push de call outchrA ;IF CHARACTER WAS not '$' THEN print it pop de inc de ;point to the next character in the string jr outstr ;go do the next character ;**************************************************************** ;* * ;* OUTPUT A CHARACTER TO THE CRT * ;* * ;* enter at OUTCHRA if character to send is in register A * ;* enter at OUTCHRE if character to send is in register E * ;* * ;* The flags register is preserved. * ;* The HL register pair is preserved. * ;**************************************************************** OUTCHRA:LD E,A ;ROUTINE ENTERED WITH CHARACTER TO PRINT IN A OUTCHRE:EX AF,AF' ;EXCHANGE TO PRESERVE FLAGS outchr: IN A,(STATUS) ;Get communications port status AND WRBIT ;test if ready to send a character JR Z,OUTCHR ;loop if not ready LD A,E ;get the CHARACTER TO PRINT from register E OUT (WRREG),A ;Output to transmitter buffer EX AF,AF' ;GET BACK FLAGS ROUTINE WAS ENTERED WITH ret SCREEN: DB CR DB 'uDECISION FLOPPY DRIVE EXERCISER' DB CR,LF DB 'Copyright (c) 1986, 1988 by Ronald E. Jacobs' DB CR,LF DB 'Revision 2.3' DB lf,lf,cr DB '^T max trk' DB CR,LF,LF DB 'D Density' DB CR,LF,LF DB 'S Side' DB CR,LF,LF DB 'NN track' DB CR,LF,LF DB 'M Motor' DB CR,LF,LF DB 'L drive' DB cr,LF,lf DB 'Command:' DB CR,LF,LF DB 'IO step In/Out' DB CR,LF DB 'H read Headers' db cr,lf DB 'R Recalibrate' DB CR,LF DB 'C Cursor addressing' db cr,lf db '^F Format a track' DB CR,LF DB '^C exit' DB '$' DENFM: DB 'FM $' DENMFM: DB 'MFM$' OFFMSG: DB 'OFF$' ONMSG: DB 'ON $' ;************************************************************************ ;* * ;* The following bytes are moved into ram when fstep is entered. * ;* They are here because fstep is operating from ROM but needs * ;* these bytes in RAM so that they can be changed dynamically. * ;* * ;************************************************************************ MV2RAM: .phase stack MOTOGL: DB 0 ;MOTOR TOGGLE FLAG ;*The order of the next 3 bytes must not be changed (for subroutine CALCTR)* DIGIT1: DB '?' ;MAKES ASCII TRACK NUMBER (TENS DIGIT) DIGIT2: DB '?' ;INITIALLY NOT KNOWN (='??') (ONES DIGIT) curtrb: db 99 ;current track number in binary MOTDRV: DB 0 ;DRIVE #(FILLED BY ROUTINE SELDRV) ;*The order of the next 3 bytes must not be changed (for subroutine CALCTR)* maxtrh: db '3' ;maximum high decimal track digit in ASCII maxtrl: db '9' ;maximum low decimal track digit in ASCII maxtrb: db 39 ;maximum track number in binary PCNTBL: ;0FFh=FSTEP has never accessed this drive PCN0: DB 0FFh ;DRIVE 0 PRESENT CYLINDER NUMBER PCN1: DB 0FFh ;DRIVE 1 PRESENT CYLINDER NUMBER PCN2: DB 0FFh ;DRIVE 2 PRESENT CYLINDER NUMBER PCN3: DB 0FFh ;DRIVE 3 PRESENT CYLINDER NUMBER sectr: db 1 ;sector number being formated ROW equ $ ;1 byte uninitialized storage COL equ ROW+1 ;1 byte uninitialized storage datbuf equ COL+1 ;7 bytes uninitialized storage .dephase ENDMV2: ;END OF ASSEMBLED CODE ENDIF ;END OF "IF ALIGNMENT" CONDITIONAL ;************************************************************************ ;* * ;* INITIALIZATION STRINGS FOR MD2 AND MD3 UARTS AND TIMER * ;* * ;* Everything after this point may be overwritten after * ;* the program begins operating. * ;* * ;************************************************************************ IF MD3 init_tab: db 0f3h ;CTC channel 0, mode 3 db 3eh db 0f0h ;CTC channel 0 set to max delay db 0ffh db 0f0h db 0ffh db 0f3h ;CTC channel 1, mode 3 db 7eh db 0f1h ;CTC channel 1 set to 9600 baud db 0dh db 0f1h db 0 db 0f3h ;CTC channel 2, mode 3 db 0beh db 0f2h ;CTC channel 2 set to 1200 baud db 68h db 0f2h db 0 db s1stat ;reset both UARTS db 80h db s2stat db 80h db s1stat db 80h db s2stat db 80h db s1stat db 40h db s2stat db 40h ;end of reset sequence db s1stat ;set both UARTS db 0ceh ;8 bits, no parity, x16, 2 stop db s2stat db 0ceh db s1stat ;Tx, Rx - on, DTR, RTS - on, ER reset db 37h db s2stat db 37h init_len equ ($-init_tab)/2 ENDIF ;ENDIF OF IF MD3 ;************************************************************************ ;* * ;* The following macro calls cause the variable following the % * ;* sign to be printed on the CRT when this program is assembled. * ;* * ;************************************************************************ ENDALL EQU $-1 ;ending address of all code and data .RADIX 16 ;change radix to base 16 for following macros if2 ;if2 assembles only on 2nd pass of 2 pass mode else ;give the following information only on first pass ONCRT 'Bit map length BITLEN',%bitlen ONCRT 'Bit map start address BITMAP',%bitmap ONCRT 'Alignment program start address ALIGN ',%align ONCRT 'Ending address of all code and data ENDALL',%endall endif .RADIX 10 ;return to default radix END