
*
* This file is the interface between the software
* and the hardware of GALer. The routines of this file
* control the hardware.
* register parameter, 32 bit integer
*
* assemble: asm Port.asm
*
* assumed scratch registers of the compiler: D0, D1, A0, A1


GAL16V8		EQU	1		; type of GAL
GAL20V8		EQU	2
GAL22V10	EQU	3
GAL20RA10	EQU	4


IC1		EQU	3		; number of IC
IC3		EQU	0		; IC1-4       : write only
IC4		EQU	1
IC5		EQU	2
IC6a		EQU	0		; IC6, IC7: read only
IC6c		EQU	4
IC7		EQU	1


HW_GALER_1_0	EQU	1		; Hardware-Version
HW_GALER_1_2	EQU	2
HW_GALER_1_3	EQU	3


ON		EQU	1		; for control of the LED
OFF		EQU	0

PROG		EQU	1		; Edit-Mode of GAL
VERIFY		EQU	0

LOW		EQU	0		; level
HIGH		EQU	1


ciaaprb		EQU	$BFE101
ciaaddrb	EQU	$BFE301
ciabpra		EQU	$BFD000
ciabddra	EQU	$BFD200



	SECTION	code,CODE


	XDEF	@InitParPort		; initialize parallel port
	XDEF	@RestoreParPort		; restore parallel-port
	XDEF	@InitGALer		; initialize GALer
	XDEF	@WriteByte		; write byte in shift register
	XDEF	@ReadByte		; read byte out of shift register
	XDEF	@SetGAL			; set type of GAL
	XDEF	@VeditOn		; edit voltage on
	XDEF	@VeditOff		; disable edit off
	XDEF	@LED			; control LED
	XDEF	@EnableVcc		; switch +5V on
	XDEF	@DisableVcc		; switch +5V off
	XDEF	@EnableVEdit		; enable edit voltage
	XDEF	@DisableVEdit		; disable edit voltage
	XDEF	@EnableOutput		; Ausgangs-Treiber aktivieren
	XDEF	@DisableOutput		; Ausgangs-Treiber deaktiviern
	XDEF	@SetRow			; set address at RAG0-RAG5
	XDEF	@SDIn			; set level of SDIn input
	XDEF	@SDOut			; get level at SDOut output
	XDEF	@Clock			; clock impuls at SCLK input
	XDEF	@STRImpuls		; make STR impuls
	XDEF	@EditMode		; set bits for edit mode
	XDEF	@ExitEditMode		; exit edit mode and switch off +5V
	XDEF	@SetPV			; set PV (VERIFY or PROG)
	XDEF	@SetVolt		; set voltage for edit mode
	XDEF	@SetPESSAVE		; set level of PESSAVE pin
	XDEF	@SetERASE		; set level of ERASE pin
	XDEF	@SetCLR			; set level of CLR pin
	XDEF	@SetARCH		; set level of ARCH pin
	XDEF	@SetBE			; set level of BE pin
	XDEF	@SetANDBE		; set level of ANDBE pin


	XDEF	_hw_version

	XREF	_GALType
	XREF	_outIC1
	XREF	_outIC3
	XREF	_outIC4
	XREF	_outIC5

	XREF	@WaitForTimer

	XREF	_LVOForbid
	XREF	_LVOPermit

	XREF	_prog_volt



* initzialize parallel port
@InitParPort:
	move.b	ciaaddrb,cia_addrb	; save direction of CIAs
	move.b	ciabddra,cia_bddra

	move.b	#%11111111,ciaaddrb	; data as output
	and.b	#%11111110,ciabddra	; use BUSY as input
	rts


* restore state of parallel port
@RestoreParPort:
	move.b	cia_addrb,ciaaddrb	; Restore data direction of CIAs
					; but don't restore the state of
	move.b	cia_bddra,d0		; the outputs. Otherwise GALer could
	and.b	#%11111110,ciabddra	; get a command like Vcc or VEdit on).
	and.b	#%00000001,d0
	or.b	d0,ciabddra
	rts


