*
* 6526.asm - CIA-Emulation
*
* Copyright (C) 1994-1995 by Christian Bauer
*

*
* Anmerkungen:
* ------------
*
* Funktionsweise/Periodic:
*  - Für jede (simulierte) C64-Rasterzeile wird vom 6510-Task die Routine
*    Periodic6526 aufgerufen, die die Timer herunterzählt, ggf. Interrupts
*    auslöst und die Joysticks abfragt
*
* Timer/Latches:
*  - Die Bytefolge im Register-File ist gegenüber dem echten 6526 umgekehrt,
*    das wird aber bei den WriteTo6526- und ReadFrom6526-Routinen wieder
*    ausgeglichen
*
* TOD-Clocks:
*  - Die TODs werden synchron mit dem VBlank gezählt. Es wird also ein
*    50Hz-Eingangssignal simuliert.
*
* Tastaturabfrage:
*  - Das Feld KeyMatrix enthält für jede Taste entsprechend der C64-
*    Tastaturmatrix ein Bit (0: Taste gedrückt, 1: Taste nicht gedrückt)
*  - Bei Lesezugriffen aus CIA-A, Port B werden entsprechend der aktiven
*    (ausgewählten) Zeilen der Tastatur die entsprechenden Bits aus der
*    Tastaturmatrix zusammengestellt
*  - Die Help-Taste löst einen NMI aus (Restore), F10 einen RESET,
*    über F9 wird das Einstellungs-Fenster aufgerufen
*
* Inkompatibilitäten:
*  - Die TOD-Clock sollte bei einem Lesezugriff nicht angehalten,
*    sondern gelatcht werden
*

		MACHINE	68020

		XREF	ShowPrefs	;Main.asm

		XREF	_ciaaprb
		XREF	_ciaaddrb

		XREF	IntIsRESET	;6510.asm
		XREF	IntIsNMI
		XREF	IntIsCIAIRQ
		XREF	Peri6526Cont

		XREF	ChangedVA	;6569.asm

		XREF	Reset6581	;6581.asm

		XREF	IECIsOpen	;1541.asm

		XDEF	Reset6526
		XDEF	ReadFrom6526A
		XDEF	ReadFrom6526B
		XDEF	WriteTo6526A
		XDEF	WriteTo6526B
		XDEF	Periodic6526
		XDEF	ChangedKeys
		XDEF	CountTODs
		XDEF	KeyPressed

		XDEF	CIACycles	;Prefs
		XDEF	Joystick1On
		XDEF	Joystick2On
		XDEF	JoystickSwap
		XDEF	KeyboardYZ

		SECTION	"CODE",CODE

**
** Definitionen
**

; CIA-Register
PRA		= 0
PRB		= 1
DDRA		= 2
DDRB		= 3
TAHI		= 4	;Timer-Wert A
TALO		= 5	;Achtung: Umgekehrte Bytefolge!
TBHI		= 6	;Timer-Wert B
TBLO		= 7
TOD10THS	= 8
TODSEC		= 9
TODMIN		= 10
TODHR		= 11
SDR		= 12
ICR		= 13	;Interrupt-Data
CRA		= 14
CRB		= 15

; Zusätzliche Register
LTCHA		= 16	;Timer-Latch A
LTCHB		= 18	;Timer-Latch B
INTMASK		= 20	;Interrupt-Enable
TODHALT		= 21	;TOD zwecks Beschreiben/Auslesen gestoppt
ALM10THS	= 22	;Alarmzeit
ALMSEC		= 23
ALMMIN		= 24
ALMHR		= 25
TODDIV		= 26	;TOD-Frequenzteiler
TACNTPHI2	= 27	;Timer A läuft und zählt Phi2
TBCNTPHI2	= 28	;Timer B läuft und zählt Phi2
TBCNTTA		= 29	;Timer B läuft und zählt Unterläufe von Timer A
JOY1		= 30	;Joystick 1 AND-Wert (nur CIA-A)
JOY2		= 31	;Joystick 2 AND-Wert (nur CIA-A)


**
** CIAs zurücksetzen
**

; CIA-A
Reset6526	lea	Registers1,a0
		clr.l	(a0)
		clr.l	4(a0)
		clr.l	8(a0)
		clr.l	12(a0)
		move.w	#-1,TAHI(a0)		;Timer auf -1
		move.w	#-1,TBHI(a0)

		move.w	#$0001,LTCHA(a0)	;Latches auf 1
		move.w	#$0001,LTCHB(a0)
		clr.b	INTMASK(a0)		;Interrupts abschalten
		clr.b	TODHALT(a0)		;TOD läuft
		clr.l	ALM10THS(a0)		;Alarmzeit auf 00:00:00.0
		clr.w	TACNTPHI2(a0)		;Beide Timer anhalten
		move.b	#$ff,JOY1(a0)		;Joystick inaktiv
		move.b	#$ff,JOY2(a0)

; CIA-B
		lea	Registers2,a0
		clr.l	(a0)
		clr.l	4(a0)
		clr.l	8(a0)
		clr.l	12(a0)
		move.w	#-1,TAHI(a0)		;Timer auf -1
		move.w	#-1,TBHI(a0)

		move.w	#$0001,LTCHA(a0)	;Latches auf 1
		move.w	#$0001,LTCHB(a0)
		clr.b	INTMASK(a0)		;Interrupts abschalten
		clr.b	TODHALT(a0)		;TOD läuft
		clr.l	ALM10THS(a0)		;Alarmzeit auf 00:00:00.0
		clr.w	TACNTPHI2(a0)		;Beide Timer anhalten

