*;**********************************
; "CPM" emulation code for AVSIM  *
;                                 *
;  rps -- 17 june 87              *
;**********************************
;
; ==================================================================
;NOTES:
;   	1) This is not, in any way, CP/M, but rather a way
;	(I hope) to emulate it on AVSIM.
;
;	2) CP/M and CP/M-like systems differ in what is returned
;	in "duplicate" registers.  This is "standard".  (I hope!)
;
;	3) You must change "MEMSIZE" (below) to fit
;	the CP/M system you are emulating
;
;	4) You must attach AVSIM I/O disk files to the proper
;	memory locations for each function that you will
; 	use:
;		SYMBOL	DIRECTION  FUNCTION
;		kybdin	in         keyboard character in
;		coutpt  out        terminal (CRT, maybe?) out
;		ptr	out	   printer
;		pch	out        paper tape punch
;		rdr	in         paper tape reader
;		kbufin	in	   keyboard buffer line input --
;				   (reads from file until CR)
;
;       5) Set all memory to RAM.
;
;	6) You must assemble and link this with "AVMACZ80 CPM".
;	Then link it with "AVLINK CPM=CPM -SY". 
;       Load the other program into AVSIM with "L D program.HEX"
;       and "L S program.SYM".
;	Then load this code into AVSIM with "L D CPM.HEX",
;	and symbols with "L S CPM.SYM".
;       Note we are loading as "data", NOT ROM.  This is because
;       we want to keep all memory as RAM, as in CPM (many
;       programs DS storage within themselves).
;
;	7) Put a breakpoint on "bkpt" to trap on rest or end 
;       of program, breakpoint "disk" to trap disk access.
;
;	8) Don't forget to have your program setup space for 
;       a stack and set the SP (if you are workig in assembler).
;       (I think that CP/M sets a default stack at 0100h.
;       This program sets up memory there, but does NOT set 
;       the SP.)
;
; ==================================================================
;
;
	PUBLIC kybdin,coutpt,ptr,pch,rdr,kbufin,bkpt,disk
;
MEMSIZE	EQU	48 * 1024       ;your choice!

	DEFSEG LOWCPM, START=0000H, CLASS=DATA
	SEG LOWCPM

bkpt:	JP	0100h		;re-start program on reset

IOBYTE:	DB	00000000B	;set IOBYTE here if needed
LOGIN:	DB 	00H		;logged in drive & user number
TOPMEM: JP	BDOS		;top of avail. memory (top TPA)
	DS	30H		;reserved (intr. vectors, etc.)
RST7:	DS 	03H		;RST7 -- used by DDT
	DS 	05H		;reserved (intr. vectors)
	DS	10H		;CBIOS scratch area
	DS	0CH		;not used
FCB:	DS	21H		;default file control block
	DS	03h		;default random record pos.
	DS	80H		;DMA buffer area



	DEFSEG HIGHCPM, START=(3C00H + MEMSIZE - 5000H), CLASS=DATA
	SEG HIGHCPM
BDOS:
	JP	BDOS2

	ORG (4A00H + MEMSIZE - 5000H)
BIOS:
BOOT:	JP 	0100H		;reset by going to start of program	
WBOOT:  JP 	0100H		;well, we'll do the same as BOOT
CONST:  JP 	KBSTAT		;actually, we'll be always ready
CONIN:	JP 	KBIN		;we'll get char from file
CONOUT: JP 	CRTOUT		;we'll write to file
LIST:   JP 	PRNTR		;again, to file
PUNCH:  JP 	PNCH		;again, to file (does anyone use this?)
READER:	JP 	READR		;from file
HOME:	JP 	NULL		;ignore from here on -- at least for now
SELDSK: JP 	NULL
SETTRK: JP 	NULL
SETSEC: JP 	NULL
SETDMA: JP 	NULL
READ:	JP 	NULL
WRITE:  JP 	NULL
LISTST: JP 	NULL
SECTRAN: JP 	NULL

KBSTAT:
	LD 	A,0FFH		;data always ready
	RET

kybdin: DS	01H		;keyboard "buffer"
KBIN:
	LD 	A, (kybdin)	;connect input file to "kybdin!"!!
	RET

coutpt: DS	01H		;crt "buffer"
CRTOUT:
	LD	A,C		;connect output file to "coutpt"!!
	LD	(coutpt),A	
	RET

ptr: DS	01H			;printer "buffer"
PRNTR:
	LD	A,C		;connect output file to "ptr"!!
	LD	(ptr),A
	RET

pch: 	DS	01H		;punch "buffer"
PNCH:
	LD	A,C		;connect output file to "pch"!!
	LD	(pch),A
	RET

rdr: 	DS	01H		;tape reader "buffer"
READR:
	LD 	A, (rdr)	;connect input file to "rdr"!!
	RET

NULL:
disk:	RET			;for now, do nothing.



BDOS2:
	LD	A,C
	CP 	00H
	JP	Z,F00
	CP 	01H
	JP	Z,F01
	CP 	02H
	JP	Z,F02
	CP 	03H
	JP	Z,F03
	CP 	04H
	JP	Z,F04
	CP 	05H
	JP	Z,F05
	CP 	06H
	JP	Z,F06
	CP 	07H
	JP	Z,F07
	CP 	08H
	JP	Z,F08
	CP 	09H
	JP	Z,F09
	CP 	0AH
	JP	Z,F0A
	CP 	0BH
	JP	Z,F0B

	RET			;just go back if disk call
	
F00:
	LD	HL,0000H	;reset - just start over
	ADD	HL,SP		;reset - just start over
	LD	(HL),0000H
	RET			

F01:
	CALL	CONIN		;console read
	LD	L,A
	LD 	H,00H
	RET

F02: 
	LD	C,E		;console out
	CALL 	CONOUT
	RET

F03:
	CALL	READER		;reader read
	LD	L,A
	LD 	H,00H
	RET

F04: 
	LD	C,E		;punch out
	CALL 	PUNCH
	RET

F05: 
	LD	C,E		;list out
	CALL 	LIST
	RET

F06:
	LD	A,E		;direct console I/O
 	CP	A,0FFH
	JP	Z,F06I		;wants to input
	LD	C,E		;output
	CALL    CONOUT
	RET
F06I:
	CALL	CONIN		;input
	LD	L,A
	LD 	H,00H
	RET

F07:
	LD	A,(IOBYTE)	;get iobyte
	LD	H,00H
	LD	L,A
	RET

F08:
	LD	A,E		;set iobyte
	LD	(IOBYTE),A	
	RET

F09:
	LD	A,(DE)		;print string
	CP	'$'
	JP	Z,F091
	LD	C,A
	CALL	CONOUT
	INC	DE
	JP	F09
F091:	RET


kbufin: DS	01H		;attach I/O file here if you use this!
F0A:				;cons buffr read (reads file to CR)
	LD	L,00H		;counter
F0A1:	LD	A,(kbufin)
	CP 	0DH
	JP	Z,F0A2
	CP	0AH
	JP	Z,F0A1		;ignore LF
	LD	(DE),A
	INC	DE
	INC	L
	JP	F0A1
F0A2:	
	LD	A,L
	LD	H,00H
	RET

F0B:
	CALL	CONST		;get console status
	LD	L,A
	LD	H,00H
	RET

	end


