Bit shift & rotate 1/2

 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
===
Outer Court
Echo Basic Postings

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