*
* 6526SC.asm - Einzelzyklus-CIA-Emulation
*
* Copyright (C) 1994-1996 by Christian Bauer
*

*
* Anmerkungen:
* ------------
*
* Funktionsweise/Periodic:
*  - Für jeden Zyklus wird vom 6510-Task die Routine Periodic6526
*    aufgerufen, die die Timer herunterzählt und ggf. Interrupts auslöst
*
* 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.
*
* Zyklenzähler:
*  - Periodic6526 erhöht auch einen Langwort-Zyklenzähler, der von der
*    6510- und 6569-Emulation benutzt wird
*
* 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).
*    InvKeyMatrix ist dieselbe Matrix mit vertauschten Zeilen und Spalten
*    (für "inverse" Tastaturabfragen).
*  - Bei Lesezugriffen aus CIA-A, Port A/B werden entsprechend der aktiven
*    (ausgewählten) Zeilen der Tastatur die entsprechenden Bits aus der
*    Tastaturmatrix zusammengestellt
*  - F9 löst einen NMI aus (Restore), F10 einen RESET
*
* Joystickabfrage:
*  - Die Joysticks werden im VBlank abgefragt, wenn auch die TODs
*    gezählt werden
*
* Lightpen:
*  - Bei jedem Schreibzugriff auf PRB/DDRB von CIA-A wird geprüft, ob die
*    Lightpen-Leitung (Bit 4) einen Übergang 1->0 macht. In diesem Fall
*    wird der VIC informiert.
*
* Inkompatibilitäten:
*  - Die TOD-Clock sollte bei einem Lesezugriff nicht angehalten,
*    sondern gelatcht werden
*  - Das Stoppen eines Timers sollte zwei Zyklen verzögert werden
*

		MACHINE	68020

		XREF	ShowPrefs	;Main.asm

		XREF	_ciaaprb
		XREF	_ciaaddrb

		XREF	IntIsNMI	;6510SC.asm
		NREF	IntIsIRQ
		NREF	IntIsCIAIRQ
		NREF	FirstIRQCycle
		XREF	FirstNMICycle
		XREF	NMIState

		XREF	ChangedVA	;6569SC.asm
		XREF	TriggerLightpen
		XREF	CycleCounter

		XREF	IECIsOpen	;IEC.asm

		XDEF	Reset6526
		XDEF	_GetCIA1Dump
		XDEF	_GetCIA2Dump
		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

		NEAR	a4,-2

		SECTION	"text",CODE

		FAR


**
** 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 (<0: Stop, 0: Läuft, >0: Verzögerung)
TBCNTPHI2	= 28	;Timer B läuft und zählt Phi2 (<0: Stop, 0: Läuft, >0: Verzögerung)
TBCNTTA		= 29	;Timer B läuft und zählt Unterläufe von Timer A
PREVLP		= 30	;Voriger Zustand der Lightpen-Leitung (nur CIA-A)


**
** CIAs zurücksetzen
**

		FAR

; 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
		st.b	TACNTPHI2(a0)		;Beide Timer anhalten
		st.b	TBCNTPHI2(a0)
		clr.b	TBCNTTA(a0)
		move.b	#$10,PREVLP(a0)		;Lightpen-Leitung ist High

		move.b	#$ff,Joystick1		;Joystick inaktiv
		move.b	#$ff,Joystick2
		move.b	#$ff,Joystick2Key

; 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
		st.b	TACNTPHI2(a0)		;Beide Timer anhalten
		st.b	TBCNTPHI2(a0)
		clr.b	TBCNTTA(a0)

; Zyklenzähler zurücksetzen
		clr.l	CycleCounter

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

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


**
** CIA-Status in Datenstruktur schreiben
**

_GetCIA1Dump	lea	Registers1,a0
		bra	GetCIADump

_GetCIA2Dump	lea	Registers2,a0

