.xlist INCLUDE MON.180 .list ;***************************************************************************** ;* * ;* Program to control the head position, etc., of floppy drives to make * ;* head alignment possible. Also reads sector IDs and reads and writes * ;* sectors. * ;* * ;* Copyright 1989 Ronald E. Jacobs * ;* * ;* (latest work done July 19, 1989) * ;* * ;***************************************************************************** if alignment ;assemble this alignment code? ;************************************************************************ ;* Equates: * ;* Set diradfg for your particular terminal cursor addressing. * ;* * ;************************************************************************ diradfg equ 0 ;1 for ADM20; 0 for ADM31 cursor addressing stack equ 2040h ;stack space, RAM use here cr equ 0Dh ;carriage return lf equ 0Ah ;line feed bs equ 08h ;backspace ;**************************************************************** ;* * ;* ROUTINE DISPLA * ;* * ;* SCROLLS WHATEVER IS ON THE SCREEN OFF AND DISPLAYS * ;* THE COMMANDS AND OTHER INFORMATION ON THE SCREEN. * ;* * ;**************************************************************** align: ;MOVED TO MON>>>>>>>ld sp,stack ;starting address of stack<<<<<<<< ld hl,mv2ram ;source of bytes to move from ROM to RAM ld de,stack ;destination of bytes to put into RAM ld bc,endmv2-mv2ram;number of bytes to move ldir ;move bytes into RAM call resbuf ;set command buffer inactive inc hl ;point to first byte in command buffer ld (hl),0 ;0 indicates byte is last byte in buffer displa: ld a,25d ;number of times to send line feed call lnfeeds ;send line feed characters to screen ld de,screen ;start addr of string call outstr ;print the string ld a,14d ;prepare for lnfeeds: b=number of line feeds call lnfeeds ;send line feed characters to screen crtdata:ld hl,datdca ;point to max track memory storage for byt2crt ld d,ndatdca ;number of times to call byt2rt out2crt:call byt2crt ;display a byte in decimal on the CRT dec d ;decrement number of times to call byt2crt jr nz,out2crt ;if byt2crt not called required number of times call fgpstr ;print the format gap in hexicecimal call rgpstr ;print the read gap in hexidecimal call bufstr ;print the sector buffer pointer on CRT call sidstr ;print "0" or "1" after SIDE call denstr ;print "FM" or "MFM" after DENSITY call motstr ;print "OFF" or "ON" after MOTOR call drvstr ;print the drive number(0 to 4) after DRIVE call hltstr ;print the head load time after HEAD LOAD call hutstr ;print the head unload time after UNLOAD call srtstr ;print the step rate time after STEP RATE frommon: ;;;;;;; call resbuf ;enter from MON if align has: reset cmd buffer comand: ld bc,comand ;pushing comand addr onto stack allows using... push bc ; ...ret instruction to get back to comand: im0 ld bc,4B25h ;B=column address w/offset,C=row addr w/offset call curadd ;move cursor to 'ST3' ld a,(st3) ;get status register 3 from memory call hexcrt ;convert A register to ASCII and send to CRT ;;;;;;; ld ix,st3done ;;;;;;; jp lbyte ;convert the a register to ascii and print ;;;;;;;st3done: ld c,28h ;C=row address-1 with offset ld hl,(bufchr) ;# of chars in cmd buffer display up to cursor ld de,0008h ;column address+offset of Command: add hl,de ;HL=# of cols from start of cmd row to cursor ld de,80d ;number of columns in a row or a ;clear the carry flag subline:inc c ;increment the row address sbc hl,de ;find # of rows (# of 80s) in total of chars jr nc,subline ;loop until 1 too many rows is subtracted add hl,de ;add back the extra row that was subtracted ld a,20h ;20h=cursor addressing offset add a,l ;A=column address with offset ld b,a ;B=column address with/offset call curadd ;move cursor to 'Command:' call inchr ;get character from keyboard or buffer ;**************************************************************** ;* * ;* SEE IF CHARACTER JUST RECEIVED FROM CONSOLE WAS * ;* A DIGIT. IF SO, CHECK FOR A SECOND DIGIT. * ;* IF NOT CHECK TO SEE IF CHARACTER IS A VALID LETTER. * ;* * ;**************************************************************** call valdig ;returns no carry if character is a digit jr c,whatchr ;if typed character wasn't a digit (wasn't 0-9) ld e,a ;save character that was typed at console call calcten ;returns in reg D the binary value of 10*digit ld a,(maxtrk) ;get maximum track number high digit in ASCII cp d ;subtract tens binary from max track value ld a,e ;retreive character that was typed at console jp nc,track ;if typed digit < max. high track ;**************************************************************** ;* * ;* DETERMINE IF A VALID LETTER COMMAND WAS TYPED * ;* AND TAKE APPROPRIATE ACTION * ;* * ;**************************************************************** whatchr:cp 03h ;03h= ^C jp z,exit cp 06h ;06h= ^F jp z,format cp 12h ;12h= ^R jp z,rptbuf cp 14h ;14h= ^T (set maximum allowed cylinder number) JP Z,GETMAX ;get & display 2 digits on CRT, store binary ;;;;;;; ld hl,maxtrk ;point to max track memory storage structure ;;;;;;; jp z,get2dig ;get & display 2 digits on CRT, store binary CP 17h ;17h= ^W JP Z,wDATA;write ;W write a sector of data cp ';' jr z,filbuf cp '/' jp z,setbuf and 0DFh ;convert character to upper case ld hl,vectabl ;table of addresses of routines ld e,'A' ;first letter of alphabet ld d,26d ;try all of the letters of the alphabet findltr:cp e ;see if char from keyboard was current letter jr z,gotltr ;if char was current letter of the alphabet inc hl ;point to next entry in table inc hl inc e ;try the next letter of the alphabet dec d ;decrement count of letters left to try ret z ;if all letters tried & no match(RET to comand) jr findltr ;see if the next letter is a match gotltr: ld e,(hl) ;get byte of address to jump to inc hl ;point to other byte of address to jump to ld d,(hl) ;get the other byte of address to jump to ex de,hl ;put the address to jump to in HL jp (hl) vectabl:dw currev ;A dw bufaddr ;B specify the sector buffer address dw getcyl ;C get & display 2 digits on CRT, store binary dw Rdata ;D read a sector of data dw id ;E read a sector ID field dw density ;F dw setrgpl ;G set read gap length dw gethead ;H get & display 2 digits on CRT, store binary dw stepi ;I dw specify ;J set head load, head unload, or step rate time dw return ;K IS UNASSIGNED dw seldrv ;L dw motor ;M dw getsecz ;N get & display 2 digits on CRT, store binary dw stepo ;O dw pause ;P dw return ;Q IS UNASSIGNED dw getrecd ;R get & display 2 digits on CRT, store binary dw sidsel ;S dw setfgpl ;T set format gap length dw getsec1 ;U get & display 2 digits on CRT, store binary dw getsecp ;V get & display 2 digits on CRT, store binary dw return ;W IS UNASSIGNED dw return ;X IS UNASSIGNED dw recal ;Y dw sleep ;Z ;************************************************************************ ;* * ;* FILBUF ROUTINE * ;* * ;* Fill the buffer for batch execution of commands. * ;* Generally Registers are used this way: * ;* BC:count of columns to character at the cursor. * ;* D:Count of control characters from cursor to end of buffer. * ;* HL:pointer to next unused character location in buffer. * ;* * ;************************************************************************ filbuf: ld de,bscolon ;2 character string:backspace and colon call outstr ;send the string to the CRT to make "Command;" ;** Initialize counters and pointers. ** ld hl,cmdbuf ;point to start of command buffer ld b,h ld c,l ;BC also points to start of command buffer xor a ;zero A: 00=insert, 0FFh=overwrite ld (hl),a ;store a null as end of buffer marker jr savins ;save insert on (overwrite off) in ram loadbuf:call inchr ;get a character from the keyboard ;** Don't accept either '^R' or ';' in the buffer string.* cp 12h ;12h is ^R jr z,loadbuf ;if ^R, don't do anything with it, ignore it. cp ';' jr z,loadbuf ;if ';', don't do anything with it, ignore it. ;** See if the character just received was ^V (toggle insert/overwrite). ** cp 16h ;is it ^V? jr nz,isctlg ;if not ^V ld a,(insert) ;get insert/overwrite selection byte from ram cpl ;toggle the insert byte (00 OR 0FFh) ;** Enter here from RPTBUF routine (will enter with register A=0). ** savins: ld (insert),a ;save insert in ram jr loadbuf ;** See if the character just received was a ^G (to delete next buffer char) ** isctlg: cp 07h ;is it ^G? jr nz,isbs ;if not ^G ld a,(bc) ;get the character from under the cursor or a ;see if character under cursor is 00 (null) jr z,loadbuf ;if no character is under cursor to delete ld d,0 ;use D=count of control characters after cursor ;** See if cursor is at null (which marks end of buffer. ** push bc ;save pointer to character in buffer at cursor movbufl:inc bc ;point to next character after the cursor ld a,(bc) ;A=next character after the cursor dec bc ;point to location of the cursor ld (bc),a ;save character at next lower memory address or a ;see if character under cursor is 00 (null) jr z,mvbfl1 ;if no character is under cursor to delete inc bc ;point to location where cursor will be after.. call outctl ; ...sending the character to the crt jr movbufl mvbfl1: pop bc ;get pointer to char. where cursor should be dec hl ;char was deleted so point to previous buf loc call bscursr jr loadbuf ;** Backspace the cursor from the end of the buffer to where it belongs. ** bscursr:ld a,2 ;send 2 space characters to write over last... ld e,' ' ; ...char(s)(in case deleted char=cntl char) call chrfeed ;write spaces over the last characters on CRT push hl ;save pointer to next unused char loc in buffer ld e,d ;D=number of control characters after cursor ld d,0 ;DE=number of control characters after cursor add hl,de ;add the number of control characters to HL inc hl ;compensate for the two spaces output above inc hl bscur: call cpbchl ;compare BC with HL:returns Z if =; NZ if not = jr z,bsdone ;if BC equals HL(if cursor back where it began) ld a,bs ;prepare to send backspace character to the CRT call outchra ;backspace the cursor on the CRT dec hl ;HL is pointing to location where cursor is now jr bscur bsdone: pop hl ;get pointer to next unused char loc in buffer return: ret ;** Compare BC with HL: return Z if equal: return NZ if unequal. ** cpbchl: push hl ;save entry HL or a ;clear carry flag sbc hl,bc ;compare BC with HL pop hl ;retrieve entry HL ret ;return Z if BC=HL; return NZ if BC not = HL ;** See if the character just received was a back space. ** isbs: cp bs ;is it a back space? jr z,isbs1 cp 13h ;13h = ^S jr nz,isctld ;if not a ^S go see if it is ^D isbs1: push hl ;save pointer to next unused char loc in buffer ld hl,cmdbuf ;pointer to start of buffer call cpbchl ;compare BC with HL:returns Z if =; NZ if not = pop hl ;get pointer to next unused char loc in buffer jr z,loadbuf ;if there are no characters to back space to dec bc ;dec. pointer to buffer location at the cursor ld a,(bc) ;get character from under cursor cp 20h ;ASCII control characters are 0 through 1Fh ld a,bs ;put a back space in A call c,outchra ;if char was a control char, backspace twice call outchra ;backspace the cursor on the CRT jpldbuf:jr loadbuf ;go get another character ;** see if the character just received was a forward space. ** isctld: cp 04h ;04h = ^D jr nz,iscr ;if not ^D ld a,(bc) ;get the character at cursor from the buffer cp 0 ;see if already at end of buffer jr z,jpldbuf ;if there are no characters to forward space to call outctl inc bc ;inc. pointer to buffer location at the cursor jr jpldbuf ;go get another character ;*Send a character to the CRT. Preceed it with ^ if it's a control character.* outctl: cp 20h ;ASCII control characters are 0 through 1Fh ld e,'^' ;send a caret to the crt call c,outchre ;if keyboard character is a control character ld e,a jr nc,bufchra ;if keyboard character not a control character set 6,e ;convert the control char. to a printing char. inc d ;increment count of control characters bufchra:jp outchre ;send the char to the CRT: use outchre's return ;** See if the character just received was a carriage return. ** iscr: cp cr ;is it a carriage return? jr nz,ldbuf ;if not a carriage return ld hl,bufactv ;point to buffer active flag (0=inactve) inc (hl) ;set buffer active flag non 0: indicates active jr setbuf ;** End up here if character other then CR, ^V, back space or forward space.** ldbuf: push af ;save a copy of the character from keyboard call outctl ;output the char & keep count of control chard pop af ;retrieve the copy of character from keyboard ld d,0 ;initialize D=count of cntrl chars after cursor ex af,af' ld a,(bc) ;get character that is currently under cursor ex af,af' ;now af' has character that was under cursor ld (bc),a ;store new character into buffer at cursor ld a,(insert) or a ;0 means insert, non zero means overwrite jr nz,owrite ;if overwriting is on ;** If insert is on. (register A will be zero)** inc hl ;point to next storage location in buffer inc bc ;increment pointer to buffer char. at cursor ld (hl),a ;store a null indicating end of buffer ;**Shift all characters after the inserted character right one position.** movbuf: push bc ;save cursor location prior to shifting right movbufr:call cpbchl ;see if register pairs bc and hl are equal... jr z,mvbfdon ;if BC equals HL ld a,(bc) ;get character that is currently under cursor ex af,af' call outctl ;print the character previously under cursor ld (bc),a ;save the character previously under cursor inc bc ;increment pointer to buffer char. at cursor jr movbufr mvbfdon:pop bc ;get back cursor location from before shifting call bscursr ;move cursor from end of buf to proper position jp jpldbuf ;**If overwriting is on.** owrite: call cpbchl ;compare BC with HL:returns Z if =; NZ if not = inc bc ;increment pointer to buffer char. at cursor jR nz,rdisply ;if cursor is before end of buffer inc hl ;point to next storage location in buffer ld (hl),0 ;store zero as end of buffer marker rdisply:push bc rdsply: ld a,(bc) ;A=next character after the cursor or a ;see if character under cursor is 00 (null) jr z,mvbfdon ;if all characters have been redisplayed call outctl ;send the character(+ '^' if control)to the crt inc bc ;next character between cursor and buffer end jr rdsply ;************************************************************************ ;* * ;* SETBUF ROUTINE * ;* * ;* Enter this routine when '/' is read from the batch command * ;* buffer. (Also entered if '/' is read from the keyboard, but * ;* in that case it won't have any effect apparent to the user.) * ;* Also enter after repeating and editing buffer to the CRT. * ;* 1. Set the buffer count to its' original value. * ;* 2. Reset the buffer pointer to start of buffer. * ;* * ;************************************************************************ setbuf: ld hl,bufactv ;HL points to buffer active flag (BUFACTV) ld b,(hl) ;get status of buffer active flag on entry call resbuf ;set BUFACTV=0 and BUFCHR counter to 0 ld (hl),b ;restore entry status of buffer active flag inc hl ;hl points to start of command buffer ld (bufptr),hl ;store pointer in memory ret ;(jp comand) ;************************************************************************ ;* * ;* SUBROUTINE RESBUF * ;* * ;************************************************************************ resbuf: xor a ;zero register A ld hl,bufchr ;point to low byte of BUFCHR(# of chars + '^'s) ld (hl),a ;zero low byte of buffer displayed char counter inc hl ;point to high byte of BUFCHR ld (hl),a ;zero high byte of BUFCHR (BUFCHR is a word) inc hl ;HL points to buffer active flag (BUFACTV) ld (hl),a ;0 indicates buffer is inactive ret ;************************************************************************ ;* * ;* RPTBUF ROUTINE * ;* * ;* Retype the buffer command line. Make editing of it possible. * ;* Execute the command line after a Carriage Return is typed. * ;* Be sure to jump from this routine to SAVINS: with register A=0. * ;* * ;************************************************************************ rptbuf: ld de,bscolon ;2 character string:backspace and colon call outstr ;send the string to the CRT ld hl,cmdbuf ;start of command buffer bufcrt: ld b,h ;BC <-- HL ld c,l ld a,(hl) ;get a character from the buffer or a ;end of string in buffer is marked with 00 jp z,savins ;if all characters have been reprinted on CRT call outctl ;send the character(+ '^' if control)to the crt inc hl ;point to next character in buffer jr bufcrt ;************************************************************************ ;* * ;* CURREV ROUTINE * ;* * ;* Toggles a BIT 0, which the cursor addressing * ;* routine uses to reverse or not reverse the order * ;* of transmission of row and column to the terminal. * ;* * ;************************************************************************ currev: ld hl,curflg inc (hl) ;toggle bit 0 pop bc ;take 2 bytes off stack since no ret(to comand) jp displa ;repaint the screen then fall thru to comand ;**************************************************************** ;* * ;* SUBROUTINE INNYBLS * ;* * ;* Input up to four hex digits from the keyboard. Enter * ;* with number of nybbles to get in B (1-4). Returns * ;* result in HL. Example: * ;* enter with b=4 * ;* enter BA98 at keyboard. * ;* returns BA98 in HL. (BA IN H, 98 IN L) * ;* * ;**************************************************************** innybls:ld hl,00 ;initialize HL. HL will hold up to four nybbles innyb: call inchr ;get a character from the keyboard ld e,a ;save a copy of the character sub '0' ;make binary from ASCII jr c,innyb ;if character was less then '0' cp 9+1 ;binary 10d jr c,is0to9 ;if character is '0'-'9' ld a,e ;get a fresh copy of the character and 11011111b ;convert character to upper case cp 'A' jr c,innyb ;if less then 'A' cp 'G' jr nc,innyb ;if greater then 'F' call outchra ;display the A-F on the CRT sub 'A'-10d ;convert to 0Ah through 0Fh jr savnyb ;save the nybble is0to9: call outchre ;display the 0-9 on the CRT savnyb: add hl,hl ;on first pass HL is zero 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 djnz innyb ;dec count of nybbles, loop if haven't gotten 4 ret ;**************************************************************** ;* * ;* BUFADDR ROUTINE * ;* * ;* Input four hex digits from the keyboard which specify * ;* a new sector buffer starting address. * ;* * ;**************************************************************** bufaddr:ld bc,2A28h ;b=column address w/offset,c=row addr w/offset call curadd ;move cursor to 'buffer' ld b,4 ;count of nybbles (characters) to get from KBD call innybls ;returns binary number in HL ld (secbuf),hl ;save the new address in RAM ret ;(jp comand) bufstr: ld bc,2A28h ;b=column address w/offset,c=row addr w/offset call curadd ;move the cursor to 'buffer' ld hl,secbuf+1 ;point to high byte of buffer address call bufstr1 ;convert high byte to ASCII and send to CRT dec hl ;point to low byte of buffer address bufstr1:ld a,(hl) ;get the byte to send to the CRT jr jphxcrt ;CRT<--byte converted to ASCII(use HEXCRT'S RET ;**************************************************************** ;* * ;* SETFGPL ROUTINE * ;* * ;* Input two hex digits from the keyboard which specify * ;* a new format gap length. * ;* * ;**************************************************************** setfgpl:ld bc,4B26h ;b=column address w/offset,c=row addr w/offset call curadd ;move cursor to FORMAT GAP ld b,2 ;count of nybbles (characters) to get from KBD call innybls ;returns binary number in hl ld a,l ;put the two nybbles into register A ld (fgpl),A ;save the new address in RAM ret ;(jp comand) fgpstr: ld bc,4B26h ;b=column address w/offset,c=row addr w/offset call curadd ;move the cursor to FORMAT GAP ld a,(fgpl) ;get the byte to send to the CRT jphxcrt:jp hexcrt ;convert the byte to ASCII and send to CRT ;**************************************************************** ;* * ;* SETRGPL ROUTINE * ;* * ;* Input two hex digits from the keyboard which specify * ;* a new read gap length. * ;* * ;**************************************************************** setrgpl:ld bc,4B27h ;b=column address w/offset,c=row addr w/offset call curadd ;move cursor to READ GAP ld b,2 ;count of nybbles (characters) to get from KBD call innybls ;returns binary number in HL ld a,l ;put the two nybbles into register A ld (rgpl),a ;save the new address in RAM ret ;(jp comand) rgpstr: ld bc,4B27h ;b=column address w/offset,c=row addr w/offset call curadd ;move the cursor to READ GAP ld a,(rgpl) ;get the byte to send to the CRT jr jphxcrt ;convert byte to ASCII, send to CRT(ret to cmd) ;**************************************************************** ;* * ;* EXIT ROUTINE * ;* * ;* 1. Move cursor to screen left edge below 'Command>'. * ;* 2. RETURN TO MONITOR if there or warm boot if not. * ;* * ;**************************************************************** exit: ld bc,2029h ;b=column address w/offset,c=row addr w/offset call curadd ;position the cursor for exit if monitor pop bc ;take COMAND address off of stack since no ret jp (iy) ;jump to monitor program (iy loaded by monstep) else jp 0 ;warmboot endif ;**************************************************************** ;* * ;* MOTOR ROUTINE * ;* * ;**************************************************************** motor: ld a,(motogl) ;motor toggle flag cpl ;toggle motor flag between 00 and FFh ld (motogl),a ;store the toggled flag JP MOTSTR ;(RET COMAND) ;;;;;;; call motstr ;;;;;;; ret ;(jp comand) motstr: ld bc,2A24h ;B=column address w/offset,C=row addr w/offset call curadd ;cursor address subroutine ld a,(motogl) ;motor toggle flag or a ;0=motor off FF=motor on ld de,offmsg ;start of off message string jr z,chgmot ;IF MOTOGL BIT 0 WAS 0, SHOW MOTOR OFF ld de,onmsg ;start of on message string chgmot: jp outstr ;print the string (use outstr's ret) ;**************************************************************** ;* * ;* RECAL ROUTINE * ;* * ;* RECALIBRATE THE MICRODECISION CONTROLLED DRIVE BY: * ;* 1. GIVING THE NEC 765 RECALIBRATE COMMAND (WHICH * ;* STEPS OUT A MAXIMUM OF 77 TRACKS UNTIL THE * ;* TRACK 0 LINE GOES TRUE. * ;* 2. TERMINATE THE COMMAND BY GIVING THE NEC 765 * ;* SENSE INTERRUPT STATUS COMMAND. * ;* * ;**************************************************************** recal: ld a,07h ;NEC 765 recalibrate command code call cmdnew ;is data port ready to receive new command? ;;;;;;; out (FDCDATA),a ;send recalibrate command to NEC 765 data port call cmdrdy ;is data port ready to receive a command byte? ld a,(motdrv) ;bits 0 (=US0) and 1 (=US1) select the drive out (fdcdata),a ;send second command byte to NEC 765 data port ei halt ;wait for an interrupt from FDC call sensint ;perform NEC 765 sense interrupt status command ld hl,cylndr ;point to cyl. no. for format/rd/write commands ld a,(curtrk) ;get the new track number ld (hl),a ;save new cylinder number into RAM call byt2crt ;display new cylinder no. as ASCII pair on CRT ld hl,curtrk ;regs. hl point to current track structure jp byt2crt ;CRT<-- track number as ASCII pair (ret to cmd) ;************************************************************************ ;* * ;* SPECIFY ROUTINE * ;* Allows specification of head load time, step rate, and head * ;* unload time for a drive. * ;* * ;************************************************************************ specify:ld bc,4223h ;B=column address w/offset,C=row addr w/offset call curadd ;move cursor to left of "head unload" position call inchr ;get a character from the keyboard and 11011111b ;convert the character to upper case cp 'L' jr z,hload ;set head load time cp 'U' ;head unload time jr z,uload ;set head unload time cp 'S' jr nz,specify ;if not an 'S' then try again with another char ;** Set the step rate time. ** srate: call srtstr ;display step rate time on CRT call getupdn ;returns with carry set if a -, cleared if a + inc (hl) ;increment srt so if it was a - we'll be ready jr c,srange ;if character entered at keyboard was a - dec (hl) ;character was a + so decrement the already... dec (hl) ; ...incremented srt srange: ld a,(hl) ;A=step rate time cp 0FFh ;allowed range is 0 to 0Fh jr nz,srt10 ;if not 0FFh ld (hl),0Fh ;if it was 0FFh, make it 0Fh jr SRATE;dispsrt ;will be jumping if it was 0FFh srt10: cp 10h ;10h is out of range jr nz,SRATE;dispsrt ;if not 10h ld (hl),0 ;if it was 10h, make it 0 jr srate ;get another '+' or '-' or carriage return ;** Enter with HL pointing to Step Rate Time. ** srtstr: ld hl,srt ;HL points to step rate time (srt) in RAM push hl ;save pointer to step rate time ld bc,4A24h ;B=column address w/offset,C=row addr w/offset ld e,(hl) ;d=step rate time ld d,0 ;de=step rate time ld h,d ld l,10h ;HL=10h or a ;clear the carry flag sbc hl,de ;subtract srt from 10h call clkmult ;double HL (SRT times 2) if 4 MHz clock pop hl ;retrieve pointer to step rate time ret ;** Set the head load time. ** hload: call hltstr ;display head load time on CRT call getupdn ;returns with carry set if a -, cleared if a + inc (hl) ;increment hut so if it was a + we'll be ready jr nc,lrange ;if character entered at keyboard was a + dec (hl) ;character was a - so decrement the already... dec (hl) ; ...incremented hut lrange: ld a,(hl) ;A=head load time cp 00 ;allowed range is 1 to 07Fh jr nz,hltFF ;if not 0 ld (hl),07Fh ;if it was 0, make it 07Fh jr HLOAD;times2 hltFF: cp 080h jr nz,HLOAD;times2 ;if not 080h ld (hl),1 ;if it was 080h, make it 1 jr hload ;get another '+' or '-' or carriage return hltstr: ld hl,hlt ;HL points to Head Load Time (hlt) in RAM push hl ;save pointer to head load time (HLT) ld bc,4A22h ;B=column address w/offset,C=row addr w/offset ld l,(hl) ;L=head load time ld h,0 ;HL=head load time add hl,hl ;head load time times 2 call clkmult ;double HL again (to times 4) if 4 MHz clock pop hl ;retrieve pointer to head load time (HLT) ret ;** Set the head unload time. ** uload: call hutstr ;display head unload time on screen call getupdn ;returns with carry set if a -, cleared if a + inc (hl) ;increment hut so if it was a + we'll be ready jr nc,urange ;if character entered at keyboard was a + dec (hl) ;character was a - so decrement the already... dec (hl) ; ...incremented hut urange: ld a,(hl) ;A=head unload time cp 0 ;allowed range is 1 to 0Fh jr nz,hut0F ;if not 0 ld (hl),0Fh ;if it was 0, make it 0Fh jr uload hut0F: cp 10h jr nz,uload ;if not 10h ld (hl),1 ;if it was 10h, make it 1 jr uload ;get another '+' or '-' or carriage return hutstr: ld hl,hut ;HL points to head unload time (hut) in RAM push hl ;save pointer to head unload time (HUT) ld bc,4A23h ;B=column address w/offset,C=row addr w/offset ld l,(hl) ;L=head unload time ld h,0 ;HL=head unload time add hl,hl ;head unload time times 2 add hl,hl ;times 4 (head unload time is in add hl,hl ;times 8 16 (or 32) mS increments) add hl,hl ;times 16 call clkmult ;double HL again (to times 32) if 4 MHz clock pop hl ;retrieve pointer to head unload time (HUT) ret ;************************************************************************ ;* * ;* SUBROUTINE CLKMULT * ;* Enter with HL pair containing a binary numeric value. HL * ;* will be returned unchanged if NEC765 clock rate is 8 MHz. HL * ;* will be returned doubled if clock rate is 4 Mhz. * ;* * ;************************************************************************ clkmult:call curadd ;move cursor to left of SRT,HUT, or HLT value ld a,(clock) ;clock=1 for 8 MHz, 2 for 4 MHz clkmlt1:dec a ;no passes for 8 MHz, 1 pass for 4 MHz jp z,wordcrt ;print word on CRT, use wordcrt's return add hl,hl ;do this 0 times for 8 MHz, once for 4 MHz jr clkmlt1 ;************************************************************************ ;* * ;* SUBROUTINE GETUPDN * ;* Get a '+', '-', or carriage return from the keyboard. If any * ;* other character is entered loop until one of these three is * ;* received. If * ;* '+' return with carry cleared. * ;* '-' return with carry set. * ;* CR send the NEC765 specify command then jp to Comand. * ;* * ;************************************************************************ getupdn:call inchr ;get a character from the keyboard cp '-' ;see if a '-' was entered at keyboard scf ;if a '-' then return with carry set ret z ;if it was a '-' cp '+' ret z ;if a '+' then returns with carry cleared cp cr ;if carriage return... jr nz,getupdn ;loop if input char not a +, -, or carriage ret ;** Issue the NEC765 specify command. ** pop hl ;take ret addr of call to getupdn off of stack drvspec:ld a,03h ;NEC 765 specify command code call cmdnew ;is data port ready to receive new command? ;;;;;;; out (fdcdata),a ;send specify command to NEC 765 data port call cmdrdy ;is data port ready to receive a command byte? ld hl,srt ;HL points to step rate time ld a,(hl) ;A=step rate time rlca ;shift step rate time into high nybble rlca rlca rlca dec hl ;HL points to head unload time or (hl) ;high A nybble=step rate;low nybble=head unload out (fdcdata),a ;send second command byte to NEC 765 data port call cmdrdy ;is data port ready to receive a command byte? dec hl ;HL points to head load time ld a,(hl) ;A=head load time rlca ;shift HLT left 1 bit dec hl ;HL points to nondma byte or (hl) ;set bit 0 to 0 if DMA mode;1 if NON-DMA mode out (fdcdata),a ;send third command byte to NEC 765 data port ret ;(jp comand) ;**************************************************************** ;* * ;* SELDRV ROUTINE * ;* * ;**************************************************************** seldrv: ld bc,2C25h ;B=column address w/offset,C=row addr w/offset call curadd ;move cursor to drive number position ;* Save data on the current drive.* call drvtbl ;RETs HL points to current drive table ex de,hl ; HL points to data w/DCA addrs savdat: ldi ;copy a byte of data into current drive's table inc hl ;skip past the column address byte inc hl ;skip past the row address byte ld a,b cp c ;see if BC (count of bytes to move) is 0 yet jr nz,savdat ;if bytes of data remain to be moved ld c,ndrvdat ;number of data items not followed by DCA pairs ldir ;copy remaining data into current drive's table drvchr: call inchr ;get actual drive number from terminal cp '4' ;must be less THAN '4' jr nc,drvchr ;if '4' or greater cp '0' ;must be '0' or greater jr c,drvchr ;if less than '0' selpnt: and 00001111b ;convert ASCII digit to binary ld (motdrv),a ;store drive number ;** Get data on the new drive. ** call drvtbl ;get pointer to current drive's table in hl getdat: ldi ;copy a byte of data into current drive's table inc de ;skip past the column address byte inc de ;skip past the row address byte ld a,b cp c ;see if BC (count of bytes to move) is 0 yet jr nz,getdat ;if bytes of data remain to be moved ld c,ndrvdat ;number of data items not followed by DCA pairs ldir ;copy remaining data into current drive's table pop hl ;remove 2 bytes pushed at comand: jp crtdata ;rewrite all data on CRT, fall thru to comand drvstr: ld bc,2C25h ;B=column address w/offset,C=row addr w/offset call curadd ;move cursor to drive letter position ld a,(motdrv) ;get the binary drive number or 30h ;convert binary drive number to ASCII jp outchra ;CRT <-- drive number (use outchra's ret) ;**************************************************************** ;* * ;* SIDSEL ROUTINE * ;* * ;* TOGGLE THE CHOSEN SIDE, DISPLAY CHOICE ON CRT, * ;* STORE CHOICE FOR USE BY MOTRUN SUBROUTINE * ;* * ;**************************************************************** sidsel: ld hl,sidbit ;point to side byte in memory ld a,00000100b ;current side is coded into bit 2 xor (hl) ;toggle bit 2 ld (hl),a ;save new side bit into memory ld hl,head ;address of selected head byte in RAM ld (hl),0 ;store head in RAM (will be zero if sidbit=0) jr z,selend ;if head zero is correct inc (hl) ;increment the head number to 01 selend: call sidstr ;display the new side on the CRT jp byt2crt ;CRT<--new head (HL points to it)(ret to comand sidstr: ld bc,2C23h ;B=column address w/offset,c=row addr w/offset call curadd ;cursor address subroutine ld a,(sidbit) bit 2,a ;current side is coded into bit 2 ld a,'0' ;be ready to print a '0' jr z,chgsid ;if selected side is 0 inc a ;change '0' to '1' and be ready to print a '1' chgsid: jp outchra ;CRT<--ASCII char (RET COMAND) ;**************************************************************** ;* * ;* DENSITY ROUTINE * ;* * ;* TOGGLE THE DENSITY SELECTION, DISPLAY CHOICE ON CRT. * ;* * ;**************************************************************** density:ld hl,denbit ;point to density byte in memory ld a,01000000b ;current density is coded into bit 6 xor (hl) ;toggle bit 6 of denbit ld (hl),a ;save new DENBIT to memory,fall thru to denstr denstr: ld bc,3A28h ;B=column address w/offset,C=row addr w/offset call curadd ;cursor address subroutine ld a,(denbit) bit 6,A ;current density is coded into bit 6 ld de,denmfm ;point to string "MFM" to print jr nz,chgden ;if selected density was FM ld de,denfm ;was "MFM", point to string " FM" to print chgden: jp outstr ;CRT <-- string DE points to (use OUTSTR's ret) ;**************************************************************** ;* * ;* ID ROUTINE * ;* * ;* Get I.D. information for a sector. * ;* * ;**************************************************************** id: ld a,(denbit) ;density bit is 6: 0=FM, 1=MFM or 00001010b ;merge the READ ID command with the density bit call cmdnew ;is data port ready to receive a new command? ;;;;;;; out (fdcdata),a ;send READ ID command to NEC 765 data port call outsidr ;output byte 2(head and drive select)to FDCDATA jp get7buf ;CRT<-- 7 result bytes (ret comand) ;**************************************************************** ;* * ;* WDATA ROUTINE * ;* * ;* Write undeleted data to selected drive, track, head, * ;* and sector. * ;* * ;**************************************************************** WDATA: ld e,0 ;E=skip data flag (SK): must be 0 for write cmd ld d,00000101b ;NEC765 write data command code call rwcmd ;issue the write data command jr wrio ;** This code runs while write data command is executing but awaiting ** ;** first byte request. ** wloop1: and 020h ;see if still executing jr NZ,WRSTAT;z,jpdater ;jmp if done LD A,'8' JP ERRCODE WRSTAT: in a,(fdcstat) ;get status byte from NEC765/INTEL8272 cp 0B0h ;see if a byte is requested yet jr z,outbyte ;jmp if 1st byte is requested dec de ;decrement time out count ld a,e ;see if timed out or d jr NZ,WRIO;z,jpdater ;if timed out LD A,'9' JP ERRCODE wrio: in a,(fdcstat) ;get status byte from NEC765/INTEL8272 cp 0B0h ;see if a byte is requested yet jr nz,wloop1 ;loop if byte is not ready ;** This code runs while NEC765 is writting bytes into the disk sector. ** outbyte:dec bc ;dec count of bytes to get from buffer ld a,b ;see if count has reached zero or c jr nz,outbyt1 ;if more than one byte is left to get in a,(fdctc) ;input terminal count if one byte is left outbyt1:ld a,(hl) ;get a byte from the buffer inc hl ;increment memory storage pointer out (fdcdata),a ;write a byte to the sector jr z,DATAOK ;if all bytes have been written to the sector ei halt ;wait for NEC765 to request a byte from buffer in a,(fdcstat) ;get status byte from the NEC765 and 020h ;see if still executing jr nz,outbyte ;if still executing ;outget7: LD A,'A' jP ERRCODE ;if not still executing ;**************************************************************** ;* * ;* RDATA ROUTINE * ;* * ;* Read undeleted data from selected drive, track, head, * ;* and sector. * ;* * ;**************************************************************** rdata: ld ix,rdata ;return here to retry if there is a disk error ld a,0;(SK)<<<<<<<<;SK is skip deleted data address mark (bit 5) ld e,a ;E contains skip data flag (SK) ld d,00000110b ;NEC 765 read data command code call rwcmd ;issue the read data command jr rdio ;** This code runs while read data command is executing but awaiting 1st byte** rloop1: and 020h ;see if still executing jp z,EXSTOP ;if(probably)HEADER NOT FOUND in a,(fdcstat) ;get status byte from NEC765/INTEL8272 cp 0F0h ;see if a byte is ready jr z,inbyte ;jmp if 1st byte ready dec de ;decrement time out count ld a,e ;see if timed out or d jP z,NO1ST ;if timed out rdio: in a,(fdcstat) ;get status byte from NEC765/INTEL8272 cp 0F0h ;see if a byte is ready jr nz,rloop1 ;loop if byte is not ready ;** This code runs while NEC765 is getting bytes from the disk sector. ** inbyte: dec bc ;dec count of bytes to get from sector ld a,b ;see if count has reached zero or c jr nz,in1byte ;if more than one byte is left to get in a,(fdctc) ;input terminal count if one byte is left in1byte:in a,(fdcdata) ;get a byte from the sector ld (hl),a ;put the byte from the sector into memory inc hl ;increment memory storage pointer jr z,DATAOK;get7buf ;if all bytes have been read from the sector ei halt ;wait for a byte from the sector in a,(fdcstat) ;get status byte from the NEC765 and 020h ;see if still executing jr nz,inbyte ;if still executing LD A,'7' Jp diskERR ;CRT <-- ERROR CODE+ABORT-RETRY-IGNORE MESSAGE ;************************************************************************ ;* SUBROUTINE GET7 * ;************************************************************************ DATAOK: ld (secbuf),hl ;save new sector buffer pointer get7buf:call bufstr ;CRT <-- end of buffer address get7: call indata ;read the 7 result bytes ST0,ST1,ST2,C,H,R,N jp headout ;CRT <-- 7 result bytes (RET to comand) ;************************************************************************ ;* * ;* SUBROUTINE RWCMD * ;* Issues the NEC765 read data OR write data commands. Enter with * ;* register E containing SK (skip data) bit and D containing the * ;* command code (read data or write data command code). * ;* Returns sector size in bytes in BC and pointer to the data * ;* buffer in HL. * ;************************************************************************ rwcmd: call locmsg ;position cursor at beginning of message area ;;;;;;; LD A,(ST3) ;GET STATUS REGISTER 3(FROM LAST INCHR) ;;;;;;; AND 00100000h ;bit 5 set means drive not ready ;;;;;;; LD A,'6' ;;;;;;; JP NZ,ERRCODE ;IF DRIVE IS NOT READY GIVE ABORT-RETRY MESSAGE ld a,0;(MT)<<<<<<<<;MT is multi-track flag (bit 7) or e ;merge SK and MT bits ld e,a ;E contains SK and MT bits ld a,(denbit) ;density is coded into bit 6: 0=FM, 1=MFM or e ;merge SK and MT bits with density bit or d ;NEC 765 (read or write) data command code CALL CMDNEW ;is data port ready to receive a new command ;;;;;;; ld (hl),a ;put the command byte into the buffer ;;;;;;; inc hl ;point to next location in FDC command buffer ld hl,fdccmds ;point to buffer for series of bytes to output push hl ;save pointer to fdccmds bytes ld a,(sidbit) ;bit 2: 0=side 1, 1=side 1 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 ld (hl),a ;save the command byte in the buffer inc hl ;point to next location in FDC command buffer ld a,(cylndr) ;C: cylinder number ld (hl),a ;put the command byte into the buffer inc hl ;point to next location in FDC command buffer ld a,(head) ;H: get head byte ld (hl),a ;put the command byte into the buffer inc hl ;point to next location in FDC command buffer ld a,(record) ;R: sector number to begin reading at ld (hl),a ;put the command byte into the buffer inc hl ;point to next location in FDC command buffer ld a,(secsize) ;N: sector size code (03=1024 selected) ld (hl),a ;put the command byte into the buffer inc hl ;point to next location in FDC command buffer ld (hl),0FFh ;buffer<--end of track(EOT)last sector to read inc hl ;point to next location in FDC command buffer ld a,(rgpl) ;read data gap length ld (hl),a ;put the command byte into the buffer pop hl ;retrieve pointer to FDCCMDS bytes ld b,7; 8 ;count of 8 bytes to output to FDC data port ld c,fdcdata ;NEC 765 data port ;;;;;;; call cmdnew ;is data port ready to receive a new command outrw: outi ;send a byte from FDCCMDS buffer to data port call cmdrdy ;is data port ready to receive a command byte? jr nz,outrw ;** Calculate BPS before outputting last byte of read/write data command. ** ld hl,128d ;HL=smallest sector size (secsize=N=0 for FM) ld a,(denbit) ;density is coded into bit 6: 0=FM 1=MFM or a ;see if zero or 1 ld a,(secsize) ;get sector size code (N) jr z,calcbp1 ;if density is FM (single) calcbps:add hl,hl ;if density is double, double 128 to make 256 dec a ;MFM does not use size code 0;begins at 256 BPS calcbp1:or a ;test for size code N=0 jr z,bps2bc add hl,hl ;double the calculated bytes per sector dec a jr calcbp1 bps2bc: ld b,h ld c,l ;BC <-- sector size in bytes (from HL) ld hl,(secbuf) ;HL points to start of sector buffer in RAM ;** output the last byte of the read or write data command. ** calcdtl:ld a,(secsize) ;get sector size code (N) or a ;test to see if sector size code is 0 ld a,128d ;if secsize=0 out 128d to FDCDATA else out 0FFh jr z,outdtl ;if sector size code is zero ld a,0FFh ;DTL: data length use 0FFh if N not equal 0 outdtl: out (fdcdata),a ;send command byte to NEC 765 data port ;** Loop while waiting for 765/8272 to begin executing the read command. ** ld de,8000h ;load time out count waitex1:in a,(fdcstat) ;get status byte from NEC765/INTEL8272 bit 5,a ;see if execution has begun(non-DMA gone high?) JR Z,WAITEX1 ;IF EXECUTION HAS NOT BEGUN ret ;nz ;if execution has begun ;;;;;;; bit 7,a ;set if NEC765 is requesting service by Z80 ;;;;;;; jr z,waitex1 ;if Request for Master (RQM) low(not requested) ;**************************************************************** ;* * ;* DISK I/O ERROR HANDLING * ;* * ;**************************************************************** EXSTOP: LD A,'3' ;WAS EXECUTING COMMAND AND STOPPED CALL OUTCHRA JR diskerr NO1ST: LD A,'4' ;WAS EXECUTING AND DIDN'T GET FIRST DATA BYTE ERRCODE:CALL OUTCHRA PUSH HL PUSH BC CALL MOTRUN ;RETURNS A=MOTOR ON BIT & DRIVE SELECT BITS OR 08h ;bit 3 set tells FDC drive is not ready out (0F7h),a ;turn on selected microdecision drive (RV2 BDS) POP BC POP HL DISKERR:ld sp,stack-2 ;LEAVE JUST "COMAND" PUSHED ONTO STACK ADD HL,BC ;BUFFER POINTER=BYTES REMAINING+BUFFER POINTER PUSH HL call GET7 ;if from 765 to Z80 and master requested call locmsg ;put cursor at start of status report space LD DE,NRDYMSG ;point to "Dr not rdy ARI" message CALL OUTSTR POP HL GETARI: in a,(status) ;read status register and rdbit jr z,GETARI ;no character ready, loop in a,(rdreg) ;read character and 01011111b ;strip parity & convert to upper case CP 'A' ;A IS FOR ABORT JR NZ,ISR ;IF NOT AN "A" CALL WIPEMSG ;BLANK OUT ABORT-RETRY-IGNORE MESSAGE CALL BUFRES ;END COMMAND BUFFER EXECUTION,ERASE CMD LINE jp bufstr ;CRT<--end of sector buf address(RET to COMAND) ISR: CP 'R' ;R IS FOR RETRY JR NZ,ISI ;WASN'T "R", GO SEE IF "I" WAS TYPED CALL WIPEMSG call motrun ;restart the drive motor JP (IX) ;RETRY A SECTOR READ COMMAND ISI: CP 'I' ;I IS FOR IGNORE JR NZ,GETARI ;NOT "A", "R", OR "I" TYPED SO GET ANOTHER CHAR ld (secbuf),hl ;save new sector buffer pointer if "I"gnore call WIPEMSG jp bufstr ;CRT<--end of sector buf address(RET to COMAND) WIPEMSG:ld b,15d ;prepare for multstr: send string 15 times ld de,bsspbs ;address of string backspace, space, backspace JP multstr ;blank the Abort-Retry-Ignore msg(RET TO CALLER ;**************************************************************** ;* * ;* STEPI ROUTINE * ;* * ;* Increment the current track number by one (if not * ;* already highest track). Force the current cylinder * ;* number to be the same as the current track number. * ;* Convert them both to ASCII and print them on the CRT. * ;* * ;**************************************************************** ;*microdecision step in routine stepi: ld a,(maxtrk) ;A= highest allowed track number ld b,a ;B= highest allowed track number ld a,(curtrk) ;A= present drive's present track number cp b ;is current track < highest allowed track ret nc ;don't step in if now =or>highest allowed track inc a ;increment track number by 1 jr step ;**************************************************************** ;* * ;* STEPO ROUTINE * ;* * ;* Decrement the current track number by one (if not * ;* already highest track). Force the current cylinder * ;* number to be the same as the current track number. * ;* Convert them both to ASCII and print them on the CRT. * ;* * ;**************************************************************** stepo: ld a,(curtrk) ;present drive's present track number cp 0 ;lowest allowed track number ret z ;don't step out if already at track 0 dec a ;decrement track number by 1 step: ld hl,curtrk ;point to address in memory for current track ld (hl),a ;save the track number ld (cylndr),a ;also save in cylndr call byt2crt ;display new track number as ASCII pair on CRT ld hl,cylndr call byt2crt ;display new cylinder number on CRT jp seek ;go do the seek ;**************************************************************** ;* * ;* PAUSE ROUTINE * ;* Do nothing while waiting for operator to strike any * ;* key. Temporarily stores a 0 in BUFACTV to make sure * ;* character input routine (inchr) gets a character from * ;* the keyboard and not the buffer. Calls inchr because * ;* inchr keeps the motor running while awaiting a * ;* character. * ;* * ;**************************************************************** pause: ld hl,bufactv ;RAM addr:0FFh=buffer active,0= buffer inactive ld e,(hl) ;save state of buffer (active or inactive) ld (hl),0 ;temporarily indicate buffer is inactive call inchr ;go wait for a character & keep motor running cp 03h ;see if ^C was typed ld (hl),e ;restore state of buffer (active or inactive) ret nz ;(jr nz,comand) if character wasn't ^C ;**If ^C typed, terminate command string execution.** ld hl,nulbyt ;point to a byte which happens to be 00 ld (bufptr),hl ;bufptr points to null byte(means end of buffer ret ;(jp comand) ;**************************************************************** ;* * ;* SLEEP ROUTINE * ;* Delay for selected time. * ;* Enter four digits. (Gives delay in Milliseconds) * ;* See the table in the data/storage section at the end * ;* of this program for an idea of how multipliers and the * ;* ones, tens, hundreds, and thousands digits are stored * ;* in memory. * ;**************************************************************** sleep: call outchra ;CRT <-- 'Z' that caused entry ld hl,0000 ;initialize ld de,1000D call getzdig ld de,100D call getzdig ld de,10D call getzdig ld de,1D call getzdig ;returns HL=the number entered dly1ms: call motrun ;keep drive motor running during the delay ld d,0EAh ;count for generating 1 millisecond delay ld a,l ;HL=count of milliseconds to delay or h ;see if hl has decremented to 0 yet jr z,dlydone ;if there are no milliseconds left to delay dlaylp: dec d ;dec count for generating 1 millisecond delay jr nz,dlaylp ;if haven't delayed 1 millisecond yet dec hl ;decrement count of milliseconds remaining jr dly1ms dlydone:ld a,(bufactv) ;get command buffer active flag (non-0=active) or a ;see if command buffer is active ret nz ;if command buffer is active ld b,5 ;number of times to send string ld de,bsspbs ;address of string backspace, space, backspace jp multstr ;erase "Zxxxx", return to comand ;**************************************************************** ;* SUBROUTINE LOCMSG * ;* Position cursor at the beginning of message space. * ;**************************************************************** locmsg: ld bc,2027h ;B=column address w/offset,C=row addr w/offset jp curadd ;put cursor at start of error report space ;**************************************************************** ;* * ;* SUBROUTINE GETZDIG * ;* * ;* Enter with DE=1, 10d, 100d, or 1000d. Get a digit * ;* from the keyboard or the buffer and multiply it by * ;* contents of DE. Return result in HL. * ;* Example: * ;* Enter with DE=1000 decimal. * ;* Type a '9' at the keyboard. * ;* Return with HL=9000 decimal. * ;**************************************************************** getzdig:call inchr ;get a character from the keyboard or buffer call valdig ;see if character is 0 through 9 jr c,getzdig ;valdig returns with carry set if not 0 thru 9 call outchra ;send character to crt sub '0' ;make the ASCII digit into a binary number addup: ret z ;this is the exit point from subroutine getzdig add hl,de dec a jr addup ;**************************************************************** ;* * ;* SUBROUTINE BYT2CRT * ;* * ;* 1. On entry, HL points to the start of a 3 byte * ;* structure in memory: * ;* DB XXh ;binary number(e.g. track) * ;* DW CCRRh ;screen address column and row * ;* 2. The cursor is moved to the appropriate address on * ;* the CRT (as defined by the word CCRRh) and the * ;* ASCII decimal representation of the byte XXh is * ;* printed on the CRT. * ;* 3. On exit, HL points to the entry HL+3 so it is ready * ;* if the next 3 byte structure is to be displayed on * ;* the screen. * ;* 4. Enter at BYTDISP to convert a binary number in HL to * ;* to three ASCII digits (000-999) and send them to the * ;* CRT without moving the cursor. * ;* 5. BC is preserved if entered at BYTDISP. * ;* * ;**************************************************************** byt2crt:ld a,(hl) ;get the byte to be converted from memory inc hl ;point to row addr w/offset ld c,(hl) ;C=row address w/offset inc hl ;point to B=column address w/offset ld b,(hl) ;B=column address w/offset call curadd ;move cursor to selected column-row position inc hl ;HL points to next 3 byte structure cp 0FFh ;if FF then never calibrated or something jr z,is0FFh push hl ;save the address of the next 3 byte group ld l,a ;get the one byte binary value ld h,0 ;zero the high byte since it's a 1 byte value nulbyt equ $-1 ;RAM loc. nulbyt=0 used as dummy buffer end call wordcrt ;turn it into 3 decimal digits and display them pop hl ;get back the address of the next 3 byte group ret wordcrt:push bc ;if entered here, registers BC are preserved ld e,' ' ;initialize the ASCII representation to ' ' ld c,100d ;prepare to subtract 100s from the hex number ld b,0 ;make BC=100d call asc ;find and display the number of hundreds in HL add hl,bc ;add the 100 that was subtracted to make neg. # ld c,10d ;prepare to subtract 10s from the hex number call asc ;find and display the number of tens in HL add hl,bc ;add the 10 that was subtracted to make neg. # ld e,'0' ;at least have a '0' in the ones position ld c,1 ;prepare to subtract 1s from the hex number call asc ;find and display the number of ones in HL pop bc ret ;routine exits here unless is0FFh is executing asc: xor a ;set the carry to 0 and zero register A ld a,e ;copy the ' ' or '0' into A ascsub: sbc hl,bc ;find number of 100s,10s,or 1s in the hex numbr jr c,ascret ;if less then 10 or 1 remains in the hex number inc a ;increment the ASCII representation jr ascsub ascret: cp ' ' ;see if still a ' ' jp z,jpouta ;when suppressing leading 0; use outchra's ret set 4,e ;change register E from ' '(20h) to '0' (30h) or e ;set bit 4 in register A (make it 30h-39h) jr jpouta ;print the 100s, 10s, or 1s digit that is in E ;** 0FFh indicates uncertainty, as a drive that hasn't been recalibrated.** is0FFh: ld a,' ' call outchra ld a,'?' ;send ' ??' to the CRT call outchra jpouta: jp outchra ;use outchra's return ;**************************************************************** ;* * ;* 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 bc,2B22h ;B=column address w/offset,C=row addr w/offset call curadd ;move cursor to track number position call outchre ;print the first digit get2nd: call inchr ;get the 2nd digit of track number call valdig ;see if A register has ASCII 0 through 9 jr c,get2nd ;valdig returns with carry set if not 0 thru 9 ld e,a ;save the ASCII character just entered sub 30h ;make the ASCII char. into a binary ones number add d ;add the binary value of the tens digit ld b,a ;save the sum of the tens+ones ld a,(maxtrk) ;get the highest allowed track number cp b ;compare it with the proposed new track number jr c,get2nd ;if new track would be larger than max track ld a,b ;put the new binary track number in register A ld (curtrk),a ;save the new current track number call outchre ;print the second digit ld hl,cylndr ;prepare for BYT2CRT:pointer to cylinder number ld (hl),a ;store new track number in cylndr also call byt2crt ;display the new track number on the CRT jp seek ;go do the seek ;************************************************************************ ;* The following five labels are entered directly from the comand * ;* parser. * ;************************************************************************ GETMAX: ld hl,maxtrk ;point to max track memory storage structure DB 0DDh ;ld hl instruction is 21h. DD 21 is LD IX,nnnn getcyl: ld hl,cylndr ;point to cylinder memory storage structure DB 0DDh ;ld hl instruction is 21h. DD 21 is LD IX,nnnn ;;;;;;; jr get2dig ;if 'C'get&display 2 digits on CRT,store binary gethead:ld hl,head ;point to head memory storage structure DB 0DDh ;ld hl instruction is 21h. DD 21 is LD IX,nnnn ;;;;;;; jr get2dig ;if 'H'get&display 2 digits on CRT,store binary getsecz:ld hl,secsize ;point to number memory storage structure DB 0DDh ;ld hl instruction is 21h. DD 21 is LD IX,nnnn ;;;;;;; jr get2dig ;if 'N'get&display 2 digits on CRT,store binary getrecd:ld hl,record ;point to record memory storage structure DB 0DDh ;ld hl instruction is 21h. DD 21 is LD IX,nnnn ;;;;;;; jr get2dig ;if 'R'get&display 2 digits on CRT,store binary getsec1:ld hl,strtsec ;point to strtsec memory storage structure DB 0DDh ;ld hl instruction is 21h. DD 21 is LD IX,nnnn ;;;;;;; jr get2dig ;if 'U'get&display 2 digits on CRT,store binary getsecp:ld hl,secpt ;point to secpt memory storage structure ;************************************************************************ ;* * ;* GET2DIG ROUTINE * ;* * ;* 1. ON ENTRY, HL points to THE START OF A 3 BYTE STRUCTURE IN * ;* MEMORY: * ;* DB XXh ;binary number(e.g. track) * ;* DW CCRRh ;SCREEN ADDRESS COLUMN AND ROW * ;* 2. The cursor is moved to the appropriate address on the CRT * ;* (as defined by the word CCRRh) and two digits are then * ;* input from the terminal. They are displayed on the CRT as * ;* they are input. The two digits are converted to a binary * ;* byte and stored in the entry HL (XXh). * ;* * ;************************************************************************ get2dig:inc hl ;point to row address byte w/offset ld c,(hl) ;prepare BC for call to CURADD inc hl ;point to column address byte w/offset ld b,(hl) ;prepare BC for call to CURADD inc b ;get2dig displays 2 digits, BYT2CRT shows 3 dec hl dec hl ;point to binary value to be displayed call curadd ;cursor address subroutine ;*NOTE: registers HL must be preserved across these calls* call get call calcten ;returns in D binary value of ASCII tens digit call get sub 30H ;make the ones a binary value in register A add a,d ;A=binary value of the pair of ASCII digits ld (hl),a ;save the binary value in memory ret ;(RET to comand) get: call inchr ;get a digit of the maximum track number call valdig ;see if A register has ASCII 0 through 9 jr c,get ;valdig returns with carry set if not 0 thru 9 jp outchra ;print the digit on the CRT(use outchra's ret) ;************************************************************************ ;* * ;* FORMAT ROUTINE * ;* Formats a microdecision drive track. * ;* * ;************************************************************************ format: call locmsg ;position cursor at beginning of message area ld a,(denbit) ;density is coded into bit 6: 0=FM, 1=MFM or 00001101b ;NEC 765 format a track command code call cmdnew ;is data port ready to receive a new command ;;;;;;; out (fdcdata),a ;send format a track cmd to NEC 765 data port call outsidr ;output byte 2(head and drive select)to FDCDATA ;;;;;;; call cmdrdy ;is data port ready to receive a command byte ;;;;;;; ld a,(sidbit) ;side bit is coded into bit 2 ;;;;;;; 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 (fdcdata),a ;byte 2 of format a track command call cmdrdy ;is data port ready to receive a command byte? ld a,(secsize) ;N: bytes per sector (03=1024 selected) out (fdcdata),a ;send command byte to NEC 765 data port call cmdrdy ;is data port ready to receive a command byte? ld a,(secpt) ;SC: sectors per track out (fdcdata),a ;send command byte to NEC 765 data port call cmdrdy ;is data port ready to receive a command byte ld a,(fgpl) ;format gap length (gap three) out (fdcdata),a ;send command byte to NEC 765 data port call cmdrdy ;is data port ready to receive a command byte? ld a,(secpt) ;use sectors per track for sector count ld b,a ;save count in register B ld a,(strtsec) ;beginning sector number ld c,a ;sector number being formatted stored in reg. C ld a,(FILBYTE);0E5h ;D: filler byte out (fdcdata),a ;send command byte to NEC 765 data port ;************************************************************************ ;* 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: ld a,(cylndr) ;get the current cylinder number (0-39) ei halt ;wait for an interrupt out (fdcdata),a ;send C information to NEC 765 data port ld a,(head) ;head (usually is 0 or 1) ei halt ;wait for an interrupt out (fdcdata),a ;send H information to NEC 765 data port ld a,c ;sector (Record) number being written ei halt ;wait for an interrupt out (fdcdata),a ;send R information to NEC 765 data port ld a,(secsize) ;sector size code ei halt ;wait for an interrupt out (fdcdata),a ;send N information to NEC 765 data port inc c ;number of sector being written djnz chrn ;dec count of secs to write;if done, fall thru ;************************************************************************ ;* * ;* SUBROUTINE INDATA * ;* * ;************************************************************************ indata: ld hl,datbuf ;7 memory bytes for temporary result storage ld b,7 ;there are 7 result bytes to be read ld c,fdcdata ;NEC765 floppy disk controller data port indat9: calì rdrdù ;is NEC 765 ready to send another result byte ini jr nz,indat9 ;if more result bytes remain to be read ret ;************************************************************************ ;* * ;* SUBROUTINE HEXCRT * ;* * ;* Convert a byte to ASCII and send the two characters to the CRT. * ;* Enter with the byte to be converted in register A. * ;* * ;************************************************************************ hexcrt: ld e,a ;save a copy of the byte into register E rrca ;get the high nybble first rrca rrca rrca call conv ;convert the high nybble to an ASCII character ld a,e ;get the copy of the byte, now do low nybble conv: and 0fh ;convert the nybble to an ASCII character add a,090h daa adc a,040h daa jp outchra ;CRT<--nybble in ASCII (ret to comand) ;************************************************************************ ;* * ;* SUBROUTINE HEADOUT * ;* Prints ST0, ST1, ST2, and CHRN (obtained from READ ID * ;* command and read data command) on the CRT. * ;* * ;************************************************************************ headout:ld bc,5B21h ;B=column address w/offset,C=row addr w/offset ld a,(datbuf+5) ;datbuf+5=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 call hexcrt ld a,' ' ;ascii space call outchra ;print a space pop hl pop bc ;get count djnz indat ;dec count, loop if all 7 bytes not printed yet ret ;done: all 7 bytes have been printed ;**************************************************************** ;* * ;* 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. * ;* All registers are returned unchanged. * ;* * ;**************************************************************** curadd: push af 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 ld a,(curflg) ;flag for row-column or reversed addr rrca ;see if bit 0 is 0 or 1 jr nc,colout rowout: ld a,b ;output column address call outchra ;print the character that is in reg A jr nc,dcadon colout: ld a,c ;output row address call outchra ;print the character that is in reg A jr nc,rowout ;is row next or are we done ? dcadon: pop af ret ;************************************************************************ ;* * ;* SUBROUTINE VALDIG * ;* * ;* Enter with a character in A. This subroutine checks the * ;* character and returns with the carry cleared if the character * ;* is between ASCII 0 and 9 (30h through 39h). If A contained * ;* anything else this subroutine returns with the carry set. * ;* All registers are returned unchanged. * ;* * ;************************************************************************ valdig: cp '0' ;is the character is a digit (ASCII 0-9)? ret c ;return with carry set if char less than '0' cp '9'+1 ;this will set carry if character '9' or less ccf ;complement carry ret ;return with carry set if char greater than '9' ;************************************************************************ ;* * ;* SUBROUTINE CALCTEN * ;* * ;* Enter with a ASCII digit 0-9 in register A. CALCTEN returns * ;* in register D the binary value of that number. Changes * ;* registers A and D only. * ;* * ;************************************************************************ calcten:push bc 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 ld d,a ;return the binary value in register D pop bc ret ;**************************************************************** ;* * ;* INCHR SUBROUTINE * ;* * ;* Checks to see if characters are comming from buffer. * ;* Fetches a character from the buffer if there are any. * ;* Else fetches a character from the console. * ;* (Inchr will return a character from the console when * ;* BUFACTV (memory location) is zero.) * ;* Returns character in register A, and since this routine * ;* is nearly always running, it keeps the motor running by * ;* calling MOTRUN. * ;* Registers BC, DE, and HL are preserved. * ;* * ;**************************************************************** ;*use microdecision sense drive status command to get status byte 3 (st3) and ;*to select the side inchr: push bc push de push hl ld a,04 ;sense drive status command call cmdnew ;is data port ready to receive a new command? ;;;;;;; out (fdcdata),a ;issue the command call outsidr ;output byte 2(head and drive select)to FDCDATA ;;;;;;; call cmdrdy ;is data port ready to receive a command byte ;;;;;;; ld a,(sidbit) ;get head select bit (coded into bit 2) ;;;;;;; ld e,a ;;;;;;; ld a,(motdrv) ;bit 0=US0, BIT 1=US1 for drive selection ;;;;;;; or e ;merge head select bits with drive select bits ;;;;;;; out (fdcdata),a ;byte 2 of drive status command ;*NOTE: reading the result is delayed until later in the INCHR routine in order ;*to keep side one selected (if it is) as long as possible ;** Get a character from the console or from the batch command buffer. ** ld a,(bufactv) ;0 if inactive, non-zero if active or a ;see if buffer is active jr z,charin ;if buffer is inactive ld hl,(bufptr) ;HL points to current byte in buffer ld a,(hl) ;get current byte from buffer push hl ;save pointer to current byte in buffer ld hl,(bufchr) ;HL=number of characters+'^'s in buffer string inc hl ;add 1 to number of characters cp 20h ;control characters are 0-1Fh jr nc,savecnt ;if not a control character inc hl ;add 1 more(for the '^')if it was a cntrl char savecnt:ld (bufchr),hl ;save number of chars+'^'s in memory pop hl ;retrieve pointer to current byte in buffer or a ;see if current byte is 0 jr z,NULBUF;bufres ;end of buffer marked by 00 call motrun in a,(status) ;read status register and rdbit ld a,(hl) ;get another copy of current byte from buffer inc hl ;HL points to current byte+1 in buffer ld (bufptr),hl ;save pointer to next byte in buffer jr z,getst3 ;nothing from kbd, so use character from buffer in a,(rdreg) ;read character to clear out I/O chip NULBUF: CALL BUFRES ;RESET COMMAND BUFFER, CLEAR CMD LINE FROM CRT ;retdumy: ld a,' ' ;dummy character to return to caller jr getst3 ;exit batch command, now get character from kbd 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 getst3: push af ;preserve the character and the flag call rdrdy ;is data port ready to send a result byte? in a,(fdcdata) ;read status byte 3 ld (st3),a ;save status register 3 information pop af ;retrieve the character and the flag pop hl pop de pop bc ret ;************************************************************************ ;* * ;* SUBROUTINE BUFRES * ;* BUFRES executes if any character is entered at the keyboard * ;* when inchr is getting a character from the command buffer. * ;* BUFRES also executes when a null (indicating the end of the * ;* command buffer is the character taken from the buffer. * ;* BUFRES terminates execution of the command buffer by reseting * ;* the buffer counter and setting the buffer active flag to 0. * ;* BUFRES also writes space characters over the command line * ;* that was displayed on the CRT. * ;* * ;************************************************************************ bufres: ld bc,2729h ;B=column address w/offset,C=row addr w/offset call curadd ;move cursor to 'Command;' ld e,'>' ;replace 'Command;' with 'Command>' call outchre call resbuf ;reset buffer counter & buffer active flag to 0 ;(RETURNS HL POINTING TO FIRST CHAR IN BUFFER-1 ld e,' ' ;prepare to send a blank space wipelin:inc hl ;point to next character in buffer ld a,(hl) ;get a character from the buffer cp 0 ;see if end of buffer has been reached RET Z ;IF COMMAND LINE ALL BLANKED OUT NOW ;;;;;;; jr z,retdumy ;if end of buffer let comand reposition cursor cp 20h ;control characters are 0-1Fh call c,outchre ;if char in buffer is a control character call outchre ;send a space jr wipelin ;************************************************************************ ;* * ;* SUBROUTINE MOTRUN * ;* * ;* Keep motor running if MOTOR ON (MOTOGL bit 0 is 1) is selected. * ;* * ;* This routine runs once before each check for a character * ;* from the terminal or the buffer. 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 jr z,drivon ;if motor is supposed to be off 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 SEEK * ;* * ;* Steps the drive head to the track specified in byte CURTRK. * ;* The seed command is a three byte command. * ;* * ;************************************************************************ seek: ld a,0Fh ;NEC 765 seek command code call cmdnew ;is data port ready to receive a new command? ;;;;;;; out (fdcdata),a ;send seek command to NEC 765 data port call outsidr ;output byte 2(head and drive select)to FDCDATA call cmdrdy ;is data port ready to receive a command byte ld a,(curtrk) ;byte 3 selects the cylinder number out (fdcdata),a ei halt ;wait for interrupt, then fall thru to SENSINT ;************************************************************************ ;* * ;* SUBROUTINE SENSINT * ;* 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. * ;* * ;************************************************************************ sensint:ld a,08 ;sense interrupt status command(clears FDD0-3) call cmdnew ;is data port ready to receive a new command? ;;;;;;; out (fdcdata),a ;issue the command ld bc,4325h ;B=column address w/offset,C=row addr w/offset call curadd ;move cursor to ST0 position call rdrdy ;is data port ready to send a result byte? in a,(fdcdata) ;read status 0 ld (st0),a ;save status register 0 information call hexcrt ;convert the A register to ASCII and print ;;;;;;; ld ix,sen0 ;;;;;;; jp lbyte ;convert the a register to ascii and print ;;;;;;;sen0: call rdrdy ;is data port ready to send a result byte? in a,(fdcdata) ;read present cylinder number ld (curtrk),a ;save the track number ld (cylndr),a ;also save the track number in CYLNDR ld a,(st0) ;get status register 0 information read earlier ret ;************************************************************************ ;* * ;* SUBROUTINE OUTSIDR * ;* * ;* Merge head select bits with drive select bits. Output the * ;* result to floppy disk controller data port. * ;* * ;************************************************************************ outsidr:call cmdrdy ;is data port ready to receive a command byte ld a,(sidbit) ;get head select bit (coded into bit 2) ld hl,motdrv ;point to drive select byte:bit 0=US0,BIT 1=US1 or (hl) ;merge head select bits with drive select bits out (fdcdata),a ;byte 2 of drive status command ret ;************************************************************************ ;* * ;* SUBROUTINE DRVTBL * ;* * ;* No register data required for entry. * ;* Returns: * ;* HL= pointer to the present drive's data table. * ;* DE= pointer to data followed by DCA address pairs. * ;* BC= number of data items followed by DCA address pairs. * ;* * ;************************************************************************ drvtbl: ld hl,drvdata-drvdlen ;table of data for each of 4 drives ld a,(motdrv) ;present drives number (0-3) inc a ;make drive number be 1-4 ld de,drvdlen ;length of a drive's data table nextdr: add hl,de ;hl points to start of a drive data structure dec a ;decrement drive number jr nz,nextdr ld de,datdca ;DE=pointer to data w/DCA address pairs ld bc,ndatdca ;number of data items followed by DCA pairs 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 first byte of new command. * ;* * ;************************************************************************ cmdnew: PUSH AF ;SAVE THE BYTE TO OUTPUT TO THE FDC DATA PORT ;;;;;;; call mddly ;delay 12.5 uS PUSH HL ;<<<<' denfm: shift ^^^ F lastchr 'M' denmfm: shift MF lastchr 'M' offmsg: shift OF lastchr 'F' onmsg: shift ^^^ O lastchr 'N' bscolon:db bs shl 1 ;used by filbuf to put a ';' after Command: lastchr ';' bsspbs: db bs shl 1 ;used to blank the character before the cursor shift ^^^ db ((bs shl 1)+1) ;readerr:shift ERROR^^^ (any^^^ key ;sector data read/write err messg ;;;;;;; lastchr ')' NRDYMSG:SHIFT Dr^^^ not^^^ rdy^^^ AR LASTCHR 'I' list ;resume listing when assembling ;************************************************************************ ;* * ;* 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 hasrun: db 0A5H ;this byte in RAM indicates program has run datdca: ;label start of data with Direct Cursor Addrs. ;** The following X pairs of source code lines must remain in this order. ** ;** The following two lines (three bytes) must remain in this order. ** curtrk: db 0FFh ;current track number in binary dw 2A22h ;curtrk column addr w/offset, row addr w/offset ;** The following two lines (three bytes) must remain in this order. ** maxtrk: db 39d ;maximum track number in binary dw 2A26h ;maxtrk column addr w/offset, row addr w/offset ;** The following two lines (three bytes) must remain in this order. ** cylndr: db 0FFh ;current cylinder number (C)in binary dw 3A22h ;cylndr column addr w/offset, row addr w/offset ;** The following two lines (three bytes) must remain in this order. ** head: db 00h ;initialize to head zero (H) dw 3A23h ;cylndr column addr w/offset, row addr w/offset ;** The following two lines (three bytes) must remain in this order. ** record: db 05h ;sector number (R) dw 3A24h ;record column addr w/offset, row addr w/offset ;** The following two lines (three bytes) must remain in this order. ** secsize:db 3 ;sector size code (N) (3=1024 bytes per sector) dw 3A25h ;secsize column addr w/offset,row addr w/offset ;** The following two lines (three bytes) must remain in this order. ** secpt: db 05h ;sectors per track dw 3A27h ;cylndr column addr w/offset, row addr w/offset ;** The following two lines (three bytes) must remain in this order. ** strtsec:db 01h ;starting sector number dw 3A26h ;cylndr column addr w/offset, row addr w/offset ndatdca equ ($-datdca)/3 ;number of data items in preceeding table ;**The following 10 lines must remain in this order&must follow ndatdca label.* drvdat: denbit: db 01000000b ;0100$0000 =MFM 0000$0000 =FM nondma: db 01 ;NEC765 in DMA mode=0;nonDMA mode=1(1 FOR uDec) hlt: db 02 ;Head Load Time range 01-7Fh steps 4mS @ 4MHz hut: db 01h ;Head Unload Time range 16-240mS steps16mS@4Mhz srt: db 0Eh ;Step Rate Time range F-0 steps 2mS @ 4MHz fgpl: db 05Fh ;format a track gap length (gap 3) rgpl: db 01Ch ;read data command gap length sidbit: db 00000000b ;0000$0100 =drive side 1 0000$0000 = side 0 motogl: db 0 ;motor toggle: 0=OFF, NON-ZERO=ON clock: db 02 ;NEC765 clock speed 1 for 8 MHz, 2 FOR 4 MHz ndrvdat equ $-drvdat ;number of data items above secbuf: dw 2400h ;RAM buffer for sector reads and writes curflg: db diradfg ;bit 0 determines order row-column transmited motdrv: db 0 ;drive #(filled by routine seldrv) FILBYTE:DB 0E5h ;FILL BYTE USED WHEN FORMATTING A TRACK ;** The following 4 sets of 17 lines each must remain in this order. ** drvdata: curtrk0:db 0FFh ;drive 0 track numbr:0FFh=drive never accessed maxtrk0:db 39d ; 0 highest physical track drive goes to cylndr0:db 0FFh ; 0 Cylinder number (C) head0: db 0 ; 0 Head number (H) record0:db 1 ; 0 Record number (R) secsiz0:db 3 ; 0 sector size number (N) secpt0: db 5 ; 0 sectors per track strsec0:db 1 ; 0 beginning sector number denbit0:db 01000000b ; 0 density bit nondma0:db 01 ; 0 FDC DMA mode=0;nonDMA mode=1(=uDec) hlt0: db 02 ; 0 head load time hut0: db 01 ; 0 head unload time srt0: db 0Eh ; 0 step rate time fgpl0: db 05Fh ; 0 format gap length rgpl0: db 01Ch ; 0 read data command gap length side0: db 0 ; 0 side number motor0: db 0 ; 0 motor on/off flag clock0: db 2 ; 0 FDC clock speed 1= 8 MHz, 2= 4 MHz drvdlen equ $-drvdata ;length of a drive's data table curtrk1:db 0FFh ;drive 1 track numbr:0FFh=drive never accessed maxtrk1:db 39d ; 1 highest physical track drive goes to cylndr1:db 0FFh ; 1 Cylinder number (C) head1: db 0 ; 1 Head number (H) record1:db 1 ; 1 Record number (R) secsiz1:db 3 ; 1 sector size number (N) secpt1: db 5 ; 1 sectors per track strsec1:db 1 ; 1 beginning sector number denbit1:db 01000000b ; 1 density bit nondma1:db 01 ; 1 FDC DMA mode=0;nonDMA mode=1(=uDec) hlt1: db 02 ; 1 head load time hut1: db 01 ; 1 head unload time srt1: db 0Eh ; 1 step rate time fgpl1: db 05Fh ; 1 format gap length rgpl1: db 01Ch ; 1 read data command gap length side1: db 0 ; 1 side number motor1: db 0 ; 1 motor on/off flag clock1: db 2 ; 1 FDC clock speed 1= 8 MHz, 2= 4 MHz curtrk2:db 0FFh ;drive 2 track numbr:0FFh=drive never accessed maxtrk2:db 39d ; 2 highest physical track drive goes to cylndr2:db 0FFh ; 2 Cylinder number (C) head2: db 0 ; 2 Head number (H) record2:db 1 ; 2 Record number (R) secsiz2:db 3 ; 2 sector size number (N) secpt2: db 5 ; 2 sectors per track strsec2:db 1 ; 2 beginning sector number denbit2:db 01000000b ; 2 density bit nondma2:db 01 ; 2 FDC DMA mode=0;nonDMA mode=1(=uDec) hlt2: db 02 ; 2 head load time hut2: db 01 ; 2 head unload time srt2: db 0Eh ; 2 step rate time fgpl2: db 05Fh ; 2 format gap length rgpl2: db 01Ch ; 2 read data command gap length side2: db 0 ; 2 side number motor2: db 0 ; 2 motor on/off flag clock2: db 2 ; 2 FDC clock speed 1= 8 MHz, 2= 4 MHz curtrk3:db 0FFh ;drive 3 track numbr:0FFh=drive never accessed maxtrk3:db 39d ; 3 highest physical track drive goes to cylndr3:db 0FFh ; 3 Cylinder number (C) head3: db 0 ; 3 Head number (H) record3:db 1 ; 3 Record number (R) secsiz3:db 3 ; 3 sector size number (N) secpt3: db 5 ; 3 sectors per track strsec3:db 1 ; 3 beginning sector number denbit3:db 01000000b ; 3 density bit nondma3:db 01 ; 3 FDC DMA mode=0;nonDMA mode=1(=uDec) hlt3: db 02 ; 3 head load time hut3: db 01 ; 3 head unload time srt3: db 0Eh ; 3 step rate time fgpl3: db 05Fh ; 3 format gap length rgpl3: db 01Ch ; 3 read data command gap length side3: DB 0 ; 3 side number motor3: DB 0 ; 3 motor on/off flag clock3: db 2 ; 3 FDC clock speed 1= 8 MHz, 2= 4 MHz ;************************************************************************ ;* * ;* The following equates define addresses of uninitialized RAM * ;* which this program will use when it runs. * ;* * ;************************************************************************ insert equ $ ;FF=insert;00=overwrite for cmd buffer editing datbuf equ insert+1 ;7 bytes uninitialized storage(ST0,1,2,C,H,R,N) st0 equ datbuf ;status register 0 st1 equ st0+1 ;status register 1 st2 equ st1+1 ;status register 2 st3 equ st2+1 ;1 byte uninitialized storage status reg. 3 ;4 bytes reserved here for cyl.head rec.number fdcst equ st3+5 ;NEC765/INTEL 8272 main status register fdccmds equ fdcst+1 ;10 byte buffer:command bytes to output to FDC bufptr equ fdccmds+10d ;pointer to char. in command buffer ;** BUFCHR, BUFACTV, and CMDBUF must remain in the following order. ** bufchr equ bufptr+2 ;displayed chars including'^'gotten so far(2byt bufactv equ bufchr+2 ;0=buffer inactive, non-zero=buffer active cmdbuf equ bufactv+1 ;uninitialized storage for batch command .dephase endmv2: ;end of assembled code endif ;end of "if alignment" conditional ;************************************************************************ ;* * ;* Initialization data for MD2 and MD3 UARTS and MD3 timer. * ;* * ;************************************************************************ if MD3 inittab: 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 ;set CTC channel 2 baud rate db 0Dh ;use 68h for 1200 baud; 0Dh for 9600 baud 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 initlen equ ($-inittab)/2 endif ;endif of if MD3 IF KPRO ;* Initialize keyboard port. Output the following bytes to port 7. * inittab:db 018h ;reset SIO db 004h ;select register 4 db 044h ;16X baud rate, 1 stop bit, no parity db 003h ;select register 3 db 0C1h ;8 bits Rx, Rx enabled db 005h ;select register 5 db 0E8h ;8 bit TX, TX enabled no RTS, no DTR db 001h ;select register 1 db 000h ;no interrupts initend: initlen equ initend-inittab ;* Initialize serial printer port. Output the following bytes to port 4. * db 018h ;reset SIO db 004h ;select register 4 db 04Ch ;16X baud rate, 2 stop bits, no parity db 003h ;select register 3 db 0C1h ;8 bits RX, RX enabled db 005h ;select register 5 db 068h ;8 bit TX, TX enabled no RTS, no DTR db 001h ;select register 1 db 000h ;no interrupts endif ;if KPRO ;************************************************************************ ;* * ;* 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 codelen equ $-serinit ;total code length .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 'Start of all code SERINIT',%serinit if monitor oncrt 'Monitor program re-entry address STRT ',%strt endif if alignment oncrt 'Alignment program start address ALIGN ',%align endif oncrt 'Ending address of all code and data ENDALL ',%endall oncrt 'Total code length is ',%codelen endif .radix 10 ;return to default radix end