'=========================================================================== ' 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..]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" 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