	title	'zeichenbezogene Ein- und Ausgabe -- chario.asm 1.803'

;****************************************************************
;*								*
;*	CHARIO.ASM						*
;*								*
;*			CBIOS fuer jk82 CP/M PLUS 		*
;*								*
;*			CHARACTER I/O				*
;*								*
;*			Dieses Modul sollte vom Anwender nicht	*
;*			veraendert werden. Eine einwandfreie	*
;*			Funktion des Betriebssystems ist sonst	*
;*			nicht mehr gewaehrleistet.		*
;*								*
;****************************************************************
;
;****************************************************************
;*								*
;*	Erstellt am:	24.03.84 durch: D. Janich		*
;*	Modifiziert am: 22.05.84 durch: D. Janich 		*
;*	Modifiziert am: 23.08.84 durch: D. Janich  (1.500)	*
;*	Modifiziert am: 21.09.84 durch: D. Janich  (1.501)	* SIO hinzugefuegt
;*	Modifiziert am: 13.12.84 durch: D. Janich  (1.502)	* PARITY ERROR BEHOBEN
;*	Modifiziert am: 10.03.85 durch: D. Janich  (1.503)	* Input-Maske nur wenn notwendig
;*	Modifiziert am: 28.03.85 durch: D. Janich  (1.504)	* Baudrate 6Mhz P/SIO + SIO
;*	Modifiziert am: 05.06.85 durch: D. Janich  (1.507)	* EPC II hinzugefuegt
;*	Modifiziert am: 18.07.85 durch: D. Janich  (1.508)	* EPC I hinzugefuegt
;*	Modifiziert am: 18.07.85 durch: L. Kleberhoff (1.600)	* EPC I korrigiert
;*	Modifiziert am: 21.11.85 durch: D. Janich  (1.601)	* CPU II korrigiert
;*	Modifiziert am: 16.04.86 durch: D. Janich  (1.602)	* EPC II korrigiert
;*	Modifiziert am: 21.10.86 durch: D. Janich  (1.603)	* Baudratenfehler P/SIO (SIO 3) beseitigt
;*	Modifiziert am: 28.01.87 durch: D. Janich  (1.604)	* CPU180 + SL186 hinzugefuegt
;*	Modifiziert am: 31.03.87 durch: D. Janich  (1.700)	* CPU180 mit Handshake
;*	Modifiziert am: 23.06.87 durch: D. Janich  (1.701)	* CPU180 Auslieferversion
;*	Modifiziert am: 10.10.87 durch: D. Janich  (1.800)	* SL186: COM1 / MSG (ON/OFF)
;*	Modifiziert am: 31.05.88 durch: D. Janich  (1.801)	* CPU180: RTS A invertiert
;*	Modifiziert am: 04.10.88 durch: D. Janich  (1.802)	* CPU1802-S1
;*	Modifiziert am: 02.11.88 durch: D. Janich  (1.803)	* CPU1803 hinzugefuegt
;*								*
;****************************************************************
;
;****************************************************************
;*								*
;*	       Copyright (C), 1984/85/87			*
;*	     Janich & Klass Computersystems			*
;*		  Zum Alten Zollhaus 20				*
;*		   D 5600 Wuppertal 1				*
;*		      West Germany				*
;*								*
;****************************************************************

	maclib	z80
	maclib	sysdef
	maclib  modebaud
	maclib	ports
	maclib	user
if cpu180
 rpoint	equ	24h		; jk82 GLU180 Basis Adresse
 c180	equ	0c0h		; HD64180 Basis Adresse
	maclib	hd64180
	maclib	c180port
endif
;	page
	public	@ctbl		; Geraetetabelle fuer Zeichen-IO
	public	@xctbl		; erweiterte Geraetetabelle fuer Zeichen-IO
	public	?dvini		; Geraet neu initialisieren
	public	?chris		; Zeichen-IO Geraet Eingabestatus
	public	?chros		; Zeichen-IO Geraet Ausgabestatus
	public	?chrin		; Zeichen-IO Geraet Eingabe
	public	?chrout		; Zeichen-IO Geraet Ausgabe
	public	sys$clk		; Systemtakt
	public	msg		; sign on message on/off
	public	cioini		; Initialisierung des Programm-Moduls
				; und Zuweisung der Geraete
	
	extrn	@civec,@covec,@aivec,@aovec,@lovec,xxlst,intsem

if epc2
	public	bcount,blink2	; Zaehler fuer Blinkzeit
	public	bspeed		; Blinkgeschwindigkeit

	extrn	char1,vout,vinit,blnkcur,getfifo,prntdot
else
 if cpu183
				; GR1803
	extrn	gr3ini		; Initialisierungsroutine
	extrn	gr3ist		; Input-Status-Routine
	extrn	gr3ost		; Output-Status-Routine
	extrn	gr3ich		; Input-Routine
	extrn	gr3och		; Output-Routine
 else
	public	termid		; Identifikation fuer EPC7220 oder CPU1803
	termid	equ	0	; nicht vorhanden
 endif
endif
if sl186
	;
	; Alle Routinen werden im Modul sl186IO.rel bereitgestellt
	;
				; SL186
	extrn	?INI186		; Initialisierungsroutine
	extrn	?IS186		; Input-Status-Routine
	extrn	?OS186		; Output-Status-Routine
	extrn	?IN186		; Input-Routine
	extrn	?OUT186		; Output-Routine

				; COM1
	extrn	?INIPS0		; Initialisierungsroutine
	extrn	?ISPS0		; Input-Status-Routine
	extrn	?OSPS0		; Output-Status-Routine
	extrn	?INPS0		; Input-Routine
	extrn	?OUTPS0		; Output-Routine

				; PCCON
	extrn	?INIPCN		; Initialisierungsroutine
	extrn	?ISPCN		; Input-Status-Routine
	extrn	?OSPCN		; Output-Status-Routine
	extrn	?INPCN		; Input-Routine
	extrn	?OUTPCN		; Output-Routine
else
	public	sl18id		; Identifikation fuer SL186IO
	sl18id	equ	0	; nicht vorhanden
endif

if s1x182
	;
	; Alle Routinen fuer LCD-Output werden im Modul LCD182.rel bereitgestellt
	;
				; LCD182
	extrn	?INIlcd		; Initialisierungsroutine
;	extrn	?ISlcd		; Input-Status-Routine (nicht vorhanden)
	extrn	?OSlcd		; Output-Status-Routine
;	extrn	?INlcd		; Input-Routine (nicht vorhanden)
	extrn	?OUTlcd		; Output-Routine

else
	public	lcdid		; Identifikation fuer LCD182
	lcdid	equ	0	; nicht vorhanden
endif
	page
;===============================================================+
;								I
; Character-IO-Identifikation					I
;								I
	public	charid		; Character-IO-ID		I
;								I
	dseg			;				I
;								I
charid				;				I
	db	'ID',cr,lf,'CHARIO   1.803  '	;		I
	db	'character I/O for'		;		I
if video1					;		I
	db	' VIDEO I '			;		I
endif						;		I
if cpu181					;		I
	db	' CPU 1801 '			;		I
endif						;		I
if cpu182					;		I
	db	' CPU 1802 '			;		I
endif						;		I
if s1x182					;		I
	db	'S1 '				;		I
endif						;		I
if cpu183					;		I
	db	' CPU 1803 '			;		I
endif						;		I
if cpu1						;		I
	db	' CPU I '			;		I
endif						;		I
if cpu2a					;		I
	db	' CPU 2A '			;		I
endif						;		I
if cpu2n					;		I
	db	' CPU 2N '			;		I
endif						;		I
if hkm						;		I
	db	' HKM-CPU '			;		I
endif						;		I
if epc1						;		I
	db	' EPC 1.6 '			;		I
endif						;		I
if epc2						;		I
	db	' EPC II '			;		I
endif						;		I
if sl186					;		I
	db	' SL186 '			;		I
endif						;		I
if psio						;		I
	db	' P/SIO '			;		I
endif						;		I
if sio						;		I
	db	' SIO '				;		I
endif						;		I
if gpib						;		I
	db	' GPIB '			;		I
endif						;		I
if noinst					;		I
	db	' *** not installed ***'	;		I
endif						;		I
	db	0				;		I
;								I
;===============================================================+
;
;
input 		macro 	port,control
		lda	control		; Controlbyte einlesen
		mov	c,a
		ral			; bit 7 loeschen
		srar	a		; "
		ana	c
		ori	0011$1111b	; Paritymaske ok
		mov	c,a
		in	port
		ana	c		; Parity ausmaskieren
		ret
		endm

output		macro	port
		mov	a,c		; character nach a
		out	port
		ret
		endm

status		macro	port,bitnummer
		in	port		; statusport einlesen
		status$end bitnummer
		endm

status$end 	macro	bitnummer	; Ende einer Status-routine
		ani	bitnummer
                rz
		mvi	a,255
		ret
		endm

