*************************************************
******************** BigBoot ********************
************** von Michael Göckel ***************
********* Markt&Technik  68oooer 1987 ***********
*************************************************

ExecBase:	EQU	4

AllocSignal:	EQU	-$14a
FindTask:	EQU	-$126
FreeSignal:	EQU	-$150
AllocMem:	EQU	-$C6
FreeMem:	EQU	-$D2
AddPort:	EQU	-$162
RemPort:	EQU	-$168
OpenDevice:	EQU	-$1bc
CloseDevice:	EQU	-$1c2
DoIO:		EQU	-$1c8
WaitIO:		EQU	-$1d8
Alert:		EQU	-$6c
CloseLibrary:	EQU	-$19e
OpenLibrary:	EQU	-$228

Open:		EQU	-$1e
Close:		EQU	-$24
Read:		EQU	-$2a
Write:		EQU	-$30
Input:		EQU	-$36
Output:		EQU	-$3c
Lock:		EQU	-$54
Examine:	EQU	-$66

FIBSize:	EQU	300
FileSize:	EQU	124

**************** Disk Commands *****************

CMD_Reset:	EQU	1
CMD_Read:	EQU	2
CMD_Write:	EQU	3
CMD_UpDate:	EQU	4
CMD_Clear:	EQU	5
CMD_Stop:	EQU	6
CMD_Start:	EQU	7
CMD_Flush:	EQU	8
TD_Motor:	EQU	9
TD_Seek:	EQU	10
TD_Format:	EQU	11
TD_Remove:	EQU	12
TD_ChangeNum:	EQU	13
TD_ChangeState:	EQU	14
TD_ProtStatus:	EQU	15

************** ExtIORequest Offsets ************

io_Command:	EQU	28
io_Error:	EQU	30
io_Actual:	EQU	32
io_Length:	EQU	36
io_Data:	EQU	40
io_Offset:	EQU	44

**************** Magic Variables ***************
BlockLongPos:	EQU	$B8

start:
	move.l	ExecBase,a6
	move.l	#DosName,a1
	clr.l	d0
	jsr	OpenLibrary(a6)
	move.l	d0,DosBase
	beq	NoDos
	move.l	#Welcome,a0
	bsr	print
	move.l	#Quest1,a0
	bsr	print
	move.l	BootName,a0
	bsr	print
	move.l	#Quest2,a0
	bsr	print
	bsr	GetChars
	move.b	#0,-1(a0,d0)	; Return löschen
	cmp.w	#1,d0
	bne	default
	move.l	BootName,a0	
default:
	move.l	#1024,d1	; Minimalgröße wegen Checksum
	bsr	GetFile
	move.l	d0,FileOrt
	move.l	d1,FileLength
	beq	NoFile
	add.w	#511,d1		; ueber nächste Sektorgrenze
	lsr.l	#8,d1
	lsr.l	#1,d1
	sub.w	#2,d1		; Zwei Sektoren sind ja schon
	cmp.w	#0,d1
	bgt	ok
	move.w	#0,d1
ok:
	move.w	d1,FileSects	; reserviert (0 & 1)
	move.l	#Quest3,a0
	bsr	print
	bsr	GetChars
	move.l	#0,d0
	bsr	GetTrackDisk
	move.l	ExecBase,a6
	move.l	#$0800,d0	; 4 Blöcke
	move.l	#$10001,d1
	jsr	AllocMem(a6)
	move.l	d0,TDBuffer
	bne	goon1
	move.l	#NoTDMem,a0
	bsr	print
	bra	cleanup3
goon1:
	bsr	MotorOn
	move.l	TDBuffer,a0
	move.l	#1024,d0
	move.l	DiskRequest,a1
	move.l	#880,d1
	bsr	DRead
	move.l	TDBuffer,a0
	add.l	#$13C,a0
	move.l	(a0),d1
	move.l	d1,BitMapSektor
	add.l	#$2C4,a0
	move.l	DiskRequest,a1
	move.l	#$400,d0
	bsr	DRead
	move.l	TDBuffer,a0
	add.l	#$400,a0
	move.l	4(a0),d0
	move.w	#0,d1		; Test ab dem 1.Sektor
	clr.l	d2
	move.l	#2,d3		; ab Bit 2 ändern
	move.l	#3,d4		; bit 0 und 1 gesetzt
	move.w	FileSects,d5	; wieviele brauche ich ?
