Page 1 of 1

Trouble getting extended memory version in Qbasic

Posted: Mon Jan 04, 2021 8:07 pm
by mikefromca
I followed the guide on QB chronicles to allow me to access the XMS routines, and I am still stuck. I don't know if its all because DOSBOX 0.74 is playing with XMS routines or not.

This is what I read:
http://www.petesqbsite.com/sections/tut ... 1-xms.html

So I then created assembly code and compiled it with NASM. This is my code:

Code: Select all

main:
;Save registers
PUSH BP
MOV BP, SP
PUSH ES
PUSH DI
PUSH DS
PUSH SI
;We pass in a structure as last 2 CALL ABSOLUTE parameters.
;ES:DI will have the pointer to that structure here.
MOV DI,[BP+08h]
mov ES,[DI]
MOV DI,[BP+06h]
mov DI,[DI]
;our Wanted Function is first integer in structure
mov AX,[ES:DI]
cmp AX,00h	;00h=XMS install check
jne ninit
  mov AX,4300h ;Call XMS checking routine
  int 2Fh
  cmp AL,80h ;AL must return 80h or XMS is not installed
  jne noxms
  mov AX,1h
  ;XMS status is 2nd integer in structure.
  ;Here it is 1 to let QB know XMS is installed
  mov [ES:DI+02h],AX 
  mov AX,4310h
  ;Save our structure address
  ;so next call wont wreck it
  push ES
  push DI
  ;Get the call address to most XMS functions
  int 2Fh
  ;ES:BX has call address but we will make it AX:BX
  mov AX,ES
  ;Restore our structure address
  pop DI
  pop ES
  ;Store memory address into a long integer in our struct
  ;Am I formatting the value wrong here?
  mov [ES:DI+08h],AX 
  mov [ES:DI+06h],BX  
  jmp ending
ninit:
cmp AX,01h
jne nquery ;386 query (Haven't tried this yet)
  mov AX,8800h
  call dword[ES:DI+06h]
  mov BH,0h
  ;mov [ES:DI+0Ch],BX ;stat
  ;mov [ES:DI+0Eh],EAX ;largest block
  ;mov [ES:DI+12h],EDX ;total kb
  ;mov [ES:DI+16h],ECX ;addr
  jmp ending
nquery:
cmp AX,00FFh
jne nver	;FFh=XMS version
  mov AX,0h
  call dword[ES:DI+06h] ;Use our long integer as address
  mov [ES:DI+04h],AX ;Store version into final integer in struct
  jmp ending
nver:
ending:
;restore registers
POP SI
POP DS
POP DI
POP ES
POP BP
;exit to QB
RETF 4h

noxms:
  ;Set our installed status to 0
  mov AX,0h
  mov [ES:DI+02h],AX 
jmp ending
And this is my QBASIC code:

Code: Select all

DECLARE FUNCTION acode$ ()

'This is the struct
TYPE xms
func AS INTEGER 'The function we want
inst AS INTEGER  'value determining if XMS is installed.
xver AS INTEGER 'version of XMS installed
addr AS LONG 	     'Address to use to call extended XMS routines
END TYPE

DIM x AS xms 'call this as x in here

x.func = 0 'Start with function 0: Check for XMS existance
x.inst = 0 'Assume nothing is installed
x.xver = 0 'Assume no version
DIM cd AS STRING * 500 'Reserve 500 bytes for binary code
cd = acode$ 'and fit the binary code in (code length is under 300 bytes)
CLS 'clean screen
DEF SEG = VARSEG(cd) 'use our code
'Here we inject our structure into call absolute
CALL absolute(VARSEG(x), VARPTR(x), VARPTR(cd))
PRINT x.inst, x.xver 'here x.inst returns 1 which is correct for just about every computer
x.func = &HFF& 'Check for memory version
'Program never goes past this point and DOSBOX locks up
CALL absolute(VARSEG(x), VARPTR(x), VARPTR(cd)) 
PRINT "results"
PRINT x.xver
END

FUNCTION acode$
'First value is hex values of the compiled code after running unix utilities nasm and xxd -p on it.
'I used ndisasm on the binary and the code returned fine.
w$ = "5589e506571e568b7e088e058b7e068b3d268b0583f8007525b80043cd2f3c807548b8010026894502b810430657cd2f8cc05f072689450826895d06eb2483f801750cb800882666ff5506b700eb133dff00750eb800002666ff550626894504eb005e1f5f075dca0400b8000026894502ebef"
'here we manually convert hex values to binary and store it in memory
cd$ = "": FOR n% = 1 TO LEN(w$) STEP 2: cd$ = cd$ + CHR$(VAL("&H" + MID$(w$, n%, 2))): NEXT
acode$ = cd$
END FUNCTION

Am I formatting my call address in assembly code correctly for NASM? because I think the problem comes down to that because everytime I execute the second call absolute to retrieve the XMS version it always locks up.

Re: Trouble getting extended memory version in Qbasic

Posted: Mon Jan 04, 2021 10:54 pm
by mikefromca
OK, I think I fixed it.

for my calls to the XMS code I needed to add the FAR keyword in asm.

This is my new assembly code that works:

Code: Select all

segment code
;XMS ACCESS
;Call absolute(codeseg+ptr,dataseg+ptr,codeseg+ptr)
;Type xms...
;int: func
;int: install check
;int: xms ver
;dint: xmsaddr
main:
PUSH BP
MOV BP, SP
PUSH ES
PUSH DI
PUSH DS
PUSH SI
MOV DI,[BP+08h] ;ES:DI=struct entry point
mov ES,[DI]
MOV DI,[BP+06h]
mov DI,[DI]
mov AX,[ES:DI]
cmp AX,00FEh	;FEh=addr call test
jne naddr
  call getaddr
  jmp ending
naddr:

cmp AX,00FFh	;FFh=XMS ver
jne nver
  call getaddr
  mov AX,0h
  call far [xmscall]
  mov [ES:DI+04h],AX ;XMS ver
  jmp ending
nver:
cmp AX,00h	;00h=XMS install check
jne ninit
  mov AX,4300h
  int 2Fh
  cmp AL,80h
  jne noxms
  mov AX,1h
  mov [ES:DI+02h],AX ;XMS install check
  jmp ending
ninit:
;XRAM address must be loaded beyond here
cmp AX,01h
jne nquery ;386 query
  mov AX,8800h
  call far [xmscall]
  mov BH,0h
  ;mov ES:[DI+0Ch],BX ;stat
  ;mov ES:[DI+0Eh],EAX ;largest block
  ;mov ES:[DI+12h],EDX ;total kb
  ;mov ES:[DI+16h],ECX ;addr
  jmp ending
nquery:
ending:
POP SI
POP DS
POP DI
POP ES
POP BP
RETF 4h

xmscall:
dd 0 ;This gets changed to the address of the XMS routines

noxms:
  mov AX,0h
  mov [ES:DI+02h],AX ;XMS install check
jmp ending

getaddr:
  push AX
  push ES
  push DI
  mov AX,4310h
  int 2Fh
  mov word[xmscall+2],ES ;mem addr
  mov word[xmscall],BX  
  pop DI
  pop ES
  pop AX
ret