; Tastaturmatrix löschen
		moveq	#-1,d0
		move.l	d0,KeyMatrix
		move.l	d0,KeyMatrix+4

; VIC-Bank 0 einstellen
		moveq	#0,d0
		bra	ChangedVA


**
** Tastaturbelegung geändert, Y und Z sortieren
**

ChangedKeys	tst.w	KeyboardYZ
		bne	1$
		move.l	#$00010004,KeyPatch1
		move.l	#$00030001,KeyPatch2
		rts
1$		move.l	#$00030001,KeyPatch1
		move.l	#$00010004,KeyPatch2
		rts


**
** In ein CIA-A-Register schreiben
** d0.w: Registernummer ($00-$0f)
** d1.b: Byte
**
** Darf das obere Wort von d0 und d1 nicht verändern!
**

WriteTo6526A	lea	Registers1,a0
		move.l	WriteTabA(pc,d0.w*4),a1
		jmp	(a1)

		CNOP	0,4
WriteTabA	dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrNormal
		dc.l	WrTALO
		dc.l	WrTAHI
		dc.l	WrTBLO
		dc.l	WrTBHI
		dc.l	WrTOD10THS
		dc.l	WrTODSEC
		dc.l	WrTODMIN
		dc.l	WrTODHR
		dc.l	WrNormal
		dc.l	WrICR
		dc.l	WrCRA
		dc.l	WrCRB

WrNormal	move.b	d1,(a0,d0.w)
		rts

WrTALO		move.b	d1,LTCHA+1(a0)
		rts

WrTAHI		move.b	d1,LTCHA(a0)
		btst	#0,CRA(a0)		;Timer A gestoppt?
		bne	1$
		move.w	LTCHA(a0),TAHI(a0)	;Ja, Timer laden
1$		rts

WrTBLO		move.b	d1,LTCHB+1(a0)
		rts

WrTBHI		move.b	d1,LTCHB(a0)
		btst	#0,CRB(a0)		;Timer B gestoppt?
		bne	1$
		move.w	LTCHB(a0),TBHI(a0)	;Ja, Timer laden
1$		rts

WrTOD10THS	and.b	#$0f,d1
		clr.b	TODHALT(a0)	;TOD weiterlaufen lassen
		btst	#7,CRB(a0)	;Alarm-Zeit schreiben?
		bne	1$
		move.b	d1,TOD10THS(a0)
		rts
1$		move.b	d1,ALM10THS(a0)
		rts

WrTODSEC	and.b	#$7f,d1
		btst	#7,CRB(a0)	;Alarm-Zeit schreiben?
		bne	1$
		move.b	d1,TODSEC(a0)
		rts
1$		move.b	d1,ALMSEC(a0)
		rts

WrTODMIN	and.b	#$7f,d1
		btst	#7,CRB(a0)	;Alarm-Zeit schreiben?
		bne	1$
		move.b	d1,TODMIN(a0)
		rts
1$		move.b	d1,ALMMIN(a0)
		rts

WrTODHR		and.b	#$9f,d1
		st.b	TODHALT(a0)	;TOD anhalten
		btst	#7,CRB(a0)	;Alarm-Zeit schreiben?
		bne	1$
		move.b	d1,TODHR(a0)
		rts
1$		move.b	d1,ALMHR(a0)
		rts

WrICR		bclr	#7,d1			;S/C-Bit löschen
		bne	1$			;War es gesetzt?
		not.b	d1			;Nein, Bits zum Löschen negieren
		and.b	d1,INTMASK(a0)		;Und Bits löschen
		bra	2$
1$		or.b	d1,INTMASK(a0)		;Bits setzen
2$		rts

WrCRA		btst	#4,d1			;Force load?
		beq	1$
		and.b	#$ef,d1
		move.w	LTCHA(a0),TAHI(a0)	;Ja, Timer laden
1$		move.b	d1,CRA(a0)

		and.b	#$21,d1			;Läuft der Timer und zählt er Phi2?
		cmp.b	#$01,d1
		seq.b	TACNTPHI2(a0)		;Ja, Flag setzen
		rts

WrCRB		btst	#4,d1			;Force load?
		beq	1$
		and.b	#$ef,d1
		move.w	LTCHB(a0),TBHI(a0)	;Ja, Timer laden
1$		move.b	d1,CRB(a0)

		and.b	#$61,d1			;Läuft der Timer und zählt er Phi2?
		cmp.b	#$01,d1
		seq.b	TBCNTPHI2(a0)		;Ja, Flag setzen
		cmp.b	#$41,d1			;Läuft er und zählt Unterläuft von Timer A?
		seq.b	TBCNTTA(a0)		;Ja, Flag setzen
		rts


**
** In ein CIA-B-Register schreiben
** d0.w: Registernummer ($00-$0f)
** d1.b: Byte
**
** Darf das obere Wort von d0 und d1 nicht verändern!
**

WriteTo6526B	lea	Registers2,a0
		move.l	WriteTabB(pc,d0.w*4),a1
		jmp	(a1)

		CNOP	0,4