init		macro	hlad,dead,bad,cad
		lxi	h,hlad
		lxi	d,dead
		lxi	b,(bad shl 8)+cad
		jmp	?ini$sio$ctc
		endm

inits		macro	hlad,dead,bad,cad
		lxi	h,hlad
		lxi	d,dead
		lxi	b,(bad shl 8)+cad
		jmp	?ini$sio$8253
		endm

chk$max$dev	macro	ziel
		mvi	a,maxdev-1
		cmp	b
		jc	ziel
		endm

if cpu180
input0 		macro 	port		; Controlbyte muss bereits in a stehen
		mov	c,a		; Controlbyte in c sichern
		ral			; bit 7 loeschen
		srar	a		; "
		ana	c
		ori	0011$1111b	; Paritymaske ok
		mov	c,a
		IN0	A,(PORT)
		ana	c		; Parity ausmaskieren
		ret
		endm

output0		macro	port
		out0	(port),c	; character ist in c
		ret
		endm
endif
	page
;----------------------------------------------------------------------
	dseg

;	*********************************************************
;	*	Zeitkonstanten fuer die CTC-Programmierung	*
;	*********************************************************
;
;	Es wurden nur die von CP/M Plus unterstuetzten Uebertragungsgeschw.
;	(50,75,110,134.5,150,300,600,1200,1800,2400,3600,4800,7200,9600,19200)
;	beruecksichtigt. Insbesondere entfallen die nach der Norm unzulaessigen
;	Baudraten von mehr als 20 kBaud und einige Zwischenwerte (2000 Baud etc.).
;
;	*****************************************************************************************
;
;	Bedeutung und Parameter (Prescaler stets 16 bei Timer-Mode):
;
;	+---------+-----------+----------+----------+-------------------------------------------+
;	I Tabelle I Baudrate  I CTC-Mode I SIO-Mode I Bedeutung					I
;	+---------+-----------+----------+----------+-------------------------------------------+
;	I thicpu1 I 600-19200 I Counter  I  *16     I > 300 Baud fuer CPU I (1.2288 MHz)	I
;	I thipsio I 600-19200 I Counter  I  *16     I > 300 Baud fuer P/SIO (1.2288 MHz)	I
;	I thiepc  I 600-19200 I Counter  I  *16     I > 300 Baud fuer EPC   (1.8432 MHz)	I
;	I thi4	  I 600-19200 I Counter  I  *16     I > 300 Baud fuer Systemtakt 4 MHz		I
;	I thi5    I 600-19200 I Counter  I  *16     I > 300 Baud fuer Systemtakt 4,9152 MHz	I
;	I thi6	  I 600-19200 I Counter  I  *32     I > 300 Baud fuer Systemtakt 6 MHz		I
;	I thi8    I 600-19200 I Counter  I  *32     I > 300 Baud fuer Systemtakt 8 MHz		I
;	I tlo4	  I  50-300   I Timer	 I  *32     I <=300 Baud fuer Systemtakt 4 MHz		I
;	I tlo5    I  50-300   I Timer    I  *32     I <=300 Baud fuer Systemtakt 4,9152 MHz	I
;	I tlo6	  I  50-300   I Timer    I  *32     I <=300 Baud fuer Systemtakt 6 MHz		I
;	I tpsio	  I  50-300   I Timer    I  *32     I <=300 Baud fuer Systemtakt 6,144 MHz	I
;	I tlo8	  I  75-300   I Timer    I  *32     I <=300 Baud fuer Systemtakt 8 MHz		I
;	+---------+-----------+----------+----------+-------------------------------------------+
;
;	*****************************************************************************************
;
if not cpu180
  ?tlow:	db	156,104, 71, 58, 52, 26			; CPU 2, 4MHz
  ?thigh:	db	208,104, 69, 52, 35, 26, 17, 13,  7	; CPU 2, 4MHz

  ?tlo4		equ	?tlow
  ?tlo5:	db	192,128, 87, 71, 64, 32
  ?tlo6:	db	234,156,107, 87, 78, 39
  ?tlo8:	db	0,  204,139,114,102, 51			; 8 / 7,5 MHz switched Clock
endif ; not cpu180
								; Fehler bei 50 Baud zu gross!
 if epc2
  ?thi6:	db	224,112, 76, 56, 38, 28, 19, 14,  7	; scheinbarer Takt: 2,18MHz
  ?thi8		equ	?thigh					; takt 4 MHz
 endif

 if cpu2a or hkm
   ?thi4	equ	?thigh					; Fehler bei 19200Bd zu gross.
   ?thi5:	db	  0,128, 85, 64, 43, 32, 21, 16,  8
   ?thi6:	db	156, 78, 52, 39, 26, 20, 13, 10,  5
   ?thi8	equ	?thigh
 endif

 if cpu12
   ?thicpu1:	db	128, 64, 43, 32, 21, 16, 11,  8,  4
 endif

 if epc1
   ?thiepc:	db	192, 96, 64, 48, 32, 24, 16, 12,  6
 endif

 if psio or s1x182
  if cpu12
     ?tpsio	equ	?tlow
  else
     ?tpsio:	db	240,160,109, 89, 80, 40			; 6,144 MHz
	if psio
		db	128, 64, 43, 32, 21, 16, 11,  8,  4
	endif
	if s1x182
		db	0, 128, 86, 64, 42, 32, 22, 16,  8
	endif

  endif
 endif

 if sio				;		sio programmiert im x32-Mode
    ?tsio	dw	2500	;    50 baud
		dw	1666	;    75 baud
		dw	1136	;   110 baud
		dw	 929	;   134,5 baud
		dw	 833	;   150 baud
		dw	 416	;   300 baud
				;		sio programmiert im x16-Mode
		dw	 417	;   600 baud
		dw	 208	;  1200 baud
		dw	 139	;  1800 baud
		dw	 104	;  2400 baud
		dw	  69	;  3600 baud
		dw	  52	;  4800 baud
		dw	  35	;  7200 baud
		dw	  26	;  9600 baud
		dw	  13	; 19200 baud
 endif
 if cpu180
    ?tcpu180	db	0010$1110b	;    50 baud
		db	1111$1111b	;    75 baud   (nicht moeglich)
		db	1111$1111B	;   110 baud   (nicht moeglich)
		db	1111$1111B	;   134,5 baud (nicht moeglich)
		db	0000$1110b	;   150 baud
		db	0000$1101b	;   300 baud
		db	0000$1100b	;   600 baud
		db	0000$1011b	;  1200 baud
		db	1111$1111B	;  1800 baud   (nicht moeglich)
		db	0000$1010b	;  2400 baud
		db	1111$1111B	;  3600 baud   (nicht moeglich)
		db	0000$1001b	;  4800 baud
		db	1111$1111B	;  7200 baud   (nicht moeglich)
		db	0000$1000b	;  9600 baud
		db	0000$0001b	; 19200 baud
		db	0000$0000b	; 38400 baud
 endif
	page
;----------------------------------------------------------------------
	cseg
		dw	@xctbl	; Erweiterung der CP/M PLUS Geraetetabelle
;
@ctbl:				; CPM PLUS Geraetetabelle
;
 if video1
		db	'VIDEO1'	; jk82 VIDEO I-Platine
		db	mb$in$out
		db	baud$none
 endif
;
 if not cpu3
		db	'SIOA  '	; SIO Port A auf CPU-Platine
  if noinst and not cpu180
		db	mb$in$out
   baud$sioa:	db	baud$none
  else
		db	mb$in$out+mb$soft$baud+mb$serial
   baud$sioa:	db	baud$9600
  endif
;
		db	'SIOB  '	; SIO Port B auf CPU-Platine
  if (noinst and not cpu180) or epc2
		db	mb$in$out
   baud$siob:	db	baud$none
  else
		db	mb$in$out+mb$soft$baud+mb$serial
   if cpu183
    baud$siob:	db	baud$1200
   else
    baud$siob:	db	baud$9600
   endif
  endif
 endif
;
 if epc2
		db	'SCREEN'	; 7220 display controller
		db	mb$output
		db	baud$none
 endif
;
 if cpu183
		db	'GR1803'	; Device-Name
		db	mb$in$out	; I/O
		db	baud$none	; keine Baudrate
 endif
;
 if psio or s1x182
		db	'SIO1  '	; SIO 1 Port A auf P/SIO-Platine
  if noinst
		db	mb$in$out
   baud$sio1:	db	baud$none
  else
		db	mb$in$out+mb$soft$baud+mb$serial
   baud$sio1:	db	baud$9600
  endif
;
		db	'SIO2  '	; SIO 1 Port B auf P/SIO-Platine
  if noinst
		db	mb$in$out
   baud$sio2:	db	baud$none
  else
		db	mb$in$out+mb$soft$baud+mb$serial
   baud$sio2:	db	baud$9600
  endif
