
; Listing11o2.s  Laden einer Datendatei mithilfe der dos.library
; Drücken Sie die linke Taste zum Laden, die rechte zum Verlassen

	SECTION DOSLOAD,CODE

;	include	"DaWorkBench.s"	; entferne das; vor dem Speichern mit "wo"

*****************************************************************************
	include	"/Sources/startup2.s"	; speichern interrupt, dma etc.
*****************************************************************************

;Mit DMASET entscheiden wir, welche DMA-Kanäle geöffnet und welche geschlossen werden sollen

			;5432109876543210
DMASET	equ	%1000001110000000	; GRAPHIC,Bitplane DMA aktivieren

WAITDISK	equ	30				; 50-150 zur Rettung (je nach Fall)

Start:
	move.l	#Picture,d0
	lea	Bplpointers2,a1
	moveq	#5-1,d1				; Anzahl der Bitplanes
PointBp:
	move.w	d0,6(a1)
	swap	d0
	move.w	d0,2(a1)
	swap	d0
	add.l	#34*40,d0			; Länge der Bitplane
	addq.w	#8,a1
	dbra	d1,PointBp			; mach das d1 mal (d1=Anzahl der Bitplanes)

; Wir zeigen auf das PIC, das geladen wird (jetzt ist es nur ein leerer Puffer)

	move.l	#Logo+40*40,d0		; Adresse Logo (etwas abgesenkt)
	lea	Bplpointers,a0	
	moveq	#6-1,d7				; 6 Bitplanes HAM.
BpLoop:
	move.w	d0,6(a0)
	swap	d0
	move.w	d0,2(a0)
	swap	d0
	addq.w	#8,a0
	add.l	#176*40,d0			; Länge Bitplane 
	dbra	d7,BpLoop


; Wir zeigen auf unseren Level 3 Int

	move.l	BaseVBR(pc),a0	     ; in a0 ist der Wert des VBR
	move.l	oldint6c(pc),crappyint	; für DOS LOAD - wir springen zum oldint
	move.l	#MyInt6c,$6c(a0)	; meine Routine Int. Level 3 anlegen

	move.w	#DMASET,$96(a5)		; DMACON - aktivieren Bitplane, Copper
	move.l	#Copperlist,$80(a5)	; Zeiger Copperlist
	move.w	d0,$88(a5)			; Start Copperlist
	move.w	#0,$1fc(a5)			; AGA "deaktivieren"
	move.w	#$c00,$106(a5)		; AGA "deaktivieren"
	move.w	#$11,$10c(a5)		; AGA "deaktivieren"

	movem.l	d0-d7/a0-a6,-(sp)
	bsr.w	mt_init				; initialisieren Sie die Musik Routine
	movem.l	(sp)+,d0-d7/a0-a6

	move.w	#$c020,$9a(a5)		; INTENA - aktivieren interrupt "VERTB"
								; per Level 3 ($6c)

Mouse:
	btst	#6,$bfe001			; linke Maustaste gedrückt? (Der Prozessor 
	bne.s	Mouse				; unterbricht die Schleife zu jedem vertical blank
								; sowie jedes WAIT der Rasterzeile $a0 und
								; unterbricht um die Musik zu spielen!)

	bsr.w	DosLoad				; Laden Sie eine Datei mit dos.lib hoch
								; während wir unsere eigene Copperliste ansehen
								; und unser Interrupts starten
	tst.l	ErrorFlag
	bne.s	ErrorLoad			; Datei nicht geladen? Dann lass es uns nicht benutzen!

Mouse2:
	btst	#2,$dff016			; rechte Maustaste gedrückt? (Der Prozessor 
	bne.s	Mouse2				; unterbricht die Schleife zu jedem vertical blank)

ErrorLoad:
	bsr.w	mt_end				; Ende der Wiederholung!

	rts							; Exit

*****************************************************************************
*	INTERRUPTROUTINE  $6c (Level 3) -  VERTB und COPER benutzt.
*****************************************************************************

