]> cloudbase.mooo.com Git - kermit-80.git/blame - cpxpcw.asm
Add AVR-CP/M system (cpxac.asm) and a Makefile
[kermit-80.git] / cpxpcw.asm
CommitLineData
e58a7a25
L
1IF NOT lasm\r
2.printx * CPXPCW.ASM *\r
3ENDIF ;NOT lasm\r
4;\r
5; KERMIT - (Celtic for "FREE")\r
6;\r
7; This is the CP/M-80 implementation of the Columbia University\r
8; KERMIT file transfer protocol.\r
9;\r
10; Version 4.08\r
11;\r
12; Copyright June 1981,1982,1983,1984,1985\r
13; Columbia University\r
14;\r
15; Originally written by Bill Catchings of the Columbia University Center for\r
16; Computing Activities, 612 W. 115th St., New York, NY 10025.\r
17;\r
18; This file contains the system-dependent code and data for KERMIT\r
19; on the Amstrad range of personal computers.\r
20;\r
21;\r
22; Revision history:\r
23;\r
24;edit 9, 22-Jan-1991 by MF. Added "sysinit" code at "init04" from Kermit\r
25; version 4.08 which had been left out of version 4.09 to reserve\r
26; space for the Amstrad's I/O buffers. Amstrad Kermit now stores\r
27; files correctly (version 4.09 had garbled files). Again,\r
28; this fix comes from Mr. D. P. Arnot of the Scottish Agricultural\r
29; College in the UK.\r
30;edit 8, 16-Jan-1991 by MF. Added a "bs" left out of "delstr" per\r
31; instruction from David P. Arnot of Scottish Agricultural\r
32; College, Auchincruive, Ayr, UK.\r
33; E-mail: <D.P.Arnot@edinburgh.ac.uk>\r
34; edit 7, 22 July 1987 by OBSchou to massage code to fit with CPXCOM.ASM\r
35; Had to rename bcnout to bcnot as the former label clashed with\r
36; one of the same name in CPXCOM.ASM. Sorry, folks.\r
37;\r
38; edit 6, 14th July, 1987 by OBSchou for Phillip Wade, Hull University\r
39; Computer Centre. Change to delchr routine for PCW machines, \r
40; as character 127 decimal is a printing character on \r
41; the Amstrad PCW. The routine has been replaced \r
42; by a bs,space,bs,bs string. (OBS Comment - why a total of THREE bs?)\r
43;\r
44; edit 5 9 May 1987 by C.J.MILES@UK.AC.UMRCC\r
45; Hangup phone and clear screen options added to\r
46; terminal mode.\r
47;\r
48; edit 4 23 March 1987 by C.J.MILES@UK.AC.UMRCC\r
49; Use direct input drom SIO for CPC machines instead\r
50; of using BDOS. Improvement reduces time for file\r
51; transfer to 65% of time used by BDOS method.\r
52; Add reverse Prestel baud rate.\r
53;\r
54; edit 3 20 March 1987 by Chris Miles (C.J.MILES@UK.AC.UMRCC)\r
55; (Greater Manchester Archaeological Unit, Manchester Univ.).\r
56; Added support for Amstrad CPC CP/M Plus machines,\r
57; Added 31250 baud rate option,\r
58; Bug fixed in sending BREAK,\r
59; Bug fixed in 1200/75 baud setup\r
60; Machine and CP/M version checks added.\r
61;\r
62; edit 2 11 Febuary, 1987 by OBSchou for Ian Young.\r
63; Changes to the send break routine to change two lines of code from\r
64; ori 018h ; send break, Tx enable\r
65; and ori 0008h ; Tx enable \r
66;\r
67; to ori 01ah ; send break, Tx enable, RTS\r
68; and ori 00ah ; Tx enable, RTS\r
69;\r
70; This is a bug fix to hopefully keep RTS actve during breaks.\r
71;\r
72; [Ed. (OBSchou) 21/1/87.\r
73; This file linked FROM cpxsys.asm, so do NOT rename this\r
74; file. The diffculty of needing a HUGE CPXSYS.ASM file on your floppy\r
75; only to act as a switcher remains, but hopefully will be better in \r
76; the future. If you ARE stuck, then rename this CPXSYS.ASM but add the\r
77; label SYSEDT: to the FAMILY label. A bit messy.]\r
78;\r
79;\r
80; The "author" of this system-dependent file is:\r
81;\r
82; Ian A. Young\r
83; Lattice Logic Ltd\r
84; 9 Wemyss Place\r
85; Edinburgh\r
86;\r
87; Some other addresses:\r
88;\r
89; ian@latlog.uucp\r
90; ...seismo!mcvax!ukc!latlog!ian\r
91; or c/o OBSchou@uk.ac.lut.multics\r
92;\r
93; ... although much of the code concerned was written by others.\r
94;\r
95\r
96\r
97; Keep module name, edit number, and last revision date in memory.\r
98\r
99;sysedt: db 'CPXSYS.ASM (36) 20-Mar-87$'\r
100family: db 'CPXPCW.ASM (9) 22-Jan-1991$'\r
101\r
102\r
103;\r
104; Assembly-time message announcing which version we are building\r
105;\r
106\r
107IF pcw\r
108.printx * Assembling Amstrad PCW Kermit-80 *\r
109ENDIF\r
110\r
111IF cpc\r
112.printx * Assembling Amstrad CPC Kermit-80 *\r
113ENDIF\r
114\r
115;\r
116; Miscellany of parameter settings\r
117;\r
118z80 EQU TRUE ; all Amstrads have a Z80.\r
119defesc EQU '\'-100O ; The default escape character.\r
120vtval EQU 0 ; we don't need VT52 emulation\r
121\r
122;\r
123; Amstrad CPC machines use 16 bit I/O address decoding and therefore\r
124; the Z80 instructions OUT (C),A and IN A,(C) must be defined.\r
125;\r
126outc EQU 79edh ; IN A,(C)\r
127inpc EQU 78edh ; OUT (C),A\r
128\r
129;\r
130; hardware information\r
131;\r
132; There is a Z80-DART (Mostek/SGS 8470) at I/O addresses E0..E3 (PCW)\r
133; and FADC..FADD (CPC), and a 8253 programmable divider running it at\r
134; E4..E7 (PCW) and FBDC..FBDF (CPC)\r
135;\r
136\r
137input EQU 01h ; input data available\r
138output EQU 04h ; output buffer ready\r
139\r
140IF pcw\r
141mnport EQU 0E0h ; data register for SIO\r
142mnprts EQU 0E1h ; control register for SIO\r
143ctc0 EQU 0E4h ; 8253 load counter 0\r
144ctc1 EQU 0E5h ; 8253 load counter 1\r
145ctcmod EQU 0E7h ; 8253 write mode word\r
146ENDIF\r
147\r
148IF cpc\r
149mnport EQU 0FADCh ; data register for SIO\r
150mnprts EQU 0FADDh ; control register for SIO\r
151ctc0 EQU 0FBDCh ; 8253 load counter 0\r
152ctc1 EQU 0FBDDh ; 8253 load counter 1\r
153ctcmod EQU 0FBDFh ; 8253 write mode word\r
154ENDIF\r
155\r
156;\r
157; SIO input buffering\r
158;\r
159siosz EQU 4096 ; size of SIO input buffer\r
160siomsk EQU 4095 ; mask for wrapping buffer round\r
161\r
162;\r
163; Extended BIOS jump-block addresses; reached through USERF\r
164;\r
165sainit EQU 00B6h ; initialise SIO\r
166sabaud EQU 00B9h ; set baud rate\r
167saparm EQU 00BCh ; fetch SIO parameters\r
168teask EQU 00BFh ; find out cursor position\r
169cdvers EQU 00E3h ; get version numbers\r
170cdinfo EQU 00E6h ; get BIOS system information\r
171\r
172;\r
173; System-dependent initialization\r
174; Called once at program start.\r
175sysxin: ; continuation of system initialzation \r
176;\r
177; check for correct CP/M version\r
178;\r
179 mvi c,12 ; get CP/M version BDOS call\r
180 call bdos\r
181 mov a,l ; check if CP/M Plus\r
182 cpi 31h\r
183 jz init08\r
184 lxi d,wrong2 ; point to error message\r
185 call prtstr\r
186 mvi c,0 ; warm boot\r
187 call bdos\r
188;\r
189init08: ;[OBS] Moved the Cinfigured for message out as\r
190 ;[OBS] it is in CPXCOM.ASM\r
191;\r
192; get addresses of BIOS routines\r
193;\r
194; BIOS USERF is used to get to extended BIOS routines\r
195;\r
196 lhld 1 ; warm boot vector\r
197 lxi d,87 ; offset to USERF vector\r
198 dad d ; DE now has USERF vector address\r
199 shld userf+1 ; ready for jumping to...\r
200;\r
201; BIOS routines for fast character I/O\r
202;\r
203 lhld 1 ; warm boot vector (#1)\r
204 lxi d,3\r
205 dad d ; next is #2, CONST\r
206 shld bcnst+1\r
207 dad d ; next is #3, CONIN\r
208 shld bcnin+1\r
209 dad d ; next is #4, CONOUT\r
210 shld bcnot+1 ;[obs] Was bcnout, but this conflicts\r
211 ;[obs] with a label in CPXCOM.ASM\r
212 dad d ; next is #5, LIST\r
213 shld blist+1\r
214 dad d ; next is #6, AUXOUT\r
215 dad d ; next is #7, AUXIN\r
216 shld baxin+1\r
217 lhld 1 ; warm boot vector again\r
218 lxi d,002Ah ; offset to LISTST (#15)\r
219 dad d\r
220 shld lptstat+1\r
221 lhld 1 ; warm boot vector again\r
222 lxi d,0033h ; offset to AUXIST (#18)\r
223 dad d\r
224 shld baxist+1\r
225;\r
226; check if running on correct Amstrad\r
227;\r
228 call userf\r
229 dw cdvers\r
230IF pcw\r
231 cpi 0\r
232ENDIF\r
233IF cpc\r
234 cpi 1\r
235ENDIF\r
236 jnz init06\r
237 lxi d,wrong1 ; point to error message\r
238 call prtstr\r
239 mvi c,0\r
240 call bdos\r
241;\r
242; verify presence of SIO board by asking the BIOS.\r
243;\r
244init06: call userf ; C gets 00 if not fitted\r
245 dw cdinfo\r
246 xra a ; a <- 0\r
247 ora c ; zero => no serial port\r
248 jnz init03 ; non-zero => OK\r
249 lxi d,nosio ; snooty message...\r
250 call prtstr\r
251 mvi c,0 ; warm boot out of here\r
252 call bdos\r
253init03:\r
254;\r
255; find initial baud rate and other information\r
256;\r
257 call userf ; gives B=rx baud, C=tx baud, D=stop bits,\r
258 ; E=parity, H=rx bits, L=tx bits.\r
259 dw saparm ; get SIO parameters\r
260 push h ; save bit settings\r
261 mov a,b ; if TX and RX speeds same, they are OK\r
262 cmp c\r
263 jz init01\r
264 cpi 8 ; rx=1200?\r
265 jnz init02 ; no, can't be Prestel\r
266 mov a,c\r
267 cpi 2 ; tx=75?\r
268 jnz init02 ; no, can't be Prestel\r
269 lxi b,0 ; otherwise 1200/75 comes out as 0s.\r
270init01: push b ; assign value to SPEED\r
271 pop h\r
272 shld speed\r
273init02: ; here if we leave it as is\r
274 pop h ; get bit settings\r
275 mov a,l ; no of TX data bits set\r
276 sui 5 ; make into 00, 01, 10, 11.\r
277 rrc\r
278 rrc\r
279 rrc\r
280 sta txbits ; we may need it later\r
281;\r
282; set handshake mode: there are two parts to this, interrupts and\r
283; hardware handshake. The MODE byte used by the firmware expresses\r
284; this combination as -(int*2 + hand*1). Thus, both options on would\r
285; be (-3) or 0FDh.\r
286;\r
287; Here, we set the interrupt part of the mode on; it helps the BIOS cope.\r
288; Unfortunately, >sigh<, according to Soft971, this will only work\r
289; if you have BIOS V1.4 or higher. I have no idea what would happen\r
290; if we tried random hanshake mode flags with lower versions, so we\r
291; just skip over if it would be dangerous...\r
292;\r
293 call userf ; fetch all parameters\r
294 dw saparm\r
295 sta orgmode ; remember original mode for later\r
296\r
297 call userf ; get BIOS version to B,C\r
298 dw cdvers\r
299 mov a,b ; BIOS major version number (eg 1)\r
300 ora a ; if zero, too low...\r
301 jz init04\r
302 cpi 1 ; if not 1, definitely OK\r
303 jnz init05\r
304 mov a,c ; otherwise, its 1.X; want >= 4\r
305 cpi 4\r
306 jm init04 ; <4 => too low\r
307\r
308init05: call userf ; get the original flags back\r
309 dw saparm\r
310 xri 0FFh ; make mode into bit mask\r
311 inr a\r
312 ori 2 ; set interrupt mode\r
313 xri 0FFh ; turn back into mode value\r
314 inr a\r
315 call userf ; feed change back to BIOS\r
316 dw sainit\r
317init04: ; come here if not setting mode\r
318\r
319; Locate large buffers for multi-sector I/O and SIO input buffering.\r
320; Space above ovlend is available for buffers; we have pretty well the machine\r
321; to ourselves in an Amstrad PCW because they all gave 61K TPAs. We don't even\r
322; bother to perform any checking.\r
323; We don't want to use more than maxsec for disk buffers because\r
324; if we use too many, the remote end could time out while we're\r
325; writing to disk. maxsec is system-dependent, but for now we'll just\r
326; use 8Kbytes. If you get retransmissions and other protocol errors after\r
327; transferring the first maxsec sectors, lower maxsec.\r
328;\r
329maxsec EQU (8*1024)/bufsiz ; 8K / number of bytes per sector\r
330\r
331 lxi h,ovlend+siosz ; get start of buffer\r
332 shld bufadr ; store in linkage section\r
333 mvi a,maxsec ; get size of buffer, in sectors\r
334 sta bufsec ; store that, too.\r
335\r
336\r
337 ret ; return from system-dependent routine\r
338\r
339;\r
340; message complaining about wrong Amstrad machine\r
341;\r
342wrong1: db 'Error - This Kermit will only run on the Amstrad '\r
343IF pcw\r
344 db 'PCW 8256/8512'\r
345ENDIF\r
346IF cpc\r
347 db 'CPC 464/664/6128'\r
348ENDIF\r
349 db cr,lf,'$'\r
350;\r
351; message complaining about version of CP/M being used\r
352;\r
353wrong2: db 'Error - Incorrect CP/M version, needs CP/M 3.x'\r
354 db cr,lf,'$' \r
355;\r
356; message complaining of no SIO board\r
357;\r
358nosio: db 'Error - No SIO option fitted to this machine'\r
359 db cr, lf, '$'\r
360\r
361;\r
362; jumps to BIOS character I/O routines.\r
363; Addresses filled in by initialisation code above.\r
364;\r
365bcnst: jmp $-$ ; console status\r
366bcnin: jmp $-$ ; console input\r
367bcnot: jmp $-$ ; console output [obs - was bcnout]\r
368blist: jmp $-$ ; printer output\r
369baxin: jmp $-$ ; aux port input\r
370baxist: jmp $-$ ; aux port status\r
371lptstat:jmp $-$ ; printer status\r
372\r
373;\r
374; Other BIOS routines\r
375;\r
376userf: jmp $-$ ; call extended BIOS function\r
377\r
378;\r
379; saved value of some original parameters\r
380;\r
381orgmode:ds 1\r
382txbits: ds 1\r
383\r
384;\r
385; system-dependent termination processing\r
386; If we've changed anything, this is our last chance to put it back.\r
387sysexit:\r
388 call userf ; fetch firmware parameters\r
389 dw saparm\r
390 lda orgmode ; replace with original mode\r
391 call userf ; inform BIOS\r
392 dw sainit\r
393 ret\r
394\r
395;\r
396; system-dependent processing for start of CONNECT command\r
397;\r
398syscon:\r
399 lxi d,conmsg ; how to get escape char message\r
400 call prtstr\r
401 ret\r
402\r
403conmsg: ; Messages printed when entering transparent (CONNECT) mode:\r
404IF pcw\r
405 db '(Use boxed minus key next to space bar to generate a Control-\)'\r
406ENDIF\r
407 db cr,lf,'$'\r
408\r
409;\r
410; syscls - system-dependent close routine\r
411; called when exiting transparent session.\r
412;\r
413syscls:\r
414 ret\r
415\r
416;\r
417; sysinh - help for system-dependent special functions.\r
418; called in response to <escape>?, after listing all the\r
419; system-independent escape sequences.\r
420;\r
421sysinh:\r
422 lxi d,inhlps ; we got options...\r
423 call prtstr ; print them.\r
424 ret\r
425\r
426;\r
427; additional, system-dependent help for transparent mode\r
428; (two-character escape sequences)\r
429;\r
430inhlps:\r
431 db cr,lf,'B Transmit a BREAK'\r
432 db cr,lf,'H Hangup using DTR'\r
433 db cr,lf,'W Wipe screen clear'\r
434 db '$' ;[hh] table terminator\r
435\r
436;\r
437; sysint - system dependent special functions\r
438; called when transparent escape character has been typed;\r
439; the second character of the sequence is in A (and in B).\r
440; returns:\r
441; non-skip: sequence has been processed\r
442; skip : sequence was not recognized\r
443;\r
444sysint: ani 137O ; convert lower case to upper, for testing...\r
445 cpi 'B' ; send break ?\r
446 jz sendbr ; yes, go do it. return nonskip when through.\r
447 cpi 'H' ; hang up ?\r
448 jz hangup\r
449 cpi 'W' ; clear screen ?\r
450 jz clrtop\r
451 jmp rskp ; take skip return - command not recognized.\r
452\r
453;\r
454; Hangup (drop DTR) and Break send routine\r
455;\r
456\r
457hangup:\r
458 mvi d,0ah ; set up hangup bit mask\r
459 mvi e,255 ; time for hangup is 2 1/2 secs\r
460 jmp setbit ; skip Tx empty test\r
461\r
462sendbr:\r
463 mvi d,9ah ; set up break bit mask\r
464 mvi e,30 ; time for break is 300 ms\r
465\r
466sndbr1: mvi a,1 ; select Read Register 1\r
467\r
468IF pcw ; allow 8 bit I/O instructions\r
469 out mnprts\r
470 in mnprts ; read the contents\r
471ENDIF\r
472\r
473IF cpc ; use 16 bit I/O instructions\r
474 lxi b,mnprts\r
475 dw outc ; OUT (C),A\r
476 dw inpc ; IN A,(C)\r
477ENDIF\r
478\r
479 ani 1 ; test "all done" flag\r
480 jz sndbr1 ; loop until it's nonzero.\r
481;\r
482; Next, set the break or hangup bit on the SIO.\r
483;\r
484setbit:\r
485 mvi a,5 ; select Write Register 5\r
486IF pcw\r
487 out mnprts\r
488ENDIF\r
489IF cpc\r
490 dw outc ; OUT (C),A\r
491ENDIF\r
492 lda txbits ; get txbits (already in correct bit positions)\r
493 ora d ; send break, Tx Enable, RTS\r
494IF pcw\r
495 out mnprts\r
496ENDIF\r
497IF cpc\r
498 dw outc ; OUT (C),A\r
499ENDIF\r
500\r
501;\r
502; Now, delay for duration of hangup or break\r
503;\r
504 mov a,e ; delay count\r
505 call delay\r
506;\r
507; Time's up. Put transmitter back in normal state and return.\r
508;\r
509 mvi a,5 ; select Write Register 5\r
510IF pcw\r
511 out mnprts\r
512ENDIF\r
513IF cpc\r
514 lxi b,mnprts\r
515 dw outc ; OUT (C),A\r
516ENDIF\r
517 lda txbits ; get txbits again\r
518 ori 8ah ; Reset break, Tx Enable, RTS\r
519IF pcw\r
520 out mnprts\r
521ENDIF\r
522IF cpc \r
523 dw outc ; OUT (C),A\r
524ENDIF\r
525 ret ; done.\r
526\r
527;\r
528; sysflt - system-dependent filter\r
529; called with character in E.\r
530; if this character should not be printed, return with A = zero.\r
531; preserves bc, de, hl.\r
532; note: <xon>,<xoff>,<del>, and <nul> are always discarded.\r
533;\r
534sysflt:\r
535 mov a,e ; get character for testing\r
536 ret\r
537;\r
538; system-dependent processing for BYE command.\r
539;\r
540sysbye:\r
541 ret\r
542\r
543;\r
544; This is the system-dependent command to change the baud rate.\r
545; DE contains the two-byte value from the baud rate table; this\r
546; value is also stored in 'speed'.\r
547;\r
548sysspd:\r
549 push d ; move to HL for firmware\r
550 pop h\r
551 mov a,h ; if h=0 then Prestel rates\r
552 ora a\r
553 jnz spd01 ; if not 1200/75 then skip\r
554 lxi h,0802H ; else set 1200/75 into HL\r
555 jmp spd03 ; jump to normal setup\r
556\r
557spd01: cpi 11h ; if h=11h then reverse Prestel\r
558 jnz spd02 ; if not 75/1200 then skip\r
559 lxi h,0208h ; else set 75/1200 into HL\r
560 jmp spd03 ; jump to normal setup\r
561\r
562spd02: cpi 10h ; if h=10h then 31250 baud\r
563 jnz spd03 ; if not 31250 then skip to normal setup\r
564 mvi a,36h ; set 8253 for mode 2 binary count\r
565 lxi b,ctcmod ; output to CTC mode register\r
566 dw outc\r
567 lxi b,ctc0 ; select transmit clock\r
568 mov a,4 ; timer value for 31250 (04h)\r
569 dw outc\r
570 mov a,0 ; timer value for 31250 (04h)\r
571 dw outc\r
572 lxi b,ctc0 ; select receive clock\r
573 mov a,4 ; timer value for 31250 (04h)\r
574 dw outc\r
575 mov a,0 ; timer value for 31250 (04h)\r
576 dw outc\r
577 ret\r
578\r
579spd03: call userf ; set whatever we have now...\r
580 dw sabaud ; using BIOS routine\r
581 ret\r
582\r
583;\r
584; Speed tables\r
585; (Note that speed tables MUST be in alphabetical order for later\r
586; lookup procedures, and must begin with a value showing the total\r
587; number of entries. The speed help tables are just for us poor\r
588; humans.\r
589;\r
590; db string length,string,divisor (2 identical bytes or 1 word)\r
591;\r
592spdtbl: db 12h ;18 entries\r
593 db 03h,'110$', 03h,03h\r
594 db 04h,'1200$', 08h,08h\r
595 db 07h,'1200/75$', 00h,00h ; real values faked up when required\r
596 db 05h,'134.5$', 04h,04h\r
597 db 03h,'150$', 05h,05h\r
598 db 04h,'1800$', 09h,09h\r
599 db 05h,'19200$', 0fh,0fh\r
600 db 04h,'2400$', 0ah,0ah\r
601 db 03h,'300$', 06h,06h\r
602 db 05h,'31250$',10h,10h ; flag to direct setup routine\r
603 db 04h,'3600$', 0bh,0bh\r
604 db 04h,'4800$', 0ch,0ch\r
605 db 02h,'50$', 01h,01h\r
606 db 03h,'600$', 07h,07h\r
607 db 04h,'7200$', 0dh,0dh\r
608 db 02h,'75$', 02h,02h\r
609 db 07h,'75/1200$',11h,11h ; real values faked up when required\r
610 db 04h,'9600$', 0eh,0eh\r
611\r
612sphtbl: db cr,lf,lf\r
613 db 'Normal rates: 50 75 110 134.5 150 300 600'\r
614 db cr,lf\r
615 db ' 1200 1800 2400 3600 4800 7200 9600 19200'\r
616 db cr,lf,lf\r
617 db 'High speed : 31250 (only between Amstrads)'\r
618 db cr,lf,lf\r
619 db 'Split rates : 1200/75 (Rx=1200, Tx= 75)'\r
620 db cr,lf\r
621 db ' 75/1200 (Rx= 75, Tx=1200)'\r
622 db cr,lf,'$'\r
623\r
624;\r
625; This is the system-dependent SET PORT command.\r
626; HL contains the argument from the command table.\r
627;\r
628sysprt:\r
629 ret\r
630\r
631prttbl equ 0 ; SET PORT is not supported\r
632prhtbl equ 0\r
633\r
634;\r
635; selmdm - select modem port\r
636; selcon - select console port\r
637; selmdm is called before using inpmdm or outmdm;\r
638; selcon is called before using inpcon or outcon.\r
639; preserves bc, de, hl.\r
640;\r
641selmdm:\r
642selcon:\r
643 ret\r
644\r
645;\r
646; Get character from console, or return zero.\r
647; result is returned in A. destroys bc, de, hl.\r
648;\r
649inpcon:\r
650 call bcnst ; get console status\r
651 ora a ; anything there?\r
652 rz ; no, forget it\r
653 jmp bcnin ; yes, get the character\r
654\r
655;\r
656; Output character in E to the console.\r
657; destroys bc, de, hl\r
658;\r
659outcon:\r
660 mov a,e ; TAB?\r
661 cpi tab\r
662 jz out001\r
663 mov c,e ; set correct arg register\r
664 jmp bcnot ; output to console via BIOS [obs was bcnout]\r
665\r
666;\r
667; perform tab expansion ourselves\r
668;\r
669out001: call userf ; get column in L\r
670 dw teask\r
671 mov a,l ; a <- column 0..n\r
672 ani 7 ; column 0..7\r
673 xri 0FFh ; not(col 0..7)\r
674 adi 9 ; a is 8-(colf7)\r
675out002: ora a ; any left?\r
676 rz ; return if not\r
677 dcr a ; one less now, anyhow\r
678 push psw ; save over BIOS call (just in case)\r
679 mvi c,' ' ; print one space\r
680 call bcnot ;[obs was bcnout]\r
681 call suck ; in case any stuff coming in\r
682 pop psw ; fetch count back\r
683 jmp out002 ; and go round again\r
684\r
685;\r
686; outmdm - output a char from E to the modem.\r
687; the parity bit has been set as necessary.\r
688; returns nonskip; bc, de, hl preserved.\r
689outmdm:\r
690IF cpc\r
691 push b ; save BC for CPC 16 bit I/O\r
692ENDIF\r
693outmd1:\r
694 call xsuck ; keep checking for incoming characters\r
695IF pcw\r
696 in mnprts ; get the output done flag.\r
697ENDIF\r
698IF cpc\r
699 lxi b,mnprts\r
700 dw inpc ; IN A,(C)\r
701ENDIF\r
702 ani output ; is it set?\r
703 jz outmd1 ; if not, loop until it is.\r
704 mov a,e\r
705IF pcw\r
706 out mnport ; output it.\r
707ENDIF\r
708IF cpc\r
709 lxi b,mnport\r
710 dw outc ; OUT (C),A\r
711 pop b ; restore BC\r
712ENDIF\r
713 ret\r
714\r
715;\r
716; get character from modem; return zero if none available.\r
717; destroys bc, de, hl.\r
718;\r
719inpmdm:\r
720 call suck ; get any characters pending\r
721 lhld sioct ; count of chars in buffer\r
722 mov a,h ; or together to get result\r
723 ora l\r
724 rz ; not got any, return now\r
725\r
726 dcx h ; down count\r
727 shld sioct\r
728\r
729 lhld siord ; read pointer\r
730 mov c,m ; fetch character ** NB TO C FOR NOW **\r
731\r
732 lxi d,1-ovlend ; bump pointer, subtract base\r
733 dad d\r
734 mov a,h ; mask high byte of offset\r
735 ani siomsk/256\r
736 mov h,a\r
737 lxi d,ovlend ; add in base again\r
738 dad d\r
739 shld siord\r
740\r
741 mov a,c ; get to proper register\r
742 ret\r
743\r
744;\r
745; flsmdm - flush comm line.\r
746; Modem is selected.\r
747; Currently, just gets characters until none are available.\r
748\r
749flsmdm: call inpmdm ; Try to get a character\r
750 ora a ; Got one?\r
751 jnz flsmdm ; If so, try for another\r
752 ret ; Receiver is drained. Return.\r
753\r
754;\r
755; SIO input buffer handling. The buffer pointers are held as pointers into\r
756; the buffer. The read pointer\r
757; is to the next unused character, the write pointer to the next unused space.\r
758;\r
759siord: dw ovlend ; next char to read\r
760siowr: dw ovlend ; next char to write\r
761sioct: dw 0 ; number in buffer\r
762\r
763xsuck: push d ; save regs version of suck\r
764 push b\r
765 push h\r
766 call suck\r
767 pop h\r
768 pop b\r
769 pop d\r
770 ret\r
771\r
772;\r
773; suck\r
774;\r
775; this routine is called whenever it would be possible that some\r
776; characters might be available in the SIO device; they are all\r
777; transferred (there may be up to 4 pending) to the buffer.\r
778;\r
779; all registers are destroyed\r
780;\r
781suck:\r
782IF pcw\r
783 call baxist ; check input status via BDOS\r
784 ora a ; check if zero\r
785ENDIF\r
786IF cpc\r
787 lxi b,mnprts ; get input status directly\r
788 dw inpc ; IN A,(C)\r
789 ani input ; mask for Rx ready\r
790ENDIF\r
791 rz ; return if no\r
792\r
793IF pcw\r
794 call baxin ; fetch character via BDOS\r
795ENDIF\r
796IF cpc\r
797 lxi b,mnport ; fetch character directly from SIO\r
798 dw inpc ; IN A,(C)\r
799ENDIF\r
800\r
801 lhld siowr ; write pointer\r
802 mov m,a ; put character\r
803\r
804 lxi d,1-ovlend ; take off base, bump pointer\r
805 dad d\r
806 mov a,h ; top byte of offset\r
807 ani siomsk/256 ; masked off\r
808 mov h,a\r
809 lxi d,ovlend ; add on base again\r
810 dad d\r
811 shld siowr ; replace pointer\r
812\r
813 lhld sioct ; bump count in buffer\r
814 inx h\r
815 shld sioct\r
816\r
817 jmp suck ; go round in case any more\r
818\r
819;\r
820; outlpt - output character in E to printer\r
821; console is selected.\r
822; preserves de.\r
823outlpt:\r
824 push d ; save DE in either case\r
825 mov c,e ; correct arg register\r
826 call blist\r
827 pop d ; restore saved register pair\r
828 ret\r
829\r
830;\r
831; Screen manipulation routines\r
832; csrpos - move to row B, column C\r
833;\r
834; csrpos for terminals that use a leadin sequence followed\r
835; by (row + 31.) and (column + 31.)\r
836; or (row) and (column)\r
837;\r
838csrpos: push b ; save coordinates\r
839 lxi d,curldn ; get cursor leadin sequence\r
840 call prtstr ; print it\r
841 pop h ; restore coordinates\r
842 mov a,h ; get row\r
843 adi (' '-1) ; space is row one\r
844 mov e,a\r
845 push h\r
846 call outcon ; output row\r
847 pop h\r
848 mov a,l ; get column\r
849 adi (' '-1) ; space is column one\r
850 mov e,a\r
851 jmp outcon ; output it and return\r
852\r
853;\r
854; delchr - make delete look like a backspace. Unless delete is a printing\r
855; character, we just need to print a backspace. (we'll output clrspc\r
856; afterwards)\r
857; For Kaypro and Vector General, delete puts a blotch on the screen.\r
858; For Apple and Osborne 1, delete moves but doesn't print.\r
859delchr:\r
860IF pcw ;[6] OBS for Phillip Wade\r
861 lxi d,delstr ;[5] send a string rather than a single character\r
862 call prtstr\r
863\r
864delstr: db bs,' ',bs,'$' ;[OBS] Was bs,space,bs,bs\r
865ENDIF ;pcw\r
866\r
867 mvi e,bs ;get a backspace\r
868 jmp outcon\r
869\r
870; erase the character at the current cursor position\r
871clrspc: mvi e,' '\r
872 call outcon\r
873 mvi e,bs ;get a backspace\r
874 jmp outcon\r
875\r
876; erase the current line\r
877clrlin: lxi d,eralin\r
878 jmp prtstr\r
879\r
880; erase the whole screen, and go home. preserves b (but not c)\r
881clrtop: lxi d,erascr\r
882 jmp prtstr\r
883\r
884\r
885IF pcw\r
886sysver: db 'Amstrad PCW with SIO option$'\r
887ENDIF\r
888IF cpc\r
889sysver: db 'Amstrad CPC with CP/M Plus$'\r
890ENDIF\r
891\r
892outlin: db esc,'H',esc,'J',cr,lf,' $'\r
893\r
894erascr: db esc,'H',esc,'J$' ;Clear screen and go home.\r
895eralin: db cr,esc,'K$' ;Clear line.\r
896curldn: db esc,'Y$' ;cursor leadin\r
897ttab: ;Table start location.\r
898ta: db esc,'A$',0 ;Cursor up.\r
899tb: db esc,'B$',0 ;Cursor down.\r
900tc: db esc,'C$',0 ;Cursor right.\r
901td: db esc,'D$',0 ;Cursor left\r
902te: db esc,'E$',0 ;Clear display\r
903tf: db '$',0,0,0 ;Enter Graphics Mode\r
904tg: db '$',0,0,0 ;Exit Graphics mode\r
905th: db esc,'H$',0 ;Cursor home.\r
906ti: db esc,'I$',0 ;Reverse linefeed.\r
907tj: db esc,'J$',0 ;Clear to end of screen.\r
908tk: db esc,'K$',0 ;Clear to end of line.\r
909\r
910ovlend equ $ ; End of overlay\r
911\r
912 END\r