;
 endif
 if psio
		db	'SIO3  '	; SIO 2 Port A auf P/SIO-Platine
  if noinst
		db	mb$in$out
   baud$sio3:	db	baud$none
  else
		db	mb$in$out+mb$serial
   baud$sio3:	db	baud$9600	; starr mit SIO1 gekoppelt
  endif
;
		db	'SIO4  '	; SIO 2 Port B auf P/SIO-Platine
  if noinst
		db	mb$in$out
   baud$sio4:	db	baud$none
  else
		db	mb$in$out+mb$soft$baud+mb$serial
   baud$sio4:	db	baud$9600
  endif
 endif
;
 if sl186
		db	'SL186 '	; Communikations-Device auf der SL186-Platine
		db	mb$in$out	; Input/Output
		db	baud$none	; No Baudrate

		db	'COM1  '	; Serielle Schnittstelle auf der SL186-Platine
		db	mb$in$out+mb$soft$baud+mb$serial
   baud$com1:	db	baud$9600

		db	'PCCON '	; Console (Tastatur+Screen) auf der SL186-Platine
		db	mb$in$out	; Input/Output
		db	baud$none	; No Baudrate
 endif
;
 if not cpu3
		db	'CEN   '	; Centronics-Port auf der CPU-Platine
		db	mb$output
		db	baud$none
 endif
;
 if psio
		db	'CEN1  '	; Centronics-Port auf der P/SIO-Platine
		db	mb$output
		db	baud$none
 endif
;
 if gpib
		db	'CEN2  '	; Centronics-Port auf der GPIB-Platine
		db	mb$output
		db	baud$none
 endif
;
 if sio
		db	'SIO1S '	; SIO 1 Port A auf SIO-Platine
		db	mb$in$out+mb$soft$baud+mb$serial
   baud$sio1s:	db	baud$9600
;
		db	'SIO2S '	; SIO 1 Port B auf SIO-Platine
		db	mb$in$out+mb$soft$baud+mb$serial
   baud$sio2s:	db	baud$9600
;
		db	'SIO3S '	; SIO 2 Port A auf SIO-Platine
		db	mb$in$out+mb$soft$baud+mb$serial
   baud$sio3s:	db	baud$9600
;
		db	'SIO4S '	; SIO 2 Port B auf SIO-Platine
		db	mb$in$out+mb$soft$baud+mb$serial
   baud$sio4s:	db	baud$9600
 endif
 if s1x182
		db	'LCD182'	; LCD-Display auf CPU 1802 S1
		db	mb$output
		db	baud$none
 endif

	inctbl				; Benutzereintrag in obige Tabelle
;
		db	0		; Terminator
;
;------------------
@xctbl:				; Erweiterung zur Geraetetabelle
;------------------
;
 if video1
		db	baud$none				; VIDEO1
 		db	no$time$out
		db	0,0,0,0,0,0				; Reserviert
 endif
if not cpu3
 if not cpu180
  control$sioa:	db	mb$handshake+mb$parity+mb$stop1+mb$bit8	; SIOA
 else
  control$sioa:	db	mb$handshake+mb$handshake$on+mb$parity+mb$stop1+mb$bit8	; SIOA
 endif
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
 if epc2
  control$siob:	db	mb$stop1+mb$bit8			; SIOB
		db	no$time$out
 else
  control$siob:	db	mb$handshake+mb$parity+mb$stop1+mb$bit8	; SIOB
		db	time$out$long
 endif
		db	0,0,0,0,0,0				; Reserviert
endif
 if cpu183
	db	0		; Kontroll-Byte fuer Handshake,
				; Parity, Stop-Bits, Wortlaenge
	db	0		; Time-Out-Laenge in Sekunden bis
				; das Geraet garantiert 'FERTIG'
				; melden muss.
	db	0,0,0,0,0,0	; Reserviert
 endif
 if epc2
  control$7220	db	baud$none				; 7220 GDP
		db	0
		db	0,0,0,0,0,0				; Reserviert
 endif
 if psio or s1x182
  control$sio1:	db	mb$handshake+mb$parity+mb$stop1+mb$bit8	; SIO1
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
  control$sio2:	db	mb$handshake+mb$parity+mb$stop1+mb$bit8	; SIO2
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
 endif
 if psio
  if psio4 or dpsio
   control$sio3:	db	mb$handshake+mb$parity+mb$stop1+mb$bit8	; SIO3
  else
   control$sio3:	db	mb$parity+mb$stop1+mb$bit8	; SIO3
  endif
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
  control$sio4:	db	mb$handshake+mb$parity+mb$stop1+mb$bit8	; SIO4
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
 endif
 if sl186
		db	baud$none				; SL186
		db	0					; kein time out
		db	mb$sl186				; SL186-Device
		db	0,0,0,0,0				; Reserviert

		db	mb$parity+mb$stop1+mb$bit8		; COM1
		db	0					; kein time out
		db	mb$sl186				; SL186-Device
		db	0,0,0,0,0				; Reserviert

		db	baud$none				; PCCON
		db	0					; kein time out
		db	mb$sl186				; SL186-Device
		db	0,0,0,0,0				; Reserviert
 endif
 if not cpu3
		db	baud$none				; CEN
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
 endif
 if psio
		db	baud$none				; CEN1
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
 endif
 if gpib
		db	baud$none				; CEN2
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
 endif
if sio
 control$sio1s:	db	mb$handshake+mb$parity+mb$stop1+mb$bit8	; SIO1S
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
 if sio4
  control$sio2s:	db	mb$handshake+mb$parity+mb$stop1+mb$bit8	; SIO2S
 else
  control$sio2s:	db	mb$parity+mb$stop1+mb$bit8		; SIO2S
 endif
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
 control$sio3s:	db	mb$handshake+mb$parity+mb$stop1+mb$bit8	; SIO3S
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
 if sio4
  control$sio4s:	db	mb$handshake+mb$parity+mb$stop1+mb$bit8	; SIO4S
 else
  control$sio4s:	db	mb$parity+mb$stop1+mb$bit8		; SIO4S
 endif
		db	time$out$long
		db	0,0,0,0,0,0				; Reserviert
endif
 if s1x182
		db	baud$none				; LCD182
 		db	no$time$out
		db	0,0,0,0,0,0				; Reserviert
 endif
;
	inxctbl			; Benutzereintrag in obige Tabelle
;
maxdev		equ	($-@xctbl)/8	; Anzahl der definierten Devices
;
;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg
;
?chario$driver:			; Tabelle der einzelnen Geraetetreiber
;
 if video1
		dw	?invideo1	; VIDEO1 ==> Dummy-Input
		dw	?isvideo1	; VIDEO1 ==> Input-Status
		dw	?osvideo1	; VIDEO1 ==> Output-Status
		dw	?invideo1	; VIDEO1 ==> Input-Routine
		dw	?outvideo1	; VIDEO1 ==> Output-Routine
 endif
 if not cpu3
		dw	?inisioa	; SIOA ==> Initialisierung
		dw	?issioa		; SIOA ==> Input-Status
		dw	?ossioa		; SIOA ==> Output-Status
		dw	?insioa		; SIOA ==> Input-Routine
		dw	?outsioa	; SIOA ==> Output-Routine
;
		dw	?inisiob	; SIOB ==> Initialisierung
		dw	?issiob		; SIOB ==> Input-Status
		dw	?ossiob		; SIOB ==> Output-Status
		dw	?insiob		; SIOB ==> Input-Routine
		dw	?outsiob	; SIOB ==> Output-Routine
 endif
 if cpu183
		dw	gr3ini		; GR1803 ==> Initialisierungsroutine
		dw	gr3ist		; GR1803 ==> Input-Status-Routine
		dw	gr3ost		; GR1803 ==> Output-Status-Routine
		dw	gr3ich		; GR1803 ==> Input-Routine
		dw	gr3och		; GR1803 ==> Output-Routine
 endif
 if epc2
		dw	vinit		; SCREEN ==> Init 7220
		dw	?isbusy		; SCREEN ==> Input ist immer busy
		dw	?os7220		; SCREEN ==> Output-Status
		dw	?in$no		; SCREEN ==> Kein Input moeglich
		dw	vout		; SCREEN ==> Output-Routine
 endif
 if psio or s1x182
		dw	?inisio1	; SIO1 ==> Initialisierung
		dw	?issio1		; SIO1 ==> Input-Status
		dw	?ossio1		; SIO1 ==> Output-Status
		dw	?insio1		; SIO1 ==> Input-Routine
		dw	?outsio1	; SIO1 ==> Output-Routine
;
		dw	?inisio2	; SIO2 ==> Initialisierung
		dw	?issio2		; SIO2 ==> Input-Status
		dw	?ossio2		; SIO2 ==> Output-Status
		dw	?insio2		; SIO2 ==> Input-Routine
		dw	?outsio2	; SIO2 ==> Output-Routine
