Terminal program for MailStation devices
1; vim:syntax=z8a:ts=8
2;
3; msTERM
4; modem routines for Rockwell RCV336DPFSP
5; https://github.com/jcs/mailstation-tools/blob/master/docs/modem-RCV336DPFSP.pdf
6;
7; Copyright (c) 2019 joshua stein <jcs@jcs.org>
8;
9; Permission to use, copy, modify, and distribute this software for any
10; purpose with or without fee is hereby granted, provided that the above
11; copyright notice and this permission notice appear in all copies.
12;
13; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14; WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15; MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16; ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17; WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18; ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19; OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20;
21
22 .module modem
23
24 .include "mailstation.inc"
25 .globl _new_mail
26
27 .area _DATA
28
29 ; modem msr
30_modem_curmsr::
31 .db #0
32_modem_flowing::
33 .db #0
34
35 .area _CODE
36
37_modem_isr::
38 push af
39 push hl
40 push bc
41 ld l, #1
42 call _modem_iir ; read IIR to identify interrupt
43 bit #0, l
44 jr nz, modem_isr_out ; no interrupt, how did we get here?
45 ld a, l
46 and #0b00001111 ; mask off high 4 bits
47 ld l, a
48has_irq:
49 and #0b00000110 ; receiver line status, some error
50 jr nz, no_rls
51 push hl
52 call _modem_lsr ; what are we supposed to do with it? (FCR bit 1?)
53 pop hl
54 jr modem_isr_out
55no_rls:
56 ld a, l
57 and #0b00000100 ; received data available or timeout
58 jr z, modem_isr_out
59 ld b, #16 ; read 16 bytes at a time
60modem_read_loop:
61 push bc
62 push hl
63 call _modem_read
64 ld b, l
65 pop hl
66 ld hl, #_modem_buf
67 ld a, (_modem_buf_pos)
68 ld l, a ; 0xf600 + (modembufpos)
69 ld (hl), b
70 inc a
71 ld (_modem_buf_pos), a
72 pop bc
73 djnz check_for_more_bytes
74 jr modem_isr_out
75check_for_more_bytes:
76 call _modem_lsr
77 bit 0, l
78 jr nz, modem_read_loop
79modem_isr_out:
80 call _modem_msr ; modem status update
81 ld a, l
82 ld (_modem_curmsr), a
83 pop bc
84 pop hl
85 pop af
86 ret
87
88
89; void modem_init(void)
90_modem_init::
91 push bc
92 push de
93 push hl
94 in a, (#SLOT_DEVICE) ; store old slot device
95 ld d, a
96 push de
97 ld a, #0
98 ld (_modem_buf_pos), a
99 call _modem_powerdown
100 ld a, #0x01
101 out (#0x26), a ; turn port 26 on
102 ld hl, #2000
103 push hl
104 call _delay ; delay 2 seconds
105 pop hl
106 ld a, #DEVICE_MODEM
107 out (#SLOT_DEVICE), a ; switch slot device to modem
108 ld a, #0b11000111 ; 14 byte FIFO
109 ld (#SLOT_ADDR + 0x2), a ; FCR = enable FIFO
110 ld a, #0b10000011
111 ld (#SLOT_ADDR + 0x3), a ; LCR = DLAB=1, 8n1
112 xor a
113 ld (#SLOT_ADDR + 0x1), a ; DLM = 0
114determine_dlab:
115dlab_57600:
116 ld hl, (_setting_modem_speed)
117 ld de, #57600
118 or a ; reset c
119 sbc hl, de
120 add hl, de
121 jr c, dlab_38400
122 ld a, #0x2 ; DLL = 2, baud rate = 57600
123 jp set_dlab
124dlab_38400:
125 ld hl, (_setting_modem_speed)
126 ld de, #38400
127 or a ; reset c
128 sbc hl, de
129 add hl, de
130 jr c, dlab_28800
131 ld a, #0x3 ; DLL = 3, baud rate = 38400
132 jr set_dlab
133dlab_28800:
134 ld hl, (_setting_modem_speed)
135 ld de, #28800
136 or a ; reset c
137 sbc hl, de
138 add hl, de
139 jr c, dlab_19200
140 ld a, #0x4 ; DLL = 4, baud rate = 28800
141 jr set_dlab
142dlab_19200:
143 ld hl, (_setting_modem_speed)
144 ld de, #19200
145 or a ; reset c
146 sbc hl, de
147 add hl, de
148 jr c, dlab_9600
149 ld a, #0x6 ; DLL = 6, baud rate = 19200
150 jr set_dlab
151dlab_9600:
152 ld hl, (_setting_modem_speed)
153 ld de, #9600
154 or a ; reset c
155 sbc hl, de
156 add hl, de
157 jr c, dlab_4800
158 ld a, #0x0c ; DLL = 0x0c, baud rate = 9600
159 jr set_dlab
160dlab_4800:
161 ld hl, (_setting_modem_speed)
162 ld de, #4800
163 or a ; reset c
164 sbc hl, de
165 add hl, de
166 jr c, dlab_2400
167 ld a, #0x18 ; DLL = 0x18, baud rate = 4800
168 jr set_dlab
169dlab_2400:
170 ld hl, (_setting_modem_speed)
171 ld de, #2400
172 or a ; reset c
173 sbc hl, de
174 add hl, de
175 jr c, dlab_1200
176 ld a, #0x30 ; DLL = 0x30, baud rate = 2400
177 jr set_dlab
178dlab_1200:
179 ld hl, (_setting_modem_speed)
180 ld de, #1200
181 or a ; reset c
182 sbc hl, de
183 add hl, de
184 jr c, dlab_300
185 ld a, #0x60 ; DLL = 0x60, baud rate = 1200
186 jr set_dlab
187dlab_300:
188 ld hl, (_setting_modem_speed)
189 ld de, #300
190 or a ; reset c
191 sbc hl, de
192 add hl, de
193 jr c, dlab_default
194 ld a, #0x01
195 ld (#SLOT_ADDR + 0x1), a ; DLM = 0x1
196 ld a, #0x80 ; DLL = 0x80, baud rate = 300
197 jr set_dlab
198dlab_default:
199 ld hl, #MODEM_DEFAULT_SPEED
200 ld (_setting_modem_speed), hl
201 jp determine_dlab ; run through the loop again
202set_dlab:
203 ld (#SLOT_ADDR), a ; DLL
204 ld a, #0b00000011
205 ld (#SLOT_ADDR + 0x3), a ; LCR = DLAB=0, 8n1
206 ld a, (#SLOT_ADDR + 0x4) ; read MCR
207 or #0b00001011
208 ld (#SLOT_ADDR + 0x4), a ; MCR = DTR, RTS, HINT
209; ld b, #0x01
210; ld c, #0x06
211; call 0x0a2f ; jp 0x1afb, do something with port 3
212; call 0x33ca ; init modem vars, activate interrupts
213 ld a, #0b00001001 ; IER = EDSSI, ERBFI
214 ld (#SLOT_ADDR + 0x1), a
215 ld a, (#SLOT_ADDR + 0x6)
216 ld (_modem_curmsr), a ; read and store MSR
217 pop de
218 ld a, d
219 out (#SLOT_DEVICE), a ; restore old slot device
220 pop hl
221 pop de
222 pop bc
223 ret
224
225
226; void modem_powerdown(void)
227; most of this is from 0x33f6 in v2.54 firmware
228_modem_powerdown::
229 push bc
230 push de
231 push hl
232 call 0x3dbe ; disable caller id?
233 ld hl, (p3shadow)
234 ld a, (hl)
235 res 7, a ; disable caller id interrupt
236 ld (hl),a
237 out (#0x03), a
238 in a, (#0x29) ; XXX what is port 29?
239 or #0x0c
240 out (#0x29), a
241 ld hl, (p28shadow)
242 ld a, (hl)
243 set 2, a
244 res 3, a
245 ld (hl), a
246 out (#0x28), a ; XXX what is port 28?
247 xor a
248 ld (#0xe63b), a ; no idea what these shadow vars are
249 ld (#0xe63a), a
250 ld (#0xe64d), a
251 ld (#0xe638), a ; but init them all to 0
252; l33f8
253 ld a, #0x01
254 ld (#0xe638), a
255 in a, (#SLOT_DEVICE) ; store old slot device
256 ld d, a
257 push de
258 ld hl, (p2shadow)
259 ld a, (hl) ; read p2shadow
260 res 5, a ; turn off port 2.5 - modem power
261 ld (hl), a ; write p2shadow
262 out (#0x02), a ; also write it to port2
263 ld hl, #300
264 push hl
265 call _delay ; delay 300ms
266 pop hl
267 ld a, #0
268 out (#0x26), a ; turn port 26 off
269 ld hl, #100
270 push hl
271 call _delay ; delay 100ms
272 pop hl
273 pop de
274 ld a, d
275 out (#SLOT_DEVICE), a ; restore old slot device
276 pop hl
277 pop de
278 pop bc
279 ret
280
281
282; char modem_read(void)
283; return a byte in hl from the modem FIFO, from 0x3328 in v2.54 firmware
284_modem_read::
285 ; use hl
286 in a, (#SLOT_ADDR) ; save old slot device
287 ld h, a ; into h
288 ld a, #DEVICE_MODEM
289 out (#SLOT_DEVICE), a ; slot device = modem
290 ld a, (#SLOT_ADDR) ; read byte from modem
291 ld l, a ; into l
292 ld a, h
293 out (#SLOT_DEVICE), a ; set old slot device
294 ld h, #0x00
295 ret ; return hl
296
297
298; void modem_write(char c)
299; write a byte to the modem TX FIFO, from 0x33b6 in v2.54 firmware
300_modem_write::
301 push ix
302 ld ix, #0
303 add ix, sp
304 ld a, 4(ix)
305 ld l, a
306 in a, (#SLOT_DEVICE)
307 ld h, a
308 ld a, #DEVICE_MODEM
309 out (#SLOT_DEVICE), a
310 ld a, l
311 ld (#SLOT_ADDR), a
312 ld a, h
313 out (#SLOT_DEVICE), a
314 pop ix
315 ret
316
317
318; int modem_ier(void)
319; return modem IER register in hl, from 0x3339 in v2.54 firmware
320_modem_ier::
321 in a, (#SLOT_DEVICE)
322 ld h, a
323 ld a, #DEVICE_MODEM
324 out (#SLOT_DEVICE), a
325 ld a, (#SLOT_ADDR + 0x1) ; read modem IER
326 ld l, a
327 ld a, h
328 out (#SLOT_DEVICE), a
329 ld h, #0x0
330 ret
331
332
333; int modem_iir(void)
334; return modem IIR register in hl, from 0x334a in v2.54 firmware
335_modem_iir::
336 in a, (#SLOT_DEVICE)
337 ld h, a
338 ld a, #DEVICE_MODEM
339 out (#SLOT_DEVICE), a
340 ld a, (#SLOT_ADDR + 0x2) ; read modem IIR
341 ld l, a
342 ld a, h
343 out (#SLOT_DEVICE), a
344 ld h, #0x0
345 ret
346
347
348; int modem_lcr(void)
349; return modem LCR register in hl
350_modem_lcr::
351 in a, (#SLOT_DEVICE)
352 ld h, a
353 ld a, #DEVICE_MODEM
354 out (#SLOT_DEVICE), a
355 ld a, (#SLOT_ADDR + 0x3) ; read LCR
356 ld l, a
357 ld a, h
358 out (#SLOT_DEVICE), a
359 ld h, #0x00
360 ret
361
362
363; int modem_lsr(void)
364; return modem LSR register in hl
365_modem_lsr::
366 in a, (#SLOT_DEVICE)
367 ld h, a
368 ld a, #DEVICE_MODEM
369 out (#SLOT_DEVICE), a
370 ld a, (#SLOT_ADDR + 0x5) ; read LSR
371 ld l, a
372 ld a, h
373 out (#SLOT_DEVICE), a
374 ld h, #0x00
375 ret
376
377
378; int modem_msr(void)
379; return modem MSR register in hl
380_modem_msr::
381 in a, (#SLOT_DEVICE)
382 ld h, a
383 ld a, #DEVICE_MODEM
384 out (#SLOT_DEVICE), a
385 ld a, (#SLOT_ADDR + 0x6) ; read modem MSR
386 ld (_modem_curmsr), a
387 ld l, a
388 ld a, h
389 out (#SLOT_DEVICE), a
390 ld h, #0x0
391 ret
392
393; void modem_hangup(void)
394; drop DTR to force a hangup
395_modem_hangup::
396 push hl
397 in a, (#SLOT_DEVICE)
398 ld h, a
399 ld a, #DEVICE_MODEM
400 out (#SLOT_DEVICE), a
401 ld a, (#SLOT_ADDR + 0x4) ; read modem MCR
402 res 0, a ; drop DTR
403 ld (#SLOT_ADDR + 0x4), a
404 push af
405 push hl
406 ld hl, #500
407 push hl
408 call _delay ; sleep 500ms
409 pop hl
410 pop hl
411 pop af
412 set 0, a ; restore DTR
413 ld a, (#SLOT_ADDR + 0x6)
414 ld (_modem_curmsr), a
415 ld (#SLOT_ADDR + 0x4), a
416 ld a, (#SLOT_ADDR + 0x6)
417 ld (_modem_curmsr), a
418 ld a, h
419 out (#SLOT_DEVICE), a
420 pop hl
421 ret
422
423; void modem_pause(void)
424; send XOFF
425_modem_pause::
426 push hl
427 ld l, #XOFF
428 push hl
429 call _modem_write
430 pop hl
431 pop hl
432 ld a, #0
433 ld (_modem_flowing), a
434 ret
435
436; void modem_unpause(void)
437; send XON
438_modem_unpause::
439 push hl
440 ld l, #XON
441 push hl
442 call _modem_write
443 pop hl
444 pop hl
445 ret