'===========================================================================
' Subject: ASSEMBLY IN QBASIC 6: INT86X       Date: 02-07-97 (22:15)       
'  Author: Rick Elbers                        Code: QB, QBasic, PDS        
'  Origin: rick@tip.nl                      Packet: ASMCODE.ABC
'===========================================================================
'ASSEMBLY IN QBASIC PART 6: CALL INTERRUPT/ INTERRUPTX
'Rick februari 1997 []

DEFINT A-Z
DECLARE SUB demo (intx(), regs())
DECLARE SUB int86X (intx(), regs())


'Hello, fellow marxists...[shit, type mismatch I guess..<g>]here I am again,

'This is a completely new routine to emulate INTERRUPTX. The datasegment
'approach is dumped. However when you go to a close look you will see that
'some very important remainder of it still resists.
'This routine tries to simulate CALL INTERRUPT/ INTERRUPTX without the
'hassles that are normally associated with it, like another sub to
'set the interruptnr, or the shared regtype. And guess what ? This routine
'really match up in speed to the regtype things( even if I abstracted from
'the setting of the interruptnumber there).
'There are a few demo's/ testprograms included.


'Initialize:
DIM intx(60): DIM regs(10): CALL int86X(intx(), regs())
'Go for it:
demo intx(), regs()


'There is one way to make all of this even faster when you put regs and intx
'in one array. That way you avoid the use of the slow segment overrides to CS.
'(2 of them). I will not make such a program because:
'1) I personally do not think you should use INTERRUPTX/ CALL INTERRUPT, but
'   instead more tuned routines. THAT will give you much more speedadvantage.
'2) I think it is more stable this way.

'A few notes as to the routine, in which I put pretty much everything that
'I know right now:
'1)BP is saved through exchange saving 2 cycles
'2)DS is restored to the stringsegment without push/pop saving 2 cycles
'3)The segment of the regs() is initialized saving the stackthing (1 cycle)
'  and a retf n( 1 cycle too)
'4)I made use of a temporary store of this segment of regs() and therefore
'  had to retrieve it using mov ds,CS[86]. Thats very slow, but interesting
'  enough other solutions are even slower.
'5)The ds and si, and es and di register are set up in a way making it
'  possible to get them both at once, saving 2 cycles in total.
'6)I do not think that you have to save the flags. QBASIC is taking care.
'  But I am not yet sure there.
'7)To make this routine really user friendly you could set up constants for
'  all registers like I did. That way you do not have to remember which reg
'  number stands for which register.

'If you do not get all the reasons you might take a look on other
'modifications I made to MarkK's tutorial.

'good bye,
'Rick

END

SUB demo (intx(), regs())
CONST intnr = 0, ax = 1, bx = 2, cx = 3, dx = 4, bp = 5, si = 6, ds = 7
CONST di = 8, es = 9, flag = 10
DEF SEG = VARSEG(intx(0)): CLS

'TIming:
regs(intnr) = &H21: regs(ax) = &H200: regs(dx) = &HB1
a! = TIMER: FOR i = -30000 TO 30000
  CALL absolute(0):
NEXT: b! = TIMER:

'Timing the same but now tuned routine:
DIM prnchar(3)
prnchar(0) = &H2B4
prnchar(1) = &HB1B2
prnchar(2) = &H21CD
prnchar(3) = &HCB
DEF SEG = VARSEG(prnchar(0)): o = VARPTR(prnchar(0))
c! = TIMER: FOR i = -30000 TO 30000
  CALL absolute(o):
NEXT: d! = TIMER: CLS :
COLOR 0, 7: PRINT "INTX versus TUNED prnchar": COLOR 7, 0
PRINT "INTX   :"; b! - a!
PRINT "prnchar:"; d! - c!
COLOR 0, 7: PRINT "Regs filled like: ": COLOR 7, 0
FOR i = 0 TO 10: PRINT HEX$(regs(i)), : regs(i) = 0: NEXT
LOCATE 22, 1: PRINT : PRINT "Press a key for next demo": LOCATE 8, 1: SLEEP

DEF SEG = VARSEG(intx(0)): regs(intnr) = &H21: regs(ax) = &H2F00:
FOR i = 2 TO 7: regs(i) = &H1111 * i: NEXT: regs(8) = &H8888
CALL absolute(0):
COLOR 0, 7: PRINT "Get DTA in ES[BX]:": COLOR 7, 0
FOR i = 0 TO 10: PRINT HEX$(regs(i)), : regs(i) = 0: NEXT: PRINT :
SLEEP