;
 endif
 if psio
		dw	?inisio3	; SIO3 ==> Initialisierung
		dw	?issio3		; SIO3 ==> Input-Status
		dw	?ossio3		; SIO3 ==> Output-Status
		dw	?insio3		; SIO3 ==> Input-Routine
		dw	?outsio3	; SIO3 ==> Output-Routine
;
		dw	?inisio4	; SIO4 ==> Initialisierung
		dw	?issio4		; SIO4 ==> Input-Status
		dw	?ossio4		; SIO4 ==> Output-Status
		dw	?insio4		; SIO4 ==> Input-Routine
		dw	?outsio4	; SIO4 ==> Output-Routine
 endif
 if sl186
		dw	?INI186		; SL186 ==> Initialisierungsroutine
		dw	?IS186		; SL186 ==> Input-Status-Routine
		dw	?OS186		; SL186 ==> Output-Status-Routine
		dw	?IN186		; SL186 ==> Input-Routine
		dw	?OUT186		; SL186 ==> Output-Routine

		dw	?INIPS0		; COM1 ==> Initialisierungsroutine
		dw	?ISPS0		; COM1 ==> Input-Status-Routine
		dw	?OSPS0		; COM1 ==> Output-Status-Routine
		dw	?INPS0		; COM1 ==> Input-Routine
		dw	?OUTPS0		; COM1 ==> Output-Routine

		dw	?INIPCN		; PCCON ==> Initialisierungsroutine
		dw	?ISPCN		; PCCON ==> Input-Status-Routine
		dw	?OSPCN		; PCCON ==> Output-Status-Routine
		dw	?INPCN		; PCCON ==> Input-Routine
		dw	?OUTPCN		; PCCON ==> Output-Routine
 endif
 if not cpu3
  if cpu180
		dw	?nothing	; CEN ==> Initialisierung nicht notwendig
  else
		dw	?inicen		; CEN ==> Initialisierung
  endif
		dw	?isbusy		; CEN ==> Input ist immer busy
		dw	?oscen		; CEN ==> Output-Status
		dw	?in$no		; CEN ==> kein Input moeglich
		dw	?outcen		; CEN ==> Output-Routine
 endif
 if psio
		dw	?inicen1	; CEN1 ==> Initialisierung
		dw	?isbusy		; CEN1 ==> Input ist immer busy
		dw	?oscen1		; CEN1 ==> Output-Status
		dw	?in$no		; CEN1 ==> kein Input moeglich
		dw	?outcen1	; CEN1 ==> Output-Routine
 endif
 if gpib
		dw	?inicen2	; CEN2 ==> Initialisierung
		dw	?isbusy		; CEN2 ==> Input ist immer busy
		dw	?oscen2		; CEN2 ==> Output-Status
		dw	?in$no		; CEN2 ==> kein Input moeglich
		dw	?outcen2	; CEN2 ==> Output-Routine
 endif
 if sio
		dw	?inisio1s	; SIO1S ==> Initialisierung
		dw	?issio1s	; SIO1S ==> Input-Status
		dw	?ossio1s	; SIO1S ==> Output-Status
		dw	?insio1s	; SIO1S ==> Input-Routine
		dw	?outsio1s	; SIO1S ==> Output-Routine
;
		dw	?inisio2s	; SIO2S ==> Initialisierung
		dw	?issio2s	; SIO2S ==> Input-Status
		dw	?ossio2s	; SIO2S ==> Output-Status
		dw	?insio2s	; SIO2S ==> Input-Routine
		dw	?outsio2s	; SIO2S ==> Output-Routine
;
		dw	?inisio3s	; SIO3S ==> Initialisierung
		dw	?issio3s	; SIO3S ==> Input-Status
		dw	?ossio3s	; SIO3S ==> Output-Status
		dw	?insio3s	; SIO3S ==> Input-Routine
		dw	?outsio3s	; SIO3S ==> Output-Routine
;
		dw	?inisio4s	; SIO4S ==> Initialisierung
		dw	?issio4s	; SIO4S ==> Input-Status
		dw	?ossio4s	; SIO4S ==> Output-Status
		dw	?insio4s	; SIO4S ==> Input-Routine
		dw	?outsio4s	; SIO4S ==> Output-Routine
 endif
 if s1x182
		dw	?inilcd		; LCD182 ==> Initialisierung
		dw	?isbusy		; LCD182 ==> Input ist immer busy
		dw	?oslcd		; LCD182 ==> Output-Status
		dw	?in$no		; LCD182 ==> kein Input moeglich
		dw	?outlcd		; LCD182 ==> Output-Routine
 endif
;
	inchtbl			; Benutzereintrag in obige Tabelle
;
;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg

cioini:	;********************************************************
	;*	Initialisierung des Programm-Moduls und 	*
	;*	Zuweisung der Geraete nach dem Ladevorgang	*
	;********************************************************
	;*	in:	IX <> 0fff0h ==> cpmldr 3.16		*
	;*		IY (bit 0..3) = Baudratencode bei 3.16	*
	;*		IX =  0fff0h ==> ldr-Vektor		*
	;*	out:	----					*
	;********************************************************

if not cpu180
		lxi	d,?tlow		; CTC-Tabelle untere Haelfte
		lxi	b,6		; Laenge der CTC-Tabelle
endif
		ldx	a,5		; ld a,(ix+5) ==> Systemtakt
		sta	sys$clock
if not (epc2 or cpu180)
		cpi	4		; 4 MHz ?
		jrz	vier$mhz
		cpi	5		; 5 MHz ?
		jrz	fuenf$mhz
		cpi	6		; 6 MHz ?
		jrz	sechs$mhz
		cpi	8		; 8 MHz ?
		jrnz	geraete$zuweisung

 acht$mhz:  ;***** 8 MHz *****

		lxi h,?tlo8 ! ldir	; CTC-Tabelle untere Haelfte OK

 if cpu2a or hkm
		lxi h,?thi8
 endif

 if cpu12
		lxi h,?thicpu1
 endif

 if epc1
		lxi h,?thiepc
 endif

		lxi b,9 ! ldir		;     obere Haelfte OK

 if psio
		lxi h,?tlo8 ! jr psio$456mhz
  else
		jr baudraten$festlegung
 endif

endif	; not (epc2 or cpu180)

 sechs$mhz: ;***** 6 MHz *****

if not cpu180
		lxi h,?tlo6 ! ldir	; CTC-Tabelle untere Haelfte OK
endif
if cpu2a or hkm or epc2
		lxi	h,?thi6
endif

if cpu12
		lxi	h,?thicpu1
endif

if epc1
		lxi	h,?thiepc
endif
if not cpu180
		lxi b,9	! ldir		; CTC-Tabelle obere Haelfte OK
endif
if psio and not cpu180
		lxi h,?tlo6 ! jr psio$456mhz
else
 if not cpu180
		jr	baudraten$festlegung
 endif
endif

if not (epc2 or cpu180)

 fuenf$mhz:	;***** 5 MHz *****

		lxi h,?tlo5 ! ldir	; CTC-Tabelle untere Haelfte OK
 if cpu2a or hkm
		lxi	h,?thi5
 endif

 if cpu12
		lxi	h,?thicpu1
 endif

 if epc1
		lxi	h,?thiepc
 endif
		lxi b,9	! ldir		; CTC-Tabelle obere Haelfte OK

 if psio
		lxi h,?tlo5 ! jr psio$456mhz
 else
		jr	baudraten$festlegung
 endif
		

 vier$mhz:	;***** 4 MHz *****

		lxi h,?tlo4 ! ldir	; CTC-Tabelle untere Haelfte OK
 if cpu2a or hkm
		lxi	h,?thi4
 endif

 if cpu12
		lxi	h,?thicpu1
 endif

 if epc1
		lxi	h,?thiepc
 endif
		lxi b,9	! ldir		; CTC-Tabelle obere Haelfte OK

endif	; not (epc2 or cpu180)

if psio and not cpu180
		lxi	h,?tlo4
 psio$456mhz:
		lxi	d,?tpsio
		lxi	b,6
		ldir			; CTC-Tabelle fuer P/SIO OK
endif

;********************************************************
;*	Baudrate der Boot-Device bestimmen		*
;********************************************************

; Boot-Device in (IX+3): 1 - VIDEO1
;			 2 - SIOB
;			 3 - SIO2
;			 4 - PCCON

baudraten$festlegung:

if (CPU180 and not cpu183) OR not (noinst or epc2)

		ldx	a,3		; ld a,(ix+3) ==> boot-device
 if not cpu3
		cpi	2		; sio b ?
		jrnz	nicht$siob
		ldx	a,4		; ld a,(ix+4) ==> baudratencode
		sta	baud$siob
		jr	geraete$zuweisung
 endif

  nicht$siob:

 if psio
		cpi	3		; sio 2 ?
		jrnz	geraete$zuweisung
		ldx	a,4		; ld a,(ix+4) ==> baudratencode
		sta	baud$sio2
 endif