* GALer initialisieren: alle Ausgänge von IC1 auf LOW (kein OutputEnable
* für IC3,4,5 aber Register-Inhalt von IC3,4,5 auf LOW stellen)
* Parameter: keine
@InitGALer:
	or.b	#%00001000,ciaaprb	; PD3=H: Decoder deaktivieren!
	and.b	#%00001000,ciaaprb	; alle anderen Datenleitungen auf LOW
			; ACHTUNG!!!: PD3 darf nur auf LOW-Pegel gehen
			; (Decoder aktiviert werden), wenn durch PD0 und
			; PD1 das IC, das angesprochen werden soll, bereits
			; selektiert ist. Ansonsten bekommt ein IC einen Takt-
			; impuls und beim nächsten Strobe liegen dann die
			; falschen Daten an.
	move.l	#IC1,d1
	moveq	#0,d0
	bsr	@WriteByte		; Ausgänge von IC1 auf LOW	

	move.l	#IC3,d1
	moveq	#0,d0
	bsr	@WriteByte		; Ausgänge von IC3 auf LOW	

	move.l	#IC4,d1
	moveq	#0,d0
	bsr	@WriteByte		; Ausgänge von IC4 auf LOW	

	move.l	#IC5,d1
	moveq	#0,d0
	bsr	@WriteByte		; Ausgänge von IC5 auf LOW	
	rts



* SetGAL:
* Setze GAL-Type fest (GAL16V8, GAL20V8, GAL22V10, GAL20RA10)
* Aufruf: SetGAL(type);
*
@SetGAL:
	move.l	d0,_GALType
	rts



* VeditOn:
* schaltet den Sperrwandler an (IC9); siehe auch VeditOff
* Auruf: VeditOn();
@VeditOn:
	move.l	#IC1,d1
	or.l	#%00001,_outIC1		; Q1 von IC1 auf HIGH => VeditOn
	move.l	_outIC1,d0
	bsr	@WriteByte		; IC1 setzen
	rts


* VeditOff:
* schaltet den Sperrwandler aus (IC9); siehe auch VeditOn
* Auruf: VeditOff();
@VeditOff:
	move.l	#IC1,d1
	and.l	#%11111110,_outIC1	; Q1 von IC1 auf LOW => VeditOff
	move.l	_outIC1,d0
	bsr	@WriteByte		; IC1 setzen
	rts


* EnableVEdit:
* schaltet die Edit-Spannung auf Pin 2 oder Pin 4 vom Textool
* (abhänging vom eingestellten GAL-Typ)
* Aufruf: EnableVEdit();
@EnableVEdit:
	moveq	#IC1,d1			; IC1 einstellen
	cmp.l	#GAL16V8,_GALType	; 16V8 eingestellt?
	bne.s	1$			; nein, dann 20V8, 22V10, 20RA10

				;*** GAL16V8 ***
	moveq	#%00000100,d0		; Q3 von IC1 auf HIGH
	bra.s	2$
				;*** 20V8, 22V10, 20RA10 ***
1$	moveq	#%00000010,d0		; Q2 von IC1 auf HIGH

2$	or.l	d0,_outIC1
	move.l	_outIC1,d0
	bsr	@WriteByte
	rts



* DisableVEdit:
* schaltet die Edit-Spannung an Pin 2 oder Pin 4 aus
* (abhänging vom eingestellten GAL-Typ)
* Aufruf: DisableVEdit();
@DisableVEdit:
	moveq	#IC1,d1			; IC1 einstellen
	cmp.l	#GAL16V8,_GALType	; 16V8 eingestellt?
	bne.s	1$			; nein, dann wird 20V8 angenommen!
				;*** GAL16V8 ***
	move.l	#%11111011,d0		; Q3 von IC1 auf LOW
	bra.s	2$
				;*** 20V8, 22V10, 20RA10 ***
1$	move.l	#%11111101,d0		; Q2 von IC1 auf low

2$	and.l	d0,_outIC1
	move.l	_outIC1,d0
	bsr	@WriteByte
	rts




* LED:
* schaltet die LED aus bzw. an
* Aufruf: LED(ON/OFF);
@LED:
	cmp.l	#ON,d0
	bne.s	2$
	or.l	#%01000000,_outIC1
	bra.s	1$
2$	and.l	#%10111111,_outIC1
1$	move.l	#IC1,d1
	move.l	_outIC1,d0
	bsr	@WriteByte		; IC1 setzen
	rts



