vermaj	 equ	$01	;Major version number
vermin	 equ	$00	;Minor version number
revyear	 equ	$87	;Year last assembled
revmonth equ	$09	;Month last assembled
revday	 equ	$15	;Day last assembled
*************************************************************************
*									*
*									*
*	8080 Simulator for MC68000					*
*									*
*	With CP/M 2.2 call support, and optional tracing		*
*									*
*									*
*	Converted to AmigaDOS September 1987 by Charlie Gibbs		*
*	(after painstakingly typing it all in from Dr. Dobbs		*
*	Journal, January through March 1986).  Improvements		*
*	described by Jim Cathey	in his letter in the June 1986		*
*	DDJ have been included.	 Repetitive code is generated		*
*	by macros whenever it would save my fingers.			*
*									*
*									*
*	Version	1.2 1/21/85 JEC						*
*		Fixed Extent bug in OPEN logic.				*
*		Sped up	code, sample MAC from 2:13 to 1:40		*
*		Now runs at a 1.4 MHz equivalent based on MAC sample.	*
*									*
*	Version	1.1 8/29/84 JEC						*
*		Fixed BIOS call	#6 bug.					*
*									*
*	Version	1.0 05/25/84 by	Jim Cathey				*
*									*
*	This program has been written for speed	whenever possible,	*
*	as such	tends to be large because of the separate subroutine	*
*	for each and every opcode of the target	processor.		*
*									*
*	On an 8MHz 68000 (Compupro) system the simulation speed	is	*
*	a little better	than a 1MHz Z-80 when running MAC.  The	time	*
*	for a sample assembly was 2:13 for the simulation vs. 0:35	*
*	on a 4MHz Z-80,	both systems used identical hard disk systems.	*
*									*
*	It is not a complete simulation, as some flag handling		*
*	isn't quite right, but it is enough to run the program          *
*	I wrote	for it (DDT, LU, MAC, and Morrow's FORMATW).            *
*									*
*************************************************************************
	code
	page
*************************************************************************
*									*
*	This file contains the startup routines, the simulator core,	*
*	tracing	code, and the CP/M 2.2 simulation.			*
*									*
*************************************************************************

	xref	optabl,flags,mloop,traceit,tracesad,traceead,traceflg
	xdef	illegl,service,dump

h19	equ	1		;Non-zero for H19 emulation

*
* ASCII	character values
*
bel	equ	$07		;Bell (or beep or whatever)
bs	equ	$08		;Backspace
ht	equ	$09		;Horizontal tab
lf	equ	$0A		;Line feed
ff	equ	$0C		;Form feed
cr	equ	$0D		;Carriage return
so	equ	$0E		;Shift out
si	equ	$0F		;Shift in
esc	equ	$1B		;Escape

*
* Register definitions for the simulation
*  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		;8080's PC is register A5.
opptr	 equr	A4		;Pointer to opcode dispatch table
pseudosp equr	A3		;8080's SP is register A3.
flagptr	 equr	A2		;Pointer to 8080's flag lookup table is A2.
targbase equr	A1		;Pointer to 8080's address space is A1.
regs	 equr	A1		;Base pointer to 8080's registers is A1.
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		;8080's flags
rega	 equr	D2		;8080's accumulator
*
* Target processor's data registers (offsets into storage area)
*
regop3	equ	-9		;Operand 3 for DAA storage
regb	equ	-8		;Offsets from register base pointer for
regc	equ	-7		; 8080's pseudo-registers.
regd	equ	-6		; A and	F are in 68000's data registers.
rege	equ	-5		; Pseudo-PC is kept in an address register.
regh	equ	-4
regl	equ	-3
regop1	equ	-2		;Operand 1 for DAA storage
regop2	equ	-1		;   "    2  "   "     "
	page
*--------------------------------
*
* Some commonly	used macros
*
*--------------------------------

sys	MACRO			;Call a system routine.
	jsr	_LVO\1(a6)
	ENDM

*----------------------
* Equates
*----------------------

Absbase      equ 4
MODE_OLDFILE equ 1005
MODE_NEWFILE equ 1006

*----------------------
* External references
*----------------------

	XREF	_LVOOpenLibrary
	XREF	_LVOCloseLibrary
	XREF	_LVOClose
	XREF	_LVODeleteFile
	XREF	_LVOInput
	XREF	_LVOIoErr
	XREF	_LVOOpen
	XREF	_LVOOutput
	XREF	_LVORead
	XREF	_LVORename
	XREF	_LVOSeek
	XREF	_LVOWaitForChar
	XREF	_LVOWrite
	page
*************************************************************************
*									*
*	Initialization							*
*									*
*************************************************************************

start:	move.l	sp,savesp	;Save the stack	pointer.
	move.b	#1,testdol	;"pstring" should test for leading $.
	clr.w	esclen		;No partial escape sequence is saved.
	clr.b	insflag		;We're not in insert mode.
	clr.b	btrcflg		;Turn off BIOS/BDOS call tracing.
	clr.b	quitflg		;Clear the quit flag.
	clr.b	bufflag		;Disable output buffering.
	clr.b	listopn		;The list device is closed.
	move.l	#strbuf,strptr	;Initialize output buffer pointer.

	lea	handles,a1
	moveq	#(handlen-handles)/4-1,d1
clrhand	clr.l	(a1)+		;Clear file handles.
	dbra	d1,clrhand
	clr.l	rawhand		;Clear RAW: handle too.

*
* Copy the command line to "cmdline", stripping out leading switches if any.
*
	lea	cmdline,a1
	subq	#1,d0
* Skip over leading blanks, if any.
leadblk	cmpi.b	#' ',(a0)+	;Leading blank?
	bne.s	bufparm		;No.
	dbra	d0,leadblk	;Skip over leading blank.
*  If the first parameter is "-b", skip over it but activate output buffering.
bufparm	subq.l	#1,a0		;Back onto the first non-blank.
	cmpi.b	#'-',(a0)	;Possible buffer switch?
	bne.s	savecmd		;No - start saving the command line.
	cmpi.b	#'B',1(a0)	;Activate output buffering?
	beq.s	setbuff		;Yes.
	cmpi.b	#'b',1(a0)
	bne.s	skipsw		;No.
setbuff	move.b	#1,bufflag	;Set buffered-output flag.
skipsw	cmpi.b	#' ',(a0)+	;Skip over the switch.
	beq.s	skipswx		; and look for start of command line.
	dbra	d0,skipsw
	addq.l	#1,a1		;Adjust A1.
	bra.s	gotcmd		;There is no command line left.
skipswx	subq.l	#1,a0		;Back onto the first blank.
	bra.s	leadblk		;Look for the next non-blank.
* Save the command line (except for leading switches).
savecmd	move.b	(a0)+,(a1)+	;Save the command line, if any.
	dbra	d0,savecmd
gotcmd	move.b	#0,-1(a1)	;Replace the newline with a null.
	move.b	cmdline,cmdflag	;Save command-line flag.

*
* Open libraries and set up a RAW: window.
*
	move.b	#1,quitflg	;Quit immediately if failure below.
	move.l	Absbase,a6	;Find library
	lea	dosname,a1	;'dos.library'
	moveq	#0,d0		;Any version
	sys	OpenLibrary	;Open dos.library.
	move.l	d0,a6		;Point to doslib for next operation.
	move.l	d0,dosbase	;Save it for future reference.
	sys	Input		;Get file handle for keyboard.
	move.l	d0,stdin	;Save it here.
	beq	quitprg		;Couldn't get keyboard handle.
	sys	Output		;Get file handle for screen.
	move.l	d0,stdout	;Save it here.
	beq	quitprg		;Couldn't get screen handle.
	move.l	#rawspec,d1
	move.l	#MODE_NEWFILE,d2
	sys	Open		;Open a RAW: window.
	move.l	d0,rawhand	;Save the file handle here.
	bne.s	opened		;We succeeded.
	move.l	#rawerr,d1
	bsr	pstring		;Display error message...
	sys	IoErr
	move.l	d0,d1
	bsr	plong		; and error code.
	bsr	pcrlf
	bra	quitprg
opened	move.b	cmdflag,quitflg	;If we have a command, execute it and quit.
	move.l	#setwin,d1
	bsr	pstring		;Set the window to 24 by 80.

*
* Come back here to load another program.
*
nextprg	lea	target,targbase	;Start of target memory
	clr.b	insflag		;Reset insert mode.
	move.l	#simsg,d1
	bsr	pstring		;In case last program sent SHIFT OUT
	clr.b	dumpcnt		;Reset dump pause counter.
	bsr	entrads		;Enter trace delimiting	addresses.
	bsr	lodfdos		;Load up the fake FDOS in target memory.
	bsr	lodregs		;Load the remaining simulation registers.
	bsr	loadcom		;Load the .COM program.

	jmp	mloop		;Execute simulation.
	page
*************************************************************************
*									*
*	Illegal	instructions and dumping				*
*									*
*************************************************************************

illegl	move.l	#illgmsg,d1	;Illegal opcode, say what & where,
	bsr	pstring
	lea	-1(pseudopc),a0
	move.b	(a0),d1
	suba.l	targbase,a0
	bsr	pbyte
	move.l	#ilgmsg2,d1
	bsr	pstring
	move.l	a0,d1
	bsr	pword
	move.l	#ilgmsg3,d1
	bsr	pstring
	move.l	#dumpmsg,d1
	bsr	pstring
	clr.b	dumpcnt
	bsr	dump		; and spill guts.
	bra	quitprg		;Quit simulation.

dump	movem.l	d0-d2,-(sp)
	move.l	#dmpmsg2,d1	;Dump all registers,
	bsr	pstring		; used for illegals and	tracing.
	lea	workbuf,a0
	move.b	rega,d1		;Accumulator
	bsr	ubyte
	move.b	regf,d1		;Flags
	bsr	ubyte
	move.b	#' ',(a0)+
	move.w	regb(regs),d1	;BC
	bsr	uword
	move.b	#' ',(a0)+
	move.w	regd(regs),d1	;DE
	bsr	uword
	move.b	#' ',(a0)+
	move.w	regh(regs),d1	;HL
	bsr	uword
	move.b	#' ',(a0)+
	move.l	pseudosp,d1	;SP
	sub.l	targbase,d1
	bsr	uword
	move.b	#' ',(a0)+
	move.l	a1,-(sp)
	move.l	pseudosp,a1
	swap	d2
	move.w	#3,d2
tosloop	move.b	1(a1),d1	;Display the top 4 stack entries.
	ror.w	#8,d1
	move.b	0(a1),d1
	bsr	uword
	move.b	#' ',(a0)+
	addq.l	#2,a1
	dbra	d2,tosloop
	move.l	(sp)+,a1
	swap	d2
	move.l	pseudopc,d1	;PC
	sub.l	targbase,d1
	bsr	uword
	move.b	#' ',(a0)+
	move.b	#' ',(a0)+
	move.b	(pseudopc),d1	;Current opcode byte
	bsr	ubyte
	move.b	#' ',(a0)+
	move.b	#' ',(a0)+
	move.b	#'$',(a0)+
	move.l	#workbuf,d1
	bsr	pstring		;Displaying as a single string is much faster.
	moveq	#0,d0
	move.b	(pseudopc),d0	;Opcode
	mulu	#9,d0		;Offset into opcode table
	lea	mnops,a0
	move.l	a0,d1
	add.l	d0,d1		;D1 -> opcode name
	move.l	d1,-(sp)
	addq.l	#1,d1
	bsr	pstring		;Display opcode name.
	move.l	(sp)+,a0
	cmpi.b	#' ',(a0)
	beq.s	nooprnd		;There are no operands.
	cmpi.b	#'C',(a0)
	bne.s	notcons
	move.b	1(pseudopc),d1	;Display single-byte operand.
	bsr	pbyte
	bra.s	nooprnd
notcons	cmpi.b	#'A',(a0)
	bne.s	nooprnd
	move.b	2(pseudopc),d1	;Display two-byte operand.
	bsr	pbyte
	move.b	1(pseudopc),d1
	bsr	pbyte
nooprnd	bsr	pcrlf
	addq.b	#1,dumpcnt	;Count the number of times dumped.
	cmpi.b	#8,dumpcnt	;Is the screen full of dumps?
	bmi.s	dumpx		;No - exit.
	move.l	#dmpmsg3,d1
	bsr	pstring		;Ask for operator action.
	bsr	dmpstr		;Make sure the prompt gets out!
	movem.l	d3/a0-a1/a6,-(sp)
	move.l	rawhand,d1	;Console input
	move.l	#dumpcnt,d2
	move.l	dosbase,a6
	moveq	#1,d3
	sys	Read		;Get the operator's reply.
	movem.l	(sp)+,d3/a0-a1/a6
	bsr	pcrlf
	cmpi.b	#'Q',dumpcnt	;Does he want to quit?
	beq	quitprg		;Yes.
	cmpi.b	#'q',dumpcnt
	beq	quitprg
	cmpi.b	#'G',dumpcnt	;Go on with tracing disabled?
	beq.s	dumpnt		;Yes.
	cmpi.b	#'g',dumpcnt
	bne.s	dmpcont
dumpnt	clr.b	traceflg	;Disable tracing and continue.
dmpcont	clr.b	dumpcnt		;Reset the counter.
dumpx	movem.l	(sp)+,d0-d2
	rts
	page
*************************************************************************
*									*
*	Initialization subroutines					*
*									*
*************************************************************************

*
* Load up the fake FDOS.
*
lodfdos	move.l	a6,-(sp)
	lea	fdos,a6
	move.l	targbase,pseudosp
	adda.l	#$10000,pseudosp
	lea	-256(pseudosp),a0
	move.w	#fdoslen,d0
lodloop	move.b	(a6)+,(a0)+
	dbra	d0,lodloop
	lea	-256(pseudosp),a0
	move.l	a0,d0
	sub.l	targbase,d0
	move.b	#$C3,0(targbase)	;Build BIOS and	BDOS jumps.
	move.b	#$C3,5(targbase)
	move.b	d0,6(targbase)
	rol.w	#8,d0
	move.b	d0,7(targbase)
	rol.w	#8,d0
	addq.w	#3,d0
	move.b	d0,1(targbase)
	rol.w	#8,d0
	move.b	d0,2(targbase)
	clr.w	-(pseudosp)	;Set up	a return stack to exit simulation.
	move.l	(sp)+,a6
	rts

*
* Set up working registers.
*
lodregs	lea	optabl,opptr	;Point base reg. to opcode dispatch table.
	lea	mloop,return
	lea	flags,flagptr
	move.l	targbase,pseudopc
	adda.l	#$100,pseudopc	;Start execution at 0100H in target space.
	moveq	#$E,regcon0e	;Set up	quick constants.
	moveq	#$1,regcon01
	moveq	#$F,regcon0f
	move.l	#$FF,regconff
	moveq	#0,rega
	moveq	#0,regf
	rts
	page
*
* Get start and end addresses for tracing.
*
entrads	tst.b	traceit		;Is tracing required?
	beq	entradx		;No.
	move.l	#tracemsg,d1	;Enter trace address if	necessary.
	bsr	pstring
	lea	workbuf,a0
	move.b	#workbufn-workbuf-2,(a0)
	bsr	getline		;Get the string.
	moveq	#0,d0
	move.b	1(a0),d0	;Number of bytes read
	addq.l	#2,a0		;Skip over length information.
	clr.b	0(a0,d0)	;Insert string terminator.
	bsr	atol		;Get trace start address.
	and.l	#$FFFF,d1
	add.l	targbase,d1
	move.l	d1,tracesad
* Now get the ending address.
	move.l	#tracemg2,d1
	bsr	pstring
	lea	workbuf,a0
	move.b	#workbufn-workbuf-2,(a0)
	bsr	getline
	moveq	#0,d0
	move.b	1(a0),d0
	addq.l	#2,a0
	clr.b	0(a0,d0)
	bsr	atol
	and.l	#$FFFF,d1
	add.l	targbase,d1
	move.l	d1,traceead
	bsr	pcrlf
* Find out whether BIOS/BDOS calls are to be traced.
	move.l	#btrcmsg,d1
	bsr	pstring
	lea	workbuf,a0
	move.b	#10,(a0)
	bsr	getline
	move.b	#1,btrcflg
	cmpi.b	#'Y',workbuf+2
	beq.s	entradx
	cmpi.b	#'y',workbuf+2
	beq.s	entradx
	clr.b	btrcflg
entradx	clr.b	traceflg	;Start with tracing turned off.
	rts
*
* Open the file to be loaded, and load it into
*  target space	if successful.
*
loadcom	movem.l	d1-d3/a1-a2/a6,-(sp)	;Save registers.
	lea	cmdline,a0
	tst.b	cmdflag		;Do we have a command already?
	bne.s	scancmd		;Yes - process it.
prompt	move.l	#aprompt,d1
	bsr	pstring		;Display the command prompt.
	lea	cmdline,a0
	move.b	#cmdlinen-cmdline-2,(a0)
	bsr	getline		;Get a command line.
	moveq	#0,d0
	move.b	1(a0),d0	;Length of command line
	beq.s	prompt		;Zero - try again.
	addq.l	#2,a0		;Skip over length information.
	clr.b	0(a0,d0)	;Insert	command	line terminator.
	cmpi.b	#3,(a0)		;Control-C?
	bne.s	scancmd		;No.
	move.b	#1,quitflg	;Set quit flag.
	bra	quitprg		;Exit the simulator.
scancmd	lea	comname,a2
	moveq	#comnamen-comname-6,d1 ;Adjust length for DBcc.
loadnam	bsr	ucase		;Convert file name to upper case.
	move.b	d0,(a2)+
	cmpi.b	#' ',(a0)       ;End of name?
	beq	gotname		;Yes.
	tst.b	(a0)		;End of	command	string?
	dbeq	d1,loadnam	;No - keep on going.
gotname	move.l	a0,comend	;Save position in command line.
	move.b	#'.',(a2)+      ;Mash file name to .COM.
	move.b	#'C',(a2)+
	move.b	#'O',(a2)+
	move.b	#'M',(a2)+
	clr.b	(a2)
	clr.b	cmdline		;Ask for a new command next time.
	move.l	#comname,d1
	move.l	#MODE_OLDFILE,d2
	move.l	dosbase,a6
	sys	Open		;Open the file.
	tst.l	d0		;Did the open fail?
	bne.s	comopen		;No.
	lea	comname,a0
openerr	cmpi.b	#'.',(a0)+      ;Find end of file name.
	bne.s	openerr
	move.b	#'?',-1(a0)
	move.b	#cr,(a0)+
	move.b	#lf,(a0)+
	move.b	#'$',(a0)
	move.l	#comname,d1
	bsr	pstring		;Echo "name?"
	bra	prompt		;Try again.

comopen	move.l	d0,-(sp)	;Save the file handle.
	move.l	d0,d1
	move.l	pseudopc,d2	;Start loading at $0100	in target.
	move.l	#65536-512,d3	;Maximum number	of bytes to load
	move.l	dosbase,a6
	sys	Read		;Load the .COM file.
	move.l	(sp)+,d1
	move.l	dosbase,a6
	sys	Close		;Close the .COM	file.

* The program has now been loaded.
	movem.l	(sp)+,d1-d3/a1-a2/a6	;Refresh registers.
	movem.l	d1-d3/a1-a2/a6,-(sp)
	lea	$80(targbase),a0	;Set up target's base page.
	move.l	a0,dmaaddr

* Set up FCBs and command line tail.
	lea	$5C(targbase),a0
	lea	$6C(targbase),a2
	clr.b	(a0)+
	clr.b	(a2)+
	moveq	#10,d0
clrfcb	move.b	#' ',(a0)+      ;Clear FCBs.
	move.b	#' ',(a2)+
	dbra	d0,clrfcb
	clr.b	$80(targbase)	;Clear the command line tail.

	move.l	comend,a0	;Restore position in command line.
fcb1	tst.b	(a0)		;End of	command	line?
	beq	loaded		;Yes.
	cmpi.b	#' ',(a0)+      ;Skip over to first file name
	beq.s	fcb1
	subq.l	#1,a0		;Back onto start of file name.
	move.l	a0,-(sp)	;Save position on command line.
	lea	$81(targbase),a2;A2 loads the command line tail.
gettail	move.b	(a0)+,(a2)+	;Copy the command tail.
	bne.s	gettail
	move.l	a2,d0
	lea	$82(targbase),a0;Don't count null terminator!
	sub.l	a0,d0
	move.b	d0,$80(targbase);Length	of command line	tail
	move.l	(sp)+,a0	;Go back to the	first file name.

	lea	$5C(targbase),a2;Address of current FCB
getfcb	move.l	a2,fcbptr	;Save pointer to current FCB.
	cmpi.b	#':',1(a0)      ;Is a drive specified?
	bne.s	getfcbf		;No.
	move.b	(a0),(a2)	;Get drive letter.
	subi.b	#'A'-1,(a2)     ;Convert to drive code.
	addq.l	#2,a0		;Skip over drive designator.
	tst.b	(a0)		;End of	command	line?
	beq.s	loaded		;Yes - we're done.
	cmpi.b	#' ',(a0)       ;End of file name?
	beq.s	getfcbx		;Yes.
getfcbf	addq.l	#1,a2		;Start of file name in FCB
getfcbl	move.b	(a0)+,(a2)+	;Copy file name	to FCB.
getfcbt	tst.b	(a0)		;End of	command?
	beq.s	loaded		;Yes.
	cmpi.b	#' ',(a0)       ;End of file name?
	beq.s	getfcbx		;Yes.
	cmpi.b	#'.',(a0)       ;Start of file name extension?
	bne.s	getfcbl		;No - continue loading file name.
	move.l	fcbptr,a2	;Copy original pointer
	adda.l	#9,a2		;Skip over to extension	field.
	addq.l	#1,a0		;Skip over the period.
	bra.s	getfcbt
getfcbx	tst.b	(a0)		;End of	command	line?
	beq.s	loaded		;Yes.
	cmpi.b	#' ',(a0)+      ;Look for another file name.
	beq.s	getfcbx
	subq.l	#1,a0		;Back onto start of file name.
	move.l	fcbptr,d0
	lea	$5C(targbase),a2
	cmp.l	d0,a2		;Was this the first FCB?
	bne.s	loaded		;No - stop after two FCBs.
	adda.l	#16,a2		;Skip over to the next FCB.
	bra.s	getfcb		;Load the next FCB.

loaded	movem.l	(sp)+,d1-d3/a1-a2/a6	;Restore registers.
	rts			;Exit.

*
* Subroutine to	get a character	and convert it to upper	case
*
ucase	move.b	(a0)+,d0
	cmpi.b	#'a',d0
	blt.s	ucasex
	cmpi.b	#'z',d0
	bgt.s	ucasex
	subi.b	#'a'-'A',d0
ucasex	rts
	page
*************************************************************************
*									*
*	BDOS / BIOS service routines					*
*									*
*************************************************************************
service	movem.l	a1/a6,-(sp)
	move.b	rega,newrega	;Save 8080 accumulator (D2)
	move.l	dosbase,a6	;Get dos.library pointer
* Decode the byte following the HLT instruction (BIOS call type).
	moveq	#0,d0		;Handle	BIOS/BDOS service request
	move.b	(pseudopc)+,d0	; of form HLT DB opcode.
	cmp	#(biostabn-biostab)/4,d0
	blt.s	dobios		;Function number is within range.
badbios	move.b	d0,-(sp)	;Flag illegal BIOS call
	move.l	#ilgbios,d1	; and spill guts.
	bsr	pstring
	move.b	(sp)+,d1
	bsr	pbyte
	bsr	pcrlf
	bsr	dump
	bra	quitprg
dobios	move.l	d0,-(sp)	;Save BIOS function number.
	beq.s	biostrx		;Zero - it's a BDOS call.
	tst.b	btrcflg		;Trace BIOS calls?
	beq.s	biostrx		;No.
	move.l	#biosmsg,d1
	bsr	pstring
	move.l	(sp),d1
	bsr	pbyte
	move.l	#atmsg,d1
	bsr	pstring
	move.b	1(pseudosp),d1	;Address where called (top stack entry)
	ror.w	#8,d1
	move.b	0(pseudosp),d1
	bsr	pword
	bsr	pcrlf
	move.l	(sp),d0
biostrx	asl	#2,d0		;Multiply function number by 4.
	addi.l	#biostab,d0	;Point at address table entry.
	movea.l	d0,a0
	movea.l	(a0),a0		;Point to appropriate service routine.
	move.l	(sp)+,d0	;Restore BIOS function number.
	jmp	(a0)		;Jump to the routine.
* If the BIOS code is zero, it's a BDOS call.
*  Decode register C using a similar routine to the BIOS decoding above.
bdosfn	moveq	#0,d0
	move.b	regc(regs),d0	;Get BDOS function number.
	cmp	#(bdostabn-bdostab)/4,d0
	blt.s	dobdos		;Function number is within range.
badbdos	move.b	d0,-(sp)
	move.l	#ilgbdos,d1	;Illegal or unsupported	BDOS call
	bsr	pstring
	move.b	(sp)+,d1
	bsr	pbyte
	bsr	pcrlf
	bsr	dump
	bra	quitprg
dobdos	move.l	d0,-(sp)	;Save BDOS function number.
	tst.b	btrcflg		;Trace BDOS calls?
	beq.s	bdostrx		;No.
	move.l	#bdosmsg,d1
	bsr	pstring
	move.l	(sp),d1
	bsr	pbyte
	move.l	#atmsg,d1
	bsr	pstring
	move.b	1(pseudosp),d1
	ror.w	#8,d1
	move.b	0(pseudosp),d1
	bsr	pword
	bsr	pcrlf
	move.l	(sp),d0
bdostrx	cmpi.b	#10,d0		;BDOS function 10 or higher?
	blt.s	bdosjmp		;No.
	bsr	dmpstr		;Dump any outstanding console output.
	move.l	(sp),d0		;Restore BDOS function number.
bdosjmp	asl	#2,d0		;Multiply function number by 4.
	addi.l	#bdostab,d0	;Point at address table entry.
	movea.l	d0,a0
	movea.l	(a0),a0		;Point to appropriate service routine.
	move.l	(sp)+,d0	;Restore BDOS function number.
	moveq	#0,d1
	move.w	regd(regs),d1	;Get argument.
	jmp	(a0)		;Jump to the routine.
* Return here after performing the BDOS	function.
results	movem.l	(sp)+,a1/a6
	moveq	#0,rega
	move.b	newrega,rega	;Get new accumulator value.
* We have finished processing the BDOS function.
	move.b	rega,d0		;Set flags.
	and.w	regconff,d0
	move.b	0(flagptr,d0.w),regf
	rts
*
* Individual BDOS service routines
*
bdos00	bra	quitprg		;Exit program.

bdos01	bsr	dmpstr		;Console input
	move.l	rawhand,d1
	move.l	#newrega,d2
	moveq	#1,d3
	sys	Read
	bra	results

bdos02	move.b	rege(regs),d1	;Console output
	clr.b	testdol		;Allow dollar signs
	bsr	pchar
	bra	results

bdos03	equ	badbdos		;Reader	input

bdos04	equ	badbdos		;Punch output

bdos05	pea	rege(regs)	;List output byte
bdos05t	tst.b	listopn		;Is the printer already open?
	bne.s	bdos05w		;Yes.
	move.l	#prtname,d1
	move.l	#MODE_NEWFILE,d2
	sys	Open		;Open the printer.
	move.l	d0,prthand	;Save the file handle.
	bne.s	bdos05o		;The open was successful.
	move.l	#badprt,d1
	bsr	pstring		;Indicate an unsuccessful open.
	bsr	dump		;Spill guts...
	bra	quitprg		; and exit.
bdos05o	move.b	#1,listopn	;Indicate that the list device is open.
bdos05w	move.l	prthand,d1
	move.l	(sp)+,d2	;Character to send to the list device
	moveq	#1,d3		;Just send one byte.
	sys	Write		;Send the byte to the list device.
	bra	results
	
bdos06	cmpi.b	#$FF,rege(regs)	;Direct	console	I/O
	bne.s	bdos02		;Send the byte.
	bsr	dmpstr		;Dump any outstanding output.
	move.l	rawhand,d1
	moveq	#1,d2		;Wait for one microsecond.
	sys	WaitForChar	;Check whether a character is ready.
	tst.l	d0		;Is a character	ready?
	bne	bdos01		;Yes - get it.
	clr.b	newrega		;Indicate that nothing is ready.
	bra	results

bdos07	move.b	3(targbase),newrega	;Get IOBYTE
	bra	results

bdos08	move.b	rege(regs),3(targbase)	;Set IOBYTE
	bra	results

bdos09	add.l	targbase,d1	;Console output	string
	bsr	pstring
	bra	results

bdos10	add.l	targbase,d1	;Console input line
	movea.l	d1,a0		;The buffer is here.
	bsr	getline		;Get a line.
	cmpi.b	#3,2(a0)	;Was it a control-C?
	bne	results		;No - continue processing.
	bra	quitprg		;Terminate the program.

bdos11	move.l	rawhand,d1	;Console status check
	moveq	#1,d2		;Wait for one microsecond.
	sys	WaitForChar	;Check whether a character is ready.
	move.b	d0,newrega	;Result	is compatible with CP/M.
	bra	results

bdos12	clr.b	regh(regs)	;Get system identification
	move.b	#$22,regl(regs)	;Pretend we're CP/M 2.2.
	bra	results

bdos13	equ	results		;Reset all drives (ignored)

bdos14	move.b	rege(regs),4(targbase)	;Select	drive
	bra	results

bdos15	move.l	#MODE_OLDFILE,d2;Open existing file
bdos15o	add.l	targbase,d1
	movea.l	d1,a0		;The FCB is here.
	move.l	d1,-(sp)
	lea	opnname,a1	;Build AmigaDOS	file name here.
	move.l	a1,d1		;We'll need it here.
	bsr	convfn		;Make a	file name.
	sys	Open		;Open the file.
	move.l	(sp)+,a1	;The FCB is here.
	lea	handles,a0
	moveq	#(handlen-handles)/4-1,d1
	clr.b	newrega		;Assume	the open succeeded.
	tst.l	d0		;Did it fail?
	bne	bdos15s		;No.
	move.b	#$FF,newrega	;Set failure code.
	bra	results
bdos15s	tst.l	(a0)+		;Find an available handle slot.
	dbeq	d1,bdos15s
	tst	d1		;Did we	find a slot?
	bmi	bdos15e		;No - error!
	move.l	d0,-4(a0)	;Save file handle address.
	moveq	#(handlen-handles)/4-1,d0
	sub.l	d1,d0
	move.b	d0,13(a1)	;Save handle number in FCB.
	bra	results
bdos15e	move.l	#fullmsg,d1	;File handle table overflow!
	bsr	pstring		;Display an error message
	bra	quitprg		; and forget the whole thing.

bdos16	move.b	#$FF,newrega	;Close file
	bsr	gethand		;Get the file handle.
	beq	results		;The file is not open.
	clr.l	0(a1,d0.w)	;Clear the handle table	entry.
	sys	Close		;Close the file.
	clr.b	newrega		;Indicate success.
	bra	results

bdos17	equ	badbdos		;Search	for first file

bdos18	equ	badbdos		;Search	for next file

bdos19	add.l	targbase,d1	;Delete	file
	movea.l	d1,a0		;The FCB is here.
	lea	opnname,a1	;Build AmigaDOS	file name here.
	move.l	a1,d1		;We'll need it here.
	bsr	convfn		;Make a	file name.
	sys	DeleteFile	;Delete	the file.
	bra	results

bdos20	clr.b	newrega		;Sequential read
	bsr	gethand
	move.l	dmaaddr,d2
	move.l	#128,d3
	sys	Read
	tst.l	d0		;Were we successful?
	bgt	results		;Yes.
	move.b	#$FF,newrega	;Set failure (EOF) flag.
	bra	results

bdos21	clr.b	newrega		;Sequential write
	bsr	gethand
	move.l	dmaaddr,d2
	move.l	#128,d3
	sys	Write
	tst.l	d0		;Were we successful?
	bgt	results		;Yes.
	move.b	#$FF,newrega	;Set failure flag.
	bra	results

bdos22	move.l	#MODE_NEWFILE,d2	;Make new file
	bra	bdos15o			;Use BDOS 15 open routine

bdos23	add.l	targbase,d1	;Rename	file
	movea.l	d1,a0
	lea	opnname,a1
	bsr	convfn		;Convert old file name.
	movea.l	d1,a0
	adda.l	#16,a0
	lea	renname,a1
	bsr	convfn		;Convert new file name.
	move.l	#opnname,d1
	move.l	#renname,d2
	sys	Rename		;Rename	the file.
	bra	results

bdos24	equ	badbdos		;Get active drive map

bdos25	move.b	4(targbase),newrega	;Get default drive number
	bra	results

bdos26	add.l	targbase,d1	;Set file buffer address
	move.l	d1,dmaaddr
	bra	results

bdos27	equ	badbdos		;Get allocation	vector

bdos28	equ	badbdos		;Protect drive

bdos29	equ	badbdos		;Get read-only map

bdos30	equ	badbdos		;Set file attributes

bdos31	equ	badbdos		;Get disk parameter block

bdos32	equ	badbdos		;Get or	set user code

bdos33	pea	_LVORead(a6)	;Direct access read
	bra.s	bdos34c		;Use common read/write routine.

bdos34	pea	_LVOWrite(a6)	;Direct access write
bdos34c	clr.b	newrega		;Common direct access read/write routine
	bsr	gethand
	move.l	d1,-(sp)	;Save file handle.
	moveq	#0,d2
	move.b	35(a0),d2	;Get seek address.
	rol.l	#8,d2
	move.b	34(a0),d2
	rol.l	#8,d2
	move.b	33(a0),d2
	rol.l	#7,d2		;Convert record number to byte displacement.
	move.b	33(a0),32(a0)	;Set up current record number in extent.
	andi.b	#$7F,32(a0)
	moveq	#14,d0
	ror.l	d0,d2
	move.b	d2,12(a0)	;Current extent number
	rol.l	d0,d2
	moveq	#-1,d3
	sys	Seek		;Seek to desired position.
	move.l	(sp)+,d1	;Get the file handle again.
	move.l	(sp)+,a0	;Address of read or write routine
	tst.l	d0		;Were we successful?
	bmi	bdos34e		;No.
	move.l	dmaaddr,d2
	move.l	#128,d3
	jsr	(a0)		;Read or write the desired record.
	tst.l	d0		;Were we successful?
	bgt	results		;Yes.
bdos34e	move.b	#6,newrega	;Set failure (invalid address) flag.
	bra	results

bdos35	equ	badbdos		;Get file end address

bdos36	equ	badbdos		;Get direct address

*
* Individual BIOS service routines
*
bios01	bra	quitprg		;Warm boot

bios02	equ	bdos11		;Console status check

bios03	equ	bdos01		;Console input byte

bios04	move.b	regc(regs),d1	;Console output byte
	clr.b	testdol		;Allow dollar signs
	bsr	pchar
	bra	results

bios05	pea	regc(regs)	;List output byte
	bra	bdos05t

bios06	equ	badbios		;Punch output byte

bios07	equ	badbios		;Reader input byte

bios08	equ	badbios		;Home disk

bios09	equ	badbios		;Select disk

bios10	equ	badbios		;Set track

bios11	equ	badbios		;Set sector

bios12	equ	badbios		;Set DMA address

bios13	equ	badbios		;Read disk

bios14	equ	badbios		;Write disk

bios15	move.b	#$FF,newrega	;List status
	bra	results


*
* End of program, one way or another
*
quitprg	move.l	savesp,sp	;Restore stack pointer.
	bsr	dmpstr		;Dump any outstanding console output.
* If the list device was used, close it.
	tst.b	listopn		;Is the printer open?
	beq.s	closprt		;No.
	move.l	prthand,d1
	sys	Close		;Close the printer.
closprt	clr.b	listopn		;Reset the "printer-open" flag.
* If any files were left open by the last program, close them.
	lea	handles,a0
	moveq	#(handlen-handles)/4-1,d0
closall	move.l	(a0)+,d1
	beq.s	closnxt		;This file isn't open.
	movem.l	a0/d0,-(sp)
	move.l	dosbase,a6
	sys	Close		;Close this file.
	movem.l	(sp)+,a0/d0
closnxt	dbra	d0,closall
* Check whether we should quit the simulation.
	tst.b	quitflg		;Exit the simulator?
	bne.s	exitsim		;Yes.
	tst.b	cmdflag		;Was .COM file loaded from command line?
	beq	nextprg		;No - re-display the command prompt.
* Terminate execution of the simulator.
exitsim	move.l	rawhand,d1	;Is RAW: open?
	beq.s	closlib		;No.
	move.l	dosbase,a6
	sys	Close		;Close RAW:
closlib	move.l	Absbase,a6
	move.l	dosbase,a1
	sys	CloseLibrary	;Close dos.library.
	moveq	#0,d0		;Return	with no	error.
	rts			;All done
	page
*************************************************************************
*									*
*	AmigaDOS interface routines					*
*									*
*************************************************************************

*
* Get a line from the console.  CP/M BDOS 10 conventions are used.
*  A0 is assumed to point to the start of the buffer.
*  If the first character encountered is a control-C, this routine
*  exits, leaving just the control-C in the buffer.
*
getline	movem.l	d2-d3/a0-a1/a6,-(sp)
	bsr	dmpstr		;Flush the screen buffer first.
	move.l	dosbase,a6
	movea.l	a0,a1
	addq.l	#2,a1		;The current character loads here.
	clr.b	1(a0)		;Clear character count.
getlinl	move.l	rawhand,d1	;Read from RAW:
	move.l	a1,d2		; into current position
	moveq	#1,d3		;  for a length of one byte.
	movem.l	d1-d3/a0-a1,-(sp)
	sys	Read		;Get a character.
	movem.l	(sp)+,d1-d3/a0-a1
	cmpi.b	#cr,(a1)	;Did we get a carriage return?
	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
	jsr	pstring		;Erase the previous character on the screen.
	movem.l	(sp)+,a0-a1
	bra.s	getlinl
getlinp	movem.l	a0-a1,-(sp)
	sys	Write		;Echo the current character.
	movem.l	(sp)+,a0-a1
getlinn	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	getlinf		;No.
	cmpi.b	#1,d0		;Is is the first character?
	beq.s	getlinx		;Yes - exit now.
getlinf	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?
	blt.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
	blt.s	pstreun		;Unknown code - copy it as is.
	cmpi.b	#'O',d0
	beq.s	pstreO		;Reset insert mode.
	bhi.s	pstreun		;Unknown code
	move.l	a0,-(sp)
	lea	esctran,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	pstresb		;No.
	subq.l	#1,a2		;Back over stored CSI character.
pstresb	move.b	d2,(a2)+	;Get the translated code.
	bra.s	pstrsub
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.
* 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
pstrsbl	move.b	(a2)+,(a1)+	;Copy substitution to output string.
	subq.w	#1,d3		;Count down remaining length.
	dbra	d0,pstrsbl
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	pstrcv1		;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.
pstrcv1	swap	d0		;Get the units digit.
	addi.b	#'0',d0		;Convert it to ASCII.
	move.b	d0,(a2)+
	rts
	endc
* 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	pstreos		;No.
	cmpi.b	#cr,-1(a0)	;Carriage return?
	beq.s	pstrseg		;Yes - dump the current segment.
	cmpi.b	#bel,-1(a0)	;Bell?
	bne.s	pstreos		;No - continue buffering.
pstrseg	move.l	a1,strptr
	bsr	dmpstr		;Dump the buffer.
	move.l	strptr,a1
pstreos	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	pstrdmp		;Yes - dump it regardless.
	tst.b	bufflag		;Is console buffering in effect?
	bne.s	pstrnxt		;Yes - don't write anything yet.
pstrdmp	bsr	dmpstr		;Dump the buffer.
	move.l	strptr,a1
pstrnxt	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	dmpstrx		;Zero - don't write anything.
	move.l	rawhand,d1	;Assume we're writing to RAW:
	bne.s	dmpstrp
	move.l	stdout,d1	;We don't have RAW: - use stdout.
dmpstrp	move.l	dosbase,a6
	sys	Write		;Display the line.
dmpstrx	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.
	tst.b	(a0)+		;Skip over drive code for now.
	moveq	#7,d0		;Maximum of 8 characters for file name
convfn1	cmpi.b	#' ',(a0)       ;End of file name?
	beq.s	convfnz		;Yes
	move.b	(a0)+,(a1)+	;Move one character of file name.
	dbra	d0,convfn1	;Try for more.
convfnz	movea.l	(sp)+,a0	;Back to start of FCB.
	adda.l	#9,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.
	move.b	(a0)+,(a1)+	;Move one character of extension.
	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 number inserted into the
*  CP/M	FCB by the open	routine.  It is	copied from the	file handle
*  table entry (whose address is set up	as 0(A1,D0.W)) to D1.
*  The Z flag will be set if the handle	is zero	(i.e. file not open).
*  A0 points to	the FCB.
*
gethand	add.l	targbase,d1	;The FCB is here.
	movea.l	d1,a0
	lea	handles,a1
	moveq	#0,d0
	move.b	13(a0),d0	;Get handle number from	FCB.
	asl.w	#2,d0		;Convert to table offset.
	move.l	0(a1,d0.w),d1	;Get the file handle.
	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	pdigent
pdiglop	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
	blt.s	ntoa2
	add.b	#'A'-'9'-1,d1	;Adjust for digits A through F.
ntoa2	add.b	#'0',d1		;Convert to ASCII.
	move.b	d1,(a0)+	;Add to the result string.
	move.l	(sp)+,d1
pdigent	swap	d0		;Get nybble count.
	dbra	d0,pdiglop
	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	#spacemsg,d1	;Print a space.
	bsr	pstring
	rts

pcrlf	move.l	#crlfmsg,d1	;Print a carriage return and line feed.
	bsr	pstring
	rts

*
* 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
atol1	move.b	(a0)+,d0	;Get the current byte.
	cmpi.b	#$40,d0
	blt.s	atol2
	and	#$5F,d0		;Mask to upper case.
atol2	cmpi.b	#'0',d0         ;Check range (0..9,A..F).
	blt.s	atolend
	cmpi.b	#'F',d0
	bhi.s	atolend
	cmpi.b	#'9',d0
	ble.s	atol3
	cmpi.b	#'A'-1,d0
	bhi.s	atol3
	bra.s	atolend
atol3	moveq	#1,d2		;Valid characters entered, set flag.
	sub.b	#'0',d0         ;Convert to binary
	cmp.b	#$9,d0		;Digit in range	0..9?
	ble.s	atol4		;Yes - conversion is complete
	sub.b	#'A'-'9'-1,d0   ;Adjust digits A..F.
atol4	ext	d0		;Convert to long.
	ext.l	d0
	asl.l	#4,d1		;Tack it onto d1.
	add.l	d0,d1
	bra.s	atol1		;Try for another digit.
atolend	subq.l	#1,a0		;Back onto the first invalid digit.
	rts
	page
*************************************************************************
*									*
*	This table contains the mnemonic strings for the 8080		*
*	opcodes.  These	are used in tracing.  The first	character	*
*	flags operands.	 Blank is nothing, A is	an address (i.e.	*
*	a 16-bit value), and C is a constant (i.e. an 8-bit value).	*
*									*
*************************************************************************

	data	data

mnops:
	dc.b	' NOP$    ALXI B,$  STAX B$  INX B$  '  ;00-03
	dc.b	' INR B$   DCR B$  CMVI B,$  RLC$    '  ;04-07
	dc.b	' ILLEGAL$ DAD B$   LDAX B$  DCX B$  '  ;08-0B
	dc.b	' INR C$   DCR C$  CMVI C,$  RRC$    '  ;0C-0F
	dc.b	' ILLEGAL$ALXI D,$  STAX D$  INX D$  '  ;10-13
	dc.b	' INR D$   DCR D$  CMVI D,$  RAL$    '  ;14-17
	dc.b	' ILLEGAL$ DAD D$   LDAX D$  DCX D$  '  ;18-1B
	dc.b	' INR E$   DCR E$  CMVI E,$  RAR$    '  ;1C-1F
	dc.b	' ILLEGAL$ALXI H,$ ASHLD $   INX H$  '  ;20-23
	dc.b	' INR H$   DCR H$  CMVI H,$  DAA$    '  ;24-27
	dc.b	' ILLEGAL$ DAD H$  ALHLD $   DCX H$  '  ;28-2B
	dc.b	' INR L$   DCR L$  CMVI L,$  CMA$    '  ;2C-2F
	dc.b	' ILLEGAL$ALXI SP,$ASTA $    INX SP$ '  ;30-33
	dc.b	' INR M$   DCR M$  CMVI M,$  STC$    '  ;34-37
	dc.b	' ILLEGAL$ DAD SP$ ALDA $    DCX SP$ '  ;38-3B
	dc.b	' INR A$   DCR A$  CMVI A,$  CMC$    '  ;3C-3F
	dc.b	' MOV B,B$ MOV B,C$ MOV B,D$ MOV B,E$'  ;40-43
	dc.b	' MOV B,H$ MOV B,L$ MOV B,M$ MOV B,A$'  ;44-47
	dc.b	' MOV C,B$ MOV C,C$ MOV C,D$ MOV C,E$'  ;48-4B
	dc.b	' MOV C,H$ MOV C,L$ MOV C,M$ MOV C,A$'  ;4C-4F
	dc.b	' MOV D,B$ MOV D,C$ MOV D,D$ MOV D,E$'  ;50-53
	dc.b	' MOV D,H$ MOV D,L$ MOV D,M$ MOV D,A$'  ;54-57
	dc.b	' MOV E,B$ MOV E,C$ MOV E,D$ MOV E,E$'  ;58-5B
	dc.b	' MOV E,H$ MOV E,L$ MOV E,M$ MOV E,A$'  ;5C-5F
	dc.b	' MOV H,B$ MOV H,C$ MOV H,D$ MOV H,E$'  ;60-63
	dc.b	' MOV H,H$ MOV H,L$ MOV H,M$ MOV H,A$'  ;64-67
	dc.b	' MOV L,B$ MOV L,C$ MOV L,D$ MOV L,E$'  ;68-6B
	dc.b	' MOV L,H$ MOV L,L$ MOV L,M$ MOV L,A$'  ;6C-6F
	dc.b	' MOV M,B$ MOV M,C$ MOV M,D$ MOV M,E$'  ;70-73
	dc.b	' MOV M,H$ MOV M,L$ HLT$     MOV M,A$'  ;74-77
	dc.b	' MOV A,B$ MOV A,C$ MOV A,D$ MOV A,E$'  ;78-7B
	dc.b	' MOV A,H$ MOV A,L$ MOV A,M$ MOV A,A$'  ;7C-7F
	dc.b	' ADD B$   ADD C$   ADD D$   ADD E$  '  ;80-83
	dc.b	' ADD H$   ADD L$   ADD M$   ADD A$  '  ;84-87
	dc.b	' ADC B$   ADC C$   ADC D$   ADC E$  '  ;88-8B
	dc.b	' ADC H$   ADC L$   ADC M$   ADC A$  '  ;8C-8F
	dc.b	' SUB B$   SUB C$   SUB D$   SUB E$  '  ;90-93
	dc.b	' SUB H$   SUB L$   SUB M$   SUB A$  '  ;94-97
	dc.b	' SBB B$   SBB C$   SBB D$   SBB E$  '  ;98-9B
	dc.b	' SBB H$   SBB L$   SBB M$   SBB A$  '  ;9C-9F
	dc.b	' ANA B$   ANA C$   ANA D$   ANA E$  '  ;A0-A3
	dc.b	' ANA H$   ANA L$   ANA M$   ANA A$  '  ;A4-A7
	dc.b	' XRA B$   XRA C$   XRA D$   XRA E$  '  ;A8-AB
	dc.b	' XRA H$   XRA L$   XRA M$   XRA A$  '  ;AC-AF
	dc.b	' ORA B$   ORA C$   ORA D$   ORA E$  '  ;B0-B3
	dc.b	' ORA H$   ORA L$   ORA M$   ORA A$  '  ;B4-B7
	dc.b	' CMP B$   CMP C$   CMP D$   CMP E$  '  ;B8-BB
	dc.b	' CMP H$   CMP L$   CMP M$   CMP A$  '  ;BC-BF
	dc.b	' RNZ$     POP B$  AJNZ $   AJMP $   '  ;C0-C3
	dc.b	'ACNZ $    PUSH B$ CADI $    RST 0$  '  ;C4-C7
	dc.b	' RZ$      RET$    AJZ $     ILLEGAL$'  ;C8-CB
	dc.b	'ACZ $    ACALL $  CACI $    RST 1$  '  ;CC-CF
	dc.b	' RNC$     POP D$  AJNC $   COUT $   '  ;D0-D3
	dc.b	'ACNC $    PUSH D$ CSUI $    RST 2$  '  ;D4-D7
	dc.b	' RC$      ILLEGAL$AJC $    CIN $    '  ;D8-DB
	dc.b	'ACC $     ILLEGAL$CSBI $    RST 3$  '  ;DC-DF
	dc.b	' RPO$     POP H$  AJPO $    XTHL$   '  ;E0-E3
	dc.b	'ACPO $    PUSH H$ CANI $    RST 4$  '  ;E4-E7
	dc.b	' RPE$     PCHL$   AJPE $    XCHG$   '  ;E8-EB
	dc.b	'ACPE $    ILLEGAL$CXRI $    RST 5$  '  ;EC-EF
	dc.b	' RP$      POP PSW$AJP $     DI$     '  ;F0-F3
	dc.b	'ACP $     PUSH P$ CORI $    RST 6$  '  ;F4-F7
	dc.b	' RM$      SPHL$   AJM $     EI$     '  ;F8-FB
	dc.b	'ACM $     ILLEGAL$CCPI $    RST 7$  '  ;FC-FF
	page
*************************************************************************
*									*
*	Fake FDOS							*
*									*
*************************************************************************

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

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

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:
	page
*************************************************************************
*									*
*	Messages							*
*									*
*************************************************************************

dosname	dc.b	'dos.library',0
aprompt	dc.b	'A>$'
crlfmsg	dc.b	cr,lf,'$'
spacemsg dc.b	' $'
bsmsg	dc.b	bs,' ',bs,'$'	;Erases the previous character
simsg	dc.b	si,'$'		;Resets MSB of each output character
rawspec	dc.b	'RAW:0/0/640/200/CP/M Emulator'
	dc.b	' by Jim Cathey and Charlie Gibbs - version '
	dc.b	vermaj&15+'0','.'
	dc.b	vermin/16+'0',vermin&15+'0',' ('
	dc.b	revyear/16+'0',revyear&15+'0','/'
	dc.b	revmonth/16+'0',revmonth&15+'0','/'
	dc.b	revday/16+'0',revday&15+'0',')',0
rawerr	dc.b	'Unable to open RAW: - code $'
setwin	dc.b	$9B,'0x',$9B,'8y',$9B,'24t',$9B,'80u',$9B,'H',$9B,'J$'
fullmsg	dc.b	'Too many files are open!',cr,lf,'$'
illgmsg	dc.b	cr,lf,'Illegal instruction $'
ilgmsg2	dc.b	' at $'
ilgmsg3	dc.b	'.$'
dumpmsg	dc.b	cr,lf,'Register contents:$'
dmpmsg2	dc.b	cr,lf
	dc.b	'-AF- -BC- -DE- -HL- -SP- -S0- -S1- -S2- -S3- -PC- -op-'
	dc.b	cr,lf,'$'
dmpmsg3	dc.b	'Q to quit program, G to go on without tracing,'
	dc.b	'any other key to continue: $'
ilgbios	dc.b	cr,lf,'Illegal BIOS call $'
ilgbdos	dc.b	cr,lf,'Illegal BDOS call $'
tracemsg dc.b	cr,lf,'Start trace at >$'
tracemg2 dc.b	'  End trace at >$'
btrcmsg	dc.b	'Trace BIOS/BDOS calls? >$'
biosmsg	dc.b	'BIOS call $'
bdosmsg	dc.b	'BDOS call $'
atmsg	dc.b	' at $'
esctran	dc.b	'ABCD',ff,so,si,'H',$8D,'JKLMP'	;Escape sequence translation
prtname	dc.b	'PRT:RAW',0
badprt	dc.b	'Unable to open the list device!$'
	page
*************************************************************************
*									*
*	Variable storage						*
*									*
*************************************************************************

	bss	bss

savesp	ds.l	1		;Stack pointer save area
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		;File handles for opened files (or zero)
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
cmdline	ds.b	128		;Command line
cmdlinen:			;End of	command	line
comname	ds.b	13		;Name of file to load
comnamen:			;End of	file name
opnname	ds.b	17		;File name for OPEN or RENAME
renname	ds.b	17		;New file name for RENAME
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
btrcflg	ds.b	1		;Trace BIOS/BDOS calls.
bufflag	ds.b	1		;Console output is buffered.
fcbptr	ds.l	1		;Pointer to current FCB
listopn	ds.b	1		;The list device is open.
*************************************************************************
*									*
*	Target processor's address space                                *
*									*
*************************************************************************

	even

registers ds.b	10		;Actual	storage	for 8080's other registers
target	ds.b	$10000		;8080's universe

	end