MyInt6c:
	btst.b	#5,$dff01f			; INTREQR - Bit 5, VERTB, ist zurückgesetzt?
	beq.s	NoIntVertb			; Wenn ja, ist es kein "echter" VERTB Interrupt!
	movem.l	d0-d7/a0-a6,-(sp)	; Register speichern auf dem stack
	bsr.w	mt_music			; Musik spielen
	bsr.w	ColorCycle			; Wechseln der Farben des Bildes
	movem.l	(sp)+,d0-d7/a0-a6	; Register vom stack nehmen
NoIntVertb:
	move.w	#$70,$dff09c		; INTREQ - Löschen Flag BLIT,VERTB,COPER
								; da der 680x0 es nicht von selbst löscht!!!
	rte							; Ende vom Interrupt VERTB

*****************************************************************************
*	Routine, die die Farben der gesamten Palette "wechselt".		     *
*	Diese Routine wechselt die ersten 15 Farben getrennt vom			 *
*   zweiten Farbblock. Es funktioniert wie das "RANGE" des Dpaint.       *
*****************************************************************************

;  Der "Counter" -Zähler wird verwendet, um 3 Frames vorher warten zu lassen
;  Laufroutine fortsetzen In der Praxis "verlangsamen" wir die Ausführung. 

Counter:
	dc.w	0

ColorCycle:
	addq.b	#1,Counter
	cmp.b	#3,Counter			; Handle nur einmal alle 3 Frames
	bne.s	NotYet				; sind wir noch nicht auf dem dritten Platz? Exit!
	clr.b	Counter				; wir sind am dritten, setzen Sie den Zähler zurück

; Rückwärtsrotation der ersten 15 Farben

	lea	Cols+2,a0				; Erste Farbadresse der ersten Gruppe
	move.w	(a0),d0				; Speichern der ersten Farbe in d0
	moveq	#15-1,d7			; 15 Farben zum "drehen" in der ersten Gruppe
Cloop1:
	move.w	4(a0),(a0)			; Kopieren Sie die Farbe vorwärts in die erste
	addq.w	#4,a0				; springe zur nächsten Spalte "zurück"
	dbra	d7,Cloop1			; wiederhole d7 mal
	move.w	d0,(a0)				; Ordne die erste als letzte gespeicherte Farbe an

; Vorwärtsrotation der zweiten 15 Farben

	lea	Cole-2,a0				; Erste Farbadresse der zweiten Gruppe
	move.w	(a0),d0				; Speichern der ersten Farbe in d0
	moveq	#15-1,d7			; Weitere 15 Farben müssen separat "rotiert" werden
Cloop2:	
	move.w	-4(a0),(a0)			; Kopieren Sie die Farbe zurück zum nächsten
	subq.w	#4,a0				; zur vorherigen Spalte springen "vorrücken"
	dbra	d7,Cloop2			; wiederhole d7 mal
	move.w	d0,(a0)				; Ordne die erste als letzte gespeicherte Farbe an
NotYet:
	rts


*****************************************************************************
; Routine, die eine Datei lädt, während wir ins Metall schlagen.
*****************************************************************************

DosLoad:
	bsr.w	PrepareLoad			; Stellen Sie Multitasking wieder her und 
								; stellen Sie das Interrupt-Load ein
	moveq	#5,d1				; Anzahl der zu wartenden frames
	bsr.w	WaitBlanks			; warte 5 frames

	bsr.s	LoadFile			; Laden Sie die Datei mit der dos.library
	move.l	d0,ErrorFlag		; Speichern Sie den Erfolgs- oder Fehlerstatus
	
; Bemerkung: Jetzt müssen wir auf den Laufwerksmotor warten
; Eine schlechte Festplatte oder CD-ROM wird heruntergefahren, bevor wir alles 
; einfrieren oder einen spektakulären Systemabsturz verursachen.

	move.w	#150,d1				; Anzahl der frames zu warten
	bsr.w	WaitBlanks			; warte 150 frames

	bsr.w	AfterLoad			; Deaktiviere multitask und vergebene interrupt
	rts

ErrorFlag:
	dc.l	0

*****************************************************************************
; Prozedur, die eine Datei einer angegebenen Länge und mit einem angegebenen
; Namen lädt. Wir müssen den ganzen Weg gehen!
*****************************************************************************