WriteTabB	dc.l	WrBPRA
		dc.l	WrNormal
		dc.l	WrBDDRA
		dc.l	WrNormal
		dc.l	WrTALO
		dc.l	WrTAHI
		dc.l	WrTBLO
		dc.l	WrTBHI
		dc.l	WrTOD10THS
		dc.l	WrTODSEC
		dc.l	WrTODMIN
		dc.l	WrTODHR
		dc.l	WrNormal
		dc.l	WrICR
		dc.l	WrCRA
		dc.l	WrCRB

WrBPRA		move.b	d1,PRA(a0)		;Floppy/VA
		tst.b	IECIsOpen		;Wenn IEC aktiv ist, Port setzen
		beq	WrBNewVA
		move.b	d1,_ciaaprb
		bra	WrBNewVA

WrBDDRA		move.b	d1,DDRA(a0)		;Floppy/VA
		tst.b	IECIsOpen		;Wenn IEC aktiv ist, DDR setzen
		beq	WrBNewVA
		move.b	d1,_ciaaddrb
WrBNewVA	move.b	DDRA(a0),d0		;VA extrahieren
		not.b	d0
		or.b	PRA(a0),d0
		not.b	d0
		and.b	#$03,d0
		bra	ChangedVA		;Und dem VIC mitteilen


**
** Aus einem CIA-A-Register lesen
** d0.w: Registernummer ($00-$0f)
** Rückgabe: d0.b: Byte
**
** Darf das obere Wort von d0 und d1 nicht verändern!
** Darf a1 nicht verändern!
**

ReadFrom6526A	move.l	ReadTabA(pc,d0.w*4),a0
		jmp	(a0)

		CNOP	0,4
ReadTabA	dc.l	RdAPRA
		dc.l	RdAPRB
		dc.l	RdANormal
		dc.l	RdANormal
		dc.l	RdATALO
		dc.l	RdATAHI
		dc.l	RdATBLO
		dc.l	RdATBHI
		dc.l	RdATOD10THS
		dc.l	RdANormal
		dc.l	RdANormal
		dc.l	RdATODHR
		dc.l	RdANormal
		dc.l	RdAICR
		dc.l	RdANormal
		dc.l	RdANormal

RdANormal	lea	Registers1,a0
		move.b	(a0,d0.w),d0
		rts

RdAPRA		lea	Registers1,a0
		move.b	DDRA(a0),d0
		not.b	d0
		or.b	PRA(a0),d0
		and.b	JOY2(a0),d0
		rts

RdAPRB		move.l	a1,-(sp)
		lea	Registers1,a0
		lea	KeyMatrix,a1
		move.b	PRA(a0),d1	;Tastaturabfrage
		move.b	#$ff,d0		;Alle aktiven Reihen dazuANDen
		lsr.b	#1,d1
		bcs	1$
		and.b	(a1),d0
1$		lsr.b	#1,d1
		bcs	2$
		and.b	1(a1),d0
2$		lsr.b	#1,d1
		bcs	3$
		and.b	2(a1),d0
3$		lsr.b	#1,d1
		bcs	4$
		and.b	3(a1),d0
4$		lsr.b	#1,d1
		bcs	5$
		and.b	4(a1),d0
5$		lsr.b	#1,d1
		bcs	6$
		and.b	5(a1),d0
6$		lsr.b	#1,d1
		bcs	7$
		and.b	6(a1),d0
7$		lsr.b	#1,d1
		bcs	8$
		and.b	7(a1),d0

8$		and.b	JOY1(a0),d0
		move.b	DDRB(a0),d1
		not.b	d1
		or.b	PRB(a0),d1
		and.b	d1,d0
		move.l	(sp)+,a1
		rts

RdATALO		move.b	Registers1+TALO,d0	;Weil die Timer im Registerfile
		rts				;als big-endian gespeichert sind

RdATAHI		move.b	Registers1+TAHI,d0
		rts

RdATBLO		move.b	Registers1+TBLO,d0
		rts

RdATBHI		move.b	Registers1+TBHI,d0
		rts

RdATOD10THS	lea	Registers1,a0
		move.b	TOD10THS(a0),d0
		clr.b	TODHALT(a0)	;TOD weiterlaufen lassen
		rts

RdATODHR	lea	Registers1,a0
		st.b	TODHALT(a0)	;TOD anhalten
		move.b	TODHR(a0),d0
		rts

RdAICR		lea	Registers1,a0
		move.b	ICR(a0),d0	;ICR beim Lesen löschen
		clr.b	ICR(a0)
		clr.b	IntIsCIAIRQ	;IRQ zurücknehmen
		rts


**
** Aus einem CIA-B-Register lesen
** d0.w: Registernummer ($00-$0f)
** Rückgabe: d0.b: Byte
**
** Darf das obere Wort von d0 und d1 nicht verändern!
** Darf a1 nicht verändern!
**

ReadFrom6526B	move.l	ReadTabB(pc,d0.w*4),a0
		jmp	(a0)

		CNOP	0,4
ReadTabB	dc.l	RdBPRA
		dc.l	RdBPRB
		dc.l	RdBNormal
		dc.l	RdBNormal
		dc.l	RdBTALO
		dc.l	RdBTAHI
		dc.l	RdBTBLO
		dc.l	RdBTBHI
		dc.l	RdBTOD10THS
		dc.l	RdBNormal
		dc.l	RdBNormal
		dc.l	RdBTODHR
		dc.l	RdBNormal
		dc.l	RdBICR
		dc.l	RdBNormal
		dc.l	RdBNormal

