'=========================================================================== ' Subject: CHANGE BORDER COLORS Date: 06-21-97 (20:32) ' Author: Denis Boyles Code: QB, QBasic, PDS ' Origin: FidoNet QUIK_BAS Echo Packet: ASMCODE.ABC '=========================================================================== ' > write assembly language subroutines? I've heard lots about them but ' > don't know where to begin. Thank You for your tolerance of the ' Withing QB, there are really two ways of using an assembly language ' subroutine. The first is by assembling your function into an .OBJ file and ' then linking it into your program. ' This requires the full Quick BASIC product however, and a suitable ' assembler. QBASIC lacks this functionality. The nice thing here is that you ' can build libraries out of similar .OBJ files. Instead of having several ' OBJ files, you'd have one library file. Which contains all the code of the ' OBJ files for you to link in. This allows one to make a communications ' library, or a special graphics library for you or others to use. ' The second method, which does work with QBASIC, involves POKEing the ' routine directly into memory. Where you then CALL ABSOLUTE it with the ' desired parameters to invoke the routine. ' The assembly code is listed as machine language instructions using a series ' of DATA statements. These are then READ and POKEd directly into a DIMed ' array for storage. Once within the array (memory) you can CALL ABSOLUTE it ' to use the function. ' In fact, CALL ABSOLUTE is specially designed for just that purpose. You can ' be quite creative and accomplish things you might think impossible in ' QBASIC. (I have so far! :) ' Finishing off, I leave you with an example program that uses the method just ' described. In it, a machine language subroutine is used to change the screen ' border color. The program itself is pretty straightforward, but the machine ' language is probably harder to understand. 'SetBorder is an INTEGER array to store the machine language code. 'clr acts as a counter for the border colors. DIM SetBorder%(9): clr% = 1 'READ/POKE the machine language into the array for later CALLing. DEF SEG = VARSEG(SetBorder%(0)) FOR ct% = 0 TO 16 READ opcode% POKE ct%, opcode% NEXT 'Setup a TIMER handler and go into a loop. The loop keeps going until 'a key is pressed on the keyboard, then the program ends. ON TIMER(1) GOSUB SetColor: TIMER ON WHILE INKEY$ = "": WEND CALL absolute(0, 0) 'restore to default "black" border END 'This is the TIMER handler which changes the border color every second. The 'change is done by calling the machine language subroutine. SetColor: CALL absolute(clr%, 0) clr% = (clr% + 1) AND &HF RETURN 'Here, the DATA statements that comprise the machine language subroutine are 'listed. These are the actual binary opcodes that the CPU executes in order 'to do things. In this case, they change the screen border color. DATA &H55,&H89,&HE5,&HB8,&H01,&H10,&H8B,&H5E DATA &H06,&H8A,&H3F,&HCD,&H10,&H5D,&HCA,&H02 DATA &H00 'The above opcode values were derived from the following assembly source 'code: 'SetBorder: ' push BP ;save BP register to the STACK ' mov BP,SP ;BP = SP so we can access STACK data ' ' mov AX,1001h ;AX = &H1001 ' mov BX,[BP+6] ;BX = offset to clr%, passed on STACK ' mov BH,[BX] ;BH = clr% ' int 10h ;BIOS VIDEO interrupt to change border ' ' pop BP ;load BP register back from STACK ' retf 2 ;FAR return to QBASIC. clear STACK