Low level floppy read code example (DMA loader)

All 680x0 related coding posts in this section please.

Moderators: simonsunnyboy, Mug UK, Zorro 2, Moderator Team

Post Reply
Fuji Shaped Bastard
Fuji Shaped Bastard
Posts: 2978
Joined: Mon Feb 20, 2012 4:42 pm

Low level floppy read code example (DMA loader)

Post by AtariZoll »

This example accessing floppy 2-sidewise, by alternating sides - what is better than going through 1 side in order, then reading other side, since less floppy step is required.
Whole routine is pretty short, so may use in game loaders for instance. There is depacking support too, without need for extra buffer - it calculates loading address according to unpacked length, loads to destination area, and depacks without overwriting packed data.
4 byte long filenames are used - I made this code for game Power Drift, 1 floppy version, suing original names. So, 1 file record is 8 bytes long.
May use only 4 byte long records table - then instead file name, file number must be given - little modded code is needed then to get LS and sector count.
Or simplest is to give straight LS and sector count to loader for each file by caller.

Code: Select all

*Hardware registers:

gpip equ  $fffffa01

dmal    equ $ffff860d
dmam equ $ffff860b
dmah   equ $ffff8609

fdcc    equ $ffff8604
dmac  equ $ffff8606

* Subrutine for loading from floppy

* params :  a0 - dest, 
* d0 long filename - 4 chars always, capital

	movem.l	d1-d6/a2-a4,-(sp)
	move.l	a0,a4   * Save dest

	lea	catc(pc),a1
	moveq	#92,d1   * 93 files total - just example

seefl	cmp.l	(a1),d0
	beq.s	gotIt
	addq.l	#8,a1
	dbf	d1,seefl
	moveq	#-34,d0    * File not found - should never happen

	movem.l	(sp)+,d1-d6/a2-a4

* need d2 - track, d3 - SS ,  d4 - count

* Here 2-sidewise loading ! :

gotIt 	moveq	#0,d2
	moveq	#0,d4
	move.w	4(a1),d2   * LS of file start, next 2 bytes are unpacked length
	move.w	12(a1),d4
	sub.w	d2,d4    * Sector count
	move.b	#$FD,d6
* d2 holds now logical sector (2 sides, alternating), d4 holds sector count for load

* Determine side :

	divu	       #20,d2
	move.l	d2,d3   * Track in d2
	swap	d3      * SS
	cmp.b	#10,d3
	bcs.s	sidA
	move.b	#$FC,d6
	sub.b	#10,d3	

	addq.w	#1,d3    * SS

	jsr	readPrep.w

* Calc load address, considering depacking process :

	moveq	#0,d5
	move.w	6(a1),d5    * Unpacked len  -  max 65535 , otherwise need different records
* Load to address of target + unpacked len - packed len +512  

	addq.w	#1,d5
	bclr	  #0,d5   * make it even

	add.l   d5,a0
	lea	    512(a0),a0
	move.l	d4,d5
	lsl.w  	#4,d5
	lsl.l	    #5,d5
	sub.l	  d5,a0

	move.l	a0,-(sp)

nexS 	jsr	read1s.w    * reading 1 sector
* Here should check d0 - for possible errors

	subq.w	#1,d4
	beq.s	ldEnd

	lea	512(a0),a0
	addq.w	#1,d3 
	cmp.w	#11,d3   * 10 sector/track
	bne.s	nexS
	moveq	#1,d3

* Need to flip side here :
	eor.b	#1,d6
	cmp.b	#$FD,d6
	bne.s	noTraI
	addq.w	#1,d2
	jsr	readPrep.w	

	bra.s	    nexS


	move.l	(sp)+,a1
	lea	32(a1),a1

	bsr	depak3

* By need call floppy deselect here - but it is done in Vblank usually
toRea	moveq	#0,d0
	movem.l	(sp)+,d1-d6/a2-a4

catc	incbin   "CAF"   * 752 bytes - for 93 files

depak3	clr.l d0
	moveq    #6,d4
	moveq    #$3f,d5   *for masking bits 5-0

* Bit meaning:  7 - if set it's back referrer , if 0 then bits
* 6-0 give count of literals to copy
* if all bits are 0 it is terminator

