
; Listing27d3.s - zwei Timerinterrupts gleichzeitig		
; Timer A des CIAB wird verwendet um ausgehend von einer festen Startzeile
; eine variable Anzahl an Rasterzeilen zu warten
; die Ausführungszeit in Rasterzeilen wird auf dem Bildschirm ausgeben
; rechte Maustaste bewegt das Ende, linke Maustaste beendet das Programm
; zusätzlich ändert sich die Farbe in diesem Bereich zeitabhängig über
; den Timer B CIAB

	SECTION	CIA,CODE

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

*****************************************************************************
	include	"/Sources/startup2.s"	; Speichern Sie Interrupt, DMA und so weiter.
*****************************************************************************

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

			;5432109876543210
DMASET	equ	%1000001110000000	; Copper und Bitplane DMA aktivieren

WAITDISK	equ	30				; 50-150 zur Rettung (je nach Fall)
MICS:		equ	4*7093			; 10ms => (*100/second)
;MICS:		equ	30				; wenn 1-0 Timer B counts Timer A underflow pulses

Start:
	move.l	#Bitplane,d0		; Adresse des Bitplane in d0
	lea	Bplpointers,a1			; Pointer in der Copperlist
	move.w	d0,6(a1)
	swap	d0
	move.w	d0,2(a1)

	lea		$dff000,a6			; Custom Register Base in a6
	move.l	#Copperlist,$80(a6)	; Zeiger Copperlist	
	move.w	#DMASET,$96(a6)		; DMACON - aktivieren Copper und Bitplane DMA
	move.w	#0,$1fc(a6)			; AGA "deaktivieren"
	move.w	#$c00,$106(a6)		; AGA "deaktivieren"
	move.w	#$11,$10c(a6)		; AGA "deaktivieren"
	move.w  #$7fff,$9a(a6)		; INTENA - disable all interrupts
	move.w  #$7fff,$9c(a6)		; INTREQ - clear all pending interrupts
	lea		$bfd000,a4			; $bfd000 - CIA-B base
	
	move.l	BaseVBR(pc),a0	    ; in a0 ist der Wert des VBR	
	move.l	#MyInt78,$78(a0)	; ich lege meinen Interrupt-Level 6 fest

Init:
	move.w	#$1,d4				; Y-Position add
	bsr	CiaInitTA				; CIA-B TA vorbereiten
	bsr	CiaInitTB				; CIA-B TB vorbereiten
	
WarteY:							
	move.l	4(a6),d0			; $dff004 - VPOSR/VHPOSR
	andi.l	#$1ff00,d0			; wirkt sich nur auf die Bits der vertikalen Zeile aus
	cmpi.l	#$02c00,d0			; warte auf Zeile  $10
	bne.s	WarteY
		
	lea     Colors(pc),a0		; Colors-Base nach a0
	move.w  (a0),d0				; Offsetwert
	adda.w  d0,a0				; Adresse des aktuellen Farbwertes 
	move.w  (a0),$180(a6)		; COLOR00 - Farbe setzen	
	bsr CiaTA					; TimerValue laden
								; Farbe grün wird in der Interruptroutine gesetzt

	bsr	TimeToWait
	bsr	Zeit

	btst	#2,$dff016			; rechte Maustaste gedrückt?
	bne.s	Mouse	
				
	bsr BewegeY2
	
Mouse:
	btst	#6,$bfe001			; Maus gedrückt? (Der Prozessor 
	bne.s	WarteY				; unterbricht die Schleife alle 10ms um die Farbe zu ändern

	rts							; Exit

*******************************************************************************
* In dieser Routine wird die untere Warteposition ermittelt                   *
*******************************************************************************

BewegeY2:	
	move.w	Rasterzeile(pc),d0	; aktuellen Wert Anzahl Rasterzeilen holen
	add.w d4,d0					; um eine Zeile erhöhen bzw. verringern
	
	cmp.w #$100,d0				; untere Grenze - bottom check - sind wir unten?	
	bne Ok1						; 				
	neg.w d4					; Richtungsumkehr 1 wird -1
Ok1:
	cmp.w #$1,d0				; obere Grenze - sind wir oben? ; 
	bne Ok2						; 
	neg.w d4					; Richtungsumkehr 1 wird -1
Ok2:		
	move.w d0,Rasterzeile		; aktuellen Wert speichern
	rts
	
