*-----------------------* * Hardware Trackloader * * MFM * * MultiDrive (testdisk) * * cia timer delay * *-----------------------* ;----------------------------------------- Offsets Custom Chip Registers INTENAR = $DFF01C DMACON = $DFF096 dmaconr = $dff002 INTENA = $DFF09A INTREQ = $DFF09C ; bits CIAA-PRA --------------------------- bits signification DSKRDY = 5 ; drive pret DSKTRK0 = 4 ; piste 0 atteinte DSKPROT = 3 ; disk protege en ecriture DSKCHNG = 2 ; disk change ; bits CIAB-PRB --------------------------- DSKMTR = 7 ; control moteur DSKSEL3 = 6 ; select DF3 DSKSEL2 = 5 ; DF2 DSKSEL1 = 4 ; DF1 DSKSEL0 = 3 ; DF0 DSKSIDE = 2 ; select face DSKDIR = 1 ; direction DSKSTEP = 0 ; deplacement d'une piste * ------------------------------------ offset dmacon D_init=$8200 D_priB=$400 D_Btpl=$100 D_Copp=$80 D_Blit=$40 D_sprt=$20 D_disk=$10 D_CON=D_init|D_copp|D_disk|D_Blit MFMBUF=12*512+256 MOTOR=0 ; 0=off / 1=on section "trackloader",code rsreset head rs.w 1 ; (tete 0-1) track rs.w 1 ; (piste 0-79) essais rs.w 1 Drives rs.w 4 flag rs.w 4 numdrive rs.b 2 VARSIZE rs.w 0 Start: bsr InitLoader move.w #1,d1 ; start track move.w #6,d7 ; nb tracks lea Buffer,a0 bsr Loader rts * --------------------------------------------------------- * * - HARDWARE TRACKLOADER MFM - * * --------------------------------------------------------- * InitLoader lea Vars(pc),a5 lea $dff000,a6 lea $bfe001,a4 ; $bfe001 en A4 lea $bfd100,a3 ; $bfd100 en A3 bsr TestDrive move.b #$00,$500(a3) ; timer B lo move.b #$0d,$600(a3) ; hi clr.b $e00(a3) ; crb lea Drives(a5),a1 addq.l #8,a1 moveq #3,d7 .loop tst.w -(a1) beq.s .pasdrive move.b d7,numdrive(a5) bsr driveon bsr.s Seek0 bsr stopdrive0 .pasdrive dbf d7,.loop rts * ----------------------------------------------------- * d1 = start track to read * d7 = nb track to read * a0 = load at this address Loader: lea Vars(pc),a5 lea $dff000,a6 lea $bfe001,a4 ; $bfe001 en A4 lea $bfd100,a3 ; $bfd100 en A3 subq.w #1,d7 bsr.s drive0 bsr.s readalldisk ifeq MOTOR bsr stopdrive0 endc ;bsr CACHECLR rts * ----------------------------------------------------- TRKZERO: move.l #0,head(a5) move.w #0,essais(a5) bsr.s drive0 Seek0 btst #DSKTRK0,(a4) beq.s .track0 bsr moveheads bra.s Seek0 .track0 rts ;------------------------------------------------ readalldisk: ; boucle de lecture de chaque piste bsr.s waitd move.w d1,d0 ; numero piste bsr readthistrack bne.s .erreur addq.w #1,d1 ; piste suivante lea $1600(a0),a0 dbf d7,readalldisk rts .erreur move.w #$0f0,$dff180 rts ; bra.s .erreur ;------------------------------------------------ drive0: MOVE.W #$8210,$96(a6) move.b numdrive(a5),d0 addq.b #3,d0 move.b #$7f,d2 bclr d0,d2 move.b #$7d,(a3) move.b d2,(a3) btst #DSKCHNG,(a4) beq.s TestDisk bsr.s waitd rts * ------------------------------------------------- Driveon: move.w #$8210,$96(a6) move.b numdrive(a5),d0 addq.b #3,d0 move.b #$7f,d2 bclr d0,d2 move.b #$7d,(a3) move.b d2,(a3) rts * ------------------------------------------------- stopdrive0: move.b numdrive(a5),d0 addq.b #3,d0 move.b #$fd,d2 bclr d0,d2 move.b #$fd,(a3) move.b d2,(a3) st (a3) move.w #$10,$96(a6) rts * -------------------------------------------------- waitd: btst #DSKRDY,(a4) bne.s waitd rts * --------------------------------------------------- TestDisk: movem.l d0-d2/d7/a1/a2,-(sp) bsr.s stopdrive0 RTestD lea Drives(a5),a1 lea Flag(a5),a2 addq.l #8,a1 addq.l #8,a2 moveq #3,d7 TestD tst.w -(a1) beq.s .pasdrive move.b d7,numdrive(a5) bsr.s driveon bchg #0,(a2) beq.s .SeekIt bclr #DSKDIR,(a3) ; Vers le sillon 79 (interieur) bra.s .SeekIt .SeekForw bset #DSKDIR,(a3) .SeekIt bsr MoveHeads btst #DSKCHNG,(a4) bne.s .Ok bsr.s stopdrive0 move.l #200,d2 .loop move.l $dff004,d0 vbl lsr.l #8,d0 andi.w #%111111111,d0 cmpi.w #255,d0 bne.s .loop subq.l #1,d2 bpl.s .loop .pasdrive lea -2(a2),a2 dbf d7,TestD bra.s RTestD .Ok ;move.w #0,flag(a5) bsr TRKZERO movem.l (sp)+,d0-d2/d7/a1/a2 rts * ------------------------------------------------------- ; Lecture de la piste D0 dans le buffer pointé par A0. ; Cette routine recherche la bonne piste (Seek), la lit ; et décode les données MFM. ReadThisTrack: movem.l a0-a6/d1-d5,-(sp) lea Vars(pc),a5 ; a5 = variables "locales" clr.w essais(a5) bsr SeekThisTrack ; recherche la piste à lire .Retry lea $dff000,a6 move.w #$4000,$24(a6) ; efface DSKLEN move.l #AdBuf,$20(a6) ; Adresse de lecture move.w #$4489,$7e(a6) ; Synchro MFM standard move.w #$7f00,$9e(a6) ; Efface ADKCON move.w #$9500,$9e(a6) ; Valeur correcte dans ADKCON move.w #$9900,$24(a6) ; Longueur de lecture (mots) move.w #$9900,$24(a6) ; écrite 2 fois move.w #2,$9c(a6) .Wait btst #1,$1f(a6) beq.s .Wait ; Pas encore move.w #$0,$24(a6) ; Efface DSKLEN bsr.s MFMUncode ; Décodage des données MFM beq.s .ReadOk .Error addq.w #1,essais(a5) andi.w #3,essais(a5) bne.s .Retry moveq #-1,d0 ; erreur de lecture ! .ReadOk movem.l (sp)+,a0-a6/d1-d5 rts ; ----------------------------------------------------------- ; Cette routine décode les données MFM de MFMBUF (1 piste) ; dans le buffer pointé par A0. ; Retourne 0 si OK, -1 si erreur MFMUncode: move.l Adbuf(a5),a1 ; données MFM move.l #$55555555,d2 ; masque bits impairs moveq #10,d5 ; 11 secteurs à décoder .GAP cmpi.w #$4489,(a1)+ ; cherche le début du secteur bne.s .GAP cmpi.w #$4489,(a1) beq.s .GAP move.l (a1)+,d0 and.l d2,d0 lsl.l #1,d0 move.l (a1)+,d1 and.l d2,d1 or.l d1,d0 ; d0=format,track,sector,count add.w d0,d0 andi.w #$1E00,d0 lea 0(a0,d0.w),a2 ; a2=secteur dans le track-buffer lea 36(a1),a1 ; saute les infos DOS et le header checksum move.l (a1)+,d0 ; d0=data checksum. a1=données moveq #9,d3 ; 10 mots longs à vérifier lea -48(a1),a3 ; a3 pointe le header (OS recovery info) .Check move.l (a3)+,d1 eor.l d1,d0 dbra d3,.Check and.l d2,d0 bne.s .ReadError addq.l #4,a1 move.l (a1)+,d3 ; d3=data area checksum lea 512(a1),a4 ; a1=oddbits, a4=evenbits moveq #127,d4 ; 128 mots de données à décoder .UncodeSector: move.l (a1)+,d0 eor.l d0,d3 and.l d2,d0 lsl.l #1,d0 move.l (a4)+,d1 eor.l d1,d3 and.l d2,d1 or.l d1,d0 move.l d0,(a2)+ dbra d4,.UncodeSector and.l d2,d3 bne.s .ReadError dbra d5,.GAP moveq #0,d0 rts .ReadError: moveq #-1,d0 rts ; -------------------------------------------------------- ; Positionne les têtes de lecture/écriture au dessus ; de la piste désignée par D0. SeekThisTrack: moveq #1,d2 bset #DSKSIDE,(a3) ; face 0 clr.w head(a5) lsr.w #1,d0 bcc.s .LowerSide bclr #DSKSIDE,(a3) ; face 1 addq.w #1,head(a5) .LowerSide: move.w d0,d1 sub.w track(a5),d0 ; Dans quelle direction aller ? beq.s .SeekOk ; Ben.. Nulle part, on y est déjà ! bpl.s .SeekForward ; Vers le sillon 79 (centre) .SeekBackward: bset #DSKDIR,(a3) ; Vers le sillon 0 (extérieur) neg.w d2 bra.s .SeekIt .SeekForward: bclr #DSKDIR,(a3) .SeekIt bsr.s MoveHeads ; Déplace les têtes d'1 piste add.w d2,track(a5) ; Inc/Dec le compteur de pistes cmp.w track(a5),d1 ; Piste demandée atteinte ? bne.s .SeekIt ; pas encore... .SeekOk rts ; ------------------------------------------ ; Fournit l'impulsion STEP au drive ; suivie du nécessaire délai timer MoveHeads: bset #DSKSTEP,(a3) ; step = high nop nop bclr #DSKSTEP,(a3) ; step = low nop nop bset #DSKSTEP,(a3) ; step = high ; ------------------------------------------------ ; Délai logiciel... !!!! ABSOLUMENT INTERDIT !!!! ; CIA TIMER DELAY ; ------------------------------------------------ timer delay move.b #$19,$e00(a3) $bfdf00 nop nop delay: btst.b #0,$e00(a3) bne.s delay rts ; datas VARS ds.b VARSIZE even ; buffer mfm section b,bss_c Adbuf ds.w MFMBUF section buf,bss_c Buffer