; konan sysgen program ; DMA EQU 0 ;YES, THIS IS THE ONLY CHANGE (1 IF TRUE) ; fdos equ 5 maxsec equ 34 ;SKIP FINAL SECTOR (SINCE IT HAS THE MAP) org 100h restart lxi sp,stack ; print start message lxi d,startmes call string call inch ;get character sta unitch cpi 0dh ;is it a return? jz readdone ;if return, skip read sbi 1 ;change A-P to 0-15 ani 0fh ;now 0-15 sta hstdsk lxi d,rverfmes ;point to read verify mes call string ;print it lda unitch ;get unit call outch ;print character lxi d,retmes call string ;print rest of message call inch ;get responce cpi 0dh ;is it a cr? it should be jnz restart ;if not, restart sysgen jmp read ;do the read readdone: lxi d,desmes ;ask for destination call string call inch sta unitch cpi 0dh ;is it a return? jz 0 ;go reboot if it was a return sbi 1 ;make a-p into 0-15 ani 0fh sta hstdsk lxi d,verifymes call string ;print place on X message lda unitch ;X unit number call outch lxi d,retmes call string call inch ;wait for return cpi 0dh ;is it return? jz write jmp readdone read: call first ;set address to first readn call readhst call next jc done ;returns with carry set when done cpi 1 ;returns with 1 in accum if error jz harderror jmp readn done cpi 1 ;test for error jz harderror jmp readdone ;warm boot system, all done write call first ;select beginning address writen call writehst call next ;get next address jc done ;if carry it is done cpi 1 ;if 1 error occured jz harderror jmp writen first lxi h,0 shld hsttrk mvi a,0 sta hstsec ;start with sector 0 lxi h,780h ;starting address shld hstbuf ;set it ret next lda hstsec cpi maxsec jz finish ; if maxsector, xfer is done inr a ;increment sector sta hstsec ;set it lhld hstbuf ;get current dma address lxi d,512 dad d ;add 512 to old address shld hstbuf ;set new dma address xra a ;zero carry ret finish stc ;set carry when done ret inch mvi c,1 ;character in command jmp fdos outch mvi c,2 mov e,a jmp fdos harderror: lxi d,ermes ;point to error message call string jmp fdos string mvi c,9 jmp fdos ermes db 'hard disk error$' startmes: db 'KONAN system generation rev Y.1 ',0dh,0ah db 'all source/destinations are on hard disk unit 0',0dh,0ah db ' A = head 0, track 0',0dh,0ah db ' B = head 0, track 402',0dh,0ah db ' C = head 1, track 0',0dh,0ah db ' D = head 1, track 402',0dh,0ah db 'source (or return to skip)$' desmes db 0dh,0ah db 'destination drive name (or return to reboot)$' verifymes: db 0dh,0ah db 'destination on $' rverfmes: db 0dh,0ah db 'source on $' retmes db ' then type return$' sector db 0 dmaadd dw 0 unitch db 0 biosbase dw 0 ds 30 ;stack location stack equ $ ; ; disk read and write routines ; created from evoy4.asm Y.5 ; ; parameters: ; writehst: ; hstdsk = logical disk number,0 = A = unit 0 head 0 track 0 ; 1 = B = unit 0 head 0 track 402 ; 2 = C = unit 0 head 1 track 0 ; etc. ; hstsec = disk sector, ie 0 to 35 ; hsttrk = track, add 402 to it if a odd unit number,ie 1,B ; hstbuf = dma address ; error flag is returned in diost ; readhst: ; same as above ; iobase equ 90h busu equ iobase busl equ iobase+1 cmnd equ iobase+2 sctad equ iobase+3 sctbu equ iobase+4 dmacl equ iobase+5 dmacu equ iobase+6 statu equ iobase+7 headq equ 2 ;two heads per unit writehst: ;entry into the write program call kcommon ;sets sector,dma,head,track,unit rc ;error return xra a ;clear bus out busl out busu ;bus is now cleared out statu ;sector buffer now zeroed ; write the header now (track msb,track lsb,head,sector) lxi h,ptrk ;point to the track mvi b,4 ;header byte count headwt mov a,m ;get byte in acumulator out sctbu ;send it inx h dcr b ;decrement count jnz headwt ;if not done jmp to header write IF DMA mvi a,02 ;dma write command out cmnd ;do the write ENDIF IF NOT DMA LHLD HSTBUF LXI D,512 NXIOW MOV A,M OUT SCTBU INX H DCR E JNZ NXIOW DCR D JNZ NXIOW ENDIF OUT STATU ;NEEDED FOR IO. THIS WAS THE GREMLIN. mvi a,1 ;disk write command out cmnd ;do the write call wt ;wait for it to finish mvi a,'A' ;error A is a timeout jc erreport ;if timeout, print A in statu ;get statu ani 20h ;is fault on? mvi a,'B' jnz erreport ;print B if write fault ;report end status ret ;done with write readhst: ;read subroutine. reads via readint then does dma call readint ;place data into the sector buffer IF DMA mvi a,04h ;dma read command out cmnd ;do the read ENDIF IF NOT DMA LHLD HSTBUF LXI D,512 NXIOR IN SCTBU MOV M,A INX H DCR E JNZ NXIOR DCR D JNZ NXIOR ENDIF ret ;return readint: ;read to sector buffer call kcommon ;set sector,dma,track,head,and unit rc ;error return xra a ;generate a zero out busl ;clean up lower bus out busu ;clean up upper bus sta cerrc ;zero the error count rdkon out statu ;set buffer to zero mvi a,88h ;disk read command out cmnd ;do the read call wt ;wait for done mvi a,'C' cc erreport ;print C if timeout error jc rcovre ;go attempt to recover the timeout in statu ;get ending status ani 4h ;is checksum on? jnz chkrecov ;go report/recover ; we will now test the header lxi h,ptrk ;point to the track mvi b,4 ;number of header bytes out statu ;zero buffer address hdrtst in sctbu ;get header read cmp m jnz frmtrcv ;recover if different dcr b inx h jnz hdrtst ;if header count is non zero test one more ; when we arive here the read is done. ret ; ; ; read recovery program follows chkrecov: mvi a,'D' call erreport ;print a D if checksum error jmp rcovre frmtrcv mvi a,'E' call erreport ;print a E if format error rcovre: lda cerrc inr a ;increment the count sta cerrc ;save the new count mov c,a ;save the error count ani 3 ;get last 2 bits,strobe early and late cpi 3 ;not legal to have both on jz rcovre ;if illegal, go to next cerrc mov a,c ;get the error count ani 18h ;get the offset minus and plus bits cpi 18h ;are the both on? jz rcovre ;if so go to the next count mov a,c ;restore the error count cpi 20h ;is this the start of the second pass? cz panic ;if 20h we will retry sel,seek,mapper etc. lda cerrc ;restore the error count mov c,a ;place it in c for future recall adi 0dch ;time to give up? jc hardrder ;if carry we have a hard read error ; if we get here we are ready to set recovery bits and try again mov a,c ;restore error count rrc ;position bits ani 8ch ;get offsets plus strobe early out busl ;set the bits mov a,c ;restore error count rrc ;position bits ani 1 ;strobe late bit out busu ;bus now complete jmp rdkon ;go do the read recovery hardrder: ;hard disk read error out statu ;set the read buffer to address 4 in sctbu in sctbu in sctbu in sctbu mvi a,'F' ;hard error jmp erreport ; ; KONAN DISK READ AND WRITE COMMON ROUTINE ; SETS THE SECTOR, DMA, UNIT, HEAD, AND TRACK ; ADDRESSES. NOTE THAT EVERY HEAD SELECT IS ; FOLLOWED BY A SEEK TO MAINTAIN COMPATIBILITY ; WITH CMD DRIVES. ; returns with carry set if error, reset if not ; KCOMMON: xra a ;make a zero sta diost ;set error flag to zero LDA HSTSEC ;GET THE DESIRED SECTOR NUMBER OUT SCTAD ;SET THE SECTOR ADDRESS STA PSECTOR ;STORE IN TABLE FOR HEADER LHLD HSTBUF ;PLACE DMA ADDRESS IN H&L MOV A,L ;GET LSB OF DMA ADDRESS OUT dmacl ;SET LSB OF DMA ADDRESS MOV A,H ;GET MSB OF DMA ADDRESS OUT dmacu ;SET MSB OF DMA ADDRESS XRA A ;MAKE A ZERO OUT BUSL ;CLEAR THE LOWER BUS OUT BUSU ;CLEAR THE UPPER BUS ; CALCULATE THE PHYSICAL ADDRESS lhld hsttrk lxi d,-402 ;402 is max track per unit dad d ;if carry track is illegal mvi a,'N' ;error N is illegal track jc erreport LXI d,402 ;OFFSET FOR INNER TRACKS lhld hsttrk ;cpm track LDA HSTDSK ;0 FOR A, 1 FOR B, ETC rrc ;place lsb in carry jnc inner ;do not add 402 if inner dad d ;add 402 if outer inner ani 0fh ;remove end around carry MVI B,0 ;B=UNIT, INITIALLY 0 NUNIT CPI HEADQ ;IS HEADQ LARGER THEN HSTDSK? JC UNDONE ;B IS UNIT, A IS HEAD sbi headq ;decrement by the number of heads per unit inr b ;increment the unit undone sta phead ;remainder is the physical head mov a,b sta punit ;unit is the quotient mov a,h ;msb of track sta ptrk ;store it in physical upper track mov a,l ;lsb of track; sta ptrk+1 ;store it in physical lower track ; physical address is now set ; ;we will now check to see if select is true, and if the track ;, head, and unit addresses are the same as the last transfer, ;stored in oldunit, oldtrk, and oldhead. ; in statu ;get the status rrc ;place selected bit into carry jnc newadd ;if not select force new address ; test new vs old address lxi h,oldunit ;h,l point to old address lxi d,punit ;d&e point to new address mvi b,4 ;number of bytes to check adcmp ldax d ;get new address byte cmp m ;compare it to old jnz newadd ;if diferent go to new address dcr b inx h ;increment the pointer to current address inx d ;increment the pointer to desired address jnz adcmp ;if loop is not done compare one more ; return without error, same address xra a ;clear carry ret newadd: ; set old to physical lxi d,oldunit lxi h,punit mvi b,4 ;count update mov a,m ;get new stax d ;update old inx d inx h dcr b jnz update lda punit ;get the physical unit rrc ;unit is upper half of byte rrc rrc rrc out busu ;place it on the bus mvi a,10h ;select command out cmnd ;select i in statu ;get status rrc ;place select in carry cmc ;carry 1 if not selected mvi a,'G' ;select error jc erreport ;print it lda phead ; cpi 0 jz hdjust ;is head zero leave allone adi 15 ;add 15 to set lolume tag hdjust out busl ;set it on the bus mvi a,40h ;set head command out cmnd ;do the head select in statu ;get the status ani 20h ;test disk fault but mvi a,'H' jnz erreport ;if fault is one, report it ; ; ; seek routine ; track substitution excluded ; seek: call gseek ;go perform the seek rnc ;return if seek was good(no carry) ; if here, first seek attempt failed call recal ;recal drive to attemmpt to clear error call gseek ;give it one more try rnc ;if no error it recovered ; if here, hard seek error occured mvi a,0ffh ;set a to all ones sta oldunit ;this will cause a select and seek upon ; next access mvi a,'I' jmp erreport ;report the seek error gseek: ; comprize commposite address to search track table for lhld ptrk ;h&l are desired track xchg ;now d&e are the track ;if track substitution were included it would be here! mov a,d ;lsb of track out busl mov a,e ;msb of track ani 3 ;strip all but track out busu ;bus now set to track mvi a,20h ;seek command out cmnd ;do the seek call wt ;wait for done mvi a,'J' jc erreport ;print J if seek timeout ret ; wait for done, return with carry off when done, ; and carry set if timeout. wt mvi h,0ffh ;h&l will be decremented for a gross timeout wz dcx h ;decrement count mov a,h ;place msb of count into a ora l ;or in lsb to see if any bit is non-zero jz timeout ;timeout if hl zero befor done in statu ;get status ani 80h ;is done on? jz wz ;if not done wait ret ;good return, carry off from the ani 80h timeout stc ;set carry ret ;error return ; ; panic routine follows ; do fault reset, recall, kill oldunit, call kcommon panic call recal ;recal unit mvi a,0ffh sta oldunit ;kill old unit to force a seek and select call kcommon ret recal xra a ;make a zero out busu ;zero upper bus mvi a,50h ;fault clear and recal bits out busl ;set onto bus mvi a,80h ;fault recovery command out cmnd ;start fault recovery xra a ;make another zero out cmnd ;turn off the fault command call wt ;wait for done mvi a,'K' cc erreport ;print a K if recal timeout ret ; ; hard disk error print ; erreport: sta diost ;set error flag lxi h,errormes call prmsg lda diost ;get error letter mov c,a ;place ascii character in c call conout ; print the error letter stc ;set carry ret ; errors include; ; A write timeout error ; B write fault ; C read timeout ; D checkword ; E format ; F hard read error ; G unit select error ; H head select error ; I hard seek error ; J seek timeout ; K recal timeout ; L mapper error ; M map overrun prmsg: mov a,m ;print message at h&l to 0 ora a rz ; more to print push h mov c,a call conout pop h inx h jmp prmsg conout mov e,c ;place character in e mvi c,02 ;character output command jmp 0005 ;let cpm print it errormes: db 0dh,0ah db 'hard disk error ' db 0 ; track: ds 2 ;two bytes for expansion dmaad: ds 2 ;direct memory address diskno: ds 1 ;disk number 0-15 diost: ds 1 ;i/o return status 0 ok ; ; do not change the order of the next 9 bytes! cerrc ds 1 ;error counter,hard diskt punit ds 1 ;physical unit ptrk ds 2 ;physical track phead ds 1 ;physical head psector ds 1 ;physical sector oldunit db 0ffh ;last selected unit oldtrk ds 2 ;last track succesfully seeked oldhead ds 1 ;last selected head ; hstdsk: ds 1 ;host disk number hsttrk: ds 2 ;host track number hstsec: ds 1 ;host sector number hstbuf ds 2 ;dma address ; sekhst: ds 1 ;seek shr secshf hstact: ds 1 ;host active flag hstwrt: ds 1 ;host written flag ; unacnt: ds 1 ;unalloc rec cnt unadsk: ds 1 ;last unalloc disk END