[comp.sources.amiga] v89i032: simcpm - cpm simulator v2.3, Part01/03

page@swan.ulowell.edu (Bob Page) (03/08/89)

Submitted-by: jlydiatt@jlami.wimsey.bc.ca (Jeff Lydiatt)
Posting-number: Volume 89, Issue 32
Archive-name: applications/simcpm23.1

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	simcpm.doc
#	ecpmdefs.i
#	options.i
#	mandog.com.uu
#	testprog.com.uu
#	simcpm2.asm2
#	simcpm1.asm2
# This archive created: Tue Mar  7 22:33:54 1989
cat << \SHAR_EOF > simcpm.doc
               SimCPM - a CP/M simulator for the Amiga

                   by Jim Cathey and Charlie Gibbs
             incorporating modifications by Willi Kusche

                    Version 2.3 - January 9, 1989


     This is a FREELY-DISTRIBUTABLE program.  Spread it around all
you like, just don't sell it, and please keep the entire package
(including this file) intact.  If you find any bugs or make any
changes, please let me know - I'd like to keep my copy up to date.

     This program is based on an article by Jim Cathey which ran in
Dr. Dobb's Journal from January to March 1986.  The original program
emulated an 8080, including CP/M BIOS and BDOS calls, on a CP/M-68K
system.  I have modified the operating system interface to run under
AmigaDOS (from the CLI only, which shouldn't bother most CP/M-ers :-).

     Willi Kusche maintains that the proper term is "emulator", rather
than "simulator."  Although I agree, the original article called it a
simulator, and the name seems to have stuck.

     *** NEW FOR VERSION 2.0 ***  Due to popular demand, I have added
support for the entire Z-80 instruction set (including undocumented
opcodes).

     WARNING!  This program uses the MOVE from SR instruction to set up
the simulated Z-80 flags.  Therefore, it will not run on the 68010 or
higher processors.  I didn't want to use the Exec's GetCC() call because
it would be too slow.  As a work-around I have set up a EQUate in
options.i which you can change to indicate that you are running on a
68010, 68020, etc.  Re-assembling with x680x0 equated to 1 will cause
all MOVE from SR instructions to be replaced by the corresponding MOVE
from CCR instructions (actually faked with a DC.W in case your assembler
doesn't support 68010 opcodes).  I have assembled a version with this
flag set, and included it in the package; it is named SimCPM010.
It should be possible to check whether x680x0 is equated to 2 and
generate code optimized for a 68020 (as if it wouldn't be fast enough
as is :-).

     SimCPM only looks at the first 12 bytes of the FCB (drive code,
file name, and file type) when opening a file.  The remainder of the
FCB is neither altered nor checked, except for BDOS calls 17 (search
for first file) and 18 (search for next file), which insert extent size
and count information only.

     If a reference is made to any drive other than A:, SimCPM will
insert the string CPMx: ahead of any file name it uses.  For instance,
if a program tries to open MYFILE.DAT on drive B:, SimCPM will try to
open CPMB:MYFILE.DAT.  You can ASSIGN these simulated drives anywhere
you want.  Drive A: will always go to the current directory, unless the
user number is not zero.  If you specify any user number other than
zero, it will be included, e.g. if the above example were opened under
user 1, SimCPM will look for CPMB01:MYFILE.DAT.  If the file were on
drive A under user 1, SimCPM will look for CPMA01:MYFILE.DAT.

     The only built-in commands supported are USER and SAVE.  All
others, such as DIR or TYPE, can easily be done using AmigaDOS
equivalents.  You might want to RUN SimCPM so that the original
CLI window will be available for this.

     The EI and DI instructions are currently ignored.

     The IN and OUT instructions are ignored except for ports 14 and
15.  Access to the Amiga's serial port is provided through a simulated
Intel 8251 USART, which is currently set up to run at 1200 bps.  Data
is read from or written to port 14, and status input is simulated on
port 15.  All output to port 15 (command) is ignored.  Note that CPU
overhead may not permit an effective throughput of 1200 bps.  (Yup,
you guessed it, it emulates the modem port on my old IMSAI.)

     The following BDOS calls are not supported:

          3 - reader input
          4 - punch output
         30 - set file attributes
         all above 36

     The only BIOS calls supported are those for program termination
and console and list I/O.  (Low-level disk access could get scary.)
If a program attempts to use an unsupported BIOS or BDOS call, an
appropriate error message will be displayed, along with a register dump,
and the program will be terminated.

     Basic H19 terminal emulation (similar to a VT52) has been
provided.  Escape sequences for cursor positioning, cursor to home,
screen clearing, and insert and delete modes are translated to the
corresponding Amiga sequences.  The program MANDOG.COM, which I
wrote for my original CP/M (H19) system and copied here unchanged,
demonstrates the cursor addressing capabilities of SimCPM.  Any escape
sequences that SimCPM can't recognize are passed through unchanged.
You can disable all escape sequence translation by changing the equated
value "h19" (in options.i) to from 1 to 0 and re-assembling.

     To speed up console output for programs which write one character
at a time, I have included a buffered output option.  If you include
the -b switch on the command-line parameter, all console output will be
held until one of the following events occurs:

          - a carriage return, line feed, or bell character is written
          - the buffer (currently 2K) becomes full
          - a BIOS or BDOS call other than console output is made.

It should be possible to use buffered output in just about any program.
Note that if a program uses the "console output string" function (BDOS
call 9), the entire string is written in a single operation even when
buffering is not requested.

     If you include the -t switch on the command line, instruction
and/or BIOS/BDOS tracing is available.  Simulations run somewhat slower
with this flag set, even if tracing is not currently active.  Tracing
is done using 8080 mnemonics by default.  If you want Z-80 mnemonics,
use -z instead of -t.  If both -z and -t are specified, -t will be
ignored.

     If the trace switch has been specified, SimCPM will prompt you
for starting and ending addresses for tracing, and whether you want
BIOS/BDOS calls traced.  Simulation starts with tracing disabled.  When
SimCPM executes an instruction at the starting address, tracing is
turned on.  All Z-80 registers and the top four stack entries, as well
as the current instruction, are displayed for each instruction until
the ending address is reached.  Tracing is then disabled until the
start address is again encountered.  After displaying 8 instructions,
execution is suspended; enter S to stop tracing and continue executing,
Q to quit the program, C to change the starting and ending addresses
for tracing, or any other key to trace the next 8 instructions.

     If you have requested BIOS/BDOS call tracing, the message

          BIOS CALL nn (hex) AT aaaa
or
          BDOS CALL nn (hex) AT aaaa

will be displayed each time a BIOS or BDOS call is made.  The BDOS
call number (contents of register C in hex) will replace "nn" for BDOS
calls, while BIOS calls will set "nn" to a sequential number starting
at 01 for program termination, 02 for console status, etc.  The address
where the call is made will be taken from the top of the stack and
displayed in place of "aaaa".

     List output is sent to PRT:RAW.  This ensures that no newline
translation will take place.  The printer is not opened until the first
attempt is made to access it.  If the printer cannot be opened for any
reason, the program will be terminated.  At program termination the
printer will be closed if it was used.

     If SimCPM is brought up with no command-line parameters, it will
present the standard CP/M A> prompt.  At this point you can run CP/M
.COM files just like on a normal CP/M system.  The command line will
be scanned for up to two FCBs and the tail will be passed to the
program.  When the program terminates, the A> prompt will be
re-displayed.  To return to AmigaDOS, enter a control-C (CP/M warm
boot) at the A> prompt.

     If command-line parameters are given, they will be passed to
SimCPM as if they had been entered at the A> prompt.  When the program
terminates, SimCPM will automatically return to AmigaDOS.  This allows
you to run CP/M programs from an EXECUTE file.

     Here are some sample invocations of SimCPM:

          simcpm
               Loads the simulator, which presents the A> prompt and
               waits for CP/M commands.  Type control-C at the prompt
               to exit.

          simcpm -b
               Same as above, except console output buffering is used.

          simcpm myprog
               Loads the simulator, which loads and runs the CP/M
               program MYPROG.COM.  When MYPROG terminates, SimCPM
               returns to AmigaDOS.

          simcpm -t myprog
               Same as above, except that before MYPROG.COM is run,
               you will be prompted for trace parameters.

          simcpm -z myprog
               Same as above, except that Z-80 mnemonics will be used
               for tracing, rather than 8080 mnemonics.

          simcpm mbasic basprog
               Loads the simulator, which loads Microsoft BASIC-80 (if
               you have it), which in turn loads and runs BASPROG.BAS.
               When BASPROG issues a SYSTEM command, SimCPM returns
               to AmigaDOS.

          simcpm -b mbasic basprog
               Same as above, but with console output buffering.  Since
               MBASIC does all console I/O one character at a time, the
               buffered option can speed it up considerably.

     I have included two CP/M programs for demonstration purposes.
TESTPROG.COM is a simple "hello, world" program (try it using the
trace option), while MANDOG.COM demonstrates cursor addressing for
an emulated H19 terminal.

     SimCPM consists of two source modules, SIMCPM1.ASM and
SIMCPM2.ASM.  No include files are needed, although amiga.lib is
required for linking.  The makefile is set up to use my own assembler,
A68k, and BLink - it should be relatively easy to adapt it to whatever
assembler and linker you are using.


     Special thanks to:

       Jim Cathey for his article in Dr. Dobb's Journal -
        it provided the starting point for this program.

       Willi Kusche (for new ideas and corrections of my Z-80 code)
       SYSOP
       KMMM Pascal BBS
       (609) 232-0773
       24 hours a day
       7 days a week
       300/1200/2400/9600 bps
       9600 is USRobotics HST protocol
       Passing a simple IQ test required for full access


     Please address any kudos, flames, etc. to

          Charlie Gibbs
          2121 Rindall Avenue
          Port Coquitlam, B.C.
          Canada
          V3C 1T9

or to Larry Phillips or Jeff Lydiatt on CompuServe or Usenet.
(I don't have the time or money to live there myself.)
SHAR_EOF
cat << \SHAR_EOF > ecpmdefs.i
*
* Emulator register definitions
*  Note, only leaves D0-D1/A0 free for use by entire
*  program without saving registers for temporary use.
*
return	 equr	A6		;JMP (return) is fast return to MLOOP.
pseudopc equr	A5		;Emulated program counter
opptr	 equr	A4		;Address of opcode dispatch table
pseudosp equr	A3		;Emulated stack pointer
flagptr  equr	A2		;Address of flag lookup table
targbase equr	A1		;Address of emulated address space
regs	 equr	A1		;Base pointer to emulated registers
regcon0e equr	D7		;Register-based constant #$E (for speed)
regcon01 equr	D6		;Register-based constant #$1
regcon0f equr	D5		;Register-based constant #$F
regconff equr	D4		;Register-based constant #$FF
regf	 equr	D3		;Emulated flag register
rega	 equr	D2		;Emulated accumulator
*
* Target processor's data registers (offsets into storage area)
*  The emulated accumulator and flag register are kept in data registers.
*  The emulated program counter and stack pointer
*  are kept in address registers.
*
regb	equ	-22		;B
regc	equ	-21		;C
regd	equ	-20		;D
rege	equ	-19		;E
regh	equ	-18		;H
regl	equ	-17		;L
regix	equ	-16		;IX
regxh	equ	-16
regxl	equ	-15
regiy	equ	-14		;IY
regyh	equ	-14
regyl	equ	-13
regb2	equ	-12		;Alternate register set for Z-80
regc2	equ	-11
regd2	equ	-10
rege2	equ	-9
regh2	equ	-8
regl2	equ	-7
rega2	equ	-6
regf2	equ	-5
regi	equ	-4		;Interrupt page address register (I)
regop1	equ	-3		;Operand 1 for DAA storage
regop2	equ	-2		;   "	 2  "	"     "
regop3	equ	-1		;   "    3  "   "     "
SHAR_EOF
cat << \SHAR_EOF > options.i
* SimCPM options

* Processor flag - 0 for 68000, 1 for 68010
x680x0	equ	0		;68000

* Set "h19" to 1 to emulate an H19, zero to pass escape codes unchanged.
h19	equ	1		;Emulate Heath/Zenith 19 escape codes.
SHAR_EOF
cat << \SHAR_EOF > mandog.com.uu

begin 644 MANDOG.COM
MS7T#S4D#$;D##@G-!0`^`S*+!3Y+,HP%S5@#.HP%_A7,/0(ZC`7^%,Q$`CJ,Q
M!?X3S%$".HP%_A+,7@(ZC`7^$<QK`A'W`PX)S04`S5@#$3($#@G-!0#-6`,14
M;00."<T%`,U8`Q&H!`X)S04`.HP%/3*,!?(8`<U)`Q&Y`PX)S04`/@<RBP4^2
M23*,!<U8`SJ,!?X5S+8".HP%_A3,O0(ZC`7^$\S*`CJ,!?X2S-<".HP%_A',8
MY`(ZC`7^$,SQ`CJ,!?X/S/X"$>,$#@G-!0#-6`,1!`4."<T%`,U8`Q$E!0X)H
MS04`S5@#$48%#@G-!0`ZC`4],HP%^CD"_@["BP$1%`#-J0/-6`,19P4."<T%%
M`,U8`Q%P!0X)S04`S5@#$7D%#@G-!0`1'@#-J0/-6`,1@@4."<T%`,.+`<V3W
M`\DA]P/-<@+)(?<#S94"(?@#S7("R2'X`\V5`B'Y`\UR`LDA^0/-E0(A^@/-I
M<@+)(?H#S94"R1&-!08$Y0X'?A(V?-41"0`9T1,-PGH"X=41.P`9T07"=P+)=
M$8T%!@3E#@<:=]41"0`9T1,-PIT"X=41.P`9T07"F@+)(>,$S04#R2'C!,TH-
M`R'D!,T%`\DAY`3-*`,AY03-!0/)(>4$S2@#(>8$S04#R2'F!,TH`R'G!,T%?
M`\DAYP3-*`,AZ`3-!0/)(>@$S2@#R1&-!08$Y0X#?A(V?-41#0`9T1,-P@T#]
MX=41(0`9T07""@/)$8T%!@3E#@,:=]41#0`9T1,-PC`#X=41(0`9T07"+0/)G
M'AL.`LT%`!Y%#@+-!0#)'AL.`LT%`!Y9#@+-!0`ZBP7&(%\.`LT%`#J,!<8@_
M7PX"S04`R1X;#@+-!0`>>`X"S04`'C4.`LT%`,D>&PX"S04`'GD.`LT%`!XU"
M#@+-!0#)(8P@*WRUPJP#&WJSPJD#R2`@("`@("`@("`@("`@("`@("`@+2TM+
M"`@("GP@?`@("`HM+2T("`I\"`I\"`I\"`I\"`I\"`I\"`I\"`HD(%X@(`@(1
M"`@*($\@(`@("`@*('P@(`@("`@*('P@(`@("`@*('P@(`@("`@*('P@(`@(Q
M"`@*('Q<("0@7B`@"`@("`H@3R`@"`@("`H@?"`@"`@("`H@?"`@"`@("`H@#
M?"`@"`@("`H@?"`@"`@("`H@?"`@)"!>("`("`@("B!/("`("`@("B!\("`(1
M"`@("B]\7"`("`@("B!\("`("`@("B]\("`("`@("GQ\("`D(%X@(`@("`@*2
M($\@(`@("`@*('P@(`@("`@*+7PM(`@("`@*('P@(`@("`@*+WP@(`@("`@*:
M?"!<("0]("`@?"`("`@("`@*?"TM+2T@"`@("`@("B]<(%PO("0]("`@+R`(G
M"`@("`@*?"TM+2T@"`@("`@("GQ\('Q\("0]("`@?"`("`@("`@*?"TM+2T@3
M"`@("`@("EPO("]<("0]("`@?"`("`@("`@*?"TM+2T@"`@("`@("GQ\('Q\!
M("0@/2`@(`H*("0@/2`@('P*+20@/2`@('P*+R0@/2`@('P*("0`````````*
M`````````````````````````````````````````````````````````````
M`````````````````````````````````````````````````````````````
4`````````````````````````````
``
end
size 1280
SHAR_EOF
cat << \SHAR_EOF > testprog.com.uu

begin 644 testprog.com
H$0D!#@G-!0#)2&5L;&\L('=O<FQD(0T*)",C(R,C(R,C(R,C(R,C(^!42
``
end
size 40
SHAR_EOF
cat << \SHAR_EOF > simcpm2.asm2
	sbbflag

sbbyl	asr.b	#1,regf 		;FD9D SBB YL (undocumented)
	move.b	regyl(regs),d0
	sbbflag

sbbiy	calcind y			;FD9E SBB (IY+d)
	asr.b	#1,regf
	move.b	0(targbase,d0.l),d0
	sbbflag

anayh	and.b	regyh(regs),rega	;FDA4 ANA YH (undocumented)
	move.b	16(flagptr,rega.w),regf
	jmp	(return)

anayl	and.b	regyl(regs),rega	;FDA5 ANA YL (undocumented)
	move.b	16(flagptr,rega.w),regf
	jmp	(return)

anaiy	calcind y			;FDA6 ANA (IY+d)
	and.b	0(targbase,d0.l),rega
	move.b	16(flagptr,rega.w),regf
	jmp	(return)

xrayh	move.b	regyh(regs),d0		;FDAC XRA YH (undocumented)
	eor.b	d0,rega
	move.b	16(flagptr,rega.w),regf
	jmp	(return)

xrayl	move.b	regyl(regs),d0		;FDAD XRA YL (undocumented)
	eor.b	d0,rega
	move.b	16(flagptr,rega.w),regf
	jmp	(return)

xraiy	calcind y			;FDAE XRA (IY+d)
	move.b	0(targbase,d0.l),d0
	eor.b	d0,rega
	move.b	16(flagptr,rega.w),regf
	jmp	(return)

orayh	or.b	regyh(regs),rega	;FDB4 ORA YH (undocumented)
	move.b	16(flagptr,rega.w),regf
	jmp	(return)

orayl	or.b	regyl(regs),rega	;FDB5 ORA YL (undocumented)
	move.b	16(flagptr,rega.w),regf
	jmp	(return)

oraiy	calcind	y			;FDB6 ORA (IY+d)
	or.b	0(targbase,d0.l),rega
	move.b	16(flagptr,rega.w),regf
	jmp	(return)

cmpyh	cmp.b	regyh(regs),rega	;FDBC CMP YH (undocumented)
	setflag

cmpyl	cmp.b	regyl(regs),rega	;FDBD CMP YL (undocumented)
	setflag

cmpiy	calcind	y			;FDBE CMP (IY+d)
	cmp.b	0(targbase,d0.l),rega
	setflag

* FDCB-prefix instructions can use the DDCB-prefix routines,
*  since the operand address is already in D0.

popiy	move.b	(pseudosp)+,regyl(regs) ;FDE1 POP IY
	move.b	(pseudosp)+,regyh(regs)
	jmp	(return)

xtiy	move.b	regyl(regs),d0		;FDE3 XTIY
	move.b	(pseudosp),regyl(regs)
	move.b	d0,(pseudosp)
	move.b	regyh(regs),d0
	move.b	1(pseudosp),regyh(regs)
	move.b	d0,1(pseudosp)
	jmp	(return)

pushiy	move.b	regyh(regs),-(pseudosp) ;FDE5 PUSH IY
	move.b	regyl(regs),-(pseudosp)
	jmp	(return)

pciy	move.w	regiy(regs),d0		;FDE9 PCIY
	lea	0(targbase,d0.l),pseudopc
	jmp	(return)

spiy	move.w	regiy(regs),d0		;FDF9 SPIY
	lea	0(targbase,d0.l),pseudosp
	jmp	(return)
	page
*************************************************************************
*									*
*	Opcode dispatch table						*
*									*
*************************************************************************
	data	data

	even
optabl	dc.l	nop00,lxib,staxb,inxb,inrb,dcrb,mvib,rlc
	dc.l	exaf,dadb,ldaxb,dcxb,inrc,dcrc,mvic,rrc
	dc.l	djnz,lxid,staxd,inxd,inrd,dcrd,mvid,ral
	dc.l	jr,dadd,ldaxd,dcxd,inre,dcre,mvie,rar
	dc.l	jrnz,lxih,shld,inxh,inrh,dcrh,mvih,daa
	dc.l	jrz,dadh,lhld,dcxh,inrl,dcrl,mvil,cma
	dc.l	jrnc,lxis,sta,inxs,inrm,dcrm,mvim,stc
	dc.l	jrc,dads,lda,dcxs,inra,dcra,mvia,cmc
	dc.l	movebb,movebc,movebd,movebe,movebh,movebl,movebm,moveba
	dc.l	movecb,movecc,movecd,movece,movech,movecl,movecm,moveca
	dc.l	movedb,movedc,movedd,movede,movedh,movedl,movedm,moveda
	dc.l	moveeb,moveec,moveed,moveee,moveeh,moveel,moveem,moveea
	dc.l	movehb,movehc,movehd,movehe,movehh,movehl,movehm,moveha
	dc.l	movelb,movelc,moveld,movele,movelh,movell,movelm,movela
	dc.l	movemb,movemc,movemd,moveme,movemh,moveml,halt,movema
	dc.l	moveab,moveac,movead,moveae,moveah,moveal,moveam,moveaa
	dc.l	addb,addc,addd,adde,addh,addl,addm,adda
	dc.l	adcb,adcc,adcd,adce,adch,adcl,adcm,adca
	dc.l	subb,subc,subd,sube,subh,subl,subm,suba
	dc.l	sbbb,sbbc,sbbd,sbbe,sbbh,sbbl,sbbm,sbba
	dc.l	andb,andc,andd,ande,andh,andl,andm,anda
	dc.l	xrab,xrac,xrad,xrae,xrah,xral,xram,xraa
	dc.l	orab,orac,orad,orae,orah,oral,oram,oraa
	dc.l	cmpb,cmpc,cmpd,cmpe,cmph,cmpl,cmpam,cmpaa
	dc.l	rnz,popb,jnz,jmpa,cnz,pushb,adi,rst0
	dc.l	rz,ret,jz,preCB,cz,call,aci,rst1
	dc.l	rnc,popd,jnc,out,cnc,pushd,sui,rst2
	dc.l	rc,exx,jc,in,cc,preDD,sbi,rst3
	dc.l	rpo,poph,jpo,xthl,cpo,pushh,ani,rst4
	dc.l	rpe,pchl,jpe,xchg,cpe,preED,xri,rst5
	dc.l	rp,popp,jp,di,cp,pushp,oria,rst6
	dc.l	rm,sphl,jm,ei,cm,preFD,cpi,rst7
	page
*************************************************************************
*									*
*	Flag register lookup tables					*
*									*
*************************************************************************
flags	dc.b	$00,$01,$04,$05,$40,$41,$44,$45,$80,$81,$84,$85,$C0,$C1,$C4,$C5
	dc.b	$44,$00,$00,$04,$00,$04,$04,$00,$00,$04,$04,$00,$04,$00,$00,$04
	dc.b	$00,$04,$04,$00,$04,$00,$00,$04,$04,$00,$00,$04,$00,$04,$04,$00
	dc.b	$00,$04,$04,$00,$04,$00,$00,$04,$04,$00,$00,$04,$00,$04,$04,$00
	dc.b	$04,$00,$00,$04,$00,$04,$04,$00,$00,$04,$04,$00,$04,$00,$00,$04
	dc.b	$00,$04,$04,$00,$04,$00,$00,$04,$04,$00,$00,$04,$00,$04,$04,$00
	dc.b	$04,$00,$00,$04,$00,$04,$04,$00,$00,$04,$04,$00,$04,$00,$00,$04
	dc.b	$04,$00,$00,$04,$00,$04,$04,$00,$00,$04,$04,$00,$04,$00,$00,$04
	dc.b	$00,$04,$04,$00,$04,$00,$00,$04,$04,$00,$00,$04,$00,$04,$04,$00
	dc.b	$80,$84,$84,$80,$84,$80,$80,$84,$84,$80,$80,$84,$80,$84,$84,$80
	dc.b	$84,$80,$80,$84,$80,$84,$84,$80,$80,$84,$84,$80,$84,$80,$80,$84
	dc.b	$84,$80,$80,$84,$80,$84,$84,$80,$80,$84,$84,$80,$84,$80,$80,$84
	dc.b	$80,$84,$84,$80,$84,$80,$80,$84,$84,$80,$80,$84,$80,$84,$84,$80
	dc.b	$84,$80,$80,$84,$80,$84,$84,$80,$80,$84,$84,$80,$84,$80,$80,$84
	dc.b	$80,$84,$84,$80,$84,$80,$84,$80,$84,$80,$80,$84,$80,$84,$84,$80
	dc.b	$80,$84,$84,$80,$84,$80,$84,$80,$84,$80,$80,$84,$80,$84,$84,$80
	dc.b	$84,$80,$80,$84,$80,$84,$84,$80,$80,$84,$84,$80,$84,$80,$80,$84
	page
*************************************************************************
*									*
*	Z-80 opcode dispatch table.  One longword entry per opcode	*
*	of the target (Z-80) processor, including illegals.		*
*									*
*************************************************************************

CBoptab:
	dc.l	rlcb,rlcc,rlcd,rlce,rlch,rlcl,rlcm,rlca 		;CB00
	dc.l	rrcb,rrcc,rrcd,rrce,rrch,rrcl,rrcm,rrca 		;CB08
	dc.l	rlrb,rlrc,rlrd,rlre,rlrh,rlrl,rlrm,rlra 		;CB10
	dc.l	rrrb,rrrc,rrrd,rrre,rrrh,rrrl,rrrm,rrra 		;CB18
	dc.l	slab,slac,slad,slae,slah,slal,slam,slaa 		;CB20
	dc.l	srab,srac,srad,srae,srah,sral,sram,sraa 		;CB28
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;CB30
	dc.l	srlb,srlc,srld,srle,srlh,srll,srlm,srla 		;CB38
	dc.l	bit0b,bit0c,bit0d,bit0e,bit0h,bit0l,bit0m,bit0a 	;CB40
	dc.l	bit1b,bit1c,bit1d,bit1e,bit1h,bit1l,bit1m,bit1a 	;CB48
	dc.l	bit2b,bit2c,bit2d,bit2e,bit2h,bit2l,bit2m,bit2a 	;CB50
	dc.l	bit3b,bit3c,bit3d,bit3e,bit3h,bit3l,bit3m,bit3a 	;CB58
	dc.l	bit4b,bit4c,bit4d,bit4e,bit4h,bit4l,bit4m,bit4a 	;CB60
	dc.l	bit5b,bit5c,bit5d,bit5e,bit5h,bit5l,bit5m,bit5a 	;CB68
	dc.l	bit6b,bit6c,bit6d,bit6e,bit6h,bit6l,bit6m,bit6a 	;CB70
	dc.l	bit7b,bit7c,bit7d,bit7e,bit7h,bit7l,bit7m,bit7a 	;CB78
	dc.l	res0b,res0c,res0d,res0e,res0h,res0l,res0m,res0a 	;CB80
	dc.l	res1b,res1c,res1d,res1e,res1h,res1l,res1m,res1a 	;CB88
	dc.l	res2b,res2c,res2d,res2e,res2h,res2l,res2m,res2a 	;CB90
	dc.l	res3b,res3c,res3d,res3e,res3h,res3l,res3m,res3a 	;CB98
	dc.l	res4b,res4c,res4d,res4e,res4h,res4l,res4m,res4a 	;CBA0
	dc.l	res5b,res5c,res5d,res5e,res5h,res5l,res5m,res5a 	;CBA8
	dc.l	res6b,res6c,res6d,res6e,res6h,res6l,res6m,res6a 	;CBB0
	dc.l	res7b,res7c,res7d,res7e,res7h,res7l,res7m,res7a 	;CBB8
	dc.l	set0b,set0c,set0d,set0e,set0h,set0l,set0m,set0a 	;CBC0
	dc.l	set1b,set1c,set1d,set1e,set1h,set1l,set1m,set1a 	;CBC8
	dc.l	set2b,set2c,set2d,set2e,set2h,set2l,set2m,set2a 	;CBD0
	dc.l	set3b,set3c,set3d,set3e,set3h,set3l,set3m,set3a 	;CBD8
	dc.l	set4b,set4c,set4d,set4e,set4h,set4l,set4m,set4a 	;CBE0
	dc.l	set5b,set5c,set5d,set5e,set5h,set5l,set5m,set5a 	;CBE8
	dc.l	set6b,set6c,set6d,set6e,set6h,set6l,set6m,set6a 	;CBF0
	dc.l	set7b,set7c,set7d,set7e,set7h,set7l,set7m,set7a 	;CBF8

DDoptab:
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;DD00
	dc.l	illgED,dadixb,illgED,illgED,illgED,illgED,illgED,illgED ;DD08
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;DD10
	dc.l	illgED,dadixd,illgED,illgED,illgED,illgED,illgED,illgED ;DD18
	dc.l	illgED,lxiix,sixd,inxix,inrxh,dcrxh,mvixh,illgED	;DD20
	dc.l	illgED,dadixx,lixd,dcxix,inrxl,dcrxl,mvixl,illgED	;DD28
	dc.l	illgED,illgED,illgED,illgED,inrix,dcrix,mviix,illgED	;DD30
	dc.l	illgED,dadixs,illgED,illgED,illgED,illgED,illgED,illgED ;DD38
	dc.l	illgED,illgED,illgED,illgED,movbxh,movbxl,movbix,illgED ;DD40
	dc.l	illgED,illgED,illgED,illgED,movcxh,movcxl,movcix,illgED ;DD48
	dc.l	illgED,illgED,illgED,illgED,movdxh,movdxl,movdix,illgED ;DD50
	dc.l	illgED,illgED,illgED,illgED,movexh,movexl,moveix,illgED ;DD58
	dc.l	movxhb,movxhc,movxhd,movxhe,mvxhxh,mvxhxl,movhix,illgED ;DD60
	dc.l	movxlb,movxlc,movxld,movxle,mvxlxh,mvxlxl,movlix,illgED ;DD60
	dc.l	movixb,movixc,movixd,movixe,movixh,movixl,illgED,movixa ;DD70
	dc.l	illgED,illgED,illgED,illgED,movaxh,movaxl,movaix,illgED ;DD78
	dc.l	illgED,illgED,illgED,illgED,addxh,addxl,addix,illgED	;DD80
	dc.l	illgED,illgED,illgED,illgED,adcxh,adcxl,adcix,illgED	;DD88
	dc.l	illgED,illgED,illgED,illgED,subxh,subxl,subix,illgED	;DD90
	dc.l	illgED,illgED,illgED,illgED,sbbxh,sbbxl,sbbix,illgED	;DD98
	dc.l	illgED,illgED,illgED,illgED,anaxh,anaxl,anaix,illgED	;DDA0
	dc.l	illgED,illgED,illgED,illgED,xraxh,xraxl,xraix,illgED	;DDA8
	dc.l	illgED,illgED,illgED,illgED,oraxh,oraxl,oraix,illgED	;DDB0
	dc.l	illgED,illgED,illgED,illgED,cmpxh,cmpxl,cmpix,illgED	;DDB8
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;DDC0
	dc.l	illgED,illgED,illgED,prDDCB,illgED,illgED,illgED,illgED ;DDC8
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;DDD0
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;DDD8
	dc.l	illgED,popix,illgED,xtix,illgED,pushix,illgED,illgED	;DDE0
	dc.l	illgED,pcix,illgED,illgED,illgED,illgED,illgED,illgED	;DDE8
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;DDF0
	dc.l	illgED,spix,illgED,illgED,illgED,illgED,illgED,illgED	;DDF8

DDCBopt:
	dc.l	rlcix,rrcix,rlix,rrix,slaix,sraix,ilgDDCB,srlix 	;DDCB06
	dc.l	bit0ix,bit1ix,bit2ix,bit3ix,bit4ix,bit5ix,bit6ix,bit7ix ;DDCB46
	dc.l	res0ix,res1ix,res2ix,res3ix,res4ix,res5ix,res6ix,res7ix ;DDCB86
	dc.l	set0ix,set1ix,set2ix,set3ix,set4ix,set5ix,set6ix,set7ix ;DDCBC6

EDoptab:
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED00
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED08
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED10
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED18
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED20
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED28
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED30
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED38
	dc.l	inbc,outcb,dsbbb,sbcd,nega,retn,im0,moveia		;ED40
	dc.l	incc,outcc,dadcb,lbcd,illgED,reti,illgED,movera 	;ED48
	dc.l	indc,outcd,dsbbd,sded,illgED,illgED,im1,moveai		;ED50
	dc.l	inec,outce,dadcd,lded,illgED,illgED,im2,movear		;ED58
	dc.l	inhc,outch,dsbbh,shld,illgED,illgED,illgED,rrd		;ED60
	dc.l	inlc,outcl,dadch,lhld,illgED,illgED,illgED,rld		;ED68
	dc.l	inmc,outcm,dsbbs,sspd,illgED,illgED,illgED,illgED	;ED70
	dc.l	inac,outca,dadcs,lspd,illgED,illgED,illgED,illgED	;ED78
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED80
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED88
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED90
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;ED98
	dc.l	ldi,cmpi,ini,outi,illgED,illgED,illgED,illgED		;EDA0
	dc.l	ldd,cpd,ind,outd,illgED,illgED,illgED,illgED		;EDA8
	dc.l	ldir,cpir,inir,otir,illgED,illgED,illgED,illgED 	;EDB0
	dc.l	lddr,cpdr,indr,otdr,illgED,illgED,illgED,illgED 	;EDB8
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;EDC0
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;EDC8
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;EDD0
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;EDD8
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;EDE0
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;EDE8
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;EDF0
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;EDF8

FDoptab:
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;FD00
	dc.l	illgED,dadiyb,illgED,illgED,illgED,illgED,illgED,illgED ;FD08
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;FD10
	dc.l	illgED,dadiyd,illgED,illgED,illgED,illgED,illgED,illgED ;FD18
	dc.l	illgED,lxiiy,siyd,inxiy,inryh,dcryh,mviyh,illgED	;FD20
	dc.l	illgED,dadiyy,liyd,dcxiy,inryl,dcryl,mviyl,illgED	;FD28
	dc.l	illgED,illgED,illgED,illgED,inriy,dcriy,mviiy,illgED	;FD30
	dc.l	illgED,dadiys,illgED,illgED,illgED,illgED,illgED,illgED ;FD38
	dc.l	illgED,illgED,illgED,illgED,movbyh,movbyl,movbiy,illgED ;FD40
	dc.l	illgED,illgED,illgED,illgED,movcyh,movcyl,movciy,illgED ;FD48
	dc.l	illgED,illgED,illgED,illgED,movdyh,movdyl,movdiy,illgED ;FD50
	dc.l	illgED,illgED,illgED,illgED,moveyh,moveyl,moveiy,illgED ;FD58
	dc.l	movyhb,movyhc,movyhd,movyhe,mvyhyh,mvyhyl,movhiy,illgED ;FD60
	dc.l	movylb,movylc,movyld,movyle,mvylyh,mvylyl,movliy,illgED ;FD60
	dc.l	moviyb,moviyc,moviyd,moviye,moviyh,moviyl,illgED,moviya ;FD70
	dc.l	illgED,illgED,illgED,illgED,movayh,movayl,movaiy,illgED ;FD78
	dc.l	illgED,illgED,illgED,illgED,addyh,addyl,addiy,illgED	;FD80
	dc.l	illgED,illgED,illgED,illgED,adcyh,adcyl,adciy,illgED	;FD88
	dc.l	illgED,illgED,illgED,illgED,subyh,subyl,subiy,illgED	;FD90
	dc.l	illgED,illgED,illgED,illgED,sbbyh,sbbyl,sbbiy,illgED	;FD98
	dc.l	illgED,illgED,illgED,illgED,anayh,anayl,anaiy,illgED	;FDA0
	dc.l	illgED,illgED,illgED,illgED,xrayh,xrayl,xraiy,illgED	;FDA8
	dc.l	illgED,illgED,illgED,illgED,orayh,orayl,oraiy,illgED	;FDB0
	dc.l	illgED,illgED,illgED,illgED,cmpyh,cmpyl,cmpiy,illgED	;FDB8
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;FDC0
	dc.l	illgED,illgED,illgED,prFDCB,illgED,illgED,illgED,illgED ;FDC8
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;FDD0
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;FDD8
	dc.l	illgED,popiy,illgED,xtiy,illgED,pushiy,illgED,illgED	;FDE0
	dc.l	illgED,pciy,illgED,illgED,illgED,illgED,illgED,illgED	;FDE8
	dc.l	illgED,illgED,illgED,illgED,illgED,illgED,illgED,illgED ;FDF0
	dc.l	illgED,spiy,illgED,illgED,illgED,illgED,illgED,illgED	;FDF8

* FDCBopt is not necessary - DDCBopt can be used,
*  since the operand address is in D0 for both routines.


	bss	bss

	even

tracesad ds.l	1		;Start address for trace
traceead ds.l	1		;End address for trace
traceflg ds.b	1		;Trace activity flag
tmprega  ds.b	1		;Work area
	end
SHAR_EOF
cat << \SHAR_EOF > simcpm1.asm2
	beq.s	getlinc 	;Yes - stop here.
	cmpi.b	#lf,(a1)	;Stop on a line feed too.
	beq.s	getlinc
	cmpi.b	#bs,(a1)	;Backspace?
	bne.s	getlinp 	;No.
	tst.b	1(a0)		;Do we have anything yet?
	beq.s	getlinl 	;No - ignore the backspace.
	subq.l	#1,a1		;Back over the previous character.
	subq.b	#1,1(a0)	;Decrement character count.
	movem.l a0-a1,-(sp)
	move.l	#bsmsg,d1
	bsr	pstring 	;Erase the previous character on the screen.
	movem.l (sp)+,a0-a1
	bra.s	getlinl
bsmsg	dc.b	bs,' ',bs,'$'	;Erases the previous character
getlinp movem.l a0-a1,-(sp)
	sys	Write		;Echo the current character.
	movem.l (sp)+,a0-a1
	addq.b	#1,1(a0)	;Bump character count.
	move.b	1(a0),d0	;Number of bytes read so far.
	cmpi.b	#3,(a1)+	;Did we get a control-C?
	bne.s	1$		;No.
	cmpi.b	#1,d0		;Is is the first character?
	beq.s	getlinx 	;Yes - exit now.
1$	cmp.b	(a0),d0 	;Is the buffer full?
	bne.s	getlinl 	;No - try for another character.
	bra.s	getlinx
getlinc bsr	pcrlf		;Carriage return or line feed
getlinx movem.l (sp)+,d2-d3/a0-a1/a6
	rts			;Exit.

*
* Display the message pointed to by D1.
*  The message must be terminated by a dollar sign.
*
pstring movem.l d2-d3/a1-a2,-(sp)	;Save work registers.
	move.l	d1,a0		;A0 scans the message.
	bset	#0,testdol	;Suppress $ test?
	beq.s	pstrs		;Yes (used by BDOS/BIOS character output)
	cmpi.b	#'$',(a0)	;Null string?
	beq	pstrx		;Yes - do nothing.
pstrs	move.l	strptr,a1	;A1 loads the output buffer.
	move.l	#strbufn,d3
	sub.l	a1,d3		;Number of bytes left in buffer
	ifne	h19
	moveq	#0,d0
	move.w	esclen,d0	;Is a partial escape sequence saved?
	beq.s	pstrl		;No.
	lea	escbuf,a2
	adda.l	d0,a2		;Continue loading it here.
	clr.w	esclen		;Reset "saved length" counter.
	cmpi.w	#2,d0		;Did we just save one byte?
	bcs.s	pstresc 	;Yes - get the remainder.
	bhi	pstreY2 	;Get the last cursor positioning byte.
	subq.l	#1,a2		;Back over dummy byte.
	bra	pstreY1 	;Get both cursor positioning bytes.
	endc
pstrl	cmpi.b	#lf,(a0)	;Line feed?
	bne.s	notlf		;No.
	lea	escbuf,a2	;Translate it to a cursor-down sequence.
	move.b	#$9B,(a2)+
	move.b	#'B',(a2)+
	addq.l	#1,a0
	bra	pstrsub
notlf:
	ifne	h19
* Optional H19 escape sequence translation
	cmpi.b	#esc,(a0)	;Escape character?
	bne	pstrm		;No - treat it normally.
	lea	escbuf,a2	;Build translated escape sequence here.
	move.b	#$9B,(a2)+	;Start with an AmigaDOS escape character.
	addq.l	#1,a0		;Check the next character.
	cmpi.b	#'$',(a0)	;End of string?
	bne.s	pstresc 	;No - analyze the sequence.
	move.w	#1,esclen	;We've saved one byte for next time.
	bra	pstrw		;Write everything up to the ESC character.
pstresc move.b	(a0)+,d0
	cmpi.b	#'[',d0 	;ANSI escape sequence?
	beq	pstrsub 	;Yes - pass the sequence with $9B header.
	cmpi.b	#'Y',d0
	beq.s	pstreY		;Set cursor position.
	cmpi.b	#'@',d0
	beq.s	pstrein 	;Set insert mode.
	cmpi.b	#'A',d0
	bcs	pstreun 	;Unknown code - copy it as is.
	cmpi.b	#'O',d0
	beq.s	pstreO		;Reset insert mode.
	bhi	pstreun 	;Unknown code
	move.l	a0,-(sp)
	lea	esctran(pc),a0	;Translation table with offset
	move.b	-'A'(a0,d0.w),d2;Get the translated code.
	move.l	(sp)+,a0
	btst	#6,d2		;Does the translated code stand alone?
	bne.s	1$		;No.
	subq.l	#1,a2		;Back over stored CSI character.
1$	move.b	d2,(a2)+	;Get the translated code.
	bra.s	pstrsub
esctran dc.b	'ABCD',ff,so,si,'H',$8D,'JKLMP' ;Escape sequence translation
pstrein move.b	#1,insflag	;Set insert mode.
	bra.s	pstrsbx
pstreO	clr.b	insflag 	;Reset insert mode.
	bra.s	pstrsbx
pstreY	cmpi.b	#'Y',d0 	;Set cursor position
	bne.s	pstreun
	cmpi.b	#'$',(a0)	;End of string?
	bne.s	pstreY1 	;No.
	move.w	#2,esclen	;Indicate we need both position bytes.
	bra	pstrw		;Finish the sequence next time.
pstreY1 moveq	#0,d0
	move.b	(a0)+,d0	;Get the first position byte.
	bsr	pstrcvd 	;Convert to decimal in save area.
	move.b	#';',(a2)+	;Add the separator character.
	cmpi.b	#'$',(a0)	;End of string?
	bne.s	pstreY2 	;No.
	sub.l	#escbuf,a2	;Number of bytes saved
	move.w	a2,esclen
	bra	pstrw		;Get the last byte next time.
pstreY2 moveq	#0,d0
	move.b	(a0)+,d0	;Get the last position byte.
	bsr	pstrcvd 	;Convert to decimal in save area.
	move.b	#'H',(a2)+	;Terminate the sequence.
	bra.s	pstrsub
pstreun move.b	#esc,escbuf	;Unidentified escape sequence -
	move.b	d0,(a2)+	; pass it through as is.
	endc
* The translated escape sequence is now in "escbuf" -
*  copy it to the output buffer.
pstrsub move.l	a2,d0
	lea	escbuf,a2	;A2 scans translated escape sequence.
	sub.l	a2,d0		;Length of translated escape sequence
	subq.l	#1,d0
1$	move.b	(a2)+,(a1)+	;Copy substitution to output string.
	subq.w	#1,d3		;Count down remaining length.
	dbra	d0,1$
pstrsbx cmpi.b	#'$',(a0)	;End of string?
	beq	pstrw		;Yes - write it out.
	tst.w	d3		;Is the buffer full?
	bmi	pstrw		;Yes - write out what we have.
	cmpi.b	#lf,-1(a0)	;Line feed?
	bne	pstrl		;No.
	tst.b	bufflag 	;Is console buffering in effect?
	beq	pstrl		;No.
	move.l	a1,strptr
	bsr	dmpstr		;Dump the buffer.
	move.l	strptr,a1
	bra	pstrl		;Check for another escape sequence.
* Subroutine to convert the byte in D0 to a character string at (A2)+
pstrcvd subi.b	#' '-1,d0	;Convert to binary row or column number.
	divu	#10,d0		;Convert to tens and units.
	tst.w	d0		;Is the number 10 or greater?
	beq.s	1$		;No - just create a one-digit number.
	addi.b	#'0',d0 	;Convert the tens digit to ASCII.
	move.b	d0,(a2)+	;Move it to the result field.
1$	swap	d0		;Get the units digit.
	addi.b	#'0',d0 	;Convert it to ASCII.
	move.b	d0,(a2)+
	rts
* Normal character processing
pstrm	tst.b	insflag 	;Are we in insert mode?
	beq.s	pstrmv		;No.
	lea	escbuf,a2
	move.b	#$9B,(a2)+	;Build an insert-character sequence.
	move.b	#'@',(a2)+
	move.b	(a0)+,(a2)+	;Here's the character to insert.
	bra.s	pstrsub 	;Use the substitution routine.
pstrmv	move.b	(a0)+,(a1)+	;Move one character.
	tst.b	bufflag 	;Is console buffering in effect?
	beq.s	2$		;No.
	cmpi.b	#cr,-1(a0)	;Carriage return?
	beq.s	1$		;Yes - dump the current segment.
	cmpi.b	#bel,-1(a0)	;Bell?
	bne.s	2$		;No - continue buffering.
1$	move.l	a1,strptr
	bsr	dmpstr		;Dump the buffer.
	move.l	strptr,a1
2$	cmpi.b	#'$',(a0)	;Test for end of string.
	dbeq	d3,pstrl	;Loop until we get there or buffer is full.
pstrw	move.l	a1,strptr
	tst	d3		;Is the buffer full?
	bmi.s	1$		;Yes - dump it regardless.
	tst.b	bufflag 	;Is console buffering in effect?
	bne.s	2$		;Yes - don't write anything yet.
1$	bsr	dmpstr		;Dump the buffer.
	move.l	strptr,a1
2$	tst	d3		;Did the output buffer overflow?
	bmi	pstrs		;Yes - get another section of the message.
pstrx	movem.l (sp)+,d2-d3/a1-a2	;Restore registers
	rts
*
* Write the contents of "strbuf" to RAW: if possible, or stdout if not.
*  The number of bytes to be written is calculated from "strptr".
*
dmpstr	movem.l d2-d3/a0-a1/a6,-(sp)
	move.l	strptr,d3
	move.l	#strbuf,d2	;Address of buffer
	move.l	d2,strptr	;Reset the buffer pointer.
	sub.l	d2,d3		;Length of output string
	beq.s	2$		;Zero - don't write anything.
	move.l	rawhand,d1	;Assume we're writing to RAW:
	bne.s	1$
	move.l	stdout,d1	;We don't have RAW: - use stdout.
1$	move.l	_DOSBase,a6
	sys	Write		;Display the line.
2$	movem.l (sp)+,d2-d3/a0-a1/a6
	rts

*
* Convert the file name in the FCB pointed to by A0
*  to an AmigaDOS-format file name in the field pointed to by A1.
*  D0 is the only other register used by this routine.
*
convfn	move.l	a1,-(sp)
	move.l	a0,-(sp)	;Save start address of FCB.
	move.b	(a0)+,d0	;Get the drive code.
	bne.s	1$		;We have a drive code.
	move.b	target+4,d0	;Use the default drive code.
	andi.b	#$0F,d0
	addq.b	#1,d0		;Start at 1 for drive A:.
1$	cmpi.b	#1,d0		;Is it drive A:?
	beq.s	4$		;Yes - don't add anything special.
	move.b	#'C',(a1)+
	move.b	#'P',(a1)+	;Set up the prefix CPMx:
	move.b	#'M',(a1)+	; where x is the drive letter.
	add.b	#'A'-1,d0
	move.b	d0,(a1)+
	move.b	target+4,d0	;Get user number.
	lsr.b	#4,d0		;Move it to low-order 4 bits.
	beq.s	3$		;Don't insert user number if it's zero.
	move.b	#'0',(a1)+	;Assume user number is less than 10.
	cmpi.b	#10,d0		;Is user number 10 or greater?
	bcs.s	2$		;No.
	move.b	#'1',-1(a1)	;Change the first digit to 1.
	subi.b	#10,d0
2$	addi.b	#'0',d0 	;Convert user number to ASCII.
	move.b	d0,(a1)+	;Insert user number into file spec.
3$	move.b	#':',(a1)+
4$	moveq	#7,d0		;Maximum of 8 characters for file name
convfn1 cmpi.b	#' ',(a0)	;End of file name?
	beq.s	3$		;Yes
	cmpi.b	#'*',(a0)	;Wild card?
	bne.s	1$		;No.
	move.b	#'#',(a1)+	;Convert to AmigaDOS format.
	move.b	#'?',(a1)+
	addq.l	#1,a0		;Skip over the asterisk.
	bra.s	2$
1$	move.b	(a0)+,(a1)+	;Move one character of file name.
2$	dbra	d0,convfn1	;Try for more.
3$	movea.l (sp)+,a0	;Back to start of FCB.
	lea	9(a0),a0	;Go to start of file name extension.
	cmpi.b	#' ',(a0)	;Do we have an extension?
	beq.s	convfnx 	;No.
	move.b	#'.',(a1)+	;Insert extension separator.
	moveq	#2,d0		;Maximum of 3 characters for extension.
convfn2 cmpi.b	#' ',(a0)	;End of extension?
	beq.s	convfnx 	;Yes.
	cmpi.b	#'*',(a0)	;Wild card?
	bne.s	1$		;No.
	move.b	#'#',(a1)+	;Convert to AmigaDOS format.
	move.b	#'?',(a1)+
	addq.l	#1,a0		;Skip over the asterisk.
	bra.s	2$
1$	move.b	(a0)+,(a1)+	;Move one character of extension.
2$	dbra	d0,convfn2	;Try for more.
convfnx clr.b	(a1)		;Terminate file name string.
	move.l	(sp)+,a1
	rts

*
* Get the file handle indicated by the first 12 bytes of the CP/M FCB
*  whose CP/M address is in D1.  The file handle (if found) is copied
*  to D1 from the file handle table entry (which is pointed to by A1).
*  If the file handle cannot be found, D1 will be set to zero.
*  In any event, A0 will be set to point to the FCB.
*
gethand	lea	0(targbase,d1.l),a0	;The FCB is here.
	lea	handles,a1	;A1 scans the file handle table.
	moveq	#(handlen-handles)/16-1,d0
1$	movem.l	d0/a0-a1,-(sp)
	tst.l	(a1)		;Is this entry empty?
	beq.s	3$		;Yes - ignore it.
	addq.l	#4,a1		;Skip over to file name in table.
	moveq	#11,d1
2$	cmp.b	(a0)+,(a1)+	;Compare first 12 bytes of FCB with table.
	bne.s	3$		;No match.
	dbra	d1,2$
	movem.l	(sp)+,d0/a0-a1
	move.l	(a1),d1		;Here's the file handle.
	rts
3$	movem.l	(sp)+,d0/a0-a1
	lea	16(a1),a1	;Try the next table entry.
	dbra	d0,1$
	moveq	#0,d1		;Couldn't find the handle!
	rts
	page
*************************************************************************
*									*
*	Serial port routines						*
*									*
*************************************************************************

*
* Read a byte from the port whose number is in D0.
*  A0 points to where to put it.
*
inp	movem.l a1/a6/d2-d3,-(sp)
	cmp.b	#$14,d0 	;Port 14?
	bne.s	inp15		;No.
	move.l	a0,-(sp)
	tst.l	rpport		;Is serial.device open?
	bne.s	1$		;Yes.
	bsr	initser 	;Set up serial.device.
1$	bsr	checkio
	tst.l	d0		;Is a character ready?
	beq.s	2$		;No - give the previous one again.
	bsr	serread 	;Read the new character.
2$	move.l	(sp)+,a0
	move.b	charin,(a0)	;Move it to user's area.
	bra.s	inpx
inp15	cmp.b	#$15,d0 	;Port 15?
	bne.s	inpx		;No - ignore it.
	move.b	#7,(a0) 	;Assume a character is ready.
	move.l	a0,-(sp)
	bsr	checkio 	;Check whether a character is ready.
	move.l	(sp)+,a0
	tst.l	d0		;Is a character ready?
	bne.s	inpx		;Yes.
	move.b	#5,(a0) 	;Don't set "receiver ready" bit.
inpx	movem.l (sp)+,a1/a6/d2-d3
	rts

*
* Write the byte pointed to by A0 to the port whose number is in D0.
*
outp	movem.l a1/a6/d2-d3,-(sp)
	cmp.l	#$14,d0 	;Port 14?
	bne.s	outpx		;No - ignore it.
	move.b	(a0),charout	;Character to write
	tst.l	rpport		;Is serial.device open?
	bne.s	1$		;Yes.
	bsr	initser 	;Set up serial.device.
1$	bsr	serwrit 	;Write the character.
outpx	movem.l (sp)+,a1/a6/d2-d3
	rts

*
* Initialize the serial port.
*
initser:

* Open a reply port for the serial input device.
	lea	readreq,a0
	move.w	#rsize-1,d0
1$	clr.b	(a0)+		;Clear the I/O request block.
	dbra	d0,1$
	clr.l	-(sp)
	move.l	#2$,-(sp)
	jsr	_CreatePort	;rpport = CreatePort ("Read_RS", NULL);
	addq.l	#8,sp
	move.l	d0,rpport
	move.l	d0,r_ReplyPort
	bne.s	openin
	move.l	#3$,d1
	bsr	pstring
	bra	quitprg
2$	dc.b	'Read_RS',0
3$	dc.b	'Can''t create input port for serial.device!',cr,lf,'$'

* Open the serial input device.
openin	move.w	#rsize,r_MLength
	move.b	#SERFLAGS,r_SerFlags
	move.l	#CTLCHAR,r_CtlChar
	lea	1$,a0
	moveq	#0,d0
	lea	readreq,a1
	moveq	#0,d1
	move.l	_SysBase,a6
	sys	OpenDevice
	tst.l	d0		;Were we successful?
	beq.s	setin		;Yes.
	move.l	#2$,d1
	bsr	pstring
	bra	quitprg
1$	dc.b	'serial.device',0
2$	dc.b	'Can''t open serial.device!',cr,lf,'$'

setin	move.l	baud,r_Baud
	move.b	bits,r_ReadLen	;Number of bits per character
	move.b	bits,r_WriteLen
	move.w	#SDCMD_SETPARAMS,r_Command
	lea	readreq,a1
	move.l	_SysBase,a6
	sys	DoIO		;Set new input port parameters.

* Set up the serial output port.
	lea	readreq,a0
	lea	writreq,a1
	move.w	#wsize-1,d0
copw	move.b	(a0)+,(a1)+	;Clone the read request block.
	dbra	d0,copw
	clr.l	-(sp)
	move.l	#1$,-(sp)
	jsr	_CreatePort	;wpport = CreatePort ("Write_RS", NULL);
	addq.l	#8,sp
	move.l	d0,wpport
	move.l	d0,w_ReplyPort
	bne.s	startup
	move.l	#2$,d1
	bsr	pstring
	bra	quitprg
1$	dc.b	'Write_RS',0
2$	dc.b	'Can''t create output port for serial.device!',cr,lf,'$'

startup bsr	setbaud 	;Set parameters and start reading.
	rts

*
* Return TRUE (D0 <> 0) if the serial port has a character.
*
checkio lea	readreq,a1
	move.l	_SysBase,a6
	sys	CheckIO
	rts

*
* Set the serial port's baud rate, number of data bits, etc.
*
setbaud tas	frstset 	;Is this the first call?
	beq.s	1$		;Yes - input port is set up.
	lea	readreq,a1
	move.l	_SysBase,a6
	sys	AbortIO 	;Abort the outstanding read.
	move.l	baud,r_Baud	;Baud rate
	move.b	bits,r_ReadLen	;Number of bits per character
	move.b	bits,r_WriteLen
	move.w	#SDCMD_SETPARAMS,r_Command
	lea	readreq,a1
	move.l	_SysBase,a6
	sys	DoIO		;Set new input port parameters.
1$	move.w	#CMD_READ,r_Command
	move.l	#1,r_Length
	move.l	#charinb,r_Data
	lea	readreq,a1
	move.l	_SysBase,a6
	sys	SendIO		;Start reading again.
* Now set up the output port - this one is more straightforward.
	move.l	baud,w_Baud
	move.b	bits,w_ReadLen
	move.b	bits,w_WriteLen
	move.w	#SDCMD_SETPARAMS,w_Command
	lea	writreq,a1
	move.l	_SysBase,a6
	sys	DoIO
	rts

*
* Write the byte in "charout" to the serial port.
*
serwrit move.w	#CMD_WRITE,w_Command
	move.l	#1,w_Length
	move.l	#charout,w_Data
	lea	writreq,a1
	move.l	_SysBase,a6
	sys	DoIO
	rts

*
* Read a byte from the serial port into "charin".
*  If a byte isn't ready, this routine will wait until one is.
*
serread lea	readreq,a1
	move.l	_SysBase,a6
	sys	WaitIO		;Wait until a character is ready.
	move.b	charinb,charin	;Get the character from the buffer.
	move.w	#CMD_READ,r_Command
	move.l	#1,r_Length
	move.l	#charinb,r_Data
	lea	readreq,a1
	move.l	_SysBase,a6
	sys	SendIO		;Get ready for the next character.
	rts
	page
*************************************************************************
*									*
*	Miscellaneous service routines					*
*	(Inelegant, but rarely used so they stand as is.)		*
*									*
*************************************************************************

*
* Display the contents of D1 in hex.
*
pbyte	move.l	#$20018,d0	;2 nybbles, 24-bit shift first
	bra.s	phex
pword	move.l	#$40010,d0	;4 nybbles, 16-bit shift first
	bra.s	phex
paddr	move.l	#$60008,d0	;6 nybbles, 8-bit shift first
	bra.s	phex
plong	move.l	#$80000,d0	;8 nybbles, no shift first
phex	lea	workbuf,a0
	move.l	a0,-(sp)
	bsr	pdigits
	move.b	#'$',(a0)+
	move.l	(sp)+,d1
	bsr	pstring
	rts
*
* Convert the contents of D1 to hex at (A0).
*  On exit, A0 points to the next available byte.
*
ubyte	move.l	#$20018,d0	;2 nybbles, 24-bit shift first
	bra.s	pdigits
uword	move.l	#$40010,d0	;4 nybbles, 16-bit shift first
	bra.s	pdigits
uaddr	move.l	#$60008,d0	;6 nybbles, 8-bit shift first
	bra.s	pdigits
ulong	move.l	#$80000,d0	;8 nybbles, no shift first
pdigits rol.l	d0,d1		;Do shift.
	bra.s	3$
1$	swap	d0		;Save nybble count.
	rol.l	#4,d1		;Print variable in d1.
	move.l	d1,-(sp)
	and	#$F,d1		;Isolate the current nybble.
	cmp	#$A,d1
	bcs.s	2$
	add.b	#'A'-'9'-1,d1	;Adjust for digits A through F.
2$	add.b	#'0',d1 	;Convert to ASCII.
	move.b	d1,(a0)+	;Add to the result string.
	move.l	(sp)+,d1
3$	swap	d0		;Get nybble count.
	dbra	d0,1$
	rts

pchar	move.b	d1,workbuf	;Print the character in D1.
	move.b	#'$',workbuf+1
	move.l	#workbuf,d1
	bsr	pstring
	rts

pspace	move.l	#1$,d1		;Print a space.
	bsr	pstring
	rts
1$	dc.b	' $'

pcrlf	move.l	#1$,d1		;Print a carriage return and line feed.
	bsr	pstring
	rts
1$	dc.b	cr,lf,'$'

*
* Convert the hex string pointed to by A0 to long in d1.
*  Stops on the first invalid hex digit, which is returned in d0.
*  A0 is left pointing to this first invalid digit.
*  d2 = 1 if any valid digits were found, 0 otherwise.
*
atol	moveq	#0,d1
	moveq	#0,d2
1$	move.b	(a0)+,d0	;Get the current byte.
	cmpi.b	#$60,d0
	bcs.s	2$
	andi.b	#$5F,d0 	;Mask to upper case.
2$	cmpi.b	#'0',d0 	;Check range (0..9,A..F).
	bcs.s	atolend
	cmpi.b	#'F',d0
	bhi.s	atolend
	cmpi.b	#'9',d0
	bls.s	3$
	cmpi.b	#'A',d0
	bcs.s	atolend
3$	moveq	#1,d2		;Valid characters entered, set flag.
	sub.b	#'0',d0 	;Convert to binary
	cmpi.b	#$9,d0		;Digit in range 0..9?
	bls.s	4$		;Yes - conversion is complete
	sub.b	#'A'-'9'-1,d0	;Adjust digits A..F.
4$	ext	d0		;Convert to long.
	ext.l	d0
	asl.l	#4,d1		;Tack it onto d1.
	add.l	d0,d1
	bra.s	1$		;Try for another digit.
atolend subq.l	#1,a0		;Back onto the first invalid digit.
	rts
	page
*************************************************************************
*									*
*	Instruction mnemonic table (used for tracing)			*
*									*
*************************************************************************

	data	data

* This table contains the mnemonic strings for the 8080/Z-80 opcodes.
*
* "q" denotes a register number in bits 3 through 5 of the opcode.
*	Values are interpreted as follows:
*		Normal 8080	Normal Z-80	DD prefix	FD prefix
*	000		B		B		B		B
*	001		C		C		C		C
*	010		D		D		D		D
*	011		E		E		E		E
*	100		H		H		XH		YH
*	101		L		L		XL		YL
*	110		M	     (HL)	    (IX+n)	    (IY+n)
*	111		A		A		A		A
*
* "r" denotes a register number in bits 0 through 2 of the opcode.
*	Values are interpreted the same as for "q" above.
*
* "p" denotes a 2-bit register pair number in bits 4 and 5 of the opcode.
*	Values are interpreted as follows:
*		8080	Z-80
*	00	B	BC
*	01	D	DE
*	10	H	HL	(no DD or FD prefix)
*	10	IX	IX	(with DD prefix)
*	10	IX	IX	(with FD prefix)
*	11	SP	SP	(if opcode is below F0)
*	11	PSW	AF	(if opcode is F0 or greater)
*
* "h" is replaced by IX or IY if the opcode prefix is DD or FD respectively.
*  If the instruction is not prefixed, "h" is replaced by HL.
*
* "n" denotes an 8-bit number following the opcode.
*
* "a" denotes a 16-bit address following the opcode.

* Mnemonics for 8080 opcodes 00 through 3F
mnop008:
	dc.b	'NOP$        LXI  p,a$   STAX p$     INX  p$     ' ;00-03
	dc.b	'INR  q$     DCR  q$     MVI  q,n$   RLC$        ' ;04-07
	dc.b	'EXAF$       DAD  p$     LDAX p$     DCX  p$     ' ;08-0B
	dc.b	'INR  q$     DCR  q$     MVI  q,n$   RRC$        ' ;0C-0F
	dc.b	'DJNZ n$     LXI  p,a$   STAX p$     INX  p$     ' ;10-13
	dc.b	'INR  q$     DCR  q$     MVI  q,n$   RAL$        ' ;14-17
	dc.b	'JR   n$     DAD  p$     LDAX p$     DCX  p$     ' ;18-1B
	dc.b	'INR  q$     DCR  q$     MVI  q,n$   RAR$        ' ;1C-1F
	dc.b	'JRNZ n$     LXI  p,a$   ShD a$      INX  p$     ' ;20-23
	dc.b	'INR  q$     DCR  q$     MVI  q,n$   DAA$        ' ;24-27
	dc.b	'JRZ  n$     DAD  p$     LhD a$      DCX  p$     ' ;28-2B
	dc.b	'INR  q$     DCR  q$     MVI  q,n$   CMA$        ' ;2C-2F
	dc.b	'JRNC n$     LXI  p,a$   STA  a$     INX  p$     ' ;30-33
	dc.b	'INR  q$     DCR  q$     MVI  q,n$   STC$        ' ;34-37
	dc.b	'JRC  n$     DAD  p$     LDA  a$     DCX  p$     ' ;38-3B
	dc.b	'INR  q$     DCR  q$     MVI  q,n$   CMC$        ' ;3C-3F

* Mnemonics for Z-80 opcodes 00 through 3F
mnop00z:
	dc.b	'NOP$        LD   p,a$   LD   (p),A$ INC  p$     ' ;00-03
	dc.b	'INC  q$     DEC  q$     LD   q,n$   RLCA$       ' ;04-07
	dc.b	'EX   AF,AF$ ADD  HL,p$  LD   A,(p)$ DEC  p$     ' ;08-0B
	dc.b	'INC  q$     DEC  q$     LD   q,n$   RRCA$       ' ;0C-0F
	dc.b	'DJNZ n$     LD   p,a$   LD   (p),A$ INC  p$     ' ;10-13
	dc.b	'INC  q$     DEC  q$     LD   q,n$   RLA$        ' ;14-17
	dc.b	'JR   n$     ADD  HL,p$  LD   A,(p)$ DEC  p$     ' ;18-1B
	dc.b	'INC  q$     DEC  q$     LD   q,n$   RRA$        ' ;1C-1F
	dc.b	'JR   NZ,n$  LD   p,a$   LD   (a),HL$INC  p$     ' ;20-23
	dc.b	'INC  q$     DEC  q$     LD   q,n$   DAA$        ' ;24-27
	dc.b	'JR   Z,n$   ADD  HL,p$  LD   HL,(a)$DEC  p$     ' ;28-2B
	dc.b	'INC  q$     DEC  q$     LD   q,n$   CPL$        ' ;2C-2F
	dc.b	'JR   NC,n$  LD   p,a$   LD   (a),A$ INC  p$     ' ;30-33
	dc.b	'INC  q$     DEC  q$     LD   q,n$   SCF$        ' ;34-37
	dc.b	'JR   C,n$   ADD  HL,p$  LD   A,(a)$ DEC  p$     ' ;38-3B
	dc.b	'INC  q$     DEC  q$     LD   q,n$   CCF$        ' ;3C-3F

* Mnemonics for opcodes 40 through 7f are easy - 76 is HLT
*  (HALT for Z-80), and all others are MOV (LD for Z-80).
mnop408 dc.b	'MOV  q,r$'
mnop40z dc.b	'LD   q,r$'
mnop768 dc.b	'HLT$'
mnop76z dc.b	'HALT$'

* Mnemonics for 8080 opcodes 80 through BF
mnop808:
	dc.b	'ADD  r$  ADC  r$  SUB  r$  SBB  r$  '	;80-9F
	dc.b	'ANA  r$  XRA  r$  ORA  r$  CMP  r$  '	;A0-BF

* Mnemonics for Z-80 opcodes 80 through BF
mnop80z:
	dc.b	'ADD  A,r$ADC  A,r$SUB  r$  SBC  A,r$'	;80-9F
	dc.b	'AND  r$  XOR  r$  OR   r$  CP   r$  '	;A0-BF

* Mnemonics for 8080 opcodes C0 through FF
*  These are interpreted by the same routine as for opcodes 00 through 3F.
mnopC08:
	dc.b	'RNZ$        POP  p$     JNZ  a$     JMP  a$     ' ;C0-C3
	dc.b	'CNZ  a$     PUSH p$     ADI  n$     RST  0$     ' ;C4-C7
	dc.b	'RZ$         RET$        JZ   a$     ILLEGAL$    ' ;C8-CB
	dc.b	'CZ   a$     CALL a$     ACI  n$     RST  1$     ' ;CC-CF
	dc.b	'RNC$        POP  p$     JNC  a$     OUT  n$     ' ;D0-D3
	dc.b	'CNC  a$     PUSH p$     SUI  n$     RST  2$     ' ;D4-D7
	dc.b	'RC$         EXX$        JC   a$     IN   n$     ' ;D8-DB
	dc.b	'CC   a$     ILLEGAL$    SBI  n$     RST  3$     ' ;DC-DF
	dc.b	'RPO$        POP  p$     JPO  a$     XTh$        ' ;E0-E3
	dc.b	'CPO  a$     PUSH p$     ANI  n$     RST  4$     ' ;E4-E7
	dc.b	'RPE$        PCh$        JPE  a$     XCHG$       ' ;E8-EB
	dc.b	'CPE  a$     ILLEGAL$    XRI  n$     RST  5$     ' ;EC-FF
	dc.b	'RP$         POP  p$     JP   a$     DI$         ' ;F0-F3
	dc.b	'CP   a$     PUSH p$     ORI  n$     RST  6$     ' ;F4-F7
	dc.b	'RM$         SPh$        JM   a$     EI$         ' ;F8-FB
	dc.b	'CM   a$     ILLEGAL$    CPI  n$     RST  7$     ' ;FC-FF

* Mnemonics for Z-80 opcodes C0 through FF
*  These are interpreted by the same routine as for opcodes 00 through 3F.
mnopC0z:
	dc.b	'RET  NZ$    LD   p,(SP)$JP   NZ,a$  JP   a$     ' ;C0-C3
	dc.b	'CALL NZ,a$  LD   (SP),p$ADD  A,n$   RST  0$     ' ;C4-C7
	dc.b	'RET  Z$     RET$        JP   Z,a$   ILLEGAL$    ' ;C8-CB
	dc.b	'CALL Z,a$   CALL a$     ADC  A,n$   RST  8$     ' ;CC-CF
	dc.b	'RET  NC$    LD   p,(SP)$JP   NC,a$  OUT  n,A$   ' ;D0-D3
	dc.b	'CALL NC,a$  LD   (SP),p$SUB  A,n$   RST  10$    ' ;D4-D7
	dc.b	'RET  C$     EXX$        JP   C,a$   IN   A,n$   ' ;D8-DB
	dc.b	'CALL C,a$   ILLEGAL$    SBC  A,n$   RST  18$    ' ;DC-DF
	dc.b	'RET  PO$    LD   p,(SP)$JP   PO,a$  EX   (SP),p$' ;E0-E3
	dc.b	'CALL PO,a$  LD   (SP),p$AND  A,n$   RST  20$    ' ;E4-E7
	dc.b	'RET  PE$    JP   (p)$   JP   PE,a$  EX   DE,p$  ' ;E8-EB
	dc.b	'CALL PE,a$  ILLEGAL$    XOR  A,n$   RST  28$    ' ;EC-FF
	dc.b	'RET  P$     LD   p,(SP)$JP   P,a$   DI$         ' ;F0-F3
	dc.b	'CALL P,a$   LD   (SP),p$OR   A,n$   RST  30$    ' ;F4-F7
	dc.b	'RET  M$     LD   SP,h$  JP   M,a$   EI$         ' ;F8-FB
	dc.b	'CALL M,a$   ILLEGAL$    CP   A,n$   RST  38$    ' ;FC-FF

* Mnemonics for opcodes CB00 through CB3F -
*  these are the same for both the 8080 and the Z-80.
mnopCB08:
mnopCB0z:
	dc.b	'RLC  r$ RRC  r$ RL   r$ RR   r$ '	;CB00-CB1F
	dc.b	'SLA  r$ SRA  r$ ILLEGAL$SRL  r$ '	;CB20-CB3F

* Mnemonics for opcodes CB40 through CBFF -
*  these are the same for both the 8080 and the Z-80.
mnopCB48:
mnopCB4z:
	dc.b	'BIT  $  RES  $  SET  $  '

* Mnemonics for 8080 opcodes ED40 through ED7F
*  These are interpreted by the same routine as for opcodes 00 through 3F.
mnopE48:
	dc.b	'IN   q,(C)$ OUT  (C),q$ DSBB p$     SBCD a$     ' ;ED40-ED43
	dc.b	'NEG$        RETN$       IM0$        MOV  I,A$   ' ;ED44-ED47
	dc.b	'IN   q,(C)$ OUT  (C),q$ DADC p$     LBCD a$     ' ;ED48-ED4B
	dc.b	'ILLEGAL$    RETI$       ILLEGAL$    MOV  R,A$   ' ;ED4C-ED4F
	dc.b	'IN   q,(C)$ OUT  (C),q$ DSBB p$     SDED a$     ' ;ED50-ED53
	dc.b	'ILLEGAL$    ILLEGAL$    IM1$        MOV  A,I$   ' ;ED54-ED57
	dc.b	'IN   q,(C)$ OUT  (C),q$ DADC p$     LDED a$     ' ;ED58-ED5B
	dc.b	'ILLEGAL$    ILLEGAL$    IM2$        MOV  A,R$   ' ;ED5C-ED5F
	dc.b	'IN   q,(C)$ OUT  (C),q$ DSBB p$     SHLD a$     ' ;ED60-ED63
	dc.b	'ILLEGAL$    ILLEGAL$    ILLEGAL$    RRD$        ' ;ED64-ED67
	dc.b	'IN   q,(C)$ OUT  (C),q$ DADC p$     LHLD a$     ' ;ED68-ED6B
	dc.b	'ILLEGAL$    ILLEGAL$    ILLEGAL$    RLD$        ' ;ED6C-ED6F
	dc.b	'IN   q,(C)$ OUT  (C),q$ DSBB p$     SSPD a$     ' ;ED70-ED73
	dc.b	'ILLEGAL$    ILLEGAL$    ILLEGAL$    ILLEGAL$    ' ;ED74-ED77
	dc.b	'IN   q,(C)$ OUT  (C),q$ DADC p$     LSPD a$     ' ;ED78-ED7B
	dc.b	'ILLEGAL$    ILLEGAL$    ILLEGAL$    ILLEGAL$    ' ;ED7C-ED7F

* Mnemonics for Z-80 opcodes ED40 through ED7F
*  These are interpreted by the same routine as for opcodes 00 through 3F.
mnopE4z:
	dc.b	'IN   q,(C)$ OUT  (C),q$ SBC  HL,p$  LD   (a),p$ ' ;ED40-ED43
	dc.b	'NEG$        RETN$       IM   0$     LD   I,A$   ' ;ED44-ED47
	dc.b	'IN   q,(C)$ OUT  (C),q$ ADC  HL,p$  LD   p,(a)$ ' ;ED48-ED4B
	dc.b	'ILLEGAL$    RETI$       ILLEGAL$    LD   R,A$   ' ;ED4C-ED4F
	dc.b	'IN   q,(C)$ OUT  (C),q$ SBC  HL,p$  LD   (a),p$ ' ;ED50-ED53
	dc.b	'ILLEGAL$    ILLEGAL$    IM   1$     LD   A,I$   ' ;ED54-ED57
	dc.b	'IN   q,(C)$ OUT  (C),q$ ADC  HL,p$  LD   p,(a)$ ' ;ED58-ED5B
	dc.b	'ILLEGAL$    ILLEGAL$    IM   2$     LD   A,R$   ' ;ED5C-ED5F
	dc.b	'IN   q,(C)$ OUT  (C),q$ SBC  HL,p$  LD   (a),p$ ' ;ED60-ED63
	dc.b	'ILLEGAL$    ILLEGAL$    ILLEGAL$    RRD$        ' ;ED64-ED67
	dc.b	'IN   q,(C)$ OUT  (C),q$ ADC  HL,p$  LD   p,(a)$ ' ;ED68-ED6B
	dc.b	'ILLEGAL$    ILLEGAL$    ILLEGAL$    RLD$        ' ;ED6C-ED6F
	dc.b	'IN   q,(C)$ OUT  (C),q$ SBC  HL,p$  LD   (a),p$ ' ;ED70-ED73
	dc.b	'ILLEGAL$    ILLEGAL$    ILLEGAL$    ILLEGAL$    ' ;ED74-ED77
	dc.b	'IN   q,(C)$ OUT  (C),q$ ADC  HL,p$  LD   p,(a)$ ' ;ED78-ED7B
	dc.b	'ILLEGAL$    ILLEGAL$    ILLEGAL$    ILLEGAL$    ' ;ED7C-ED7F

* Mnemonics for miscellaneous ED-prefix instructions -
*  these are the same for both the 8080 and the Z-80.
mnopEA8:
mnopEAz:
	dc.b	'LDI$ CPI$ INI$ OUTI$'	;EDA0-EDA3
	dc.b	'                    '	;EDA4-EDA7 (illegal)
	dc.b	'LDD$ CPD$ IND$ OUTD$'	;EDA8-EDAB
	dc.b	'                    '	;EDAC-EDAF (illegal)
	dc.b	'LDIR$CPIR$INIR$OTIR$'	;EDB0-EDB3
	dc.b	'                    '	;EDB4-EDB7 (illegal)
	dc.b	'LDDR$CPDR$INDR$OTDR$'	;EDB8-EDBB

* Mnemonic for illegal instructions
mnopilg dc.b	'ILLEGAL$'
	page
*************************************************************************
*									*
*	Fake FDOS							*
*									*
*************************************************************************

*
* Fake BDOS for target system
*
fdos	dc.b	tHLT,0,tRET	;BIOS jump table
	dc.b	tJMP,$33,$FF	;Warm boot
	dc.b	tJMP,$36,$FF	;Console status
	dc.b	tJMP,$39,$FF	;Console input
	dc.b	tJMP,$3C,$FF	;Console output
	dc.b	tJMP,$3F,$FF	;List output
	dc.b	tJMP,$42,$FF	;Punch output
	dc.b	tJMP,$45,$FF	;Reader input
	dc.b	tJMP,$48,$FF	;Home disk
	dc.b	tJMP,$4B,$FF	;Select disk
	dc.b	tJMP,$4E,$FF	;Set track
	dc.b	tJMP,$51,$FF	;Set sector
	dc.b	tJMP,$54,$FF	;Set DMA address
	dc.b	tJMP,$57,$FF	;Read
	dc.b	tJMP,$5A,$FF	;Write
	dc.b	tJMP,$5D,$FF	;Get list device status
	dc.b	tJMP,$60,$FF	;Sector translation

*
* Fake BIOS for target system
*
	dc.b	tHLT,1,tRET	;Warm boot
	dc.b	tHLT,2,tRET	;Console status
	dc.b	tHLT,3,tRET	;Console input
	dc.b	tHLT,4,tRET	;Console output
	dc.b	tHLT,5,tRET	;List output
	dc.b	tHLT,6,tRET	;Punch output
	dc.b	tHLT,7,tRET	;Reader input
	dc.b	tHLT,8,tRET	;Home disk *
	dc.b	tHLT,9,tRET	;Select disk *
	dc.b	tHLT,10,tRET	;Set track *
	dc.b	tHLT,11,tRET	;Set sector *
	dc.b	tHLT,12,tRET	;Set DMA address *
	dc.b	tHLT,13,tRET	;Read *
	dc.b	tHLT,14,tRET	;Write *
	dc.b	tHLT,15,tRET	;Get list device status *
	dc.b	tHLT,16,tRET	;Sector translation *

*
* Fake Disk Parameter Block
*
fakedpb	dc.b	11,0		;SPT (sectors per track)
	dc.b	4		;BSH (block shift to record number)
	dc.b	15		;BLM (block number mask to record no.)
	dc.b	0		;EXM (logical->physical extent shift)
	dc.b	439&255,439/256	;DSM (highest allocation block number)
	dc.b	255,0		;DRM (highest directory entry number)
	dc.b	$F0,0		;AL0, AL1 (initial allocation vector)
	dc.b	64,0		;CKS (size of directory check area)
	dc.b	0,0		;OFF (offset, number of reserved tracks)

*
* Fake Disk Block Allocation Table
*
fakealv	dcb.b	21,$FF
	dc.b	%11111100
	dcb.b	10,0

fdoslen equ	*-fdos

*
* BDOS function vector table
*
	cnop	0,4
bdostab dc.l	bdos00,bdos01,bdos02,bdos03,bdos04,bdos05,bdos06,bdos07
	dc.l	bdos08,bdos09,bdos10,bdos11,bdos12,bdos13,bdos14,bdos15
	dc.l	bdos16,bdos17,bdos18,bdos19,bdos20,bdos21,bdos22,bdos23
	dc.l	bdos24,bdos25,bdos26,bdos27,bdos28,bdos29,bdos30,bdos31
	dc.l	bdos32,bdos33,bdos34,bdos35,bdos36
bdostabn:

*
* BIOS function vector table
*
	cnop	0,4
biostab dc.l	bdosfn,bios01,bios02,bios03,bios04,bios05,bios06,bios07
	dc.l	bios08,bios09,bios10,bios11,bios12,bios13,bios14,bios15
biostabn:

null	dc.b	0		;Null string
	page
*************************************************************************
*									*
*	Variable storage						*
*									*
*************************************************************************

	bss	bss

* File information block - must be on a 4-byte boundary!
fib:
fibkey	ds.l	1
fibtype ds.l	1	;Type (file if negative, directory if positive)
fibname ds.b	108	;File name (null-terminated)
fibprot ds.l	1	;Protection mask
fibent	ds.l	1
fibsize ds.l	1	;Number of bytes in file
fibblks ds.l	1	;Number of blocks in file
fibdays ds.l	1	;Date stamp - number of days since Jan. 1, 1978
fibmins ds.l	1	;Date stamp - number of minutes past midnight
fibtick ds.l	1	;Date stamp - number of ticks past minute
fibcmt	ds.b	116	;Comments (null-terminated)

* InfoData structure
InfoData:
id_NumSoftErrors ds.l	1	;number of soft errors on disk
id_UnitNumber	 ds.l	1	;Which unit disk is (was) mounted on
id_DiskState	 ds.l	1	;See defines below
id_NumBlocks	 ds.l	1	;Number of blocks on disk
id_NumBlocksUsed ds.l	1	;Number of block in use
id_BytesPerBlock ds.l	1
id_DiskType	 ds.l	1	;Disk Type code
id_VolumeNode	 ds.l	1	;BCPL pointer to volume node
id_InUse	 ds.l	1	;Flag, zero if not in use
id_SIZEOF	 equ	36

* Miscellaneous storage areas
savesp	ds.l	1		;Stack pointer save area
_SysBase ds.l	1		;Copy of _AbsExecBase
_DOSBase ds.l	1		;Pointer to dos.library
stdin	ds.l	1		;Keyboard handle (stdin)
stdout	ds.l	1		;Screen handle (stdout)
rawhand ds.l	1		;RAW: file handle
prthand ds.l	1		;PRT:RAW file handle
handles ds.l	8*4		;File handle (or zero) plus 12 bytes of FCB
handlen:			;End of file handle table
dmaaddr ds.l	1		;Current DMA address
comend	ds.l	1		;End of .COM file name on command line
dtstamp ds.l	3		;Date and time stamp
rpport	ds.l	1		;Serial input message port
wpport	ds.l	1		;Serial output message port
baud	ds.l	1		;New baud rate for "setbaud"
bits	ds.b	1		;Number of data bits
charin	ds.b	1		;Current input character
charinb ds.b	1		;Serial input buffer
charout ds.b	1		;Current output character
frstset ds.b	1		;$80 after first call to "setbaud"
cmdline ds.b	128		;Command line
cmdlinen:			;End of command line
comname ds.b	20		;Name of file to load
comnamen:			;End of file name
opnname ds.b	24		;File name for OPEN or RENAME
renname ds.b	24		;New file name for RENAME
srchnam ds.b	11		;CP/M file name for search first/next
ext17	ds.w	1		;Extent counter for search first/next
newrega ds.b	1		;BIOS/BDOS accumulator work area
workbuf ds.b	80		;Work buffer for "pstring" (including $)
workbufn:			;End of work buffer
strbuf	ds.b	2048		;String output buffer
strbufn ds.b	8		;"strbuf" overflow area - must follow "strbuf"!
strptr	ds.l	1		;Current position in "strbuf"
escbuf	ds.b	8		;Translated escape sequence
esclen	ds.w	1		;Number of bytes saved in "escbuf"
cmdflag ds.b	1		;Take program name from command line.
quitflg ds.b	1		;"quitprg" exit flag
testdol ds.b	1		;"pstring" should test for leading $
insflag ds.b	1		;We're in insert mode.
dumpcnt ds.b	1		;"dump" counter for pausing
traceit ds.b	1		;-t (trace) flag was set on command line
btrcflg ds.b	1		;Trace BIOS/BDOS calls.
bufflag ds.b	1		;Console output is buffered.
z80flag ds.b	1		;Display Z-80 mnemonics in instruction trace.
opcode	ds.b	1		;Current opcode (used for tracing)
prefix	ds.b	1		;Instruction prefix (DD or FD)
fcbptr	ds.l	1		;Pointer to current FCB
listopn ds.b	1		;The list device is open.
builtin ds.b	1		;1 = USER command, 2 = SAVE command
acmap	ds.w	1		;Active drive map
romap	ds.w	1		;Read-only map
newdmap ds.w	1		;Map bit from "mapdrv"

*
* Serial port read request
*
	ds.l	0
readreq 	;struct IOExtSer
		;struct IOStdReq
		;struct Message
	ds.b	14	;struct Node
r_ReplyPort	ds.l 1	;Pointer to MsgPort (message reply port)
r_MLength ds.w	1	;Message length in bytes
		; End of struct Message
	ds.l	1	;Pointer to device node
	ds.l	1	;Pointer to Unit (driver private)
r_Command ds.w	1	;Device command
	ds.b	1	;io_Flags
	ds.b	1	;Error or warning number
		; End of struct IOReq - IOStdReq continues...
r_Actual ds.l	1	;Actual number of bytes transferred
r_Length ds.l	1	;Requested number of bytes transferred
r_Data	ds.l	1	;Points to data area.
r_Offset ds.l	1	;Offset for block-structured devices
		; End of struct IOStdReq
r_CtlChar ds.l	1	;control char's (order = xON,xOFF,INQ,ACK)
r_RBufLen ds.l	1	;length in bytes of serial port's read buffer
r_ExtFlags ds.l 1	;additional serial flags (see bitdefs below)
r_Baud	ds.l	1	;baud rate requested (true baud)
	ds.l	1	;duration of break signal in MICROseconds
		;struct IOTArray termination character array
r_ReadLen ds.b	1	;bits per read character (# of bits)
r_WriteLen ds.b 1	;bits per write character (# of bits)
r_StopBits ds.b 1	;stopbits for read (# of bits)
r_SerFlags ds.b 1	;see SerFlags bit definitions below
r_Status ds.w	1	;status of serial port
rsize	equ	*-readreq

*
* Serial port write request
*
	ds.l	0
writreq 	;struct IOExtSer
		;struct IOStdReq
		;struct Message
	ds.b	14	;struct Node
w_ReplyPort	ds.l 1	;Pointer to MsgPort (message reply port)
w_MLength ds.w	1	;Message length in bytes
		; End of struct Message
	ds.l	1	;Pointer to device node
	ds.l	1	;Pointer to Unit (driver private)
w_Command ds.w	1	;Device command
	ds.b	1	;io_Flags
	ds.b	1	;Error or warning number
		; End of struct IOReq - IOStdReq continues...
w_Actual ds.l	1	;Actual number of bytes transferred
w_Length ds.l	1	;Requested number of bytes transferred
w_Data	ds.l	1	;Points to data area.
w_Offset ds.l	1	;Offset for block-structured devices
		; End of struct IOStdReq
w_CtlChar ds.l	1	;control char's (order = xON,xOFF,INQ,ACK)
w_RBufLen ds.l	1	;length in bytes of serial port's read buffer
w_ExtFlags ds.l 1	;additional serial flags (see bitdefs below)
w_Baud	ds.l	1	;baud rate requested (true baud)
	ds.l	1	;duration of break signal in MICROseconds
		;struct IOTArray termination character array
w_ReadLen ds.b	1	;bits per read character (# of bits)
w_WriteLen ds.b 1	;bits per write character (# of bits)
w_StopBits ds.b 1	;stopbits for read (# of bits)
w_SerFlags ds.b 1	;see SerFlags bit definitions below
w_Status ds.w	1	;status of serial port, as follows:
wsize	equ	*-writreq
*		   BIT	ACTIVE	FUNCTION
*		    0	 low	busy
*		    1	 low	paper out
*		    2	 low	select
*		    3	 low	Data Set Ready
*		    4	 low	Clear To Send
*		    5	 low	Carrier Detect
*		    6	 low	Ready To Send
*		    7	 low	Data Terminal Ready
*		    8	 high	read overrun
*		    9	 high	break sent
*		   10	 high	break received
*		   11	 high	transmit x-OFFed       
*		   12	 high	receive x-OFFed       
*		13-15		reserved

*************************************************************************
*									*
*	Target processor's address space				*
*									*
*************************************************************************

	even

registers ds.b	22		;Actual storage for Z-80's other registers
target	ds.b	$10000		;Z-80's universe

	end
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.