]> cloudbase.mooo.com Git - kermit-80.git/blame - cpxbee.asm
Bugfix in outmdm (output buffer flush)
[kermit-80.git] / cpxbee.asm
CommitLineData
e58a7a25
L
1IF NOT lasm\r
2.printx * CPXBEE.ASM *\r
3ENDIF ;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
58sysedt: db 'CPXSYS.ASM (35) 01-Dec-86$'\r
59family: 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
66z80 EQU TRUE ; They all use Z80s\r
67\r
68defesc EQU ']'-100O ;The default escape character for Microbee\r
69\r
70vtval EQU 0 ; use default emulation which is adm3a superset\r
71\r
72;\r
73sysxin: ;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
92sysexit:\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
101syscon:\r
102 lxi d,conmsg\r
103 call prtstr\r
104 ret\r
105\r
106conmsg: ; 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
112syscls:\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
119sysinh:\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
127inhlps:\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
140sysint: 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
152longbr:\r
153 mvi e,180 ; time for long break is 1800 ms\r
154 jmp setbit\r
155\r
156sendbr:\r
157 mvi e,30 ; time for break is 300 ms\r
158\r
159setbit: \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
180sysflt:\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
187sysbye:\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
195sysspd:\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
209spdtbl: 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
233sphtbl: 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
239sysprt:\r
240 ret\r
241\r
242prttbl equ 0 ; SET PORT is not supported\r
243prhtbl 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
253selmdm:\r
254selcon:\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
260inpcon:\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
270outcon:\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
283outmdm:\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
294outm2: 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
304inpmdm:\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
313flsmdm: 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
320lptstat:\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
328outlpt:\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
334outlp1: 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
346csrpos: 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
365delchr:\r
366 lxi d,delstr\r
367 jmp prtstr\r
368\r
369\r
370; erase the character at the current cursor position\r
371clrspc: 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
377clrlin: lxi d,eralin\r
378 jmp prtstr\r
379\r
380; erase the whole screen, and go home\r
381clrtop: lxi d,erascr\r
382 jmp prtstr\r
383\r
384\r
385sysver: db 'Microbee$'\r
386outlin: db 1AH,cr,lf,tab,'$' ;(Clear screen, home cursor)\r
387erascr: db 1AH,'$' ;Clear screen and go home.\r
388eralin: db cr,esc,'T$' ;Clear line.\r
389delstr: db bs,'$' ; Adjust for delete\r
390curldn: db esc,'=$' ;Cursor lead-in\r
391ttab: ;Table start location.\r
392ta: db ('K'-100O),'$',0,0 ;Cursor up.\r
393tb: db 12O,'$',0,0 ;Cursor down.\r
394tc: db ('L'-100O),'$',0,0 ;Cursor right.\r
395td: db bs,'$',0,0 ;Cursor left.\r
396te: db subt,'$',0,0 ;Clear screen.\r
397tf: db '$',0,0,0 ;(can't) Enter graphics mode\r
398tg: db '$',0,0,0 ;(can't) Exit graphics mode\r
399th: db ('^'-100O),'$',0,0 ;Cursor home.\r
400ti: db ('K'-100O),'$',0,0 ;Reverse linefeed.\r
401tj: db esc,'Y$',0 ;Clear to end of screen.\r
402tk: db esc,'T$',0 ;Clear to end of line.\r
403\r
404\r
405;Microbee software serial port routines\r
406porta equ 0\r
407portb 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
423int 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
556t75: 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
560t7512: db 124,13 ; 75R/1200T\r
561 db 55,7\r
562 db 194,1 ; txout delay\r
563 dw txout\r
564t110: db 129,9\r
565 db 55,5\r
566 db 5,217 \r
567 dw trout\r
568t150: db 59,7\r
569 db 23,4\r
570 db 2,158\r
571 dw trout\r
572t300: db 26,4\r
573 db 134,2\r
574 db 3,75\r
575 dw trout\r
576t600: db 139,2\r
577 db 191,1\r
578 db 2,34\r
579 dw trout\r
580t1200: db 195,1\r
581 db 90,1\r
582 db 3,13\r
583 dw trout\r
584t1275: db 195,1 ; 1200R/75T\r
585 db 90,1\r
586 db 124,13\r
587 dw txout\r
588t2400: db 94,1\r
589 db 40,1\r
590 db 2,3\r
591 dw trout\r
592t4800: db 44,1\r
593 db 15,1\r
594 db 44,1\r
595 dw txout\r
596t9600: 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
603setbaud:\r
604 lxi h,fulldel\r
605 mvi b,8\r
606setb2: 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
617txout: 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
623txout2: mov a,c ; 4T\r
624 jnc txout4 ;10T skip if space\r
625 ori 20h ; 3T (average) set mark\r
626txout4: out portb ;11T\r
627 lhld txrxdel ;16T\r
628txout6: 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
646trout: mov a,e\r
647 mvi b,ndata\r
648 lxi h,0\r
649tro2: 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
660tro10: mvi b,tqfudge ;adjust char in hl to align with\r
661 ;tx bit of portb\r
662tro12: 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
678tro14: 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
691tro16: dcr l\r
692 jnz tro16\r
693 dcr h\r
694 jnz tro16\r
695tro18: 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
703tro20: 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
716tro22: 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
723qbit: call txrx ;17T + 162T\r
724 lda txrxdel ;13T\r
725qbit2: dcr a ; 4T\r
726 jnz qbit2 ;10T\r
727 lda txrxdel+1 ;13T\r
728qbit4: 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
749txrx: 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
759txrx2: dcr d ; 4T one less qtr bit to send\r
760 ;76T total\r
761;now receive part\r
762txrx4: 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
773txrx6: dcr e ; 4T one less qtr bit to receive\r
774txrx8: 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
779txrx10:\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
790txrx12: 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
806txrx14: 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
815txrx16: 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
824txrx18: 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
837intb: ;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
847intb2: 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
854intb4: lhld fulldel ;16T full bit delay\r
855intb6: 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
872intb10: dcr l\r
873 jnz intb10\r
874 dcr h\r
875 jnz intb10\r
876intb12: 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
884intb14: 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
897intb16: 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
907rsin: 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
920rsi2: pop h\r
921 pop d\r
922 ret\r
923\r
924rsi4: 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
930rsi6: 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
942inta: 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
949parout: push h\r
950 lxi h,pflag\r
951par2: 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
960oldint: db 0 ; storage for old i reg\r
961trtemp: db 0\r
962ptemp: db 0 ;temp storage used by inta interrupt\r
963pflag: db 0 ;0ffh if waiting for printer. 00h if ready\r
964\r
965;receive queue pointers\r
966maxque equ 2048 ; receiver queue size\r
967rptr: dw maxque-1\r
968wptr: dw maxque-1\r
969\r
970;transmit\r
971ndata equ 8 ; 8 data bits\r
972nstrt equ 1 ; 1 start bit\r
973nstop equ 1 ; 1 stop bit\r
974ntotal equ nstrt+ndata+nstop\r
975rqbit equ 4*(nstrt+ndata) ;number of quarter bits to receive\r
976tqbit equ 4*(nstrt+ndata+nstop) ;number of quarter bits to transmit\r
977tqfudge equ 13-nstrt-ndata\r
978\r
979;H=0 or L=0 behave as 256\r
980;receive delays.\r
981fulldel: dw 0 ; 3584(H-1) + 14H + 14L + 67 cycles\r
982semidel: 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
985txrxdel: dw 0 ;\r
986txcall: dw trout ; address of subroutine to transmit char\r
987\r
988; receiver queue\r
989rqueue: ds maxque\r
990\r
991\r
992ovlend equ $ ; End of overlay\r
993\r
994IF lasm\r
995 END\r
996ENDIF\r