LoadFile:
	move.l	DosBase(pc),a6
	move.l	#FileName,d1		; handle speichern
	move.l	#1,d2				; handle speichern
	move.l	#81158,d3			; handle speichern
	jsr	-$42(a6)				; SEEK - "Seeka" die Datei

	move.l	#FileName,d1		; Adresse mit String "file name + Pfad"
	move.l	#$3ED,d2			; AccessMode: MODE_OLDFILE - File das es 
								; schon gibt, und deshalb können wir lesen.
	move.l	DosBase(pc),a6
	jsr	-$1e(a6)				; LVOOpen - "Öffnen" Sie die Datei
	move.l	d0,FileHandle		; Speichern Sie seinen handle
	beq.s	ErrorOpen			; wenn d0 = 0 dann liegt ein Fehler vor!

; Wir laden die Datei hoch

	move.l	d0,d1				; FileHandle in d1 für das Lesen
	move.l	#Buffer,d2			; Adresse Ziel in d2
	move.l	#42240,d3			; Dateilänge (GENAU!)
	move.l	DosBase(pc),a6
	jsr	-$2A(a6)				; LVORead - Lesen Sie die Datei und kopieren Sie sie in den Puffer
	cmp.l	#-1,d0				; Fehler gefunden? (hier ist es mit -1 angegeben)
	beq.s	ErrorRead

; Chiudiamolo

	move.l	FileHandle(pc),d1		; FileHandle in d1
	move.l	DosBase(pc),a6
	jsr	-$24(a6)				; LVOClose - schließe die Datei

; Beachten Sie, dass die anderen Programme dies nicht tun, wenn Sie die Datei nicht SCHLIESSEN
; Sie können auf diese Datei zugreifen (Sie können sie nicht löschen oder verschieben).

	moveq	#0,d0				; Wir berichten über Erfolge
	rts

; Hier sind die schmerzhaften Notizen im Fehlerfall:

ErrorRead:
	move.l	FileHandle(pc),d1; FileHandle in d1
	move.l	DosBase(pc),a6
	jsr	-$24(a6)				; LVOClose - schließe die Datei
ErrorOpen:
	moveq	#-1,d0				; Wir melden einen Misserfolg
	rts


FileHandle:
	dc.l	0

; Textstring, der mit einer 0 endet, auf die d1 vorher zeigen muss
; Öffnen Sie die Datei dos.lib. Es lohnt sich, den ganzen Weg zu legen.

FileName:
	dc.b	"/Sources/amiet.raw",0	; Pfad+Name file
	even

*****************************************************************************
; Interruptroutine, die beim Laden ausgeführt werden soll. Die Routinen dafür
; wird in diesem Interrupt abgelegt und auch während des 
; Ladens von Diskette, Festplatte oder CD-ROM ausgeführt.
; BITTE BEACHTEN SIE, DASS WIR DEN INTERRUPT COPER UND NICHT DEN VBLANK VERWENDEN
; DIES WEIL WÄHREND DES LADENS VON DER DISKETTE, INSBESONDERE UNTER KICK 1.3,
; DER INTERRUPT VERTB NICHT STABIL IST, so dass die Musik stockt.
; Wenn wir stattdessen "$9c,$8010" in unsere Copperliste setzen, sind wir sicher
; dass diese Routine nur einmal pro Frame ausgeführt wird.
*****************************************************************************

MyInt6cLoad:
	btst.b	#4,$dff01f			; INTREQR - Bit 4, COPER, gelöscht?
	beq.s	NoInt				; Wenn ja, ist es kein "echter" int COPER!
	move.w	#%10000,$dff09c		; Wenn nicht, ist es die richtige Zeit, lasst uns 
	movem.l	d0-d7/a0-a6,-(sp)	; die Anforderung entfernen!
	bsr.w	mt_music			; Musik spielen
	movem.l	(sp)+,d0-d7/a0-a6
NoInt:
	dc.w	$4ef9				; Hexadezimalwert von JMP
CrappyInt:
	dc.l	0	; Adresse, an die gesprungen werden soll, um AUTOMATISIERT zu werden...
				; VORSICHT: der selbstmodifizierende Code sollte
				; nicht verwendet werden. Jedenfalls, mit
				; ClearMyCache vorher und nachher funktioniert es!