RdBNormal	lea	Registers2,a0
		move.b	(a0,d0.w),d0
		rts

RdBPRA		lea	Registers2,a0
		move.b	DDRA(a0),d0	;Floppy/VA
		not.b	d0
		or.b	PRA(a0),d0

		tst.b	IECIsOpen	;Wenn IEC aktiv ist, davon lesen
		beq	1$
		and.b	#$03,d0
		move.b	_ciaaprb,d1
		and.b	#$fc,d1
		or.b	d1,d0
1$		rts

RdBPRB		lea	Registers2,a0
		move.b	DDRB(a0),d0	;Userport
		not.b	d0		;Eingabebits immer 1
		or.b	PRB(a0),d0
		rts

RdBTALO		move.b	Registers2+TALO,d0	;Weil die Timer im Registerfile
		rts				;als big-endian gespeichert sind

RdBTAHI		move.b	Registers2+TAHI,d0
		rts

RdBTBLO		move.b	Registers2+TBLO,d0
		rts

RdBTBHI		move.b	Registers2+TBHI,d0
		rts

RdBTOD10THS	lea	Registers2,a0
		move.b	TOD10THS(a0),d0
		clr.b	TODHALT(a0)	;TOD weiterlaufen lassen
		rts

RdBTODHR	lea	Registers2,a0
		st.b	TODHALT(a0)	;TOD anhalten
		move.b	TODHR(a0),d0
		rts

RdBICR		lea	Registers2,a0
		move.b	ICR(a0),d0	;ICR beim Lesen löschen
		clr.b	ICR(a0)
		rts


**
** Wird jede Rasterzeile einmal aufgerufen
**

*
* CIA-A
* d1: ICR
* d2: INTMASK
* d3: CIACycles
*

Periodic6526	lea	Registers1,a0
		move.b	ICR(a0),d1
		move.b	INTMASK(a0),d2
		move.w	CIACycles,d3

*
* Timer A
*

		tst.b	TACNTPHI2(a0)	;Wird Phi2 gezählt?
		beq	CiaATADone

		sub.w	d3,TAHI(a0)	;Ja, herabzählen
		bcc	CiaATADone	;Unterlauf?

		or.b	#$01,d1		;Ja, IRQ-Bit setzen
		btst	#0,d2		;IRQ freigegeben?
		beq	CiaATANoIRQ
		or.b	#$80,d1		;Ja, IR-Bit setzen
		st.b	IntIsCIAIRQ	;und IRQ auslösen

CiaATANoIRQ	move.w	LTCHA(a0),TAHI(a0) ;Zähler neu laden
		btst	#3,CRA(a0)	;One-Shot?
		beq	1$
		and.b	#$fe,CRA(a0)	;Ja, Zähler stoppen
		clr.b	TACNTPHI2(a0)

1$		tst.b	TBCNTTA(a0)	;Läuft Timer B und zählt er
		beq	CiaATADone	; Unterläufe von Timer A?

		subq.w	#1,TBHI(a0)	;Ja, Timer B runterzählen
		bcs	CiaATBUnderflow	;Untergelaufen?
CiaATADone

*
* Timer B
*

		tst.b	TBCNTPHI2(a0)	;Wird Phi2 gezählt?
		beq	CiaATBDone

		sub.w	d3,TBHI(a0)	;Ja, herabzählen
		bcc	CiaATBDone	;Unterlauf?

CiaATBUnderflow	or.b	#$02,d1		;Ja, IRQ-Bit setzen
		btst	#1,d2		;IRQ freigegeben?
		beq	CiaATBNoIRQ
		or.b	#$80,d1		;Ja, IR-Bit setzen
		st.b	IntIsCIAIRQ	;und IRQ auslösen

CiaATBNoIRQ	move.w	LTCHB(a0),TBHI(a0) ;Zähler neu laden
		btst	#3,CRB(a0)	;One-Shot?
		beq	CiaATBDone
		and.b	#$fe,CRB(a0)	;Ja, Zähler stoppen
		clr.b	TBCNTPHI2(a0)
		clr.b	TBCNTTA(a0)
CiaATBDone

*
* ICR zurückschreiben
*

		move.b	d1,ICR(a0)

*
* CIA-B
* d1: ICR
* d2: INTMASK
* d3: CIACycles
*

		lea	Registers2,a0
		move.b	ICR(a0),d1
		move.b	INTMASK(a0),d2

*
* Timer A
*

		tst.b	TACNTPHI2(a0)	;Wird Phi2 gezählt?
		beq	CiaBTADone

		sub.w	d3,TAHI(a0)	;Ja, herabzählen
		bcc	CiaBTADone	;Unterlauf?

		or.b	#$01,d1		;Ja, IRQ-Bit setzen
		btst	#0,d2		;IRQ freigegeben?
		beq	CiaBTANoIRQ
		or.b	#$80,d1		;Ja, IR-Bit setzen
		st.b	IntIsNMI	;und NMI auslösen

