***************************************************************** * * * Firmware for Disk Jockey Model B. * * * ***************************************************************** title '*** Disk Jockey Model B Firmware ***' origin equ 0E000H org origin BEGINS EQU ORIGIN+3deh RAM EQU ORIGIN+400h IO EQU ORIGIN+3f8h UDATA EQU IO DREG EQU IO+1 USTAT EQU IO+1 DCMD EQU IO+2 DSTAT EQU IO+2 CSTALL EQU IO+3 CMDREG EQU IO+4 CSTAT EQU IO+4 TRKREG EQU IO+5 SECREG EQU IO+6 DATREG EQU IO+7 LIGHT EQU 1 HEAD EQU 1 DENSITY EQU 1 ISTAT EQU 4 TZERO EQU 4 LOAD EQU 4 ULOAD EQU 6 OSTAT EQU 10Q DSIDE EQU 10Q NOLITE EQU 11Q DCRINT EQU 11Q HCMD EQU 11Q INDEX EQU 20Q WINDXD EQU 22Q SKCMD EQU 30Q RINDXD EQU 32Q SVCMD EQU 35Q WPROT EQU 100Q ACCESS EQU 100Q RSTBIT EQU 200Q READY EQU 200Q RDCMD EQU 200Q WRCMD EQU 240Q STBITS EQU 300Q RACMD EQU 304Q CLRCMD EQU 320Q DBOOT JMP BOOT TERMIN JMP CIN TRMOUT JMP COUT TKZERO JMP HOME TRKSET JMP SEEK SETSEC JMP SECSET SETDMA JMP DMA DREAD JMP READ DWRITE JMP WRITE SELDRV JMP DRIVE TPANIC JMP CPAN TSTAT JMP TMSTAT DMAST JMP DMSTAT STATUS JMP DISKST DSKERR JMP LERROR SETDEN JMP DENFIX SETSID JMP SIDEFX DS 107Q BOOT LXI SP,TRACK+1 ;initialize SP CALL TIMOUT ;poc/reset timeout LXI H,1 PUSH H ;track 0, sector 1 MVI L,DCRINT ;set up the PUSH H ; side select MVI H,377Q ; and initial PUSH H ; drive PUSH H ; parameters PUSH H PUSH H LXI H,10Q ;initialize PUSH H ; tzflag & cdisk MVI L,176Q ;initialize PUSH H ; disk & drvsel MVI L,10Q ;initialize PUSH H ; hdflag & dsflag MVI H,30Q ;initialize PUSH H ; timer constant MVI A,177Q ;start 1791 STA DREG MVI A,CLRCMD ;1791 reset STA CMDREG LDHEAD XRA A ;load the head CALL HDCHK ; and test for JNC DOOROK ; drive ready MVI A,LIGHT ;turn on the STA DCREG ; error LED CALL TIMOUT ;timeout to JMP LDHEAD ; close drive door DOOROK MVI A,NOLITE ;turn off the STA DCREG ; error LED CALL MEASUR ;head load time POP B ;adjust the stack LXI B,RAM+300H ;DMA addr PUSH B ;initialize PUSH D ; dmaadr & timer LXI H,0 ;initialize PUSH H ; intrfg & ramins NOP ;debug instruction PUSH B ;boot address MVI B,12 ;number of retrys LDLOOP PUSH B ;save the retry no. CALL READ ;read boot sector POP B ;restor retry no. RNC ;successful read? DCR B ;no - count down JNZ LDLOOP ; and try again LERROR MVI C,11Q LXI D,0a2c3h LELOOP DCX D MOV A,D ORA E JNZ LELOOP MVI A,10Q ;blink XRA C ; the LED at MOV C,A ; top of the STA DCMD ; circuit board JMP LERROR+2 COUT LDA USTAT ;get UART status ANI OSTAT ;output ready mask JNZ COUT ;test buffer empty MOV A,C ;character data CMA ;negative logic bus STA UDATA ;send data to UART CMA ;make positive RET CIN LDA USTAT ;get UART status ANI ISTAT ;input ready mask JNZ CIN ;wait for input LDA UDATA ;get the character CMA ;adjust for negative bus ANI 177Q ;trim to 7 bits RET CPAN LDA USTAT ;get UART status ANI ISTAT ;input ready mask RNZ ;test for data CALL CIN ;get character CMP C ;test for panic chtr RET TMSTAT LDA USTAT ;get UART status ANI ISTAT ;input ready mask RET DISKST LXI H,TRKREG ;most recent MOV C,M ; track to C INX H ;most recent MOV B,M ; sector to B LDA DCREG ;get current CMA ; density in ANI 1 ; the msb RRC ; position MOV D,A ;save in D LDA SIDE ;put the RLC ; most recent RLC ; side select RLC ; in bit positin ORA D ; 6 and merge MOV D,A ;save in D LDA DSFLAG ;get the XRI DSIDE ; most recent RAL ; double sided RAL ; status and place ADD D ; in bit position MOV D,A ; 5 and merge LDA SECLEN ;get the RAL ; sector length RAL ; code bits in ORA D ; positions 2 & 3 MOV D,A ; and merge LDA CDISK ;get the current ADD D ; disk no. in bit RET ; positions 0 & 1 DMSTAT PUSH H ;save the HL pair LHLD DMAADR ;move the MOV B,H ; DMA address to MOV C,L ; the BC pair POP H ;recover HL RET DRIVE MOV A,C ;drive select ANI 3 ; values must be STA DISK ; between zero RET ; and three DMA LXI H,-RAM ;test the DAD B ; DMA address JC DMASET ; for conflict LXI H,8-ORIGIN DAD B ; with the I/O JNC DMASET ; on the DJ/2D MVI A,20Q ; controller RET DMASET MOV H,B ;store the MOV L,C ; BC pair SHLD DMAADR RET HOME CALL HDLOAD ;load the head RC ;not ready error CALL HENTRY ;move the head PUSH PSW ;save status SBB A ;update the STA TRACK ; track STA TRKREG ; registers XRA A ;set the not STA TZFLAG ; verified flag JMP LEAVE+1 ;unload the head HENTRY XRA A ;set the force STA HDFLAG ; verify flag LXI H,0 ;timeout constant MVI A,HCMD ;move the head CALL CENTRY ;to track 0 ANI TZERO ;track zero bit RNZ STC ;error flag RET SECSET XRA A ;test for ORA C ; zero value STC ;error flag RZ ;error return ANI 37Q ;trim & clear cry STA SECTOR RET SEEK MOV A,C ;test for CPI 77 ; track CMC ; too large RC STA TRACK RET WRITE CALL PREP ;prepare for write JC LEAVE ;abort operation LXI H,CMDREG ;issue a force MVI M,CLRCMD ; interruupt cmd XTHL ;time delay XTHL ; padding XTHL ; instructions XTHL MVI A,WPROT ;write prot mask ANA M ;test for write OK JNZ PLEAVE ;abort operation MVI A,WINDXD ;stax d instruction MVI C,WRCMD ;write sector cmd CALL SPREP ;prepare for stall MOV A,M ;1st data byte CALL BEGINS ;dynamic stall JMP WRENTRY ;enter write loop WRLOOP MOV A,M ;load 1st byte of data STAX D ;write 1st byte of data WRENTRY INX H ;advance pointer MOV A,M ;load 2nd byte of data STAX D ;write 2nd byte of data INX H ;advance pointer MOV A,M ;load 3rd byte of data STAX D ;write 3rd byte of data INX H ;advance pointer DCR B ;reduce block count MOV A,M ;load 4th byte of data STAX D ;write 4th byte of data INX H ;advance pointer JNZ WRLOOP ;write next 4 bytes JMP CBUSY READ CALL PREP ;prepare for read JC LEAVE ;abort operation MVI A,RINDXD ;ldax d instruction MVI C,RDCMD ;read sector cmd CALL SPREP ;prepare for stall CALL BEGINS ;dynamic stall MOV M,A ;store data LDAX D ;read next byte JMP RDENTRY ;enter read loop RDLOOP LDAX D ;read 1st byte INX H ;advance pointer MOV M,A ;store 1st byte LDAX D ;read 2nd byte RDENTRY INX H ;advance pointer MOV M,A ;store 2nd byte LDAX D ;read 3rd byte INX H ;advance pointer MOV M,A ;store 3rd byte DCR B ;reduce block count LDAX D ;read 4th byte INX H ;advance pointer MOV M,A ;store 4th byte JNZ RDLOOP ;read next 4 bytes CBUSY LDA CSTAT ;get 1791 status RAR ;busy bit to carry JC CBUSY RAL ;restore the ACC ANI 337Q ;error bit mask JZ LEAVE ;no error PLEAVE STC ;error flag LEAVE PUSH PSW ;save the status LDA DCREG ;control bits XRI LOAD ;toggle the STA DCMD ; head load bit LDA DRVSEL ;enable access to STA DREG ; the data register POP PSW ;recover the status RET PREP CALL HDLOAD ;load the head RC ;test for drive ready LDA TRKREG ;get old track INR A ;test for head CZ HENTRY ; not calibrated RC ;seek error? LXI H,TRKREG ;old track LDA TRACK ;new track CMP M ;test for head motion INX H ;advance to the INX H ; data register MOV M,A ;save new track MOV A,C ;turn off data reg STA DREG ; access control bit JZ TVERFY ;test for seek XRA A ;force a read STA HDFLAG ; header operation LDA DSTAT ;get the double ANI DSIDE ; sided flag STA DSFLAG ;save for status RAR ;shift for RAR ; 3/6 ms step RAR ; rate constant ADI SKCMD ;do a LXI H,0 ; seek CALL CENTRY ; operation JC SERROR ;seek error? TVERFY LDA HDFLAG ;get the force ORA A ; verify hdr flag JNZ CHKSEC ;no seek & head OK MVI B,2 ;verify retry count SLOOP MVI A,SVCMD ;do a verify CALL COMAND ; command ANI 231Q ;error bit mask MOV D,A ;save JZ RDHDR ;no error LDA DCREG ;denisty control XRI DENSITY ;flip the density STA DCREG ;update and STA DCMD ; change density DCR B ;decrement retry JNZ SLOOP ; count & test MOV A,D SERROR STC PUSH PSW CALL HENTRY POP PSW RET RDHDR MVI B,12Q ;number of retrys RHLOOP MVI A,32Q ;read instruction MVI C,RACMD ;read header cmd CALL SPREP ;prepare for read CALL BEGINS ;dynamic stall STA TRACK+1 ;save the track LDAX D ;get the side no. LXI H,TRACK+2 ;data pointer MOV M,A ;store side no. INX H ;advance pointer RHL1 LDAX D ;get disk data 0 MOV M,A ;store in mem INR L ;advance pointer JNZ RHL1 ;test end of page LXI H,CSTAT ;wait for 1791 CALL BUSY ; to finish cmd ORA A ;test for errors JZ CHKSEC ;transfer OK? DCR B ;no - test for JNZ RHLOOP ; hard error JMP SERROR ;recalibrate CHKSEC LDA SECLEN ;get the sector MOV C,A ; size and setup MVI B,0 ; the table offset LXI H,STABLE ;sector table DAD B ;sector size pntr LDA SECTOR ;get the sector MOV B,A ; and save in B ADD M ;compare w/table MVI A,20Q ;error flag RC ;error return MOV A,B ;initialize 1791 STA SECREG ; sector register MVI A,40Q ;128 byte sector SZLOOP DCR C ;reduce size count MOV B,A ;sector size to B RM ;return on minus RAL ;double the count ORA A ;clear the carry JMP SZLOOP STABLE DB 345Q ;26 sector diskettes DB 345Q ;26 sector diskettes DB 360Q ;15 sector diskettes DB 367Q ;8 sector diskettes HDLOAD LXI H,DISK ;new drv ptr MOV C,M ;save new drv in C INX H ;current drv ptr MOV E,M ;save old drv in E MOV M,C ;update current drv INX H ;home cmd flag MOV A,E ;test for CMP C ; drive change MOV A,M ;head load mask MVI M,HEAD ;update the mask JZ HDCHK ;no drive change? INX H ;addr of drive table PUSH H ;save table addr MVI D,0 ;set up the MOV B,D ; offset address DAD D ;calculate the DAD D ; parameter addr LDA DCREG ;save the MOV M,A ;density status INX H ;track pointer LXI D,TRKREG ;1791 trk reg LDAX D ;get current track MOV M,A ;save in the table POP H ;beginning of table DAD B ;new drive DAD B ; table pointer MOV A,M ;get density status STA DCREG ;update DCREG INX H ;get the old MOV A,M ; track number STAX D ; and update 1791 MVI A,177Q ;drive select bits DSROT RLC ;rotate to DCR C ; select the JP DSROT ; proper drive ANI 177Q ;set the run bit STA DRVSEL ;save in drv reg XRA A ;force a head load HDCHK LXI H,DSTAT ;test for ANA M ; head loaded STA HDFLAG ;save the head PUSH PSW ; loaded status LDA DRVSEL ;get current drive MOV C,A ;save LDA SIDE ;get current side CMA ; and merge ANA C ; with drive select STA DREG ;select drive & side XRI ACCESS ;toggle access bit MOV C,A ;save for PREP routine LDA DCREG ;den & head cntl bits MOV B,A ;save LDA TRACK ;get the new track SUI 1 ;force single SBB A ; density DCR A ; if track = 0 CMA ;compliment ORA B ;merge w/control bits MOV M,A ;load head & set density POP PSW ;head load status JNZ RDYCHK ;conditionally PUSH H ; wait for head LHLD TIMER ; load time out TLOOP DCX H ;count down MOV A,H ; 40 ms for ORA L ; head load JNZ TLOOP ; time out POP H RDYCHK MOV A,M ;test for ANI READY ; drive ready RNZ UNLOAD LDA DCREG ;force a ORI ULOAD ; head MOV M,A ; unload MVI A,READY ;set drive STC ; not ready RET ; error flag COMAND LHLD TIMER ;get index count DAD H ; and multiply DAD H ; by four CENTRY XCHG ;save in D-E pair LXI H,CSTAT ;issue command MOV M,A ; to the 1791 NBUSY MOV A,M ;wait RAR ; for the JNC NBUSY ; busy flag BUSY MOV A,M ;test for RAR ; device busy MOV A,M ;restore status RNC ;return if not busy DCX D ;test for MOV A,D ; two disk ORA E ; revolutions JNZ BUSY ;47 machine cycles MOV E,M ;get error code PUSH H ;save cmd address INX H ;track register MOV D,M ;save present track LDA DRVSEL ;control bits XRI RSTBIT ;reset the 1791 STA DREG ; controller to JMP PATCH+3 ;jump around patch PATCH JMP HDLOAD ;patch for old ATE NOP ;fill instruction XRI STBITS ; clear the XTHL ; command busy STA DREG ; fault condition MVI M,CLRCMD ;force interrupt XTHL ;restore the MOV M,D ; the track reg POP H ;restore the stack MOV A,E ;error code to A STC ; error flag RET MEASUR LXI D,0 ;initialize count LXI H,DSTAT ;status port MVI C,INDEX ;index bit flag INDXLO MOV A,M ;wait for ANA C ; index JZ INDXLO ; pulse high INDXHI MOV A,M ;wait for ANA C ; index JNZ INDXHI ; pulse low INDXCT INX D ;advance count XTHL ;four dummy XTHL ; instructions XTHL ; to lengthen XTHL ; the delay MOV A,M ;wait for ANA C ; the index JZ INDXCT ; to go high RET ;98 machine cycles DENFIX MOV A,C ;trim the ANI 1 ; excess bits CMA ;compliment and MOV B,A ; save in B LXI H,DISK ;new disk ptr MOV E,M ;get disk no. MVI D,0 ;offset addr INX H ;current disk ptr MOV A,M ;move to ACC XRA E ;cmpr old w/new PUSH PSW ;save status INX H ;disk table INX H ; address DAD D ;add the DAD D ; offset MOV A,M ;get parameters ORI 1 ;mask off density ANA B ;set new density MOV M,A ;update parameters POP PSW ;test new=old? RNZ MOV A,M ;updata CDISK STA DCREG ; also RET TIMOUT LXI H,0 ;time-out delay TILOOP DCX H ;decrement count MOV A,H ;test for delay ORA L ; count equal zero XTHL ;long NOP XTHL ; instruction JNZ TILOOP RET SPREP STA RAMINS ;store instruction STA CSTALL ;ready stall logic LHLD DMAADR ;dma address LXI D,DATREG ;data register MOV A,C ;execute the STA CMDREG ; operation RET SBEGIN PUSH H ;save the pointer LXI H,DSTALL ;setup jump DSTALL PCHL ;dynamic stall POP H ;restore pointer RET ;return SIDEFX MOV A,C ;get the side bit ANI 1 ;trim the excess RAL ;move the bit RAL ; to the side RAL ; select bit RAL ; position STA SIDE ;save side bit RET PWRJMP NOP ;power-on NOP ; jump NOP ; sequence NOP ; with NOP NOP ; padding JMP DBOOT DS 10Q ;I/O locations org ram+3c9h STACK DS 31Q RAMINS NOP ;dynamic stall escape INTRFG DB 0 ;interrupt enable flag TIMER DW 1800h ;head load time out DMAADR DW RAM+300H ;dma address DSFLAG DB 10Q HDFLAG DB 0 ;read header flag DRVSEL DB 176Q ;drive select constant DISK DB 0 ;new drive CDISK DB 10Q ;current disk TZFLAG DB 0 ;home cmd indicator DOPRAM DB 11Q ;drive 0 parameters DOTRK DB 377Q ;drive 0 track no D1PRAM DB 11Q ;drive 1 parameters D1TRK DB 377Q ;drive 1 track no D2PRAM DB 11Q ;drive 2 parameters D2TRK DB 377Q ;drive 2 track no D3PRAM DB 11Q ;drive 3 parameters D3TRK DB 377Q ;drive 3 track no DCREG DB 11Q ;current parameters SIDE DB 0 ;new side SECTOR DB 1 ;new sector TRACK DB 0 ;new track TRKNO DB 0 ;disk SIDENO DB 0 ; sector SECTNO DB 0 ; header SECLEN DB 0 ; data CRCLO DB 0 ; buffer CRCHI DB 0