Welcome, Guest. Please login or register.
Amiga Kit Amiga Store Iridium Banner AMIStore App Store A1200/A600 4xIDE Interface

AuthorTopic: Trackloader Questions  (Read 1413 times)

0 Members and 1 Guest are viewing this topic.

Offline MskoDestny

Trackloader Questions
« on: December 29, 2005, 04:00:33 PM »
I managed to track down a copy of the hardware reference manual (my uncle used to program professionally for the Amiga) and I've begun my Amiga hardware banging journey, but I have some questions related to accessing the floppy drive. The Hardware manual is kind of light on disk details so I've been going through the source to the Interphase trackloader and while I understand what it's doing, I still have a couple of questions.

1)The interphase loader uses nops in a couple of places for short delays to generate appropriate length pulses for things like the step and motor signals. This seems like a somewhat unreliable way to generate a delay since presumably a nop doesn't take the same amount of time on an 060 (or a mythical Coldfire accelerator) as it does on a 68000. Is there a better way to generate this delay (reading from the CIA's maybe)?

2)What address is the bootblock loaded to at boot time?

3)How do I detect if a high density floppy is in the drive? Will the same method reliably report double density in a double density drive or do I have to determine whether or not a high density drive is installed first?
 

Offline JLF65

Re: Trackloader Questions
« Reply #1 on: January 06, 2006, 10:35:50 PM »
Quote
MskoDestny wrote:
1)The interphase loader uses nops in a couple of places for short delays to generate appropriate length pulses for things like the step and motor signals. This seems like a somewhat unreliable way to generate a delay since presumably a nop doesn't take the same amount of time on an 060 (or a mythical Coldfire accelerator) as it does on a 68000. Is there a better way to generate this delay (reading from the CIA's maybe)?


Considering that you use the CIA lines to control the floppy, most disk drivers use reading the CIA as the delay method of choice. It works on all classic Amigas.

Quote
2)What address is the bootblock loaded to at boot time?


Don't remember, but you can use BSR to get the address inside the code pretty easily. Boot code really should be PC relative to avoid trouble.

Quote
3)How do I detect if a high density floppy is in the drive? Will the same method reliably report double density in a double density drive or do I have to determine whether or not a high density drive is installed first?


Amiga drives have a drive ID sequence you use to determine if there is a drive connected and such.

1 - Turn the motor on, then turn it off. This resets the drive ID shift port. Deassert SELxB*.

2 - Drive SELxB* active and read the RDY* line for one bit of the ID. Deassert SELxB*.

3 - Loop to 2 until you have 32 bits.

Some values:
$00000000 = no floppy connected
$FFFFFFFF = 3.5" floppy with no media or DD media
$AAAAAAAA = 3.5" floppy with HD media (HD drives only)
$55555555 = 5.25" floppy

The AEHD drive used some custom values in there. I'll see if I can't dig up the code to my old patch for the AEHD for that info.
 

Offline JLF65

Re: Trackloader Questions
« Reply #2 on: January 07, 2006, 01:14:02 AM »
Okay... I have the no drive and DD drive backwards above.  :-D

If you check the developer includes, you find:

DRT_EMPTY EQU $FFFFFFFF
DRT_AMIGA EQU $00000000
DRT_150RPM EQU $AAAAAAAA
DRT_37422D2S EQU $55555555

WAY back in '97, I wrote a patch for OS3.1 that fixed some drive ID issues and allowed the use of the AEHD transparently without AE's crappy driver. I'm positive I put it on AmiNet, but I can't find it there. I'm quoting the source below. Feel free to use whatever is handy.

Code: [Select]
; Universal Drive Patch
; Copyright (C) 1997 Joseph Fenton. All rights reserved.

include devpac:system.gs
output c:udp

;--------------------------------------------------------------------
; note: this program cannot be run from WB

entry bra.b start

; Standard 2.x/3.x version string

dc.b 0,'$VER: Universal Drive Patch 2.0 (3.6.97)',0

CNOP 0,4

; The main program code.

start movea.l 4.w,a6
CALLSYS Forbid

; get memory for AE drive command function

moveq #4,d0
move.l #MEMF_CLEAR+MEMF_CHIP+MEMF_PUBLIC,d1
cmpi.w #39,LIB_VERSION(a6)
blo.b .ac ; pre-39 was buggy in reverse
ori.l #MEMF_REVERSE,d1
.ac CALLSYS AllocMem
move.l d0,ChipPtr
bne.b .ok0

