;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ
;ญ			-> DiskBOOTloader <-			   ญ
;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ
;ญ                    1990 by Duke/Level Four		  	   ญ
;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ
;Notes:	
;a)	If you want to load and execute CRUNCHED proggys with this 
;	loader, you should know the address where the decruncher puts
;	your program into memory to be sure that it won't scratch the
;	loader-routine. Moreover you have to know that your prog
;	will crash if you load it into its own decrunch area!
;	To prevent such crashes, you're able to set the address
;	of the bootloader and the address where your prog should
;	be located after loading by changing the address at
;	"Bootstart". !!!DON'T DECREASE THE OFFSET AT "Buffer"!!!
;b)	How to install the bootloader on your disk (df0:):
;	1. assemble this loader (with MASTERSEKA)
;	2. bstart_boot   <Return>  ;calculate boot-checksum
;	3. ws0		 <Return>  ;(w)rite(s)ector on df(0)
;	4. BEG>start_boot<Return>
;	5. SECTOR>0	 <Return>  ;start sector 0
;	6. AMOUNT>2	 <Return>  ;write 2 sectors (1024 bytes)
;	Now you must save the program which you want to load to the
;	same disk on the correct tracks. You can do that with
;	MASTERSEKA, too, by typing:
;	1.ri		   <Return>  ;(r)ead (i)mage
;	2.FILENAME>progname<Return>  ;enter name of your program here
;	3.BEG>$40000       <Return>  ;load prog. to $40000 for example
;	4.END>             <Return>  ;load WHOLE prog. just return here
;	5.wt0		   <Return>  ;(w)rite (t)rack on df(0)
;	6.BEG>$40000	   <Return>
;	7.CYLINDER>enter startcylinder here (1 cylinder=2 tracks)
;	8.AMOUNT>enter length of your prog in cylinders (1cyl=11264bytes)

;If you have no MASTERSEKA you can use the Amiga Mon or the C-mon
;to install your program and the loader on disk.
;Ok. Now your AMIGA should load and execute your program correctly.
;signed duke/l4

;ญญญญญญญญญญญญญญMACRO-definitionsญญญญญญญญญญญญญญญญญญ
color:	macro
	move.w	#\1,$180(a6)
	endm

;now we waste diskspace by using the following step-macro (but who
;cares ? - This bootblock is about 920 bytes long...)

step:	macro
	move.b	floppystatus(pc),d0
	move.b	d0,d1
	bclr	#0,d0		;clear DSKSTEP after setting it...STEP!
	move.b	d0,(a0)		;a0=$bfd100 (CIA-B PRB)
	nop			;wait a little
	nop
	move.b	d1,(a0)		;set DSKSTEP back to 1
	bsr.l	timer		;wait a while
	endm
;ญญญญญญญญญญญญญญญญญStatementsญญญญญญญญญญญญญญญญญญญญญญ
	Bootstart	=	$20000
;ญbootstart=address of bootloader - may be changed!ญ

;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ
	Buffer		=	Bootstart+$4000
;ญbuffer=address of your decoded program - !!!DON'T DECREASE IT!!!ญ
;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ

	Amount		=	22
;ญamount of tracks to read - may be changed, of course!

	first_track	=	26
;ญfirst track to read - may be changed, too!
;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ

		org	$40000	;$40000 should work without 1MB, too.
		load	$40000

start_boot:
	dc.b	"DOS",0		;DOS id 
	dc.l	0		;space for checksum
	dc.l	$370		;pointer to rootblock
;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ
	movem.l	d0-d7/a0-a6,-(a7)
	lea	bootstart,a0	;copy bootblock to bootstart (s. above)
	lea	start_boot(pc),a1
	move.w	#$ff,d7		;copy 1024 bytes
copy_boot:
	move.l	(a1)+,(a0)+
	dbf	d7,copy_boot
	jmp	bootstart+[start-start_boot] ;jump in loader
;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ
;Here the loading-routine...

