;	BootBlockBuster 'BBB' © 1990 by EHJ

;	Zeigt den Bootblock einer Diskette
;	Im INTERNEN Laufwerk (DF0:) an
;	Es werden nur Buchstaben ausgegeben, alle anderen
;	Zeichen werden durch '_' (Unterstrich) ersetzt
;	Zusätzlich Ausgabe des Diskettennamens und der
;	auf der Diskette freien Bytes

;	Start vom CLI: 'BBB' oder 'RUN BBB'
;	Start von Workbench durch Doppelklick

;	Nächste Diskette: Einfach einlegen
;           Programmende: Klick auf Closegadget

ExecBase=4

;---Funktionen aus exec.library
Forbid=-132
AllocMem=-198
FreeMem=-210
FindTask=-294
AddPort=-354
RemPort=-360
GetMsg=-372
ReplyMsg=-378
WaitPort=-384
OpenLib=-408
CloseLib=-414
OpenDev=-444
CloseDev=-450
DoIO=-456

;---Funktionen aus intuition.library
CloseWindow=-72
DrawBorder=-108
OpenWindow=-204

;---Funktionen aus graphics.Library
Text=-60
Move=-240
RectFill=-306
SetAPen=-342

;---Test, ob vom CLI oder von Workbench gestartet wurde
g:	move.l	a7,Stack	;Stack merken
	sub.l	a1,a1		;A1 auf 0
	move.l	ExecBase,a6
	jsr	FindTask(a6)	;eigenen Task suchen
	move.l	d0,Task		;und merken
	move.l	d0,a4		;Zeiger auf Task in A4
	tst.l	$ac(a4)		;ist 172. Byte <> 0 ?
	bne.s	vomCLI		;dann vom CLI gestartet

;---Es wurde von Workbench gestartet
	lea	$5c(a4),a0	;WB-Message
	jsr	WaitPort(a6)	;abwarten,
	jsr	GetMsg(a6)	;abholen
	move.l	d0,WBMessage	;und merken

;---Es wurde vom CLI gestartet
vomCLI:	bsr 	OpenAll		;alles öffnen
	cmp.w	#4711,d0	;Fehler ?
	beq	ENDE		;ja, Programm beenden

;---Hauptschleife
Haupt:	bsr	Loesch		;Fensterinhalt löschen
	bsr 	RootBlockLesen	;Root-Block lesen und ausgeben

;---Warte auf Ereignis
Loop:	bsr	Warte		;warte auf Ereignis
	cmp.w	#$200,d6	;WINDOWCLOSE ?
	bne.s	wLoop		;nein, weiter

	bra.s	AlleZu		;sonst Programm beenden

wLoop:	cmp.w	#$8000,d6	;DISKINSERTED ?
	beq.s	Haupt		;ja, Bootblock ausgeben

	cmp.l	#$10000,d6	;DISKREMOVED ?
	bne.s	Loop		;nein, weiter warten

;---'Diskette einlegen' ausgeben
	bsr	Loesch		;Lösche Fenster
	bsr	Weiss		;Schrift weiss
	move.l	#248,d0		;Cursor
	moveq	#50,d1		;auf x,y-Koordinaten
	bsr	Cursor		;setzen
	lea	LegeTxt,a0	;'Diskette einlegen'
	moveq	#17,d0		;17 Buchstaben
	bsr	Txt		;ausgeben

;---Rahmen um 'Diskette einlegen' zeichnen
	lea	Border,a1	;Rahmenstrukur nach A1
	moveq	#0,d0		;Koordinaten
	moveq	#0,d1		;auf 0
	move.l	IntBase,a6
	move.l	RastPort,a0	;Rahmen
	jsr	DrawBorder(a6)	;zeichnen

Loop5:	bsr	Warte		;Warte auf
	cmp.w	#$200,d6	;WINDOWCLOSE ?
	beq.s	AlleZu		;ja, BBB beenden

	cmp.w	#$8000,d6	;DISKINSERTED ?
	beq.s	Haupt		;ja, alles von vorn

	bra.s	Loop5		;sonst weiter warten