secloop:
	btst	d1,d0
	beq	nomore
	cmp.w	d5,d2		; hab ich schon genug ?
	bhs	hab_genug
	bclr	d1,d0		; wenn ich ihn brauche, reservieren
	bset	d3,d4		; und markieren in BlockLong
hab_genug:
	add.l	#1,d2
nomore:
	addi.w	#1,d1
	addi.w	#1,d3
	cmp.w	#20,d1
	blt	secloop
	move.l	d0,4(a0)
	move.w	d2,Tracksects
	move.l	d4,BlockLong
	move.l	#MengeMsg,a0
	bsr	print
	clr.l	d0
	move.w	tracksects,d0
	bsr	ItoA
	bsr	print
	move.l	#Menge2Msg,a0
	bsr	print
	move.w	TrackSects,d2
	cmp.w	Filesects,d2
	bhi	goon2
	move.l	#StillUsed,a0
	bsr	print
	bra	Cleanup4
goon2:
	move.l	FileOrt,a0	; Anfang der Daten
	move.l	BlockLong,d4	; belegte Blocks
	move.l	d4,BlockLongPos(a0) ; in den Bootblock schreiben
	bsr	BootblockChecksum
	move.l	#$200,d0	; Blocklänge
	move.l	#$0,d1		; Offset
	clr.l	d3
wrloop:
	bclr	d3,d4
	beq	dontwrite
	bsr	DWrite		; dieser Block wird geschrieben
	bne	cleanup4	; ein Fehler während DWrite
	add.l	#$200,a0	; nächster Block
dontwrite:
	add.w	#1,d3
	add.l	#$200,d1	; nächster Block
	tst.l	d4		; noch nicht 0
	bne	wrloop		; dann noch Blocks zu schreiben
	jsr	DUpDate		; nun Track auf die Disk
	move.l	TDBuffer,a0
	add.l	#$400,a0
	bsr	BitMapChecksum
	move.l	BitMapSektor,d1	; SektorNummer
	move.l	#512,d0		; Länge des Sektors
	lsl.l	#8,d1		; *256
	lsl.l	#1,d1		; *2
	bsr	DWrite		; Data noch in a0
	bne	cleanup4	; ein Fehler während DWrite
	bsr	DUpDate
	move.l	#GoodInstall,a0
	bsr	print
cleanup4:
	bsr	MotorOff
cleanup3:
	move.l	ExecBase,a6
	move.l	TDBuffer,a1
	move.l	#$0800,d0
	jsr	FreeMem(a6)
	move.l	ExecBase,a6
	move.l	FileOrt,a1
	move.l	FileLength,d0
	jsr	FreeMem(a6)
	move.l	DiskRequest,a1
	bsr	CloseTrackDisk
NoFile:
	move.l	ExecBase,a6
	move.l	DosBase,a1
	jsr	CloseLibrary(a6)
NoDos:
	move.l	oldcheck,d0
	move.l	newcheck,a0
;	ILLEGAL
	clr.l	d0
	rts
FileOrt:	DC.L	0
FileLength:	DC.L	0
FileSects:	DC.W	0
TrackSects:	DC.W	0
BitMapSektor:	DC.L	0
TDBuffer:	DC.L	0
BlockLong:	DC.L	0
BootName:	DC.L	BN
BN:		DC.B	"df1:boottrack",0
even
************** BootblockChecksum ***************
** --> a0 = Zeiger auf den Bootblock     <-- **
***********************************************
BootblockChecksum:
	movem.l	d0-d3/a0-a1,-(a7)
	clr.l	d0
	clr.l	d2
	clr.l	d3
	move.l	#$FF,d1		; 256 Longwords summieren
	move.l	a0,a1		; Anfangsadresse sichern
	clr.l	$4(a0)		; alte Checksumme löschen
	move.w	#$4,CCR		; Z Bit setzen, X Bit löschen
bo_Checkloop:
	move.l	(a0)+,d2	; Longword holen
	addx.l	d2,d0		; mit Carry addieren
	dbra	d1,bo_Checkloop
	move.l	#-1,d1
	subx.l	d0,d1
	move.l	d1,$4(a1)	; und Checksumme in den Bootblock
	move.l	d1,test
	movem.l	(a7)+,d0-d3/a0-a1
	rts