*****************************************************************************
; Routine, die das Betriebssystem mit Ausnahme der Copperliste wiederherstellt
; Außerdem setzen Sie unseren $6c-Interrupt, der dann zum System-Interrupt springt.
; Beachten Sie, dass der Interrupt während des Ladevorgangs vom int "COPER" verwaltet wird.
*****************************************************************************

PrepareLoad:
	lea	$dff000,a5				; Basis der CUSTOM-Register für Offset
	move.w	$2(a5),OldDmaL		; Speichern Sie den alten Status von DMACON
	move.w	$1C(a5),OldIntenaL	; Speichern Sie den alten Status von INTENA
	move.w	$1e(a5),OldIntreqL	; Speichern Sie den alten Status von INTREQ
	move.l	#$80008000,d0		; Bereiten Sie die Maske der High-Bits vor
	or.l	d0,OldDma			; Bit 15 der gespeicherten Werte setzen
	or.w	d0,OldIntreq		; der Register, um sie zurückzusetzen.

	bsr.w	ClearMyCache

	move.l	#$7fff7fff,$9a(a5)	; DEAKTIVIEREN SIE INTERRUPTS & INTREQS

	move.l	BaseVBR(pc),a0	     ; in a0 ist der Wert des VBR
	move.l	OldInt64(pc),$64(a0) ; Sys int lev1 speichern (softint,dskblk)
	move.l	OldInt68(pc),$68(a0) ; Sys int lev2 speichern (I/O,ciaa,int2)
	move.l	#MyInt6cLoad,$6c(a0) ; Int was dann zu dem von sys springt. 
	move.l	OldInt70(pc),$70(a0) ; Sys int lev4 speichern (audio)
	move.l	OldInt74(pc),$74(a0) ; Sys int lev5 speichern (rbf,dsksync)
	move.l	OldInt78(pc),$78(a0) ; Sys int lev6 speichern (exter,ciab,inten)

	move.w	#%1000001001010000,$96(a5) ; Aktivieren Sie aus Sicherheitsgründen "blit" und "disk"
	move.w	OLDINTENA(pc),$9A(a5)	; INTENA STATUS
	move.w	OLDINTREQ(pc),$9C(a5)	; INTREQ
	move.w	#$c010,$9a(a5)		; Wir müssen sicher sein, dass COPER
								; (interrupt über Copperlist) ON ist!

	move.l	4.w,a6
	jsr	-$7e(a6)				; Enable
	jsr	-$8a(a6)				; Permit

	move.l	GfxBase(pc),a6
	jsr	-$e4(a6)				; Warten Sie, bis alle blittata verschwunden sind
	jsr	-$e4(a6)				; WaitBlit
	jsr	-$1ce(a6)				; DisOwnBlitter, das Betriebssystem 
								; kann den Blitter jetzt wieder benutzen
								; (In Kick 1.3 wird es zum Laden von der Diskette verwendet.)
	move.l	4.w,a6
	suba.l	a1,a1				; NULL task - finde diese Aufgabe
	jsr	-$126(a6)				; findtask (Task(name) in a1, -> d0=task)
	move.l	d0,a1				; Task in a1
	moveq	#0,d0				; Priorität in d0 (-128, +127) - NORMAL
								; (damit die Laufwerke atmen können)
	jsr	-$12c(a6)				; _LVOSetTaskPri (d0=Priorität, a1=task)
	rts

OldDmaL:
	dc.w	0
OldIntenaL:						; Old status INTENA
	dc.w	0
OldIntreqL:						; Old status INTREQ
	dc.w	0

*****************************************************************************
; Routine, die das Betriebssystem schließt und unseren Interrupt zurücksetzt
*****************************************************************************