* EnableVcc:
* schaltet die Spannungsversorgung ein; siehe auch DisableVcc
* bei GAL16V8: Pin22 vom Textool-Sockel
* bei GAL20V8, 20RA10, 22V10: Pin24 vom Textool-Sockel
* Aufruf: EnableVcc();
@EnableVcc:
	movem.l	d0-d7/a0-a6,-(sp)	; Register retten
	move.l	#300000,d0		; 300 ms warten
	jsr	@WaitForTimer
	movem.l	(sp)+,d0-d7/a0-a6

	move.l	#IC1,d1			; IC1 selektieren
	cmp.l	#GAL16V8,_GALType	; 16V8 eingestellt?
	bne.s	1$			; nein, dann wird 20V8 angenommen!!!
	moveq	#%00011000,d0		; Q4,5 von IC1 auf HIGH=>+5V an Pin22
	bra.s	2$
1$	moveq	#%00010000,d0		; Q5 auf HIGH => +5V an Pin 24	
2$	or.l	d0,_outIC1
	move.l	_outIC1,d0
	bsr	@WriteByte		; IC1 setzen
	rts


* DisableVcc:
* schaltet die Spannungsversorgung aus; siehe auch EnableVcc
* Aufruf: DisableVcc();
@DisableVcc:
	movem.l	d0-d7/a0-a6,-(sp)	; Register retten
	move.l	#50000,d0		; sicherheitshalber 50mS warten, bis
	jsr	@WaitForTimer		; das GAL die letzte Aktion richtig
	movem.l	(sp)+,d0-d7/a0-a6

	move.l	#IC1,d1			; IC1 selektieren
	cmp.l	#GAL16V8,_GALType	; 16V8 eingestellt?
	bne.s	1$			; nein, dann wird 20V8 angenommen!!!
	move.l	#%11100111,d0		; Q4,5 von IC1 auf LOW
	bra.s	2$
1$	move.l	#%11101111,d0		; Q5 auf HIGH
2$	and.l	d0,_outIC1
	move.l	_outIC1,d0
	bsr	@WriteByte		; IC1 setzen
	rts



* EnableOutput:
* OutputEnable-Eingang (OE) von IC3, IC4, IC5 auf HIGH
* Aufruf: EnableOutput();
@EnableOutput:
	move.l	#IC1,d1
	or.l	#%00100000,_outIC1
	move.l	_outIC1,d0
	bsr	@WriteByte
	rts

* DisableOutput:
* OutputEnable-Eingang (OE) von IC3, IC4, IC5 auf LOW
* Aufruf: DisableOutput();
@DisableOutput:
	move.l	#IC1,d1
	and.l	#%11011111,_outIC1
	move.l	_outIC1,d0
	bsr	@WriteByte
	rts



* ReadByte:
* read bit from IC6a, IC6c or byte from IC7
* Call:   byte=ReadByte(source);
*         source: IC6a, IC6b, IC7
* PD3 is already HIGH, so reading is possible
@ReadByte:
	and.b	#%11111100,ciaaprb	; set PD0 and PD1 LOW

	cmp.l	#HW_GALER_1_3,_hw_version
	beq.s	rb_version1_3		; hardware version 1.3

; *** this is for the hardware versions 1.0, 1.1, 1.2 ***

	cmp.l	#IC6a,d0		; read from IC6a?
	bne.s	rb_IC7			; no, then IC7
	or.b	#%00000001,ciaaprb	; PD0 HIGH=>HIGH at Clk of IC7
					; set PD0 HIGH =>IC6a is selected
	moveq	#0,d0
	move.b	ciabpra,d0
	not.b	d0			; invert
	and.b	#%00000001,d0		; get BUSY bit
	bra	rb_end			; now we have the state of pin 22
rb_IC7
	moveq	#0,d0			; PD3 is HIGH=>reading is possible

	or.b	#%00000100,ciaaprb	; set PD2 (Strobe) HIGH => put data
	and.b	#%11111011,ciaaprb	; from input register into shift register
					; then set PD2 LOW again
					; PD3 is HIGH => reading is possible
	move.l	d2,-(sp)
	moveq	#7,d2			; loop counter
rb_l1	rol.b	#1,d0
	move.b	ciabpra,d1		; get BUSY bit
	and.b	#%00000001,d1		; AND BUSY bit
	or.b	d1,d0			; move BUSY bit in D0
	and.b	#%11111100,ciaaprb	; set PD0 LOW => LOW at Clk of IC7
	or.b	#%00000001,ciaaprb	; set PD0 HIGH => HIGH at Clk of IC7
					; ==> next bit is available
	nop
	nop
	and.b	#%11111100,ciaaprb	; set PD0 LOW=>IC6b is selected
	dbf	d2,rb_l1		; read 8 bits
	not.b	d0			; invert them
	move.l	(sp)+,d2
	bra.s	rb_end