GetCIADump	move.l	4(sp),a1
		move.l	(a0),(a1)+
		move.b	TALO(a0),(a1)+	;Wegen umgekehrter Bytefolge
		move.b	TAHI(a0),(a1)+
		move.b	TBLO(a0),(a1)+
		move.b	TBHI(a0),(a1)+
		move.l	TOD10THS(a0),(a1)+
		move.l	SDR(a0),(a1)+

		move.b	LTCHA+1(a0),(a1)+
		move.b	LTCHA(a0),(a1)+
		move.b	LTCHB+1(a0),(a1)+
		move.b	LTCHB(a0),(a1)+
		move.l	ALM10THS(a0),(a1)+
		move.b	INTMASK(a0),(a1)
		rts


**
** 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
**

		NEAR

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

		CNOP	0,4
WriteTabA	dc.l	WrNormal
		dc.l	WrAPRB
		dc.l	WrNormal
		dc.l	WrADDRB
		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	WrASDR
		dc.l	WrAICR
		dc.l	WrCRA
		dc.l	WrCRB

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

WrAPRB		move.b	d1,PRB(a0)
		bra	CheckLP

WrADDRB		move.b	d1,DDRB(a0)

CheckLP		move.b	DDRB(a0),d0	;Lightpen-Leitung
		not.b	d0
		or.b	PRB(a0),d0
		and.b	#$10,d0
		cmp.b	PREVLP(a0),d0	;Änderung?
		beq	1$
		move.b	d0,PREVLP(a0)	;Ja, negative Flanke?
		bne	1$
		bra	TriggerLightpen	;Ja, LP triggern
1$		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

WrASDR		move.b	d1,SDR(a0)
		or.b	#$08,ICR(a0)		;SDR-Interrupt auslösen
		btst	#3,INTMASK(a0)
		beq	1$
		or.b	#$80,ICR(a0)
		tst.w	IntIsIRQ
		bne	2$
		move.l	CycleCounter,FirstIRQCycle
2$		st.b	IntIsCIAIRQ
1$		rts

WrAICR		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$
		move.b	ICR(a0),d0		;Anstehende Interrupts erlaubt?
		and.b	INTMASK(a0),d0
		and.b	#$1f,d0
		beq	3$
		or.b	#$80,ICR(a0)		;Ja, IRQ auslösen
		tst.w	IntIsIRQ
		bne	4$
		move.l	CycleCounter,FirstIRQCycle
4$		st.b	IntIsCIAIRQ
3$		rts				;Nein

WrCRA		bclr	#4,d1			;Force load?
		beq	1$
		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
		bne	2$
		tst.b	TACNTPHI2(a0)		;Ja, läuft der Timer bereits?
		bpl	3$
		move.b	#3,TACNTPHI2(a0)	;Nein, Timer starten (Verzögerung)
3$		rts
2$		st.b	TACNTPHI2(a0)		;Timer läuft nicht
		rts

WrCRB		bclr	#4,d1			;Force load?
		beq	1$
		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
		bne	2$
		tst.b	TBCNTPHI2(a0)		;Ja, läuft der Timer bereits?
		bpl	3$
		move.b	#3,TBCNTPHI2(a0)	;Nein, Timer starten (Verzögerung)
3$		rts
2$		st.b	TBCNTPHI2(a0)
		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
**

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	WrBSDR
		dc.l	WrBICR
		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

WrBSDR		move.b	d1,SDR(a0)
		or.b	#$08,ICR(a0)		;SDR-Interrupt auslösen
		btst	#3,INTMASK(a0)
		beq	1$
		or.b	#$80,ICR(a0)
		tst.b	NMIState
		bne	1$
		move.l	CycleCounter,FirstNMICycle
		st.b	NMIState
		st.b	IntIsNMI
1$		rts

WrBICR		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$
		move.b	ICR(a0),d0		;Anstehende Interrupts erlaubt?
		and.b	INTMASK(a0),d0
		and.b	#$1f,d0
		beq	3$
		or.b	#$80,ICR(a0)		;Ja, NMI auslösen
		tst.b	NMIState
		bne	3$
		move.l	CycleCounter,FirstNMICycle
		st.b	NMIState
		st.b	IntIsNMI
3$		rts				;Nein