;---Programm beenden
AlleZu:	bsr	CloseAll	;Alles schließen

;---Programm endgültig beenden
ENDE:	tst.l	WBMessage	;Workbench-Message vorhanden ?
	beq.s	TUESS		;nein, weiter

	move.l	ExecBase,a6
	jsr	Forbid(a6)	;Multitasking abschalten
	move.l	WBMessage,a1	;Message
	jsr	ReplyMsg(a6)	;zurückschicken
TUESS:	move.l	Stack,a7	;Stack wieder herstellen
	moveq	#0,d0		;D0 löschen, dann
	rts			;ENDE UND AUS
;------------------------------------------------
;---UP - Root-Block (880) einlesen, Disknamen in 1.Zeile ausgeben
RootBlockLesen:
	bsr	Weiss		;Schrift weiss
	moveq	#60,d0		;Cursor auf
	moveq	#24,d1		;1.Zeile - x,y = 60,24
	bsr	Cursor		;setzen
	lea	Disk,a0		;'Disk-Name: '
	moveq	#11,d0		;11 Buchstaben
	bsr	Txt		;ausgeben
	move.l	#880,Block	;Block 880 (Root-Block)
	bsr	BlockLesen	;einlesen
	bsr	Rot		;Schrift rot
	move.l	Puffer,a0
	move.l	312(a0),MapOK	;BitMapBlock gültig ?
	move.l	316(a0),BitMap	;Zeiger auf BitMapBlock
	move.b	432(a0),d0	;Länge des Disk-Namens
	ext.w	d0		;D0 auf Wortlänge
	lea	433(a0),a0	;Adresse des Namens
	bsr	Txt		;Disk-Namen ausgeben

;---wenn BitMapBlock gültig, steht in MapOk $FFFFFFFF,
;   dann können freie Blocks/Bytes errechnet werden,
;   sonst sofort Boot-Block einlesen
	cmp.l	#$ffffffff,MapOK;BitMapBlock gültig ?
	bne	BootBl		;nein, keine Anzeige freier Bytes

	move.l	BitMap,Block	;BitMapBlock
	bsr	BlockLesen	;einlesen

;---Im BitMapBlock stehen alle belegten/freien Blöcke der Disk
;   LangWort 0 enthält die Checksumme des Blocks
;   Ab 4.Byte stehen 110 Worte, wobei bei Jedem ein gesetztes Bit
;   bedeutet, daß der Block frei ist:
;   110 (Worte) * 16 (Bits) = 1760 (GesamtBlöcke)
;   Freie Blöcke*488(Bytes pro Block)=freie Bytes der Diskette
	move.l	Puffer,a0
	move.l	(a0)+,d7	;A0 um 4 Bytes weiter (Checksumme)
	clr.l	FreiBlocks	;Zähler für freie Blöcke auf 0
	moveq	#109,d7		;110 Worte untersuchen
Loop2:	move.w	(a0)+,Wort	;1 Wort holen
	moveq	#15,d6		;16 Bittests je Wort
Bits:	rol.w	Wort		;1 Bit testen
	bcc.s	W1		;Bit = 0, dann nicht gesetzt

	addq.l	#1,FreiBlocks	;Bit = 1, dann Block frei	
W1:	dbra	d6,Bits		;alle 16 Bits untersucht?
	dbra	d7,Loop2	;alle 110 Wörter untersucht?

	move.l	FreiBlocks,d0	;Freie Blöcke
	mulu	#488,d0		;mal 488 Bytes je Block
	move.l	d0,FreiBlocks	;= freie Bytes
	tst.l	d0		;sind 0 Bytes frei ?
	bne.s	W2		;nein, mehr, weiter

	move.b	#"0",FreiBytes	;ja, Ascii '0'
	move.w	#1,Lang		;mit Länge 1
	bra.s	Ascii2		;ausgeben

