Source file: /~heha/vt/viewers/vt080.zip/src/v2/VI²C.ASM

;Include-Datei für Videotextdekoder als TSR
;Hochoptimiert auf Geschwindigkeit und Codegröße
;Version für c't-Videotextkarte und das h#s-Derivat derselben
;API-Beschreibung:
;I2CBasis: Standard (c't): 100h, 1F0h, 200h, 220h, 300h, 3E0h
;aber:	1F0: Kollision mit Festplatte
;	200: Kollision mit Gameport
;	220: Kollision mit SoundBlaster
;	300: Kollision mit einigen Prototypen- und Netzkarten
;I2CBasis: Standard (h#s): 100h, 104h, 108h, 210h, 300h, 3e0h, 3e4h (,10ch)
;bis auf 300h keine bisher bekannten Kollisionen



;SCHNITTSTELLEN
;proc SI2C	;Sende CX Bytes zum VTD aus Puffer SI
	;PE: CX=I2CAnzahl (0 = Null Bytes)
	;    SI=Puffer im Datensegment, DS im Datensegment
	;PA: CY=1: Fehler; dann Ansprung der Critical-Error-Routine
	;    SI=SI+CX (wenn fehlerfrei)
	;VR: SI


;proc RI2C	;Empfange CX Bytes vom VTD nach Puffer DS:SI
	;PE: CX=I2CAnzahl (0 = Null Bytes)
	;    SI=Puffer im Datensegment, DS im Datensegment
	;PA: CY=1: Fehler; dann Ansprung der Critical-Error-Routine
	;    SI=SI+CX (wenn fehlerfrei)
	;VR: SI

;SStrI2C:	;PASCAL-String SI schicken

;SBufEI2C:	;Mit ein paar Steuerzeichen via STOS gefüllten Puffer ausgeben
	;PE: DI zeigt hinter das letzte aufgefüllte Zeichen im Puffer
	;PA: CX=Anzahl
	;VR: CX

;SBufI2C:	;I2CAnzahl:CX; fest aus Buf, PA:CY, VR:FLAGS

;RBufI2C:	;I2CAnzahl:CX; fest aus Buf, PA:CY, VR:FLAGS

;proc I2CInit
	;PE: -
	;PA: AL=Statusbyte
	;CY=1: I2C-Fehler (z.B. Karte nicht auf dieser Adresse)
;	call	StopI2C
;I2CStat:

;proc AddWaitI2C
	;Warte-INs hinzufügen
	;CY=1: Keine weiteren Wait-States möglich

;proc SubWaitI2C
	;Warte-INs entfernen
	;CY=1: Wait-States sind bereits Null

;proc ProgAcq
	;Programmiert VTD auf die Suche nach
	;PE: DX=Seite, Bit 15=Wildcard-Flag
	;    CX=Unterseite, Bit 15=Wildcard-Flag
	;    BH=Akquisitor-Nummer 0..3(..7)
	;PA: CY=1: Fehler auf I2C-Bus
	;VR: AX, ein paar Bytes von [Buf]

;proc GetPageInfo
	;hole aus [SI] (Abbild der Zeile 25) die Angaben über:
	;DX- Seite
	;CX- Unterseite
	;BX- C-Bits
	;AH- HamErrors
	;VR:AX,SI

;****** CCT-Hardwarezugriff-Routine (Ebene I) ******
;+++ Ebene 1a: Bitzugriff +++
INPU:	in	al,dx
adr0:	in	al,dx		;4 Waits in Form von INs
	in	al,dx
	in	al,dx
	in	al,dx
	ret

proc StartI2C		;Start für I²C-Bus
;DX ist standardmäßig bei SDAH
;(DX-2=SCLH, DX-1=SCLL, DX=SDAH, DX+1=SDAL)
	mov	dx,[I2CBasis]
	xchg	ah,al	;am Anfang: SDA=SCL=HIGH
	inc	dx
	inc	dx

	inc	dx
	call	INPU;	SDAL
	call	INPU;	SDAL	;4µs
	dec	dx
	dec	dx
	call	INPU;	SCLL	;sdal;scll am Schluß: SDA=SCL=LOW
	inc	dx
	xchg	al,ah
	ret
	endp

StopI2C:		;Ende der Übertragung
	mov	dx,[I2CBasis]
	inc	dx
	inc	dx
proc StopI2Ci		;Ende der Übertragung (intern DX=SDAH-Adr)
	inc	dx
	call	INPU;	SDAL	;Am Anfang: SDA=X, SCL=LOW
	dec	dx
	dec	dx
	dec	dx
	call	INPU;	SCLH
	call	INPU;	SCLH	;4µs
	inc	dx
	inc	dx
	call	INPU;	SDAH	;am Schluß: SDA=SCL=HlGH
	ret
	endp

;+++ Ebene 1b: Bytezugriff +++
proc SByI2C	;1 Byte senden
	;PE: AL: Zu sendendes Byte
	;    DX=SDAH-Adresse
	;PA: CY=Fehler (fehlende Empfangsquittung des SAA)
	;VR: AH
	push	cx
	mov	cx,8
	xchg	ah,al	;Datenbyte nach AH
@@l:
	rol	ah,1	;Bit7 herausshiften, ohne AH zu zerstören
	jc	@@1
	inc	dx
	call	INPU;	SDAL
	dec	dx
	jr	@@2
@@1:
	call	INPU;	SDAH
	in	al,dx	;Kontrolle, ob kein anderer stört
	shr	al,1	;(Warten hier nicht erforderlich!)
	cmc
	jc @@e
@@2:
	dec	dx
	dec	dx
	call	INPU;	SCLH	;2µs
	call	INPU;	SCLH	;4µs, Empfänger braucht Zeit zum Einsampeln
	inc	dx
	call	INPU;	SCLL
	inc	dx
	loop @@l
	call	INPU;	SDAH
	dec	dx
	dec	dx
	call	INPU;	SCLH
	inc	dx
	inc	dx
	call	INPU;	SDAH	;zum Einlesen
	shr al,1
@@e:
	dec	dx
	call	INPU;	SCLL
	inc	dx
	xchg al,ah	;unverändert
	pop cx
	ret
	endp

proc RByI2C
	;PE: Bit0(AL)=1: Letztes Byte erwartet
	;    DX: SDAH-Adresse
	;PA: AL:Datenbyte
	;    CY=1: Fehler beim Empfang (Irgendwas klemmt auf der Leitung)
	;    (tritt höchstens bei gesetztem Bit0(AL) auf!)
	;VR: AX, DX
	push	cx
	mov	cx,8
	xchg	ah,al
	call	INPU;	SDAH	;SCL ist schon Low
	dec	dx
	jr	@@l1
@@l:	;(In DIESER Schleife ist DX=SCLL=Basis+1!)
	call	INPU;	SCLL	;In der Schleife 4µs SCL auf LOW lassen
@@l1:
	dec	dx
	call	INPU;	SCLH
	inc	dx
	inc	dx
	call	INPU;	SDAH	;Bit einlesen
	shr	al,1
	rcl	ah,1	;Bit einschieben und (am Ende) Bit0 ausschieben
	dec	dx
	call	INPU;	SCLL
	loop	@@l	;Nächstes Datenbit
	inc	dx
	jc	@@1	;Wenn allerletztes Byte
	inc	dx
	call	INPU;	SDAL	;Quittungsbit
	dec	dx
	clc		;Hier gibts nie einen Fehler
	jr	@@2
@@1:
	call	INPU;	SDAH	;Zeit schinden! - Kein Quittungsbit
	in	al,dx	;Leitung abhorchen
	shr	al,1	;Störung?
	cmc		;CY=1, wenn Datenbit D0=0
@@2:
	dec	dx
	dec	dx
	call	INPU;	SCLH
	call	INPU;	SCLH	;4µs
	inc	dx
	call	INPU;	SCLL
	inc	dx
	xchg	al,ah
	pop cx
	ret
	endp

;#################################################### (ab hier
;### Fundamentale Pufferlese- und Schreibroutinen ### hardware-
;#################################################### unabhängig)
;+++ Ebene 1c: Pufferzugriff +++
CCTW	equ	22h	;Bausteinadresse zum Schreiben
CCTR	equ	23h	;Bausteinadresse zum Lesen

proc SI2C	;Sende CX Bytes zum VTD aus Puffer SI
	;PE: CX=I2CAnzahl (0 = Null Bytes)
	;    SI=Puffer im Datensegment, DS im Datensegment
	;PA: CY=1: Fehler; dann Ansprung der Critical-Error-Routine
	;    SI=SI+CX (wenn fehlerfrei)
	;VR: SI
	push	ax cx dx
	 mov	al,CCTW
	 cld
	 inc	cx
	 call	StartI2C
@@l:
	 call	SByI2C
	 jc	@@e
	 lodsb
	 loop	@@l
	 dec	si		;!!!
@@e:
	 JR	I2Cexi
	endp

proc RI2C	;Empfange CX Bytes vom VTD nach Puffer DS:SI
	;PE: CX=I2CAnzahl (0 = Null Bytes)
	;    SI=Puffer im Datensegment, DS im Datensegment
	;PA: CY=1: Fehler; dann Ansprung der Critical-Error-Routine
	;    SI=SI+CX (wenn fehlerfrei)
	;VR: SI
	push	ax cx dx
	 mov	al,CCTR
	 call	StartI2C
	 call	SByI2C
	 jc	@@e
	 jcxz	@@e
@@l:
	 cmp	cx,2	;CY=1 wenn CX=1
	 sbb	al,al	;AL=1 wenn CX=1; AL=0 sonst
	 call	RByI2C
	 jc	@@e	;Fehler beim Empfang
	 mov	[si],al
	 inc	si
	 loop	@@l
@@e:
I2Cexi:	 call StopI2Ci
	pop	dx cx ax
	jnc	@@x
	call	[pI2Cerr]	;Error Handler!
@@x:	ret
	endp

;###################################################
;### Speziellere Pufferlese- und Schreibroutinen ###
;###################################################
;+++ Schreiben +++ (SStrI2C, SBufEI2C, SBufI2C, SI2C)
SStrI2C:	;PASCAL-String SI schicken
	push	si
	 mov	cl,[si]
	 inc	si
	 mov	ch,0
	 jr	SBI2C

SBufEI2C:	;Mit ein paar Steuerzeichen via STOS gefüllten Puffer ausgeben
	;PE: DI zeigt hinter das letzte aufgefüllte Zeichen im Puffer
	;PA: CX=Anzahl
	;VR: CX
	push	si
	 mov	cx,di
	 mov	si,ofs Buf0
	 sub	cx,si
	 jr	SBI2C

SBufI2C:	;I2CAnzahl:CX; fest aus Buf, PA:CY, VR:FLAGS
	push	si
	 mov	si,ofs Buf
SBI2C:	 call	SI2C
	pop	si
	ret

;+++ Lesen +++ (RBufI2C, RI2C)
RBufI2C:	;I2CAnzahl:CX; fest aus Buf, PA:CY, VR:FLAGS
	push	si
	 mov	si,ofs Buf
	 call	RI2C
	pop	si
	ret

;################################
;### Initialisierungsroutinen ###
;################################
proc I2CInit
	;PE: -
	;PA: AL=Statusbyte
	;CY=1: I2C-Fehler (z.B. Karte nicht auf dieser Adresse)
	call	StopI2C
I2CStat:
	mov	[wo Buf],100h	;R11B adressieren
	mov	cx,2
	call	SBufI2C
	jc	@@e
	mov	[wo Buf],1401h	;Mode TCS on
	call	SBufI2C
	jc	@@e
	mov	[by Buf],0bh
	dec	cx		;Anzahl=1
	call	SBufI2C
	jc	@@e
	call	RBufI2C
	jc	@@e
	mov	al,[by Buf]	;Status und ROM-Versions-Byte
	mov	[wo Buf],000h
	inc	cx		;Anzahl=2
	call	SBufI2C
@@e:	ret
endp

proc AddWaitI2C
	;Warte-INs hinzufügen
	;CY=1: Keine weiteren Wait-States möglich
	mov	bx,[Waits]
	cmp	bx,4
	cmc
	jc	@@e
	mov	[byte adr0+bx],0ech ;= IN al,dx
	inc	[Waits]
@@e:	ret
endp

proc SubWaitI2C
	;Warte-INs entfernen
	;CY=1: Wait-States bereits auf Null
	mov	bx,[Waits]
	cmp	bx,1		;Kleiner 1?
	jc	@@e
	dec	bx
	mov	[byte adr0+bx],0C3h ;= RET
	mov	[Waits],bx
@@e:	ret
endp

proc I2Cstderr
	bset	[ctrl0],bit 7
	inc	[I2CErrors]
	stc
	ret
endp

Detected encoding: OEM (CP437)1
Wrong umlauts? - Assume file is ANSI (CP1252) encoded