**
** Aus einem CIA-A-Register lesen
** d0.w: Registernummer ($00-$0f)
** Rückgabe: d0.b: Byte
**

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

		CNOP	0,4
ReadTabA	dc.l	RdAPRA
		dc.l	RdAPRB
		dc.l	RdNormal
		dc.l	RdNormal
		dc.l	RdTALO
		dc.l	RdTAHI
		dc.l	RdTBLO
		dc.l	RdTBHI
		dc.l	RdTOD10THS
		dc.l	RdNormal
		dc.l	RdNormal
		dc.l	RdTODHR
		dc.l	RdNormal
		dc.l	RdAICR
		dc.l	RdNormal
		dc.l	RdNormal

RdNormal	move.b	(a0,d0.w),d0
		rts

RdAPRA		lea	InvKeyMatrix,a1
		move.b	DDRB(a0),d1	;Tastaturabfrage
		not.b	d1
		or.b	PRB(a0),d1
		and.b	Joystick1,d1
		move.b	DDRA(a0),d0
		not.b	d0
		or.b	PRA(a0),d0
		lsr.b	#1,d1		;Alle aktiven Spalten dazuANDen
		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	Joystick2,d0
		rts

RdAPRB		lea	KeyMatrix,a1
		move.b	DDRA(a0),d1	;Tastaturabfrage
		not.b	d1
		or.b	PRA(a0),d1
		and.b	Joystick2,d1
		move.b	DDRB(a0),d0
		not.b	d0

		lsr.b	#1,d1		;Alle aktiven Reihen dazuANDen
		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$
		move.b	PRB(a0),d1
		and.b	DDRB(a0),d1
		or.b	d1,d0
		and.b	Joystick1,d0
		rts

RdTALO		move.b	TALO(a0),d0	;Weil die Timer im Registerfile
		rts			;als big-endian gespeichert sind

RdTAHI		move.b	TAHI(a0),d0
		rts

RdTBLO		move.b	TBLO(a0),d0
		rts

RdTBHI		move.b	TBHI(a0),d0
		rts

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

RdTODHR		st.b	TODHALT(a0)	;TOD anhalten
		move.b	TODHR(a0),d0
		rts

RdAICR		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
**

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

		CNOP	0,4
ReadTabB	dc.l	RdBPRA
		dc.l	RdBPRB
		dc.l	RdNormal
		dc.l	RdNormal
		dc.l	RdTALO
		dc.l	RdTAHI
		dc.l	RdTBLO
		dc.l	RdTBHI
		dc.l	RdTOD10THS
		dc.l	RdNormal
		dc.l	RdNormal
		dc.l	RdTODHR
		dc.l	RdNormal
		dc.l	RdBICR
		dc.l	RdNormal
		dc.l	RdNormal

RdBPRA		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		move.b	DDRB(a0),d0	;Userport
		not.b	d0		;Eingabebits immer 1
		or.b	PRB(a0),d0
		rts

RdBICR		move.b	ICR(a0),d0	;ICR beim Lesen löschen
		clr.b	ICR(a0)
		clr.b	NMIState	;NMI zurücknehmen
		rts


**
** Wird jede Rasterzeile einmal aufgerufen
**

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

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

*
* Timer A
*

		tst.b	TACNTPHI2(a0)	;Wird Phi2 gezählt?
		bmi	CiaATADone	;Nein
		bne	CiaATADelay	;Ja, aber noch warten

		subq.w	#1,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
		tst.w	IntIsIRQ	;IRQ schon ausgelöst?
		bne	1$
		move.l	CycleCounter,FirstIRQCycle ;Nein, Zyklus merken
1$		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?
		bra	CiaATADone

CiaATADelay	subq.b	#1,TACNTPHI2(a0) ;Verzögerung beim Starten des Timers
CiaATADone

*
* Timer B
*

		tst.b	TBCNTPHI2(a0)	;Wird Phi2 gezählt?
		bmi	CiaATBDone	;Nein
		bne	CiaATBDelay	;Ja, aber noch warten

		subq.w	#1,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
		tst.w	IntIsIRQ	;IRQ schon ausgelöst?
		bne	1$
		move.l	CycleCounter,FirstIRQCycle ;Nein, Zyklus merken
