|DÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ |Dº |5The Happy Hacker |DºÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ |DÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ ^C^1Bits 'N PC's ^Cby ^CGeorge Leritte This time we have another installment on interfacing assembly language and a couple of short routines for your BASIC programs, one that's new and one that's a revision of an earlier routine. In Turbo Pascal, there is a function for moving parts of memory from one spot to another. Sometimes, there is a need for doing that in BASIC. Our SMOVE routine does just that, and it does it pretty quickly, too. In issue 9, we published a video scrolling routine that used BIOS interrupt 10 to scroll parts of the screen. One of our readers complained that he got lost in the shuffle towards the last part of the discussion. Admittedly, passing the variables the way we did it is not the best way to do things, but it did get the job done. We will correct it this month with the code in BASIC, the assembly language source code, and the object file for inclusion in your compiled BASIC versions. For those of you who weren't here in Issue 9, I'll offer a short refresher on BIOS interrupt 10. BIOS interrupt 10 controls the video services offered on the IBM PC. With it, you can set or determine the video mode, set or determine the cursor location and size, write to the screen, or scroll windows on your computer and other nice things. The problem is interfacing them with your programs. For the screen scroll routine, the registers are loaded with the desired values and the interrupt call is performed. For the interrupt 10 scroll window service, the registers and the information needed is: AH: 6 (for scrolling up) or 7 (for scrolling down) AL: number of lines to scroll (0 to clear window) BH: attribute to be used for blanked area CH: row coordinate of upper left corner of window CL: column coordinate of upper left corner of window DH: row coordinate of lower right corner of window DL: column coordinate of lower right corner of window Note that the row coordinates range from 0 to 24 and the column coordinates range from 0 to the screen width minus one, not 1 to 25 and 1 to the screen width as in BASIC. The implications become obvious. You can scroll all or part of the screen by using this interrupt. From BASIC, once the assembly language is complete, you load the routine into memory and determine its starting location. The BASIC manuals suggest putting it in a location outside BASIC's data space. This is fine, as long as you have enough memory. Today's computers almost always have at least 256K of RAM, so memory shouldn't be a problem. However, putting routines in absolute memory locations can cause problems if you have a lot of memory resident software, since you cannot guarantee the memory location you selected will not be in BASIC's data segment anyway. Since I started doing this on a 128K machine, and like to have it in BASIC's data space where I can keep an eye on it, and since it occupies only 22 bytes of memory, I place the routine in an array variable and use BASIC's VARPTR function to get the starting address of the routine. I also don't have to fool with segments using the DEF SEG statement, since the routine is in the data segment. You pass the parameters to the routine with the call statement. If you have loaded the routine in the array scr%(), the syntax is: scroll%=varptr(scr%(0)) call scroll% (ch%,cl%,dh%,dl%,attribute%,lines%,direction%) The varptr statement is precautionary because if you define a new variable (not redefine an old one), the location of the array will move and you will crash your program. I put the two statements together in a subroutine and call it when needed. Also note the parameters passed are integers. The subroutine is expecting integers and you must define them with the type identifer % or with a defint statement at the beginning of your program. The first four variables in the example line correspond to the register values needed for the interrupt and the last three are the attribute to be used in the blank window, the number of lines to scroll, and the direction to scroll the window. If the routine doesn't work, the first place to check is the order and value of the parameters you're passing. Check the sample program on the disk to see how I've done it. In a compiled program, you simply use the call scroll statement and compile your program to object code, then link it with the command LINK PROGNAME+SCROLL. This is why the object code to the routine is on the disk and also why the line 'public scroll' is in the assembly listing. This tells the link program that the name SCROLL is an external routine. I used this routine in the conversion of Rock and Roll Quiz for this issue. The SCROLL.BAS file on this disk is the interpreted BASIC source code for a demo. The SCROLL.ASM file is the source code for the assembly language routine, and the SCROLL.OBJ is the object code needed for use with a compiler. Sometimes you may have a need for moving data from one place to another quickly and for..next loops are just too slow. The solution is our SMOVE routine. SMOVE means short move--memory moves within the data segment. I've written a long move version--moves anywhere in memory, but it's too easy to crash the computer with it, so, I'm sorry to say, you won't see it here. If you like you can modify SMOVE, but any crashes are your fault. SMOVE uses the MOVS assembly language instruction. MOVS means 'Move String'. There are two versions, MOVSB and MOVSW, move string-bytes and move string- words. If you load register CX with the number of bytes or words to move, you can move sections of memory very quickly with REP MOVS. Don't worry about the 'string' label. They had to call it something. For arguments sake, let's say you had a large array of numbers to fill with a repeating sequence of numbers. You could do it with code like this: 10 dim t%(1999) 20 for i=0 to 49 30 for j=0 to 39: t%(I*50+j)= j+1: next j 40 next i If you created a small array of 40 elements, and then copy repeatedly the small array into the larger, you could load the large array quicker. With SMOVE, you can do this 12 to 13 times quicker than the above code. With the routine loaded in the sm%() array and the data you want to move in the f%() array, the syntax of SMOVE is: smove%=varptr(sm%(0)): from_offset%=varptr(f%(0)): to_offset%=varptr(t%(0)) call smove% (from_offset%,to_offset%,no_bytes%) The variables from_offset% and to_offset% are the memory locations of the data you are moving. To change the destination in the array, change the index of the t%() variable. The variable, no_bytes%, is the number of bytes to move. See the sample program on this disk. As with SCROLL, the variables being passed must be integers. Also, limit the definitions of new variables between calls. The assembly language source code and the object code is on disk. Use the object code with your compiled programs just like the example for SCROLL. The SMOVE.BAS file on this disk is the interpreted BASIC source code for a demo. The SMOVE.ASM file is the source code for the assembly language routine, and the SMOVE.OBJ is the object code needed for use with a compiler. Well, that's all for now. If you come up with any interesting uses for these routines, let us know. Happy computing.