CiaBTANoIRQ	move.w	LTCHA(a0),TAHI(a0) ;Zähler neu laden
		btst	#3,CRA(a0)	;One-Shot?
		beq	1$
		and.b	#$fe,CRA(a0)	;Ja, Zähler stoppen
		clr.b	TACNTPHI2(a0)

1$		tst.b	TBCNTTA(a0)	;Läuft Timer B und zählt er
		beq	CiaBTADone	; Unterläufe von Timer A?

		subq.w	#1,TBHI(a0)	;Ja, Timer B runterzählen
		bcs	CiaBTBUnderflow	;Untergelaufen?
CiaBTADone

*
* Timer B
*

		tst.b	TBCNTPHI2(a0)	;Wird Phi2 gezählt?
		beq	CiaBTBDone

		sub.w	d3,TBHI(a0)	;Ja, herabzählen
		bcc	CiaBTBDone	;Unterlauf?

CiaBTBUnderflow	or.b	#$02,d1		;Ja, IRQ-Bit setzen
		btst	#1,d2		;IRQ freigegeben?
		beq	CiaBTBNoIRQ
		or.b	#$80,d1		;Ja, IR-Bit setzen
		st.b	IntIsNMI	;und NMI auslösen

CiaBTBNoIRQ	move.w	LTCHB(a0),TBHI(a0) ;Zähler neu laden
		btst	#3,CRB(a0)	;One-Shot?
		beq	CiaBTBDone
		and.b	#$fe,CRB(a0)	;Ja, Zähler stoppen
		clr.b	TBCNTPHI2(a0)
		clr.b	TBCNTTA(a0)
CiaBTBDone

*
* ICR zurückschreiben
*

		move.b	d1,ICR(a0)

*
* Joystickabfrage
*

		lea	Registers1,a0

; Port 1
		move.b	#$ff,d2		;Vorgabe: Joystick inaktiv
		tst.w	Joystick1On(pc)
		beq	15$

		btst	#6,$bfe001	;Feuerknopf
		bne	11$
		bclr	#4,d2

11$		move.w	$dff00a,d0
		btst	#1,d0		;Rechts
		beq	12$
		bclr	#3,d2

12$		btst	#9,d0		;Links
		beq	13$
		bclr	#2,d2

13$		move.w	d0,d1
		add.w	d0,d0
		eor.w	d1,d0
		btst	#1,d0		;Runter
		beq	14$
		bclr	#1,d2

14$		btst	#9,d0		;Hoch
		beq	15$
		bclr	#0,d2

15$		move.b	d2,JOY1(a0)

; Port 2
		move.b	#$ff,d2		;Vorgabe: Joystick inaktiv
		tst.w	Joystick2On(pc)
		beq	25$

		btst	#7,$bfe001	;Feuerknopf
		bne	21$
		bclr	#4,d2

21$		move.w	$dff00c,d0
		btst	#1,d0		;Rechts
		beq	22$
		bclr	#3,d2

22$		btst	#9,d0		;Links
		beq	23$
		bclr	#2,d2

23$		move.w	d0,d1
		add.w	d0,d0
		eor.w	d1,d0
		btst	#1,d0		;Runter
		beq	24$
		bclr	#1,d2

24$		btst	#9,d0		;Hoch
		beq	25$
		bclr	#0,d2

25$		move.b	d2,JOY2(a0)

; Joysticks vertauschen?
		tst.w	JoystickSwap(pc)
		beq	30$
		move.b	JOY1(a0),d0
		move.b	JOY2(a0),JOY1(a0)
		move.b	d0,JOY2(a0)

; In 6510-Task zurückspringen
30$		bra	Peri6526Cont


**
** TODs zählen
**

*
* CIA-A
*

CountTODs	lea	Registers1,a0
		subq.b	#1,TODDIV(a0)	;Frequenzteiler herabzählen
		bpl	CiaATODNop

		btst	#7,CRA(a0)	;Untergelaufen,
		beq	CiaATOD60Hz	; je nach 50/60Hz-Flag neu laden
		move.b	#4,TODDIV(a0)
		bra	CiaATODLoaded
CiaATOD60Hz	move.b	#5,TODDIV(a0)

CiaATODLoaded	move	#0,ccr		;X löschen
		move.b	#1,d0		;1/10 Sekunden erhöhen
		move.b	TOD10THS(a0),d1
		abcd	d0,d1
		move.b	d1,TOD10THS(a0)
		cmp.b	#$10,d1		;Über 10?
		blo	CiaATODDone

		clr.b	TOD10THS(a0)	;Ja, 1/10 Sekunden auf Null setzen
		move	#0,ccr		;und Sekunden erhöhen
		move.b	#1,d0
		move.b	TODSEC(a0),d1
		abcd	d0,d1
		move.b	d1,TODSEC(a0)
		cmp.b	#$60,d1		;Über 60?
		blo	CiaATODDone

		clr.b	TODSEC(a0)	;Ja, Sekunden auf Null setzen
		move	#0,ccr		;und Minuten erhöhen
		move.b	#1,d0
		move.b	TODMIN(a0),d1
		abcd	d0,d1
		move.b	d1,TODMIN(a0)
		cmp.b	#$60,d1		;Über 60?
		blo	CiaATODDone

		clr.b	TODMIN(a0)	;Ja, Minuten auf Null setzen
		move	#0,ccr		;und Stunden erhöhen
		move.b	#1,d0
		move.b	TODHR(a0),d1
		and.b	#$1f,d1		;AM/PM ausmaskieren
		abcd	d0,d1
		and.b	#$80,TODHR(a0)	;Stunden schreiben, AM/PM lassen
		or.b	d1,TODHR(a0)

		cmp.b	#$12,d1		;Über 12?
		blo	CiaATODDone

		and.b	#$1f,TODHR(a0)	;Ja, Stunden auf Null setzen
		eor.b	#$80,TODHR(a0)	;und AM/PM umdrehen

