Back when my only machine was an Amstrad PCW, I used it to take my first tentative steps onto the Internet. Within 24 hours of getting on-line, I realised that the VT100 emulation offered by programs such as COMM+ and QTERM was rather inadequate. Keyboard redefinition was missing, along with attributes like bold and underlining. Instead, these various attributes were all mapped to the single property of inverse video, making the use of programs like the popular text only Web browser Lynx very confusing. Furthermore, otherwise great programs like ZMP are let down by not having any VT100 emulation whatsoever.
And so EMU was born out of my own selfish need to browse the Web. Once I had an acceptable VT100 emulation working, I added support for the ISO-8859-1 character set, the preferred character set of the World Wide Web. The PCW actually already supports most of the Latin 1 characters, it's just that they're ordered differently within the PCW's BIOS, so using a hash table look-up system, I only needed to design 17 new characters.
Here, better late than never, is the source of the program. If you only want a binary version of the program, that's OK, too.
A note for users of QTERM: when making catch files, make sure that you don't use option 'J' to junk control characters, as this will remove important display codes from the catch file.
You can turn the VT100 emulation off and remove EMU from memory at any time by typing EMUOFF [RETURN].
If you use [STOP] to interrupt the display of a file containing VT100 escape codes, you may find that one or more highlighting attributes are still set. It is annoying to have to proceed with a combination of inverse video, bold and underlining, so EMU provides the EMURST command. If you type EMURST [RETURN], all textual emphasis will be turned off.
You may find that the remote system you connect with not only expects you to treat the data it sends you as VT100, but also expects to receive its input from you in VT100 form. This usually manifests itself in the refusal of the cursor keys to do anything useful in a menu on the remote system. Should this prove to be a problem, the EMUKEY command should provide the solution. Note that this will only work in combination with communications software that doesn't use the [EXIT] key for its own purposes. COMM+ and ZMP are examples of such programs, although the former allows an alternative key to be defined for this purpose.
If you use such a program, you will have to redefine the keys externally. The file EMU-B.KEY is provided for this purpose. Your CP/M master disc contains a program called SETKEYS, which you should use to install the keyboard definition file. Simply type SETKEYS EMU-B.KEY [RETURN] and the cursor keys will subsequently send the correct control codes.
Regardless of whether you use the EMUKEY command or the EMU-B.KEY file to redefine the keyboard, you will need to remove EMU from memory to restore the keys to their original state. Should it become necessary to return the keys to their default state whilst using EMU (e.g. because you have finished work on- line and now wish to use EMU off-line), you will first have to remove EMU and then reinstall it.
You should note that the built-in EMUOFF, EMURST and EMUKEY commands
will not work from within a .SUB file or Z-system alias. If you wish
to use any of these commands in a .SUB file or alias, you should
instead use the program EMUSUB. This program takes a single parameter
and has the following syntax:
|EMUSUB /O||send EMUOFF command to EMU|
|EMUSUB /R||send EMURST command to EMU|
|EMUSUB /K||send EMUKEY command to EMU|
EMU works by redirecting the BIOS CONOUT routine to intercept all console output. This is necessary in order to make sure that the screen output of ALL programs is trapped and acted upon. Intercepting at the BDOS level is inadequate, because there can be no guarantee that another program will use the BDOS for its output. Unfortunately, this method has the disadvantage that output redirection can't be acted upon. It is thus impossible to use EMU to make a clean print-out of a file containing VT100 escape codes.
EMU's VT100 emulation isn't complete, but it is the best available for the PCW. Significant features not implemented are:
Although some remote systems attempt to interrogate the calling system
as to its precise specification, a response does not appear to be
essential. The interrogating system simply goes ahead with VT100
EMU's VT100 emulation is based on the specification outlined in the 'Digital VT100 Programming Reference Card'.
Details of the ISO-8859-1 specification were obtained from Martin Ramsch's excellent overview.
Further interesting details on ISO-8859-1 were obtained from the ISO-8859
FAQ by Michael Gschwind.
EMU was written to be compiled with M$'s M80 assembler and linked with the standard Digital Research linker, LINK.COM. GENCOM is also needed to turn the relocatable code into an RSX, or TSR if you come from an M$-DOS background.
FYNDE is a CP/M implementation of UNIX's grep (or, if you prefer, M$-DOS's FIND) and is useful for locating entry points in the code to make sure they tally with the source. You will find it very useful if you intend on modifying the source to EMU.
In short, the following EMU.SUB file will make life somewhat easier when assembling. Note that it must be called EMU.SUB to work.
m80 =$0 link $0 m80 $02,$02=$02 link $02[op] era $02.rsx ren $02.rsx=$02.prl gencom $0 $02 era $0?.rel era $0?.sym fynde $02.prn vtoffx: fynde $02.prn emul: fynde $02.prn conorg:
If you've got any questions about the code, you can drop me a line,
but be warned that this was the last program for CP/M on the PCW that
I ever programmed, and a few years have passed since then. In
other words, the code looks barely any more familiar to me than to you.
This file contains the equates used by all the other source files.
;EMUEQU.MAC - equates used by EMU1.MAC, EMU2.MAC, EMURST.MAC and EMUOFF.MAC no equ 0 yes equ not no wrmboot equ 0 BDOS equ 5 ;BDOS entry point defDMA equ 080h ;default DMA buffer charram equ 0b800h ;start of character matrix RAM SCB equ 0fb9ch ;System Control Block emuins equ SCB+9 ;4th user byte in SCB for use as installation status flag conmode equ SCB+033h ;console mode. Bit 2 controls tab expansion curDMA equ SCB+03ch ;address of current DMA buffer stored here conout equ 0fc0dh ;jump-table entry to BIOS CONOUT routine userf equ 0fc5ah ;address of BIOS USERFunction teask equ 0bfh ;offset to XBIOS TE ASK routine setexp equ 0d4h ;offset to XBIOS SET EXPAND routine scrrun equ 0e9h ;offset to XBIOS SCR RUN routine print equ 9 input equ 10 nul equ 0 beep equ 7 tab equ 9 lf equ 10 cr equ 13 ESC equ 27 zpm3 equ no ;set 'yes' if ZPM3 BDOS fitted and you're feeling lucky iso8859 equ yes ;set 'yes' if support for ISO-8859-1 (Latin 1) character ;set required xcls equ no ;ANSI systems expect the 'clear screen' sequence ;(ESC [ 2 J) to additionally home the cursor. Some ;systems also expect ASCII 12 to do this. ;set 'yes' if you need support for such a system
We try and do as much as possible in this file, since this is the transient part of EMU. When run, this part does some sanity checking and character redefinition, and then exits, leaving EMU2 loaded as an RSX and the BIOS's CONOUT routine redirected through it.
title EMU1 v1.02 2/12/95 subttl (c) Ian Macdonald (firstname.lastname@example.org) .comment | EMU provides a rudimentary VT100 emulation for the Amstrad PCW's VT52 terminal. Whilst the VT100 implementation is not complete, it is superior to that offered by comms programs such as COMM+ and QTERM. Commands available: EMU installs the RSX and turns VT100 emulation on. EMURST resets highlighting attributes. EMUOFF resets highlighting attributes, turns VT100 emulation off and removes the RSX. EMUKEY configures cursor keys to produce VT100 keys. v1.00 14/7/95 - first official release (identical to v0.14 beta) v1.01 5/8/95 - bug which caused unimplemented escape codes to affect screen display under certain circumstances fixed v1.02 2/12/95 - EMUKEY command added for redefining cursor keys to VT100 | include EMUEQU.MAC ;get equates ;The VTOFF, EMUL and CONORG entry points move according to the ZPM3 and ISO8859 equates ;in EMUEQU.MAC (which control conditional assembly in EMU2.MAC). The VTOFFX, EMUL and ;CONORG equates in this file control assembly of the correct addresses. vtoffx set 0c9h ;jump offset to relevant part of routine in RSX emul set 0d2h ;jump offset to routine in RSX conorg set 02e0h ;jump offset to routine in RSX if zpm3 conorg set conorg+2 if1 .printx * Assembling ZPM3 version of EMU1... * endif endif if iso8859 vtoffx set vtoffx+00fh emul set emul+031h conorg set conorg+050h if1 .printx * Assembling ISO-8859-1 (Latin 1) character set version of EMU1... * endif endif if xcls conorg set conorg+10 if1 .printx * Assembling with non-standard 'clear screen' sequences... * endif endif .z80 ld de,signon call display ;display sign-on message ld a,(emuins) cp 'E' ;is EMU already installed? jr z,fail1 ;if so, abort ld a,(BDOS+2) cp 0c1h ;have we got enough common memory to play with? jr c,fail2 ;if not, bye-bye success:ld a,'E' ld (emuins),a ;set installation flag if iso8859 ld de,charram+180*8 ;180 is first character to replace ld hl,newchar ;start of new character data ld bc,6*8 ;6 characters of each 8 bytes ld a,082h di ;disable interrupts out (0f2h),a ;switch in block 2 at 8000h-bfffh ldir ;load characters 180 to 185 ld de,charram+187*8 ;187 is next character to replace ld c,2*8 ;2 characters of each 8 bytes ldir ;load characters 187 to 188 ld de,charram+191*8 ;191 is next character to replace ld c,1*8 ;1 character of 8 bytes ldir ;load character 191 ld de,charram+220*8 ;220 is next character to replace ld c,4*8 ;4 characters of each 8 bytes ldir ;load characters 220 to 223 ld de,charram+252*8 ;252 is next character to replace ld c,4*8 ;4 characters of each 8 bytes ldir ;load characters 252 to 255 ld a,086h out (0f2h),a ;replace block 6 ei endif ld de,conorg+1 ld a,(BDOS+2) ld h,a ld l,0 add hl,de ;get actual address of CONORG in HL ld (corg+1),hl ;store it ld hl,(conout) corg: ld (0000),hl ;save original CONOUT address ld de,emul ld h,a ld l,0 add hl,de ;get address of RSX's EMUL routine in HL ld (conout),hl ;redirect CONOUT via EMU ld de,instal ;display installation message display:ld c,print jp BDOS fail1: ld de,alinst jr exit fail2: ld de,nomem exit: call display ;display installation failure message ld a,(BDOS+2) ld h,a ld l,vtoffx ;get address of relevant part of RSX's VTOFF routine jp (hl) ;execute it if iso8859 newchar:db 195,60,102,102,102,60,195,0 ;international currency symbol db 0,0,0,126,6,0,0,0 ;negation sign (logical NOT) db 126,0,0,0,0,0,0,0 ;spacing macron db 0,24,24,126,24,24,126,0 ;+/- sign db 24,36,8,16,60,0,0,0 ;superscript 2 db 24,36,8,36,24,0,0,0 ;superscript 3 db 0,0,204,204,204,204,246,192 ;micro sign (lower case Mu) db 0,0,0,0,0,0,24,56 ;spacing cedilla db 16,48,16,16,56,0,0,0 ;superscript 1 db 248,108,102,246,102,108,248,0 ;upper case Eth db 0,0,0,108,56,108,0,0 ;multiplication sign db 12,24,102,60,24,24,24,0 ;upper case Y-acute db 224,124,102,102,102,124,224,0 ;upper case Thorn db 192,96,252,24,124,198,124,0 ;lower case Eth db 0,0,24,0,126,0,24,0 ;division sign db 12,24,102,102,102,62,6,124 ;lower case Y-acute db 0,240,96,124,102,124,96,96 ;lower case Thorn endif signon: db 'EMU ' if xcls db '(ANSI) ' else if not iso8859 db '(ASCII) ' endif endif db 'v1.02 2/12/95 (c) Ian Macdonald (email@example.com)' db cr,lf,lf,'$' instal: db 'VT100 emulation now on. Commands available:',cr,lf,lf db 'EMUOFF - uninstall emulator.',cr,lf db 'EMURST - reset highlighting attributes.',cr,lf db 'EMUKEY - install VT100 cursor keys.',cr,lf,'$' alinst: db beep,'ERROR: EMU already installed.',cr,lf,'$' nomem: db beep,'ERROR: not enough memory. Please remove some RSXes.',cr,lf,'$' end
OK, this is the beef of the program. This part is the RSX that gets installed when EMU is run and handles all the emulation, command handling and restoration when EMU is removed from memory.
It's not always very pretty and I've probably broken some golden rules, but it had to be as fast as possible, so I optimised for speed instead of legibility.
title EMU2 v1.02 2/12/95 subttl (c) Ian Macdonald (firstname.lastname@example.org) .comment | EMU provides a rudimentary VT100 emulation for the Amstrad PCW's VT52 terminal. Whilst the VT100 implementation is not complete, it is superior to that offered by comms programs such as COMM+ and QTERM. Commands available: EMU installs the RSX and turns VT100 emulation on. EMURST resets highlighting attributes. EMUOFF resets highlighting attributes, turns VT100 emulation off and removes the RSX. EMUKEY configures cursor keys to produce VT100 keys. v1.00 14/7/95 - first official release (identical to v0.14 beta) v1.01 5/8/95 - bug which caused unimplemented escape codes to affect screen display under certain circumstances fixed v1.02 2/12/95 - EMUKEY command added for redefining cursor keys to VT100 Further information: 1. Conditional assembly is provided to support the entire ISO-8859-1 (Latin 1) character set. This is the preferred character set on the Internet. The HTTP protocol used by World Wide Web browsers guarantees the integrity of 8 bit transmission. Furthermore, some people break the 'rule' of only using true ASCII (ISO-646) characters in e-mail and Usenet messages. As a consequence, characters with an ASCII value greater than 159 are almost always incorrectly displayed by the PCW, which has a non-standard character set. Set the 'iso8859' equate in EMUEQU.MAC if required. 2. If you assemble EMU with support for the ISO-8859-1 character set (see point 1 above), then you will be unable to correctly display native PCW documents containing characters with ASCII values greater than 159. This is because these values are remapped by EMU to display the Latin 1 characters. Some characters are even redefined. 3. Conditional assembly is provided for the implementation of bold. If you have installed Simeon Cran's ZPM3 replacement BDOS, you have the option of setting the 'zpm3' equate in EMUEQU.MAC. This will give you a faster bold routine, but also makes the program slightly unstable. When assembled in this way, EMU may cause a crash if you subsequently run a program which extends into memory between 8000h and BFFFh. In practice, there will only be a danger of this if the program in question is larger than 32k. COMM+ (36k) seems to work without problems. If using EMU in this way, I strongly recommend that you make a point of immediately uninstalling EMU after using any application that requires it. However, I would strongly suggest that you don't use this option at all! Note that setting the 'zpm3' equate _guarantees_ a crash on systems still using the original Digital Research BDOS. In short, set this equate at your own risk! 4. Some systems erroneously expect the 'clear screen' sequence (ESC [ 2 J) to additionally home the cursor. I am also informed that some systems expect ASCII 12 to do the same. If you encounter such a system, set the 'xcls' equate in EMUEQU.MAC. These non-standard features will then be supported. 5. The 4th SCB user byte is used as an installation status flag. This could cause conflicts if also used by other programs. As a consequence, there is a very remote chance that EMU may erroneously report that it is already installed when you attempt to install it. Likewise, there is a slightly greater chance that double installation may occur. A software reset is highly recommended in this latter case. Further improvements to be made: Any features not required by the Lynx WWW browser have been omitted for speed. 1. Highlighting attribute 5 (blink) would be nice, but probably impossible on the PCW. 2. Alternate character sets would be nice, but what software needs them? 3. Double height/width would be nice, but again, what software needs them? 4. Terminal interrogation support, particularly 'What are you?' (ESC [ c or ESC [ 0 c). This is used by some BBS systems, but doesn't appear to be essential. The interrogating system simply goes ahead with VT100 transmission anyway after receiving a null response. 5. Implementation of scrolling regions, but probably superfluous. This would also be destructive if EMU was installed under a program which defined its own windows, as the PCW cannot cope with multiple windows. Bugs and incompatibility: 1. EMU causes a crash when ZMP patched with ZMP15PCW.MAC dated 16/6/95 is run. This is because both EMU and ZMP make use of the Z80 alternate register set in their screen display routines. The version of ZMP15PCW.MAC dated 28/6/95 solves this. There should be no conflicts with other communications software, unless screen output goes directly via the BIOS, using the alternate registers without preserving them. 2. Any CP/M program which uses ESC M (delete line containing cursor and scroll rows below up one line) while EMU is installed will not behave as expected. This is because ESC M means 'reverse index' in VT100. 3. The character produced by the sequence ESC ESC (lower case Tau) cannot be displayed while EMU is installed. | include EMUEQU.MAC ;get equates if zpm3 if1 .printx * Assembling ZPM3 version of EMU2... * endif endif if iso8859 if1 .printx * Assembling ISO-8859-1 (Latin 1) character set version of EMU2... * endif endif if xcls if1 .printx * Assembling with non-standard 'clear screen' sequences... * endif endif .z80 ;standard RSX header serial: db 0,0,0,0,0,0 start: jp rsx next: jp next prev: dw 7 remove: db no nonbank:db 0 name: db 'EMU ' loader: db 0 spare: ds 2 ;general housekeeping rsx: ld hl,conmode set 2,(hl) ;turn off tab expansion (just doing it is much quicker ;than testing whether a print function is being called). ;we must repeatedly turn it off in case another program ;turns it back on ld a,c cp 10 ;BDOS 10 ? jr nz,next ;if not, pass to BDOS (or next RSX) ld (stadd),sp ;save calling program's stack ld sp,tstack ;create our own push de ;save BDOS 10 buffer location call next ;get line input pop hl ;get buffer location in HL ld sp,(stadd) ;restore stack ld a,h or l ;is buffer at 0 ? jr nz,getnr ;if not, standard call used ld hl,(curDMA) ;otherwise, use current DMA buffer getnr: inc hl ld a,(hl) ;get number of bytes in buffer cp 6 ;EMUOFF and EMURST commands = 6 characters each ret nz ;if different, return to calling program ex de,hl ;get buffer in DE ld hl,command ;start of command table ld bc,6 ;6 bytes in each command loop1: call testch ;test for valid command jr z,vtoff ;if fully matched, EMUOFF inc hl inc hl ;otherwise, bump up command table pointer ld bc,3 ;3 characters to test (RST) dec de ;prepare buffer pointer loop2: call testch ;test for valid command if iso8859 jp z,exit ;matched EMURST: turn attributes off and exit else jr z,exit ;matched EMURST: turn attributes off and exit endif inc hl inc hl ;otherwise, bump up command table pointer ld bc,0303h ;C (decremented by CPI) mustn't get in the way of B loop3: ld a,(de) ;get input character or 32 ;convert to lower case cpi ;compare with command table ret nz ;return to calling program if no match inc de ;bump up buffer pointer djnz loop3 ;loop if we've still got a match emukey: ld bc,09103h ;expansion token 091h, 3 characters long ld hl,curup ;address of new data call setkey ;install token ld bc,09303h ;expansion token 093h, 3 characters long ld hl,curlft ;address of new data call setkey ;install token ld bc,09403h ;expansion token 094h, 3 characters long ld hl,currgt ;address of new data call setkey ;install token ld bc,09603h ;expansion token 096h, 3 characters long ld hl,curdn ;address of new data call setkey ;install token rst wrmboot ;return to CP/M via a warm boot setkey: call userf dw setexp ret testch: inc de ;bump up buffer pointer ld a,(de) ;get input character or 32 ;convert to lower case cpi ;compare with command table ret po ;exit loop if we've had all the characters (Z flag set) jr z,testch ;loop if we've still got a match ret ;otherwise, return (Z flag not set) vtoff: if iso8859 ld de,charram+180*8 ;180 is first character to replace ld hl,orgchar ;start of original character data ld bc,restore ;address of routine to restore characters call userf ;call it dw scrrun endif defkey: ld bc,09101h ;expansion token 091h, 1 character long ld hl,defup call setkey ;restore token ld bc,09301h ;expansion token 093h, 1 character long ld hl,deflft call setkey ;restore token ld bc,09401h ;expansion token 094h, 1 character long ld hl,defrgt call setkey ;restore token ld bc,09601h ;expansion token 096h, 1 character long ld hl,defdn call setkey ;restore token ld hl,(conorg+1) ld (conout),hl ;restore original CONOUT address xor a ld (emuins),a ;set uninstallation flag vtoffx: ld a,yes ld (remove),a ;set flag to remove RSX exit: call noatt ;turn all highlighting attributes off rst wrmboot ;do a warm boot if iso8859 restore:ld bc,6*8 ;6 characters of each 8 bytes ldir ;load characters 180 to 185 ld de,charram+187*8 ;187 is next character to replace ld c,2*8 ;2 characters of each 8 bytes ldir ;load characters 187 to 188 ld de,charram+191*8 ;191 is next character to replace ld c,1*8 ;1 characters of 8 bytes ldir ;load character 191 ld de,charram+220*8 ;220 is next character to replace ld c,4*8 ;4 characters of each 8 bytes ldir ;load characters 220 to 223 ld de,charram+252*8 ;252 is next character to replace ld c,4*8 ;4 characters of each 8 bytes ldir ;load characters 252 to 255 ret endif ;start of the emulator proper emul: ld hl,hadESC ld a,c ;get character in A cp ESC ;is it an ESCape? jr z,isESC ;if so, skip ahead ld a,(hl) or a ;are we in an ESCape sequence? jp z,norm ;if not, display it as per usual ld a,(lstch) ;get previous character cp '?' ;was it a question-mark? jr nz,ftest ;if not, conduct further tests ld a,c ;get current character cp '9'+1 ;is it probably a digit? ret c ;if so, return jp resfgs ;otherwise, end of ESC [ ? sequence isESC: ld (hl),a ;otherwise, flag ESC ret ;return without displaying ;discover from previous character in ESC sequence what to do with current one ftest: cp '[' jr z,square cp '#' jp z,hash cp '(' jp z,lftbr cp ')' jp z,rgtbr ld a,c ;if none of the above, get current character ld (lstch),a ;store it as last character ;if current character is 2nd character in longer ESCape sequence, return without ;displaying it cp '[' ret z cp '£' ret z cp '(' ret z cp ')' ret z ;cp 'E' ;commented out for VT52 compatibility ;jr z,nline cp 'M' jr z,revidx ;reverse index cp '7' jr z,savcur ;save cursor position cp '8' jr z,rescur ;restore cursor position cp '<' jr c,dochar ;less than '<' cp '>'+1 jp c,resfgs ;'>' or less (weed out ESC <, ESC = and ESC > ) dochar: exx ;save character to be printed (in C) ld c,ESC call enorm ;send ESC exx ;retrieve control character call enorm ;print it jp resfgs ;reset flags nline: ;ld c,'B' ;jr dochar ;commented out for VT52 compatibility revidx: ld c,'I' jr dochar ;reverse index savcur: ld c,'j' jr dochar ;save cursor position rescur: ld c,'k' jr dochar ;restore cursor position square: ld a,c ;get current character in A cp '0' jr c,notdgt ;less than a digit cp '9'+1 jr nc,notdgt ;more than a digit sub '0' ;convert to real figure ld c,a ;save in C ld hl,(lstdgt) ;get address of last digit ld a,(haddgt) or a ;already had a digit? jr z,stordgt ;if not, store this one ld a,(hl) ;otherwise, get last one, which must represent tens add a,a ;x 2 ld b,a ;save result in B add a,a ;x 4 add a,a ;x 8 add a,b ;x 10 add a,c ;+ units ld (hl),a ;store the new figure ret stordgt:ld (hl),c ;store this digit inc a ld (haddgt),a ;set flag to signify presence of digit ld hl,nrdgts inc (hl) ;bump digit count ret notdgt: ld a,(nrdgts) or a ld a,c ;get current character in A jr z,nodgt ;no digit pending cp ';' jr z,semic ;digit separator cp 'm' jr z,chatt ;set character attributes cp 'A' ret c ;less than 'A': ignore cp 'D'+1 jp c,cursor ;A, B, C or D: move cursor cp 'H' jp z,curxy ;move cursor to X,Y cp 'J' jp z,erascr ;erase section of screen cp 'K' jp z,eraline ;erase section of line cp 'f' jp z,curxy ;move cursor to X,Y ;ret ;ignore any other codes jp resfgs ;ignore any other codes nodgt: cp 'H' jr z,dochar cp 'J' jr z,dochar ;send straight to screen (same as VT52) cp 'K' jr z,dochar ;send straight to screen (same as VT52) cp 'm' jr z,noatt cp ';' ret z ;digit separator cp '?' jr z,qmark cp 'A' ;ret c ;less than 'A' jp c,resfgs ;less than 'A' cp 'D'+1 ;ret nc ;greater than 'D' jp nc,resfgs ;greater than 'D' jp dochar semic: ld hl,(lstdgt) inc hl ;bump pointer to last digit ld (lstdgt),hl xor a ld (haddgt),a ;reset 'had a digit' flag ret chatt: ld a,(nrdgts) ld b,a ;get number of attributes in B ld hl,dgtbuf ;get start of attribute list in HL attlp: ld a,(hl) ;get attribute cp 1 ;bold? jr nz,ntest ;if not, conduct next test ld (bold),a ;bold on jr natt ;get next attribute ntest: cp 5 ;blink? jr z,natt ;if so, get next attribute: blink not implemented cp 8 ;attribute > 7 ? jr nc,natt ;if so, ignore ld (curatt),hl ;save address of current attribute ld (hl),b ;convenient place to save attribute count or a ;attribute 0 ? (all attributes off) jr nz,ntest2 ;if not, next test call noatt ;turn all attributes off jr recov ;recover attribute address and count ntest2: cp 7 ;highlight? jr z,revon ;if so, turn on ld c,'r' ;otherwise, assume attribute 4 (underline on) jr dchar revon: ld c,'p' ;inverse video dchar: call dochar ;set attribute recov: ld hl,(curatt) ;recover current attribute address ld b,(hl) ;recover attribute count natt: inc hl ;address of next attribute djnz attlp ;get next attribute jp resfgs ;reset flags noatt: xor a ld (bold),a ;bold off ld c,'u' call dochar ;underline off ld c,'q' jp dochar ;inverse video off qmark: ld (lstch),a ;mark as last char. ('?' ESCapes not implemented) ret curxy: ld c,'Y' call dochar ;send ESC for X,Y sequence ld a,(dgtbuf) ;get Y co-ordinate call setco ;set Y co-ordinate ld a,(dgtbuf+1) ;get X co-ordinate setco: add a,31 ;add offset ld c,a jp enorm ;set X co-ordinate ;flags already reset by ESC Y cursor: ld (direct+1),a ;store cursor direction ld a,(dgtbuf) curtab: ld b,a ;get number of positions to move loop4: exx ;save position count ld c,ESC call enorm ;send ESCape direct: ld c,'?' ;cursor direction is patched here call enorm ;move cursor exx ;retrieve position count djnz loop4 ;go around again jr resfgs ;reset flags eraline:ld a,(dgtbuf) or a jp z,dochar ;ESC [ 0 K means erase to end of line dec a jr z,eralcur ;ESC [ 1 K means erase line up to cursor eralb: ld c,'l' jp dochar ;ESC [ 2 K means erase entire line containing cursor eralcur:ld c,'o' jp dochar erascr: ld a,(dgtbuf) or a jp z,dochar ;ESC [ 0 J means erase to end of screen dec a jr z,scrcur ;ESC [ 1 J means erase from top of screen to cursor erasb: if xcls ld c,'H' call dochar endif ld c,'E' jp dochar ;ESC [ 2 J means erase entire screen scrcur: ld c,'d' jp dochar ;none of the following 3 ESCapes is implemented, so we let them drop into the ;register reset routine hash: ;jr resfgs lftbr: ;jr resfgs rgtbr: ;jr resfgs resfgs: xor a ld hl,hadESC ld (hl),a ;zero hadESC inc hl ld (hl),a ;zero haddgt inc hl ld (hl),a ;zero lstch inc hl ld (hl),a ;zero nrdgts inc hl ;HL = lstdgt ld de,dgtbuf ld (hl),e inc hl ld (hl),d ;reset last digit pointer to start of digit buffer ret norm: ld a,c cp tab ;is character a tab? jr z,istab ;if so, take care of our own tab expansion if xcls cp 12 jp z,erasb endif cp ' '+1 ;is it a control character or a space? jr c,enorm ;if so, don't bother to make it bold if iso8859 sub 160 ;value of first ISO-8859-1 character jr c,tbold ;if lower, skip ahead ld d,0 ld b,32 sub b ;ASCII > 191 ? jr nc,accent ;if so, accented character add a,b ;otherwise, readjust ld hl,lookup ;start of look-up table jr zerob ;get character accent: inc a ;no upper case Scharfes S ld hl,accents ;start of accented characters in look-up table cp b ;is it lower case? jr c,upcase ;if not, skip ahead sub b ;adjust for correct position in look-up table zerob: ld b,d ;zero B for lower case upcase: ld e,a ;offset to character in DE add hl,de ;get address in look-up table ld a,(hl) ;look up accented character sub b ;if necessary, make it upper case ld c,a ;put it in C tbold: endif ld a,(bold) or a jr z,enorm ;bold not on: process immediately ld de,charram ;start of character RAM ld a,c ;get character in A ld h,0 ld l,a ;get character in HL add hl,hl add hl,hl add hl,hl ;x 8 (multiply ASCII value by 8) add hl,de ;get address of bit-map in character RAM ld (chadd),hl ;save it ld de,cchar ;address to save existing bit-map if zpm3 ld bc,8 ;8 bytes of character data ex af,af' ;save ASCII value ld a,082h di ;disable interrupts out (0f2h),a ;switch in block 2 at 8000h-bfffh ldir ;save bit-map ld hl,(chadd) ;restore its address in character RAM to HL ld d,h ld e,l ;make a copy of the address in DE ld bc,0808h ;8 bytes to make bold (C is for later) mbold: ld a,(hl) ;get character data rra ;rotate data out of true or (hl) ;superimpose original ld (hl),a ;save it inc hl ;get next byte of character data djnz mbold ;loop ld a,086h out (0f2h),a ;replace block 6 ei ex af,af' ;get ASCII value back in A exx ;save BC and DE ld c,a ;get character in C call enorm ;display bold character exx ;restore BC and DE ld hl,cchar ;start of saved bit-map ld a,082h di ;disable interrupts out (0f2h),a ;switch in block 2 at 8000h-bfffh ldir ;restore original bit-map ld a,086h out (0f2h),a ;replace block 6 ei ret else ld bc,scrrt1 call userf ;save bit-map of character and make bold dw scrrun call enorm ;display bold character ld bc,scrrt2 call userf ;restore original bit-map dw scrrun ret scrrt1: ld bc,8 ;8 bytes of character data ldir ;save bit-map ld c,a ;save ASCII value of character in C ld hl,(chadd) ;restore its address in character RAM to HL ld b,8 ;8 bytes to make bold mbold: ld a,(hl) ;get character data rra ;rotate data out of true or (hl) ;superimpose original ld (hl),a ;save it inc hl ;get next byte of character data djnz mbold ;loop ret scrrt2: ld de,(chadd) ;address in character RAM to copy back to ld hl,cchar ;start of saved bit-map ld bc,8 ;8 bytes to restore ldir ;restore original bit-map ret endif istab: ld a,'C' ld (direct+1),a ;set direction for 'cursor right' call userf dw teask ;get current cursor column in L ld a,l cpl ;complement to obtain 255 minus L and 00000111b ;only least significant 3 bits are important (7 minus L) inc a ;add one to obtain true figure (8 minus L) jp curtab ;move cursor to next tab stop (assuming 8 columns apart - ;tab setting/clearing not implemented) enorm: conorg: jp 0000 ;jump to BIOS CONOUT (address patched by EMU1) command:db 'emuoffrstkey' ;3 commands: EMUOFF, EMURST and EMUKEY curup: db ESC,'[A' ;VT100 cursor control codes curlft: db ESC,'[D' currgt: db ESC,'[C' curdn: db ESC,'[B' defup: db '_' and 01fh ;PCW cursor control codes deflft: db 'A' and 01fh defrgt: db 'F' and 01fh defdn: db '^' and 01fh if iso8859 .comment | Look-up table for remapping ISO-8859-1 (Latin 1) characters. Upper case accented letters are obtained by subtracting 32 from the values in the table. PCW ISO-8859-1 Character === ========== ========= | lookup: db ' ' ; 160 non-breaking space db 175 ; 161 inverted exclamation mark db 177 ; 162 cent sign db 163 ; 163 pound sign db 180 ; 164 international currency symbol db 189 ; 165 yen sign db '|' ; 166 broken vertical bar db 166 ; 167 section sign db 178 ; 168 spacing diaeresis db 164 ; 169 copyright sign db 160 ; 170 feminine ordinal indicator db 171 ; 171 left double guillemet db 181 ; 172 negation sign (logical NOT) db '-' ; 173 soft hyphen db 190 ; 174 registered sign db 182 ; 175 spacing macron db 162 ; 176 degree sign db 183 ; 177 +/- sign db 184 ; 178 superscript 2 db 185 ; 179 superscript 3 db 179 ; 180 spacing acute db 187 ; 181 micro sign (lower case Mu) db 165 ; 182 paragraph sign db 144 ; 183 middle dot db 188 ; 184 spacing cedilla db 191 ; 185 superscript 1 db 161 ; 186 masculine ordinal indicator db 172 ; 187 right double guillemet db 168 ; 188 1/4 fraction db 169 ; 189 1/2 fraction db 170 ; 190 3/4 fraction db 174 ; 191 inverted question mark accents:db 186 ; 223 Scharfes S db 234 ; 224 A-grave db 224 ; 225 A-acute db 229 ; 226 A-circumflex db 250 ; 227 A-tilde db 240 ; 228 A-diaeresis db 247 ; 229 A-ring db 246 ; 230 AE-diphthong db 245 ; 231 C-cedilla db 235 ; 232 E-grave db 225 ; 233 E-acute db 230 ; 234 E-circumflex db 241 ; 235 E-diaeresis db 236 ; 236 I-grave db 226 ; 237 I-acute db 231 ; 238 I-circumflex db 242 ; 239 I-diaeresis db 252 ; 240 Icelandic Eth db 249 ; 241 N-tilde db 237 ; 242 O-grave db 227 ; 243 O-acute db 232 ; 244 O-circumflex db 251 ; 245 O-tilde db 243 ; 246 O-diaeresis db 253 ; 247 division sign db 248 ; 248 O-slash db 238 ; 249 U-grave db 228 ; 250 U-acute db 233 ; 251 U-circumflex db 244 ; 252 U-diaeresis db 254 ; 253 Y-acute db 255 ; 254 Icelandic Thorn db 239 ; 255 Y-diaeresis orgchar:db 16,56,108,198,0,0,0,0 ;spacing circumflex db 0,198,204,24,32,91,219,0 ;per thousandth db 64,192,70,73,70,9,6,0 ;1/8 fraction db 224,16,102,25,230,9,6,0 ;3/8 fraction db 240,128,230,25,230,9,6,0 ;5/8 fraction db 240,16,38,73,134,9,6,0 ;7/8 fraction db 0,56,108,198,198,108,56,0 ;open circle db 0,56,124,254,254,124,56,0 ;full circle db 251,85,81,81,0,0,0,0 ;trademark sign db 192,48,12,48,204,48,192,0 ;greater than or equal to db 6,24,96,24,102,24,6,0 ;less than or equal to db 6,12,126,24,126,48,96,0 ;not equal to db 0,0,50,76,0,126,0,0 ;approximately equal to db 8,12,254,7,254,12,8,0 ;double shafted right arrow db 16,48,127,224,127,48,16,0 ;double shafted left arrow db 0,36,126,195,126,36,0,0 ;double shafted left/right arrow db 0,126,0,126,0,126,0,0 ;equivalent to endif hadESC: ds 1 ;flag for ESCape character haddgt: ds 1 ;flag for 'had a digit' lstch: ds 1 ;store for last character nrdgts: ds 1 ;store for number of digits in buffer lstdgt: dw dgtbuf ;pointer to current digit in buffer dgtbuf: ds 4 ;digit buffer curatt: ds 2 ;pointer to current attribute bold: ds 1 ;flag for bold attribute chadd: ds 2 ;address in character RAM of bold character stadd: ds 2 ;address of calling program's stack cchar: ds 8 ;store for character data when displaying in bold ds 8 ;stack used by BDOS 10 tstack: end
title EMUOFF v1.00 23/6/95 subttl (c) Ian Macdonald (email@example.com) .comment | Program to uninstall EMU from within a .SUB file or alias. | include EMUEQU.MAC ;get equates .z80 ld de,defDMA ld hl,ststr ld bc,endstr-ststr ldir ;relocate EMUOFF command in default DMA buffer ld c,input ld de,0 ;use current DMA, i.e. default jp BDOS ;send EMUOFF command to RSX ststr: db 6,0,'emuoff',cr,nul endstr: end
title EMURESET v1.00 23/6/95 subttl (c) Ian Macdonald (firstname.lastname@example.org) .comment | Program to reset EMU's highlighting attributes from within a .SUB file or alias | include EMUEQU.MAC ;get equates .z80 ld c,print ld de,signon jp BDOS ;turn off attributes and display sign-on message signon: db ESC,'[m' ;VT100 escape code for 'turn all attributes off' db 'EMURESET v1.00 23/6/95 (c) Ian Macdonald (email@example.com)',cr,lf db lf,'Highlighting attributes now reset.',cr,lf,'$' end
title EMUSUB v1.00 3/12/95 subttl (c) Ian Macdonald (firstname.lastname@example.org) .comment | Program to send commands to EMU from within a .SUB file or Z-system alias. | include EMUEQU.MAC ;get equates .z80 ld hl,defDMA ld a,(hl) ;get number of characters in command tail cp 3 ;is it 3? jr nz,help ;if not, display help text inc hl inc hl ;move pointer to first character in command tail ld a,(hl) cp '/' ;is it '/'? jr nz,help ;if not, display help text inc hl ;move pointer to parameter ld a,(hl) cp 'O' ;is it 'O'? jr z,emuoff ;if so, EMUOFF cp 'R' ;is it 'R'? jr z,emurst ;if so, EMURST cp 'K' ;is it 'K'? jr z,emukey ;if so, EMUKEY ;otherwise, display help text help: ld de,htxt prt: ld c,print jp BDOS ;turn off attributes and display sign-on message emuoff: ld hl,str1 emuk: ld de,defDMA ld bc,str2-str1 ;string length always the same ldir ;relocate command in default DMA buffer ld c,input ld de,0 ;use current DMA, i.e. default jp BDOS ;send command to RSX emukey: ld hl,str2 jr emuk emurst: ld de,rsttxt jr prt str1: db 6,0,'emuoff',cr,nul str2: db 6,0,'emukey',cr,nul rsttxt: db ESC,'[m$' ;VT100 escape code for 'turn all attributes off' htxt: db 'EMUSUB v1.00 3/12/95 (c) Ian Macdonald (email@example.com)',cr,lf,lf db 'Commands available:',cr,lf,lf db 'EMUSUB /O - uninstall emulator.',cr,lf db 'EMUSUB /R - reset highlighting attributes.',cr,lf db 'EMUSUB /K - install VT100 cursor keys.',cr,lf,'$' end