***************************************************************** * * * CP/M-68K BIOS * * Basic Input/Output Subsystem * * For ERG 68000 with Tarbell floppy disk controller * * * ***************************************************************** .globl _init * bios initialization entry point .globl _ccp * ccp entry point _init: move.l #traphndl,$8c * set up trap #3 handler clr.l d0 * log on disk A, user 0 rts traphndl: cmpi #nfuncs,d0 bcc trapng lsl #2,d0 * multiply bios function by 4 movea.l 6(pc,d0),a0 * get handler address jsr (a0) * call handler trapng: rte biosbase: .dc.l _init .dc.l wboot .dc.l constat .dc.l conin .dc.l conout .dc.l lstout .dc.l pun .dc.l rdr .dc.l home .dc.l seldsk .dc.l settrk .dc.l setsec .dc.l setdma .dc.l read .dc.l write .dc.l listst .dc.l sectran .dc.l setdma .dc.l getseg .dc.l getiob .dc.l setiob .dc.l flush .dc.l setexc nfuncs=(*-biosbase)/4 wboot: jmp _ccp constat: move.b $ffff01,d0 * get status byte andi.w #2,d0 * data available bit on? beq noton * branch if not moveq.l #$1,d0 * set result to true rts noton: clr.l d0 * set result to false rts conin: bsr constat * see if key pressed tst d0 beq conin * wait until key pressed move.b $ffff00,d0 * get key and.l #$7f,d0 * clear all but low 7 bits cmpi.b #1,d0 beq break rts break: trap $f .dc.w 0 * return to MACSBUG rts conout: move.b $ffff01,d0 * get status and.b #$1,d0 * check for transmitter buffer empty beq conout * wait until our port has aged... move.b d1,$ffff00 * and output it rts * and exit lstout: rts pun: rts rdr: rts listst: move.b #$ff,d0 rts * * Disk Handlers for Tarbell 1793 floppy disk controller * maxdsk = 2 * this BIOS supports 2 floppy drives dphlen = 26 * length of disk parameter header iobase = $00fffff8 * Tarbell floppy disk port base address dcmd = iobase * output port for command dstat = iobase * input status port dtrk = iobase+1 * disk track port dsect = iobase+2 * disk sector port ddata = iobase+3 * disk data port dwait = iobase+4 * input port to wait for op finished dcntrl = iobase+4 * output control port for drive selection home: clr.b track rts seldsk: * select disk given by register d1.b moveq #0,d0 cmp.b #maxdsk,d1 * valid drive number? bpl selrtn * if no, return 0 in d0 move.b d1,seldrv * else, save drive number lsl.b #4,d1 move.b d1,selcode * select code is 00 for drv 0, $10 for drv 1 move.b seldrv,d0 mulu #dphlen,d0 add.l #dph0,d0 * point d0 at correct dph selrtn: rts settrk: move.b d1,track rts setsec: move.b d1,sector rts sectran: * translate sector in d1 with translate table pointed to by d2 * result in d0 movea.l d2,a0 ext.l d1 move.b #0(a0,d1),d0 ext.l d0 rts setdma: move.l d1,dma rts read: * Read one sector from requested disk, track, sector to dma address * Retry if necessary, return in d0 00 if ok, else non-zero move.b #10,errcnt * set up retry counter rretry: bsr setup ori #$88,d3 * OR read command with head load bit move.b d3,dcmd * output it to FDC rloop: btst #7,dwait beq rdone * if end of read, exit move.b ddata,(a0)+ * else, move next byte of data bra rloop rdone: bsr rstatus * get FDC status bne rerror clr.l d0 rts rerror: bsr errchk * go to error handler subq.b #1,errcnt bne rretry move.l #$ffffffff,d0 rts write: * Write one sector to requested disk, track, sector from dma address * Retry if necessary, return in d0 00 if ok, else non-zero move.b #10,errcnt * set up retry counter wretry: bsr setup ori #$a8,d3 * OR write command with head load bit move.b d3,dcmd * output it to FDC wloop: btst #7,dwait beq wdone * if end of read, exit move.b (a0)+,ddata * else, move next byte of data bra wloop wdone: bsr rstatus * get FDC status bne werror clr.l d0 rts werror: bsr errchk * go to error handler subq.b #1,errcnt bne wretry move.l #$ffffffff,d0 rts setup: * common read and write setup code * select disk, set track, set sector were all deferred until now move.b #$d0,dcmd * clear controller, get status move.b curdrv,d3 cmp.b seldrv,d3 bne newdrive * if drive not selected, do it move.b track,d3 cmp.b oldtrk,d3 bne newtrk * if not on right track, do it clr.l d3 * if head already loaded, no head load delay btst #5,dstat * if head unloaded, treat as new disk bne sexit newdrive: move.b selcode,dcntrl * select the drive move.b seldrv,curdrv newtrk: bsr chkseek * seek to correct track if required moveq #4,d3 * force head load delay sexit: move.b sector,dsect * set up sector number move.b track,dtrk * set up track number move.l dma,a0 * dma address to a0 rts errchk: btst.b #4,d7 bne chkseek * if record not found error, reseek rts chkseek: * check for correct track, seek if necessary bsr readid * find out what track we're on beq chks1 * if read id ok, skip restore code restore: * home the drive and reseek to correct track move.b #$0B,dcmd * restore command to command port rstwait: btst #7,dwait bne rstwait * loop until restore completed btst #2,dstat beq restore * if not at track 0, try again clr.l d3 * track number returned in d3 from readid chks1: move.b d3,dtrk * update track register in FDC move.b track,oldtrk * update oldtrk cmp.b track,d3 * are we at right track? beq chkdone * if yes, exit move.b track,ddata * else, put desired track in data reg of FDC move.b #$18,dcmd * and issue a seek command chks2: btst #7,dwait bne chks2 * loop until seek complete move.b dstat,d3 * read status to clear FDC chkdone: rts readid: * read track id, return track number in d3 move.b #$c4,dcmd * issue read id command move.b dwait,d7 * wait for intrq move.b ddata,d3 * track byte to d3 rid2: btst #7,dwait beq rstatus * wait for intrq move.b ddata,d7 * read another byte bra rid2 * and loop rstatus: move.b dstat,d7 andi.b #$9d,d7 * set condition codes rts flush: clr.l d0 * return successful rts getseg: move.l #memrgn,d0 * return address of mem region table rts getiob: rts setiob: rts setexc: andi.l #$ff,d1 * do only for exceptions 0 - 255 cmpi #47,d1 beq noset * this BIOS doesn't set Trap 15 cmpi #9,d1 * or Trace beq noset 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 noset: rts .data seldrv: .dc.b $ff * drive requested by seldsk curdrv: .dc.b $ff * currently selected drive track: .dc.b 0 * track requested by settrk oldtrk: .dc.b 0 * track we were on sector: .dc.w 0 dma: .dc.l 0 selcode: .dc.b 0 * drive select code errcnt: .dc.b 10 * retry counter memrgn: .dc.w 1 * 1 memory region .dc.l $800 * starts at 800 hex .dc.l $17800 * goes until 18000 hex * disk parameter headers dph0: .dc.l xlt .dc.w 0 * dummy .dc.w 0 .dc.w 0 .dc.l dirbuf * ptr to directory buffer .dc.l dpb * ptr to disk parameter block .dc.l ckv0 * ptr to check vector .dc.l alv0 * ptr to allocation vector dph1: .dc.l xlt .dc.w 0 * dummy .dc.w 0 .dc.w 0 .dc.l dirbuf * ptr to directory buffer .dc.l dpb * ptr to disk parameter block .dc.l ckv1 * ptr to check vector .dc.l alv1 * ptr to allocation vector * disk parameter block dpb: .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 * 64 directory entries .dc.w $c000 * directory mask .dc.w 16 * directory check size .dc.w 2 * track offset * sector translate table xlt: .dc.b 1, 7,13,19 .dc.b 25, 5,11,17 .dc.b 23, 3, 9,15 .dc.b 21, 2, 8,14 .dc.b 20,26, 6,12 .dc.b 18,24, 4,10 .dc.b 16,22 .bss dirbuf: .ds.b 128 * directory buffer ckv0: .ds.b 16 * check vector ckv1: .ds.b 16 alv0: .ds.b 32 * allocation vector alv1: .ds.b 32 .end