CiaATODDone	move.l	TOD10THS(a0),d0	;Alarmzeit erreicht?
		cmp.l	ALM10THS(a0),d0
		bne	CiaATODNop
		move.b	ICR(a0),d0	;Ja, IRQ-Bit setzen
		or.b	#$04,d0
		btst	#2,INTMASK(a0)	;IRQ freigegeben?
		beq	CiaATODNoIRQ
		or.b	#$80,d0		;Ja, IR-Bit setzen
		st.b	IntIsCIAIRQ	;und IRQ auslösen
CiaATODNoIRQ	move.b	d0,ICR(a0)
CiaATODNop

*
* CIA-B
*

		lea	Registers2,a0
		subq.b	#1,TODDIV(a0)	;Frequenzteiler herabzählen
		bpl	CiaBTODNop

		btst	#7,CRA(a0)	;Untergelaufen,
		beq	CiaBTOD60Hz	; je nach 50/60Hz-Flag neu laden
		move.b	#4,TODDIV(a0)
		bra	CiaBTODLoaded
CiaBTOD60Hz	move.b	#5,TODDIV(a0)

CiaBTODLoaded	move	#0,ccr		;X löschen
		move.b	#1,d0		;1/10 Sekunden erhöhen
		move.b	TOD10THS(a0),d1
		abcd	d0,d1
		move.b	d1,TOD10THS(a0)
		cmp.b	#$10,d1		;Über 10?
		blo	CiaBTODDone

		clr.b	TOD10THS(a0)	;Ja, 1/10 Sekunden auf Null setzen
		move	#0,ccr		;und Sekunden erhöhen
		move.b	#1,d0
		move.b	TODSEC(a0),d1
		abcd	d0,d1
		move.b	d1,TODSEC(a0)
		cmp.b	#$60,d1		;Über 60?
		blo	CiaBTODDone

		clr.b	TODSEC(a0)	;Ja, Sekunden auf Null setzen
		move	#0,ccr		;und Minuten erhöhen
		move.b	#1,d0
		move.b	TODMIN(a0),d1
		abcd	d0,d1
		move.b	d1,TODMIN(a0)
		cmp.b	#$60,d1		;Über 60?
		blo	CiaBTODDone

		clr.b	TODMIN(a0)	;Ja, Minuten auf Null setzen
		move	#0,ccr		;und Stunden erhöhen
		move.b	#1,d0
		move.b	TODHR(a0),d1
		and.b	#$1f,d1		;AM/PM ausmaskieren
		abcd	d0,d1
		and.b	#$80,TODHR(a0)	;Stunden schreiben, AM/PM lassen
		or.b	d1,TODHR(a0)

		cmp.b	#$12,d1		;Über 12?
		blo	CiaBTODDone

		and.b	#$1f,TODHR(a0)	;Ja, Stunden auf Null setzen
		eor.b	#$80,TODHR(a0)	;und AM/PM umdrehen

CiaBTODDone	move.l	TOD10THS(a0),d0	;Alarmzeit erreicht?
		cmp.l	ALM10THS(a0),d0
		bne	CiaBTODNop
		move.b	ICR(a0),d0	;Ja, IRQ-Bit setzen
		or.b	#$04,d0
		btst	#2,INTMASK(a0)	;IRQ freigegeben?
		beq	CiaBTODNoIRQ
		or.b	#$80,d0		;Ja, IR-Bit setzen
		st.b	IntIsNMI	;und NMI auslösen
CiaBTODNoIRQ	move.b	d0,ICR(a0)
CiaBTODNop	rts


**
** Taste wurde gedrückt
** d0.b: RawKey-Code
**

KeyPressed	lea	KeyMatrix,a0

		bclr	#7,d0		;KeyUp/KeyDown
		bne	1$

		cmp.b	#$40,d0
		bhs	KeyDownSpecial
		and.w	#$003f,d0
		movem.w	KeyTable(pc,d0.w*4),d0/d1
		bclr	d1,(a0,d0.w)
		rts

1$		cmp.b	#$40,d0
		bhs	KeyUpSpecial
		and.w	#$003f,d0
		movem.w	KeyTable(pc,d0.w*4),d0/d1
		bset	d1,(a0,d0.w)
		rts