endif ; (CPU180 and not cpu183) OR not (noinst or epc2)


;********************************************************
;*	Zuweisung der Geraete nach dem Ladevorgang	*
;********************************************************

;***** Ermittlung des "CON:"-Vektors *****

if video1
 convek	equ	0010$0000$0000$0000b	; siob
else
 convek	equ	0100$0000$0000$0000b	; siob
endif

conivek	equ	convek			; console in  epc2
conovek	equ	convek shr 1		; console out epc2

if cpu3
 convek$pc	set	0010$0000$0000$0000b	; pccon
else
 convek$pc	set	0000$1000$0000$0000b	; pccon
endif

if video1
 convek$pc	set	convek$pc shr 1
endif

;***** Ermittlung des "AUX:"-Vektors *****

auxvek	equ	convek shl 1

;***** Ermittlung des "LST:"-Vektors *****

lstvek	set	convek shr 1

if s1x182
  lstvek	set	lstvek shr 2
  convek$pc	set	convek$pc shr 2
endif

if psio
 if not cpu3
  lstvek	set	lstvek shr 4
  convek$pc	set	convek$pc shr 4
 else
  lstvek	set	lstvek shr 2
  convek$pc	set	convek$pc shr 4
 endif
endif

if sl186
 if cpu3 and not (psio or gpib)
  lstvek	set	convek$pc shl 1
 else
  lstvek	set	lstvek shr 3
 endif
endif

if epc2 or cpu183
  lstvek	set	lstvek shr 1
endif

geraete$zuweisung:

if not (epc2 or cpu183)

	lxi	h,convek
	ldx	a,3			; ld a,(ix+3) ==> boot-device
 if video1
	cpi	1			; video-Karte ?
	jrnz	nicht$video$karte
	lxi	h,1000$0000$0000$0000b 	; console = video 1
 endif

 nicht$video$karte:

 if sl186
	cpi	4			; pccon ?
	jrnz	nicht$pccon
	lxi	h,convek$pc		; console = pccon
 endif

 nicht$pccon:

 if psio and not cpu3	

	cpi	3			; sio 2 ?
	jrnz	convek$in$hl$ok

	;***** convek in hl um 2 Positionen nach rechts shiften *****

	lxi	h,convek shr 2
 endif

convek$in$hl$ok:

	shld	@civec			; console input
	shld	@covec			; console output

else ; not (epc2 or cpu183)

	lxi	h,conovek
	shld	@covec			; console output
 if epc2
	lxi	h,conivek
 endif
	shld	@civec			; console input

endif ; not (epc2 or cpu183)

	lxi	h,auxvek	
	shld	@aivec			; aux	  input  ==> sioa
	shld	@aovec			; aux     output ==> sioa
	lxi	h,lstvek
	shld	@lovec			; lst	  output ==> cen

				; I/O-Zuordnung kann durch den Anwender
	user$set$io		; in der Datei 'USER.LIB' geaendert werden.

	page
;----------------------------------------------------------------------
	dseg

;****************************************************************
;*	Einsprungpunkte des Character-I/O			*
;****************************************************************

?dvini:	;********************************************************
	;*	Geraet initialisieren gemaess ctbl und xctbl	*
	;********************************************************
	;*	in:	B = Geraetenummer			*
	;*	out:	----					*
	;********************************************************
;
	chk$max$dev ?nothing
	lxi	h,xxlst			; xon/xoff-Liste
	mov	e,b			; Geraetenummer
	mvi	d,0			; de = offset xon/xoff liste
	dad	d			; hl = xon/xoff-Merker des Geraetes
	mvi	m,-1			; xon
	lxi h,?chario$driver ! jr ?verteiler
