32 registers in 16 bit programs? sounds like someone had some fun with 'unreal' mode
...i wonder if the nec v20 (or v30) are still made... would be fun to put in my old tandy 1000SL...
Okay, I never heard of that or used it before. But that was not what I meant. I meant only the general purpose registers and the instructions, and nothing to do with address space.
So MUL EAX, EBX is perfectly legal in regular real mode for a 386 and higher. I am not sure about the additional segment registers.
Oh, I used to use assembly and QB together, and that helped get the speed up and the size down. For instance, say you wanted to support a mouse. You could write mouse routines in pure Quick Basic and use their Int and IntX functions to pass the parameters to the CPU and call an interrupt to the loaded mouse driver. But, that was a convoluted way of doing it, and QB only used signed numbers. You could work around the signed number thing by using a long integer, subtracting from zero if larger than 16k, etc, but that brought in additional code. But if you write your routines in assembly and make them for QB (by declaring to the assember ".model medium, basic" or you'd declare it large model if using Basic 7 instead of QB 4.5), you could avoid calling a number of QB linking libraries and do the job much more faster and efficiently. You don't have to call the Int subroutine/function when you can simply load the registers directly, without regard to signage, and call the hardware Int command. If you have a function rather than a sub, you'd simply return your status code in AX, or DX:AX if long integer. If you were to use EAX, then I guess what you could do would be to do a Mov EDX, EAX, and then do a SHR EDX, 16. Then QB would see the DX and AX (and what is in the upper EAX bits would be irrelevant).
Another trick I used was creating data structs in ASM and then using PEEK (and Def Seg if necessary) to read them in QB. That was often faster then the DATA commands, and didn't call in that library (which may have also called in the long integer library, etc).
I also used an alternative linking library in QB written by Crescent Software. After a while, I even called the QB libraries in assembly. When you called string libraries, you had to have a string descriptor, and that usually came from QB's memory manager. But, if you manually called them, you would set aside room in your assembly for string descriptors and make fake ones with the length and address of the string in question (often in your assembly data). And if you needed temporary ones, just call B$SASS just like QB and then pass on the returned descriptor to other QB internal routines.
You could use PDQ's routines in your own assembly code without using QB at all, but you'd have to use their included base template to do the startup and cleanup. However, I once flattened one out. I started using the template and the other modules I needed. Then I flattened it by making it inline code and removing the subroutine calls. Then I got to thinking, why not delete the template code, set to tiny model, do the ".org 100h" and make sure there was no stack segment (and that it was all under 64k, though that was not a concern)? Then I ran TASM, ran LINK, then ran EXE2BIN, and renamed it with the .com extension. And if you wanted the command line, you could have a section with ".org 0h" and put a variable name in there. But you put all your code starting at 100h (256 bytes past the command line starting address in memory). After that, I just started writing as .com where I could.
I had a number of tiny .com files for batch file use. For instance, it only takes 16 bytes to reset the PC. (Technically, it probably corrupts the stack, but that is like the ethics question of using sterile needles to do lethal injection...) I had one to do a hot reboot too that only reloaded DOS without resetting the PC, but it only worked in some instances. If you had loaded MSCDEX, it would probably corrupt the interrupt vector table to where the hot bootstrapping command would only hang the machine.