************** BitMapCheckSum **************
** --> a0 = Basisadresse der BitMap   <-- **
********************************************
BitMapChecksum:
	movem.l	d0-d3/a0-a1,-(a7)
	clr.l	d0
	clr.l	d2
	clr.l	d3
	move.l	a0,a1
	move.l	(a0),oldcheck	; zum testen
	clr.l	(a0)
	move.w	#$7F,d1		; hier nur 512 Bytes testen
bm_Checkloop:
	move.l	(a0)+,d2
	sub.l	d2,d0
	dbra	d1,bm_Checkloop
	move.l	d0,(a1)		; in die BitMap schreiben
	move.l	d0,newcheck	; zum testen
	movem.l	(a7)+,d0-d3/a0-a1
	rts

************** ItoA **************
**     d0 = Integer Zahl    <-- **
** --> a0 = ASCII String        **
**********************************
ItoA:
	move.l	#ASCII_Zahl+6,a0
	move.l	#0,-4(a0)	; String clearen
	move.w	#0,-6(a0)	; zweiter Teil
w_loopi:
	divu	#10,d0		; Nachkommastelle = 1.Stelle
	swap	d0
	addi.w	#"0",d0
	move.b	d0,-(a0)
	clr.w	d0
	swap	d0
	cmp.w	#0,d0
	bne	w_loopi
	rts
even				; even, damit move.l funktioniert
ASCII_Zahl:	blk.b	7,0

even
*********** Track Disk SubRoutines *************

************** MotorOn & MotorOff **************
**     a1 = Initialisierter ExtIORequest <-- ***
************************************************
MotorOn:
	move.l	DiskRequest,a1
	move.w	#TD_Motor,io_Command(a1)
	move.l	#1,io_Length(a1)
	move.l	ExecBase,a6
	jsr	DoIO(a6)
	rts
MotorOff:
	move.l	DiskRequest,a1
	move.w	#TD_Motor,io_Command(a1)
	move.l	#0,io_Length(a1)
	move.l	ExecBase,a6
	jsr	DoIO(a6)
	rts
DCheckWP:
	movem.l	d0-d7/a0-a6,-(a7)
	move.l	DiskRequest,a1
	move.w	#TD_Protstatus,io_Command(a1)
	move.l	ExecBase,a6
	jsr	DoIO(a6)
	move.l	DiskRequest,a1
	move.l	io_Actual(a1),d0
	movem.l	(a7)+,d0-d7/a0-a6
	rts

******************* Disk Read ******************
* a1 = Zeiger auf                              *
*      Initialisierte ExtIOReqest Struktur <-- *
* a0 = Zeiger auf Buffer                   <-- *
* d0 = Laenge des Buffers (bzw. Reads)     <-- *
* d1 = SektorNummer                        <-- *
************************************************
DRead:
	lsl.l	#8,d1
	lsl.l	#1,d1
	move.w	#CMD_Read,io_Command(a1)
	move.l	d1,io_Offset(a1)
	move.l	a0,io_Data(a1)
	move.l	d0,io_Length(a1)
	move.l	ExecBase,a6
	jsr	DoIO(a6)
	rts	

even
************** DWrite **************
**     a0 = Anfang der Daten  <-- **
**     d0 = Laenge der Daten  <-- **
**     d1 = Offset            <-- **
************************************
DWrite:
	movem.l	d0-d7/a0-a6,-(a7)
	bsr	DCheckWP
	beq	NotProtected
	move.l	#WPon,a0
	bsr	print
	move.b	#1,d0		; Zero löschen
	bra	EndofWrite
NotProtected:
	move.l	DiskRequest,a1
	move.l	d1,io_Offset(a1)
	move.w	#CMD_Write,io_Command(a1)
	move.l	d0,io_Length(a1)
	move.l	a0,io_Data(a1)
	move.l	ExecBase,a6
	jsr	DoIO(a6)
	move.b	#0,d0		; Zero setzen
EndofWrite:
	movem.l	(a7)+,d0-d7/a0-a6
	rts

