Area: Quik_Bas Msg: #53 Date: 09-09-92 10:49 (Public) From: Steve Gartrell To: All Subject: INT 8 Handler
'I figured out why people post stuff like this...It's the 'electronic equivalent of the mad scientist's "POWER!" laugh... 'This version is hotted up a tad...The DemRegs variable 'passes back the status of the registers at the time of the 'interrupt. Likewise, if you change a DemRegs.(anyreg) 'value inside the handler sub, that value will be placed 'in the respective register!!! Dangerous toy, A? The 'global variable Busy% is read inside the Absolute array 'ASM; if it's <> 0 then the routine chains directly (mostly) 'to the original vector. Which you will want, if you are going 'to DEF SEG out of DGROUP, for instance!!! ' 'Let it run for 10 or 20 seconds, and you'll start seeing the ' registers passed back... ' This WON'T WORK in the environment, though some interrupts may! 'This is _not_ a toy...If you are not sure what you are doing, ' try thinking about worst-case scenarios, and take proper ' preventative measures...Like, if you play with disk access ' interrupts, BACK UP!! 'Compiled and tested under QB45 and PDS... DEFINT A-Z '$INCLUDE: 'QBX.BI' 'QB.BI if using QB4.5 DECLARE SUB Handler () 'remark out the original DECLARE SUB Absolute declaration in your ' include file; it's modified here... DECLARE SUB Absolute (RegsOff%, Busy%, OldSeg%, OldOff%,_ StartPtr%, address AS INTEGER) 'bet ya can't guess what my middle initial is... TYPE SKGregs ax AS INTEGER bx AS INTEGER cx AS INTEGER dx AS INTEGER si AS INTEGER di AS INTEGER es AS INTEGER ds AS INTEGER flags AS INTEGER bp AS INTEGER END TYPE CONST C$ = "Created 08/31/92 by Steve Gartrell." 'don't want this stuff moving around!!! These ' MUST remain global!!! '$STATIC DIM SHARED AsmArray%(1 TO 88), DemRegs AS SKGregs DIM SHARED OldOff%, OldSeg%, RetToAsm%, RegsOff%, SetUp% DIM SHARED TicCnt%, Busy% '$DYNAMIC CLS LOCATE 1, 70: PRINT LEFT$(TIME$, 8) SetUp% = VARPTR(AsmArray%(47)) RetToAsm% = VARPTR(AsmArray%(29)) NewSeg% = VARSEG(AsmArray%(1)) NewOff% = VARPTR(AsmArray%(1)) RegsOff% = VARPTR(DemRegs) DIM Regs AS RegTypeX 'DOS get interrupt vector using the clock 08h for ' demo purposes...Can use any other, too, but be ' aware that results can be extremely dependent ' upon what QB/PDS has done/is gonna do with the ' original vector!!! Regs.ax = &H3508 CALL InterruptX(&H21, Regs, Regs) 'save 08h original vector OldSeg% = Regs.es OldOff% = Regs.bx 'read all the sneaky little ASM opcodes in, which are primarily ' concerned with register saving, and navigating around the ' flow "limitations" imposed by QB/PDS... RESTORE FOR Word% = 1 TO 88 READ DataStr$ AsmArray(Word%) = VAL(DataStr$) NEXT 'Call the sub that sets up necessary address calculations... Handler 'OldSeg% & OldOff% are global, remember... 'Use DOS set interrupt call to change interrupt &H08 vector to ' the one returned for the AsmArray code that resides in DGROUP... Regs.ax = &H2508 Regs.ds = NewSeg% Regs.dx = NewOff% CALL InterruptX(&H21, Regs, Regs) cnt& = 0 DO 'gotta do something to show clock is interrupt driven ' Fix Busy% true, and the interrupt-driven time ' print can occur before this LOCATE and PRINT finish, ' with the number then showing up at coordinate 2,1!! cnt& = cnt& + 1 Busy% = -1 LOCATE 5, 35 PRINT cnt&; Busy% = 0 IF cnt& > 2000000 THEN cnt& = 1 LOOP UNTIL LEN(INKEY$) 'Return INT &H08 to it's original vector-THIS MUST ALWAYS ' BE DONE!!! Regs.ax = &H2508 Regs.ds = OldSeg% Regs.dx = OldOff% CALL InterruptX(&H21, Regs, Regs) LOCATE 24, 1 END 'This is the end, my FIDO friend, the end... '88 WORDS, FIRST call at VARPTR(47), LAST call at VARPTR(29) ReversedOpcodes: DATA &H8B55,&H9CEC,&H061E,&H5657,&H5152,&H5053,&HD78C,&HDF8E DATA &H90BB,&H8B90,&H2307,&H75C0,&H8E30,&H8BC7,&HFCF4,&H90BF DATA &HB990,&H000A,&HA5F3,&HEF83,&H5714,&HEE83,&H5614,&HB8FB DATA &H9090,&HB850,&H9090,&HCB50,&HC483,&H8C0E,&H8ED7,&H8EDF DATA &H5FC7,&HFC5E,&H0AB9,&HF300,&H58A5,&H595B,&H5E5A,&H075F DATA &H9D1F,&H2E5D,&H2EFF,&H0058,&H9090,&H9090,&H8B55,&H50EC DATA &H5253,&H8B56,&H065E,&H1F8B,&HEB83,&H8B5C,&H0246,&H0305 DATA &H8900,&H3487,&H8B00,&H0446,&H8789,&H0030,&HF38B,&H5E8B DATA &H8B08,&H8917,&H5894,&H8B00,&H0A5E,&H178B,&H9489,&H005A DATA &H5E8B,&H890C,&H119C,&H8B00,&H0E5E,&H178B,&H9489,&H001F DATA &HC68B,&H5805,&H8900,&H5644,&H5A5E,&H585B,&HCA5D,&H000A REM $STATIC SUB Handler STATIC SHARED OldOff%, OldSeg%, RetToAsm%, RegsOff%, SetUp% SHARED TicCnt%, Busy%, DemRegs AS SKGregs, NewOff% 'Make sure we're looking at DGROUP DEF SEG CALL Absolute(RegsOff%, Busy%, OldSeg%, OldOff%, SetUp%, SetUp%) EXIT SUB 'This routine's LIFE DEPENDS UPON a certain amount of ' code bytes between the EXIT SUB and the next command ' (happens to be JGE [IF < THEN] here, but not critical). IF ' YOU SPECIFY /D(ebug) when compiling, YOUR system will HANG!! ' ('Cuz the compiler will sneak some stuff in in between ' the EXIT SUB and your first line of code!!!) Also, ERROR ' handling (/E/X compile options) in QB is probably ' impossible, and should be approached with care in PDS (like, ' anything but LOCAL error handling is probably out of the ' question, and LOCAL in this sub is a no-no!!!) ' Put any code you want between the EXIT SUB and the ' DEF SEG...EXCEPT (at least) END or it's equivalents... ' You MUST return the clock to it's original vector before ' exiting to DOS, SHELLing, and so forth!!! ' 'update if it's safe to do so! IF TicCnt% < 10 THEN TicCnt% = TicCnt% + 1 'a little delay... ELSE Busy% = -1 LOCATE 1, 70 PRINT LEFT$(TIME$, 8) 'update the time LOCATE 2, 1 'print the register values at interrupt... ' Remember, if you change a register variable at ' this point, it _will_ change the register contents!! PRINT "AX = "; HEX$(DemRegs.ax); "h"; SPACE$(4) PRINT "BX = "; HEX$(DemRegs.bx); "h"; SPACE$(4) PRINT "CX = "; HEX$(DemRegs.cx); "h"; SPACE$(4) PRINT "DX = "; HEX$(DemRegs.dx); "h"; SPACE$(4) PRINT "SI = "; HEX$(DemRegs.si); "h"; SPACE$(4) PRINT "DI = "; HEX$(DemRegs.di); "h"; SPACE$(4) PRINT "ES = "; HEX$(DemRegs.es); "h"; SPACE$(4) PRINT "DS = "; HEX$(DemRegs.ds); "h"; SPACE$(4) PRINT "BP = "; HEX$(DemRegs.bp); "h"; SPACE$(4) PRINT "Flags = "; HEX$(DemRegs.flags); "h"; SPACE$(4) TicCnt% = 1 Busy% = 0 END IF DEF SEG CALL Absolute(dummy%, dummy%, dummy%, dummy%, dummy%, RetToAsm%) END 'I stuck this END in here just to show you that ' the instruction pointer will never get here... END SUB --- D'Bridge 1.30/071082 * Origin: RadioLink! Columbus, OH (614)766-2162 HST/DS (1:226/140)
Books at Amazon:
Back to BASIC: The History, Corruption, and Future of the Language
Hackers: Heroes of the Computer Revolution (including Tiny BASIC)
Go to: The Story of the Math Majors, Bridge Players, Engineers, Chess Wizards, Scientists and Iconoclasts who were the Hero Programmers of the Software Revolution
The Advent of the Algorithm: The Idea that Rules the World
Moths in the Machine: The Power and Perils of Programming
Mastering Visual Basic .NET