BBS: Inland Empire Archive Date: 05-10-92 (13:11) Number: 139 From: MATT PRITCHARD @ 930/21 Refer#: NONE To: RICHARD VANNOY Recvd: NO Subj: Bit shift & rotate 1/2 Conf: (2) Quik_Bas
MP>I've seen the recent discussion on Bit Shifting and must admit... RV> As a beginner in ASM, I've never tried putting ASM in RV> any other language's code. Just a few questions on your RV> code to see if I have the basic idea. RV> Is this right? RV> 1. Write the ASM procedure(s). RV> 2. Compile to .OBJ. RV> 3. Name all procedures in .INC. RV> 4. Compile your program normally, except pull in the RV> assembly .OBJ with the linker. Richard, You're only a beginner in ASM? I would have thought otherwise; but your questions are quite valid and worthwhile; so here it goes. I provided a dump of the ".OBJ" file at the start of the messages on Bit shifting so that you could skip steps 1 & 2 above. and a listing of all the routines so you could skip step 3. The purpose in providing the Assembly listing here in the Quick_Bas echo was to let people see the inner workings of the routines. You have to have the .OBJ to start with. From there you make a .QLB for use in the environment. If you have the .ASM (source code) that's great; you can get in there are change the code if you want to. The QB/QBX Environment takes care of finding the actual routines in the .QLB file and the Linker takes care of that when it makes the .EXE file. ---------------------------------------------- RV> Let's say you have a PROC XYZ declared as RV> DECLARE SUB XYZ(a%, b$) RV> How does your assembly sub know where to find a% and b$? Good Question: a% and b$ are "parameters" that are "passed" to the XYZ routine. And there are 2 ways that QuickBASIC/PDS will pass parameters: "Pass by Value" and "Pass by Reference". What you see above is "Pass by Reference"; to "Pass By value" you use the "BYVAL" keyword in the DECLARE SUB|FUNCTION statement. Both of these methods involve placing data on the "Stack". "Pass by Value" - If you have the number "1234", you push the number "1234" directly on the stack before you call XYZ. "Pass by Reference" - If you have the number "1234" you put it in memory somewhere, and push the memory location (to find it at) onto the stack. or.. another way to say it: "Pass By Reference" DECLARE SUB XYZ (a%) a% = 1234 CALL XYZ (a%) a% is an integer variable whose value (1234) is stored at (for sake of discussion) memory location 500. To call XYZ, the computer: 1) puts "500" on the stack, and 2) Calls XYZ. XYZ reads the address 500 off of the stack, and says "ahh, I can find the value I am looking for at memory address 500" It goes and reads memory at address 500 and finds the value 1234. "Pass By Value" DECLARE SUB XYZ (BYVAL a%) a% = 1234 CALL XYZ (a%) a% is an integer variable whose value (1234) is stored at memory location nnnn. To call XYZ, the computer: 1) reads the value at nnnn, 2) put that value on the stack, and 3) Calls XYZ XYZ reads the value (1234) directly off the stack. ----------------------------------------------------------------- As we can see, Pass by Value adds an extra step before the call, but the called routine has less work to do. By default, all calls in QuickBASIC are "Pass by Reference", you can't "Pass by value" without using BYVAL in declarations. One more *important* thing: sub XYZ can *change* the value of a% if it is passed by reference. If it is passed by value, it can't change a%. It knows what value a% has, but it doesn't know where in memory a% is actually stored. Another effect of the 2 ways to pass paramemters. When passing by reference, the compiler has to turn a constant into a variable before it can make the call. When you have: DECLARE SUB XYZ( x1%, x2%, y1%, y2% ) CALL XYZ (10, 5, 100, 50) you actually get: DECLARE SUB XYZ( x1%, x2%, y1%, y2%) < temp.x1 = 10 > < temp.x2 = 5 > '(Slight of hand by the compiler) < temp.y1 = 100 > < temp.y2 = 50 > CALL XYZ( temp.x1, temp.x2, temp.y1, temp.y2 ) When you allways call a routine with constants, you can get tighter code by passing by value. --------------------------------------------------------- Strings in QuickBASIC and PDS are a special case. Strings are allways passed by reference. The reference that is passed has to be decoded to get the real memory address as well as the length of the string. PDS 7.1 adds a whole new way to decode the string reference. ---------------------------------------------------------- RV> How do you return a value? Do you put it in AX, then use RV> CALL Interrupt in BASIC to read it, or do you put the RV> address of the answer somewhere or what? There are a couple ways to return values to QuickBasic: The only difference between DECLARE SUB and DECLARE FUNCTION is that DECLARE FUNCTION will return information in the AX and DX registers. Depending on what type of function was declared, QuickBASIC will know how to handle the info it gets back. Take this snippit of code: DECLARE FUNCTION AssemblySUB% X = AssemblySub% >>> Continued to next message ===
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