*******************************************************************************
* In dieser Routine wird der TimerA Value ermittelt							  * 
*******************************************************************************
; 1 Rasterzeile dauert in PAL:  64,0µs/ 1,409683 µs = 45,40 ~ 45 ticks
; 1 Rasterzeile dauert in NTSC: 63,5µs/ 1,396825 µs = 45,46 ~ 45 ticks

TimeToWait:
		move.w	Rasterzeile(pc),d0			; Rasterzeile
		mulu.w	#45,d0						; TimerValue = Rasterzeile*45
		move.w	d0,TimerValue		
	rts

Rasterzeile:	dc.w	$2		; Rasterzeile von 2 bis 260	
TimerValue:		dc.w	0		; Anzahl Rasterzeilen in Wert für Timer A

*******************************************************************************
* In dieser Routine wird die untere Warteposition Y2Wert ermittelt            *
*******************************************************************************
	
Zeit: 
	movem.l d0-d2/a0-a3,-(sp)
;--- Zeile ermitteln ---------
	move.w	Rasterzeile(pc),d0			; Rasterzeile
	;move.w #$45,d0					; zu Testzwecken - den festen Wert $45 = 69 ausgeben
_timeDisplayCounter:
	and.l #$0000FFFF,d0
	moveq #0,d1
	moveq #3-1,d2
_timeLoopNumber:
	divu #10,d0						; => d0=remainder:quotient of the division of d0 coded on 32 bits
	swap d0
	add.b #$30-$20,d0				; ASCII code for "0" minus the first character offset in font8 ($20)
	move.b d0,d1
	lsl.l #8,d1
	clr.w d0
	swap d0
	dbf d2,_timeLoopNumber
	
	divu #10,d0						; => d0=remainder:quotient of the division of d0 coded on 32 bits
	swap d0
	add.b #$30-$20,d0				; ASCII code for "0" minus the first character offset in font8 ($20)
	move.b d0,d1

									; => d1 : d1 : sequence of 4 ASCII offsets in the font for the 4
									; characters to display, but in reverse order (ex: 123 => "3210")
									
;--- Zeichen drucken ---------
	;move.l #$11191210,d1			; zu Testzwecken Zeichen  0291
	lea font8,a0					; Adresse Font 8x8 Pixel			
	lea Bitplane,a1					; Startadresse Bitplane
	moveq #4-1,d0					; Anzahl der Zeichen
_timeLoopDisplay:					; Label Schleife
	clr.w d2	
	move.b d1,d2					; zu druckendes Zeichen in d2 kopieren
	lsl.w #3,d2						; *8, weil Zeichen 8x8 Pixel hat um zu Überspringen
	lea (a0,d2.w),a2				; das entsprechende Zeichen im Font finden (Anfangsadresse)
	move.l a1,a3					; Adresse Bitplane kopieren
	moveq #8-1,d2					; Schleife über 8 Zeilen des Zeichens
_timeLoopDisplayChar:				; Label Schleife Charakter
	move.b (a2)+,(a3)				; Zeichen nach Bitplane kopieren		
	lea 320>>3(a3),a3				; 320>>3=$28 = 40Bytes --> nächste Zeile
	dbf d2,_timeLoopDisplayChar
	lea 1(a1),a1					; 1 Byte vor in Bitplane
	lsr.l #8,d1						; in d1 stehen 4 Werte, den nächsten Wert auswählen
	dbf d0,_timeLoopDisplay

	movem.l (sp)+,d0-d2/a0-a3
	rts

*******************************************************************************
* In dieser Routine wird der CIA-B Timer A voreingestellt			          *
*******************************************************************************

CiaInitTA:
			; CRA für Timer A -> TA im one-shot-mode		
	move.b  $e00(a4),d0			; $bfde00 - CRA, CIAB
			 ; 76543210
	andi.b  #%11000000,d0		; setzt Bit 0-5 zurück 
	ori.b   #%00001000,d0		; One-Shot mode (runmode single)
	move.b  d0,$e00(a4)			; CRA - Steuerregister festlegen	
	
	rts
		
*******************************************************************************
* In dieser Routine wird der CIA-B Timer B voreingestellt			          *
*******************************************************************************

; Reihenfolge:
	; CRB, CIA-B		- Steuerregister TB festlegen	
	; TBLO/Hi, CIA-B	- Timerwert TB vorladen
	; ICR, CIA-B		- Interrupt TB freigeben
	; CRB, CIA-B		- Timer TB starten

