
%if 0

lDebug X commands - EMS support

Copyright (C) 1995-2003 Paul Vojta
Copyright (C) 2008-2023 E. C. Masloch

Usage of the works is permitted provided that this
instrument is retained with the works, so that any entity
that uses the works is notified of this instrument.

DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.

%endif

	usesection lDEBUG_DATA_ENTRY
	align 2, db 0
xaresult:	dw -1

	usesection lDEBUG_CODE

		; X commands - manipulate EMS memory.
		;
		; Reference:
		;  http://www.nondot.org/sabre/os/files/MemManagement/LIMEMS41.txt

xx:	cmp al, '?'
	je xhelp		; if a call for help
	or al, TOLOWER
	cmp al, 'a'
	je xa			; if XA command
	cmp al, 'd'
	je xd			; if XD command
	cmp al, 'm'
	je xm			; if XM command
	cmp al, 'r'
	je xr			; if XR command
	cmp al, 's'
	je xs			; if XS command
	jmp error

xhelp:	lodsb
	extcallcall chkeol
.eol_checked:
	mov dx, msg.xhelp
internaldatarelocation
%if ELD
	extcallcall putsz
	retn
%else
	jmp putsz_exthelp	; print string and return
%endif

		; XA - Allocate EMS.
xa:	call emschk
	extcallcall skipcomma
	extcallcall getword	; get argument into DX
	extcallcall chkeol	; expect end of line here
	mov bx, dx

	or word [xaresult], strict byte -1
internaldatarelocation -3
	mov ax, 5A00h		; use the EMS 4.0 version to alloc 0 pages
	test bx, bx
	jz short .nullcnt
	mov ah, 43h		; allocate handle
.nullcnt:
	call emscall
	xchg ax, dx		; mov ax, dx
	mov word [xaresult], ax
internaldatarelocation
	mov di, xaans1
internaldatarelocation
	extcallcall hexword
	mov dx, xaans
internaldatarelocation
	jmp putsz		; print string and return

		; XD - Deallocate EMS handle.
xd:	call emschk
	extcallcall skipcomma
	extcallcall getword	; get argument into DX
	extcallcall chkeol	; expect end of line here

	mov ah, 45h		; deallocate handle
	call emscall
	xchg ax, dx		; mov ax,dx
	mov di, xdans1
internaldatarelocation
	extcallcall hexword
	mov dx, xdans
internaldatarelocation
	jmp putsz		; print string and return

		; XR - Reallocate EMS handle.
xr:	call emschk
	extcallcall skipcomma
	extcallcall getword	; get handle argument into DX
	mov bx, dx
	extcallcall skipcomm0
	extcallcall getword	; get count argument into DX
	extcallcall chkeol	; expect end of line here
	xchg bx, dx

	mov ah, 51h		; reallocate handle
	call emscall
	mov dx, xrans
internaldatarelocation
	jmp putsz		; print string and return

		; XM - Map EMS memory to physical page.
xm:	call emschk
	extcallcall skipcomma
	extcallcall getword	; get logical page (FFFFh means unmap)
	mov bx, dx		; save it in BX
	extcallcall skipcomm0
	extcallcall getbyte	; get physical page (DL)
	push dx
	extcallcall skipcomm0
	extcallcall getword	; get handle into DX
	extcallcall chkeol	; expect end of line
	 pop ax			; recover physical page into AL
	 push ax
	mov ah, 44h		; function 5 - map memory
	call emscall
	mov di, xmans1
internaldatarelocation
	xchg ax, bx		; mov ax, bx
	extcallcall hexword
	mov di, xmans2
internaldatarelocation
	pop ax
	extcallcall hexbyte
	mov dx, xmans
internaldatarelocation
	jmp putsz		; print string and return

		; XS - Print EMS status.
xs:
	call emschk
	lodsb
	extcallcall chkeol	; no arguments allowed

		; First print out the handles and handle sizes.  This can be done either
		; by trying all possible handles or getting a handle table.
		; The latter is preferable, if it fits in memory.
	mov ah, 4Bh		; function 12 - get handle count
	call emscall
%if ELD
	cmp bx, 256 / 4		; (hardcode line_out length)
%else
	cmp bx, (line_out_end-line_out)/4
%endif
	jbe short xs3			; if we can do it by getting the table
	xor dx, dx		; handle

xs1:
		; try EMS 4.0 function 5402h to get total number of handles
	mov ax, 5402h
	call emscall.witherrors
	mov cx, bx		; cx = number of handles
	jz @F

	mov cx, 0FFh		; total number of handles (assumed)
				;  this does not match the prior code here,
				;  which used 100h handles assuming that
				;  0FFh is the last valid handle number.
				; however, if we assume that there are 0FFh
				;  valid handles then the last number is 0FEh!
@@:

	mov ah, 4Ch		; function 13 - get handle pages
	call emscall.witherrors
	jnz short .err
	xchg ax, bx		; mov ax,bx
	call hndlshow
.cont:
	inc dx			; increment handle number to access
	jz @F			; (if 0000h handles, do not loop forever)
	cmp dx, cx		; end of the loop ?
	jb short xs1		; if more to be done -->
@@:
	jmp short xs5		; done with this part

.err:
	cmp ah, 83h		; no such handle?
	je short .cont		; just skip -->
	jmp emscall.errorhandle	; if other error -->

		; Get the information in tabular form.
xs3:
	mov ah, 4Dh		; function 14 - get all handle pages
	mov di, relocated(line_out)
