]>
Commit | Line | Data |
---|---|---|
e58a7a25 L |
1 | IF NOT lasm\r |
2 | .printx * CPXBEE.ASM *\r | |
3 | ENDIF ;NOT lasm\r | |
4 | ; KERMIT - (Celtic for "FREE")\r | |
5 | ;\r | |
6 | ; This is the CP/M-80 implementation of the Columbia University\r | |
7 | ; KERMIT file transfer protocol.\r | |
8 | ;\r | |
9 | ; Version 4.09\r | |
10 | ;\r | |
11 | ; Copyright June 1981,1982,1983,1984,1985\r | |
12 | ; Columbia University\r | |
13 | ;\r | |
14 | ; Originally written by Bill Catchings of the Columbia University Center for\r | |
15 | ; Computing Activities, 612 W. 115th St., New York, NY 10025.\r | |
16 | ;\r | |
17 | ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,\r | |
18 | ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many\r | |
19 | ; others.\r | |
20 | ;\r | |
21 | ;\r | |
22 | ;\r | |
23 | ; revision history:\r | |
24 | ;\r | |
25 | ; edit 1, 1st September 1990 \r | |
26 | ; Original version by Russell Lang <rjl@monu1.cc.monash.edu.au>\r | |
27 | ; The 'microbee' is designed and manufactured in Australia\r | |
28 | ; by Microbee Systems Ltd (previously Applied Technology).\r | |
29 | ; The microprocessor is a Z80 at 3.375MHz.\r | |
30 | ; The video screen is memory mapped from 0F000h to 0F7FFh, \r | |
31 | ; with Programmable Characters 80-FF from 0F800h to 0FFFFh. \r | |
32 | ; The serial and parallel ports are implemented using a Z80 PIO.\r | |
33 | ; The early model microbees were ROM-Basic computers with up\r | |
34 | ; to 32k of battery backed RAM. Later models dropped the\r | |
35 | ; ROM-Basic and added disk drives and CP/M. The disk systems\r | |
36 | ; include the 56k (64k) APC (5.25" drives), 64k Computer-In-A-Book \r | |
37 | ; (3.5"), 128k Dynamic (5.25" or 3.5"), 256TC (3.5").\r | |
38 | ; \r | |
39 | ; This version of kermit was developed on a 56k APC.\r | |
40 | ; It has been tested on 56k, 64k, 128k and 256k Microbees.\r | |
41 | ;\r | |
42 | ; The serial port is implemented in software NOT hardware.\r | |
43 | ; A special transmit routine allows simultaneous receiving\r | |
44 | ; for all speeds except 75/1200, 1200/75, 4800, 9600.\r | |
45 | ; The receive routine is interrupt driven with a 2 kbyte buffer.\r | |
46 | ; The 9600 bit/s speed is marginal on receive - if the transmitter\r | |
47 | ; is slightly fast (more than about 1%), the serial routine will \r | |
48 | ; not have enough time to put the character in the buffer before \r | |
49 | ; the next character arrives.\r | |
50 | \r | |
51 | \r | |
52 | ;\r | |
53 | ; *** MAIN CODE START ***\r | |
54 | ;\r | |
55 | ;\r | |
56 | ; Keep module name, edit number, and last revision date in memory.\r | |
57 | \r | |
58 | sysedt: db 'CPXSYS.ASM (35) 01-Dec-86$'\r | |
59 | family: db 'CPXBEE.ASM (1) 01-Sep-90$'\r | |
60 | \r | |
61 | \r | |
62 | ; Assembly time message announcing which version we're building\r | |
63 | \r | |
64 | .printx * Assembling Microbee Kermit-80 *\r | |
65 | \r | |
66 | z80 EQU TRUE ; They all use Z80s\r | |
67 | \r | |
68 | defesc EQU ']'-100O ;The default escape character for Microbee\r | |
69 | \r | |
70 | vtval EQU 0 ; use default emulation which is adm3a superset\r | |
71 | \r | |
72 | ;\r | |
73 | sysxin: ;continuation of system initialisation code\r | |
74 | ; set up baud rate\r | |
75 | lxi h,t300\r | |
76 | shld speed\r | |
77 | xchg\r | |
78 | call setbaud\r | |
79 | ; change the interrupt vector so that we intercept rs232 input\r | |
80 | db 0EDh,57h ;ld a,i ;get old interrupt reg\r | |
81 | sta oldint\r | |
82 | mvi a,int ;new value\r | |
83 | db 0EDh,47h ;ld i,a\r | |
84 | ret ; return from system-dependent routine\r | |
85 | \r | |
86 | \r | |
87 | ;\r | |
88 | ; sysexit - System-dependent termination processing\r | |
89 | ; if we've changed anything, this is our last\r | |
90 | ; chance to put it back.\r | |
91 | ;\r | |
92 | sysexit:\r | |
93 | lda oldint ;restore old interrupt reg\r | |
94 | db 0EDh,47h ;ld i,a\r | |
95 | ret\r | |
96 | \r | |
97 | ;\r | |
98 | ; syscon - System-dependent processing for start\r | |
99 | ; of CONNECT command.\r | |
100 | ;\r | |
101 | syscon:\r | |
102 | lxi d,conmsg\r | |
103 | call prtstr\r | |
104 | ret\r | |
105 | \r | |
106 | conmsg: ; Messages printed when entering transparent (CONNECT) mode:\r | |
107 | db cr,lf,'$'\r | |
108 | ;\r | |
109 | ; syscls - system-dependent close routine\r | |
110 | ; called when exiting transparent session.\r | |
111 | ;\r | |
112 | syscls:\r | |
113 | ret\r | |
114 | ;\r | |
115 | ; sysinh - help for system-dependent special functions.\r | |
116 | ; called in response to <escape>?, after listing\r | |
117 | ; all the system-independent escape sequences.\r | |
118 | ;\r | |
119 | sysinh:\r | |
120 | lxi d,inhlps ; we got options...\r | |
121 | call prtstr ; print them.\r | |
122 | ret\r | |
123 | \r | |
124 | \r | |
125 | ; additional, system-dependent help for transparent mode\r | |
126 | ; (two-character escape sequences)\r | |
127 | inhlps:\r | |
128 | db cr,lf,'B Transmit a BREAK (0.3s)'\r | |
129 | db cr,lf,'L Transmit a LONG BREAK (1.8s)'\r | |
130 | db cr,lf,'W Wipe screen clear'\r | |
131 | db '$'\r | |
132 | \r | |
133 | ; sysint - system dependent special functions\r | |
134 | ; called when transparent escape character has been typed;\r | |
135 | ; the second character of the sequence is in A (and in B).\r | |
136 | ; returns:-\r | |
137 | ; non-skip: sequence has been processed\r | |
138 | ; skip : sequence was not recognized\r | |
139 | ;\r | |
140 | sysint: ani 137O ; convert lower case to upper, for testing...\r | |
141 | cpi 'B' ; send break ?\r | |
142 | jz sendbr ; then jump to send break routine\r | |
143 | cpi 'L' ; long break ?\r | |
144 | jz longbr ; then jump to long break routine\r | |
145 | cpi 'W' ; clear screen ?\r | |
146 | jz clrtop ; then jump to clear screen routine\r | |
147 | jmp rskp ; take skip return - command not recognized.\r | |
148 | \r | |
149 | ;\r | |
150 | ; Break routines\r | |
151 | ;\r | |
152 | longbr:\r | |
153 | mvi e,180 ; time for long break is 1800 ms\r | |
154 | jmp setbit\r | |
155 | \r | |
156 | sendbr:\r | |
157 | mvi e,30 ; time for break is 300 ms\r | |
158 | \r | |
159 | setbit: \r | |
160 | in portb\r | |
161 | ani 0dfh ; mask with tx bit\r | |
162 | out portb\r | |
163 | ;\r | |
164 | ; Now, delay for duration of hangup or break\r | |
165 | mov a,e ; delay count\r | |
166 | call delay\r | |
167 | ;\r | |
168 | ; Time's up. Put transmitter back in normal state and return.\r | |
169 | in portb\r | |
170 | ori 20h ; mask with tx bit\r | |
171 | out portb\r | |
172 | ret ; done.\r | |
173 | \r | |
174 | ; sysflt - system-dependent filter\r | |
175 | ; called with character in E.\r | |
176 | ; if this character should not be printed, return with A = zero.\r | |
177 | ; preserves bc, de, hl.\r | |
178 | ; note: <xon>,<xoff>,<del>, and <nul> are always discarded.\r | |
179 | ;\r | |
180 | sysflt:\r | |
181 | mov a,e ; get character for testing\r | |
182 | ret\r | |
183 | \r | |
184 | ;\r | |
185 | ; sysbye - system-dependent processing for BYE command.\r | |
186 | ;\r | |
187 | sysbye:\r | |
188 | ret\r | |
189 | \r | |
190 | ;\r | |
191 | ; This is the system-dependent command to change the baud rate.\r | |
192 | ; DE contains the two-byte value from the baud rate table; this\r | |
193 | ; value is also stored in 'speed'.\r | |
194 | ;\r | |
195 | sysspd:\r | |
196 | call setbaud\r | |
197 | ret\r | |
198 | \r | |
199 | ;\r | |
200 | ; Speed tables\r | |
201 | ; (Note that speed tables MUST be in alphabetical order for later\r | |
202 | ; lookup procedures, and must begin with a value showing the total\r | |
203 | ; number of entries. The speed help tables are just for us poor\r | |
204 | ; humans.\r | |
205 | \r | |
206 | ; db string length,string,divisor (2 identical bytes or 1 word)\r | |
207 | ; [Toad Hall]\r | |
208 | \r | |
209 | spdtbl: db 11 ;11 entries\r | |
210 | db 03h,'110$'\r | |
211 | dw t110\r | |
212 | db 04h,'1200$'\r | |
213 | dw t1200\r | |
214 | db 07h,'1200/75$'\r | |
215 | dw t1275\r | |
216 | db 03h,'150$'\r | |
217 | dw t150\r | |
218 | db 04h,'2400$'\r | |
219 | dw t2400\r | |
220 | db 03h,'300$'\r | |
221 | dw t300\r | |
222 | db 04h,'4800$'\r | |
223 | dw t4800\r | |
224 | db 03h,'600$'\r | |
225 | dw t600\r | |
226 | db 02h,'75$'\r | |
227 | dw t75\r | |
228 | db 07h,'75/1200$'\r | |
229 | dw t7512\r | |
230 | db 04h,'9600$'\r | |
231 | dw t9600\r | |
232 | \r | |
233 | sphtbl: db cr,lf,'75 75/1200 110 150 300 600 1200 1200/75'\r | |
234 | db ' 2400 4800 9600$'\r | |
235 | \r | |
236 | \r | |
237 | ;\r | |
238 | ; This is the system-dependent SET PORT command.\r | |
239 | sysprt:\r | |
240 | ret\r | |
241 | \r | |
242 | prttbl equ 0 ; SET PORT is not supported\r | |
243 | prhtbl equ 0\r | |
244 | \r | |
245 | \r | |
246 | ;\r | |
247 | ; selmdm - select modem port\r | |
248 | ; selcon - select console port\r | |
249 | ; selmdm is called before using inpmdm or outmdm;\r | |
250 | ; selcon is called before using inpcon or outcon.\r | |
251 | ; preserves BC, DE, HL.\r | |
252 | ;\r | |
253 | selmdm:\r | |
254 | selcon:\r | |
255 | ret\r | |
256 | ;\r | |
257 | ; Get character from console, or return zero.\r | |
258 | ; result is returned in A. destroys bc, de, hl.\r | |
259 | ;\r | |
260 | inpcon:\r | |
261 | mvi c,dconio ;Direct console I/O BDOS call.\r | |
262 | mvi e,0FFH ;Input.\r | |
263 | call BDOS\r | |
264 | ret\r | |
265 | ;\r | |
266 | ;\r | |
267 | ; Output character in E to the console.\r | |
268 | ; destroys bc, de, hl\r | |
269 | ;\r | |
270 | outcon:\r | |
271 | \r | |
272 | mvi c,dconio ;Console output bdos call.\r | |
273 | call bdos ;Output the char to the console.\r | |
274 | ret\r | |
275 | \r | |
276 | \r | |
277 | \r | |
278 | ;\r | |
279 | ;\r | |
280 | ; outmdm - output a char from E to the modem.\r | |
281 | ; the parity bit has been set as necessary.\r | |
282 | ; returns nonskip; bc, de, hl preserved.\r | |
283 | outmdm:\r | |
284 | ;\r | |
285 | push psw\r | |
286 | push b\r | |
287 | push d\r | |
288 | push h\r | |
289 | mov a,e\r | |
290 | lxi h,outm2 ; return address\r | |
291 | push h\r | |
292 | lhld txcall\r | |
293 | pchl ; send to rs232 port\r | |
294 | outm2: pop h\r | |
295 | pop d\r | |
296 | pop b\r | |
297 | pop psw\r | |
298 | ret\r | |
299 | \r | |
300 | \r | |
301 | ;\r | |
302 | ; get character from modem; return zero if none available.\r | |
303 | ; bc, de, hl preserved.\r | |
304 | inpmdm:\r | |
305 | call rsin ; get char if available\r | |
306 | ret ; return with character in A\r | |
307 | \r | |
308 | \r | |
309 | ;\r | |
310 | ; flsmdm - flush comm line.\r | |
311 | ; Modem is selected.\r | |
312 | ; Currently, just gets characters until none are available.\r | |
313 | flsmdm: call inpmdm ; Try to get a character\r | |
314 | ora a ; Got one?\r | |
315 | jnz flsmdm ; If so, try for another\r | |
316 | ret ; Receiver is drained. Return.\r | |
317 | \r | |
318 | ;\r | |
319 | ; lptstat - get the printer status. Return a=0 if ok, or 0ffh if not.\r | |
320 | lptstat:\r | |
321 | lda pflag\r | |
322 | ret\r | |
323 | \r | |
324 | ;\r | |
325 | ; outlpt - output character in E to printer\r | |
326 | ; console is selected.\r | |
327 | ; preserves de.\r | |
328 | outlpt:\r | |
329 | push d ; save DE in either case\r | |
330 | ana a ; if A = 0 do nothing,\r | |
331 | jz outlp1 ; [30] if a=0 do nothing\r | |
332 | mov a,e\r | |
333 | call parout\r | |
334 | outlp1: pop d ; restore saved register pair\r | |
335 | ret\r | |
336 | \r | |
337 | \r | |
338 | ;\r | |
339 | ;\r | |
340 | ; Screen manipulation routines\r | |
341 | ; csrpos - move to row B, column C\r | |
342 | ;\r | |
343 | ; csrpos for terminals that use a leadin sequence followed\r | |
344 | ; by (row + 31.) and (column + 31.)\r | |
345 | ;\r | |
346 | csrpos: push b ; save coordinates\r | |
347 | lxi d,curldn ; get cursor leadin sequence\r | |
348 | call prtstr ; print it\r | |
349 | pop h ; restore coordinates\r | |
350 | mov a,h ; get row\r | |
351 | adi (' '-1) ; space is row one\r | |
352 | mov e,a\r | |
353 | push h\r | |
354 | call outcon ; output row\r | |
355 | pop h\r | |
356 | mov a,l ; get column\r | |
357 | adi (' '-1) ; space is column one\r | |
358 | mov e,a\r | |
359 | jmp outcon ; output it and return\r | |
360 | \r | |
361 | ;\r | |
362 | ; delchr - make delete look like a backspace. Unless delete is a\r | |
363 | ; printing character, we just need to print a backspace\r | |
364 | ; (we'll output clrsp afterwards)\r | |
365 | delchr:\r | |
366 | lxi d,delstr\r | |
367 | jmp prtstr\r | |
368 | \r | |
369 | \r | |
370 | ; erase the character at the current cursor position\r | |
371 | clrspc: mvi e,' '\r | |
372 | call outcon\r | |
373 | mvi e,bs ;get a backspace\r | |
374 | jmp outcon\r | |
375 | \r | |
376 | ; erase the current line\r | |
377 | clrlin: lxi d,eralin\r | |
378 | jmp prtstr\r | |
379 | \r | |
380 | ; erase the whole screen, and go home\r | |
381 | clrtop: lxi d,erascr\r | |
382 | jmp prtstr\r | |
383 | \r | |
384 | \r | |
385 | sysver: db 'Microbee$'\r | |
386 | outlin: db 1AH,cr,lf,tab,'$' ;(Clear screen, home cursor)\r | |
387 | erascr: db 1AH,'$' ;Clear screen and go home.\r | |
388 | eralin: db cr,esc,'T$' ;Clear line.\r | |
389 | delstr: db bs,'$' ; Adjust for delete\r | |
390 | curldn: db esc,'=$' ;Cursor lead-in\r | |
391 | ttab: ;Table start location.\r | |
392 | ta: db ('K'-100O),'$',0,0 ;Cursor up.\r | |
393 | tb: db 12O,'$',0,0 ;Cursor down.\r | |
394 | tc: db ('L'-100O),'$',0,0 ;Cursor right.\r | |
395 | td: db bs,'$',0,0 ;Cursor left.\r | |
396 | te: db subt,'$',0,0 ;Clear screen.\r | |
397 | tf: db '$',0,0,0 ;(can't) Enter graphics mode\r | |
398 | tg: db '$',0,0,0 ;(can't) Exit graphics mode\r | |
399 | th: db ('^'-100O),'$',0,0 ;Cursor home.\r | |
400 | ti: db ('K'-100O),'$',0,0 ;Reverse linefeed.\r | |
401 | tj: db esc,'Y$',0 ;Clear to end of screen.\r | |
402 | tk: db esc,'T$',0 ;Clear to end of line.\r | |
403 | \r | |
404 | \r | |
405 | ;Microbee software serial port routines\r | |
406 | porta equ 0\r | |
407 | portb equ 2\r | |
408 | \r | |
409 | \r | |
410 | ; interrupt vectors\r | |
411 | ; We change the Z80 Interrupt register to point to these vectors.\r | |
412 | ; Instead of trying to identify a particular Microbee system, \r | |
413 | ; we just put vectors here for all systems.\r | |
414 | ;\r | |
415 | ; known vectors are:\r | |
416 | ; 48h : 56k (64k apc) - tested 19-Jun-1990\r | |
417 | ; 48k : 64k - tested 01-Sep-1990\r | |
418 | ; 50h : dreamdisk (3rd party disk for Microbee)\r | |
419 | ; e0h : 128k - tested 19-Jun-1990\r | |
420 | ; e0h : 256k - tested 01-Sep-1990\r | |
421 | \r | |
422 | org ($ and 0ff00h) + 100h\r | |
423 | int equ $/256 ; byte for interrupt register\r | |
424 | \r | |
425 | dw inta ; printer vector\r | |
426 | dw intb ; rs232 vector\r | |
427 | dw inta\r | |
428 | dw intb\r | |
429 | dw inta\r | |
430 | dw intb\r | |
431 | dw inta\r | |
432 | dw intb\r | |
433 | dw inta\r | |
434 | dw intb\r | |
435 | dw inta\r | |
436 | dw intb\r | |
437 | dw inta\r | |
438 | dw intb\r | |
439 | dw inta\r | |
440 | dw intb\r | |
441 | dw inta\r | |
442 | dw intb\r | |
443 | dw inta\r | |
444 | dw intb\r | |
445 | dw inta\r | |
446 | dw intb\r | |
447 | dw inta\r | |
448 | dw intb\r | |
449 | dw inta\r | |
450 | dw intb\r | |
451 | dw inta\r | |
452 | dw intb\r | |
453 | dw inta\r | |
454 | dw intb\r | |
455 | dw inta\r | |
456 | dw intb\r | |
457 | dw inta\r | |
458 | dw intb\r | |
459 | dw inta\r | |
460 | dw intb\r | |
461 | dw inta\r | |
462 | dw intb\r | |
463 | dw inta\r | |
464 | dw intb\r | |
465 | dw inta\r | |
466 | dw intb\r | |
467 | dw inta\r | |
468 | dw intb\r | |
469 | dw inta\r | |
470 | dw intb\r | |
471 | dw inta\r | |
472 | dw intb\r | |
473 | dw inta\r | |
474 | dw intb\r | |
475 | dw inta\r | |
476 | dw intb\r | |
477 | dw inta\r | |
478 | dw intb\r | |
479 | dw inta\r | |
480 | dw intb\r | |
481 | dw inta\r | |
482 | dw intb\r | |
483 | dw inta\r | |
484 | dw intb\r | |
485 | dw inta\r | |
486 | dw intb\r | |
487 | dw inta\r | |
488 | dw intb\r | |
489 | dw inta\r | |
490 | dw intb\r | |
491 | dw inta\r | |
492 | dw intb\r | |
493 | dw inta\r | |
494 | dw intb\r | |
495 | dw inta\r | |
496 | dw intb\r | |
497 | dw inta\r | |
498 | dw intb\r | |
499 | dw inta\r | |
500 | dw intb\r | |
501 | dw inta\r | |
502 | dw intb\r | |
503 | dw inta\r | |
504 | dw intb\r | |
505 | dw inta\r | |
506 | dw intb\r | |
507 | dw inta\r | |
508 | dw intb\r | |
509 | dw inta\r | |
510 | dw intb\r | |
511 | dw inta\r | |
512 | dw intb\r | |
513 | dw inta\r | |
514 | dw intb\r | |
515 | dw inta\r | |
516 | dw intb\r | |
517 | dw inta\r | |
518 | dw intb\r | |
519 | dw inta\r | |
520 | dw intb\r | |
521 | dw inta\r | |
522 | dw intb\r | |
523 | dw inta\r | |
524 | dw intb\r | |
525 | dw inta\r | |
526 | dw intb\r | |
527 | dw inta\r | |
528 | dw intb\r | |
529 | dw inta\r | |
530 | dw intb\r | |
531 | dw inta\r | |
532 | dw intb\r | |
533 | dw inta\r | |
534 | dw intb\r | |
535 | dw inta\r | |
536 | dw intb\r | |
537 | dw inta\r | |
538 | dw intb\r | |
539 | dw inta\r | |
540 | dw intb\r | |
541 | dw inta\r | |
542 | dw intb\r | |
543 | dw inta\r | |
544 | dw intb\r | |
545 | dw inta\r | |
546 | dw intb\r | |
547 | dw inta\r | |
548 | dw intb\r | |
549 | dw inta\r | |
550 | dw intb\r | |
551 | dw inta\r | |
552 | dw intb\r | |
553 | \r | |
554 | \r | |
555 | ; tables for baud rates\r | |
556 | t75: db 124,13 ; full delay\r | |
557 | db 55,7 ; semi delay\r | |
558 | db 168,255 ; txrx delay\r | |
559 | dw trout ; address of subroutine to transmit char\r | |
560 | t7512: db 124,13 ; 75R/1200T\r | |
561 | db 55,7\r | |
562 | db 194,1 ; txout delay\r | |
563 | dw txout\r | |
564 | t110: db 129,9\r | |
565 | db 55,5\r | |
566 | db 5,217 \r | |
567 | dw trout\r | |
568 | t150: db 59,7\r | |
569 | db 23,4\r | |
570 | db 2,158\r | |
571 | dw trout\r | |
572 | t300: db 26,4\r | |
573 | db 134,2\r | |
574 | db 3,75\r | |
575 | dw trout\r | |
576 | t600: db 139,2\r | |
577 | db 191,1\r | |
578 | db 2,34\r | |
579 | dw trout\r | |
580 | t1200: db 195,1\r | |
581 | db 90,1\r | |
582 | db 3,13\r | |
583 | dw trout\r | |
584 | t1275: db 195,1 ; 1200R/75T\r | |
585 | db 90,1\r | |
586 | db 124,13\r | |
587 | dw txout\r | |
588 | t2400: db 94,1\r | |
589 | db 40,1\r | |
590 | db 2,3\r | |
591 | dw trout\r | |
592 | t4800: db 44,1\r | |
593 | db 15,1\r | |
594 | db 44,1\r | |
595 | dw txout\r | |
596 | t9600: db 19,1\r | |
597 | db 1,1\r | |
598 | db 19,1\r | |
599 | dw txout\r | |
600 | \r | |
601 | \r | |
602 | ; copy table entries to locations used by serial routines\r | |
603 | setbaud:\r | |
604 | lxi h,fulldel\r | |
605 | mvi b,8\r | |
606 | setb2: ldax d\r | |
607 | mov m,a\r | |
608 | inx h\r | |
609 | inx d\r | |
610 | dcr b\r | |
611 | jnz setb2\r | |
612 | ret\r | |
613 | \r | |
614 | \r | |
615 | ;transmit character in E\r | |
616 | ; destroys all regs\r | |
617 | txout: mvi b,ntotal ;total number of bits to send\r | |
618 | di\r | |
619 | in portb ;c = portb with tx bit zeroed\r | |
620 | ani 0dfh\r | |
621 | mov c,a\r | |
622 | ora a ;carry=0 (start bit)\r | |
623 | txout2: mov a,c ; 4T\r | |
624 | jnc txout4 ;10T skip if space\r | |
625 | ori 20h ; 3T (average) set mark\r | |
626 | txout4: out portb ;11T\r | |
627 | lhld txrxdel ;16T\r | |
628 | txout6: dcr l ;delay\r | |
629 | jnz txout6\r | |
630 | dcr h\r | |
631 | jnz txout6 ; 14*L + 14*H + 3584*(H-1)\r | |
632 | stc ; 4T carry=1 (stop bit)\r | |
633 | mov a,e ; 4T shift next bit to carry\r | |
634 | rar ; 4T\r | |
635 | mov e,a ; 4T\r | |
636 | dcr b ; 4T\r | |
637 | jnz txout2 ;10T\r | |
638 | ;loop = 74T + (delay loop)\r | |
639 | ei\r | |
640 | ret\r | |
641 | \r | |
642 | \r | |
643 | ;\r | |
644 | ;transmit character in E\r | |
645 | ;simultaneous receive char if necessary\r | |
646 | trout: mov a,e\r | |
647 | mvi b,ndata\r | |
648 | lxi h,0\r | |
649 | tro2: rrc ;shift tx char to hl\r | |
650 | mov c,a\r | |
651 | mov a,l\r | |
652 | ral\r | |
653 | mov l,a\r | |
654 | mov a,h\r | |
655 | ral\r | |
656 | mov h,a\r | |
657 | mov a,c ;recover\r | |
658 | dcr b\r | |
659 | jnz tro2\r | |
660 | tro10: mvi b,tqfudge ;adjust char in hl to align with\r | |
661 | ;tx bit of portb\r | |
662 | tro12: stc ; pad out\r | |
663 | mov a,l\r | |
664 | ral\r | |
665 | mov l,a\r | |
666 | mov a,h\r | |
667 | ral\r | |
668 | mov h,a\r | |
669 | dcr b\r | |
670 | jnz tro12\r | |
671 | mvi a,0ffh ;flag to say we are not receiving\r | |
672 | sta trtemp ;save it\r | |
673 | mvi d,tqbit ;total number of qtr bits to send\r | |
674 | in portb ;b = portb with tx bit zeroed\r | |
675 | ani 0dfh\r | |
676 | mov b,a\r | |
677 | mvi e,0 ;we are not receiving yet\r | |
678 | tro14: in portb\r | |
679 | ori 8h ;test CTS\r | |
680 | jz tro14 ;loop till Clear To Send\r | |
681 | out 09h ;Color Wait OFF\r | |
682 | di\r | |
683 | call qbit\r | |
684 | lda trtemp ;are we receiving\r | |
685 | ora a\r | |
686 | jnz tro22 ;skip if not\r | |
687 | in portb ;is last bit a mark?\r | |
688 | ori 10h\r | |
689 | jz tro18 ;skip if mark (don't wait for stop)\r | |
690 | lhld fulldel ;delay to stop bit\r | |
691 | tro16: dcr l\r | |
692 | jnz tro16\r | |
693 | dcr h\r | |
694 | jnz tro16\r | |
695 | tro18: lhld wptr ; check buffer\r | |
696 | xchg\r | |
697 | lhld rptr\r | |
698 | dcx d ; decrement queue pointer\r | |
699 | mov a,d\r | |
700 | ora e\r | |
701 | jnz tro20 ; skip if no queue wrap around\r | |
702 | lxi d,maxque-1 ; wrap around\r | |
703 | tro20: mov a,l ; sub hl,de\r | |
704 | sub e\r | |
705 | mov l,a\r | |
706 | mov a,h\r | |
707 | sbb d\r | |
708 | mov h,a\r | |
709 | ora l ; check for zero\r | |
710 | jz tro22 ; skip if buffer full\r | |
711 | xchg\r | |
712 | shld wptr ; update queue\r | |
713 | lxi d,rqueue\r | |
714 | dad d\r | |
715 | mov m,c ; put char in queue\r | |
716 | tro22: ei\r | |
717 | ret ;ret\r | |
718 | \r | |
719 | \r | |
720 | ; routine for quarter bit timing\r | |
721 | ; for transmit and simultaneous receive\r | |
722 | ; total execution time is 223T + L*14T + H*34T\r | |
723 | qbit: call txrx ;17T + 162T\r | |
724 | lda txrxdel ;13T\r | |
725 | qbit2: dcr a ; 4T\r | |
726 | jnz qbit2 ;10T\r | |
727 | lda txrxdel+1 ;13T\r | |
728 | qbit4: dcr a ; 4T\r | |
729 | nop ; 4T\r | |
730 | nop ; 4T\r | |
731 | nop ; 4T\r | |
732 | nop ; 4T\r | |
733 | nop ; 4T\r | |
734 | jnz qbit4 ;10T\r | |
735 | mov a,d ; 4T Check if still sending or receiving\r | |
736 | ora e ; 4T\r | |
737 | jnz qbit ;10T\r | |
738 | ret\r | |
739 | \r | |
740 | \r | |
741 | ;simultaneous transmit/receive\r | |
742 | ;do next quarter bit\r | |
743 | ; regs: b = portb with tx bit zeroed\r | |
744 | ; c = character being received\r | |
745 | ; d = number of qtr bits remaining to send\r | |
746 | ; e = number of qtr bits remaining to receive (0 if not receiving)\r | |
747 | ; hl = character being transmitted\r | |
748 | ;this subroutine always executes in 162T (or 163T)\r | |
749 | txrx: mov a,d ; 4T qtr bits remaining to send\r | |
750 | ora a ; 4T\r | |
751 | jz txrx12 ;10T skip if no bits remaining (may be receiving)\r | |
752 | ani 03h ; 7T a complete bit?\r | |
753 | jnz txrx10 ;10T skip if not\r | |
754 | dad h ;11T shift tx bit to bit 5 of h\r | |
755 | mov a,h ; 4T\r | |
756 | ani 20h ; 7T extract tx bit\r | |
757 | ora b ; 4T combine with portb\r | |
758 | out portb ;11T send it\r | |
759 | txrx2: dcr d ; 4T one less qtr bit to send\r | |
760 | ;76T total\r | |
761 | ;now receive part\r | |
762 | txrx4: mov a,e ; 4T qtr bits remaining to receive\r | |
763 | ora a ; 4T\r | |
764 | jz txrx16 ;10T skip if not receiving\r | |
765 | ani 3h ; 7T a complete bit?\r | |
766 | jnz txrx14 ;10T skip if not\r | |
767 | in portb ;11T get input\r | |
768 | ani 10h ; 7T extract rx bit\r | |
769 | sui 1 ; 7T bit to carry\r | |
770 | mov a,c ; 4T bit to c\r | |
771 | rar ; 4T\r | |
772 | mov c,a ; 4T\r | |
773 | txrx6: dcr e ; 4T one less qtr bit to receive\r | |
774 | txrx8: ret ;10T\r | |
775 | ;86T total\r | |
776 | \r | |
777 | ;come here if transmitting, but not a complete bit\r | |
778 | ;delay to match up execution times\r | |
779 | txrx10:\r | |
780 | ora a ; 4T\r | |
781 | ora a ; 4T\r | |
782 | ora a ; 4T\r | |
783 | ora a ; 4T\r | |
784 | ora a ; 4T\r | |
785 | ori 00h ; 7T\r | |
786 | jmp txrx2 ;10T\r | |
787 | \r | |
788 | ;come here if not sending (but still receiving)\r | |
789 | ;delay to match up execution times\r | |
790 | txrx12: ora a ; 4T\r | |
791 | ora a ; 4T\r | |
792 | ora a ; 4T\r | |
793 | ora a ; 4T\r | |
794 | ora a ; 4T\r | |
795 | ora a ; 4T\r | |
796 | ora a ; 4T\r | |
797 | ora a ; 4T\r | |
798 | ora a ; 4T\r | |
799 | ora a ; 4T\r | |
800 | ora a ; 4T\r | |
801 | ora a ; 4T\r | |
802 | jmp txrx4 ;10T\r | |
803 | \r | |
804 | ;come here if receiving (but not a complete bit)\r | |
805 | ;delay to match up execution time\r | |
806 | txrx14: ora a ; 4T\r | |
807 | ora a ; 4T\r | |
808 | ora a ; 4T\r | |
809 | ora a ; 4T\r | |
810 | ora a ; 4T\r | |
811 | ori 00h ; 7T\r | |
812 | jmp txrx6 ;10T\r | |
813 | \r | |
814 | ;come here if not receiving\r | |
815 | txrx16: in portb ;11T check if start bit\r | |
816 | ani 10h ; 7T\r | |
817 | jz txrx18 ;10T skip if mark\r | |
818 | mvi e,rqbit ; 7T get quarter bit count for receive\r | |
819 | xra a ; 4T\r | |
820 | sta trtemp ;13T store flag to say we are receiving\r | |
821 | ori a ; 7T delay (should be 6T)\r | |
822 | ret ;10T\r | |
823 | \r | |
824 | txrx18: ora a ; 4T\r | |
825 | ora a ; 4T\r | |
826 | ora a ; 4T\r | |
827 | ora a ; 4T\r | |
828 | ora a ; 4T\r | |
829 | jmp txrx8 ;10T\r | |
830 | \r | |
831 | \r | |
832 | \r | |
833 | \r | |
834 | ; RS232 input interrupt routine\r | |
835 | ; stores received character in queue\r | |
836 | ; ;semi delay starts here\r | |
837 | intb: ;20T (approx.) for interrupt\r | |
838 | push psw ;11T\r | |
839 | push b ;11T\r | |
840 | push d ;11T\r | |
841 | push h ;11T\r | |
842 | in portb ;11T\r | |
843 | ani 10h ; 7T test input for start bit\r | |
844 | jz intb16 ;10T skip if no start bit.\r | |
845 | out 09h ;11T\r | |
846 | lhld semidel ;16T half bit delay\r | |
847 | intb2: dcr l ; 4T\r | |
848 | jnz intb2 ;10T inner loop 14T*L\r | |
849 | dcr h ; 4T\r | |
850 | jnz intb2 ;10T outer loop (14*H + 256*14*(H-1))T\r | |
851 | mvi e,8 ; 6T number of data bits\r | |
852 | ;semi delay ends here (125T + delay loop)\r | |
853 | ;full delay starts here\r | |
854 | intb4: lhld fulldel ;16T full bit delay\r | |
855 | intb6: dcr l\r | |
856 | jnz intb6\r | |
857 | dcr h\r | |
858 | jnz intb6 ; 14*L + 14*H + 3584*(H-1)\r | |
859 | in portb ;11T test input\r | |
860 | ani 10h ; 7T\r | |
861 | sui 1 ; 7T input bit to carry\r | |
862 | mov a,c ; 4T\r | |
863 | rar ; 4T\r | |
864 | mov c,a ; 4T and then to C\r | |
865 | dcr e ; 4T bit count\r | |
866 | jnz intb4 ;10T loop till all data bits collected\r | |
867 | ;full delay ends here (67T + delay loop)\r | |
868 | in portb\r | |
869 | ani 10h\r | |
870 | jz intb12 ; skip if mark\r | |
871 | lhld fulldel ; wait for stop bit\r | |
872 | intb10: dcr l\r | |
873 | jnz intb10\r | |
874 | dcr h\r | |
875 | jnz intb10\r | |
876 | intb12: lhld wptr ; check buffer\r | |
877 | xchg\r | |
878 | lhld rptr\r | |
879 | dcx d ; decrement queue pointer\r | |
880 | mov a,d\r | |
881 | ora e\r | |
882 | jnz intb14 ; skip if no queue wrap around\r | |
883 | lxi d,maxque-1 ; wrap around\r | |
884 | intb14: mov a,l ; sub hl,de\r | |
885 | sub e\r | |
886 | mov l,a\r | |
887 | mov a,h\r | |
888 | sbb d\r | |
889 | mov h,a\r | |
890 | ora l ; check for zero\r | |
891 | jz intb16 ; skip if buffer full\r | |
892 | xchg\r | |
893 | shld wptr ; update queue\r | |
894 | lxi d,rqueue\r | |
895 | dad d\r | |
896 | mov m,c ; put char in queue\r | |
897 | intb16: pop h\r | |
898 | pop d\r | |
899 | pop b\r | |
900 | pop psw\r | |
901 | ei\r | |
902 | db 0EDh,4Dh ;reti\r | |
903 | \r | |
904 | ;\r | |
905 | ; get char from serial port buffer.\r | |
906 | ; exit: A=char or Z if no char\r | |
907 | rsin: push d\r | |
908 | push h\r | |
909 | lhld rptr\r | |
910 | xchg\r | |
911 | lhld wptr\r | |
912 | mov a,l ;sub hl,de\r | |
913 | sub e\r | |
914 | mov l,a\r | |
915 | mov a,h\r | |
916 | sbb d\r | |
917 | mov h,a\r | |
918 | ora l ;check for zero\r | |
919 | jnz rsi4 ;get char\r | |
920 | rsi2: pop h\r | |
921 | pop d\r | |
922 | ret\r | |
923 | \r | |
924 | rsi4: push psw\r | |
925 | dcx d ; decrement queue pointer\r | |
926 | mov a,d\r | |
927 | ora e\r | |
928 | jnz rsi6 ; skip if no queue wrap around\r | |
929 | lxi d,maxque-1 ; wrap around\r | |
930 | rsi6: pop psw\r | |
931 | xchg\r | |
932 | shld rptr\r | |
933 | lxi d,rqueue\r | |
934 | dad d\r | |
935 | mov e,m ;get char from queue\r | |
936 | ori 0ffh ;set NZ\r | |
937 | mov a,e\r | |
938 | jmp rsi2\r | |
939 | \r | |
940 | ; printer routines\r | |
941 | \r | |
942 | inta: sta ptemp\r | |
943 | mvi a,0\r | |
944 | sta pflag\r | |
945 | lda ptemp\r | |
946 | ei\r | |
947 | db 0EDh,4Dh ;reti\r | |
948 | \r | |
949 | parout: push h\r | |
950 | lxi h,pflag\r | |
951 | par2: db 0CBh,46h ;bit 0,(hl)\r | |
952 | jnz par2\r | |
953 | mvi m,0ffh\r | |
954 | out porta\r | |
955 | pop h\r | |
956 | ret\r | |
957 | \r | |
958 | ; data storage\r | |
959 | \r | |
960 | oldint: db 0 ; storage for old i reg\r | |
961 | trtemp: db 0\r | |
962 | ptemp: db 0 ;temp storage used by inta interrupt\r | |
963 | pflag: db 0 ;0ffh if waiting for printer. 00h if ready\r | |
964 | \r | |
965 | ;receive queue pointers\r | |
966 | maxque equ 2048 ; receiver queue size\r | |
967 | rptr: dw maxque-1\r | |
968 | wptr: dw maxque-1\r | |
969 | \r | |
970 | ;transmit\r | |
971 | ndata equ 8 ; 8 data bits\r | |
972 | nstrt equ 1 ; 1 start bit\r | |
973 | nstop equ 1 ; 1 stop bit\r | |
974 | ntotal equ nstrt+ndata+nstop\r | |
975 | rqbit equ 4*(nstrt+ndata) ;number of quarter bits to receive\r | |
976 | tqbit equ 4*(nstrt+ndata+nstop) ;number of quarter bits to transmit\r | |
977 | tqfudge equ 13-nstrt-ndata\r | |
978 | \r | |
979 | ;H=0 or L=0 behave as 256\r | |
980 | ;receive delays.\r | |
981 | fulldel: dw 0 ; 3584(H-1) + 14H + 14L + 67 cycles\r | |
982 | semidel: dw 0 ; 3584(H-1) + 14H + 14L + 125 cycles\r | |
983 | ;1/4 bit transmit and simultaneous tx/rx delay 34H + 14L + 223 cycles\r | |
984 | ;or full bit delay 3584(H-1) + 14H + 14L + 74 cycles\r | |
985 | txrxdel: dw 0 ;\r | |
986 | txcall: dw trout ; address of subroutine to transmit char\r | |
987 | \r | |
988 | ; receiver queue\r | |
989 | rqueue: ds maxque\r | |
990 | \r | |
991 | \r | |
992 | ovlend equ $ ; End of overlay\r | |
993 | \r | |
994 | IF lasm\r | |
995 | END\r | |
996 | ENDIF\r |