; *** this is for hardware version 1.3  ***

rb_version1_3:

	cmp.l	#IC6a,d0		; read from IC6a?
	bne.s	rb_c1
					; read IC6a
					; PD0 and PD1 is LOW=>IC6a is selected
	moveq	#0,d0
	move.b	ciabpra,d0		; read parallel port
	not.b	d0			; invert
	and.b	#%00000001,d0		; get BUSY bit
	bra.s	rb_end			; now we have the state of pin 22


rb_c1	cmp.l	#IC6c,d0		; read from IC6b?
	bne.s	rb_c2			; no, then IC7
					; Read IC6c

	or.b	#%00000010,ciaaprb	; PD0 LOW, PD1 HIGH => IC6c is selected
	moveq	#0,d0
	move.b	ciabpra,d0		; read parallel port
	not.b	d0			; invert
	and.b	#%00000001,d0		; get BUSY bit
	bra.s	rb_end			; now we have the state of pin 23


rb_c2					; read IC7
	moveq	#0,d0			; PD3 is HIGH=>reading is possible

	or.b	#%00000101,ciaaprb	; set PD2 (Strobe) HIGH => put data
	and.b	#%11111011,ciaaprb	; from input register into shift register
					; then set PD2 LOW again
					; PD3 is HIGH => reading is possible

	move.l	d2,-(sp)
	moveq	#7,d2			; loop counter
rb_l2	rol.b	#1,d0
	move.b	ciabpra,d1		; get BUSY bit
	and.b	#%00000001,d1		; AND BUSY bit
	or.b	d1,d0			; move BUSY bit in D0
	and.b	#%11111100,ciaaprb	; set PD0 LOW => LOW at Clk of IC7
	or.b	#%00000001,ciaaprb	; set PD0 HIGH => HIGH at Clk of IC7
					; ==> next bit is available
	dbf	d2,rb_l2		; read 8 bits
	not.b	d0			; invert them
	move.l	(sp)+,d2

rb_end
	rts				; D0 is result




* WriteByte:
* schreibt das Byte "byte" in das IC "IC", wobei IC=IC1, IC3, IC4 oder IC5
* sein kann
* zuerst wird das MSB übertragen!!!
* Aufruf: WriteByte(byte,IC)
@WriteByte:
	movem.l	d2/d3,-(sp)		; Register retten
					; Datenbyte in D0
					; IC in D1
				; geschriebenes Byte mitprotokolieren
	cmp.l	#IC1,d1
	bne.s	1$
	move.l	d0,_outIC1
	bra.s	cont$
1$	cmp.l	#IC3,d1
	bne.s	2$
	move.l	d0,_outIC3
	bra.s	cont$
2$	cmp.l	#IC4,d1
	bne.s	3$
	move.l	d0,_outIC4
	bra.s	cont$
3$	move.l	d0,_outIC5
cont$

	and.b	#%11111100,ciaaprb	; PD0 und PD1 setzen (IC aus-
	or.b	d1,ciaaprb		; wählen)
	and.b	#%11110111,ciaaprb	; Decoder aktivieren

	moveq	#7,d3			; Schleifenzähler
	ror.b	#3,d0			; MSB nach D4 (Datenleitung)

loop$	move.b	d0,d2			; Datenbyte sichern
	and.b	#%00010000,d2		; Datenbit ausmaskieren
	or.b	d2,ciaaprb		; Datenbit (PD4) vom Par.-Port setzen

	or.b	#%00001000,ciaaprb	; Clock-Impuls durch PD3 geben
	and.b	#%11110111,ciaaprb	; LOW-HIGH Übergang

	and.b	#%11101111,ciaaprb	; Datenbit (PD4) auf LOW

	rol.b	#1,d0			; nächstniedrigeres Bit senden
	dbf	d3,loop$

	or.b	#%00001000,ciaaprb	; Decoder wieder deaktivieren!!!
					; (sehr WICHTIG, siehe InitGAL:)
	or.b	#%00000100,ciaaprb	; PD2 (Strobe) auf HIGH-> Daten werden
	and.b	#%11111011,ciaaprb	; vom Schieberegister in das Datenreg.
					; übernommen. Dann PD2 wieder auf LOW.
	movem.l	(sp)+,d2/d3
	rts