;
?chris:	;********************************************************
	;*	Eingabestatus					*
	;********************************************************
	;*	in:	B = Geraetenummer			*
	;*	out:	A = Statusergebnis (FF=READY/00=BUSY	*
	;*		Z = Flag gemaess Ergebnis in A 		*
	;********************************************************
;
	chk$max$dev ?isbusy
	lxi h,?chario$driver+2 ! jr ?verteiler
;
?chros:	;********************************************************
	;*	Ausgabestatus					*
	;********************************************************
	;*	in:	B = Geraetenummer			*
	;*	out:	A = Statusergebnis (FF=READY/00=BUSY	*
	;*		Z = Flag gemaess Ergebnis in A 		*
	;********************************************************
;
	chk$max$dev ?isbusy
	lxi h,?chario$driver+4 ! jr ?verteiler
;
?chrin:	;********************************************************
	;*	Eingabe (keine Statusabfrage erforderlich)	*
	;********************************************************
	;*	in:	B = Geraetenummer			*
	;*	out:	A = eingegebenes Zeichen		*
	;********************************************************
;
	chk$max$dev ?in$no
	lxi h,?chario$driver+6 ! jr ?verteiler
;
?chrout:;********************************************************
	;*	Ausgabe (keine Statusabfrage erforderlich)	*
	;********************************************************
	;*	in:	B = Geraetenummer			*
	;*		C = auszugebenes Zeichen		*
	;*	out:	----					*
	;********************************************************
;
	chk$max$dev ?nothing
	lxi h,?chario$driver+8
;
;
?verteiler:
;
	mov a,b ! add a ! add a ! add b 	; a = 5 * b
	mvi d,0 ! mov e,a ! dad d ! dad d	; hl = ..routine
	mov e,m ! inx h   ! mov d,m		; de = .routine
	xchg	! pchl				; jp (hl)
;
;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg
;
 if video1
;
   ?isvideo1:			; Input-Status VIDEO I
;
	in video1$status
	status$end video1$in$bit
;
   ?osvideo1:			; Output-Status VIDEO I
;
	in 	video1$status
	ani	video1$out$bit
	jrz	?video1$out$ready
	xra	a
	ret
   ?video1$out$ready:
	mvi	a,255
	ana	a
	ret
;
   ?invideo1:			; Input VIDEO I
;
	in video1$data
	ret
;
   ?outvideo1:			; Output VIDEO I
;
	output video1$data
;
 endif
;
;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg
;
 if not (cpu3 or epc2 or cpu180)
;
   ?inisioa:			; Initialisierung SIO A
;
	init	control$sioa,baud$sioa,sioa$control,sioa$ctc
;
   ?inisiob:			; Initialisierung SIO B
;
	init	control$siob,baud$siob,siob$control,siob$ctc
;
   ?inicen:			; Initialisierung der Centronics-Schnittstelle
;
	mvi	b,0000$1111b	; Bit 7..4 = OUT ; Bit 3..0 = IN
	mvi	c,cen$control$b ; Control Port Kanal B der PIO
	jmp	?ini$pio
;
   ?issioa:			; Input-Status SIO A auf CPU-Platine
;
	status	sioa$status,sio$in$bit
;
   ?issiob:			; Input-Status SIO B auf CPU-Platine
;
	status	siob$status,sio$in$bit
;
   ?ossioa:			; Output-Status SIO A auf CPU-Platine
;
	status	sioa$status,sio$out$bit
;
   ?ossiob:			; Output-Status SIO B auf CPU-Platine
;
	status	siob$status,sio$out$bit
;
   ?oscen:			; Output-Status Centronics-Port auf CPU-Platine
;
	status	cen$status,pio$out$bit
;
   ?insioa:			; Input SIO A auf CPU-Platine
;
	input sioa$data,control$sioa
;
   ?insiob:			; Input SIO B auf CPU-Platine
;
	input siob$data,control$siob
;
   ?outsioa:			; Output SIO A auf CPU-Platine
;
	output sioa$data
;
   ?outsiob:			; Output SIO B auf CPU-Platine
;
	output siob$data
;
   ?outcen:			; Output Centronics-Port auf CPU-Platine
;
	mov a,c ! mvi b,cen$strobe$bit ! mvi c,cen$data  ! jmp ?pio$out
;
 endif
;
;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg
;
 if cpu180
;
   ?inisioa:			; Initialisierung SIO A
;
	xra	a		; a = 0
	out0	(stat0),a	; no interrupts
	in0	a,(stat0)	; dummy read
	lxi	h,baud$sioa
	lxi	d,old$baud$sioa
	call	baud$cpu180
	lda	control$sioa
	mov	c,a		; control$sioa fuer spaetere Benutzung
	cma			; complement, da Parity fuer 64180 falsch herum
	ani	mb$parity$even
	ora	b
	out0	(cntlb0),a	; baudrate ok, parity even/odd ok

	in0	a,(cntla0)	; ASCI Control Register A0
	call	control$cpu180
	res	4,a		; RTS = 0
	out0	(cntla0),a	; parity, stop-bit, data-bit ok / RTS = 1
	ret

old$baud$sioa:	db	baud$9600	; alte baudrate
;
   ?inisiob:			; Initialisierung SIO B
;
	lda	control$siob
	push	psw		; control$siob
	ani	mb$handshake$on
	rlc			; handshake_on-bit nach links
	out0	(stat1),a	; no interrupts , handshake ok
	in0	a,(stat1)	; dummy read
	lxi	h,baud$siob
	lxi	d,old$baud$siob
	call	baud$cpu180
	pop	psw		; control$siob
	mov	c,a		; control$siob fuer spaetere Benutzung
	cma			; complement, da Parity fuer 64180 falsch herum
	ani	mb$parity$even
	ora	b
	out0	(cntlb1),a	; baudrate ok, parity even/odd ok

	in0	a,(cntla1)	; ASCI Control Register A1
	call	control$cpu180
	out0	(cntla1),a	; parity, stop-bit, data-bit ok / CKA1D = 1
	ret

old$baud$siob:	db	baud$9600	; alte baudrate
;
   ?issioa:			; Input-Status SIO A auf CPU-Platine
;
	lda	control$sioa
	ani	mb$handshake$on
	jrz	no$handshake$sioa
	in0	a,(cntla0)
	res	4,a		; RTS = 0
	out0	(cntla0),a
no$handshake$sioa:
	in0	a,(stat0)	; ASCI Status Register 0
	ani	rdrf		; recive data register full
	rz
	mvi	a,255
	ret
;
   ?issiob:			; Input-Status SIO B auf CPU-Platine
;
	in0	a,(stat1)	; ASCI Status Register 1
	ani	rdrf		; recive data register full
	rz
	mvi	a,255
	ret
;
   ?ossioa:			; Output-Status SIO A auf CPU-Platine
;
	in0	a,(stat0)	; ASCI Status Register 0
	ani	tdre		; transmit data register empty
	rz
	mvi	a,255
	ret
;
   ?ossiob:			; Output-Status SIO B auf CPU-Platine
;
	in0	a,(stat1)	; ASCI Status Register 1
	ani	tdre		; transmit data register empty
	rz
	mvi	a,255
	ret
;
   ?oscen:			; Output-Status Centronics-Port auf CPU-Platine
;
	mvi	a,peah		; Busy-Bit in Parity-Error high
	di			; rpoint vor interrupt-routinen schuetzen
	out0	(rpoint),a	; peah adressieren
	in0	c,(rpoint+1)	; (peah) einlesen
	mvi	a,mcr		; memory control
	out0	(rpoint),a	; mcr adressieren
	lda	intsem		; interrupt semaphore
	ana	a		; flags restaurieren
	jrnz	?oscen$end	; verzweigen, wenn interrupt disabled bleibt
	ei			; rpoint steht wieder auf mcr
?oscen$end:
	mov	a,c		; (peah)
	ani	bsystr		; nur busy-bit von interesse
	jnz	?isbusy		; busy-bit falsch herum
	dcr	a		; a = 255 ==> ready
	ret
;
   ?insioa:			; Input SIO A auf CPU-Platine
;
	lda	control$sioa
	bit	1,a		; mb$handshake$on
	jrz	input$sioa	; verzweigen, wenn handshake nicht aktiv
	in0	c,(cntla0)	; ASCI Control Register A 0
	setb	4,c		; RTS = 1
	out0	(cntla0),c
input$sioa:
	input0 rdr0
;
   ?insiob:			; Input SIO B auf CPU-Platine
;
	lda	control$siob
	input0 rdr1
;
   ?outsioa:			; Output SIO A auf CPU-Platine
;
	output0 tdr0
;
   ?outsiob:			; Output SIO B auf CPU-Platine
;
	output0 tdr1
;
   ?outcen:			; Output Centronics-Port auf CPU-Platine
;
	mvi	a,cend		; Centronics Data
	di			; rpoint vor interrupt-routinen schuetzen
	out0	(rpoint),a	; cend adressieren
	out0	(rpoint+1),c	; Output Data
	mvi	a,peah		; Strobe-Bit in Parity-Error high
	out0	(rpoint),a	; peah adressieren
	in0	a,(rpoint+1)	; (peah) einlesen
	ori	bsystr		; Strobe on
	out0	(rpoint+1),a	; set strobe on
	nop			; wait
	ani	nbsyst		; strobe off
	out0	(rpoint+1),a	; set strobe off
	mvi	a,mcr		; memory control
	out0	(rpoint),a	; mcr adressieren
	lda	intsem		; interrupt semaphore
	ana	a		; flags restaurieren
	rnz			; return, wenn interrupt disabled bleibt
	ei			; rpoint steht wieder auf mcr
	ret
;
 baud$cpu180:
;
; Eingangsparameter: HL - .baud in @ctbl
;		     DE - .old$baud
;
; Ausgangsparameter:  b - Baudratencode
;
; falls Baudrate nicht moeglich, erfolgt ein Return auf das vorherige Programm
; und nicht auf das direkt rufende Programm

	mov	c,m		; baudratencode cpm
	mvi	b,0
	push	h		; .baud
	lxi	h,?tcpu180-1	; .cpu180-Baudratentabelle
	dad	b		; .baud cpu180
	mov	a,m		; baudratencode cpu180
	cpi	255		; nicht moegliche baudrate ?
	pop	h		; .baud
	jrnz	baud$cpu180$moeglich
	ldax	d		; old$baud
	mov	m,a		; baud = old$baud
	pop	h		; 1. return
	ret			; 2. return

 baud$cpu180$moeglich:

	mov	b,a		; baudratencode cpu180
	mov	a,c		; baudratencode cpm
	stax	d		; old$baud = baudratencode cpm
	ret			; 1. return

 control$cpu180:
;
; Eingangsparameter: a - Control Register A
;		     c - control$sio
;
; Ausgangsparameter: a - new Control Register a
;
	ani	0111$1000b	; MPE = 0 ; mod0 .. mod2 = 0
	ori	0110$0000b	; Enable Receiver and Transmitter
	mov	b,a
	mov	a,c		; control$sio
	ani	mb$parity$on
	rrc
	rrc			; parity$on auf bit 1
	ora	b
	mov	b,a		; parity ok
	mov	a,c		; control$sio
	cma			; stop$bit ist invers
	ani	mb$stop1
	rlc
	rlc
	rlc			; stop1 auf bit 0
	ora	b
	mov	b,a		; stop bit ok
	mov	a,c		; control$sio
	ani	mb$bit6
	rlc
	rlc
	rlc			; 8/7 databit auf bit 2
	ora	b
	setb	4,a		; CKA1D / RTS0
	ret
 endif
;
;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg

if epc2

;
   ?inisioa:			; Initialisierung SIO A
;
	lxi	d,baud$sioa
	mvi	c,sioa$rx$ctc
	call	?ini$ctc
	lxi	d,baud$sioa
	mvi	c,sioa$tx$ctc
	call	?ini$ctc	; beide ctc-Kanaele initialisiert
	lxi	h,control$sioa
	mvi	b,sioa$control
	jmp	?ini$sio	; sio a initialisiert
;
   ?inisiob:			; Initialisierung SIO B (verboten)
;				; Achtung: wr5 auch fuer centronics
	ret
;
   ?inicen:			; Initialisierung der Centronics-Schnittstelle
;
	ret			; nicht erforderlich
;
   ?os7220:				; immer ready
	mvi	a,255
	ret

   ?issioa:			; Input-Status SIO A auf CPU-Platine
;
	status	sioa$status,sio$in$bit
;
   ?issiob:			; Input-Status SIO B auf CPU-Platine
;				; and blink cursor
	lda	bcount
	inr	a
	sta	bcount
	jrnz	issiob
	lda	bspeed		; Blinkgeschwindigkeit
	mov	c,a
	lda	blink2
	inr	a
	ana	c		; blinken erforderlich ?
	sta	blink2
	cz	blnkcur		; blink cursor
issiob:	lda	char1
	ora	a
	jrnz	issb1
	in	siob$status 
	ani	sio$in$bit
issb1:	rz
	mvi	a,255
	ret
;
   ?ossioa:			; Output-Status SIO A auf CPU-Platine
;
	status	sioa$status,sio$out$bit
;
   ?ossiob:			; Output-Status SIO B auf CPU-Platine
;
	status	siob$status,sio$out$bit
;
   ?oscen:			; Output-Status Centronics-Port auf CPU-Platine
;
	mvi	a,10h		; res ext status interrupt
	out	siob$control
	in	siob$status
	ani	10h		; busy?
	rz
	mvi	a,255
	ret
;
   ?insioa:			; Input SIO A auf CPU-Platine
;
	input	sioa$data,control$sioa
;
   hardcopy:			; EPC II hardcopy
;
	call	prntdot		; print dots
hardwt:	in	siob$status
	ani	sio$in$bit
	jrz	hardwt		; wait for next character
;
   ?insiob:			; Input SIO B auf CPU-Platine
;
	xra	a
	sta	bcount
	sta	blink2
	call	blnkcur		; input toggles cursor
	call	getfifo
	ora	a
	rnz			; character from fifo if poss
	lda	control$siob	; Controlbyte einlesen
	mov	c,a
	ral			; bit 7 loeschen
	srar	a		; "
	ana	c
	ori	0011$1111b	; Paritymaske ok
	mov	c,a
	in	siob$data
	ana	c		; Parity ausmaskieren
	ora	a
	jrz	hardcopy
	ret
	
;
   ?outsioa:			; Output SIO A auf CPU-Platine
;
	output	sioa$data
;
   ?outsiob:			; Output SIO B auf CPU-Platine
;
	output	siob$data
;
   ?outcen:			; Output Centronics-Port auf CPU-Platine
;
	mov	a,c
	out	cen		; Daten ausgeben
	mvi	a,5
	out	siob$control
	lda	siob$wr5
	ori	80h
	out	siob$control	; strobe ein
	mvi	a,5
	out	siob$control
	lda	siob$wr5
	out	siob$control	; strobe aus
	ret
;
siob$wr5:	db	0000$1010b	; write register 5 (SIOB)
bcount:		db	255		; blink counter (lower)
blink2:		db	255		; blink counter (higher)
bspeed:		db	0fh		; slow blinking

endif ; epc2

;
;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg
;
 if psio or s1x182
;
   ?inisio1:			; Initialisierung SIO 1 + SIO 3
;
  if psio
	lda baud$sio1  ! sta baud$sio3	; Baudraten SIO 1 und SIO 3 starr gekoppelt
	lxi h,?inisio3 ! push h		; Anschliessend SIO 3 initialisieren
  endif
	init	control$sio1,baud$sio1,sio1$control,sio1$ctc
;
   ?inisio2:			; Initialisierung SIO 2
;
	init	control$sio2,baud$sio2,sio2$control,sio2$ctc
;
 endif
 if psio
   ?inisio3:			; Initialisierung SIO 3
;
	init	control$sio3,baud$sio3,sio3$control,sio3$ctc
;
   ?inisio4:			; Initialisierung SIO 4
;
	init	control$sio4,baud$sio4,sio4$control,sio4$ctc
;
   ?inicen1:			; Initialisierung der Centronics-Schnittstelle
;
	mvi	b,0000$1111b	 ; Bit 7..4 = OUT ; Bit 3..0 = IN
	mvi	c,cen1$control$b ; Control Port Kanal B der PIO
	jmp	?ini$pio
;
 endif
 if psio or s1x182
   ?issio1:			; Input-Status SIO 1 Port A auf P/SIO-Platine
;
	status	sio1$status,sio$in$bit
;
   ?issio2:			; Input-Status SIO 1 Port B auf P/SIO-Platine
;
	status	sio2$status,sio$in$bit
;
 endif
 if psio
   ?issio3:			; Input-Status SIO 2 Port A auf P/SIO-Platine
;
	status	sio3$status,sio$in$bit
;
   ?issio4:			; Input-Status SIO 2 Port B auf P/SIO-Platine
;
	status	sio4$status,sio$in$bit
;
 endif
 if psio or s1x182
   ?ossio1:			; Output-Status SIO 1 Port A auf P/SIO-Platine
;
	status	sio1$status,sio$out$bit
;
   ?ossio2:			; Output-Status SIO 1 Port B auf P/SIO-Platine
;
	status	sio2$status,sio$out$bit
;
 endif
 if psio
   ?ossio3:			; Output-Status SIO 2 Port A auf P/SIO-Platine
;
	status	sio3$status,sio$out$bit
;
   ?ossio4:			; Output-Status SIO 2 Port B auf P/SIO-Platine
;
	status	sio4$status,sio$out$bit
;
   ?oscen1:			; Output-Status Centronics-Port auf P/SIO-Platine
;
	status	cen1$status,pio$out$bit
;
 endif
 if psio or s1x182
   ?insio1:			; Input SIO 1 Port A auf P/SIO-Platine
;
	input sio1$data,control$sio1
;
   ?insio2:			; Input SIO 1 Port B auf P/SIO-Platine
;
	input sio2$data,control$sio2
;
 endif
 if psio
   ?insio3:			; Input SIO 2 Port A auf P/SIO-Platine
;
	input sio3$data,control$sio3
;
   ?insio4:			; Input SIO 2 Port B auf P/SIO-Platine
;
	input sio4$data,control$sio4
;
 endif
 if psio or s1x182
   ?outsio1:			; Output SIO 1 Port A auf P/SIO-Platine
;
	output sio1$data
;
   ?outsio2:			; Output SIO 1 Port B auf P/SIO-Platine
;
	output sio2$data
;
 endif
 if psio
   ?outsio3:			; Output SIO 2 Port A auf P/SIO-Platine
;
	output sio3$data
;
   ?outsio4:			; Output SIO 2 Port B auf P/SIO-Platine
;
	output sio4$data
;
   ?outcen1:			; Output Centronics-Port auf P/SIO-Platine
;
	mov a,c ! mvi b,cen1$strobe$bit ! mvi c,cen1$data  ! jmp ?pio$out
;
 endif
;
;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg
;
 if sio
;
   ?inisio1s:			; Initialisierung SIO 1S
;
	inits	control$sio1s,baud$sio1s,sio1s$control,sio1s$8253
;
   ?inisio2s:			; Initialisierung SIO 2S
;
	inits	control$sio2s,baud$sio2s,sio2s$control,sio2s$8253
;
   ?inisio3s:			; Initialisierung SIO 3S
;
	inits	control$sio3s,baud$sio3s,sio3s$control,sio3s$8253
;
   ?inisio4s:			; Initialisierung SIO 4S
;
	inits	control$sio4s,baud$sio4s,sio4s$control,sio4s$8253
;
   ?issio1s:			; Input-Status SIO 1 Port A auf SIO-Platine
;
	status	sio1s$status,sio$in$bit
;
   ?issio2s:			; Input-Status SIO 1 Port B auf SIO-Platine
;
	status	sio2s$status,sio$in$bit
;
   ?issio3s:			; Input-Status SIO 2 Port A auf SIO-Platine
;
	status	sio3s$status,sio$in$bit
;
   ?issio4s:			; Input-Status SIO 2 Port B auf SIO-Platine
;
	status	sio4s$status,sio$in$bit
;
   ?ossio1s:			; Output-Status SIO 1 Port A auf SIO-Platine
;
	status	sio1s$status,sio$out$bit
;
   ?ossio2s:			; Output-Status SIO 1 Port B auf SIO-Platine
;
	status	sio2s$status,sio$out$bit
;
   ?ossio3s:			; Output-Status SIO 2 Port A auf SIO-Platine
;
	status	sio3s$status,sio$out$bit
;
   ?ossio4s:			; Output-Status SIO 2 Port B auf SIO-Platine
;
	status	sio4s$status,sio$out$bit
;
   ?insio1s:			; Input SIO 1 Port A auf SIO-Platine
;
	input sio1s$data,control$sio1s
;
   ?insio2s:			; Input SIO 1 Port B auf SIO-Platine
;
	input sio2s$data,control$sio2s
;
   ?insio3s:			; Input SIO 2 Port A auf SIO-Platine
;
	input sio3s$data,control$sio3s
;
   ?insio4s:			; Input SIO 2 Port B auf SIO-Platine
;
	input sio4s$data,control$sio4s
;
   ?outsio1s:			; Output SIO 1 Port A auf SIO-Platine
;
	output sio1s$data
;
   ?outsio2s:			; Output SIO 1 Port B auf SIO-Platine
;
	output sio2s$data
;
   ?outsio3s:			; Output SIO 2 Port A auf SIO-Platine
;
	output sio3s$data
;
   ?outsio4s:			; Output SIO 2 Port B auf SIO-Platine
;
	output sio4s$data
;
 endif
;
;
;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg
;
 if gpib
;
   ?inicen2:			; Initialisierung der Centronics-Schnittstelle
;
	mvi	b,1111$1110b	 ; Bit 0 = OUT ; Bit 7..1 = IN
	mvi	c,cen2$control$b ; Control Port Kanal B der PIO
	jmp	?ini$pio
;
   ?oscen2:			; Output-Status Centronics-Port auf GPIB-Platine
;
	in 	cen2$status 
	ani	cen2$busy$bit
	jrz	?cen2$out$ready
	xra	a
	ret
   ?cen2$out$ready:
	mvi	a,255
	ana	a
	ret
;
   ?outcen2:			; Output Centronics-Port auf GPIB-Platine
;
	mov a,c ! mvi c,cen2$data ! mvi b,cen2$strobe$bit ! jmp ?pioout
;
 endif
;
;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg
;
?in$no:				; Dummy-Input
;
	mvi a,1aH ! ret
;

if hkm or cpu12 or cpu2a or psio or epc1 or gpib
;
?pio$out:			; Centronics-Output ueber die PIO
				; der CPU-, P/SIO- oder GPIB-Platine
;===============================
; Eingangsregister:
;			A - enthaelt auszugebenden Character
;			B - enthaelt Strobebyte fuer die benutzte PIO
;			C - enthaelt Datenport der benutzten PIO
; Bemerkung:
;		alle Register duerfen zerstoert werden
;
	outp	a
	dcr	c
	dcr	c		; c = Statusport
	outp	b		; strobe on
	xra	a		; strobe off
	outp	a
	ret
endif
;
?isbusy:
;
	xra a			; immer nicht bereit
;
?nothing:
;
	ret
;
;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg

if hkm or cpu12 or cpu2a or psio or epc1 or gpib

;
?ini$pio:				; Initialisierung einer PIO
					; als Centronics-Schnittstelle
;
; Eingangsparameter:  
;		       C - PIO-Control-Port-Adresse Kanal B
;		       B - I/O Register Control Word Kanal A
;
; Bemerkung: alle Register duerfen zerstoert werden
;
		mvi	a,0000$1111b	; Output Mode 0 Port B
		outp	a
		dcr	c		; C = Data Kanal B
		dcr	c		; C = Control Kanal A
		mvi	a,1100$1111b	; Output Mode 3 Port A
		outp	a
		outp	b		; Control Word
		dcr	c		; C = Data Kanal A
		mvi	a,1000$0000b	; init = /1
		outp	a
		xra	a
		outp	a		; alle Ausgaenge auf 0
		ret
;

endif

;----------------------------------------------------------------------
	page
;----------------------------------------------------------------------
	dseg
;

if sio

?ini$sio$8253:				; Initialisierung von SIO und 8253

; Eingangsparameter:  HL - .control in @xctbl
;		      DE - .baud in @ctbl
;		       C - 8253-Control-Port-Adresse
;		       B - SIO-Control-Port-Adresse
;
; Bemerkung: alle Register duerfen zerstoert werden
;	     falls (baud) = 0 ist, findet keine Initialisierung statt
;
		ldax	d		; a = (baud)
		ana	a		; flags setzen
		rz			; return, falls Baudrate unbekannt


			; Initialisierung eines 8253 als Baudratengenerator

		push	d
		push	h
		push	b

		mov	a,c		; 8253-control-port-adresse
		ori	3		; mode-wort-adresse 8253
		mov	b,c
		mov	c,a		; mode-wort-adresse 8253

		rarr	b		; mode-wort konstruieren
		rar
		rarr	b
		rar			; adresse in bit 6+7

		ori	mode$8253
		outp	a

		pop	b		; 8253-control-port-adresse

		lxi	h,?tsio-2	; 8253-Tabelle
		ldax	d		; a = mode byte
		mov	e,a
		mvi	d,0
		
		dad	d
		dad	d		; hl = .teiler

		mov	a,m		; a = 8253-Teiler (low)
		outp	a		; 8253
		inx	h
		mov	a,m		; a = 8253-Teiler (high)
		outp	a		; 8253

		pop	h
		pop	d


		jmp	?ini$sio	; initialisierung der sio

endif

if cpu12 or cpu2a or hkm or epc1 or psio or s1x182

?ini$sio$ctc:				; Initialisierung von SIO und CTC

; Eingangsparameter:  HL - .control in @xctbl
;		      DE - .baud in @ctbl
;		       C - CTC-Control-Port-Adresse
;		       B - SIO-Control-Port-Adresse
;
; Bemerkung: alle Register duerfen zerstoert werden
;	     falls (baud) = 0 ist, findet keine Initialisierung statt
;
		ldax	d		; a = (baud)
		ana	a		; flags setzen
		rz			; return, falls Baudrate unbekannt

		call	?ini$ctc	; ctc initialisieren

endif
if cpu12 or cpu2a or hkm or epc1 or psio or sio or epc2 or s1x182

?ini$sio:				; sio initialisieren

		push	b		; Portadressen in den Stack
		lda	?wr3		; sio write register 3
		ani	1		; Rx ENABLE erhalten
		mov	b,a		; b = ?wr3
		mov	a,m		; a = control byte 
		ani	mb$handshake$on	; handshake maskieren
		jrz	?ini$sio$01
		setb	5,b		; auto enables
?ini$sio$01:	mov	a,m		; a = control byte
		ani	mb$bit8		; wortlaenge ausmaskieren
		ora	b		; write register 3 fertig
		sta	?wr3
		mvi	b,0000$0100b	; ein oder zwei stop bits
		mov	a,m		; a = control byte
		ani	mb$stop1	; anzahl der stop bits ausmaskieren
		jrnz	?ini$sio$02
		setb	3,b		; 2 stop bits
?ini$sio$02:	mov	a,m		; a = control byte
		ani	mb$parity$on+mb$parity$even
		rar
		RAR
		rar			; Parity control bits ok
		ora 	b
		mov	b,a
 if cpu2a or hkm
		xthl
		mov	a,h		; a = sio portadresse
		xthl
		ani	0f0h		; nur bit 7..4
		cpi	psio$port	; psio ?
		jrz	?nicht$6mhz	; bei 6/8Mhz keine Sonderbehandlung
		cpi	sio$port	; sio ?
		jrz	?nicht$6mhz	; bei 6/8MHz keine Sonderbehandlung
		lda	sys$clock
		cpi	6		; 6/8 MHz ?
		jrc	?nicht$6mhz
		mvi	a,1000$0000b	; x32 clock mode
		jr	?ini$sio$03
 endif
?nicht$6mhz:
		ldax	d		; a = mode byte
		cpi	7		; hohe oder niedrige gruppe
		mvi	a,1000$0000b	; x32 clock mode
		jrc	?ini$sio$03
		rar			; x16 clock mode
?ini$sio$03:	ora	b		; write register 4 fertig
		sta	?wr4
		lda	?wr5		; sio write register 5
		ani	1000$1010b	; DTR, TxE, RTS unveraendert lassen
		mov	b,a		; b = ?wr5
		mov	a,m		; a = control byte
		ani	mb$bit8		; wortlaenge maskieren
		rar			; auf die richtige position
		ora	b		; write register 5 fertig
		sta	?wr5
		pop	b		; portadressen
		mov	c,b		; sio portadresse
		lxi	h,?sio$tab
		mvi	b,sio$tab$len
		outir
		ret
endif

if cpu12 or cpu2a or hkm or epc1 or psio or epc2 or s1x182

?ini$ctc:		; Initialisierung eines CTC als Baudratengenerator

; Eingangsparameter:  DE - .baud in @ctbl
;		       C - CTC-Control-Port-Adresse
;
; Bemerkung: HL,DE,BC duerfen nicht zerstoert werden
;
		push	d
		push	h

		ldax	d		; a = mode byte
		cpi	7		; hohe oder niedrige gruppe
		mvi	a,counter	; CTC im counter mode
		jrnc	?ini$ctc$04
		mvi	a,timer		; CTC im timer mode
 ?ini$ctc$04:	outp	a		; CTC
		ldax	d		; a = mode byte
		mov	e,a		; e = mode byte
		mvi	d,0
  if not cpu180
		lxi	h,?tlow-1	; CTC-Tabelle
  else
		lxi	h,?tpsio-1	; andere CTC-Tabelle
  endif
  if psio and not (cpu12 or cpu180)
		mvi	a,psio$port	; basisportadresse der p/sio
		ana	b
		cpi	psio$port	; sio auf der p/sio ?
		jrnz	?ini$ctc$05
		lxi	h,?tpsio-1	; andere CTC-Tabelle
  endif
 ?ini$ctc$05:	dad	d
		mov	a,m		; a = CTC-Teiler
		outp	a		; CTC

		pop	h
		pop	d

		ret

endif
;
;----------------------------------------------------------------------
	dseg
if cpu12 or cpu2a or hkm or epc1 or psio or sio or epc2 or s1x182
;
?sio$tab:			; Initialisierungstabelle der SIO
;
	db	0001$1000b	; channel reset
	db	1		; write register 1
	db	0		; no interrupts
	db	2		; write register 2
	db	0
	db	3		; write register 3
?wr3:	db	0000$0001b	; Rx enable
	db	4		; write register 4
?wr4:	db	0
	db	5		; write register 5
?wr5:	db	1000$1010b	; DTR, Tx Enable, RTS
	db	6		; write register 6
	db	0
	db	7		; write register 7
	db	0
sio$tab$len equ $-?sio$tab
;
endif
;
sys$clk:
sys$clock:	db	0	; Merker fuer den Systemtakt
;
msg:		db	msgon	; sign on message on/off
;
	end
