;[]-------------------------------------------------------------------------[]
;|	Program name: 3_2_2.ASM                                              |
;|	Image   file: 3_2_2.COM                                              |
;|	Note        : This is a TSR program.                                 |
;|                    It is combined 3_1_6.ASM with 3_2_1.ASM.               |
;|                    It can write the register value to 'REGISTER.DAT' and  |
;|                      load the register value from the file.               |
;|                    It also can use INT 05H to display the register value. |
;[]-------------------------------------------------------------------------[]


cseg	segment
	assume	cs:cseg,ds:cseg
	org	100H
start:
	jmp	initialize

;------- Data area ---------------------

old_int05	dd	?
old_int13	dd	?
old_int60	dd	?
old_int61	dd	?
in_dos_seg	dw	?
in_dos_off	dw	?
busy_05		db	0

count		dw	0
reg_buf		dw	800H dup (0FFFFH)
reg_file	db	'REGISTER.DAT',0
handle		dw	0
reg_title	db	' AX    BX    CX    DX    AX    BX    CX    DX   FLAG'
		db	0DH,0AH,0

;------- Define area -------------------

BLOCK		EQU	9
AX_1		EQU	[di+00]
BX_1		EQU	[di+02]
CX_1		EQU	[di+04]
DX_1		EQU	[di+06]
AX_2		EQU	[di+08]
BX_2		EQU	[di+10]
CX_2		EQU	[di+12]
DX_2		EQU	[di+14]
FLAG_2		EQU	[di+16]

;------- Include area ------------------

DEBUG	EQU	1
include	register.inc
include	interrup.inc
include	display.inc
include	file.inc
include	debug.inc

;------- INT 05H -----------------------

new_int05	proc	far

	cmp	cs:busy_05,1		; Test for INT 05H busy
	je	i05_done		; If busy then branch

	sti				; Enable interrupt
	mov	cs:busy_05,1		; Set INT 05H busy
	call	dis_buffer		; Display buffer
	mov	cs:busy_05,0		; Reset INT 05H idle

i05_done:
	iret				; Return calling program

new_int05	endp

;---------------------------------------
; Display buffer that saved register values
;---------------------------------------

dis_buffer	proc	near

	pushall				; Save all the register values

	mov	ax,cs			; Adjust DS, ES
	mov	ds,ax
	mov	es,ax

	call    dreturn			; Display return
	dstring	reg_title		; Display title

	mov	bx,offset reg_buf	; Get buffer start address
	mov	cx,0			; Let CX to be a counter

;---------------------------------------
; In the following routine, AX, BX, CX, DX are used for:
;	AX: displaying data
;	BX: point to buffer which to be displayed
;	CX: total displayed data, used for comparing with count
;	DX: control display format
;	    ( one block per line & insert one blank line per two blocks)
;---------------------------------------

n3:	mov	dx,0			; Reset DX counting
n2:	mov	ax,[bx]			; Get data
	call	dsword			; Display it
	dstr	<' ',' '>		; Display '  '
	add	bx,2			; BX point to next data
	add	dx,1			; Increase DX
	add	cx,2			; Increase CX
	cmp	dx,BLOCK		; Does one block have been displayed ?
	jne	n1			; If not, check another
	call	dreturn			; If yes, display return
	jmp	n2			; and go on displaying
n1:	cmp	dx,BLOCK * 2		; Does two blocks have been displayed ?
	jne	n2			; If not, go on displaying
	call	dreturn			; If yes, display return
	call	dreturn			; and insert one blank line
	cmp	cx,count		; Does all data have been displayed?
	jbe	n3			; If not, go on displaying

	popall				; Restore all the register values

	ret				; Return

dis_buffer	endp

;------- INT 13H -----------------------

new_int13	proc	far

	sti				; Enable interrupt

	pushf				; Save FLAG value
	call	in_dos			; Check in_dos
	jne	i13_1			; It is in dos, so branch

	cmp     ah,00H			; Check for reseting disk
	je	i13_1			; If true, then branch

	cmp	dl,00H			; Check for accessing disk A
	je	i13_2			; If true, go to save routine.

i13_1:	popf				; Restore FLAG value
	cli				; Disable interrupt
	jmp	cs:old_int13		; Jump to Old INT 13H routine

i13_2:	popf				; Restore FLAG value
	call	record_reg1		; Record register value
	call	transfer_data		; Transfer data
	call	record_reg2		; Record register value
	ret	2			; Discard FLAG value in stack
new_int13	endp

;---------------------------------------
; Check IN DOS subroutine.
; If INT 21H is idle, then set ZR flag, else reset to NR flag.
;---------------------------------------

in_dos		proc	near
	pushr	<bx,es>			; Save register
	mov	es,cs:in_dos_seg	; Let ES:BX point to in_dos byte
	mov	bx,cs:in_dos_off	;
	cmp	byte ptr es:[bx],0	; Check this byte (if idle then set ZR)
	popr	<es,bx>			; Restore register
	ret