* SetRow:
* Adresse an RAG0-RAG5 anlegen
* Aufruf: SetRow(row);
* row:	  zu adressierende Zeile (0-63)
@SetRow:

	move.l	d0,-(sp)		; Row (D0) auf Stack

	cmp.l	#GAL22V10,_GALType
	beq	setrow22V10
	cmp.l	#GAL20RA10,_GALType
	beq	setrow20RA10

			; ***  GAL16V8 und GAL20V8  ***
				    ; RAG5 setzen (bei 16 und 20V8 gleich)
	and.l	#$fe,_outIC5		; Bit0(=RAG5) löschen
	asr.b	#5,d0			; Bit0 von D0=RAG5
	or.l	d0,_outIC5		; RAG5=Bit von D0=> RAG5 gesetzt

	cmp.l	#GAL16V8,_GALType	; GAL16V8?
	bne.s	setrow20V8		; nein, dann GAL20V8 annehmen

				;*** GAL16V8 ***
				    ; RAG0 setzen
	move.l	(sp),d0			; row holen
	and.l	#$ef,_outIC3		; Bit4(=RAG0) löschen
	and.l	#1,d0			; Bit0 von "row" ausmaskieren
	asl.b	#4,d0
	or.l	d0,_outIC3		; Bit4(=RAG0) setzen
				    ; RAG1-RAG4 setzen
	move.l	(sp),d0			; row holen
	and.l	#$0f,_outIC4		; Bit4-7(=RAG1-RAG4) löschen
	and.l	#%00011110,d0		; Bit1-4 von "row" ausmaskieren
	asl.l	#3,d0			; an Bit4-7 schieben
	or.l	d0,_outIC4		; RAG1-RAG4 setzen
	bra.s	write
				;*** GAL20V8 ***
setrow20V8			    ; RAG0 für GAL20V8 setzen
 	move.l	(sp),d0			; row holen
	and.l	#%11011111,_outIC3	; Bit5(=RAG0) löschen
	and.l	#1,d0			; Bit0 von "row" ausmaskieren
	asl.b	#5,d0
	or.l	d0,_outIC3		; Bit5(=RAG0) setzen
				    ; RAG4 setzen
	move.l	(sp),d0			; row holen
	and.l	#%01111111,_outIC4	; Bit7(=RAG4) löschen
	and.l	#%00010000,d0		; Bit4 von "row" ausmaskieren
	asl.l	#3,d0
	or.l	d0,_outIC4		; Bit7(=RAG4) setzen
				    ; RAG1-RAG3 setzen
	move.l	(sp),d0			; row holen
	and.l	#%11100011,_outIC4	; Bit2-4(=RAG1-RAG3) löschen
	and.l	#%00001110,d0		; Bit1-3 aus "row" ausmaskieren
	asl.l	#1,d0
	or.l	d0,_outIC4		; RAG1-RAG3 setzen

write				    ; errechnete Werte in ICs schreiben
	move.l	#IC3,d1
	move.l	_outIC3,d0
	bsr	@WriteByte

	move.l	#IC4,d1
	move.l	_outIC4,d0
	bsr	@WriteByte

	move.l	#IC5,d1
	move.l	_outIC5,d0
	bsr	@WriteByte

	bra.s	setrowend


			; ***  GAL22V10 und GAL20RA10  ***
setrow22V10			; bei 22V10 und 20RA10 GALs wird RAG0-5 in
setrow20RA10			; das interne Schiebereg. des GALs getaktet,
				; da diese GALs keine RAG-Pins haben
	moveq	#5,d1			; D0 = Row
setrow1
	movem.l	d0/d1,-(sp)
	and.l	#%0000001,d0		; LSB ausmaskieren
	bsr.s	@SDIn			; RAGx ins Schieberegister des
	bsr.s	@Clock			; GALs takten
	movem.l	(sp)+,d0/d1
	asr.b	#1,d0
	dbf	d1,setrow1

setrowend
	addq.l	#4,sp			; Stack korrigieren
	rts