AfterLoad:
	move.l	4.w,a6
	suba.l	a1,a1				; NULL task - finde diese Aufgabe
	jsr	-$126(a6)				; findtask (Task(name) in a1, -> d0=task)
	move.l	d0,a1				; Task in a1
	moveq	#127,d0				; Priorität in d0 (-128, +127) - MAXIMUM
	jsr	-$12C(a6)				; _LVOSetTaskPri (d0=priorität, a1=task)

	jsr	-$84(a6)				; Forbid
	jsr	-$78(a6)				; Disable

	move.l	GfxBase(pc),a6
	jsr	-$1c8(a6)				; OwnBlitter, das gibt uns exklusiv den Blitter
								; Verhinderung seiner Verwendung durch das Betriebssystem.
	jsr	-$e4(a6)				; WaitBlit - Er wartet auf das Ende jeder blittata
	jsr	-$e4(a6)				; WaitBlit

	bsr.w	ClearMyCache

	lea	$dff000,a5				; Custom base per offsets
WarteY:
	move.l	4(a5),d0			; VPOSR und VHPOSR - $dff004/$dff006
	and.l	#$1ff00,d0			; wählen Sie nur die Bits der vertikalen Pos.
	cmp.l	#$12d00,d0			; warte auf Zeile $12d um das zu verhindern
	beq.s	WarteY				; Das Ausschalten des DMA führt zu Flimmern

	move.l	#$7fff7fff,$9a(a5)	; DEAKTIVIEREN SIE INTERRUPTS & INTREQS

			; 5432109876543210
	move.w	#%0000010101110000,d0	; DEAKTIVIEREN DMA

	btst	#8-8,OldDma			; test Bitplane
	beq.s	NoPlanesA
	bclr.l	#8,d0				; nicht ausschalten planes
NoPlanesA:
	btst	#5,OldDma+2			; test Sprite
	beq.s	NoSprites
	bclr.l	#5,d0				; nicht ausschalten Sprite
NoSprites:
	move.w	d0,$96(a5)			; DEAKTIVIEREN DMA

	move.l	BaseVBR(pc),a0			; in a0 ist der Wert des VBR
	move.l	#MyInt6c,$6c(a0)		; meine Routine int. Level 3.
	move.w	OldDmaL(pc),$96(a5)		; Gibt den alten DMA-Status zurück
	move.w	OldIntenaL(pc),$9A(a5)	; INTENA STATUS
	move.w	OldIntreqL(pc),$9C(a5)	; INTREQ
	rts

*****************************************************************************
; Diese Routine wartet d1-Frames. Alle 50 Bilder vergehen 1 Sekunde.
;
; d1 = Anzahl der zu wartenden Frames
;
*****************************************************************************

WaitBlanks:
	lea	$dff000,a5				; OFFSET für CUSTOM REGISTER 
WBlan1:
	move.w	#$80,d0
WBlan2:
	cmp.b	6(a5),d0			; VHPOSR
	bne.s	WBlan2
WBlan3:
	cmp.b	6(a5),d0			; VHPOSR
	beq.s	WBlan3
	dbra	d1,WBlan1
	rts

*****************************************************************************
;	Wiederholungsroutine protracker/soundtracker/noisetracker
;
	include	"/Sources/music.s"
*****************************************************************************

	SECTION	GRAPHIC,DATA_C

Copperlist:
	dc.w	$8e,$2c81			; DIWSTRT
	dc.w	$90,$2cc1			; DIWSTOP
	dc.w	$92,$0038			; DDFSTRT
	dc.w	$94,$00d0			; DDFSTOP
	dc.w	$102,0				; BPLCON1
	dc.w	$104,0				; BPLCON2
	dc.w	$108,0				; BPL1MOD
	dc.w	$10a,0				; BPL2MOD

Bplpointers:
	dc.w	$e0,0,$e2,0			; erste	 Bitplane
	dc.w	$e4,0,$e6,0			; zweite    "
	dc.w	$e8,0,$ea,0			; dritte    "
	dc.w	$ec,0,$ee,0			; vierte    "
	dc.w	$f0,0,$f2,0			; fünfte    "
	dc.w	$f4,0,$f6,0			; sechste   "

	dc.w	$180,0				; COLOR00 schwarz


				 ;5432109876543210
	dc.w	$100,%0110101000000000	; BPLCON0 - 320*256 HAM!

	dc.w	$180,$0000,$182,$134,$184,$531,$186,$443
	dc.w	$188,$0455,$18a,$664,$18c,$466,$18e,$973
	dc.w	$190,$0677,$192,$886,$194,$898,$196,$a96
	dc.w	$198,$0ca6,$19a,$9a9,$19c,$bb9,$19e,$dc9
	dc.w	$1a0,$0666

	dc.w	$9707,$fffe			; warte auf Zeile $97

	dc.w	$100,$200			; BPLCON0 - keine Bitplanes
	dc.w	$180,$00e			; COLOR00 blau

	dc.w	$b907,$fffe			; warte auf Zeile $b9