1$		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)
		bra	CiaATBDone

CiaATBDelay	subq.b	#1,TBCNTPHI2(a0) ;Verzögerung beim Starten des Timers
CiaATBDone

*
* ICR zurückschreiben
*

		move.b	d1,ICR(a0)

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

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

*
* Timer A
*

		tst.b	TACNTPHI2(a0)	;Wird Phi2 gezählt?
		bmi	CiaBTADone	;Nein
		bne	CiaBTADelay	;Ja, aber noch warten

		subq.w	#1,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
		tst.b	NMIState	;NMI schon ausgelöst?
		bne	1$
		move.l	CycleCounter,FirstNMICycle ;Nein, Zyklus merken
		st.b	NMIState	;und NMI auslösen
		st.b	IntIsNMI
1$

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?
		bra	CiaBTADone

CiaBTADelay	subq.b	#1,TACNTPHI2(a0) ;Verzögerung beim Starten des Timers
CiaBTADone

*
* Timer B
*

		tst.b	TBCNTPHI2(a0)	;Wird Phi2 gezählt?
		bmi	CiaBTBDone	;Nein
		bne	CiaBTBDelay	;Ja, aber noch warten

		subq.w	#1,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
		tst.b	NMIState	;NMI schon ausgelöst?
		bne	1$
		move.l	CycleCounter,FirstNMICycle
		st.b	NMIState	;und NMI auslösen
		st.b	IntIsNMI
1$

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)
		bra	CiaBTBDone

CiaBTBDelay	subq.b	#1,TBCNTPHI2(a0) ;Verzögerung beim Starten des Timers
CiaBTBDone

*
* ICR zurückschreiben
*

		move.b	d1,ICR(a0)

*
* 6510-Zyklus ausführen und Zyklenzähler erhöhen
*

		jsr	(a6)
		addq.l	#1,CycleCounter
		rts


**
** 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	#$80,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
		tst.w	IntIsIRQ	;IRQ schon ausgelöst?
		bne	1$
		move.l	CycleCounter,FirstIRQCycle ;Nein, Zyklus merken
1$		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	#$80,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
		tst.b	NMIState	;NMI schon ausgelöst?
		bne	1$
		move.l	CycleCounter,FirstNMICycle ;Nein, Zyklus merken
		st.b	NMIState	;und NMI auslösen
		st.b	IntIsNMI
1$
CiaBTODNoIRQ	move.b	d0,ICR(a0)
CiaBTODNop

*
* 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,Joystick1

; Port 2
		move.b	Joystick2Key,d2	;Vorgabe: Zehnerblock-Emulation
		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,Joystick2

; Joysticks vertauschen?
		tst.w	JoystickSwap(pc)
		beq	30$
		move.b	Joystick1,d0
		move.b	Joystick2,Joystick1
		move.b	d0,Joystick2
30$		rts


**
** Taste wurde gedrückt
**

		FAR

KeyDown		MACRO
		bclr	#\1,\2(a0)
		bclr	#\2,\1(a1)
		ENDM

KeyUp		MACRO
		bset	#\1,\2(a0)
		bset	#\2,\1(a1)
		ENDM

_KeyPressed	move.l	4(sp),d0
		lea	KeyMatrix,a0
		lea	InvKeyMatrix,a1

		bclr	#7,d0				;KeyUp/KeyDown
		bne	KeyUp

		cmp.b	#$40,d0
		bhs	KeyDownSpecial
		and.w	#$003f,d0			;$00..$3f

		cmp.b	#$0f,d0				;Joystick-Emulation
		beq	KeyDownJoyFire
		cmp.b	#$1d,d0
		beq	KeyDownJoyDL
		cmp.b	#$1e,d0
		beq	KeyDownJoyDown
		cmp.b	#$1f,d0
		beq	KeyDownJoyDR
		cmp.b	#$2d,d0
		beq	KeyDownJoyLeft
		cmp.b	#$2e,d0
		beq	KeyDownJoyFire
		cmp.b	#$2f,d0
		beq	KeyDownJoyRight
		cmp.b	#$3d,d0
		beq	KeyDownJoyUL
		cmp.b	#$3e,d0
		beq	KeyDownJoyUp
		cmp.b	#$3f,d0
		beq	KeyDownJoyUR

		movem.w	KeyTable(pc,d0.w*4),d0/d1
		bclr	d1,(a0,d0.w)
		bclr	d0,(a1,d1.w)
		rts