* SDIn:
* lege ein Bit an den SDIn-Eingang (Pin 11 vom Textool-Sockel)
* Aufruf: SDIn(bit);    bit: 0=LOW; 1=HIGH
@SDIn:
					; Bit steht in d0
	asl.b	#2,d0			; an die richtige Stelle schieben
	and.l	#%11111011,_outIC5	; SDIn-Bit löschen
	or.l	d0,_outIC5		; Bit auf LOW oder HIGH setzen
	move.l	#IC5,d1
	move.l	_outIC5,d0
	bsr	@WriteByte
	rts


* SDOut:
* ein Bit aus dem SDOut-Ausgang lesen
* Pin 14 (GAL16V8, 22V10, 20RA10), Pin 15 (GAL20V8) am Textool-Sockel
* Aufruf: bit=SDOut();
* bit: 0: SDOut-Pin ist LOW; 1: SDOut-Pin ist HIGH
@SDOut:
	move.l	#IC7,d0			; ein Byte aus IC7 holen
	bsr	@ReadByte		; Bit0=Pin14, Bit1=Pin15

	cmp.l	#GAL20V8,_GALType	; GAL20V8 eingestellt?
	beq.s	sdout1			; nein, dann 16V8, 22V10, 20RA10
	and.l	#1,d0			; Bit0 ausmaskieren
	bra.s	sdoutend		; D0=Bit
				    ; GAL20V8
sdout1	asr.l	#1,d0			; SDOut-Bit an Bit-Pos. 0
	and.l	#1,d0
sdoutend				; 32-Bit-Ergebnis in D0
	rts




