***************************************************************** * * * Firmware for Disk Jockey Model B. * * * ***************************************************************** title '*** Disk Jockey Model B Firmware ***' origin equ 0E000H org origin 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 INTRQ EQU 4 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 JREADY 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 JCOUT TKZERO JMP JHOME TRKSET JMP SEEK JSECT JMP SECSET JDMA JMP DMA DREAD JMP JREAD DWRITE JMP JWRITE 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 66Q 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 JREAD ;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 JCOUT LDA USTAT ;get UART status ANI OSTAT ;output ready mask JNZ JCOUT ;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 JCDISK ;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 JHOME 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 ISSUE STA ECOUNT+1 ;update count CALL MEASUR ;find index MVI C,1 ;Start with sector 1 ISLOOP MOV A,C ;Initilize the STA SECREG ; sector register LDA SECTOR ;Test for CMP C ; target sector RZ MVI A,RDCMD ;do a fake CALL COMAND ; read command JC PLEAVE ;Abort on error INR C ;Increment sector number JMP ISLOOP COMNDP STA CMDREG ;Start operation MOV C,B ;Initilize block count LXI D,DATREG ;Data register LHLD DMAADR ;transfer address RET JWRITE CALL JPREP ;prepare for write JC LEAVE ;abort operation WRENTRY MVI A,WRCMD ;write sector cmd CALL COMNDP WRLOOP MOV A,M ;load 1st byte of data INX H STAX D ;write 1st byte of data MOV A,M ;load 2nd byte of data INX H STAX D ;write 2nd byte of data MOV A,M ;load 3rd byte of data INX H STAX D ;write 3rd byte of data DCR c ;reduce block count MOV A,M INX H STAX D JNZ WRLOOP ;write next 4 bytes LXI H,WRENTRY JMP CBUSY JREAD CALL JPREP ;prepare for read JC LEAVE ;abort operation RDENTRY MVI a,RDCMD CALL COMNDP RDLOOP LDAX D ;read 1st byte MOV M,A ;store 1st byte INX H LDAX D ;read 2nd byte MOV M,A ;store 2nd byte INX H LDAX D ;read 3rd byte MOV M,A ;store 3rd byte INX H DCR c ;reduce block count LDAX D ;read 4th byte MOV M,A ;store 4th byte INX H JNZ RDLOOP ;read next 4 bytes LXI H,RDENTRY CBUSY PUSH H ;Save return LXI H,CSTAT ;Wait for 1791 CALL BUSY ; to finish command ANI 137Q ;Error mask JZ LEAVE-1 ;No error CPI 20Q ;Premature interupt JNZ PLEAVE ;Other type of error LDA ECOUNT ;decrement error count DCR A ; by one JM STEST ;Hard interupt error STA ECOUNT ;Update count RET STEST LDA ECOUNT+1 ;Decrement error DCR A JP ISSUE MVI A,20Q PLEAVE STC ;error flag POP H 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 JPREP 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 LXI D,DATREG ;Data register LXI H,TRACK+1 ;Data pointer MVI A,RACMD ;Start read header command STA CMDREG 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 LXi h,505h SHLD ECOUNT 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 JREADY ; drive ready RNZ UNLOAD LDA DCREG ;force a ORI ULOAD ; head MOV M,A ; unload MVI A,JREADY ;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 JMP PATCH+3 ;jump around patch PATCH JMP HDLOAD ;patch for old ATE 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 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 SBEGIN PUSH H LXI H,DSTALL DSTALL PCHL POP H RET 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 ECOUNT DW 0 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 JCDISK 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 ***************************************************************** * * * Cbios for CP/M Ver 2.2 for Disk Jockey 2D controller (all * * revs). Handles diskettes with sector sizes of 128 bytes * * single density, 256, 512, 1024 bytes double density. * * * * Written by Bobby Dale Gifford. * * 9/1/79 * * * * Disk Map of sectors used by Cold Boot, Warm Boot, Firmware, * * and CP/M: * * * * trk 0 sec 1 = First sector of cold boot. e700h * * 0 2 = Cold boot 256. 80h * * 0 3 = Cold boot 512. 80h * * 0 4 = Cold boot 1024. 80h * * 0 5 = Warm boot 256. 80h * * 0 6 = Warm boot 512. 80h * * 0 7 = Warm boot 1024. 80h * * 0 8 = Cold/Warm boot. 3200h * * 0 9 = Firmware. e400h * * 0 10 = Firmware+80h. e480h * * 0 11 = Firmware+100h e500h * * 0 12 = Firmware+180h. e580h * * 0 13 = Firmware+200h. e600h * * 0 14 = Firmware+280h. e680h * * 0 15 = Firmware+300h. e700h * * 0 16 = Firmware+380h. e780h * * 0 17 = CCP. 2d00h * * 0 10 = CCP+80h. 2d80h * * 0 12 = CCP+100h. 2e00h * * 0 14 = CCP+180h. 2e80h * * 0 16 = CCP+200h. 2f00h * * 0 18 = CCP+280h. 2f80h * * 0 20 = CCP+300h. 3000h * * 0 22 = CCP+380h. 3080h * * 0 24 = CCP+400h. 3100h * * 0 26 = CCP+480h. 3180h * * 1 = Rest of CP/M. 3200h-4fffh * * * ***************************************************************** title '*** Cbios For CP/M Ver. 2.2 ***' ***************************************************************** * * * The following revision number is in reference to the CP/M * * 2.0 Cbios. * * * ***************************************************************** revnum equ 31 ;Cbios revision number cpmrev equ 22 ;CP/M revision number ***************************************************************** * * * The following equates relate the Thinker Toys 2D controller. * * If the controller is non standard (0E000H) only the ORIGIN * * equate need be changed. This version of the Cbios will work * * with 2D controller boards rev 0, 1, 3, 3.1, 4. * * * ***************************************************************** djram equ RAM ;Disk Jockey 2D RAM address djcin equ TERMIN ;Disk Jockey 2D character input routine djcout equ TRMOUT ;Disk Jockey 2D character output routine djhome equ TKZERO ;Disk Jockey 2D track zero seek djtrk equ JSECT ;Disk Jockey 2D track seek routine djsec equ JSECT ;Disk Jockey 2D set sector routine djdma equ JDMA ;Disk Jockey 2D set DMA address djread equ DREAD ;Disk Jockey 2D read routine djwrite equ DWRITE ;Disk Jockey 2D write routine djsel equ SELDRV ;Disk Jockey 2D select drive routine djtstat equ TSTAT ;Disk Jockey 2D terminal status routine djstat equ STATUS ;Disk Jockey 2D status routine djerr equ DSKERR ;Disk Jockey 2D error, flash led djden equ SETDEN ;Disk Jockey 2D set density routine djside equ SETSID ;Disk Jockey 2D set side routine ***************************************************************** * * * CP/M system equates. If reconfiguration of the CP/M system * * is being done, the changes can be made to the following * * equates. * * * ***************************************************************** msize equ 24 ;Memory size of target CP/M bias equ (msize-20)*1024 ;Memory offset from 20k system ccp equ 2d00h+bias ;Console command processor bdos equ ccp+800h ;BDOS address bios equ ccp+1600h ;CBIOS address cdisk equ 4 ;Address of last logged disk buff equ 80h ;Default buffer address tpa equ 100h ;Transient memory intioby equ 0 ;Initial IOBYTE iobyte equ 3 ;IOBYTE location wbot equ 0 ;Warm boot jump address entry equ 5 ;BDOS entry jump address ***************************************************************** * * * The following are internal Cbios equates. Most are misc. * * constants. * * * ***************************************************************** retries equ 10 ;Max retries on disk i/o before error acr equ 0dh ;A carriage return alf equ 0ah ;A line feed aetx equ 3 ;A ETX char aack equ 6 ;A ACK char clear equ 1ah ;Clear screen char on ADM3 terminal maxdisk equ 4 ;Maximum # of disk drives dblsid equ 8 ;Side bit from controller ***************************************************************** * * * The jump table below must remain in the same order, the * * routines may be changed, but the function executed must be * * the same. * * * ***************************************************************** org bios ;CBIOS starting address jmp cboot ;Cold boot entry point wboote jmp wboot ;Warm boot entry point jmp const ;Console status routine jmp conin ;Console input cout jmp conout ;Console output jmp list ;List device output jmp punch ;Punch device output jmp reader ;Reader device input jmp home ;Home drive jmp setdrv ;Select disk jmp settrk ;Set track jmp setsec ;Set sector jmp setdma ;Set DMA address jmp read ;Read the disk jmp write ;Write the disk jmp listst ;List device status jmp sectran ;Sector translation djdrv jmp djsel ;Hook for SINGLE.COM program ***************************************************************** * * * Signon message output during cold boot. * * * ***************************************************************** prompt db acr,alf,alf db '0'+msize/10 ;CP/M memory size db '0'+(msize mod 10) db 'K CP/M Vers. ' ;CP/M version number db cpmrev/10+'0' db '.' db (cpmrev mod 10)+'0' db ', Cbios rev ' db revnum/10+'0','.' ;Cbios revision number db revnum mod 10+'0' db acr,alf db 'For Thinker Toys Disk Jockey 2D Controller ' db '@ 0' if origin/4096 > 10 ;Controller origin (HEX) db origin/4096+'A'-10 else db origin/4096+'0' endif if (origin/256 and 0fh) > 10 db (origin/256 and 0fh)+'A'-10 else db (origin/256 and 0fh)+'0' endif db '00H.' db acr,alf,0 ***************************************************************** * * * Utility routine to output the message pointed at by H&L, * * terminated with a null. * * * ***************************************************************** message mov a,m ;Get a character of the message inx h ;Bump text pointer ana a ;Test for end rz ;Return if done push h ;Save pointer to text mov c,a ;Output character in C call cout ;Output the character pop h ;Restore the pointer jmp message ;Continue until null reached ***************************************************************** * * * Cboot is the cold boot loader. All of CP/M has been loaded in * * when control is passed here. * * * ***************************************************************** cboot lxi sp,tpa ;Set up stack call tinit ;Initialize the terminal lxi h,prompt ;Prep for sending signon message call message ;Send the prompt xra a ;Select disk A sta cpmdrv sta cdisk ***************************************************************** * * * Gocpm is the entry point from cold boots, and warm boots. It * * initializes some of the locations in page 0, and sets up the * * initial DMA address (80h). * * * ***************************************************************** gocpm lxi h,buff ;Set up initial DMA address call setdma mvi a,(jmp) ;Initialize jump to warm boot sta wbot sta entry ;Initialize jump to BDOS lxi h,wboote ;Address in warm boot jump shld wbot+1 lxi h,bdos+6 ;Address in BDOS jump shld entry+1 xra a ;A <- 0 sta bufsec ;Disk Jockey buffer empty sta bufwrtn ;Set buffer not dirty flag lda cdisk ;Jump to CP/M with currently selected disk in C mov c,a lxi d,cmndbeg ;Beginning of initial command lxi h,ccp+8 ;Command buffer mvi a,cmndend-cmndbeg+1 ;Length of command sta ccp+7 mov b,a call movlop lda cwflg ana a lda autoflg jz cldbot rar cldbot rar jc ccp jmp ccp+3 ;Enter CP/M cwflg db 0 ;Cold/warm boot flag ***************************************************************** * * * The following byte determines if an initial command is to be * * given to CP/M on warm or cold boots. The value of the byte is * * used to give the command to CP/M: * * * * 0 = never give command. * * 1 = give command on cold boots only. * * 2 = give the command on warm boots only. * * 3 = give the command on warm and cold boots. * * * ***************************************************************** autoflg db 1 ;Auto command feature ***************************************************************** * * * If there is a command inserted here, it will be given if the * * auto feature is enabled. * * For Example: * * * * cmndbeg db 'MBASIC MYPROG' * * cmndend db 0 * * * * will execute microsoft basic, and mbasic will execute the * * "MYPROG" basic program. * * * ***************************************************************** cmndbeg db '' ;Initial command goes here cmndend db 0 ***************************************************************** * * * Wboot loads in all of CP/M except the CBIOS, then initializes * * system parameters as in cold boot. See the Cold Boot Loader * * listing for exactly what happens during warm and cold boots. * * * ***************************************************************** wboot lxi sp,tpa ;Set up stack pointer mvi a,1 wflg equ $-1 ;Test if beginning or ana a ; ending a warm boot mvi a,1 sta wflg sta cwflg ;Set cold/warm boot flag jz gocpm xra a sta wflg mov c,a call djdrv ;Select drive A mvi c,0 ;Select single density call djden mvi c,0 ;Select side 0 call djside mvi a,15 ;Initialize the sector to read sta newsec lxi h,ccp-100h ;And the DMA address shld newdma call warmlod ;Read in CP/M lxi b,ccp+500h ;Load address for rest of warm boot call djdma mvi c,8 call djsec call warmrd jmp ccp+503h warmlod mvi a,15 ;Previous sector newsec equ $-1 inr a ;Update the previous sector inr a cpi 27 ;Was it the last ? jc nowrap sui 9 ;Yes cpi 19 rz lhld newdma lxi d,-480h dad d shld newdma nowrap sta newsec ;Save the new sector to read mov c,a call djsec lxi h,ccp-100h ;Get the previous DMA address newdma equ $-2 lxi d,100h ;Update the DMA address dad d shld newdma ;Save the DMA address mov b,h mov c,l call djdma ;Set the DMA address call warmrd jmp warmlod warmrd lxi b,retries*100h+0;Maximum # of errors wrmread push b call djtrk ;Set the track call djread ;Read the sector pop b rnc ;Continue if successful dcr b jnz wrmread ;Keep trying jmp djerr ***************************************************************** * * * Setsec just saves the desired sector to seek to until an * * actual read or write is attempted. * * * ***************************************************************** setsec mov a,c ;Save the sector number sta cpmsec ;CP/M sector # ret ***************************************************************** * * * Setdma saves the DMA address for the data transfer. * * * ***************************************************************** setdma mov h,b ;hl <- bc mov l,c shld cpmdma ;CP/M dma address ret ***************************************************************** * * * Home is translated into a seek to track zero. * * * ***************************************************************** home mvi c,0 ;Track to seek to ***************************************************************** * * * Settrk saves the track # to seek to. Nothing is done at this * * point, everything is deffered until a read or write. * * * ***************************************************************** settrk mov a,c ;A <- track # sta cpmtrk ;CP/M track # ret ***************************************************************** * * * Sectran translates a logical sector # into a physical sector * * #. * * * ***************************************************************** sectran inx b push d ;Save table address push b ;Save sector # call getdpb ;Get DPB address into HL mov a,m ;Get # of CP/M sectors/track ora a ;Clear cary rar ;Divide by two sub c push psw ;Save adjusted sector jm sidetwo sidea pop psw ;Discard adjusted sector pop b ;Restore sector requested pop d ;Restor address of xlt table sideone xchg ;hl <- &(translation table) dad b ;bc = offset into table mov l,m ;hl <- physical sector mvi h,0 ret sidetwo lxi b,15 ;Offset to side bit dad b mov a,m ani 8 ;Test for double sided jz sidea ;Media is only single sided pop psw ;Retrieve adjusted sector pop b cma ;Make sector request positive inr a mov c,a ;Make new sector the requested sector pop d call sideone mvi a,80h ;Side two bit ora l ; and sector mov l,a ret ***************************************************************** * * * Setdrv selects the next drive to be used in read/write * * operations. If the drive has never been selected before, a * * parameter table is created which correctly describes the * * diskette currently in the drive. Diskettes can be of four * * different sector sizes: * * 1) 128 bytes single density. * * 2) 256 bytes double density. * * 3) 512 bytes double density. * * 4) 1024 bytes double density. * * * ***************************************************************** setdrv mov a,c ;Save the drive # sta cpmdrv cpi maxdisk ;Check for a valid drive # jnc zret ;Illegal drive # mov a,e ;Test if drive ever logged in before ani 1 jnz setdrv1 ;Bit 0 of E = 0 -> Never selected before mvi a,1 ;Select sector 1 of track 1 sta truesec sta cpmtrk call fill ;Flush buffer and refill jc zret ;Test for error return call djstat ;Get status on current drive ani 0ch ;Strip off unwanted bits push psw ;Used to select a DPB rar lxi h,xlts ;Table of XLT addresses mov e,a mvi d,0 dad d push h ;Save pointer to proper XLT call getdpb ;Get DPH pointer into DE xchg ; pop d mvi b,2 ;Number of bytes to move call movlop ;Move the address of XLT lxi d,8 ;Offset to DPB pointer dad d ;HL <- &DPH.DPB push h lhld origin+7 ;Get address of DJ terminal out routine inx h ;Bump to look at address of ; uart status location mov a,m xri 3 ;Adjust for proper rev DJ mov l,a mvi h,(origin+300h)/100h mov a,m ani dblsid ;Check double sided bit lxi d,dpb128s ;Base for single sided DPB's jnz sideok lxi d,dpb128d ;Base of double sided DPB's sideok xchg ;HL <- DBP base, DE <- &DPH.DPB pop d ;Restore DE (pointer into DPH) pop psw ;Offset to correct DPB ral ral mov c,a mvi b,0 dad b xchg ;Put DPB address in DPH mov m,e inx h mov m,d setdrv1 call getdpb ;Get address of DPB in HL lxi b,15 ;Offset to sector size dad b mov a,m ;Get sector size ani 7h sta secsiz mov a,m rar rar rar rar ani 0fh sta secpsec xchg ;HL <- DPH ret zret lxi h,0 ;Seldrv error exit ret ***************************************************************** * * * Getdpb returns HL pointing to the DPB of the currently * * selected drive, DE pointing to DPH. * * * ***************************************************************** getdpb lda cpmdrv ;Get drive # mov l,a ;Form offset mvi h,0 dad h dad h dad h dad h lxi d,dpzero ;Base of DPH's dad d push h ;Save address of DPH lxi d,10 ;Offset to DPB dad d mov a,m ;Get low byte of DPB address inx h mov h,m ;Get low byte of DPB mov l,a pop d ret ***************************************************************** * * * Xlts is a table of address that point to each of the xlt * * tables for each sector size. * * * ***************************************************************** xlts dw xlt128 ;Xlt for 128 byte sectors dw xlt256 ;Xlt for 256 byte sectors dw xlt512 ;Xlt for 512 byte sectors dw xlt124 ;Xlt for 1024 byte sectors ***************************************************************** * * * Write routine moves data from memory into the buffer. If the * * desired CP/M sector is not contained in the disk buffer, the * * buffer is first flushed to the disk if it has ever been * * written into, then a read is performed into the buffer to get * * the desired sector. Once the correct sector is in memory, the * * buffer written indicator is set, so the buffer will be * * flushed, then the data is transferred into the buffer. * * * ***************************************************************** write mov a,c ;Save write command type sta writtyp mvi a,1 ;Set write command db (mvi) or (b*8) ;This "mvi b" instruction causes ; the following "xra a" to ; be skipped over. ***************************************************************** * * * Read routine to buffer data from the disk. If the sector * * requested from CP/M is in the buffer, then the data is simply * * transferreä froí thå buffeò tï thå desireä dma address. If * * the buffer does not contain the desired sector, the buffer is * * flushed to the disk if it has ever been written into, then * * filled with the sector from the disk that contains the * * desired CP/M sector. * * * ***************************************************************** read xra a ;Set the command type to read sta rdwr ;Save command type ***************************************************************** * * * Redwrt calculates the physical sector on the disk that * * contains the desired CP/M sector, then checks if it is the * * sector currently in the buffer. If no match is made, the * * buffer is flushed if necessary and the correct sector read * * from the disk. * * * ***************************************************************** redwrt mvi b,0 ;The 0 is modified to contain the log2 secsiz equ $-1 ; of the physical sector size/128 ; on the currently selected disk. lda cpmsec ;Get the desired CP/M sector # push psw ;Temporary save ani 80h ;Save only the side bit mov c,a ;Remember the side pop psw ;Get the sector back ani 7fh ;Forget the side bit dcr a ;Temporary adjustment divloop dcr b ;Update repeat count jz divdone ora a ;Clear the cary flag rar ;Divide the CP/M sector # by the size ; of the physical sectors jmp divloop ; divdone inr a ora c ;Restore the side bit sta truesec ;Save the physical sector number lxi h,cpmdrv ;Pointer to desired drive,track, and sector lxi d,bufdrv ;Pointer to buffer drive,track, and sector mvi b,4 ;Count loop dtslop dcr b ;Test if done with compare jz move ;Yes, match. Go move the data ldax d ;Get a byte to compare cmp m ;Test for match inx h ;Bump pointers to next data item inx d jz dtslop ;Match, continue testing ***************************************************************** * * * Drive, track, and sector don't match, flush the buffer if * * necessary and then refill. * * * ***************************************************************** call fill ;Fill the buffer with correct physical sector rc ;No good, return with error indication ***************************************************************** * * * Move has been modified to cause either a transfer into or out * * the buffer. * * * ***************************************************************** move lda cpmsec ;Get the CP/M sector to transfer dcr a ;Adjust to proper sector in buffer ani 0 ;Strip off high ordered bits secpsec equ $-1 ;The 0 is modified to represent the # of ; CP/M sectors per physical sectors mov l,a ;Put into HL mvi h,0 dad h ;Form offset into buffer dad h dad h dad h dad h dad h dad h lxi d,buffer ;Beginning address of buffer dad d ;Form beginning address of sector to transfer xchg ;DE = address in buffer lxi h,0 ;Get DMA address, the 0 is modified to ; contain the DMA address cpmdma equ $-2 mvi a,0 ;The zero gets modified to contain ; a zero if a read, or a 1 if write rdwr equ $-1 ana a ;Test which kind of operation jnz into ;Transfer data into the buffer outof call mover xra a ret into xchg ; call mover ;Move the data, HL = destination ; DE = source mvi a,1 sta bufwrtn ;Set buffer written into flag mvi a,0 ;Check for directory write writtyp equ $-1 dcr a mvi a,0 sta writtyp ;Set no directory write rnz ;No error exit ***************************************************************** * * * Flush writes the contents of the buffer out to the disk if * * it has ever been written into. * * * ***************************************************************** flush mvi a,0 ;The 0 is modified to reflect if ; the buffer has been written into bufwrtn equ $-1 ana a ;Test if written into rz ;Not written, all done lxi h,djwrite ;Write operation ***************************************************************** * * * Prep prepares to read/write the disk. Retries are attempted. * * Upon entry, H&L must contain the read or write operation * * address. * * * ***************************************************************** prep xra a ;Reset buffer written flag sta bufwrtn shld retryop ;Set up the read/write operation mvi b,retries ;Maximum number of retries to attempt retrylp push b ;Save the retry count lda bufdrv ;Get drive number involved in the operation mov c,a call djdrv ;Select the drive lda buftrk ana a ;Test for track zero mov c,a push b cz djhome ;Home the drive if track 0 pop b ;Restore track # call djtrk ;Seek to proper track lda bufsec ;Get sector involved in operation push psw ;Save the sector # rlc ;Bit 0 of A equals side # ani 1 ;Strip off unnecessary bits mov c,a ;C <- side # call djside ;Select the side pop psw ;A <- sector # ani 7fh ;Strip off side bit mov c,a ;C <- sector # call djsec ;Set the sector to transfer lxi b,buffer ;Set the DMA address call djdma call djread ;The read operation is modified to write retryop equ $-2 pop b ;Restore the retry counter mvi a,0 ;No error exit status rnc ;Return no error dcr b ;Update the retry counter stc ;Assume retry count expired mvi a,0ffh ;Error return rz jmp retrylp ;Try again ***************************************************************** * * * Fill fills the buffer with a new sector from the disk. * * * ***************************************************************** fill call flush ;Flush buffer first rc ;Check for error lxi d,cpmdrv ;Update the drive, track, and sector lxi h,bufdrv mvi b,3 ;Number of bytes to move call movlop ;Copy the data lxi h,djread jmp prep ;Select drive, track, and sector. ; Then read the buffer ***************************************************************** * * * Mover moves 128 bytes of data. Source pointer in DE, Dest * * pointer in HL. * * * ***************************************************************** mover mvi b,128 ;Length of transfer movlop ldax d ;Get a bte of source mov m,a ;Move it inx d ;Bump pointers inx h dcr b ;Update counter jnz movlop ;Continue moving until done ret ***************************************************************** * * * Terminal driver routines. Iobyte is initialized by the cold * * boot routine, to modify, change the "intioby" equate. The * * I/O routines that follow all work exactly the same way. Using * * iobyte, they obtain the address to jump to in order to execute* * the desired function. There is a table with four entries for * * each of the possible assignments for each device. To modify * * the I/O routines for a different I/O configuration, just * * change the entries in the tables. * * * ***************************************************************** citty equ djcin ;Input from the Disk Jockey 2D cotty equ djcout ;Output to the Disk Jockey 2D ***************************************************************** * * * const: get the status for the currently assigned console * * device. The console device can be gotten from iobyte, * * then a jump to the correct console status routine is * * performed. * * * ***************************************************************** const lxi h,cstble ;Beginning of jump table jmp conin1 ;Select correct jump ***************************************************************** * * * csreader: if the console is assigned to the reader then a * * jump will be made here, where another jump will * * occur to the correct reader status. * * * ***************************************************************** csreadr lxi h,csrtble ;Beginning of reader status table jmp readera ***************************************************************** * * * conin: take the correct jump for the console input routine. * * The jump is based on the two least significant bits of * * iobyte. * * * ***************************************************************** conin call flush ;Flush the disk buffer lxi h,citble ;Beginning of character input table * * Entry at conin1 will decode the two least significant bits * of iobyte. This is used by conin,conout, and const. * conin1 lda iobyte ral * * Entry at seldev will form an offset into the table pointed * to by H&L and then pick up the address and jump there. * seldev ani 6h ;Strip off unwanted bits mvi d,0 ;Form offset mov e,a dad d ;Add offset mov a,m ;Pick up high byte inx h mov h,m ;Pick up low byte mov l,a ;Form address pchl ;Go there ! ***************************************************************** * * * conout: take the proper branch address based on the two least * * significant bits of iobyte. * * * ***************************************************************** conout push b ;Save the character call flush ;Flush the disk buffer pop b ;Restore the character lxi h,cotble ;Beginning of the character out table jmp conin1 ;Do the decode ***************************************************************** * * * reader: select the correct reader device for input. The * * reader is selected from bits 2 and 3 of iobyte. * * * ***************************************************************** reader lxi h,rtble ;Beginning of reader input table * * Entry at readera will decode bits 2 & 3 of iobyte, used * by csreader. * readera lda iobyte * * Entry at reader1 will shift the bits into position, used * by list and punch. * readr1 rar jmp seldev ***************************************************************** * * * punch: select the correct punch device. The selection comes * * from bits 4&5 of iobyte. * * * ***************************************************************** punch lxi h,ptble ;Beginning of punch table lda iobyte * * Entry at pnch1 rotates bits a little more in prep for * seldev, used by list. * pnch1 rar rar jmp readr1 ***************************************************************** * * * list: select a list device based on bits 6&7 of iobyte * * * ***************************************************************** list lxi h,ltble ;Beginning of the list device routines list1 lda iobyte rar rar jmp pnch1 ***************************************************************** * * * Listst: Get the status of the currently assigned list device * * * ***************************************************************** listst lxi h,lstble ;Beginning of the list device status jmp list1 ***************************************************************** * * * If customizing I/O routines is being performed, the table * * below should be modified to reflect the changes. All I/O * * devices are decoded out of iobyte and the jump is taken from * * the following tables. * * * ***************************************************************** * * console input table * citble dw citty ;Input from tty (currently assigned ; by intioby,input from 2d) dw cicrt ;Input from crt (currently SWITCHBOARD ; serial port 1) dw reader ;Input from reader (depends on reader ; selection) dw ciuc1 ;Input from user console 1 (currently ; SWITCHBOARD serial port 1) * * console output table * cotble dw cotty ;Output to tty (currently assigned ; by intioby,output to 2d) dw cocrt ;Output to crt (currently SWITCHBOARD ; serial port 1) dw list ;Output to list device (depends on ; bits 6&7 of iobyte) dw couc1 ;Output to user console 1 (currently ; SWITCHBOARD serial port 1) * * list device table * ltble dw cotty ;Output to tty (currently assigned ; by intioby,output to 2d) dw cocrt ;Output to crt (currently SWITCHBOARD ; serial port 1) dw colpt ;Output to line printer (currently ; SWITCHBOARD serial port 1) dw coul1 ;Output to user line printer 1 (currently ; SWITCHBOARD serial port 1) * * punch device table * ptble dw cotty ;Output to the tty (currently assigned ; by intioby,output to 2d) dw coptp ;Output to paper tape punch (currently ; SWITCHBOARD serial port 1) dw coup1 ;Output to user punch 1 (currently ; SWITCHBOARD serial port 1) dw coup2 ;Output to user punch 2 (currntlly ; SWITCHBOARD serial port 1) * * reader device input table * rtble dw citty ;Input from tty (currently assigned ; by intioby, input from 2d) dw ciptr ;Input from paper tape reader (currently ; SWITCHBOARD serial port 1) dw ciur1 ;Input from user reader 1 (currently ; SWITCHBOARD serial port 1) dw ciur2 ;Input from user reader 2 (currently ; SWITCHBOARD serial port 1) * * console status table * cstble dw cstty ;Status of tty (currently assigned ; by intioby, ststus from 2d) dw cscrt ;Status from crt (currently SWITCHBOARD ; serial port 1) dw csreadr ;Status from reader (depends on reader device ) dw csuc1 ;Status from user console 1 (currently ; SWITCHBOARD serial port 1) * * status from reader device * csrtble dw cstty ;Status from tty (currently assigned ; by intioby, status of 2d) dw csptr ;Status from paper tape reader (currently ; SWITCHBOARD serial port 1) dw csur1 ;Status from user reader 1 (currently ; SWITCHBOARD serial port 1) dw csur2 ;Status of user reader 2 (currently ; SWITCHBOARD serial port 1) * * Status from list device * lstble dw ready ;Console always ready dw ready ;Get list status dw lslpt dw lslpt ***************************************************************** * * * The following equates set output device to output to the * * SWITCHBOARD serial port 1. * * * ***************************************************************** cocrt equ $ ;Output from crt couc1 equ $ ;Output from user console 1 coptp equ $ ;Output from paper tape punch coup1 equ $ ;Output from user punch 1 coup2 equ $ ;Output from user punch 2 colpt in 2 ;Output from line printer,get status ani 80h ;Wait until ok to send jz colpt mov a,c ;output the character out 1 ret ***************************************************************** * * * Custom I/O printer driver for Diablo printer with 1200 baud * * ETX/ACK handshake. * * * ***************************************************************** coul1 call colpt ;Output the character lda count dcr a sta count rnz mvi a,50 sta count mvi c,aetx call colpt pwait call ciptr cpi aack jnz pwait ret count db 50 ***************************************************************** * * * The following equates set the input from the devices to come * * from the SWITCHBOARD serial port 1. * * * ***************************************************************** ciuc1 equ $ ;Input from user console 1 cicrt equ $ ;Input from crt ciur1 equ $ ;Input from user reader 1 ciur2 equ $ ;Input from user reader 2 ciptr in 2 ;Input from paper tape reader, get status ani 40h ;Wait for character jz ciptr in 1 ani 7fh ;Strip off the parity ret ***************************************************************** * * * console status routines, test if a character has arrived. * * * ***************************************************************** cstty call djtstat ;Status from Disk Jockey 2D stat mvi a,0 ;Prep for zero return rnz ;Nothing found dcr a ;Return with 0FFH ret ***************************************************************** * * * The following equates cause the devices to get status from * * the SWITCHBOARD serial port 1. * * * ***************************************************************** csur1 equ $ ;Status of user reader 1 csur2 equ $ ;Status of user reader 2 csptr equ $ ;Status of paper tape reader csuc1 equ $ ;Status of user console 1 cscrt in 2 ;Status from crt, get status ani 40h ;Strip of data ready bit xri 40h ;Make correct polarity jmp stat ;Return proper indication ***************************************************************** * * * List device status routines. * * * ***************************************************************** lslpt in 2 ;All other devices wait ani 80h rz ready mvi a,0ffh ret ***************************************************************** * * * Tinit can be modified for different I/O setups. * * * ***************************************************************** tinit mvi c,clear ;Initialize the terminal routine mvi a,intioby ;Initialize IOBYTE sta iobyte jmp cout ***************************************************************** * * * Xlt tables (sector skew tables) for CP/M 2.0. These tables * * define the sector translation that occurs when mapping CP/M * * sectors to physical sectors on the disk. There is one skew * * table for each of the possible sector sizes. Currently the * * tables are located on track 0 sectors 6 and 8. They are * * loaded into memory in the Cbios ram by the cold boot routine. * * * ***************************************************************** xlt128 db 0 db 1,7,13,19,25 db 5,11,17,23 db 3,9,15,21 db 2,8,14,20,26 db 6,12,18,24 db 4,10,16,22 xlt256 db 0 db 1,2,19,20,37,38 db 3,4,21,22,39,40 db 5,6,23,24,41,42 db 7,8,25,26,43,44 db 9,10,27,28,45,46 db 11,12,29,30,47,48 db 13,14,31,32,49,50 db 15,16,33,34,51,52 db 17,18,35,36 xlt512 db 0 db 1,2,3,4,17,18,19,20 db 33,34,35,36,49,50,51,52 db 5,6,7,8,21,22,23,24 db 37,38,39,40,53,54,55,56 db 9,10,11,12,25,26,27,28 db 41,42,43,44,57,58,59,60 db 13,14,15,16,29,30,31,32 db 45,46,47,48 xlt124 db 0 db 1,2,3,4,5,6,7,8 db 25,26,27,28,29,30,31,32 db 49,50,51,52,53,54,55,56 db 9,10,11,12,13,14,15,16 db 33,34,35,36,37,38,39,40 db 57,58,59,60,61,62,63,64 db 17,18,19,20,21,22,23,24 db 41,42,43,44,45,46,47,48 ***************************************************************** * * * Each of the following tables describes a diskette with the * * specified characteristics. The tables are currently stored * * on track 0 sector 13. They are read into memory by the GOCPM * * routine in the CBIOS for CP/M ver 2.0. * * * ***************************************************************** ***************************************************************** * * * The following DPB defines a diskette for 128 byte sectors, * * single density, and single sided. * * * ***************************************************************** dpb128s dw 26 ;CP/M sectors/track db 3 ;BSH db 7 ;BLM db 0 ;EXM dw 242 ;DSM dw 63 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 16 ;CKS dw 2 ;OFF db 1h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette for 256 byte sectors, * * double density, and single sided. * * * ***************************************************************** dpb256s dw 52 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 242 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 12h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette as 512 byte sectors, * * double density, and single sided. * * * ***************************************************************** dpb512s dw 60 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 280 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 33h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette as 1024 byte sectors, * * double density, and single sided. * * * ***************************************************************** dp1024s dw 64 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 299 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 74h ;16*((#cpm sectors/physical sector) -1) + ;log2(#bytes per sector/128) + 1 + ;8 if double sided. ***************************************************************** * * * The following DPB defines a diskette for 128 byte sectors, * * single density, and double sided. * * * ***************************************************************** dpb128d dw 52 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 1 ;EXM dw 242 ;DSM dw 127 ;DRM db 0c0h ;AL0 db 0 ;AL1 dw 32 ;CKS dw 2 ;OFF db 9h ***************************************************************** * * * The following DPB defines a diskette as 256 byte sectors, * * double density, and double sided. * * * ***************************************************************** dpb256d dw 104 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 486 ;DSM dw 255 ;DRM db 0f0h ;AL0 db 0 ;AL1 dw 64 ;CKS dw 2 ;OFF db 1ah ***************************************************************** * * * The following DPB defines a diskette as 512 byte sectors, * * double density, and double sided. * * * ***************************************************************** dpb512d dw 120 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 561 ;DSM dw 255 ;DRM db 0f0h ;AL0 db 0 ;AL1 dw 64 ;CKS dw 2 ;OFF db 3bh ***************************************************************** * * * The following DPB defines a diskette as 1024 byte sectors, * * double density, and double sided. * * * ***************************************************************** dp1024d dw 128 ;CP/M sectors/track db 4 ;BSH db 15 ;BLM db 0 ;EXM dw 599 ;DSM dw 255 ;DRM db 0f0h ;AL0 db 0 ;AL1 dw 64 ;CKS dw 2 ;OFF db 7ch ***************************************************************** * * * CP/M disk parameter headers, unitialized. * * * ***************************************************************** dpzero dw 0 ;Address of translation table (filled ; in by setdrv) dw 0,0,0 ;Used by BDOS dw dirbuf ;Address of directory buffer dw 0 ;Address of DPB (filled in by setdrv) dw csv0 ;Directory check vector dw alv0 ;Allocation vector dpone dw 0 dw 0,0,0 dw dirbuf dw 0 dw csv1 dw alv1 dptwo dw 0 dw 0,0,0 dw dirbuf dw 0 dw csv2 dw alv2 dpthre dw 0 dw 0,0,0 dw dirbuf dw 0 dw csv3 dw alv3 ***************************************************************** * * * Cbios ram locations that don't need initialization. * * * ***************************************************************** cpmsec db 0 ;CP/M sector # cpmdrv db 0 ;CP/M drive # cpmtrk db 0 ;CP/M track # truesec db 0 ;Disk Jockey sector that contains CP/M sector bufdrv db 0 ;Drive that buffer belongs to buftrk db 0 ;Track that buffer belongs to bufsec db 0 ;Sector that buffer belongs to buffer ds 1024 ;Maximum size buffer for 1K sectors alv0 ds 75 ;Allocation vector for drive A alv1 ds 75 ;Allocation vector for drive B alv2 ds 75 ;Allocation vector for drive C alv3 ds 75 ;Allocation vector for drive D csv0 ds 64 ;Directory check vector for drive A csv1 ds 64 ;Directory check vector for drive B csv2 ds 64 ;Directory check vector for drive C csv3 ds 64 ;Directory check vector for drive D dirbuf ds 128 ;Directory buffer END************************************ * * * Firmware for Disk Jockey Model B. * * * ***************************************************************** title '*** Disk Jockey Model B Firmware ***' origin equ 0E000H org origin 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 INTRQ EQU 4 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 JREADY 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 JHOME TRKSET JMP SEEK JSECT JMP SECSET JDMA JMP DMA DREAD JMP JREAD 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 66Q 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