; Die häßlichste Tastaturabfrage aller Zeiten...
KeyDownSpecial	cmp.b	#$5f,d0		;Help -> Restore
		beq	KeyHelpD
		cmp.b	#$59,d0		;F10 -> Reset
		beq	KeyF10D
		cmp.b	#$58,d0		;F9 -> Prefs
		beq	KeyF9D
		cmp.b	#$40,d0		;Space
		beq	KeySpaceD
		cmp.b	#$41,d0		;Backspace -> DEL
		beq	KeyBackD
		cmp.b	#$44,d0		;Return
		beq	KeyReturnD
		cmp.b	#$45,d0		;Esc -> R/S
		beq	KeyEscD
		cmp.b	#$46,d0		;Delete -> HOME
		beq	KeyDeleteD
		cmp.b	#$4c,d0		;Crsr up -> Shift CUD
		beq	KeyUpD
		cmp.b	#$4d,d0		;Crsr down -> CUD
		beq	KeyDownD
		cmp.b	#$4e,d0		;Crsr right -> CLR
		beq	KeyRightD
		cmp.b	#$4f,d0		;Crsr left -> Shift CLR
		beq	KeyLeftD
		cmp.b	#$50,d0		;F1
		beq	KeyF1D
		cmp.b	#$51,d0		;F2
		beq	KeyF2D
		cmp.b	#$52,d0		;F3
		beq	KeyF3D
		cmp.b	#$53,d0		;F4
		beq	KeyF4D
		cmp.b	#$54,d0		;F5
		beq	KeyF5D
		cmp.b	#$55,d0		;F6
		beq	KeyF6D
		cmp.b	#$56,d0		;F7
		beq	KeyF7D
		cmp.b	#$57,d0		;F8
		beq	KeyF8D
		cmp.b	#$60,d0		;Shift links
		beq	KeyShiftLD
		cmp.b	#$61,d0		;Shift rechts
		beq	KeyShiftRD
		cmp.b	#$62,d0		;Caps -> SHL
		beq	KeyShiftLD
		cmp.b	#$63,d0		;Ctrl
		beq	KeyCtrlD
		cmp.b	#$66,d0		;Amiga links -> C=
		beq	KeyAmigaD
		cmp.b	#$67,d0		;Amiga rechts -> C=
		beq	KeyAmigaD
		rts

KeyUpSpecial	cmp.b	#$40,d0		;Space
		beq	KeySpaceU
		cmp.b	#$41,d0		;Backspace -> DEL
		beq	KeyBackU
		cmp.b	#$44,d0		;Return
		beq	KeyReturnU
		cmp.b	#$45,d0		;Esc -> R/S
		beq	KeyEscU
		cmp.b	#$46,d0		;Delete -> HOME
		beq	KeyDeleteU
		cmp.b	#$4c,d0		;Crsr up -> Shift CUD
		beq	KeyUpU
		cmp.b	#$4d,d0		;Crsr down -> CUD
		beq	KeyDownU
		cmp.b	#$4e,d0		;Crsr right -> CLR
		beq	KeyRightU
		cmp.b	#$4f,d0		;Crsr up -> Shift CUD
		beq	KeyLeftU
		cmp.b	#$50,d0		;F1
		beq	KeyF1U
		cmp.b	#$51,d0		;F2
		beq	KeyF2U
		cmp.b	#$52,d0		;F3
		beq	KeyF3U
		cmp.b	#$53,d0		;F4
		beq	KeyF4U
		cmp.b	#$54,d0		;F5
		beq	KeyF5U
		cmp.b	#$55,d0		;F6
		beq	KeyF6U
		cmp.b	#$56,d0		;F7
		beq	KeyF7U
		cmp.b	#$57,d0		;F8
		beq	KeyF8U
		cmp.b	#$60,d0		;Shift links
		beq	KeyShiftLU
		cmp.b	#$61,d0		;Shift rechts
		beq	KeyShiftRU
		cmp.b	#$62,d0		;Caps -> SHL
		beq	KeyShiftLU
		cmp.b	#$63,d0		;Ctrl
		beq	KeyCtrlU
		cmp.b	#$66,d0		;Amiga links -> C=
		beq	KeyAmigaU
		cmp.b	#$67,d0		;Amiga rechts -> C=
		beq	KeyAmigaU
		rts

KeyHelpD	st.b	IntIsNMI	;NMI auslösen
		rts

KeyF10D		st.b	IntIsRESET	;6510-Reset
		bsr	Reset6526
		bra	Reset6581

KeyF9D		jmp	ShowPrefs

; Es folgt ein Alptraum. Bitte die Augen schließen.
KeySpaceD	bclr	#4,7(a0)
		rts
KeySpaceU	bset	#4,7(a0)
		rts
KeyBackD	bclr	#0,(a0)
		rts
KeyBackU	bset	#0,(a0)
		rts
KeyReturnD	bclr	#1,(a0)
		rts
KeyReturnU	bset	#1,(a0)
		rts
KeyEscD		bclr	#7,7(a0)
		rts
KeyEscU		bset	#7,7(a0)
		rts
KeyDeleteD	bclr	#3,6(a0)
		rts
KeyDeleteU	bset	#3,6(a0)
		rts
KeyUpD		bclr	#4,6(a0)
		bclr	#7,(a0)
		rts
KeyUpU		bset	#4,6(a0)
		bset	#7,(a0)
		rts
KeyDownD	bclr	#7,(a0)
		rts
KeyDownU	bset	#7,(a0)
		rts
KeyRightD	bclr	#2,(a0)
		rts
KeyRightU	bset	#2,(a0)
		rts
KeyLeftD	bclr	#4,6(a0)
		bclr	#2,(a0)
		rts
KeyLeftU	bset	#4,6(a0)
		bset	#2,(a0)
		rts
KeyF1D		bclr	#4,(a0)
		rts
KeyF1U		bset	#4,(a0)
		rts