;---LangWort in ASCII-Text für Ausgabe umwandeln
W2:	move.l	FreiBlocks,d0	;LangWort in D0
	lea	Tabelle,a1	;TabellenAdresse
	moveq	#5,d3		;max.6 Tests, ob
Loop4:	cmp.l	(a1)+,d0	;FreiBlocks > Tabellenwert ?
	bpl.s	Ascii		;wenn ja, dann liegt die Anzahl

	dbra	d3,Loop4	;der ASCII-Stellen fest

Ascii:	tst.l	-(a1)		;1 Tabellen-Eintrag zurückgehen
	move.l	FreiBlocks,d0
	move.w	d3,d1		;D3 Durchgänge =
	addq.w	#1,d3		;Länge des ASCII-Strings (+1)
	move.w	d3,Lang		;in Lang merken
	lea	FreiBytes,a0	;ASCII-Textadresse
Loop3:	move.l	(a1)+,d3	;Einen Tabellenwert holen
	move.l	#$D0,d2		;$D0 nach D2 - bei jeder
Sub:	sub.l	d3,d0		;Subtraktion wird von $D0
	dbmi	d2,Sub		;1 abgezogen, was nach der

	neg.b	d2		;Negierung das Zweier-
	move.b	d2,(a0)+	;komplement einer ASCII-Zahl
	add.l	d3,d0		;ergibt - z.b.: 1 Subtraktion:
	dbra	d1,Loop3	;$D0 - 1 = $CF, negiert = $31 = '1'

Ascii2:	bsr	Weiss		;Schrift weiss
	lea	FreiTxt,a0	;' Freie Bytes: '
	moveq	#14,d0		;14 Buchstaben
	bsr	Txt		;ausgeben
	bsr	Rot		;Schrift rot
	lea	FreiBytes,a0	;Freie Bytes als ASCII
	move.w	Lang,d0		;mit 'Lang' Buchstaben
	bsr	Txt		;ausgeben

;---UP - Boot-Block einlesen und auf Bildschirm ausgeben
BootBl:	clr.l	Block		;Block 0
	bsr	BlockLesen	;einlesen
	bsr	Weiss		;Schrift weiss
	move.l	#60,x		;Koordinaten für die
	move.l	#40,y		;1.Zeile x,y = 60,20
	move.b	#1,Zeile	;1.Zeile (Zähler)
	move.l	Puffer,Puffer2	;2.Puffer zum Hochzählen
Noch:	move.l	Puffer2,a0	;ab hier stehen 1024 Bytes
	lea	String,a1	;ab hier 64 Bytes (1 Zeile)
	moveq	#63,d7		;64 Bytes sollen
	moveq	#0,d0		;geholt werden
Loop1:	move.b	(a0)+,d0	;hole ein Byte
	cmp.b	#$40,d0
	ble.s	Tausch		;kleiner als 'A' ?

	cmp.b	#$5a,d0
	ble.s	OK		;kleiner/gleich 'Z' ?

	cmp.b	#$60,d0
	ble.s	Tausch		;kleiner als 'a' ?

	cmp.b	#$7b,d0
	bge.s	Tausch		;größer als 'z' ?

	bra.s	OK

Tausch:	move.b	#"_",d0		;Zeichen durch '_' ersetzen
OK:	move.b	d0,(a1)+	;und im String ablegen
	dbra	d7,Loop1	;alle 64 Zeichen fertig ?

	move.l	x,d0		;Cursor auf Koordinaten
	move.l	y,d1		;der aktuellen Zeile
	bsr	Cursor		;setzen
	lea	String,a0	;und umgewandelten, fertigen,
	moveq	#64,d0		;64 Zeichen langen String
	bsr	Txt		;ausgeben
	add.l	#10,y		;y-Koordinate + 10 für nächste Zeile
	addq.b	#1,Zeile	;Zeilenzähler erhöhen
	add.l	#64,Puffer2	;Puffer um 64 weitersetzen
	cmp.b	#17,Zeile	;schon alle 16 Zeilen ?
	bne.s	Noch		;nein, noch weiter

	move.l	#184,d0		;Cursor auf x- und
	move.l	#210,d1		;y-Koordinaten
	bsr	Cursor		;setzen
	lea	WahlTxt,a0	;'Nächste Diskette...'
	moveq	#33,d0		;33 Buchstaben

