************************************************************************* * * * CP/M-68K Loader BIOS * * for CompuPro CPU-68K and Disk 1 floppy disk controller * * by Michael A. Perry * * Double Density * * with full track buffering * * * * last modified 10/14/83 by J. R. Stoner * * * ************************************************************************* syssup = 1 * zero to select the system support console iobase = $ff0000 * base of 68000's memory mapped i/o sio = iobase+$10 * serial i/o data port siostat = sio+1 * serial i/o status port select = sio+7 * Interfacer III or IV user number console = 7 * Interfacer III or IV console user number printer = 4 * Interfacer III or IV printer user number prnter1 = 5 * Interfacer III or IV UL1 user number sysio = iobase+$5c * base port for the system support sysst = sysio+1 * status port for same dstat = iobase+$c0 * disk status port ddata = dstat+1 * disk data port ddma = dstat+2 * disk dma port dpblen = 16 retries = 7 .globl _bios init: nop .ifeq syssup move.b #$ee,sysio+2 * set system support to 9600, 8bit, none move.b #$3e,sysio+2 move.b #$27,sysio+3 .endc .ifne syssup move.b #console,select * initialize the console port move.b #$ee,sio+2 * to 9600 baud, 8 bit, no parity move.b #$3e,sio+2 move.b #$27,sio+3 .endc move.b #printer,select * initialize the LPT port move.b #$ee,sio+2 * to 9600 baud, 8 bit, no parity move.b #$7e,sio+2 move.b #$27,sio+3 move.b #prnter1,select * initialize the UL1 port move.b #$ee,sio+2 * to 9600 baud, 8 bit, no parity move.b #$7e,sio+2 move.b #$27,sio+3 bsr specify * set disk stepping rate rts _bios: cmpi #functions,d0 bge nogood lsl #2,d0 * multiply bios function by 4 movea.l 6(pc,d0),a0 * get handler address jsr (a0) * call handler nogood: rts table: .dc.l init .dc.l nogood .dc.l nogood .dc.l nogood .dc.l conout .dc.l nogood .dc.l nogood .dc.l nogood .dc.l nogood .dc.l seldsk .dc.l settrk .dc.l setsec .dc.l setdma .dc.l read .dc.l nogood .dc.l nogood .dc.l sectran .dc.l nogood .dc.l getseg .dc.l nogood .dc.l nogood .dc.l nogood .dc.l setexc functions=(*-table)/4 .ifne syssup nop * because of the assembler bug conout: move.b #console,select emit: move.b siostat,d0 * get status and.b #$1,d0 * wait for transmitter buffer empty beq emit move.b d1,sio * and output it rts .endc .ifeq syssup nop * because of the assembler bug conout: move.b sysst,d0 and.b #$1,d0 beq conout move.b d1,sysio rts .endc seldsk: * select disk A * return its dph in d0.l move.l #dph0,d0 * point d0 at correct dph * find the density of the disk, and set * its density flag, dpb and xlt to the new values move.l d0,a3 * save dph address bsr restore * home new disk move.b #1,d6 bsr seek * seek track one (zero is single dens.) bsr rid * get density moveq #0,d7 move.l d7,d3 move stat,d2 bne setd0 * bad status means single density, else move.b stat+6,d3 * get density byte setd0: move.b d3,density * update density bsr sds * get sides move.b d5,sides * update side flag move.l d3,d4 * d3 and d4 have density (0..3) mulu #dpblen*2,d3 tst.b d5 beq setd1 add #dpblen,d3 * double sided setd1: add.l #dpb0,d3 * point d3 at selected dpb mulu #4,d4 add.l #xlts,d4 move.l d4,a1 * point a1 into table of translation tables move.l (a1),(a3) * update xlt move.l d3,14(a3) * update dpb move.l a3,d0 * restore dph to d0 rts settrk: * set track number to value in d1 move.w d1,cpmtrk rts setsec: * set logical sector number to value in d1 move.b d1,cpmsec rts sectran: * translate sector in d1 using translation table pointed to by d2 * return result in d0 move.l d2,a0 ext.l d1 move.b #0(a0,d1),d0 ext.l d0 rts setdma: * set data address to value in d1 move.l d1,cpmdma rts send: * send byte in d4 to disk controller btst #7,dstat beq send move.b d4,ddata rts results: * read all result bytes from disk controller lea stat,a0 res1: btst #7,dstat beq res1 btst #6,dstat beq resx move.b ddata,(a0)+ bra res1 resx: rts specify: * set disk stepping rate and head load time moveq #3,d4 bsr send .ifeq syssup moveq #$df,d4 * 3ms/step .endc .ifne syssup moveq #$8f,d4 .endc bsr send moveq #$46,d4 * 70ms head load bsr send rts waitint: * wait until Disk 1 interrupt flag becomes true btst #7,ddma beq waitint rts sis: * Sense Interrupt Status: must be used after seek or home bsr waitint moveq #8,d4 bsr send bsr results * read all result bytes move.b stat,d4 * status for correct drive? cmpi.b #$20,d4 * successful seek? rts restore: * home the disk moveq #2,d2 * 3 retries rest1: moveq #$7,d4 bsr send move.b #0,d4 bsr send bsr sis * get status dbeq d2,rest1 * retry on error rts seek: * position the disk head to the track in d6.b moveq #2,d2 * 3 retries seek1: moveq #$0f,d4 bsr send move.b #0,d4 bsr send move.b d6,d4 * track number bsr send bsr sis * get status dbeq d2,seek1 * retry on error beq seekx * exit if ok bsr restore * home disk if fatal seekx: rts sds: * Sense Drive Status * tests for double sided move.b #4,d4 bsr send move.b #0,d4 bsr send bsr results move.b stat,d5 and.b #8,d5 * select double sided bit rts rid: * Read ID field: find density move.b #$4a,d4 bsr send move.b #0,d4 bsr send bsr waitint bsr results * read all result bytes rts setcmd: * set up the command buffer for the next read or write moveq #0,d2 move track,d6 beq setcmd1 * force single density on track 0 move.b density,d2 * get density byte beq setcmd1 * if not single density or.b #$40,cmd * then set mfm bit setcmd1: move.l d2,d3 * d2 and d3 have density byte = n mulu #3,d3 * index into gap table add.l #gaps,d3 move.l d3,a1 * point a1 at gpl/dtl entry lea cmd+1,a0 * set up the command buffer move.b side,d5 lsl.b #2,d5 * side is bit 2 of drive byte move.b d5,(a0)+ move.b track+1,(a0)+ * low byte of track number move.b side,(a0)+ * redundant side byte move.b #1,(a0)+ * sector move.b d2,(a0)+ * density byte move.b (a1)+,(a0)+ * eot = spt move.b (a1)+,(a0)+ * gpl move.b (a1)+,(a0)+ * dtl rts command: * set dma address for data transfer lea dma+1,a0 move.b (a0)+,ddma move.b (a0)+,ddma move.b (a0)+,ddma * send 9 bytes from command buffer to disk controller lea cmd,a0 * point a0 at command buffer moveq #8,d3 * send 9 bytes com: move.b (a0)+,d4 bsr send dbra d3,com bsr waitint * wait until done bsr results * read all result bytes rts rdwr: * Common routine to read or write a physical track move.l #buffer,dma * dma transfers are to and from buffer move.w track,d6 * perform a seek to desired track bsr seek bsr setcmd * set up the command buffer moveq #retries,d5 rdwr1: bsr command * issue command move.w stat,d4 * was disk i/o successful? and #$f8ff,d4 * ignore the minor device sub #$4080,d4 * 4080 is status for good read or write beq rdwrok * exit if ok dbra d5,rdwr1 * retry rdwrerr: moveq #1,d0 * return error status rts rdwrok: moveq #0,d0 * return good status rts read: * Read one sector from requested disk, track, sector to dma address * Retry if necessary; return zero in d0 if ok. * make certain that the desired data is in the buffer moveq #0,d0 move.l d0,d6 move.l d0,d5 move cpmtrk,d6 * get logical track clr.b side * default to side zero tst.b sides * if double sided: beq inbuf3 move d6,d5 and #1,d5 * get side number move.b d5,side lsr #1,d6 * get track number inbuf3: move d6,track cmp.b bufsid,d5 bne inbuf1 cmp buftrk,d6 beq inbuf2 * new track, perform read inbuf1: move.b #6,cmd * select read bsr rdwr * perform read bne readx * exit on error move track,buftrk * update buffer track number move.b side,bufsid inbuf2: moveq #0,d2 move.b cpmsec,d2 sub #1,d2 * number from 0 mulu #128,d2 * d2 has offset into buffer add.l #buffer,d2 * d2 has data address move.l cpmdma,a1 * a1 has dma address move.l d2,a0 * a0 points to data moveq #127,d2 mov: move.b (a0)+,(a1)+ dbra d2,mov readx: rts getseg: move.l #region,d0 * return address of memory region table rts setexc: andi.l #$ff,d1 * do only for exceptions 0 - 255 lsl #2,d1 * multiply exception nmbr by 4 movea.l d1,a0 move.l (a0),d0 * return old vector value move.l d2,(a0) * insert new vector rts .data region: .dc.w 1 * one region .dc.l $2000 * start of TPA .dc.l $10000 * length * disk parameter headers .even dph0: .dc.l xlt0 .dc.w 0 * dummy .dc.w 0 .dc.w 0 .dc.l dirbuf * ptr to directory buffer .dc.l dpb0 * ptr to disk parameter block .dc.l 0 * ptr to check vector .dc.l 0 * ptr to allocation vector * disk parameter block dpb0: .dc.w 26 * sectors per track .dc.b 3 * block shift .dc.b 7 * block mask .dc.b 0 * extent mask .dc.b 0 * dummy fill .dc.w 242 * disk size .dc.w 63 * directory entries .dc.w $c000 * directory mask .dc.w 16 * directory check size .dc.w 2 * track offset dpb0d: .dc.w 26 * sectors per track .dc.b 4 * block shift .dc.b 15 * block mask .dc.b 1 * extent mask .dc.b 0 * dummy fill .dc.w 242 * disk size .dc.w 127 * directory entries .dc.w $c000 * directory mask .dc.w 32 * directory check size .dc.w 4 * track offset dpb1: .dc.w 52 * sectors per track .dc.b 4 * block shift .dc.b 15 * block mask .dc.b 0 * extent mask .dc.b 0 * dummy fill .dc.w 242 * disk size .dc.w 127 * directory entries .dc.w $c000 * directory mask .dc.w 32 * directory check size .dc.w 2 * track offset dpb1d: .dc.w 52 * sectors per track .dc.b 4 * block shift .dc.b 15 * block mask .dc.b 0 * extent mask .dc.b 0 * dummy fill .dc.w 485 * disk size .dc.w 255 * directory entries .dc.w $f000 * directory mask .dc.w 64 * directory check size .dc.w 4 * track offset dpb2: .dc.w 60 * sectors per track .dc.b 4 * block shift .dc.b 15 * block mask .dc.b 0 * extent mask .dc.b 0 * dummy fill .dc.w 261 * disk size .dc.w 127 * directory entries .dc.w $c000 * directory mask .dc.w 32 * directory check size .dc.w 2 * track offset dpb2d: .dc.w 60 * sectors per track .dc.b 4 * block shift .dc.b 15 * block mask .dc.b 0 * extent mask .dc.b 0 * dummy fill .dc.w 523 * disk size .dc.w 255 * directory entries .dc.w $f000 * directory mask .dc.w 64 * directory check size .dc.w 4 * track offset dpb3: .dc.w 64 * sectors per track .dc.b 4 * block shift .dc.b 15 * block mask .dc.b 0 * extent mask .dc.b 0 * dummy fill .dc.w 299 * disk size .dc.w 127 * directory entries .dc.w $c000 * directory mask .dc.w 32 * directory check size .dc.w 2 * track offset dpb3d: .dc.w 64 * sectors per track .dc.b 4 * block shift .dc.b 15 * block mask .dc.b 0 * extent mask .dc.b 0 * dummy fill .dc.w 599 * disk size .dc.w 255 * directory entries .dc.w $f000 * directory mask .dc.w 64 * directory check size .dc.w 4 * track offset * sector translation tables xlt0: .dc.b 1,7,13,19,25 .dc.b 5,11,17,23 .dc.b 3,9,15,21 .dc.b 2,8,14,20,26 .dc.b 6,12,18,24 .dc.b 4,10,16,22 xlt1: .dc.b 1,2,19,20,37,38 .dc.b 3,4,21,22,39,40 .dc.b 5,6,23,24,41,42 .dc.b 7,8,25,26,43,44 .dc.b 9,10,27,28,45,46 .dc.b 11,12,29,30,47,48 .dc.b 13,14,31,32,49,50 .dc.b 15,16,33,34,51,52 .dc.b 17,18,35,36 xlt2: .dc.b 1,2,3,4,17,18,19,20,33,34,35,36,49,50,51,52 .dc.b 5,6,7,8,21,22,23,24,37,38,39,40,53,54,55,56 .dc.b 9,10,11,12,25,26,27,28,41,42,43,44,57,58,59,60 .dc.b 13,14,15,16,29,30,31,32,45,46,47,48 xlt3: .dc.b 1,2,3,4,5,6,7,8 .dc.b 25,26,27,28,29,30,31,32 .dc.b 49,50,51,52,53,54,55,56 .dc.b 9,10,11,12,13,14,15,16 .dc.b 33,34,35,36,37,38,39,40 .dc.b 57,58,59,60,61,62,63,64 .dc.b 17,18,19,20,21,22,23,24 .dc.b 41,42,43,44,45,46,47,48 xlts: .dc.l xlt0,xlt1,xlt2,xlt3 gaps: .dc.b 26,$07,$80 .dc.b 26,$0e,$ff .dc.b 15,$1b,$ff .dc.b 08,$35,$ff .bss cmd: .ds.b 10 stat: .ds.b 8 cpmdma: .ds.l 1 dma: .ds.l 1 cpmsec: .ds.b 1 sector: .ds.b 1 cpmtrk: .ds.w 1 buftrk: .ds.w 1 track: .ds.w 1 bufsid .ds.b 1 side: .ds.b 1 sides: .ds.b 1 density: .ds.b 1 * current density .even dirbuf: .ds.b 128 buffer: .ds.b $2000 .end