************** DUpDate *************
DUpDate:
	movem.l	d0-d7/a0-a6,-(a7)
	move.l	DiskRequest,a1
	move.w	#CMD_UpDate,io_Command(a1)
	move.l	ExecBase,a6
	jsr	DoIO(a6)
	movem.l	(a7)+,d0-d7/a0-a6
	rts

*************** GetTrackDisk **************
**     d0 = Unit (0=df0:,1=df1:)     <-- **
** --> a1 = ExtIORequest, 0 if error     **
*******************************************
GetTrackDisk:
	move.l	d0,Unit
	move.l	#0,a0		; kein Name
	move.b	#0,d0		; Priorität
	bsr	CreatePort
	move.l	a0,DiskPort
	beq	gt_fail1
	move.l	#56,d0
	bsr	CreateExtIO
	move.l	a0,DiskRequest
	beq	gt_fail2
	move.l	ExecBase,a6
	move.l	#DiskName,a0
	move.l	Unit,d0		; Unit 0
	move.l	DiskRequest,a1
	move.l	#0,d1		; Flags
	jsr	OpenDevice(a6)
	tst.l	d0
	bne	gt_fail3
	move.l	DiskRequest,a1
	rts
gt_fail1:
	move.l	#0,a1
	rts

*************** CloseTrackDisk ***************
**     a1 = Initialisierte ExtIORequest <-- **
**********************************************
CloseTrackDisk:
	move.l	a1,DiskRequest
	move.l	ExecBase,a6
	move.l	DiskRequest,a1
	jsr	CloseDevice(a6)
gt_fail2:
	move.l	DiskRequest,a0
	bsr	DeleteExtIO
gt_fail3:
	move.l	DiskPort,a0
	bsr	DeletePort
	move.l	#0,a1
	rts
Unit:		DC.L	0
DiskPort:	DC.L	0
DiskRequest:	DC.L	0
DiskName:	DC.B	"trackdisk.device",0
even
*******************************
*          Amiga Lib          *      
* Funktionen aus der AmigaLib *
*   für den Seka Assembler.   *
* Diese Funktionen werden für *
*  den Aufruf verschiedener   *
*       Devices benötigt.     *
*******************************
even
*********** Create Port ************
**     a0 = Zeiger auf Namen  <-- **
**     d0 = Prioritaet        <-- **
** --> a0 = MsgPort               **
************************************

CreatePort:
	move.l	a0,Name
	move.b	d0,Prio
	move.l	ExecBase,a6
	move.b	#-1,d0		; irgendein Signal allokieren
	jsr	AllocSignal(a6)
	move.b	d0,sigBit
	bmi.l	NoSignal
	move.l	ExecBase,a6
	move.l	#$10001,d1	; MEMF_CHIP | MEMF_PUBLIC
	move.l	#34,d0		; SizeOf(MsgPort)
	jsr	AllocMem(a6)
	move.l	d0,port
	beq	NoMemory
	move.l	d0,a0
	move.l	Name,10(a0)	; Name nach ln_Name
	move.b	Prio,9(a0)	; Prio nach ln_Prio
	move.b	#4,8(a0)	; Type MsgPort nach ln_Type
	move.b	#0,14(a0)	; PA_Signal nach mp_Flags
	move.b	sigBit,15(a0)	; sigBit nach mp_SigBit
	move.l	ExecBase,a6
	move.l	#0,a1
	jsr	FindTask(a6)
	move.l	d0,16(a0)	; Task nach mp_SigTask
	cmpi.l	#0,Name
	beq	doNewList
	move.l	ExecBase,a6
	move.l	port,a1
	jsr	AddPort(a6)
	bra.s	rts
doNewList:
	lea	20(a0),a0	; Zeiger auf mp_MsgList
	bsr	NewList		; Initialisieren
rts:
	move.l	port,a0		; Zeiger auf Port zurück
	rts
NoSignal:
	clr.l	port
	bra.s	rts
NoMemory:
	move.l	ExecBase,a6
	clr.l	d0
	move.b	sigBit,d0
	jsr	FreeSignal(a6)
	bra.s	NoSignal
even
port:		DC.L	0
sigBit:		DC.B	0
Prio:		DC.B	0
Name:		DC.L	0

