


    *** BootLoader.S by Photon ***	;NOTE: PC-relative code is PREFERRED.

;To write to disk in Asm-One, use the command WS0 Boot 0 2 followed by CC0

LoaderVars	=$100			;Useful variables, see CPUinfo:
Loader		=$120			;start of load script

MyUserStack=$7fffc			;SSP is at a safe place, but set user
					;stack.

MFMsync	=$4489				;AmigaDOS standard sync marker.
MFMlen	=12980				;Legacy trackdata read length in bytes

ShortWt:MACRO				;CPU-independent nop;nop replacement
	tst.w (a6)
	ENDM

    *** Boot Block starts here ***

Boot:	dc.b 'DOS',0
	dc.l 0,880

BootCode:	;gathers some data, turns off OS, copies itself to $100

    *--- Fetch system info ---*

	move.l 4.w,a6			;execbase (will soon be destroyed)
	move.l 294(a6),d4		;CPUinfo in lowest byte for your use.
	sub.l a4,a4			;VBR will always be 0 when booting
					;from floppy. No GetVBR needed.
    *--- Fastmem available? ---*

	move.l #$20004,d1		;fast+largest
	jsr -216(a6)			;AvailMem()
	move.l d0,d5
	sub.l #2048,d5			;leave room for stacks to grow
	moveq #4,d1
	jsr -198(a6)			;AllocMem()
	and.l #-8,d0
	move.l d0,a5			;Start Address

    *--- OS off ---*			;you're nice'n all, but now you die.

	lea $dff002,a6			;Loader uses this custom base addr

	tst.w (a6)			;wait out blitter
.wblit:	btst #6,(a6)
	bne.s .wblit

	move.l #$7fff7fff,d1
	move.l d1,$9a-2(a6)		;disable interrupts & req
	move.w d1,$9c-2(a6)		;play it again Sam
	sub.w #$20,d1			;don't affect Sprite DMA until Vblank
	move.w d1,$96-2(a6)		;disable DMA

	lea MyUserStack,a7		;some safe place compatible with 
					;platform requirements
    *--- Copy rest of code/data to fixed address ---*

	lea CopyStart(PC),a0
	lea (LoaderVars).w,a1
	moveq #(BootE-CopyStart)/8,d2
.copyl:	move.l (a0)+,(a1)+
	move.l (a0)+,(a1)+
	dbf d2,.copyl
	JMP (Loader).w			;Info from Exec passed in 4 registers

********************  $100.w  ********************

CopyStart:

CPUinfo:	dc.l 0			;$100
FastMemSize:	dc.l 0			;$104
SysVBR:		dc.l 0			;$108
FastMemStart:	dc.l 0			;$10c

MFMcyl:		dc.w 0
MFMhead:	dc.w 0
MFMdrv:		dc.w 0
MFMchk:		dc.l 0

		dc.w 0			;reserved for your use.

LoadVector:	bra.w LoadMFMB		;for external calls, JSR ($11c).w

LoadScript:				;At $120, sysinfo in 4 regs, a6=$dff002
	lea CPUinfo(PC),a3		;Use this for PC-rel in a pinch.
	movem.l d4/d5/a4/a5,(a3)
	bsr.s WaitEOF
	lea NullCop(PC),a0
	move.l a0,$80-2(a6)		;blank copper
	move.w #$87d0,$96-2(a6)		;enable DMA (sprites enabled when used)

    *--- load first part ---*

	lea $42000,a0			;to dest addr
	moveq #2,d0			;from sector 2
	move.w #-9,d1			;load 9 sectors (- to trigger Step0)
	jsr ($11c).w			;call LoadVector, and return when done.
	lea $dff000,a6			;restore plain custombase addr for demo
	JMP (a0)			;start demo.

;or use JSR and continue loading script here.


    *** MFMLoader.S by Photon ***	;requires a6=$dff002

WaitEOF:
	btst #0,5-2(a6)
	beq.s WaitEOF
.w1:	cmp.b #$37,6-2(a6)
	bne.s .w1
.w2:	cmp.b #$37,6-2(a6)		;wait for last PAL line, $138
	beq.s .w2
	rts

LoadMFMB:		;load sectors.a0=dst,d0=startsec.W,d1=nrsecs.W(-=Step0)
	MOVEM.L D0-D7/A0-A6,-(SP)
	lea $bfd100,a4
	bsr MotorOn
	tst.w d1			;if neg length,then Step0 first
	bpl.s .NoSt0
	neg.w d1
.St0:	btst #4,$f01(a4)		;head on cyl 0?
	beq.s .Rdy0
	bsr.s StepOut
	bra.s .St0
.Rdy0:	lea MFMcyl(PC),a1
	clr.w (a1)
.NoSt0:	and.l #$ffff,d0
	divu #22,d0			;startcyl
	sub.w MFMcyl(PC),d0		;delta-step
	beq.s .StRdy
	bmi.s .StOut
	subq.w #1,d0
.StIn:	bsr.s StepIn
	dbf d0,.StIn
	bra.s .StRdy
.StOut:	not.w d0			;=neg+sub#1
.StOutl:bsr.s StepOut
	dbf d0,.StOutl
.StRdy:	swap d0				;startsec within cyl
	cmp.w #11,d0
	blt.s .Head0
	sub.w #11,d0
	bra.s .Head1
.Head0:	bset #2,(a4)
	lea MFMhead(PC),a1
	clr.w (a1)
	bsr LoadTrak			;read track+decode
	beq.s .End