* When bit 7 set, bit 6: if 1 then long distance back given by 2 following byte
*  bit 6: when 0  then short distance given by following 1 byte
*  bits 5-0  count of bytes referred. 
*  By short refer.  0 means 3, 1 means 4, etc  up to 66 .
*  By long refer.  0 means 4, 1 means 5, etc  up to 67 .

main3 	clr.w d0 *prep for dbf
	move.b (a1)+,d0
	bmi.s back3 
	beq.s nom3 *end
	subq.w #1,d0 *compens dbf
litc 	move.b (a1)+,(a4)+
	dbf d0,litc
	bra.s main3

nom3	rts

back3	move.b d0,d2
	and.w d5,d2 *d5=$3f
* Test is long or short referrer:
	btst    d4,d0   *test bit 6
	bne.s  longr
	addq.w #2,d2 *compens	
displl	move.b (a1)+,d0 * displac
calcadr	move.l a4,a2
	sub.l d0,a2
baksl	move.b (a2)+,(a4)+
	dbf d2,baksl
	bra.s main3

longr	addq.w #3,d2 *compens
	move.b (a1)+,d0 * displac
	lsl.w  #8,d0   *MSB
	bra.s   displl

* End of C3 depak

* Floppy code self :

read1s     *d2-track, d3 - sector #

* First step if needed
* See FDC track register content :

  move.w #$82,(a2)  *Track register
  bsr delay

  move.w  (a3),d0   * Current track
  cmp.b  d0,d2   * b !
  beq.s noStep

  move.w #$86,(a2)  *Data register
  bsr delay

  move.w d2,(a3) *Track No
  bsr delay
  bsr comand
  move.w #$13,(a3)  *Seek command, steprate 3ms
  bsr comexd  


* Read 1 sector :

   move.l   a0,d0

  move.b d0,dmal.w
  lsr.w #8,d0
  move.b d0,dmam.w
  swap d0
  move.b d0,dmah.w
  move.w #$84,(a2)
  bsr delay
  move.w  d3,(a3)
  bsr delay

  move.w #$90,(a2)
  move.w #$190,(a2)
  move.w #$90,(a2)
  bsr delay
  move.w #1,(a3)  *Block number-one sector of 512
  bsr comand

  move.w #$80,(a3)  * Read sector command
  bsr delay
  bsr comexd


readprep   * in d6 is side flag 
  movea.w #$8800,a2
  move.b #14,(a2)
  move.b  (a2),d0
  or.b  #3,d0     * must set to inactive state, side A - otherwise may select bad side !
  and.b   d6,d0    *  $FD   for side A, $FC for side B - both drive A always
  move.b  d0,2(a2)

* Prepare registers for DMA, FDC access
  lea dmac.w,a2  *DMA mode register
  lea fdcc.w,a3  *FDC register(s)

comand move.w #$80,(a2)

delay move.l d7,-(sp)
  moveq #12,d7
dll  dbf d7,dll
  move.l (sp)+,d7

  move.l #300000,d0 * give enough time
cfort  btst #5,gpip.w
  beq.s cef
  subq.l #1,d0
  bne.s cfort
  move.w #$fe,d0 *Drive not ready-usually means-no disk in drive

cef  move.w #$80,(a2)  *Read status     12T
  move.w (a3),d0     *    8T
  btst #4,d0    *  12T
  beq.s de2    *  12T
  move.w #$f8,d0   *RNF    
de2  btst #3,d0     *   12T
  beq.s de3     * 12T
  move.w #$fc,d0  *CRC   
de4   *TOS standard error nummers used.
  rts      *  16T

deselFlo    * deselecting floppy after finished
* by watching motor on in status

  lea dmac.w,a2  *DMA mode register
  lea fdcc.w,a3  *FDC register(s)

readFloS   nop
  move.w #$80,(a2)  *Read status     12T
  bsr   delay
  move.w (a3),d0     *    8T

  btst   #7,d0
  bne.s   readFlos
  movea.w #$8800,a2
  move.b #14,(a2)
  move.b  (a2),d0
  or.b  #$3,d0
  move.b  d0,2(a2)


Famous Schrodinger's cat hypothetical experiment says that cat is dead or alive until we open box and see condition of poor animal, which deserved better logic. Cat is always in some certain state - regardless from is observer able or not to see what the state is.
Post Reply

Return to “680x0”