Bplpointers2:
	dc.w	$e0,0,$e2,0			; erste	 Bitplane
	dc.w	$e4,0,$e6,0			; zweite    "
	dc.w	$e8,0,$ea,0			; dritte    "
	dc.w	$ec,0,$ee,0			; vierte    "
	dc.w	$f0,0,$f2,0			; fünfte    "

	dc.w	$100,%0101001000000000	; BPLCON0 - 5 Bitplanes LOWRES

; Die Palette, die in 2 Gruppen von 16 Farben "gedreht" wird.

Cols:
	dc.w	$180,$040,$182,$050,$184,$060,$186,$080	; Grünton
	dc.w	$188,$090,$18a,$0b0,$18c,$0c0,$18e,$0e0
	dc.w	$190,$0f0,$192,$0d0,$194,$0c0,$196,$0a0
	dc.w	$198,$090,$19a,$070,$19c,$060,$19e,$040

	dc.w	$1a0,$029,$1a2,$02a,$1a4,$13b,$1a6,$24b	; Blauton
	dc.w	$1a8,$35c,$1aa,$36d,$1ac,$57e,$1ae,$68f
	dc.w	$1b0,$79f,$1b2,$68f,$1b4,$58e,$1b6,$37e
	dc.w	$1b8,$26d,$1ba,$15d,$1bc,$04c,$1be,$04c
Cole:

	dc.w	$da07,$fffe			; warte auf Zeile $da
	dc.w	$100,$200			; BPLCON0 - deaktiviere Bitplanes
	dc.w	$180,$00e			; COLOR00 blau

	dc.w	$ff07,$fffe			; warte auf Zeile $ff
	dc.w	$9c,$8010			; INTREQ - Fordern Sie einen COPER-Interrupt an,
								; Musik spielen (auch während wir 
								; Laden mit der dos.library).

	dc.w	$ffff,$fffe			; Ende Copperlist


*****************************************************************************
; 		DESIGN 320*34 zu 5 bitplanes (32 Farben)
*****************************************************************************

Picture:
	incbin "/Sources/pic320x34x5.raw"


*****************************************************************************
;				MUSIK
*****************************************************************************

mt_data:
	dc.l	mt_data1

mt_data1:
	incbin	"/Sources/mod.fairlight"

******************************************************************************
; Puffer, in dem das Image über doslib von der Festplatte geladen wird
******************************************************************************

	SECTION	BITPLANE,BSS

Buffer:
Logo:
	ds.b	6*40*176	; 6 bitplanes * 176 Zeilen * 40 bytes (HAM)

	end

In diesem Beispiel laden wir das Logo, das unmittelbar darüber erscheint. Wenn 
Sie es von der Diskette laden werden Sie feststellen, dass es plane für plane
in Stücken erscheint, die tatsächlich Stück für Stück geladen sind!
Es wäre besser, es in einen separaten Puffer zu laden, und nach dem Laden alles
zusammen anzuzeigen.
Das Grundlegende beim Laden ist, dass die wartende Zeit nach dem Laden, 
ausreichend ist, bevor Sie alles schließen. Sonst ist es das Ende!
Im Interrupt wird nicht die Farbroutine ausgeführt, sondern nur die
Musikroutine, zumindest merkt man die Zeit, die man "für die Sicherheit"
wartet. Da diese Zeit sowieso abgewartet werden sollte, wäre es klug, ein 
Verblassen oder eine zeitraubende Routine, die vorher etwas Nettes tut zu
machen. Schließe alles, zumindest hast du die Zeit gewartet, aber nicht ohne es
zu benutzen!