KeyUp		cmp.b	#$40,d0
		bhs	KeyUpSpecial
		and.w	#$003f,d0			;$00..$3f

		cmp.b	#$0f,d0				;Joystick-Emulation
		beq	KeyUpJoyFire
		cmp.b	#$1d,d0
		beq	KeyUpJoyDL
		cmp.b	#$1e,d0
		beq	KeyUpJoyDown
		cmp.b	#$1f,d0
		beq	KeyUpJoyDR
		cmp.b	#$2d,d0
		beq	KeyUpJoyLeft
		cmp.b	#$2e,d0
		beq	KeyUpJoyFire
		cmp.b	#$2f,d0
		beq	KeyUpJoyRight
		cmp.b	#$3d,d0
		beq	KeyUpJoyUL
		cmp.b	#$3e,d0
		beq	KeyUpJoyUp
		cmp.b	#$3f,d0
		beq	KeyUpJoyUR

		movem.w	KeyTable(pc,d0.w*4),d0/d1
		bset	d1,(a0,d0.w)
		bset	d0,(a1,d1.w)
KeyNOP		rts

KeyDownSpecial	sub.b	#$40,d0
		cmp.b	#$20,d0
		bhs	KeyDownMod
		and.w	#$1f,d0				;$40..$5f
		jmp	([KeyDownSpecTab,pc,d0.w*4])

KeyDownMod	sub.b	#$20,d0
		cmp.b	#$08,d0
		bhs	KeyNOP
		and.w	#$07,d0				;$60..$67
		cmp.w	#$07,d0				;Amiga rechts ignorieren
		beq	1$
		movem.w	KeyModTable(pc,d0.w*4),d0/d1
		bclr	d1,(a0,d0.w)
		bclr	d0,(a1,d1.w)
1$		rts

KeyUpSpecial	sub.b	#$40,d0
		cmp.b	#$20,d0
		bhs	KeyUpMod
		and.w	#$1f,d0				;$40..$5f
		jmp	([KeyUpSpecTab,pc,d0.w*4])

KeyUpMod	sub.b	#$20,d0
		cmp.b	#$08,d0
		bhs	KeyNOP
		and.w	#$07,d0				;$60..$67
		cmp.w	#$07,d0				;Amiga rechts ignorieren
		beq	1$
		movem.w	KeyModTable(pc,d0.w*4),d0/d1
		bset	d1,(a0,d0.w)
		bset	d0,(a1,d1.w)
1$		rts

KeySpaceD	KeyDown	4,7
		rts
KeySpaceU	KeyUp	4,7
		rts
KeyBackD	KeyDown	0,0
		rts
KeyBackU	KeyUp	0,0
		rts
KeyTabD		KeyDown	7,7
		tst.b	NMIState	;NMI schon ausgelöst?
		bne	1$
		move.l	CycleCounter,FirstNMICycle ;Nein, Zyklus merken
		st.b	IntIsNMI	; und NMI auslösen
1$		rts
KeyTabU		KeyUp	7,7
		rts
KeyEnterD
KeyReturnD	KeyDown	1,0
		rts
KeyEnterU
KeyReturnU	KeyUp	1,0
		rts
KeyEscD		KeyDown	7,7
		rts
KeyEscU		KeyUp	7,7
		rts
KeyDeleteD	KeyDown	3,6
		rts
KeyDeleteU	KeyUp	3,6
		rts
KeyUpD		KeyDown	4,6
		KeyDown	7,0
		rts
