--------------------
Hardware Trackloader
--------------------
from an article "Les Disques Chouettes" by Loïc
Far in Amiga News Tech issues #24-25-27-30
(jul/aug/sept/nov 1990).
(cover disks)
source
(original)
of the hardware trackloader with multidrive test and cia
timer delay
cover disk #25
see some trackloader sources
(Interphase/Toki custom, standard
Trackloader, raw sector loaders)
base
before any other non-dos formats (protected or not)
the
Complex Interface Adapter CIA assists the DMA disk starting
motor, moving I/O heads, choosing the active side and
while providing to the system the state of drive.
the
DMA disk take charge of Read/Write :
synchronizes the reading with a control word - SyncWord
(standard $4489) - to guarantee the alignment of the
datas in memory.
the standard coding of the datas is MFM (IBM, Atari...)
or GCR
Mfm Uncoding is done by the 68000 (possible with the
blitter, but why?!)
CIA-A
: $bfe001 - 4 bits used - Input
Bit
|
Nom
|
Fonction |
5
|
RDY
|
Disk
Ready. set to 0 when motor on and disk ready |
4
|
TRACK0
|
Track
Zero Detect. set to 0 when I/O head on track 0 |
3
|
WPRO
|
Write
Protected. set to 0 if write protected disk |
2
|
CHNG
|
Disk
Change. set to 0 when changing disk. set to 1
when disk is inserted and an impulse step transmitted |
CIA-B
: $bfd100 - 8 bits used - control - Output
Bit
|
Nom
|
Fonction |
7
|
MTR
|
Disk
Motor Control. It doesn't have immediate action
but is received by the drive when selected by SELx.
To start/stop drive, it's initially necessary to
set MTR then select the drive. |
6
|
SEL3
|
select
drive DF3 |
5
|
SEL2
|
select
drive DF2 |
4
|
SEL1
|
select
drive DF1 |
3
|
SEL0
|
select
drive DF0. always. |
2
|
SIDE
|
select
face. it must be maintained during 100 microseconds
for writing, and during at least 1,3 millisecond
between a writing and change of side. 0 : higher
side, 1 : lower side |
1
|
DIR
|
select
direction. 0 : towards center. before the step impulse.
2 mc68000 instructions are necessary. better is
worth a timer more compatible : CIA Timer, than
dbra loop. |
0
|
STEP
|
send
an impulse for moving head. fast: inactive-active-inactive.
move of a track to another in 3 millisec max.
during a change of direction, 18 millisec. between
2 step impulses. |
example:
include
"hardware/cia.i"
lea $bfd000,a5 CIA-B
lea $bfe001,a4 CIA-A
bsr
MotorOn
bsr SeekTrack0
bsr MotorOff
rts
MotorOn:
bset #CIAB_DSKSEL0,ciaprb(a5) ; df0: off
bclr #CIAB_DSKMOTOR,ciaprb(a5) ; 0: motor on
bclr #CIAB_DSKSEL0,ciaprb(a5) ; df0: on
rts
MotorOff:
bset #CIAB_DSKSEL0,ciaprb(a5) ; df0: off
bset #CIAB_DSKMOTOR,ciaprb(a5) ; 1: motor off
bclr #CIAB_DSKSEL0,ciaprb(a5) ; df0: on
rts
SeekTrack0:
bset #CIAB_DSKDIREC,ciaprb(a5) ; dir=1
.seek btst #CIAB_DSKTRACK0,ciapra(a4)
beq.s .Ok
bsr Step
bsr Delay
bra.s .seek
.ok rts
Step:
bclr #CIAB_DSKSTEP,ciaprb(a5)
nop
nop
nop
bset #CIAB_DSKSTEP,ciaprb(a5)
rts
Delay:
// software delay !!
move.w #3000,d7
dbra d7,*
TestDrive:
btst #CIAB_DSKRDY,ciapra(a4)
bne.s TestDrive
rts
---------
Timer CIA
---------
;--- delay Timer A CIA-B
move.w #$2000,$dff09a ; INTENA bit 13 - stop interrupt
CIA-B
move.l #$bfe001,a0 ; CIA-B
move.b $e00(a0),d0 ; register CRA
andi.b #$c0,d0 ; mask unused bits
ori.b #8,d0 ; mode on-shot
move.b d0,$e00(a0) ; init timer A, mode one-shot
move.b #$28,$400(a0) ; 3ms=2128 PAL
move.b #$21,$500(a0) ; 2148 NTSC
wait:
btst.b #0,$d00(a0) ; test register ICR
beq.s wait ; wait
...
bset.b
#0,$e00(a0) ; reset the timer
bra.s wait ; loop
------------
format MFM
------------
this
format makes possible to avoid any error of synchro
during read/write, by inserting one bit of synchro (parity)
between each bit of data. Initially coding the odd bits
then the even bits, in 2 consecutive buffers
;
d0 = nb long word to uncode -1
; a0 = odd bits
; a1 = even bits
; a2 = uncode buffer
Decode:
move.l (a0)+,d1
move.l (a1)+,d2
andi.l #$55555555,d1
andi.l #$55555555,d2
lsl.l #1,d1 ;*2
or.l d2,d1
move.l d1,(a2)+
dbra d0,Decode
rts
MFM
sector header :
2 bytes @ $00 ($AAAA MFM)
2 bytes @ $A1 ($4489 MFM)
1 long word : sector description (8 bytes MFM)
16 bytes : AmigaDOS reserved (32 bytes MFM)
1 long word : header checksum (8 bytes MFM)
1 long word : data checksum (8 bytes MFM)
512 bytes datas (1024 bytes MFM)
the
first 2 bytes to 0 ($aaaa in mfm) : beginning of the
sector
the two following bytes are used to indicate to the
DMA when it must start to write/read
the data read in memory this value is a particular word
in MFM,
placed in front of each sector : it corresponds to the
value $A1 coded without bit 7.
It's sure that this value will never be found in the
data of the sector.
It's possible for protection to use another value that
$4489.
The sector description : 4 bytes : $FF (amiga format),
# track, # sector, sector numbers
remaining to be read before reaching the end of track.
the DMA disc reading full track since a random position,
thus know the position of the sector in the track.
the 2 checksums allow of check for each sector which
the reading proceeded well (or exclusive EOR of each
long word)
-----------
MFM Tracks
-----------
a track contains 11 sectors made up of a various datas
field of 32 bytes
followed by a data field of 512 bytes.
the track is preceded by a GAP of approximately 700
bytes (vari according to the position of the track)
it makes it possible to prevent at writing that the
last datas don't crush the first (a track is circular)
700+(2*(11*(32+512))) = 12668 bytes MFM by track
SECTOR:
offset |
val
|
? |
0 |
$aaaa
|
first
word |
2 |
$aaaa
|
second
word |
4 |
$4489
|
first
synchro word |
6 |
$4489
|
second
synchro word |
8 |
xxxxx
|
ID
sector odd bits |
12 |
xxxxx
|
ID
sector even bits |
16 |
xxxxx
|
AmigaDOS datas odd bits |
32 |
xxxxx
|
AmigaDOS datas even bits |
48 |
xxxxx
|
checksum
header (odd bits) |
52 |
xxxxx
|
checksum
header (even bits) |
56 |
xxxxx
|
checksum
datas (odd bits) |
60 |
xxxxx
|
checksum
datas (even bits) |
64 |
xxxxx
|
datas
odd bits |
576 |
xxxxx
|
datas
even bits |
Uncode
steps:
1- ID sector
2- checksum header
3- checksum datas
4- datas
+
check 2 checksums (see MFMUncode routine)
-----------
Test Drives
-----------
(from ANT #30 by François 'Altaïr' Braün)
source
cover disk #30
detect multiple drive (df0-1-2-3)
based on RKM
1-
MTR off
2- SELxB off
3- SELxB on
4- MTR on
5- SELxB off
loop:
6- SELxB on
7- SELxB off
8- lire et sauver l'etat de DSKRDY
9- SELxB on
10- loop (6-9) x16
routine:
put 4 ID of each drive in buffer
TestDrive:
lea Buffer(pc),a0
bsr TestDisk
rts
Buffer: dc.w 0,0,0,0
TestDisk:
movem.l d0-d7/a1,-(sp)
addq.l #8,a0 ; end of buffer 3 to 0
lea $bfd100,a1 ; CIA-B
moveq #2,d0 ; 3 drives DF3 - DF2 - DF1)
test:
move.b d0,d1
addq.b #4,d1 ; bit DSKSELx (4 à 6)
bclr #7,(a1) ; DSKMOTOR low
bclr d1,(a1) ; DSKSELx low
bset d1,(a1) ; DSKSELx high
bset #7,(a1) ; DSKMOTOR high
bclr d1,(a1) ; DSKSELx low
moveq #0,d2 ; ID
moveq #15,d3 ; 16 tests (1 word)
.loop:
lsl.l #1,d2
bset d1,(a1) ; DSKSELx high
bclr d1,(a1) ; DSKSELx low
btst #5,$f01(a1) ; CIA-A $bfe001 DSKRDY
bne.s .next
bset #0,d2
.next:
bset
d1,(a1) ; DSKSELx high
dbra d3,.loop
move.w
d2,-(a0)
dbra d0,test
move.w
d0,-(a0) ; DF0 always present
movem.l (sp)+,d0-d3/a1
rts
------------------------------------------
Second
Part : DMA disk : Read/Write datas
------------------------------------------
The data transmitted via DMA disk, having been encoded
or mfm gcr or another for writing
Initialization steps :
- set data buffer : register DSKPT ($dff020-22)
- init register DSKLEN (write) ($dff020) :
bit 15 DMAEN
bit 14 Write
bit 0-13 Lenght
1. DSKEN de DMACON set to 1 (always when DMAEN=1)
2. secure: activate 2x DMAEN
- desactivate DMAEN : DSKLEN=0
- set address buffer in DSKPT
- init DSKLEN : LEN-WRITE-DMAEN, 2x
- wait DMA disk ending
- secure: DSKLEN=0
An interrupt is generated after reading / writing the
last word
state: DSKBYTR $dff01a (read)
If you do not want to read an entire track, you can
start the DMA access to a fixed position. Written on
the word of data where the disk controller must start
within DSKSYNC
DSKSYNC : $dff07e (write)
Data word that the transfer should begin.
When the controller reads the data, he compares it with
the word data DSKSYNC.
When both match, he began transferring
- wait sync word at the beginning of a data block
- start Interruption when OK
type of encoding data in ADKCON $dff09e (write) - ADKCONR
$dff010 (read)
ADKCON:
15. set/clr
13-14. Precomp 0, 2 (140 nanosec), 4 (280 nanosec),
6 (560 nanosec)
12. Memprec : 0= GCR 1=MFM
10. wordsync: 0=MFM 1=GCR
9. Msbsync : 1 = synchro msb
8. fast : 1 = 2 microsec (MFM) - 0 = 4 microsec (GCR)
Writting
Datas
-----------
Code the datas in MFM :
(soon)
and replace the Read routine with :
...
Write:
move.w #$7f00,$9e(a6)
move.w #$8100,$9e(a6)
bsr DiskReady
move.l #MFMBuffer,$20(a6)
move.w #$D978,$24(a6)
move.w #$D978,$24(a6)
move.w #2,$9c(a6)
.wait
btst #1,$1f(a6)
beq.s .wait
move.w #$4000,$24(a6)
...
|