CiaInitTB:
	move.b  $f00(a4),d0				; $bfdf00 - CRB, CIA-B
	
	andi.b  #%00000000,d0			; setzt alles zurück, Bit 3=0 - runmode continuous
	;ori.b	#%01000000,d0			; 1-0 Timer B counts Timer A underflow pulses
	;								; Zeit anpassen z.B. MICS:		equ	30
	move.b  d0,$f00(a4)				; CRB - Steuerregister festlegen

	move.b  #(MICS&$ff),$600(a4)	; TBLO - Setzen Sie das Low-Byte der Zeit
	move.b  #(MICS>>8),$700(a4)		; TBHI - Setzen Sie das High-Byte der Zeit

	move.b  #%01111111,$d00(a4)		; ICR - alle CIA Interrupts sperren	
	move.b  #$82,$d00(a4)			; ICR, CIA-B - Timer TB ein	
	move.w  #$e000,$9a(a6)			; INTENA - Bit 15, 14, 13
	bset.b  #0,$f00(a4)				; CRB, CIA-B - Start timer!!

	rts		
	
*******************************************************************************
* In dieser Routine wird der Timerwert des CIA-B Timer A eingestellt          *
*******************************************************************************

CiaTA:	; 1x pro Frame
	; TimerValue ist variabel, abhängig von der Anzahl der Rasterzeilen
	; Timer startet beim Schreiben Timer Hi automatisch
	; TA-Flag abfragen über Loop-Schleife oder besser über Interrupt
	
	move.b  #%01111111,$d00(a4)	; ICR - alle CIA Interrupts sperren								
	move.w	TimerValue(pc),d0	; countdown
	move.b	d0,$400(a4)			; Timer A - set lo byte
	lsr.w	#8,d0
	move.b	d0,$500(a4)			; Timer A - set hi byte	
;Loop:
;	btst	#0,$d00(a4)			; ICR - Test TA-Bit ->clear ICR
;	beq.s	Loop				; not set->wait

	move.b	#%10000011,$d00(a4)	; ICR - Timer A und B CIA-B freigeben

	rts				
		
*******************************************************************************
*	INTERRUPT-Routine  $78 (Level 6) - Timer B CIA-B						  *
*******************************************************************************

; 13 EXTER 6 ($78)	Input/Output Port und Timer, verbunden mit INT6-Leitung

myInt78:
	movem.l	d0-d7/a0-a6,-(sp)	; speichern der Register auf dem Stack
	move.w	$1c(a6),d1			; INTENAR in d1
	btst.l	#14,d1				; Bit Master Toggle zurückgesetzt?
	beq.s	NoInt6				; wenn ja, Interrupt ist nicht aktiv!
	and.w	$1e(a6),d1			; INREQR - in d1 bleiben nur die Bits gesetzt
								; die in INTENA und INTREQ gesetzt sind
								; um sicher zu sein, dass wenn der Interrupt
								; auftritt, auch aktiviert war.
	btst.l	#13,d1				; INTREQR - EXTER?
	beq.w	NoInt6

	; es handelt sich um einen 'gültigen' Level 6 - Interrupt - Exter
Exter:
	move.b	$bfdd00,d0			; CIA-B ICR - wir speichern seinen Wert, denn
								; durch das Lesen von ICR, verursachen wir
								; auch seine Nullsetzung, so ist der Interrupt
								; "gelöscht" wie in INTREQ
IntTA:
	btst	#0,d0				; Bit TA, (Interrupt CIA), zurückgesetzt?
	beq.w	IntTB
	move.w  #$00f,$180(a6)		; COLOR00 grün $00dff180 - Farbe setzen
IntTB:
	btst	#1,d0				; Bit TB, (Interrupt CIA), zurückgesetzt?
	beq.w NoInt6
	
	; wenn wir hier sind war es ein Timer B Interrupt

	lea     Colors(pc),a0		; Colors-Base nach a0
    move.w  (a0),d0				; aktueller Zählerwert auslesen (ist Offsetwert und Farbwert)   
    addq.w  #2,d0				; Zählerwert wird immer um zwei erhöht, steht somit bei Beginn auf 0, dann 2 usw.
    cmpi.w  #8*14*2-2,d0		; mit "Ende" vergleichen ob 112 Farbwerte = $de
    bne.b   NoBounce			; solange ungleich überspringen
	moveq   #0,d0				; Zählerwert auf Null zurück
NoBounce: 
	move.w  d0,(a0)+			; aktuellen Zählerwert zurückschreiben und aufs nächste Wort zeigen 
    adda.w  d0,a0				; Adresse auf aktuellen Farbwert erhöhen
	;move.w  (a0),$180(a6)		; $00dff180 - Farbe setzen
			
