PAGE 55,132
TITLE I/O SIMULATION TEST PROGRAM
.286

;
;	This is a sample user qualified breakpoint.
;

INT_NUM EQU	65H		;THIS IS THE PSUDEO INTERRUPT NUMBER

REG_WORD STRUC
REG_DI		DW	?
REG_SI		DW	?
REG_BP		DW	?
REG_SP		DW	?
REG_BX		DW	?
REG_DX		DW	?
REG_CX		DW	?
REG_AX		DW	?
REG_IP		DW	?
REG_CS		DW	?
REG_FLAGS	DW	?
REG_WORD ENDS

REG_BYTE STRUC
REG_DI1 	DW	?
REG_SI1 	DW	?
REG_BP1 	DW	?
REG_SP1 	DW	?
REG_BL		DB	?
REG_BH		DB	?
REG_DL		DB	?
REG_DH		DB	?
REG_CL		DB	?
REG_CH		DB	?
REG_AL		DB	?
REG_AH		DB	?
REG_BYTE ENDS

STACK SEGMENT STACK
        DW      50 DUP(0)
STACK ENDS

DATA SEGMENT BYTE PUBLIC 'DATA'

NEW_VAL DW	?
NEXT_IN_LOC DW	0
NEXT_OUT_LOC DW  0
PUBLIC BUFFIN
BUFFIN	 DW	1000H	DUP(0)
PUBLIC BUFFOUT
BUFFOUT  DW	1000H	DUP(0)
DATA ENDS

CODE SEGMENT PUBLIC 'CODE'
CODE ENDS

LAST SEGMENT PUBLIC 'LAST'
LAST ENDS

CODE SEGMENT BYTE PUBLIC 'CODE'
ASSUME CS:CODE,DS:DATA
PUBLIC START
START:	MOV	BX,LAST 		;THE END OF THE PROGRAM
	MOV	AX,ES			;SUBTRACT FROM THE TOP OF THE HEADER
	SUB	BX,AX			;BX NOW HAS THE SIZE TO KEEP WHEN WE
					; TERMINATE AND STAY RESIDENT

	MOV	AX,DATA 		;GET OUR DATA SEGMENT
        MOV     DS,AX
	XOR	AX,AX			;POINT ES AT SEGMENT ZERO
	MOV	ES,AX			;

	MOV	AX,OFFSET IO_ROUTINE	;GET A POINTER TO THE I/O ROUTINE
	MOV	ES:[INT_NUM*4],AX	;POINT THE INTERRUPT TO THE IO ROUTINE
	MOV	AX,CS			;GET THE CURRENT SEGMENT
	MOV	ES:[INT_NUM*4+2],AX	;MOVE IT IN

	MOV	AH,31H			;USE THE MSDOS KEEP PROCESS FUNCTION
	MOV	DX,BX			;GET THE SIZE OF OUR ROUTINES
	INT	21H			;THATS IT

;---------------------------------------------------------------------------
;  This routine will be called when ever Soft-ICE reaches a break point
; and the ACTION is set to our INT_NUM.  The stack will be set up as if
; a normal REAL mode interrupt had happend. ie;
;
;		    FLAGS
;		    CS
;		    IP
;  The opcodes that we will be looking for are:
;	0ECH - IN  AL,DX
;	0EDH - IN  AX,DX
;	0EEH - OUT AL,DX
;	0EFH - OUT AX,DX
;   Note that bit 02h tells us whether it is an IN or an OUT and bit 01h tells
;  us whether it is a BYTE or a WORD.
;
;---------------------------------------------------------------------------
IO_ROUTINE PROC FAR
	PUSHA				;SAVE ALL THE CURRENT REGISTERS
	MOV	BP,SP			;USE BP TO POINT BACK ONTO THE STACK
	PUSH	DS			;SAVE THE SEGMENTS ALSO
	PUSH	ES			;
	MOV	AX,DATA 		;GET OUR DATA SEGMENT
	MOV	DS,AX			;SET IT UP
	MOV	AX,[BP].REG_CS		;GET THE OLD CS REGISTER
	MOV	ES,AX			;SET ES TO THAT SEGMENT
	MOV	SI,[BP].REG_IP		;USE SI TO POINT TO THE IP
	MOV	AL,ES:[SI-1]		;GET THE OPCODE OF THE I/O INSTRUCTION
	CMP	AL,0ECH 		;WAS IT IN IT I/O OPCODE RANGE?
	JB	NOT_AN_IO		;NOPE
	CMP	AL,0EFH 		;CHECK THE HIGH END
	JA	NOT_AN_IO		;NOPE NOT THIS ONE EITHER
	MOV	DX,[BP].REG_DX		;GET THE DX REGISTER FROM THE STACK
	MOV	CL,0			;ASSUME IT WAS A BYTE ACCESS
	TEST	AL,01H			;WAS IT A BYTE OR A WORD?
	JZ	BYTE_ACCESS		;YES, JUST A BYTE
	MOV	CL,1			;MARK IT AS WORD ACCESS
BYTE_ACCESS:
	TEST	AL,02H			;WAS IT AN IN OR AN OUT
	JNZ	OUT_OPCODE		;IT WAS AN OUT
IN_OPCODE:
;---------------------------------------------------------------------------
;  ENTRY:   CL = BYTE OR WORD ACCESS
;		 0 = BYTE
;		 1 = WORD
;
;	     DX = THE I/O PORT
;
;  EXIT:
;	     [BP].REG_AX OR [BP].REG_AL   SHOULD HAVE THE SIMULATED VALUE
;
;---------------------------------------------------------------------------

	MOV	BX,NEXT_IN_LOC
	MOV	AX,BUFFIN[BX+2]
	MOV	[BP].REG_AL,AL		;MOVE IN JUST A BYTE
	ADD	NEXT_IN_LOC,4
	MOV	AX,NEW_VAL		;GET THE LAST OUTPUT VALUE
	OR	CL,CL			;IS IT A BYTE OR A WORD
	JZ	DO_BYTE 		;JUST A BYTE
	MOV	[BP].REG_AX,AX		;MOVE IT IN
	JMP	IO_DONE
DO_BYTE:
	MOV	[BP].REG_AL,AL		;MOVE IN JUST A BYTE
	JMP	IO_DONE
OUT_OPCODE:
;---------------------------------------------------------------------------
;  ENTRY:   CL = BYTE OR WORD ACCESS
;		 0 = BYTE
;		 1 = WORD
;
;	     DX = THE I/O PORT
;
;	     [BP].REG_AX OR [BP].REG_AL   THE VALUE GOING OUT
;
;---------------------------------------------------------------------------
	MOV	AX,[BP].REG_AX		;GET THE VALUE
	MOV	NEW_VAL,AX		;SAVE IT

	MOV	BX,NEXT_OUT_LOC
	MOV	BUFFOUT[BX],DX
	MOV	BUFFOUT[BX+2],AX
	ADD	NEXT_OUT_LOC,4

IO_DONE:
NOT_AN_IO:
	POP	ES			;RESTORE ALL OF THE SEGMENTS AND REGS
	POP	DS			;
	POPA				;
	IRET				;RETURN TO THE INSTRUCTION AFTER THE
					; I/O
IO_ROUTINE ENDP


CODE ENDS

END START