CALLSYS Permit
move.l #ERROR_NO_FREE_STORE,d0
rts

; get memory for ReadUnitID patch code

.ok0 move.l #CODE_LENGTH,d0
move.l #MEMF_CLEAR+MEMF_PUBLIC,d1
cmpi.w #39,LIB_VERSION(a6)
blo.b .af ; pre-39 was buggy in reverse
ori.l #MEMF_REVERSE,d1
.af CALLSYS AllocMem
move.l d0,MemPtr
bne.b .ok1

moveq #4,d0
movea.l ChipPtr,a1
CALLSYS FreeMem

CALLSYS Permit
move.l #ERROR_NO_FREE_STORE,d0
rts

; get timer.device base

.ok1 lea DeviceList(a6),a0
lea timerName,a1
CALLSYS FindName
move.l d0,TimerBase
bne.b .ok2

move.l #CODE_LENGTH,d0
movea.l MemPtr,a1
CALLSYS FreeMem

moveq #4,d0
movea.l ChipPtr,a1
CALLSYS FreeMem

CALLSYS Permit
move.l #RETURN_WARN,d0
rts

; copy patch code into the allocated memory

.ok2 lea ReadUnitID,a0
move.l MemPtr,a1
move.l #CODE_LENGTH,d0
CALLSYS CopyMem

; get disk.resource base

lea DskRsrcName,a1
CALLSYS OpenResource
tst.l d0
bne.b .ok3

move.l #CODE_LENGTH,d0
movea.l MemPtr,a1
CALLSYS FreeMem

moveq #4,d0
movea.l ChipPtr,a1
CALLSYS FreeMem

CALLSYS Permit
move.l #RETURN_WARN,d0
rts

; Patch disk.resource ReadUnitID() function.
; This is the system-friendly method!

.ok3 lea _LVOReadUnitID,a0 ; function offset
movea.l d0,a1 ; library base
move.l MemPtr,d0 ; new function pointer
CALLSYS SetFunction

; Exit leaving patch in memory. You don't have to 'run' this program.

CALLSYS Permit
moveq #RETURN_OK,d0
rts

;--------------------------------------

CNOP 0,4

MemPtr dc.l 0

DskRsrcName dc.b 'disk.resource',0
even

timerName dc.b 'timer.device',0


;--------------------------------------------------------------------

CNOP 0,4

; This is the new ReadUnitID() function.  It handles the disk identification
; and AEHD drive controlling.

ReadUnitID movem.l d2-d3/a3,-(a7)
move.l d0,d2 ; unit number
move.b #8,d3
lsl.b d0,d3 ; drive select bit
lea $30(a6),a0 ; unit id table
lsl.l #2,d0 ; offset for unit
lea (a0,d0.w),a3 ; ptr to this unit id
bsr.w GetDriveID ; get 32bit ID
cmpi.l #DRT_EMPTY,d0 ; drive present?
bne.b .1 ; yes, check for HD
tst.l d2 ; check unit number
bne.b .2 ; external, no drive
moveq #DRT_AMIGA,d0 ; assume internal present
.1 bsr.w CheckDrive ; check disk type
.2 move.l d0,(a3) ; set disk type

; Check for whether ReadUnitIDwas called from trackdisk.device. If not,
; simply exit back to the calling code.  If called from trackdisk, cleanup
; the stack, determine which setup vector to return in a1, and return to
; trackdisk at appropriate offset.

movea.l 12(a7),a3 ; return address
cmpi.l #$2C5F4E75,(a3) ; movea.l (a7)+,a6  rts
bne.b .4 ; not trackdisk
movea.l 20(a7),a3 ; next return addr
cmpi.w #$B0AB,(a3) ; cmp.l d16(a3),d0
bne.b .4 ; not trackdisk

; trackdisk is trying to determine the disk type

movem.l (a7)+,d2-d3/a3
addq.l #4,a7 ; pop 1st return address
movea.l (a7)+,a6
movea.l (a7)+,a1 ; trackdisk return addr

; Determine structure offset for different versions of trackdisk. This
; allows the code to be mostly independent of the version of trackdisk.
; This works for versions 37 through 40.

move.w 2(a1),d2 ; prev ID offset
subi.w #$54,d2 ; offset for this version
cmp.l $54(a3,d2.w),d0 ; same type as previously?
bne.b .3 ; no
jmp (a1) ; yes, return to trackdisk

; determine which setup routine is needed for this disk type