KeyUpU		KeyUp	4,6
		KeyUp	7,0
		rts
KeyDownD	KeyDown	7,0
		rts
KeyDownU	KeyUp	7,0
		rts
KeyRightD	KeyDown	2,0
		rts
KeyRightU	KeyUp	2,0
		rts
KeyLeftD	KeyDown	4,6
		KeyDown	2,0
		rts
KeyLeftU	KeyUp	4,6
		KeyUp	2,0
		rts
KeyF1D		KeyDown	4,0
		rts
KeyF1U		KeyUp	4,0
		rts
KeyF3D		KeyDown	5,0
		rts
KeyF3U		KeyUp	5,0
		rts
KeyF5D		KeyDown	6,0
		rts
KeyF5U		KeyUp	6,0
		rts
KeyF7D		KeyDown	3,0
		rts
KeyF7U		KeyUp	3,0
		rts
KeyF2D		KeyDown	4,6
		KeyDown	4,0
		rts
KeyF2U		KeyUp	4,6
		KeyUp	4,0
		rts
KeyF4D		KeyDown	4,6
		KeyDOwn	5,0
		rts
KeyF4U		KeyUp	4,6
		KeyUp	5,0
		rts
KeyF6D		KeyDown	4,6
		KeyDown	6,0
		rts
KeyF6U		KeyUp	4,6
		KeyUp	6,0
		rts
KeyF8D		KeyDown	4,6
		KeyDown	3,0
		rts
KeyF8U		KeyUp	4,6
		KeyUp	3,0
		rts
KeyF9D		tst.b	NMIState	;NMI schon ausgelöst?
		bne	1$
		move.l	CycleCounter,FirstNMICycle ;Nein, Zyklus merken
		st.b	IntIsNMI	; und NMI auslösen
1$		rts
KeyNKAsterD	tst.w	KeyboardYZ
		bne	1$
		KeyDown	1,6	;*
		rts
1$		KeyDown	5,6	;=
		rts
KeyNKAsterU	tst.w	KeyboardYZ
		bne	1$
		KeyUp	1,6
		rts
1$		KeyUp	5,6
		rts
KeyNKSlashD	tst.w	KeyboardYZ
		bne	1$
		KeyDown	7,6	;/
		rts
1$		KeyDown	6,6	;^
		rts
KeyNKSlashU	tst.w	KeyboardYZ
		bne	1$
		KeyUp	7,6
		rts
1$		KeyUp	6,6
		rts
KeyNKLeftParD	KeyDown	4,6	;[
		KeyDown	5,5
		rts
KeyNKLeftParU	KeyUp	4,6
		KeyUp	5,5
		rts
KeyNKRightParD	KeyDown	4,6	;]
		KeyDown	2,6
		rts
KeyNKRightParU	KeyUp	4,6
		KeyUp	2,6
		rts

; Joystick-Emulation
KeyDownJoyUp	bclr	#0,Joystick2Key
		rts
KeyDownJoyDown	bclr	#1,Joystick2Key
		rts
KeyDownJoyLeft	bclr	#2,Joystick2Key
		rts
KeyDownJoyRight	bclr	#3,Joystick2Key
		rts
KeyDownJoyUL	bclr	#0,Joystick2Key
		bclr	#2,Joystick2Key
		rts
KeyDownJoyUR	bclr	#0,Joystick2Key
		bclr	#3,Joystick2Key
		rts
KeyDownJoyDL	bclr	#1,Joystick2Key
		bclr	#2,Joystick2Key
		rts
KeyDownJoyDR	bclr	#1,Joystick2Key
		bclr	#3,Joystick2Key
		rts
KeyDownJoyFire	bclr	#4,Joystick2Key
		rts

KeyUpJoyUp	bset	#0,Joystick2Key
		rts
KeyUpJoyDown	bset	#1,Joystick2Key
		rts
KeyUpJoyLeft	bset	#2,Joystick2Key
		rts
KeyUpJoyRight	bset	#3,Joystick2Key
		rts
KeyUpJoyUL	bset	#0,Joystick2Key
		bset	#2,Joystick2Key
		rts