*********** DeletePort ************
**     a0 = Zeiger auf Port  <-- **
***********************************
DeletePort:
	cmpi.l	#0,10(a0)
	beq	NoRemPort
	move.l	a0,-(a7)	; Zeiger auf Port sichern
	move.l	ExecBase,a6
	move.l	a0,a1
	jsr	RemPort(a6)
	move.l	(a7)+,a0	; Zeiger auf Port wiederholen
NoRemPort:
	move.b	#$FF,8(a0)	; ln_Type auf InRemove
	move.l	#-1,20(a0)	; mp_MsgList.lh_Head auf -1
	move.l	a0,-(a7)	; Port sichern
	move.l	ExecBase,a6
	clr.l	d0
	move.b	15(a0),d0
	jsr	FreeSignal(a6)
	move.l	ExecBase,a6
	move.l	(a7)+,a1	; Port wiederherstellen
	move.l	#34,d0		; SizeOf( MsgPort )
	jsr	FreeMem(a6)
	rts

*********** NewList ****************
**     a0 = Zeiger auf ListHead   **
************************************
LH_Tail:	EQU	4
LH_TailPred:	EQU	8

NewList:
	move.l	a0,(a0)			; LH_Head
	addq.l	#LH_Tail,(a0)		; auf LH_Tail zeigen
	clr.l	LH_Tail(a0)		; LH_Tail = 0
	move.l	a0,LH_TailPred(a0)	; auf LH_Head setzen
	rts

************* CreateExtIO **************
**     a0 = Zeiger auf ReplyPort  <-- **
**     d0 = Size des IORequests   <-- **
** --> a0 = Zeiger auf IORequest      **
****************************************

CreateExtIO:
	cmpi.l	#0,a0
	beq	NoReplyPort
	move.w	d0,Size
	move.l	a0,ReplyPort
	move.l	ExecBase,a6
	move.l	#$10001,d1	; MEMF_Clear | MEMF_Public
	jsr	AllocMem(a6)	; d0 enthaelt Size !!
	move.l	d0,a0		; ioReq nach a0
	beq	NoMemory2
	move.b	#5,8(a0)	; NT_MESSAGE nach ln_Type
	move.w	Size,18(a0)	; Size nach mn_Length
	move.l	ReplyPort,14(a0); ReplyPort nach mn_ReplyPort
	rts

NoReplyPort:
NoMemory2:
	move.l	#0,a0
	rts	
Size:		DC.W	0
ReplyPort:	DC.L	0

************** DeleteExtIO **************
**     a0 = Zeiger auf IORequest       **
*****************************************
DeleteExtIO:
	cmpi.l	#0,a0
	beq	rts2
	move.b	#$ff,8(a0)	; ln_Type auf InRemove
	move.l	#-1,20(a0)	; io_Device auf -1 setzen
	move.l	#-1,24(a0)	; IO_Unit auf -1 setzen

	move.l	Execbase,a6
	move.w	18(a0),d0	; mn_Length
	move.l	a0,a1		; IORequest freimachen
	jsr	FreeMem(a6)
rts2:
	rts

************** CreateStdIO **************
**     a0 = Zeiger auf ReplyPort   <-- **
** --> a0 = Zeiger auf IOStdRequest    **
*****************************************
CreateStdIO:
	move.l	#32,d0		; Länge des StdIORequests
	bsr	CreateExtIO
	rts

************** DeleteStdIO **************
**     a0 = Zeiger auf IORequest   <-- **
*****************************************
DeleteStdIO:
	bsr	DeleteExtIO
	rts

align 4
******** GetFile ************************
** a0 = Zeiger auf FileName        <-- **
** d1 = Minimalgroesse des Buffers <-- **
** --> d0 = Zeiger auf File            ** 
** --> d1 = FileLaenge                 ** 
***************************************** 
** Der Benutzer muß sich um das FreeMem 
** des Bereiches kümmern

GetFile:
	move.l	a0,FileName
	move.l	d1,Buffersize
	move.l	DosBase,a6
	move.l	FileName,d1
	move.l	#1005,d2
	jsr	Lock(a6)
	move.l	d0,FileLock
	beq	rts
	move.l	ExecBase,a6
	move.l	#FIBSize,d0
	move.l	#$10001,d1
	jsr	AllocMem(a6)
	move.l	d0,FileInfoBlock
	beq	arts
	move.l	DosBase,a6
	move.l	FileLock,d1
	move.l	FileInfoBlock,d2
	jsr	Examine(a6)
	cmpi.w	#0,d0
	beq	FreeFIB
	move.l	FileInfoBlock,a0
	move.l	FileSize(a0),d0
	addi.l	#16,d0			; Sicherheit !!
	cmp.l	Buffersize,d0
	blt	gross_genug
	move.l	d0,Buffersize