linkdatarelocation line_out
	call emscall
	test bx, bx
	jz short xs5
	mov si, di
xs4:
	lodsw
	xchg ax, dx
	lodsw
	call hndlshow
	dec bx
	jnz short xs4		; if more to go

xs5:
	mov dx, crlf
internaldatarelocation
	extcallcall putsz	; print string

		; Next print the mappable physical address array.
		; The size of the array shouldn't be a problem.
	mov ax, 5800h		; function 25 - get mappable phys. address array
	mov di, relocated(line_out)
linkdatarelocation line_out	; address to put array
	call emscall
	mov dx, xsnopgs
internaldatarelocation
	jcxz xs7		; NO mappable pages!

	mov si, di
xs6:
	push cx
	lodsw
	mov di, xsstr2b
internaldatarelocation
	extcallcall hexword
	lodsw
	mov di, xsstr2a
internaldatarelocation
	extcallcall hexbyte
	mov dx, xsstr2
internaldatarelocation
	extcallcall putsz	; print string
	pop cx			; end of loop
	test cl, 1
	jz short xs_nonl
	mov dx, crlf		; blank line
internaldatarelocation
	extcallcall putsz	; print string
xs_nonl:
	loop xs6
	mov dx, crlf		; blank line
internaldatarelocation
xs7:
	extcallcall putsz	; print string

		; Finally, print the cumulative totals.
	mov ah, 42h		; function 3 - get unallocated page count
	call emscall
	mov ax, dx		; total pages available
	sub ax, bx		; number of pages allocated
	mov bx, xsstrpg
internaldatarelocation
	call sumshow		; print the line
	mov ah, 4Bh		; function 12 - get handle count
	call emscall
	push bx			; number of handles allocated

		; try EMS 4.0 function 5402h to get total number of handles
	mov ax, 5402h
	call emscall.witherrors	; don't use emscall, this function may fail!
	mov dx, bx
	jz @F

	mov dx, 0FFh		; total number of handles
@@:
	pop ax			; ax = number of handles allocated
	mov bx, xsstrhd
internaldatarelocation
	jmp sumshow		; print the line

		; Call EMS
emscall:
	call .witherrors
	jz short .ret		; return if OK
.errorhandle:
	mov al, ah
	cmp al, 8Bh
	jg short .ce2		; if out of range (signed comparison intended)
	cbw
	mov bx, ax
	shl bx, 1
	mov dx, word [emserrs+100h+bx]
internaldatarelocation
	test dx, dx
	jnz short .ce4		; if there's a word there
.ce2:
	mov dx, emserrx
internaldatarelocation
	extcallcall putsz
	mov di, relocated(line_out)
linkdatarelocation line_out
	extcallcall hexbyte
	extcallcall putsline_crlf
	extcallcall cmd3	; quit

.witherrors:
%if _PM
	extcallcall ispm
	jnz short .rm
subcpu 286
	push word [ss:relocated(pspdbg)]
linkdatarelocation pspdbg
	push 67h
 %if ELD
	extcall intcall_ext_return_es, PM required	; must NOT be extcallcall
	add sp, 4		; discard es and interrupt number
 %else
	call intcall
 %endif
	db __TEST_IMM16		; (skip int opcode)
subcpureset
.rm:
%endif
	int 67h
	test ah, ah
.ret:
emschk.ret:
	retn


		; Check for EMS
		; maybe should disable this while bootloaded ?
emschk:
	mov al, 67h
	extcallcall intchk	; ZR if offset = -1 or segment = 0
				; CHG: ax, dx, bx
	jz .failed
	mov ah, 46h
	call emscall.witherrors	; get version
	jz short .ret		; success -->
.failed:
	mov dx, emsnot
internaldatarelocation
emscall.ce4:
	jmp prnquit		; otherwise abort with message -->

		; HNDLSHOW - Print XS line giving the handle and pages allocated.
		;
		; Entry	DX	Handle
		;	AX	Number of pages
		;
		; Exit	Line printed
		;
		; Uses	ax, di
hndlshow:
	mov di, xsstr1b
internaldatarelocation
	extcallcall hexword
	mov ax, dx
	mov di, xsstr1a
internaldatarelocation
	extcallcall hexword
	push dx
	mov dx, xsstr1
internaldatarelocation
	extcallcall putsz	; print string
	pop dx
	retn

		; SUMSHOW - Print summary line for XS command.
		;
		; Entry	AX	Number of xxxx's that have been used
		;	DX	Total number of xxxx's
		;	BX	Name of xxxx
		;
		; Exit	String printed
		;
		; Uses	AX, CX, DX, DI
sumshow:
	mov di, xsstr3
internaldatarelocation
	push di
	call trimhex
	xchg ax, dx		; mov ax,dx
	mov di, xsstr3a
internaldatarelocation
	call trimhex
	pop dx			; mov dx,xsstr3
	extcallcall putsz	; print string
	mov dx, bx
	extcallcall putsz	; print string
	mov dx, xsstr4
internaldatarelocation
	jmp putsz		; print string and return

		; TRIMHEX - Print word without leading zeroes.
		;
		; Entry	AX	Number to print
		;	DI	Where to print it
		;
		; Uses	AX, CX, DI.
trimhex:
	extcallcall hexword
	sub di, 4		; back up DI to start of word
	mov cx, 3
	mov al, '0'
.loop:
	scasb
	jne .done		; return if not a '0'
	mov byte [di-1], ' '
	loop .loop
.done:
	retn
