rapid1337.com

Sting’s HARDWARE TRACKLOADER

2007-08-13 · [ code ] · by staff

             /

<-- All Terrain Racing” (c) 1995 Team 17 | [ Code ]

[ read in diskmag ]



***************************************************************************
*             /                                                           *
*       _____.__ _                                         .___.          *
*      /    /_____________.  _________.__________.________ |   |________  *
*  ___/____      /    ____|_/         |         /|        \\|   ._      /  *
*  \\     \\/      \\    \\     \\    /    |    :___/?|    \\    \\   |/     /   *
*   \\_____________\\___/_____/___/_____|____|     |____|\\_____________/    *
*     -========================/===========|______\\================-      *
*                                                                         *
*   .---.----(*(          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

#amiga #cracking #loaders


<-- All Terrain Racing” (c) 1995 Team 17 | [ Code ] | Angels Loader -->