QB006 - Mixing QBasic And Assembler

Languages : QBasic
Tools : QBASIC.EXE
Statements : Dim, Poke, Def Seg, VarSeg, VarPtr, Call Absolute, For, Data, Read
Prerequisites : Install QBasic (from Tools CD #3 \ Microsoft Tools (part 2 of 2) \ QBasic - simply copy it onto your hard disk)
Estimated time : 25 minutes - not including "For Fun".

Here We Go

There are lots of ways to mix QBasic with other programs, but what we're going to focus on here is a special method of integrating QBasic with small assembly language programs.

First, let's make the assembly language program.

Go into DOS DEBUG.  (Enter the Command Prompt or MS-DOS Prompt and type DEBUG and press enter.)

Type the following (pressing Enter at the end of each line) :

a 100
push ds
push si
mov ax,b800
mov ds,ax
mov al,17
mov si,1
mov [si],al
inc si
inc si
cmp si,fa2
jl 10c
pop si
pop ds
retf

Then press Enter once more, which should get you back to the little minus sign (which we call the "Debug Prompt").

Now I realise at this point you don't have a clue what you're just done. You've written a program which will change the colours on your screen. That's pretty cool. You could save this as a .COM program and run it, but for now we're going to put this program inside one of your QBasic programs, and show you how to run it from inside QBasic!

Next, type "d 100" and press enter.


It doesn't matter if the blob of numbers at the bottom of your screen is slightly different than shown here, as long as the first 25 hexadecimal digit pairs are identical.  For those who don't yet know what "hexadecimal digit pair" means, simply ensure that on your screen, the numbers in the final big block of numbers match what's shown here, beginning at "1E 56 B8" (i.e. the beginning of the big block) and finishing just after halfway through the second line with the three hexadecimal digit pairs "5E 1F CB".

Here's a QBasic program which incorporates the above assembler language program into itself.

Enter it very carefully, ensuring especially that the numbers in the first four lines are IDENTICAL, and then press F5 to run it.  What happens?  We've changed the background colour of the screen, along with the colour of any text on the screen.  Add some "Print" lines to the program.  Notice the colour of the text you print.

So, how did we get from there to here?  Some of you have already noticed that those hexadecimal number in the "Data" lines of the QBasic program correspond exactly to the hexadecimal digit pairs in the DOS Debug 'dump'.  By modifying the content of those "Data" statements, you could include pretty much any assembler language you want into a the same QBasic program.  BUT, why do we have "FOR PokeOffset = 0 to 24"?  It's because there are 25 'bytes' (hexadecimal digit pairs) in the assembly language program.  So if you do change the assembly language program, not only should you update the "Data" lines in QBasic, but you should also change the "24" to one less than the number of bytes in your new program.

In the assembly language program, the bit that controls which colours are selected is the line that says "mov al,17".  You can change the "12" to any other two-digit hexadecimal number.  You can experiment and see what colours you get!  *Hint : the first hexadecimal digit pair on the second "Data" line in QBasic is that number which controls the colour.  You can change it directly in QBasic without having to change it in Debug as well.)

Or what if you only want to fill half the screen?  The line which controls how much of the screen you fill is the one which says "cmp si,fa2".  What happens if you change it to "cmp si,782"?  (Hint : to change that directly in QBasic, go to the third "Data" line, and change the third hexadecimal digit pair from "a2" to "82", and the fourth hexadecimal digit pair from "f" (OK, that's not exactly a pair, but it's still hexadecimal) to "7".)

Oh - another thing - save often!  :o)  The slightest slip-up when you're dealing with assembly language and you crash the program.

For Fun

What if you wanted to save the assembler language program as a .COM program to run directly from the Command Prompt?  You need to do two things.  First, you need to change the final instruction from "retf" to the two instructions "mov ah,0" and "int 21" (in that order).  If you've already typed in the program and you're still in Debug, you can make the change without having to re-type the entire program.  All you have to do is type "a 118" at the Debug Prompt and press Enter.  Then type "mov ah,0" and press Enter, and then type "int 21" and press Enter twice, bringing you back to the Debug Prompt.  If at this point you type "u 100" and press Enter, you'll see the current version of the program, and you'll notice that instead of "retf" it now includes your two new instructions.  The next step is to give the program a name, so type something like "n Colours.com" (where "Colours" can be replaced with a name of your choosing) and press Enter.  The third step is to tell Debug how long your program is.  To do this, type "r cx" and press Enter, then type "1c" and press Enter.  The final step is to tell Debug to actually save the file.  Type "w" and press Enter.  Voila!

To exit Debug, type "q" at the Debug Prompt and press Enter.

If you saved the assembly language program as Colours.com, you should be able to run it from the Command Prompt.  (Note that if you run it from Windows Explorer, it disappears too quickly after you run it.  Review the Assembler Language lessons and try modifying the program so that it waits for a keypress before exiting!)

In fact, if you want to, you can run Colours.com from QBasic instead of Poking the machine code into memory.

Of course, this only works if Colours.com is in the "current directory", a concept we haven't touched on yet. The advantage of Poking the machine code into place is that you only have to worry about one file, whereas the other way, there's always the possibility that Colours.com will end up in the wrong place or be deleted by the user for no good reason or have any of a thousand other things happen to it. Poking is great and efficient for very small assembler language programs, but if the assembler language program was a lot bigger, having a separate .COM would almost certainly be the best way to go. Can you guess the reasons why?

Conclusion

We've done some very advanced stuff in this lesson, and we've also been dealing with some very 'low level' aspects of the design of your computer.  Unless you've been extraordinarily accurate, you've probably crashed QBasic a few times by getting the code even just slightly wrong!  :o)  (I crashed it about five times preparing the lesson!!!  :o)  )

You haven't necessarily understood a lot of what we did or why we did it that way, but you've been introduced to vital concept which, when finally grasped, will greatly improve your understanding of the machines you're bossing around.  You'll get the most value from this lesson if you cross-reference it with the assembly language lessons, and if you ask lots of "Why?" questions, and do some experiments yourself to try to get a better understanding of what works and what doesn't and what does what.

Also never forget that answers to a host of your questions are only a Google away!  Until next time...

Copyright (C) Jonathan Field 2004
Version 20041021Thu
Comments / Suggestions