'Functionality:

'DS[DX]
COLOR 0, 7: PRINT "Print string from DS[DX]:": COLOR 7, 0
a$ = "doei$"
regs(intnr) = &H21: regs(ax) = &H900: regs(dx) = SADD(a$):
regs(ds) = VARSEG(a$): CALL absolute(0): SLEEP: PRINT

'Various including ES[bp]
COLOR 0, 7: PRINT "Print string from ES[BP]:": COLOR 7, 0
regs(intnr) = &H10: regs(ax) = &H1301: regs(bx) = &H7: regs(cx) = 5
regs(dx) = &H1310: regs(bp) = SADD(a$): regs(es) = VARSEG(a$)
CALL absolute(0): SLEEP


'a difficult one:
PRINT : COLOR 0, 7: PRINT "Press a key for last demo"; : COLOR 7, 0: SLEEP: CLS
COLOR 7, 0: PRINT "We shelled from QBASIC to debug": COLOR 7, 0:
VIEW PRINT 2 TO 25:
'---------------------------------------------------------------------
exec$ = "c:\windows\command\debug.exe0": DIM exename(LEN(exec$))
regs(ds) = VARSEG(exename(0)): regs(dx) = VARPTR(exename(0))
DEF SEG = regs(ds):
FOR i = regs(dx) + 1 TO LEN(exec$): POKE i - 1, ASC(MID$(exec$, i, 1)): NEXT
DEF SEG
'---------------------------------------------------------------------------
commandtail$ = "c:\DOS\edit.com"
param$ = CHR$(LEN(commandtail$)) + commandtail$ + CHR$(13)
'---------------------------------------------------------------------------
DIM parameter(7 + LEN(param$) + 10): regs(es) = VARSEG(parameter(0)): regs(bx) = VARPTR(parameter(0))
'------------
'paramblock:
'------------
'0 W  pointer naar omgeving (0= default dos environment)
'2 DW pointer naar commandtail
'6 DW FCB1 pointer
'10 DW FCB2 pointer
'14 FCB=20*nul
'34 Commandtail
'---------------------------------------------------------
DEF SEG = regs(es):
parameter(0) = 0                                       'default environ
parameter(1) = regs(bx) + 34: parameter(2) = regs(es)  'ptr > commandtail
parameter(3) = regs(bx) + 14: parameter(4) = regs(es)  'ptr >FCB 1
parameter(5) = regs(bx) + 14: parameter(6) = regs(es)  'ptr >FCB2

FOR i = regs(bx) + 14 TO regs(bx) + 33: POKE i, 0: NEXT         'FCB's
FOR i = 1 TO LEN(param$): POKE regs(bx) + 33 + i, ASC(MID$(param$, i, 1)): NEXT
DEF SEG
'------------------------------------------------------------------------
DEF SEG = VARSEG(intx(0)):
regs(intnr) = &H21: regs(ax) = &H4B00:
CALL absolute(0)


'Errors oke ?
regs(ax) = &H4800: regs(bx) = &HFFFF
CALL absolute(0)

LOCATE 15, 1: COLOR 0, 7: PRINT "REGS FILLED LIKE:": COLOR 7, 0
FOR i = 0 TO 10: PRINT HEX$(regs(i)), : regs(i) = 0: NEXT: PRINT
PRINT : PRINT "If flags did not show the carry set, you do not had QBASIC loaded<g>"
PRINT : PRINT "Good bye"

END SUB

SUB int86X (intx(), regs())
'-------------------------------------------------------
'This routine gives credit and thanks to Rusty Angel!
'-------------------------------------------------------
'Pass: regs()1   2   3   4   5   6   7   8   9    10
'Array intnr, ax, bx, cx, dx, bp, si, ds, di, es, flag

'adress: 0    2   4   6   8   a   c       10       14
'displc:      0   2   4   6   8   a       e        12
'-------------------------------------------------------
regseg = VARSEG(regs(0))                                         'clocks bytes

asm$ = ""

'Save ES( no trick available)                        
'----------------------------
asm$ = asm$ + CHR$(&H6)                            'push Es          3     01