* Clock:
* erzeuge Clock-Impuls (Low-High-Low-Übergang) am SCLK-Eingang (Pin 10
* vom Textool-Sockel
* Aufruf: Clock();
@Clock:
	or.l	#%00000010,_outIC5	; SCLK-Bit auf HIGH
	move.l	#IC5,d1
	move.l	_outIC5,d0
	bsr	@WriteByte

	and.l	#%11111101,_outIC5	; SCLK-Bit auf LOW
	move.l	#IC5,d1
	move.l	_outIC5,d0
	bsr	@WriteByte

	rts



* STRImpuls:
* setzt /STR-Eingang (Pin 13 am Textool-Socker) für die Dauer von "STRLength"
* auf LOW
* Aufruf: STRImpuls(long STRLength);
* STRLength: Dauer des Low-Impulses in Mikrosekunden (Langwort!)
@STRImpuls:
	movem.l	d0-d7/a0-a6,-(sp)	; Register retten

	move.l	4,a6
	jsr	_LVOForbid(a6)

	and.l	#%11110111,_outIC5	; STR-Pin auf LOW
	move.l	#IC5,d1
	move.l	_outIC5,d0
	bsr	@WriteByte

	cmp.l	#100,(sp)		; bis ein Wert in ein IC getaktet wird
	bls.s	1$			; vergehen ca. 100us => keinen Timer
	move.l	(sp),d0			; Dauer des Impulses in Mikrosekunden
	jsr	@WaitForTimer		; Low-Impuls
1$
	or.l	#%00001000,_outIC5	; STR-Pin wieder auf HIGH
	move.l	#IC5,d1
	move.l	_outIC5,d0
	bsr	@WriteByte

	jsr	_LVOPermit(a6)

	movem.l	(sp)+,d0-d7/a0-a6	; Registerinhalte zurückholen
	rts



* SetPV:
* Legt am P/V-Pin den entsprechenden Pegel für "Programmieren" bzw.
* "Verify" an.
* Aufruf:  SetPV(mode);
* mode :   VERIFY (lesen, P/V low), PROG (schreiben, P/V high)
@SetPV:
					; Mode steht in D0

	cmp.l	#GAL16V8,_GALType	; GAL16V8?
	bne.s	setpv1			; nein, dann 1

				;***  GAL16V8  ***
	move.l	_outIC3,d1
	and.l	#%11011111,d1
	asl.b	#5,d0			; Mode-Bit zu Bit 5 schieben
	or.l	d0,d1
	move.l	d1,d0			; P/V setzen
	move.l	#IC3,d1			; IC3 setzen
	bsr	@WriteByte
	bra.s	setpvend

setpv1
	cmp.l	#GAL20V8,_GALType
	bne.s	setpv2
				;***  GAL20V8  ***

	move.l	_outIC3,d1
	and.l	#%10111111,d1
	asl.b	#6,d0			; Mode-Bit zu Bit 6 schieben
	or.l	d0,d1
	move.l	d1,d0			; P,/V-Bit setzen
	move.l	#IC3,d1			; IC3 setzen
	bsr	@WriteByte
	bra.s	setpvend

setpv2
				;***  22V10, 20RA10  ***

	move.l	_outIC4,d1
	and.l	#%11111011,d1
	asl.b	#2,d0
	or.l	d0,d1
	move.l	d1,d0			; P,/V-Bit setzen
	move.l	#IC4,d1			; IC4 setzen
	bsr	@WriteByte

setpvend
	rts





* Edit-Mode:
* schaltet das GAL in den Edit-Mode; /STR auf HIGH; P/V auf LOW
* und SDOUT über einen 10kOhm-Widerstand auf VIH
* Aufruf: EditMode(mode);
* mode: PROG oder VERIFY (für Spannungseinstellung)
@EditMode:
	movem.l	d0-d7/a0-a6,-(sp)	; Register sichern

	cmp.l	#GAL16V8,_GALType   	; GAL16V8?
	bne.s	em1			; nein, dann em1

				;*** GAL16V8 ***
	moveq	#IC3,d1			; IC3, P/V auf LOW
	moveq	#%00000000,d0
	bsr	@WriteByte

	moveq	#IC4,d1
	moveq	#%00000000,d0		; IC4 initialisieren
	bsr	@WriteByte

	moveq	#IC5,d1			; /STR auf HIGH
	moveq	#%00011000,d0		; IC5 initialisieren
	bsr	@WriteByte
	bra.s	em2


em1	cmp.l	#GAL20V8,_GALType
	bne.s	em5

				;*** GAL20V8 ***
	moveq	#IC3,d1			; IC3, P/V auf LOW
	moveq	#%00000000,d0
	bsr	@WriteByte

	moveq	#IC4,d1
	moveq	#%00000000,d0		; IC4 initialisieren
	bsr	@WriteByte

	moveq	#IC5,d1			; /STR auf HIGH
	moveq	#%00101000,d0		; IC5 initialisieren
	bsr	@WriteByte
	bra.s	em2


em5
				;*** GAL20RA10 ***
				;*** GAL22V10  ***

	moveq	#IC3,d1			; IC3, OPs auf VIL
	moveq	#%00000000,d0
	bsr	@WriteByte

	moveq	#IC4,d1
	moveq	#%00000000,d0		; IC4, P/V auf LOW
	bsr	@WriteByte

	moveq	#IC5,d1			; /STR, SDOUT auf HIGH
	moveq	#%00011000,d0		; IC5 initialisieren
	bsr	@WriteByte


em2
				    ; richtige Spannung auswählen
	cmp.l	#VERIFY,(sp)		; Lesen?
	bne.s	em3			; nein, dann Programmieren!

	moveq	#4,d0			; 12 Volt einstellen
	cmp.l	#GAL22V10,_GALType	; wenn 22V10, dann 16.5 Volt
	bne.s	em6
	moveq	#0,d0
em6	bsr	@SetVolt
	bra.s	em4

em3	move.l	_prog_volt,d0		; Programmierspannung einstellen
	bsr	@SetVolt

em4	bsr	@VeditOn		; Edit-Spannung aufbauen

	move.l	#50000,d0		; 50 ms warten, bis sich die
	jsr	@WaitForTimer		; Edit-Spannung aufgebaut hat

	bsr	@EnableOutput		; Bits anlegen
	bsr	@EnableVcc		; Vcc anlegen

	move.l	#100000,d0		; Prellzeit der Relais überbrücken
	jsr	@WaitForTimer

	bsr	@EnableVEdit		; Edit-Spannung anlegen
				    ; GAL befindet sich jetzt im Edit-Mode
	moveq	#5,d0			; 5 us warten bevor nächste Aktion
	jsr	@WaitForTimer		; erlaubt ist

	movem.l	(sp)+,d0-d7/a0-a6	; Registerinhalte zurückholen
	rts



* ExitEditMode:
* Schaltet zuerst VEdit und VCC ab, dann wird der Inhalt der ICs
* zurückgesetzt.
* Aufruf: ExitEditMode();
@ExitEditMode:
	movem.l	d0-d7/a0-a6,-(sp)	; Register sichern

	bsr	@DisableVEdit

	bsr	@DisableVcc

	bsr	@InitGALer

	bsr	@EnableOutput

	movem.l	(sp)+,d0-d7/a0-a6
	rts



* SetVolt:
* selektiert durch IC 10 und IC11 die gewünschte Spannung
* Aufruf: SetVolt(value);
* value:  0=16.50 Volt; 1=15.75 Volt; 2=14.5 Volt; 3=14.00 Volt; 4=12.00 Volt
*
@SetVolt:
					; Parameter in D0
	move.l	d0,-(sp)		; Wert sichern

	and.l	#%00000001,d0
	rol.l	#7,d0
	and.l	#%01111111,_outIC1
	or.l	d0,_outIC1		; Q8 (Pin 11) von IC1 setzen
	move.l	_outIC1,d0
	move.l	#IC1,d1
	bsr	@WriteByte

	move.l	(sp)+,d0
	and.l	#%00000110,d0
	rol.l	#5,d0
	and.l	#%00111111,_outIC5
	or.l	d0,_outIC5		; Q7 und Q8 von IC5 setzen
	move.l	_outIC5,d0
	move.l	#IC5,d1
	bsr	@WriteByte

	rts




** Die nachfolgenden Routinen sind ausschließlich für 22V10 und/oder 20RA10
** GALs bestimmt.



* SetPESSAVE:
* setzt den PESSAVE-Pin (Pin 4) von GAL20RA10
* Bemerkung: diese Routine ist auschließlich für 20RA10 GALs bestimmt
* Aufruf: SetPESSAVE(pegel)
* Parameter: pegel = HIGH oder LOW

* SetERASE:
* setzt den ERASE-Pin (Pin 4) von GAL22V10
* Bemerkung: diese Routine ist auschließlich für 22V10 GALs bestimmt
* Aufruf: SetERASE(pegel)
* Parameter: pegel = HIGH oder LOW

@SetPESSAVE:
@SetERASE:

	and.l	#%11110111,_outIC4
	cmp.l	LOW,d0
	beq.s	1$

	or.l	#%00001000,_outIC4

1$	move.l	#IC4,d1
	move.l	_outIC4,d0
	bsr	@WriteByte

	rts



* SetCLR:
* setzt den CLR-Pin (Pin 6) von GAL22V10 und GAL20RA10
* Aufruf: SetCLR(pegel)
* Parameter: pegel = HIGH oder LOW

@SetCLR:

	and.l	#%11011111,_outIC4
	cmp.l	LOW,d0
	beq.s	1$

	or.l	#%00100000,_outIC4

1$	move.l	#IC4,d1
	move.l	_outIC4,d0
	bsr	@WriteByte

	rts


* SetBE:
* setzt den BE-Pin (Pin 7) von GAL22V10 und GAL20RA10
* Aufruf: SetBE(pegel)
* Parameter: pegel = HIGH oder LOW

@SetBE:

	and.l	#%10111111,_outIC4
	cmp.l	LOW,d0
	beq.s	1$

	or.l	#%01000000,_outIC4

1$	move.l	#IC4,d1
	move.l	_outIC4,d0
	bsr	@WriteByte

	rts



* SetARCH:
* setzt den ARCH-Pin (Pin 8) von GAL22V10 und GAL20RA10
* Aufruf: SetARCH(pegel)
* Parameter: pegel = HIGH oder LOW

@SetARCH:

	and.l	#%01111111,_outIC4
	cmp.l	LOW,d0
	beq.s	1$

	or.l	#%10000000,_outIC4

1$	move.l	#IC4,d1
	move.l	_outIC4,d0
	bsr	@WriteByte

	rts


* SetANDBE:
* setzt den ANDBE-Pin (Pin 9) von GAL20RA10
* Bemerkung: diese Routine ist auschließlich für 22V10 GALs bestimmt
* Aufruf: SetCLR(pegel)
* Parameter: pegel = HIGH oder LOW

@SetANDBE:

	and.l	#%11111110,_outIC5
	cmp.l	LOW,d0
	beq.s	1$

	or.l	#%00000001,_outIC5

1$	move.l	#IC5,d1
	move.l	_outIC5,d0
	bsr	@WriteByte

	rts






	SECTION	data,DATA

_hw_version:	dc.l	0

cia_addrb:	dc.b	0
cia_bddra:	dc.b	0

	END