NoInt6:
	move.w  #$2000,$dff09c		; INTREQ Anfrage entfernen, int ausgeführt!
	movem.l	(sp)+,d0-d7/a0-a6	; wiederherstellen der Register vom Stack

	rte

Colors:
    dc.w          -2,$0110,$0220,$0330,$0440,$0550,$0660,$0770
    dc.w        $0880,$0990,$0aa0,$0bb0,$0cc0,$0dd0,$0ee0,$0ff0
    dc.w        $0ff0,$0fe0,$0fd0,$0fc0,$0fb0,$0fa0,$0f90,$0f80
    dc.w        $0f70,$0f60,$0f50,$0f40,$0f30,$0f20,$0f10,$0f00
    dc.w        $0f00,$0f01,$0f02,$0f03,$0f04,$0f05,$0f06,$0f07
    dc.w        $0f08,$0f09,$0f0a,$0f0b,$0f0c,$0f0d,$0f0e,$0f0f
    dc.w        $0f0f,$0e0f,$0d0f,$0c0f,$0b0f,$0a0f,$090f,$080f
    dc.w        $070f,$060f,$050f,$040f,$030f,$020f,$010f,$000f
    dc.w        $000f,$001f,$002f,$003f,$004f,$005f,$006f,$007f
    dc.w        $008f,$009f,$00af,$00bf,$00cf,$00df,$00ef,$00ff
    dc.w        $00ff,$00fe,$00fd,$00fc,$00fb,$00fa,$00f9,$00f8
    dc.w        $00f7,$00f6,$00f5,$00f4,$00f3,$00f2,$00f1,$00f0
    dc.w        $00f0,$00e0,$00d0,$00c0,$00b0,$00a0,$0090,$0080
    dc.w        $0070,$0060,$0050,$0040,$0030,$0020,$0010,0
					
*******************************************************************************

	SECTION GRAPHIC,DATA_C

Copperlist:
	dc.w	$8e,$2c81	; DiwStrt
	dc.w	$90,$2cc1	; DiwStop	
	dc.w	$92,$38		; DdfStart
	dc.w	$94,$d0		; DdfStop
	dc.w	$102,0		; BplCon1
	dc.w	$104,0		; BplCon2
	dc.w	$108,0		; Bpl1Mod
	dc.w	$10a,0		; Bpl2Mod

				; 5432109876543210
	dc.w	$100,%0001001000000000  ; Bit 12 an!! 1 Bitplane Lowres	

Bplpointers:
	dc.w	$e0,0,$e2,0	; erste Bitplane

	dc.w	$180,$00f	; Color0	; Hintergrund Schwarz
	dc.w	$182,$0f0	; Color1	; Farbe 1 der Bitplane
	
	dc.w	$3401,$fffe
	dc.w	$0100,$0200
							
	dc.w	$ffff,$fffe	; Ende der Copperlist

Font8:		
	incbin "/Sources/font8.fnt"

******************************************************************************

	SECTION LEEREPLANE,BSS_C	

Bitplane:
	ds.b	40*256			; Bitplane auf 0 Lowres
	
	end


Wenn sie im für den Timer B den INMODE von 0-0 auf 1-0 ändern ist es möglich
auch dies durch dieses Programm zu zeigen. Ändern sie aber hierfür den
Zählerwert in der Variablen MICS auf z.B. 30. 	

	ori.b #%01000000,d0			; 1-0 Timer B counts Timer A underflow pulses 

Bit 6,5  INMODE   Bits CRB6 and CRB5 select one of four possible
                input modes for Timer B, as follows:

                CRB6  CRB5   Mode Selected
                ----  ----   ---------------------------------------
                 0     0     Timer B counts 02 pulses
                 0     1     Timer B counts positive CNT transitions
                 1     0     Timer B counts Timer A underflow pulses
                 1     1     Timer B counts Timer A underflow pulses
                               while CNT pin is held high.                                                                                                                                                                                                                                                                                                                                                                      te horizontale Position eines 320x256 Screens mit DiwStrt bei
$81. ($81+$140=$1C1) (129+320=449) 449/2=224	bzw. $e0

Um auf die Zeile $2d zu warten kann man in der vorhergehenden Zeile warten wo
der Raster aus dem Screen geht. Nun hat man mehr Rasterzeit um z.B. die Palette
zu ändern. 

Oder allgemein sollten Copperanweisungen ausserhalb von DDFSTOP und vor Beginn
DDFSTRT platziert werden.