'Load DS[SI] with regs() and interruptnr to CS:[&h25]
'---------------------------------------------------
asm$ = asm$ + CHR$(&HB8) + MKI$(regseg)            'mov ax,regseg    1     04
asm$ = asm$ + CHR$(&H8E) + CHR$(&HD8)              'mov ds,ax        3     06
asm$ = asm$ + CHR$(&HA1) + MKI$(0)                 'mov ax,[0] intnr 1+5   09
asm$ = asm$ + CHR$(&H2E) + CHR$(&HA2) + MKI$(&H25) 'mov CS[&h25],al  2+9+1 13
asm$ = asm$ + CHR$(&HBE) + CHR$(&H2) + CHR$(0)     'mov si,2         1     16

'Load the registers.                                                    26
'-------------------
asm$ = asm$ + CHR$(&H8B) + CHR$(&H4)              'mov ax,[si]       1+5   18
asm$ = asm$ + CHR$(&H8B) + CHR$(&H5C) + CHR$(&H2) 'mov bx,[si+2]     1+9   21
asm$ = asm$ + CHR$(&H8B) + CHR$(&H4C) + CHR$(&H4) 'mov cx,[si+4]     1+9   24
asm$ = asm$ + CHR$(&H8B) + CHR$(&H54) + CHR$(&H6) 'mov dx,[si+6]     1+9   27
asm$ = asm$ + CHR$(&H87) + CHR$(&H6C) + CHR$(&H8) 'xchg bp,mov [si+8]3+9   30
asm$ = asm$ + CHR$(&HC4) + CHR$(&H7C) + CHR$(&HE) 'les di,[si+E]     6+9   33
asm$ = asm$ + CHR$(&HC5) + CHR$(&H74) + CHR$(&HA) 'lds si,[si+A]     6+9   36

'Execute interrupt                                                      104
'-----------------
asm$ = asm$ + CHR$(&HCD) + CHR$(&H0)              'int nr           26     38

'Set up DS[SI] again to regs and store DS                               130
'-----------------------------------------
asm$ = asm$ + CHR$(&H1E)                          'push ds          3      39
asm$ = asm$ + CHR$(&H2E) + CHR$(&H8E) + CHR$(&H1E) + MKI$(86)'mov ds,cs[0]2+9+1 44
asm$ = asm$ + CHR$(&H89) + CHR$(&H36) + MKI$(&HC) 'mov [c],si       1+9    48
asm$ = asm$ + CHR$(&HBE) + CHR$(&H2) + CHR$(&H0)  'mov si,2         1      51

'Store it!                                                              156
'---------
asm$ = asm$ + CHR$(&H89) + CHR$(&H4)              'mov [si],ax      1+5    53
asm$ = asm$ + CHR$(&H9F)                          'lahf             1      54
asm$ = asm$ + CHR$(&H88) + CHR$(&H64) + CHR$(&H12)'mov [si+12],ah   1+9    57
asm$ = asm$ + CHR$(&H89) + CHR$(&H5C) + CHR$(&H2) 'mov [si+2],bx    1+9    60
asm$ = asm$ + CHR$(&H89) + CHR$(&H4C) + CHR$(&H4) 'mov [si+4],cx    1+9    63
asm$ = asm$ + CHR$(&H89) + CHR$(&H54) + CHR$(&H6) 'mov [si+6],dx    1+9    66
asm$ = asm$ + CHR$(&H87) + CHR$(&H6C) + CHR$(&H8) 'xchg [si+8],bp   3+9    69
asm$ = asm$ + CHR$(&H89) + CHR$(&H7C) + CHR$(&HE) 'mov [si+e],di    1+9    72
asm$ = asm$ + CHR$(&H8C) + CHR$(&H44) + CHR$(&H10)'mov [si+10],es   3+9    75
asm$ = asm$ + CHR$(&H58)                          'pop ax  get ds   4      76
asm$ = asm$ + CHR$(&H89) + CHR$(&H44) + CHR$(&HC) 'mov [si+c] ,ax   1+9    79
'                                                                      251        
asm$ = asm$ + CHR$(&H7)                           'pop es           3      80
asm$ = asm$ + CHR$(&HB8) + MKI$(VARSEG(asm$))     'mov ax,stringseg 1      83
asm$ = asm$ + CHR$(&H8E) + CHR$(&HD8)             'mov ds,ax        3      85
asm$ = asm$ + CHR$(&HCB)                          'retf             13     86
'TEMP Storage arrea:
'-------------
asm$ = asm$ + MKI$(regseg)     'segment regs storage         271 clocks   88 bytes

DEF SEG = VARSEG(intx(0)): FOR i = 0 TO LEN(asm$) - 1:
POKE i, ASC(MID$(asm$, i + 1, 1)): NEXT
DEF SEG


END SUB