gross_genug:
	move.l	ExecBase,a6
	move.l	BufferSize,d0
	move.l	#$10003,d1
	jsr	AllocMem(a6)
	move.l	d0,Buffer
	beq	FreeFIB
	move.l	DosBase,a6
	move.l	FileName,d1	;File öffnen
	move.l	#1005,d2
	jsr	Open(a6)
	move.l	d0,Handle
	beq	FreeBuf
	move.l	DosBase,a6
	move.l	Handle,d1
	move.l	Buffer,d2
	move.l	BufferSize,d3
	jsr	Read(a6)
	cmpi.w	#0,d0
	beq	FreeBuf
CloseIt:
	move.l	DosBase,a6
	move.l	Handle,d1
	jsr	Close(a6)
FreeFIB:
	move.l	ExecBase,a6
	move.l	#FIBSize,d0
	move.l	FileInfoBlock,a1
	jsr	FreeMem(a6)
	move.l	Buffer,d0
arts:
	move.l	BufferSize,d1
	rts
FreeBuf:
	move.l	ExecBase,a6
	move.l	BufferSize,d0
	move.l	Buffer,a1
	jsr	FreeMem(a6)
	move.l	#0,Buffer
	bra	CloseIt
Handle:		DC.L	0
FileLock:	DC.L	0
FileInfoBlock:	DC.L	0
Buffer:		DC.L	0
BufferSize:	DC.L	0
DosBase:	DC.L	0
FileName:	DC.L	0
DosName:	DC.B	'dos.library',0

even
*************** Print **************
**     a0 = Zeiger auf String <-- **
************************************
print:
	move.l	a0,-(a7)
	move.l	DosBase,a6
	jsr	Output(a6)
	move.l	d0,d1
	move.l	(a7)+,a0
	move.l	a0,d2
	andi.w	#-2,d2
NullFind:
	tst.b	(a0)+
	bne.s	NullFind
	move.l	a0,d3
	sub.l	d2,d3
	move.l	DosBase,a6
	jsr	Write(a6)
	rts

*************** GetChars **************
**     a0 = Zeiger auf String    <-- **
** --> a0 = Zeiger auf Eingabe       **
** --> d0 = Laenge der Eingabe       **
***************************************
GetChars:
	move.l	DosBase,a6
	jsr	Input(a6)
	move.l	d0,d1
	move.l	#InBuffer,d2
	move.l	#80,d3
	move.l	DosBase,a6
	jsr	Read(a6)
	move.l	#InBuffer,a0
	rts

InBuffer:	blk.b	40,0

test:		DC.L	0
oldcheck:	DC.L	0
newcheck:	DC.L	0
even
NoTDMem:	DC.B	"Kann keinen Speicher für den Trackdisk-"
		DC.B	"Buffer allokieren !",10,0
even
StillUsed:	DC.B	"Tut mir leid, aber auf dieser Disk ist "
		DC.B	"kein Platz mehr für den Boot-Track!",10,0
even
Welcome:	DC.B	"BigBoot",10
		DC.B	"für Markt & Technik, 68oooer Magazin, von"
		DC.B	" Michael Göckel ",10
		DC.B	"Ich versuche die Installation ",10,0
Quest1:		DC.B	"Wie ist der Filename des zu installierenden"
		DC.B	" Files ?",10,"(Return = ",34,0
Quest2:		DC.B	34,")",10,0
Quest3:		DC.B	"Bitte legen Sie nun die Disk auf der ich"
		DC.B	" installieren soll in df0:",10
		DC.B	"und drücken Sie Return ",10,0
MengeMsg:	DC.B	"Auf dieser Disk sind ",0
Menge2Msg:	DC.B	" freie Sektoren. ",0
WPon:		DC.B	"Diskette ist schreibgeschützt!",10,0
GoodInstall:	DC.B	"Der BootTrack ist nun installiert,",10
		DC.B	"Viel Spaß damit ! ",10,0