S:
Start:
	lea	$dff000,a6	;coustom base
	lea	s(pc),a5	;addressoffset (bootblock MUST be pc-
				;relative)

	move.w	$01c(a6),oldint-s(a5)
	ori.w	#$8000,oldint-s(a5)
	move.w	$002(a6),olddma-s(a5)
	ori.w	#$8000,olddma-s(a5)
	move.w	$010(a6),oldadk-s(a5)
	ori.w	#$8000,oldadk-s(a5)
	move.w	#$7fff,d0
	move.w	d0,$096(a6)	;switch dma's off
	move.w	d0,$09a(a6)	;forbid interrupts
	move.w	d0,$09c(a6)	;clear intreq
	move.w	d0,$09e(a6)	;clear adkcon

	color	0		;background color while loading
	move.w	#$8210,$96(a6)	;diskdma on!

;select DRIVE:	  3210
	moveq	#%0001,d0	;set right bit for drive 0,1,2 or 3
	bsr.l	select_drive	;select drive from which you want to read

	bsr.l	motor_on	;drivemotor on

	moveq	#0,d0		;move track number ->d0
	bsr.l	head_pos	;move head to track 0 (orientation)

	bsr.l	init_read	;init diskregisters
;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ
	move.w	#Amount,trackct-s(a5);set trackcounter
;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ

Load_tracks:
	bchg	#1,$bfe001	;switch led on/off each cylinder
	move.w	track(pc),d0	;move head to starttrack
	bsr.l	head_pos
	bsr.l	test_disk	;check if disk in drive
;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ
	bsr.l	read_track	;read track
	bsr.l	decode_track	;decode track
;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ
	addq.w	#1,track-s(a5)	;next track (add/sub=increase/decrease)
	subq.w	#1,trackct-s(a5);decrease trackcounter
	bne.s	load_tracks
;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ
	bsr.l	Motor_off	;drivemotor off
	move.l	bufferpt2(pc),a0;change jump in-address at bufferpt2
	jsr	(a0)		;jump in loaded program
Exit:
	move.w	Olddma(pc),$096(a6)
	move.w	Oldint(pc),$09a(a6)
	move.w	Oldadk(pc),$09e(a6)
	movem.l	(a7)+,d0-d7/a0-a6

;Here the normal bootroutine is following. But please notice that it's
;now impossible for the operating-system to access its disk operations
;correctly, because we used the hardware in that direct way without
;permission of the operating-system. That's the reason why you'll see
;a 'not a DOS disk'-requester after returning from the loader. So you
;see that it would be better to jump into the reset-routine instead 
;of accessing the following 'find resident'-routine. 

;Reset your AMIGA...
;	move.l	$4.w,a6
;	clr.l	38(a6)		;destroy chkbase to force...
;	move.l	#$fc00d2,$80.w
;	trap	#0		;...cold reset

;...or be stupid and try the normal boot-procedure.
	move.l	$4.w,a6
	lea     Dosname(pc),a1
	jsr 	-96(a6)		;FindResident()
	move.l 	d0,a0
	move.l 	22(a0),a0
	moveq	#0,d0
	Rts

dosname:dc.b	"dos.library",0
olddma:	dc.w	0
oldint:	dc.w	0
oldadk:	dc.w	0
track:	dc.w	first_track
trackct:dc.w	0		;trackcounter

Init_Read:
	clr.w	$24(a6)		;DSKLEN->forbid diskdma and writing
	move.w	#$4489,$7e(a6)	;set standard SYNC
	move.w	#$7f00,$9e(a6)	;clear ADKCON
	move.w	#$9500,$9e(a6)	;set required bits
	move.w	#$0002,$9c(a6)	;clear DSKBLK bit
	Rts

Read_Track:
	clr.w	$24(a6)		;DSKLEN->forbid diskdma
	lea	trackbuff(pc),a0
	move.l	a0,$20(a6)	;set DSKPTH and DSKPTL
	move.w	#$9a00,$24(a6)	;enable diskdma and set amount of
	move.w	#$9a00,$24(a6)	;words+2 to transfer.