.3 pea $22(a1) ; new return address
lea SetupDD(pc),a1
cmpi.l #DRT_AMIGA,d0
beq.b .5 ; 3.5" DD
lea SetupAE(pc),a1
cmpi.l #$0F03FFFF,d0
beq.b .5 ; AEHD drive in HD mode
lea SetupHD(pc),a1
cmpi.l #DRT_150RPM,d0
beq.b .5 ; 3.5" HD

; not recognized, return and use previous disk type settings

movea.l (a7)+,a1 ; return address
lea 4-$22(a1),a1 ; branch if same address
cmp.l d0,d0 ; same as previous
jmp (a1)

.4 movem.l (a7)+,d2-d3/a3
.5 rts

;--------------------------------------

CNOP 0,4

; Read the drive ID bits and set the AEHD speed select if needed.

GetDriveID not.b d3 ; drive select low
lea $BFD100,a0

; turn motor on, then off to reset drive ID circuit

move.b #$7F,d0
move.b d0,(a0) ; assert motor
and.b d3,d0
move.b d0,(a0) ; select drive, motor on
move.b #$FF,(a0) ; deassert motor
move.b d3,(a0) ; select drive, motor off
move.b #$FF,(a0) ; deselect drive

; read drive ID bits

moveq #31,d1 ; 32 bits
moveq #0,d0
.1 lsl.l #1,d0
move.b d3,(a0) ; select drive
btst #5,$BFE001 ; get ID bit
beq.b .2
bset #0,d0
.2 move.b #$FF,(a0) ; deselect drive
dbra d1,.1 ; next bit

not.b d3 ; drive select high

move.l d0,d1
andi.l #$FF1FFFFF,d1 ; AEHD drive ID mask
cmpi.l #$0F03FFFF,d1 ; AEHD drive?
beq.b .3 ; yes
rts

; AEHD drive - determine the disk type and set the drive speed.

.3 btst #21,d0 ; disk type bit
bne.w AEHD ; HD disk
bra.w AEDD ; DD disk

;--------------------------------------

CNOP 0,4

; Determine if disk reported as DD is really HD by timing the track
; using the index pulse.

CheckDrive cmpi.l #DRT_AMIGA,d0 ; 3.5" DD?
bne.w .exit ; no, exit
cmpi.l #$0F03FFFF,d1 ; AEHD drive?
beq.w .exit ; yes, exit

not.b d3 ; drive select low
lea $BFD000,a0
move.b #$7F,d2
move.b d2,$100(a0) ; assert motor
and.b d3,d2
move.b d2,$100(a0) ; select drive, motor on

bsr.w GetSystemTime
move.l d0,d2
addi.l #800,d2 ; .8 sec
.loop0 btst #5,$1001(a0) ; /RDY
beq.b .1 ; motor up to speed
bsr.b GetSystemTime
cmp.l d2,d0
blt.b .loop0 ; wait for motor to spin up

.1 tst.b $D00(a0) ; clear icr
bsr.b GetSystemTime
move.l d0,d2
addi.l #500,d2 ; .5 sec
.loop1 btst #4,$D00(a0) ; /INDEX = FLG bit in icr
bne.b .2 ; found index
bsr.b GetSystemTime
cmp.l d2,d0
blt.b .loop1 ; wait for index pulse
bra.b .dd ; timeout

.2 move.l d0,d2
addi.l #500,d2 ; .5 sec
.loop2 btst #4,$D00(a0) ; /INDEX = FLG bit in icr
bne.b .3 ; found index
bsr.b GetSystemTime
cmp.l d2,d0
blt.b .loop2 ; wait for index pulse
bra.b .dd ; timeout

.3 sub.l d0,d2 ; time left in .5 sec
cmpi.l #250,d2
blt.b .hd ; took more than .25 sec

.dd moveq #DRT_AMIGA,d0 ; 3.5" DD
bra.b .4

.hd move.l #DRT_150RPM,d0
.4 not.b d3 ; drive select high
move.b #$FF,$100(a0) ; deselect drive
.exit rts

;------------------

CNOP 0,4

GetSystemTime movem.l d1/a0-a1/a6,-(a7)
lea SysTime(pc),a0
movea.l TimerBase(pc),a6
CALLSYS GetSysTime
lea SysTime(pc),a0
move.l #$FFFFF,d0
and.l (a0)+,d0 ; tv_secs & 000FFFFF
mulu.w #1000,d0 ; ms
move.l (a0),d1 ; tv_micro
divu.w #1000,d1 ; ms
andi.l #$FFFF,d1
add.l d1,d0 ; total ms
movem.l (a7)+,d1/a0-a1/a6
rts

