1.  It's Just Numbers

Home Up Next

At a deeper level inside any computer, the CPU (central processing unit) operates on numbers. It uses numbers to tell it what to do and it uses numbers to tell it with what it should do it. If that last sentence is hard to chew, all I really mean is that a CPU uses numbers in calculations but also for instructions on how to perform those calculations. In short, numbers are everything to a CPU.

The only way a computer tells whether a number is data or is an instruction is by which path the number arrives at the CPU. If it arrives though the instruction path, it is a command to follow. If it arrives through the data path, it is some kind of data being used by one of those commands.

Normally, QBASIC doesn't let you reach this level in the computer. Instead, you enter in valid BASIC instructions and deep within QBASIC there is already the needed numeric commands, which a CPU really uses, for interpreting your BASIC instructions in some appropriate fashion. But you can arrange things in QBASIC so that you can actually force it to directly execute specific and exact instructions, written for a much deeper level.  In other words, you can write assembly code and have it execute within the QBASIC environment. To do this in QBASIC, assembly code is first represented as numbers and then these numbers are placed precisely into memory. (To do this in simple fashion, I usually use hexadecimal notation, as you will see.)

Assembly programs in QBASIC

In case you don't already know it, assembly code is just a short semantic step above machine code.  It provides a symbolic way of describing machine instructions, rather than using the exact binary numbers that the CPU really processes when it runs a program. It also provides a symbolic way of naming your data, too, rather than having to specify specific memory addresses which are almost impossible to remember or having to keep track of where they reside. Using symbols in this way makes more sense to humans who need to read and write code and makes it much easier to edit and change them, as well.

In the end, though, these assembly programs wind up becoming just a series of numbers that the CPU interprets as code.  The CPU only operates on the binary code.  Assembly code is designed for human readability and not for direct use by the CPU.  So an assembler is used to convert from the human readable approximation into actual machine code (or something very close to it.) Regardless, this means that if you can get the right numbers placed in the right order in the computer's memory, you can just tell the computer to access that data as if it were code and it will run it.

In short, you can get QBASIC to load actual code into the computer memory by first treating it as data, a feature that QBASIC already handles quite well. Then you can use another feature in QBASIC to ask it to treat that loaded data as code. That is how QBASIC can be used to support accessing assembly programming.

For example, here's a short routine written in assembly language and designed to accept a string length and a pointer to the string itself and reverse the order of the characters in it:

ReverseStr PROC strlen:PTR WORD, strofs:PTR WORD
           mov bx, strlen
           mov cx, [bx]
           mov bx, strofs
           mov bx, [bx]
           mov di, bx
           add di, cx
           .WHILE (cx > 1)
             dec di
             mov al, [di]
             xchg al, [bx]
             mov [di], al
             inc bx
             sub cx, 2
           .ENDW
           ret
ReverseStr ENDP

In the binary language of the x86 CPU though, those instructions are converted into the following sequence of numbers in memory:

DATA &H8B55, &H8BEC, &H085E, &H0F8B, &H5E8B, &H8B06, &H8B1F, &H03FB
DATA &HEBF9, &H4F0B, &H058A, &H0786, &H0588, &H8343, &H02E9, &HF983
DATA &H7701, &H5DF0, &H04CA, &H0000

When the source code fragment above (as part of an appropriate program "skeleton") is assembled with an assembler tool, those are the values that are produced.  And if those numbers are read into an INTEGER array in QBASIC then they can be thought of as equivalent to the assembly source code above.

I won't spend a lot of time trying to drill this fact in.  If it doesn't make sense to you now, it will one day.  But the fact remains that these are equivalent to each other and that QBASIC can use this fact to make it possible to use assembly programming as part of your QBASIC programming.

Even if you aren't familiar with writing assembly programs, I think you can easily see from above which of the two would probably be easier to work with, change, enhance, and otherwise maintain. That's why I strongly recommend that you take the time to learn to properly use ML as your assembler tool and to rely on it for any development you do for QBASIC interfacing.  (I have a web page that describes how to get the ML assembler here, along with some other helpful software development tools. Also, if you want to read through a small tutorial of mine on using the DEBUG program and ML assembler, you can look here.)

Please also keep in mind that what I've shown above are fragments.  The assembly source code is incomplete -- it needs some additional directives before an assembler can properly process it.  (There is a completed version, given a little later on.)  The DATA statements are also incomplete -- additional QBASIC code is required in order to properly use them.  I've exerpted them solely to call attention to their rough equivalence.  (There also is a completed version, given a little later on.)

 

Last updated: Wednesday, July 06, 2005 21:02