Wait_Dma:
	btst	#1,$1f(a6)	;DSKBLK=0 ?
	beq.s   Wait_Dma	;yeah=> wait
	clr.w	$24(a6)		;forbid writing
	move.w  #$0002,$9c(a6)	;clear DSKBLK
	Rts

;ญTimer A-delay
timer:				;waits ca. 1/100 sec.
	move.b	#$00,$bfde00	;clear CRA
	move.b	#$7f,$bfdd00	;clear ICR
	move.b	#$00,$bfd400	;timer a -low
	move.b	#$20,$bfd500	;timer a -high (wait-value=$2000)
	move.b	#$09,$bfde00	;set oneshot/start
wait_timer:
	btst	#0,$bfdd00	;test ta-bit/that clears ICR
	beq.s	wait_timer
	rts

Wait_ready:
	btst	#5,$bfe001	;wait for DRIVEREADY
	bne.s	Wait_ready	;it's useless here, because the wait-
	Rts			;loop is long enough, but......

test_disk:
	btst	#2,$bfe001
	beq.s	error
	Rts
error:	move.w	$dff006,$dff180
	bra.s	error

Select_Drive:
	lea	floppystatus(pc),a0
	lea	motorstatus(pc),a1
	moveq	#-1,d1		;$ffffffff -> d1
	lsl.w	#3,d0		;shift selectbit to right position
	eor.b	d0,d1		;selectbit must be zero
	move.b	d1,(a0)		;save byte ->floppystatus.b
	eori.b	#$80,d1		;clear DSKMOTOR-bit
	move.b	d1,(a1)		;save byte ->motorstatus.b
	Rts

Motor_On:
	move.b	#$7f,$bfd100	;Bits 0-6 HIGH/Bit 7 LOW
	nop
	nop
	move.b	motorstatus(pc),d0
	move.b	d0,$bfd100	;DSKMOTOR and DSKSELx LOW
	bsr.l	Wait_Ready
	Rts

Motor_Off:
	move.b	#$ff,$bfd100	;Bits 0-7 HIGH
	nop
	nop
	move.b	motorstatus(pc),d0
	ori.b	#$80,d0		;DSKMOTOR HIGH DSKSELx LOW
	move.b	d0,$bfd100
	Rts

;This routine moves the r/w-head to a track with the number stored
;in d0. A similar routine is also used by the operating-system
;(at $fea3da)

Head_Pos:
	lea	$bfd100,a0
	lea	s(pc),a5
	tst.w	d0			;track number=0?
	beq.l	Move_zero		;yeah=>step to track 0
	move.w	Tracknum(pc),d2		;current track number
	cmp.w	d2,d0			;oldtrack=newtrack ?
	beq.s	Head_end		;yes=>don't move head
	move.w	d0,d3
	move.b	Floppystatus(pc),d1
	bset	#2,d1			;select head 0 (lower side)
	btst	#0,d3			;track number even ?
	beq.s	Down_Right		;yes=>head 0 is the right one
	bclr	#2,d1			;no, select head 1 (upper side)
Down_Right:
	move.b	d1,Floppystatus-s(a5)
	move.b	d1,(a0)
	move.w	d3,Tracknum-s(a5)	;save new track-number
	lsr.w	#1,d2			;d2=current cylinder
	lsr.w	#1,d3			;d3=new cylinder
	sub.w	d3,d2			;make difference
	bmi.s	Seek_in			;diff. negativ=> step in
	beq.s	Head_end
	bra.s	Seek_out		;diff. positiv=> step out
Seek_in:
	bclr	#1,d1			;step in
	move.b	d1,Floppystatus-s(a5)
	neg.w	d2			;make number positive
	bra.s	Step_Ok
Seek_out:
	bset	#1,d1			;step out
	move.b	d1,Floppystatus-s(a5)
	bra.s	Step_Ok
HeadStep:
	Step				;call step-macro
Step_Ok:
	dbf	d2,HeadStep
Head_end:
	Rts	

Move_zero:				;move head to track zero
	move.b	Floppystatus(pc),d1
	bset	#2,d1
	bset	#1,d1
	move.b	d1,Floppystatus-s(a5)
	clr.w	Tracknum-s(a5)
