Source file: /~heha/hsn/terminal/sources.zip/at_ser.asm

;******************************************************************************
;** Serielle Schnittstelle, voll gepufferte E/A, „halbes“ XON/XOFF-Protokoll **
;******************************************************************************
.equ	CPUCLK		=8000000
.equ	BAUDRATE	=9600
.equ	OBUFLEN		=16		;Ausgabepuffer-Größe
.equ	IBUFLEN		=8		;Eingabepuffer-Größe
;.equ	XON_THRESHOLD	=2		;Schwelle für Senden von XON
;.equ	XOFF_THRESHOLD	=IBUFLEN-4	;Schwelle für Senden von XOFF
.equ	XON		=0x11		;^Q
.equ	XOFF		=0x13		;^S

.set	ubr	=(CPUCLK/16/BAUDRATE)-1	;Baudraten-Register-Wert (12 bit)

.dseg
obuf:	.byte	OBUFLEN		;Ausgabepuffer
ibuf:	.byte	IBUFLEN		;Eingabepuffer
.def	obufrd	=r10		;2 Zeiger in Ausgabepuffer
.def	obufwr	=r11
.def	ibufrd	=r12		;2 Zeiger in Eingabepuffer
.def	ibufwr	=r13
.def	uflags	=r14		;Flag-Bits: Bit0=XOFF
.def	inchar	=r25		;Letztes gelesenes Zeichen/Byte
.cseg

;** ISR Zeichenausgabe
isend:	cbi	UCSRB,UDRIE		;UDRIE=0, „lokale“ Interrupts gesperrt
	sei				;globale Interrupts frei
	push	r16
	push	XL
	 mov	XL,obufrd		;UDR=*obufrd++;
	 ld	r16,X+
	 out	UDR,r16
	 ldi	r16,obuf+OBUFLEN	;if (obufrd==obuf+OBUFLEN) obufrd=obuf;
	 cpse	XL,r16
	  rjmp	is1
	 ldi	XL,obuf
is1:	 mov	obufrd,XL
	 cpse	obufrd,obufwr		;if (obufrd!=obufwr) UDRIE=1;
	  sbi	UCSRB,UDRIE		; // weitere Zeichen
	pop	XL
	pop	r16
	reti

;** ISR Zeicheneingabe mit direkter XON/XOFF-Behandlung
irecv:	cbi	UCSRB,RXCIE		;RXCIE=0, „lokale“ Interrupts gesperrt
	sei				;globale Interrupts frei
	push	r16
	in	r16,SREG
	push	r16
	 in	r16,UDR			;temp=UDR;
	 cpi	r16,XOFF		;if (temp==XOFF) {
	 brne	ir1
	 cbi	UCSRB,UDRIE		; UDRIE=0;	// Senden einstellen
	 set				; uflags.xoff=1;
	 rjmp	ir2			; return;
ir1:					;}
	 cpi	r16,XON			;if (temp==XON) {
	 brne	ir3
	 cpse	obufwr,obufrd		; if (obufrd!=obufwr) UDRIE=1;
	  sbi	UCSRB,UDRIE		;	// weiter senden
	 clt				; uflags.xoff=0;
ir2:	 bld	uflags,0
	 rjmp	ire			; return;
ir3:					;}
	 push	XL
	  mov	XL,ibufwr		;*ibufwr++=UDR
	  st	X+,r16
	  cpi	XL,ibuf+IBUFLEN		;if (ibufwr==ibuf+IBUFLEN) ibufwr-=IBUFLEN
	  brne	ir4
	  subi	XL,IBUFLEN
ir4:	  mov	ibufwr,XL
	  cp	ibufrd,ibufwr		;if (ibufrd==ibufwr) {	// Überlauf
	  brne	ir6			;bei Überlauf das älteste Zeichen löschen
	  mov	XL,ibufrd
	  inc	XL			; ibufrd++;
	  cpi	XL,ibuf+IBUFLEN		; if (ibufrd==ibuf+IBUFLEN) ibufrd-=IBUFLEN;
	  brne	ir5
	  subi	XL,IBUFLEN
ir5:	  mov	ibufrd,XL
ir6:	 pop	XL
ire:	 				; }
	pop	r16
	out	SREG,r16
	pop	r16
	sbi	UCSRB,RXCIE		;RXCIE=1, „lokale“ Interrupts wieder zulassen
	reti

spac:	ldi	r16,' '		;Leerzeichen ausgeben
;** void putc(char r16)
;VR: XL
putc:	mov	XL,obufwr		;X=obufwr
	st	X+,r16			;*X++=r16; //diese Stelle ist stets frei
	cpi	XL,obuf+OBUFLEN	;if (X==obuf+OBUFSIZE) X-=OBUFSIZE;
	brne	pu1
	subi	XL,OBUFLEN
pu1:	cp	XL,obufrd		;while (X==obufrd) sleep(); //solange voll
	brne	pu2
	sleep
	rjmp	pu1
pu2:	mov	obufwr,XL		;obufwr=X; // nicht mehr voll, vorschieben
	sbrs	uflags,0
	 sbi	UCSRB,UDRIE		;ISR anschubsen, wenn kein XOFF
	ret

;** bool[NZ] peekc(void)		;setzt „inchar“
;VR: XL
	cp	ibufwr,ibufrd
	breq	pe2			;Z=1, kein Zeichen vorhanden
	mov	XL,ibufrd
	ld	inchar,X+
	cpi	XL,ibuf+IBUFLEN
	brne	pe1
	subi	XL,IBUFLEN
pe1:	clz				;Z=0, Zeichen vorhanden
pe2:	ret
Detected encoding: UTF-80