;---UP - Text ausgeben - Länge in D0, Textadresse in A0
Txt:	move.l	RastPort,a1
	jmp	Text(a6)	;Text ausgeben

;---UP - Schriftfarbe rot
Rot:	moveq	#3,d0		;Farbe 3 (rot)
	bra.s	Farbe		;setzen

;---UP - Schriftfarbe weiss oder andere Farbe
Weiss:	moveq	#1,d0		;Farbe 1 (weiß)
Farbe:	move.l	GfxBase,a6
	move.l	RastPort,a1
	jmp	SetAPen(a6)	;Farbe setzen und zurück

;---UP - Fensterinhalt löschen
Loesch:	moveq	#0,d0		;Hintergrundfarbe
	bsr	Farbe		;setzen
	moveq	#60,d0		;Obere
	moveq	#15,d1		;linke Ecke
	move.l	#575,d2		;Untere
	move.l	#215,d3		;rechte Ecke
	jmp	RectFill(a6)	;füllen

;---UP - Cursor auf x/y-Position setzen, x in D0, y in D1
Cursor:	move.l	GfxBase,a6
	move.l	RastPort,a1
	jmp	Move(a6)

;---UP - Librarys, Fenster und Trackdisk-Device öffnen,
;	 Speicher für Bootblock reservieren
OpenAll:
	move.l	ExecBase,a6
	lea	IntName,a1		;Intuition-Library
	jsr	OpenLib(a6)		;öffnen
	move.l	d0,IntBase		;Bei Fehler:
	beq	Error			;4711 und zurück

	lea	GfxName,a1		;Graphics-Library
	jsr	OpenLib(a6)		;öffnen
	move.l	d0,GfxBase
	beq	Error3			;INT schließen, zurück

	move.l	IntBase,a6
	lea	WinDef,a0		;Fenster
	jsr	OpenWindow(a6)		;öffnen
	move.l	d0,Winhd
	beq	Error4			;INT+GFX zu, zurück

	move.l	d0,a0			;RastPort des Fensters
	move.l	50(a0),RastPort		;festhalten
	move.l	86(a0),MsgPort		;MessagePort festhalten

	move.l	ExecBase,a6
	move.l	#1024,d0		;1024 Bytes
	move.l	#$10002,d1		;im CHIP-RAM löschen
	jsr	AllocMem(a6)		;und reservieren
	move.l	d0,Puffer		;ab Puffer im Speicher
	beq.s	Error5			;Alles zu, zurück

	lea	DiskIO,a1	;Disk I/O-Bereich
	move.l	Task,reply+16	;Task in I/O-Port eintragen
	move.l	#reply,14(a1)	;I/O-Port in Disk-I/O eintragen
	moveq	#0,d0		;DF0: (für DF1: hier 1 einsetzen)
	moveq	#0,d1		;keine Flags
	lea	trdName,a0	;'trackdisk.device'
	jsr	OpenDev(a6)	;öffnen
	tst.l	d0		;Fehler ?
	bne.s	Error2		;ja, alles andere zu und zurück

	rts

;---UP - Alles (was geöffnet wurde) wieder schließen
CloseAll:
	lea	DiskIO,a1	;trackdisk.device
	move.l	ExecBase,a6
	jsr	CloseDev(a6)	;schließen
