1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
|
;***************************************************************************
;*======= Copyright (C) 1985,86 Martin Schoenbeck, Spenge =================*
;* *
;* Pufferverwaltung fuer Stream-I/O-Kanaele *
;* und allgemeine Stream-I/O-Routinen *
;* *
;***************************************************************************
;******************************************************************************
; macro zur definition der fuer 'stream' notwendigen daten im ccb
stream macro bufsiz,bufadr
ccbentry stream_stat
;;definition der bits in stream_stat
outrestart = 1 ;;output war fertig, muss neu gestartet werden
wasxon = 2 ;;es wurde bereits xon empfangen
out_xon_xoff = 4 ;;ausgabeseitig findet xon/xoff handshake statt
in_xon_xoff = 8 ;;eingabeseitig findet xon/xoff handshake statt
sendxon_xoff = 10h ;;xon oder xoff muss gesendet werden
sendxon = 20h ;;xon senden (in verbindung mit sendxon_xoff verwendet)
in_xoff_send = 40h ;;xoff wurde ausgesendet -> nur dann xon senden
db outrestart + wasxon + in_xoff_send
ccbentry buffersize
db bufsiz
ccbentry content
db 0 ;;puffer ist anfangs leer
ccbentry inpointer
db 0 ;;wir fuellen den puffer vom anfang an
ccbentry outpointer
db 0 ;;und leeren ihn auch von da
ccbentry buffer
dw offset bufadr ;;pufferadresse
ccbentry andmask
db 0ffh ;;high bit loeschen
ccbentry xormask
db 0 ;;keine bits kippen
ccbentry errorandmask
db 0ffh ;;high bit loeschen
ccbentry errorxormask
db 0 ;;keine bits kippen
ccbentry outandmask
db 0ffh ;;high bit loeschen
ccbentry outxormask
db 0 ;;keine bits kippen
ccbentry breakchar
db '?' ;;nach ? umsetzen
ccbentry xoffchar
db 'S'-40h ;;ctrl-s ist xoff
ccbentry xonchar
db 'Q'-40h ;;ctrl-q ist xon
ccbentry stream_icount
dw 0
ccbentry stream_ocount
dw 0
endm
fillbuffer:
; di zeigt auf ccb
; das z-flag ist rueckgesetzt, wenn der output neu gestartet werden muss
or cx,cx ;falls laenge null: alles uebernommen melden
jnz fillit
stc ;'alles uebernommen' setzen
ret ;war null, nichts zu tun
fillit:
push cx ;gewuenschte laenge merken fuer rueckmeldung
fillagain:
mov al,shard:(di+buffersize) ;puffergroesse holen
sub al,shard:(di+content) ;belegte abziehen
jz bufferfull ;nichts mehr frei
push cx ;noch zu uebernehmende merken
or ch,ch ;nachsehen, ob laenge > 255
ifnz <mov cl,0ffh> ;nein, dann bis zu 255 byte uebernehmen
cmp al,cl ;kleinere von freien und gewuenschten nehmen
ifc <mov cl,al> ;anzahl freie ist kleiner
mov al,shard:(di+buffersize) ;groesse holen
sub al,shard:(di+inpointer) ;zeiger abziehen -> abstand vom pufferende
jnz takeminimum
mov byte ptr shard:(di+inpointer),0 ;ist am ende, vorne anfangen
mov al,cl ;von daher volle groesse
takeminimum: ;minimum (abstand vom ende, max moegliche) -> c
cmp al,cl ;welches ist groesser
ifc <mov cl,al> ;a ist kleiner, nehmen wir das
mov ch,0 ;laenge fuer movsb
push cx ;merken
mov dx,shard:(di+buffer)
add dl,shard:(di+inpointer)
ifc <inc dh> ;zielstartadresse nach dx
;es:bx enthaelt quellenstart
;ds:dx enthaelt zieladresse
push es
push ds
pop es ;es / ds vertauschen
pop ds
xchg bx,si ;bx als source
xchg dx,di ;dx als destination
cld
rep movsb ;uebertragen
xchg bx,si ;register zuruecktauschen
xchg dx,di
push es
push ds
pop es
pop ds
pop cx ;uebernommene laenge nach cx
add shard:(di+inpointer),cl ;neuen inpointer errechnen
add shard:(di+content),cl ;neuen inhalt
pop bp ;gewuenschte laenge nach bp
sub bp,cx ;restlaenge ausrechnen
mov cx,bp ;restlaenge nach cx
jnz fillagain ;ok, fertig
pop cx ;alles uebernommen
test byte ptr shard:(di+stream_stat),outrestart ;output neu starten?
stc ;carry setzen
ret
bufferfull: ;nicht alles uebernommen
pop bx ;gewuenschte laenge vom stack holen
sub bx,cx ;uebernommene laenge errechnen
mov cx,bx ;uebernommene nach bc
test byte ptr shard:(di+stream_stat),outrestart ;output neu starten?
ret ;carry ist geloescht
frout:
;* meldet anzahl freie im puffer und carry, wenn puffer leer
mov al,shard:(di+buffersize) ;groesse
mov ch,al ;merken
sub al,shard:(di+content) ;minus inhalt gibt freie
cmp al,ch ;volle puffergroesse?
cmc ;carry ist genau dann gesetzt, wenn bl>al
mov ch,0
mov cl,al ;laenge melden
ret
getnextchar:
;* diese routine muss im disable interrupt aufgerufen werden und wird so verlassen
;* z-flag -> kein zeichen mehr gefunden
;* dx,ax,f werden zerstoert
test byte ptr (di+stream_stat),sendxon_xoff ;muessen wir xon/xoff senden
jnz getxon_xoff
test byte ptr shard:(di+stream_stat),wasxon ;war schon xon
jz getret ;nein, z sagt: kein zeichen mehr da
or byte ptr shard:(di+stream_stat),outrestart ;puffer leer, neustart erforderlich
cmp byte ptr shard:(di+content),0 ;noch was im puffer
jz getret ;ja
and byte ptr shard:(di+stream_stat),not outrestart ;kein neustart erforderlich
dec byte ptr shard:(di+content) ;einen vom inhalt abziehen
mov dx,shard:(di+buffer) ;buffer adresse + outpointer nach cx
mov al,shard:(di+outpointer)
cmp al,shard:(di+buffersize) ;sind wir am ende angelangt
ifz <mov al,0> ;ja, dann auf den anfang setzen
inc al ;auf naechstes zeigen
mov shard:(di+outpointer),al ;neuen outpointer setzen
dec al ;alten outpointer wiederherstellen
xor ah,ah ;ah loeschen
add dx,ax ;byte im puffer errechnen
xchg bx,dx
mov al,shard:[bx] ;zeichen holen
xchg bx,dx
and al,(di+outandmask) ;unerwuenschte bits blenden
xor al,(di+outxormask) ;andere evtl. kippen
inc word ptr (di+stream_ocount) ;zeichen zaehlen
inc dx ;puffer steht nie auf 0
;nz => zeigt an, dass zeichen da
getret:
ret
getxon_xoff:
and byte ptr (di+stream_stat),not sendxon_xoff ;jetzt senden wirs
test byte ptr (di+stream_stat),sendxon ;sollen wir xon senden
jz getxoff ;nein, dann wars xoff
and byte ptr (di+stream_stat),not sendxon ;muss jetzt auch weg
or al,1 ;nz => zeichen da
mov al,(di+xonchar) ;xon holen
ret
getxoff:
or al,1 ;nz => zeichen
mov al,(di+xoffchar) ;xoff holen
ret
xonfound:
test byte ptr shard:(di+stream_stat),wasxon ;warten wir auf xon
lahf
or byte ptr shard:(di+stream_stat),wasxon ;jetzt war auf jeden fall eins da
sahf
ret ;z => output wieder starten
xofffound:
and byte ptr shard:(di+stream_stat),not wasxon ;ab sofort auf xon warten
ret ;nz => output nicht wieder starten
input:
and al,shard:(di+andmask) ;evtl. bits ausblenden
xor al,shard:(di+xormask) ;oder kippen
allinput:
test byte ptr shard:(di+stream_stat),out_xon_xoff
jz directinput
cmp al,shard:(di+xonchar)
jz xonfound
cmp al,shard:(di+xoffchar)
jz xofffound
directinput: ;input ohne xon/xoff
mov ch,al ;zeichen nach ch
mov al,shard:(di+channel_no) ;kanal nach al
inc word ptr shard:(di+stream_icount) ;zeichen zaehlen
call inputinterrupt
or al,1 ;nz => kein output restart
ret
errorinput:
and al,shard:(di+errorandmask) ;evtl. bits ausblenden
xor al,shard:(di+errorxormask) ;oder kippen
jmp allinput
breakinput:
mov al,shard:(di+breakchar)
jmp allinput
stream_weiter:
cli
mov al,(di+stream_stat) ;aktuellen status holen
test al,in_xon_xoff ;ueberhaupt xon_xoff handshake
jz stream_weiter_end ;nein, ei und zurueck
test al,in_xoff_send ;habe ich ein xoff gesendet
jz stream_weiter_end ;nichts liefern
or al,sendxon+sendxon_xoff ;bitte schick ein xon
and al,0ffh-in_xoff_send ;das xoff ist erledigt
mov (di+stream_stat),al ;neuen status setzen
test byte ptr (di+stream_stat),outrestart ;nz => output neu starten
stream_weiter_end:
sti
ret
stream_stop:
cli
mov al,(di+stream_stat) ;aktuellen status holen
test al,in_xon_xoff ;ueberhaupt xon_xoff handshake
jz stream_stop_end ;nein, ei und zurueck
or al,in_xoff_send+sendxon_xoff ;bitte schick ein xoff und merk dirs
and al,0ffh-sendxon ;auf keinen fall mehr xon schicken
mov (di+stream_stat),al ;neuen status setzen
test byte ptr (di+stream_stat),outrestart ;nz => output neu starten
stream_stop_end:
sti
ret
enablexon:
or byte ptr shard:(di+stream_stat),in_xon_xoff ;ab sofort xon/xoff handshake
enableoutxon:
or byte ptr (di+stream_stat),out_xon_xoff ;auch ausgabe seitig
ret
disablexon:
and byte ptr (di+stream_stat),not in_xon_xoff ;ab sofort eingabe und
disablexoff:
and byte ptr (di+stream_stat),not out_xon_xoff ;ausgabe wieder ohne xon/xoff
test byte ptr shard:(di+stream_stat),wasxon ;warten wir noch auf xon
lahf
or byte ptr shard:(di+stream_stat),wasxon ;dann haben wir jetzt eins
sahf
ret ;z => outputrestart
set_out_mask:
mov (di+outandmask),dx
ret
set_inp_mask:
mov (di+andmask),dx
ret
set_inp_errmask:
mov (di+errorandmask),dx
ret
stream_in_count:
cli
mov cx,(di+stream_icount)
mov word ptr (di+stream_icount),0
sti
ret
stream_out_count:
cli
mov cx,(di+stream_ocount)
mov word ptr (di+stream_ocount),0
sti
ret
|