KeyF3D		bclr	#5,(a0)
		rts
KeyF3U		bset	#5,(a0)
		rts
KeyF5D		bclr	#6,(a0)
		rts
KeyF5U		bset	#6,(a0)
		rts
KeyF7D		bclr	#3,(a0)
		rts
KeyF7U		bset	#3,(a0)
		rts
KeyF2D		bclr	#4,6(a0)
		bclr	#4,(a0)
		rts
KeyF2U		bset	#4,6(a0)
		bset	#4,(a0)
		rts
KeyF4D		bclr	#4,6(a0)
		bclr	#5,(a0)
		rts
KeyF4U		bset	#4,6(a0)
		bset	#5,(a0)
		rts
KeyF6D		bclr	#4,6(a0)
		bclr	#6,(a0)
		rts
KeyF6U		bset	#4,6(a0)
		bset	#6,(a0)
		rts
KeyF8D		bclr	#4,6(a0)
		bclr	#3,(a0)
		rts
KeyF8U		bset	#4,6(a0)
		bset	#3,(a0)
		rts
KeyShiftLD	bclr	#7,1(a0)
		rts
KeyShiftLU	bset	#7,1(a0)
		rts
KeyShiftRD	bclr	#4,6(a0)
		rts
KeyShiftRU	bset	#4,6(a0)
		rts
KeyCtrlD	bclr	#2,7(a0)
		rts
KeyCtrlU	bset	#2,7(a0)
		rts
KeyAmigaD	bclr	#5,7(a0)
		rts
KeyAmigaU	bset	#5,7(a0)
		rts


**
** Datenbereich
**

		CNOP	0,4
Registers1	ds.b	32	;CIA-A-Register
Registers2	ds.b	32	;CIA-B-Register

CIACycles	dc.w	0	;Anzahl Phi2-Zyklen pro Rasterzeile (für Timer)
Joystick1On	dc.w	0	;Joystick an Port 1 wird abgefragt
Joystick2On	dc.w	0	;Joystick an Port 2 wird abgefragt
JoystickSwap	dc.w	0	;Joysticks vertauschen
KeyboardYZ	dc.w	0	;Amerikanische Tastaturbelegung

; Tastaturübersetzungstabelle:
; Für jeden Amiga-RawKey Spalte und Zeile in der KeyMatrix
		CNOP	0,4
KeyTable	dc.w	7,1	;` -> <-
		dc.w	7,0	;1
		dc.w	7,3	;2
		dc.w	1,0	;3
		dc.w	1,3	;4
		dc.w	2,0	;5
		dc.w	2,3	;6
		dc.w	3,0	;7
		dc.w	3,3	;8
		dc.w	4,0	;9
		dc.w	4,3	;0
		dc.w	5,0	;ß -> +
		dc.w	5,3	;´ -> -
		dc.w	6,0	;\ -> £
		dc.w	0,0
		dc.w	4,3	;NP 0

		dc.w	7,6	;Q
		dc.w	1,1	;W
		dc.w	1,6	;E
		dc.w	2,1	;R
		dc.w	2,6	;T
KeyPatch1	dc.w	1,4	;Y -> Z
		dc.w	3,6	;U
		dc.w	4,1	;I
		dc.w	4,6	;O
		dc.w	5,1	;P
		dc.w	5,6	;ü -> @
		dc.w	6,1	;+ -> *
		dc.w	0,0
		dc.w	7,0	;NP 1
		dc.w	7,3	;NP 2
		dc.w	1,0	;NP 3

		dc.w	1,2	;A
		dc.w	1,5	;S
		dc.w	2,2	;D
		dc.w	2,5	;F
		dc.w	3,2	;G
		dc.w	3,5	;H
		dc.w	4,2	;J
		dc.w	4,5	;K
		dc.w	5,2	;L
		dc.w	5,5	;ö -> :
		dc.w	6,2	;ä -> ;
		dc.w	6,5	;# -> =
		dc.w	0,0
		dc.w	1,3	;NP 4
		dc.w	2,0	;NP 5
		dc.w	2,3	;NP 6

		dc.w	6,6	;< -> ^
KeyPatch2	dc.w	3,1	;Z -> Y
		dc.w	2,7	;X
		dc.w	2,4	;C
		dc.w	3,7	;V
		dc.w	3,4	;B
		dc.w	4,7	;N
		dc.w	4,4	;M
		dc.w	5,7	;,
		dc.w	5,4	;.
		dc.w	6,7	;- -> /
		dc.w	0,0
		dc.w	0,0
		dc.w	3,0	;NP 7
		dc.w	3,3	;NP 8
		dc.w	4,0	;NP 9

; Bit  7   6   5   4   3   2   1   0
; 0   CUD  F5  F3  F1  F7 CLR RET DEL
; 1   SHL  E   S   Z   4   A   W   3
; 2    X   T   F   C   6   D   R   5
; 3    V   U   H   B   8   G   Y   7
; 4    N   O   K   M   0   J   I   9
; 5    ,   @   :   .   -   L   P   +
; 6    /   ^   =  SHR HOM  ;   *   £
; 7   R/S  Q   C= SPC  2  CTL  <-  1

KeyMatrix	ds.b	8	;C64-Tastaturmatrix pro Taste ein Bit
				;0: Taste gedrückt

		END