.Head1:	bclr #2,(a4)			;Head 1
	lea MFMhead(PC),a1
	move.w #1,(a1)
	bsr LoadTrak			;read track+decode
	beq.s .End
	bsr.s StepIn			;1 cyl forward
	bra.s .Head0
.End:	bsr.s MotorOff
	MOVEM.L (SP)+,D0-D7/A0-A6
	RTS

StepOut:
	bset #1,(a4)
	lea MFMcyl(PC),a1
	subq.w #1,(a1)
	ShortWt
	bclr #0,(a4)
	ShortWt
	bset #0,(a4)
	bsr.s StepWt
	RTS

StepIn:
	bclr #1,(a4)
	lea MFMcyl(PC),a1
	addq.w #1,(a1)
	ShortWt
	bclr #0,(a4)
	ShortWt
	bset #0,(a4)
	bsr.s StepWt
	RTS

StepWt:
	moveq #67,d6			;wait >3 ms
LeaveLine:
.loop1:	move.b 6-2(a6),d7
.loop2:	cmp.b 6-2(a6),d7
	beq.s .loop2
	dbf d6,.loop1
	RTS

MotorOn:
	move.w MFMdrv(PC),d7
	addq.w #3,d7
	or.b #$78,(a4)
	bset d7,(a4)
	ShortWt
	bclr #7,(a4)			;turns motor on
	ShortWt
	bclr d7,(a4)
	ShortWt
.DiskR:	btst #5,$f01(a4)		;wait until motor running
	bne.s .DiskR
	RTS

MotorOff:
	move.w MFMdrv(PC),d7
	addq.w #3,d7
	bset d7,(a4)
	ShortWt
	bset #7,(a4)
	ShortWt
	bclr d7,(a4)
	RTS

LoadTrak:		;load track+decode.a0=dst,d0=secoffs,d1=secsleft
	MOVE.W D0,-(SP)
	MOVE.W D1,-(SP)
	lea (MFMbuf).w,a1
	move.w #2,$9c-2(a6)		;Clr Req
	move.l a1,$20-2(a6)
	move.w #$8210,$96-2(a6)		;DskEna
	move.w #MFMsync,$7e-2(a6)
	move.w #$9500,$9e-2(a6)
	move.w #$4000,$24-2(a6)
	move.w #$8000+MFMlen/2,$24-2(a6)	;DskLen(12980)+DmaEn
	move.w #$8000+MFMlen/2,$24-2(a6)	;start reading MFMdata
.Wrdy:
	btst #1,$1f-2(a6)		;wait until data read
	beq.s .Wrdy
	move.w d0,d2
	add.w d1,d2			;highest sec# (d0=lowest)
	cmp.w #11,d2
	ble.s .NoOvr
	moveq #11,d2
.NoOvr:	sub.w d0,d2			;nrsecs
	move.l #$55555555,d3		;and-const
	move.w d2,d1
	subq.w #1,d1			;loopctr
.FindS:	cmp.w #MFMsync,(a1)+		;search for a sync word
	bne.s .FindS
	cmp.b (a1),d3			;search for 0-nibble
	bne.s .FindS
	move.l (a1)+,d4			;decode fmtbyte/trk#,sec#,eow#
	move.l (a1)+,d5
	and.w d3,d4
	and.w d3,d5
	add.w d4,d4
	or.w d5,d4
	lsr.w #8,d4			;sec#
	sub.w d0,d4			;do we want this sec?
	bmi.s .Skip
	cmp.w d2,d4
	blt.s .DeCode
.Skip:	lea 48+1024(a1),a1		;nope
	bra.s .FindS
.DeCode:lea 40(a1),a1			;found a sec,skip unnecessary data
	move.l a1,d6
	lea MFMchk(PC),a1
	clr.l (a1)
	move.l d6,a1
	move.l (a1)+,d6			;decode data chksum.L
	move.l (a1)+,d5
	and.l d3,d6
	and.l d3,d5
	add.l d6,d6
	or.l d5,d6			;chksum
	lea 512(a1),a2
	add.w d4,d4			;x512
	lsl.w #8,d4
	lea (a0,d4.w),a3		;dest addr for this sec
	moveq #127,d7
.DClup:	move.l (a1)+,d4
	move.l (a2)+,d5
	and.l d3,d4
	and.l d3,d5
	eor.l d4,d6			;EOR with checksum
	eor.l d5,d6			;EOR with checksum
	add.l d4,d4
	or.l d5,d4
	move.l d4,(a3)+
	dbf d7,.DClup			;chksum should now be 0 if correct
	lea MFMchk(PC),a1
	or.l d6,(a1)			;or with track total chksum
	move.l a2,a1
	dbf d1,.FindS			;decode next sec
	MOVE.W (SP)+,D1
	MOVE.W (SP)+,D0
	move.l MFMchk(PC),d3		;track total chksum OK?
	bne LoadTrak			;no,retry
	moveq #0,d0			;set to start of track
	move.w d2,d3
	add.w d3,d3
	lsl.w #8,d3
	add.w d3,a0
	sub.w d2,d1			;sub #secs loaded
	RTS

NullCop:
	dc.w $1fc,0
	dc.w $100,$0200
	dc.w $96,$0020			;ensure sprite DMA is off until needed
	dc.w $ffdf,$fffe
	dc.l -2
BootE:

    *** Boot Block ends here ***

	dc.b "BootLoader by Photon/Scoopex"	;pad with random bytes
	blk.b 1024,0

;MFMbuf is placed here after bootblock end, $3c0.w or so when copied.

MFMbuf	=LoaderVars+(BootE-CopyStart)
MFMbufE	=MFMbuf+MFMlen	;lowest free address. $372e for a full bootblock.

	END