Error2:	move.l	Puffer,a1	;Pufferspeicher
	move.l	#1024,d0	;1024 Bytes
	move.l	ExecBase,a6
	jsr	FreeMem(a6)	;freigeben
Error5:	move.l	Winhd,a0	;Fenster
	move.l	IntBase,a6
	jsr	CloseWindow(a6)	;schließen
Error4:	move.l	GfxBase,a1	;GFX
	bsr	Close		;schließen
Error3:	move.l	IntBase,a1	;INT
	bsr	Close		;schließen
Error:	move.w	#4711,d0
	rts

;---UP - Eine Library schließen
Close:	move.l	ExecBase,a6
	jmp	CloseLib(a6)

;---UP - 2 Blöcke von Diskette in Puffer einlesen
BlockLesen:
	move.l	ExecBase,a6
	lea	DiskIO,a1
	move.w	#2,28(a1)	;COMMAND CMD_READ
	move.l	Puffer,40(a1)	
	move.l	#1024,36(a1)	;1024 Bytes
	move.l	Block,d0	;zu holenden Block nach D0
	mulu	#512,d0		;mal 512 Bytes per Block
	move.l	d0,44(a1)
	jsr	DoIO(a6)	;Block in Puffer einlesen
	lea	DiskIO,a1
	move	#9,28(a1)	;COMMAND TD_MOTOR
	move.l	#0,36(a1)	;Motor ausschalten
	jmp	DoIO(a6)	;und zurück

;---UP - Warten auf: Closegadget, Diskette rein/raus
Warte:	move.l	ExecBase,a6
	move.l	MsgPort,a0
	jsr	WaitPort(a6)	;warte auf Message
	move.l	MsgPort,a0
	jsr	GetMsg(a6) 	;Message abholen
	tst.l	d0		;war da was ?
	beq.s	Warte		;nein, weiter warten

	move.l	d0,a1		;Zeiger auf Message-Struktur
	move.l	20(a1),d6	;Ereignis (im 20.Byte)
	jmp	ReplyMsg(a6)	;'Message erhalten' melden, zurück
;-----------------------------------------------
;---Fenster-Definition (auf Workbench, volle Größe)
WinDef:	dc.w	0,0,640,256
	dc.b	0,1
	dc.l	$18200,$1100c,0,0,WinName,0,0,0,0
	dc.w	1

;---Rechteck um 'DISKETTE EINLEGEN'
Border:	dc.w	240,39
	dc.b	3,0,0,5
	dc.l	Koord,0
Koord:	dc.w	0,0,151,0,151,16,0,16,0,0

;---Variablen/Texte
Stack:		dc.l	0
WBMessage:	dc.l	0
Task:		dc.l	0
Winhd:		dc.l	0
IntBase:	dc.l	0
GfxBase:	dc.l	0
RastPort:	dc.l	0
MsgPort:	dc.l	0
x:		dc.l	0
y:		dc.l	0
Puffer:		dc.l	0
Puffer2:	dc.l	0
BitMap:		dc.l	0
MapOK:		dc.l	0
Block:		dc.l	0
FreiBlocks:	dc.l	0
Tabelle:	dc.l	100000,10000,1000,100,10,1
DiskIO:		blk.l	20,0
reply:		blk.l	8,0
Wort:		dc.w	0
Lang:		dc.w	0
String:		blk.b	66,0
FreiBytes:	dc.b	0,0,0,0,0,0
Zeile:		dc.b	0
WinName:	dc.b	"                     "
		dc.b	"BootBlockBuster © 1990 by EHJ",0
Disk:		dc.b	"Disk-Name: ",0
WahlTxt:	dc.b	"NÄCHSTE DISKETTE IN DF0: EINLEGEN",0
LegeTxt:	dc.b	"DISKETTE EINLEGEN",0
FreiTxt:	dc.b	" Freie Bytes: ",0
IntName:	dc.b	"intuition.library",0
GfxName:	dc.b	"graphics.library",0
trdName:	dc.b	"trackdisk.device",0

