▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ░▒▓█ rapid1337.com █▓▒░ ╓──────────────────────────────────────────╖ ║ Sting’s HARDWARE TRACKLOADER ║ ╟──────────────────────────────────────────╢ ║ / ║ ╟──────────────────────────────────────────╢ ║·· code/stings-hardware-trackloader.html ·║ ╙──────────────────────────────────────────╜ ============================================================================ Title ..: Sting’s HARDWARE TRACKLOADER Author .: staff Date ...: 2007-08-13 Section : Code ============================================================================ ``` *************************************************************************** * / * * _____.__ _ .___. * * / /_____________. _________.__________.________ | |________ * * ___/____ / ____|_/ | /| \\| ._ / * * \\ \\/ \\ \\ \\ / | :___/?| \\ \\ |/ / * * \\_____________\\___/_____/___/_____|____| |____|\\_____________/ * * -========================/===========|______\\================- * * * * .---.----(*( HARDWARE TRACKLOADER )*)---.---. * * `-./ \\.-' * * (c)oded by StingRay * * -------------------- * * August 2007 * * * * SPECIAL "PLEASE NEW ZEALAND'S BEST" RELEASE * * * *************************************************************************** ; 10/11/12-Aug-2007 ; ; thanks to Cr?xshadows, :Wumpscut:, Das Ich, Funker Vogt, [:SITD:], ; God Module, Suicide Commando, etc. for music while coding this :) *************************************************** *** HISTORY *** *************************************************** ; 16-Aug-2007 - special "please New Zealand's best" release ; - checksum checks added, increases loadersize to 530 ; bytes, it's off by default, enable it by setting ; LD_CHECKSUM to 1 ; - according to New Zealand's best, this loader is ; "extremely limited and buggy". So better use ; a loader coded by New Zealand's best. Good luck ; finding one. ;) If you should find one, better check ; the size of the mfm buffer in that very loader then ; as New Zealand's best has quite a complicated and ; very special approach to calculate mfm buffer ; sizes. At least it's too complicated for me because ; I can't see that my MFM buffer size is too small but ; if New Zealand's best says it is, then it is! ; 13-Aug-2007 - due to a bug the fast "step to next track" routine ; is gone (happened when the loader was called multiple ; times), using LD_StepToTrack again, loader is 30 ; bytes smaller now and works reliable as added bonus :) ; - optimized the size a bit more, LD_CURRENTRACK is now ; d5, loadersize is 494 bytes now :) ; - boundary check in the mfm decoder improved, if ; end is reached, it simply exits, no need to decode ; another sector then :) ; - current loadersize (safety off): 494 bytes ; - quick and dirty bugfix, loader didn't work correctly ; if # of bytes to skip was >512bytes, for now this ; quickfix should do (uses 512*11 bytes memory, guess why), ; might do a better fix later ; 12-Aug-2007 - missing cia timers implemented ; - rasterline timing removed as it's not easy ; to implement without a lot of changes due to the ; way current cia timing is implemented, doesn't ; matter anway as there are 4 selectable CIA timers, ; should be more than adequate ; - instead of using LD_StepToTrack a much simpler ; and faster routine is used to step to the next ; track now, increases loadersize but also the speed :) ; - forgot to set error code in LD_DriveReady, wrong ; error returned if the drive actually DID clear the ; DSKRDY bit :) ; - fixed timeout in LD_LoadTrack, apparently 5ms was ; way too short, timeout value is now 20*50=1000 ms=1sec ; - added LD_SAFETY, if enabled some error checks are ; performed ; - doesn't trash any bytes (max. 3) at the end of the buffer ; anymore ; - offset logic fixed, everything seems to work fine now ; - size optimized LD_DriveOn and LD_StepToTrack ; - some hours later: should work with start offsets ; that are not a multiple of 4 now, slows down mfm decoding ; quite a bit because of the needed checks and writing ; bytes only instead of longs, could be made faster ; with special case code but that would enlarge the loader ; and it's big enough already (558 bytes), at least ; there should be no memory trashing at all anymore and ; it should work with all offsets/lengths ; - some minutes later: 'FUCK IT' I say! :) Got sick of that ; fucked up innerloop, I now use the MFM buffer as ; temporary buffer and copy it afterwards to the real ; address, a lot faster, a lot shorter and only uses ; 512 bytes more memory :) ; 11-Aug-2007 - added the loader part ; - some bugfixes and size optimizing ; - first working version ; - offset logic wrong, trashes 2 bytes ; - drive check improved, split into 2 different ; routines now (LD_DriveOn, LD_DriveReady) ; after the 500ms timer is expired, a read attempt ; is performed to check if the drive is available/ready ; - added timeout check in LD_LoadTrack, if no IRQ signal ; is received within 5ms an error is returned, according ; to the HW manual, max. time needed to get to the ; next track is 3ms so 5ms is more than enough time ; - split the timer routines in LD_StartTimer, ; LD_CheckTimer and LD_WaitTimer ; 10-Aug-2007 - started coding ; - cia timers, step to track, selectable drives, ; no actual loading/mfm decoding yet IF 0 ; example code, change 0 to 1 to assemble it SECTION CODE,CODE_c TEST move.w #$4000,$dff09a lea BUFFER,a0 ; destination lea MFM,a1 ; mfm buffer moveq #0,d0 ; start offset in bytes move.l #100000,d1 ; length in bytes moveq #1,d2 ; drive to use jsr LOADER lea BUFFER,a0 ; destination ;lea MFM,a1 ; mfm buffer move.l #80*11*512,d0 ; start offset in bytes move.l #200000,d1 ; length in bytes moveq #1,d2 ; drive to use jsr LOADER lea BUFFER,a0 ; destination ;lea MFM,a1 ; mfm buffer move.l #40*11*512,d0 ; start offset in bytes move.l #200000,d1 ; length in bytes moveq #1,d2 ; drive to use jsr LOADER move.w #$c000,$dff09a rts BUFFER dcb.l 200000/4,"STR!" dcb.l 1024/4,"STR!" MFM dcb.l $2400/2,"MFM!" MFMEND dcb.l $2400/2,"END!" ENDC ; internal constants, don't touch LD_TIME3MS = 2148 ; 3000/1.3968255 LD_TIME5MS = 3580 ; 5000/1.3968255, LD_TIME18MS = 12886 ; 18000/1.3968255, after reversing dir LD_NODRIVE = 1 ; drive not accessible LD_READERROR = 2 ; timeout while reading track LD_OUTOFBOUNDS = 3 ; requested offset/length out of bounds LD_CRCERROR = 4 ; checksum error LD_CIAA_A = 1 ; cia a, timer a LD_CIAA_B = 2 ; cia a, timer b LD_CIAB_A = 3 ; cia b, timer a LD_CIAB_B = 4 ; cia b, timer b ; these are the ONLY user changeable settings LD_USECIA = LD_CIAB_A ; which timer to use, look above LD_SAFETY = 0 ; set to 1 for more safety, e.g boundary ; checking, increases loadersize LD_CHECKSUM = 0 ; set to 1 to enable checksum check ******************************************* *** TRACKLOADER *** ******************************************* ; a0.l: load address ; a1.l: mfm buffer (only once, $2400 words) ; d0.l: offset (bytes, 0-160*11*512) ; d1.l: size (bytes, 0-160*11*512) ; d2.w: drive (0-3) ;------ ; d0.l: error code (0 = no error) LOADER movem.l d1-a6,-(a7) lea $dff000,a6 lea $bfd100,a5 lea LD_VARS(pc),a4 tst.l LD_MFM(a4) ; mfm buffer already set? bne.b .mfmok move.l a1,LD_MFM(a4) .mfmok IFNE LD_SAFETY move.l d1,d4 sub.l d0,d4 cmp.l #160*11*512,d4 ble.b .ok moveq #LD_OUTOFBOUNDS,d0 bra.b .error ENDC .ok lea (a0,d1.l),a3 ; end of buffer move.l d0,d4 divu.w #512*11,d4 move.w d4,d5 ; LD_CURRENTTRACK(a4) swap d4 ; number of bytes to skip addq.b #3,d2 bsr.b LD_DriveOn ; select drive bsr.b LD_DriveReady ; selected drive ready? tst.l d0 beq.b .driveok moveq #LD_NODRIVE,d0 ; return correct errorcode :) bra.b .exit .driveok .loop bsr.b LD_StepToTrack ; move stepper motor to start track bsr.w LD_LoadTrack ; load and decode track tst.l d0 ; error? bne.b .exit bsr.w LD_DecodeTrack IFNE LD_CHECKSUM tst.l d0 bne.b .exit ENDC addq.w #1,d5 cmp.l a0,a3 bhi.b .loop moveq #0,d0 ; no error .exit bsr.b LD_DriveOff ; switch off drive .error movem.l (a7)+,d1-a6 rts ******************************************* *** DRIVE HANDLING ROUTINES *** ******************************************* ; d2.b: drive LD_DriveOn moveq #$7d,d1 ; deselect all drives bra.b LD_DriveSet ; d2.b: drive LD_DriveOff moveq #-3,d1 ; move.b #$fd,d1 LD_DriveSet move.b d1,(a5) bclr d2,d1 move.b d1,(a5) rts ; waits for DSKRDY bit to go low or a 500ms timer to expire ; after that, a read attempt is performed to check if the ; drive is available ; ; required because there are drives (f.e. some external drives, ; hello Mr.Spiv :D or the crappy drives in the Escom Amigas ; without the floppy fix (which btw is also a shitload of ; crap because it never switches off the drive motor!)) ; that don't ever clear the DSKREADY bit LD_DriveReady moveq #10-1,d7 .loop move.w #LD_TIME5MS*10,d0 ; 50 ms bsr.b LD_StartTimer .check btst #5,$bfe001-$bfd100(a5) beq.b .motorok bsr.b LD_CheckTimer beq.b .check dbf d7,.loop ; 10*50ms ; no DSKREADY signal within 500ms, try to read a track ; to check if drive is ready bra.w LD_LoadTrack .motorok moveq #0,d0 ; no error rts ******************************************* *** TIMER ROUTINES *** ******************************************* IFEQ LD_USECIA-1 ; CIA A, TIMER A ; d0.w: time in ms LD_StartTimer move.b #1$bfee01-$bfd100(a5) ; set one-shot mode move.b d0,$bfe401-$bfd100(a5) ; set timerA low byte lsr.w #8,d0 move.b d0,$bfe501-$bfd100(a5) ; set timerA high byte and start timer rts ; returns timer status (z-flag set: timer still running) LD_CheckTimer btst #0,$bfed01-$bfd100(a5) ; wait for timerA interrupt rts ELSE IFEQ LD_USECIA-2 ; CIA A, TIMER B ; d0.w: time in ms LD_StartTimer move.b #1$bfef01-$bfd100(a5) ; set one-shot mode move.b d0,$bfe601-$bfd100(a5) ; set timerB low byte lsr.w #8,d0 move.b d0,$bfe701-$bfd100(a5) ; set timerB high byte and start timer rts ; returns timer status (z-flag set: timer still running) LD_CheckTimer btst #1,$bfed01-$bfd100(a5) ; wait for timerB interrupt rts ELSE IFEQ LD_USECIA-3 ; CIA B, TIMER A ; d0.w: time in ms LD_StartTimer move.b #1$e00-$100(a5) ; set one-shot mode move.b d0,$400-$100(a5) ; set timerA low byte lsr.w #8,d0 move.b d0,$500-$100(a5) ; set timerA high byte and start timer rts ; returns timer status (z-flag set: timer still running) LD_CheckTimer btst #0,$d00-$100(a5) ; wait for timerA interrupt rts ELSE IFEQ LD_USECIA-4 ; CIA B, TIMER B ; d0.w: time in ms LD_StartTimer move.b #1$f00-$100(a5) ; set one-shot mode move.b d0,$600-$100(a5) ; set timerB low byte lsr.w #8,d0 move.b d0,$700-$100(a5) ; set timerB high byte and start timer rts ; returns timer status (z-flag set: timer still running) LD_CheckTimer btst #1,$d00-$100(a5) ; wait for timerB interrupt rts ENDC ENDC ENDC ENDC ; simply waits for the timer to expire LD_WaitTimer .wait bsr.b LD_CheckTimer beq.b .wait rts LD_Wait18ms move.w #LD_TIME18MS,d0 LD_Timer bsr.b LD_StartTimer bra.b LD_WaitTimer ******************************************* *** STEP TO ACTUAL TRACK *** ******************************************* LD_StepToTrack tst.b LD_INITFLAG(a4) bne.b .noinit bsr.b LD_MoveToTrack0 ; move to track 0 for orientation st LD_INITFLAG(a4) .noinit bclr #1,(a5) ; default direction = inwards bset #2,(a5) ; default side: 0 move.w LD_LASTTRACK(a4),d0 move.w d5,d1 lsr.w #1,d0 ; /2 because we have 2 sides/track lsr.w #1,d1 bcc.b .sideok bclr #2,(a5) ; odd track, side is 1 .sideok sub.w d0,d1 beq.b .exit ; already at correct track bgt.b .step neg.w d1 ; we need positive loopcounter bset #1,(a5) ; direction = outwards .step bsr.b LD_Step subq.w #1,d1 bne.b .step move.w d5,LD_LASTTRACK(a4) .exit rts LD_MoveToTrack0 .loop btst #4,$e001-$d100(a5) ; already on track0? beq.b .ok ; yes, nothing to do bset #1,(a5) ; direction = outwards bsr.b LD_Step ; step one track bra.b .loop .ok clr.w LD_LASTTRACK(a4) rts LD_Step bclr #0,(a5) ; set step signal bset #0,(a5) ; clear step signal bra.b LD_Wait18ms ; wait for steppermotor to finish ******************************************* *** LOAD AND DECODE ONE TRACK *** ******************************************* ; a0: destination ; a3: end of buffer ; d4: offset ;---- ; d0: error code (0: no error) ; split into 2 parts because of the drive check LD_LoadTrack move.w #1$96(a6) ; enable disk dma move.w #~(1$ff00,$9e(a6) ; clear adkcon (just to be sure) ; set fastmode (mfm), wordsync, mfmprec, no precomp move.w #1$9e(a6) move.w #$4000,$24(a6) move.w #$4489,$7e(a6) move.w #1$9c(a6) ; clear disk irq move.l LD_MFM(a4),a1 move.l a1,$20(a6) move.w #1$1900,$24(a6) move.w #1$1900,$24(a6) bsr.b .timer moveq #20,d3 ; 1s, should be more than enough .waitDMA move.w $1e(a6),d1 btst #1,d1 bne.b .done bsr.w LD_CheckTimer beq.b .waitDMA bsr.b .timer ; reload timer subq.w #1,d3 bne.b .waitDMA moveq #LD_READERROR,d0 ; timeout! bra.b .error .done moveq #0,d0 ; no error .error move.w #$4000,$24(a6) move.w #1$96(a6) ; disable disk dma rts .timer move.w #LD_TIME5MS*10,d0 ; 50ms bra.w LD_StartTimer ; decode mfm ; a0: destination ; a1: mfm buffer ; a3: end of buffer ; d4: offset LD_DecodeTrack IFNE LD_CHECKSUM movem.l d2/d5/a5,-(a7) ; save ELSE move.l a5,-(a7) ENDC lea $1900*2(a1),a5 ; temp move.l #$55555555,d3 moveq #0,d7 .secloop move.l a1,a2 .getsync cmp.w #$4489,(a2)+ bne.b .getsync cmp.w #$4489,(a2) beq.b .getsync ; get info data movem.l (a2),d0/d1 bsr.b .decode lsr.w #8,d0 ; d0: sector number cmp.w d0,d7 ; are we on the correct sector? beq.b .sectorok lea $440-8(a2),a2 bra.b .getsync .sectorok ; calc checksum IFNE LD_CHECKSUM movem.l $38-8(a2),d0/d1 bsr.b .decode move.l d0,d5 ; save moveq #0,d2 ; checksum for this sector ENDC lea $40-8(a2),a2 ; point to data moveq #512/4-1,d6 .loop move.l 512(a2),d1 ; data (even) move.l (a2)+,d0 ; data (odd) IFNE LD_CHECKSUM eor.l d0,d2 eor.l d1,d2 ENDC bsr.b .decode move.l d0,(a5)+ dbf d6,.loop IFNE LD_CHECKSUM moveq #LD_CRCERROR,d0 and.l d3,d2 cmp.l d2,d5 bne.b .crcerror ENDC addq.w #1,d7 cmp.w #11,d7 blt.b .secloop lea $1900*2(a1),a5 add.w d4,a5 move.w #512*11,d0 sub.w d4,d0 ; # of bytes to copy .copy cmp.l a3,a0 bge.b .exit move.b (a5)+,(a0)+ subq.w #1,d0 bne.b .copy moveq #0,d4 ; next track starts at the beginning .exit IFNE LD_CHECKSUM moveq #0,d0 ; no errors ENDC .crcerror IFNE LD_CHECKSUM movem.l (a7)+,d2/d5/a5 ELSE move.l (a7)+,a5 ENDC rts .decode and.l d3,d0 and.l d3,d1 add.l d0,d0 ; $ff: init done rs.b 1 ; padding LD_VARS_SIZEOF rs.b 0 dcb.b LD_VARS_SIZEOF PRINTT PRINTT "LOADERSIZE:" PRINTV *-LOADER PRINTT ``` ---------------------------------------------------------------------------- -- rapid1337.com -- The dumping ground for all things tech // knowledge is the weapon --