;--------------------------------------

CNOP 0,4

; Set the AEHD drive to the proper speed for the disk type.

AEDD moveq #DRT_AMIGA,d0 ; 3.5" DD
move.b #$F9,d2 ; set DD speed opcode
bra.b SetAE

AEHD move.l d1,d0 ; AEHD drive in HD mode
move.b #$FB,d2 ; set HD speed opcode

SetAE movem.l d0/a1,-(a7)
lea $BFD000,a0
lea $DFF000,a1
not.b d3 ; drive select low
move.b d2,$100(a0) ; speed
and.b d3,d2
move.b d2,$100(a0) ; select drive, set speed

; write a longword of 0 to activate the AEHD setting

move.w #$4000,dsklen(a1)
move.w #$1002,intreq(a1) ; clear disk ints
move.l ChipPtr(pc),dskpt(a1)
move.w #$C002,dsklen(a1)
move.w #$C002,dsklen(a1) ; start write to set speed

; wait for DSKBLK

move.l #$20000,d2
.loop move.w intreqr(a1),d0 ; ints
btst #1,d0 ; DSKBLK
bne.b .1 ; done
subq.l #1,d2
bne.b .loop

; timeout, stop the DMA

move.w #$4000,dsklen(a1)
.1 move.w #$4000,dsklen(a1) ; stop any disk DMA
move.w #2,intreq(a1) ; clear DSKBLK

move.b #$FF,$100(a0) ; deselect drive
not.b d3 ; drive select high
movem.l (a7)+,d0/a1
rts

;--------------------------------------

CNOP 0,4

; These routines setup the trackdisk variables needed to distinguish
; one format from another. They call a common track buffer setup.

SetupDD move.l #880*1024,$44(a3,d2.w) ; total storage
move.l #300000,$50(a3,d2.w) ; timeout
move.w #11,$4E(a3,d2.w) ; # sec/trk
move.w #15296,$48(a3,d2.w) ; track length + overlap
move.w #13628,$4A(a3,d2.w) ; track length
move.w #1660,$4C(a3,d2.w) ; gap length
move.l #DRT_AMIGA,$54(a3,d2.w) ; disk type
move.b #DRIVE3_5,$40(a3,d2.w) ; drive type
bra.b SetupTrkBuffer

CNOP 0,4

SetupAE move.l #1520*1024,$44(a3,d2.w) ; total storage
move.l #500000,$50(a3,d2.w) ; timeout
move.w #19,$4E(a3,d2.w) ; # sec/trk
move.w #24004,$48(a3,d2.w) ; track length + overlap
move.w #22334,$4A(a3,d2.w) ; track length
move.w #1662,$4C(a3,d2.w) ; gap length
move.l #$0F03FFFF,$54(a3,d2.w) ; disk type
move.b #4,$40(a3,d2.w) ; drive type
bra.b SetupTrkBuffer

CNOP 0,4

SetupHD move.l #1760*1024,$44(a3,d2.w) ; total storage
move.l #600000,$50(a3,d2.w) ; timeout
move.w #22,$4E(a3,d2.w) ; # sec/trk
move.w #30584,$48(a3,d2.w) ; track length + overlap
move.w #27256,$4A(a3,d2.w) ; track length
move.w #3320,$4C(a3,d2.w) ; gap length
move.l #DRT_150RPM,$54(a3,d2.w) ; disk type
move.b #DRIVE3_5_150RPM,$40(a3,d2.w) ; drive type

SetupTrkBuffer movea.l $68(a3,d2.w),a1 ; track buffer ptr
move.w #-1,(a1) ; track invalid
clr.b 2(a1) ; clear track flags
move.w $4C(a3,d2.w),d0 ; gap length
lea $68(a1,d0.w),a0
adda.w d2,a0
adda.w d2,a0 ; start of data area
move.l a0,4(a1) ; track data ptr
suba.w d0,a0 ; start of gap area
lsr.w #2,d0 ; # longs in track gap
subq.w #1,d0 ; for dbra
move.l #$AAAAAAAA,d1 ; MFM zero value
.1 move.l d1,(a0)+ ; clear track gap
dbra d0,.1
rts

;--------------------------------------

CNOP 0,4

ChipPtr dc.l 0

TimerBase dc.l 0

SysTime dc.l 0,0


;--------------------------------------------------------------------

CODE_END:

CODE_LENGTH equ CODE_END-ReadUnitID

end