Headzero:
	btst	#4,$bfe001		;test if zero
	beq.s	zero1
	Step
	bra.s	Headzero
zero1:
	bclr	#1,Floppystatus-s(a5)
	Step
	bset	#1,Floppystatus-s(a5)
	Step
	bra.s	Head_end

;ญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญญ
;This routine decodes the block-header and checks the format-sign.
;After this it calculates the checksum from the data-block and
;compares it with the checksum wich is stored in the block-header.
;While calculating the checksum it decodes the data block, of course.

decode_track:
	move.l	bufferpt(pc),a0		;pointer to decodebuffer
	lea	trackbuff(pc),a1	;pointer to MFMbuffer
	moveq	#11-1,d5		;decode 11 blocks (-1 coz dbf)
	move.l	#$55555555,d3		;filter for tactbits

decode_all_blocks:
	cmpi.w	#$4489,(a1)+		;1st sync-word found ?
	bne.s	decode_all_blocks	;no=> go on searching

sync_found:
	cmpi.w	#$4489,(a1)		;2. sync-word found ?
	bne.s	syncs_ok		;no=> all syncs skipped
	addq.w	#2,a1			;yes=>
	bra.s	sync_found		;search for remaining syncs

syncs_ok:				;decode infoblock
	move.l	(a1)+,d0		;odd bits
	move.l	(a1)+,d1		;even bits
	and.l	d3,d0
	and.l	d3,d1
	add.l	d0,d0
	or.l	d1,d0

	swap	d0
	andi.w	#$ff00,d0		;mask format-sign (must be $ff)
	cmpi.w	#$ff00,d0		;right value?
	bne.s	formatrerror		;no==>ERROR!
	swap	d0

	andi.w	#$ff00,d0		;mask sector number*256
	add.w	d0,d0			;d0=d0*2 (=sector number*512)
	move.l	a0,a2			;address of decodebuffer ->a2
	adda.w	d0,a2			;calc. correct destination

	adda.w	#40,a1			;address of checksum ->a1
	move.l	(a1)+,d4		;decode checksum
	move.l	(a1)+,d1
	and.l	d3,d4
	and.l	d3,d1
	add.l	d4,d4
	or.l	d1,d4			;store checksum ->d4

	moveq	#128-1,d6		;decode 128*2 longs to 512 bytes 
	moveq	#0,d2			;clear datachecksum

decodeblock:				;decode datablock
	move.l	512(a1),d1		;even bits
	move.l	(a1)+,d0		;odd bits

	eor.l	d0,d2			;calc checksum
	eor.l	d1,d2			;dito

	and.l	d3,d0			;decode longword
	and.l	d3,d1
	add.l	d0,d0
	or.l	d1,d0
	move.l	d0,(a2)+		;store longword in buffer
	dbf	d6,decodeblock		;decode next longword

	and.l	d3,d2			;remove tactbits
	cmp.l	d4,d2			;checksum correct ?
	bne.s	chksumerror		;no=>ERROR!
	adda.w	#512,a1			;reach next block
	dbf	d5,decode_all_blocks

	adda.w	#$1600,a0		;bufferadr.+ 1track (5632bytes)
	move.l	a0,bufferpt-s(a5)	;store new address
	Rts

chksumerror:
	color		$f00		;backgroundcolor red
	st		chkflag-s(a5)	;set errorflag to -1
	Rts

formatrerror:
	color		$f00		;backgroundcolor red
	st		hdrflag-s(a5)	;set errorflag to -1
	Rts

tracknum:	dc.w	0
floppystatus:	dc.b	0
motorstatus:	dc.b	0
chkflag:	dc.b	0
hdrflag:	dc.b	0
bufferpt:	dc.l	buffer
bufferpt2:	dc.l	buffer		;here you can change the jump-
					;in address of your prog.
		dc.b	"ญ Loader by Duke of LEVEL FOUR - ASD ญ"
Even
trackbuff:
endprg:
		blk.b	200,0 ;just to clear remaining bytes in mem