KeyUpJoyUR	bset	#0,Joystick2Key
		bset	#3,Joystick2Key
		rts
KeyUpJoyDL	bset	#1,Joystick2Key
		bset	#2,Joystick2Key
		rts
KeyUpJoyDR	bset	#1,Joystick2Key
		bset	#3,Joystick2Key
		rts
KeyUpJoyFire	bset	#4,Joystick2Key
		rts


**
** Datenbereich
**

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

; Prefs
CIACycles	dc.w	0	;Unbenutzt
Joystick1On	dc.w	0	;Joystick an Port 1 wird abgefragt
Joystick2On	dc.w	0	;Joystick an Port 2 wird abgefragt
		XDEF	_JoystickSwap
_JoystickSwap
JoystickSwap	dc.w	0	;Joysticks vertauschen
KeyboardYZ	dc.w	0	;Amerikanische Tastaturbelegung

Joystick1	dc.b	0	;Joystick 1 AND-Wert
Joystick2	dc.b	0	;Joystick 2 AND-Wert
Joystick2Key	dc.b	0	;Joystick 2 AND-Wert für Emulation über Zehnerblock

; 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	5,4	;NP .
		dc.w	3,0	;NP 7
		dc.w	3,3	;NP 8
		dc.w	4,0	;NP 9

KeyDownSpecTab	dc.l	KeySpaceD
		dc.l	KeyBackD
		dc.l	KeyTabD
		dc.l	KeyEnterD
		dc.l	KeyReturnD
		dc.l	KeyEscD
		dc.l	KeyDeleteD
		dc.l	KeyNOP

		dc.l	KeyNOP
		dc.l	KeyNOP
		dc.l	KeyNOP
		dc.l	KeyNOP
		dc.l	KeyUpD
		dc.l	KeyDownD
		dc.l	KeyRightD
		dc.l	KeyLeftD

		dc.l	KeyF1D
		dc.l	KeyF2D
		dc.l	KeyF3D
		dc.l	KeyF4D
		dc.l	KeyF5D
		dc.l	KeyF6D
		dc.l	KeyF7D
		dc.l	KeyF8D

		dc.l	KeyF9D
		dc.l	KeyNOP
		dc.l	KeyNKLeftParD
		dc.l	KeyNKRightParD
		dc.l	KeyNKSlashD
		dc.l	KeyNKAsterD
		dc.l	KeyNOP
		dc.l	KeyNOP

KeyUpSpecTab	dc.l	KeySpaceU
		dc.l	KeyBackU
		dc.l	KeyTabU
		dc.l	KeyEnterU
		dc.l	KeyReturnU
		dc.l	KeyEscU
		dc.l	KeyDeleteU
		dc.l	KeyNOP

		dc.l	KeyNOP
		dc.l	KeyNOP
		dc.l	KeyNOP
		dc.l	KeyNOP
		dc.l	KeyUpU
		dc.l	KeyDownU
		dc.l	KeyRightU
		dc.l	KeyLeftU

		dc.l	KeyF1U
		dc.l	KeyF2U
		dc.l	KeyF3U
		dc.l	KeyF4U
		dc.l	KeyF5U
		dc.l	KeyF6U
		dc.l	KeyF7U
		dc.l	KeyF8U

		dc.l	KeyNOP
		dc.l	KeyNOP
		dc.l	KeyNKLeftParU
		dc.l	KeyNKRightParU
		dc.l	KeyNKSlashU
		dc.l	KeyNKAsterU
		dc.l	KeyNOP
		dc.l	KeyNOP

KeyModTable	dc.w	1,7		;Shift left
		dc.w	6,4		;Shift right
		dc.w	1,7		;Caps lock -> Shift left
		dc.w	7,2		;Control
		dc.w	7,5		;Alt left -> C=
		dc.w	7,5		;Alt right -> C=
		dc.w	7,5		;Amiga left -> C=
		dc.w	0,0		;Amiga right

; 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
InvKeyMatrix	ds.b	8	;Gespiegelte Tastaturmatrix

		END