in_dos		endp

;---------------------------------------
; Record register value before accessing disk.
;---------------------------------------

record_reg1	proc	near

	pushall				; Save all the register values

	mov	ax,cs			; Adjust DS, ES
	mov	ds,ax
	mov	es,ax

	cmp	count,0F00H		; Check for buffer remainder size
	ja	record1_done		; Not enough, don't record

	mov	di,offset reg_buf	; Get buffer start address
	add	di,count		; Adjust di with count

	get_ax				; Get AX from stack
	mov	AX_1,ax			; Put AX to buffer
	get_bx				; Get BX from stack
	mov	BX_1,ax			; Put BX to buffer
	get_cx				; Get CX from stack
	mov	CX_1,ax			; Put CX to buffer
	get_dx				; Get DX from stack
	mov	DX_1,ax			; Put DX to buffer

record1_done:

	popall				; Restore all the register value

	ret				; Return

record_reg1	endp

;---------------------------------------
; Transfer data by using Old INT 13H
;---------------------------------------

transfer_data	proc	near

	cli
	pushf
	call	cs:old_int13		; Call old_int13 to access disk
	sti

	ret

transfer_data	endp

;---------------------------------------
; Record register value after accessing disk.
;---------------------------------------

record_reg2	proc	near

	pushall				; Save all the register values

	mov	ax,cs			; Adjust DS, ES
	mov	ds,ax
	mov	es,ax

	cmp	count,0F00H		; Check for buffer remainder size
	ja	record2_done		; Not enough, don't record

	mov	di,offset reg_buf	; Get buffer start address
	add	di,count		; Adjust di with count

	get_ax				; Get AX from stack
	mov	AX_2,ax			; Put AX to buffer
	get_bx				; Get BX from stack
	mov	BX_2,ax			; Put BX to buffer
	get_cx				; Get CX from stack
	mov	CX_2,ax			; Put CX to buffer
	get_dx				; Get DX from stack
	mov	DX_2,ax			; Put DX to buffer
	get_f				; Get FLAG from stack
	mov	FLAG_2,ax		; Put FLAG to buffer

	add	count,BLOCK * 2		; Increase count with block size

	call	save_reg		; Write reg_buf to file 'REGISTER.DAT'

record2_done:

	popall				; Restore all the register values

	ret				; Return

record_reg2	endp

;------- INT 13H Subroutine ------------

;---------------------------------------
; Save buffer data to 'REGISTER.DAT'.
;---------------------------------------

save_reg	proc	near

	pushall				; Save all the register values

	mov	ax,cs			; Adjust DS, ES
	mov	ds,ax
	mov	es,ax

	h_creat	reg_file,0		; Creat 'REGISTER.DAT' file
	mov	cx,count		; Get count value
	add	cx,2			; Write count+2 bytes
	h_write	handle,count,cx		; from count to file
	h_close	handle			; Close 'REGISTER.DAT'

	popall				; Restore all the register values

	ret				; Return

save_reg	endp

;---------------------------------------
; Load buffer data from 'REGISTER.DAT'.
;---------------------------------------

load_reg	proc	near

	pushall				; Save all the register values

	mov	ax,cs			; Adjust DS, ES
	mov	ds,ax
	mov	es,ax

	h_open	reg_file,RDWR		; Open 'REGISTER.DAT'
	jc	l1			; If error then branch
	h_read	handle,count,1002H	; Read 1008H bytes to count
	h_close	handle			; Close 'REGISTER.DAT'

l1:	popall				; Restore all the register values

	ret				; Return

load_reg	endp

;------- INT 60H -----------------------

new_int60	proc	far

	assume	cs:cseg,ds:nothing	; Override segment

	sti
	pushr	<ax,dx,ds>

	set_int	05H,<word ptr old_int05>,<word ptr old_int05[2]>
	set_int	13H,<word ptr old_int13>,<word ptr old_int13[2]>
	set_int	60H,<word ptr old_int60>,<word ptr old_int60[2]>
	set_int	61H,<word ptr old_int61>,<word ptr old_int61[2]>

	popr	<ds,dx,ax>
	iret

new_int60	endp

;------- Main program ------------------

initialize:

	assume	cs:cseg,ds:cseg

	mov	ah,34H			; Get in_dos byte address
	int	21H
	mov	in_dos_seg,es
	mov	in_dos_off,bx

	call	load_reg		; Load data to reg_buf

	get_int	05H,old_int05
	set_int	05H,<offset new_int05>
	get_int	13H,old_int13
	set_int	13H,<offset new_int13>
	get_int	60H,old_int60
	set_int	60H,<offset new_int60>
	get_int	61H,old_int61
	set_int	61H,<offset new_int61>

	mov	dx,offset initialize	; Terminate and stay resident
	int	27H

cseg	ends
	end	start
