-
Notifications
You must be signed in to change notification settings - Fork 0
/
vt100.modem.S
419 lines (323 loc) · 5.26 KB
/
vt100.modem.S
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
lst off
rel
xc
xc
mx %11
cas se
use vt.equ
use debug
SCCBREG equ $c038
SCCAREG equ $c039
SCCBDATA equ $c03a
SCCADATA equ $c03b
SerFlag equ $e10104 ;
*
* scc speed:
*
* time constant = ( clock / (2 * clock mode * baud rate)) - 2
* baud rate = clock / ( 2 * clock mode * (time constant + 2))
*
* clock mode = 1x, 16x, 32x, or 64x (selected via write register 4 bits 6/7)
* clock = 3.6864 MHz crystal (scc runs at 14.31818 / 4 = ~ 3.58 Mhz)
* time constant = write register 12 (low) + 13 (high)
*
*
* see IIgs TN #18 - Do-It-Yourself SCC Access
modem_startup ent
enable_modem ent
* sep #$30
php
sei
stz read_q_head
stz read_q_tail
stz write_q_head
stz write_q_tail
* zero out the buffer [for CDA debugger]
ldx #0
]loop stz read_buffer,x
inx
bne ]loop
lda SCCBREG ; sync access
ldx #0
]loop
lda :table,x
bmi :done
sta SCCBREG
inx
lda :table,x
sta SCCBREG
inx
bra ]loop
:done
* adjust SerFlag so serial IRQs will be handled.
lda >SerFlag
ora #%00_000_111 ; channel B interrupts.
sta >SerFlag
plp
rts
:table ; register, value
* db 9,%01_0_1_0_0_0_1 ; reset channel B (modem port) - handled @ startup.
db 4,%01_00_01_0_0 ; x16 clock, 1 stop bit, no parity
db 3,%11_0_0_0_0_0_0 ; 8 bits, rx disabled
db 5,%0_11_0_0_0_1_0 ; 8 bits, RTS
db 11,%0_10_10_0_00 ; modem port, rcv/tx clock = br
db 12,10 ; 9600 baud (low)
db 13,0 ; 9600 baud (high)
db 14,0 ; disable baud rate generator
db 14,%000_0_0_0_0_1 ; enable baud rate generator
db 3,%11_0_0_0_0_0_1 ; 8 bits, rx enabled
db 5,%0_11_0_1_0_1_0 ; 8 bits, tx enabled, RTS
db 15,0 ; disable external interrupts
db 0,%00_010_0_00 ; reset ext/status interrupts
db 1,%0_0_0_10_0_0_0 ; interrupts on rx or special condition
db 9,%00_0_0_1_0_1_0 ; master interrupts enabled.
db -1,-1
disable_modem ent
* local mode
mx %11
php
sei
lda SCCBREG ; sync access
lda #9
sta SCCBREG
lda #%01_0_1_0_0_0_1 ; reset channel B.
sta SCCBREG
stz read_q_head
stz read_q_tail
stz write_q_head
stz write_q_tail
plp
rts
modem_shutdown ent
mx %11
php
sei
lda SCCBREG ; sync access
lda #9
sta SCCBREG
lda #%01_0_1_0_0_0_1 ; reset channel B.
sta SCCBREG
lda >SerFlag
and #%11_111_000 ; channel B interrupts.
sta >SerFlag
plp
rts
write_modem_sync ent
mx %11
* a: byte to send
tay ; save
* ldx #0
php
:mask = %0010_0100 ; tx buffer empty, clear to send
:wait
cli ; guard scc register access.
sei
stz SCCBREG
lda SCCBREG
and #:mask
cmp #:mask
bne :wait
sty SCCBDATA
plp
rts
read_modem_sync ent
* c set if data read
* v set if overrun
mx %11
* ldx #0
rep #$41 ; clear C + V
stz SCCBREG
lda SCCBREG
and #%0001
beq :rts
* read reg 1 for overrun
lda #1
sta SCCBREG
lda SCCBREG
and #%0010_0000
beq :ok
* clear the overrun
lda #$30 ; reg0, error reset.
sta SCCBREG
stz SCCBREG
sep #$40 ; V
:ok
* lda #8
* sta SCCBREG
* lda SCCBREG
lda SCCBDATA
* debugging...
sec
:rts rts
write_buffer equ $1d00
read_buffer equ $1e00
modem_vector ent
jml modem_int
modem_int
*
* called in 8-bit native mode, interrupts disabled.
* d = unknown
* a/x/y don't need to be preserved.
* return carry clear if handled, carry set if not.
* doesn't access direct page.
* check/clear overrun?
*
* n.b. - vt100 would drop $00 and $7f characters here - I drop them later.
*
mx %11
phb
phk
plb
lda SCCBREG ; sync
stz SCCBREG
lda SCCBREG
and #%0000_0001 ; rx ready.
beq :nope
:read
lda SCCBDATA
ldx DPAGE+read_q_head
sta read_buffer,x
inc DPAGE+read_q_head
* more?
stz SCCBREG
lda SCCBREG
and #%0000_0001 ; rx ready.
bne :read
clc
bra :finish
:nope
sec
:finish
* reset errors.
lda #%00_110_000
stz SCCBREG
sta SCCBREG
* reset highest ius
lda #%00_111_000
stz SCCBREG
sta SCCBREG
plb
rtl
modem_io ent
debug modem_io
mx %11
php
sei
bit LOCAL
bmi :local
:write
* send any outbound data...
:mask = %0010_0100 ; tx buffer empty, clear to send
ldx write_q_tail
cpx write_q_head
beq :read
lda SCCBREG ; sync
stz SCCBREG
lda SCCBREG
and #:mask
cmp #:mask
bne :read
* ldx write_q_tail
lda write_buffer,x
sta SCCBDATA
inc write_q_tail
:read
ldx read_q_tail
cpx read_q_head
beq :nope
lda read_buffer,x
inc read_q_tail
* $00 and $7f dropped here.
and #$7f
beq :read
cmp #$7f
beq :read
plp
sec
rts
:nope
plp
clc
rts
:local
ldx write_q_tail
cpx write_q_head
beq :nope
lda write_buffer,x
inc write_q_tail
plp
sec
rts
write_modem ent
write_modem_async ent
mx %11
php
sei
* bit LOCAL
* bmi :local
ldx write_q_head
sta write_buffer,x
inc write_q_head
plp
rts
*:local
* ldx read_q_head
* sta read_buffer,x
* inc read_q_head
* plp
* rts
write_modem_str ent
; y = address of string (0-terminated)
; inc write_q_head vs inx
; because it wraps at $ff
mx %10
php
sei
* bit LOCAL
* bmi :local
:loop lda |$0000,y
beq :fini
ldx write_q_head
sta write_buffer,x
inc write_q_head
iny
bra :loop
*:local lda |$0000,y
* beq :fini
* ldx read_q_head
* sta read_buffer,x
* inc read_q_head
* iny
* bra :local
:fini
plp
rts
read_modem ent
read_modem_async ent
mx %11
php
sei
ldx read_q_tail
cpx read_q_head
beq :nope
lda read_buffer,x
inc read_q_tail
plp
sec
rts
:nope
plp
clc
rts
reset_modem_buffer ent
mx %11
php
sei
stz read_q_head
stz read_q_tail
stz write_q_head
stz write_q_tail
plp
rts
*buffer ds 256
sav vt100.modem.L