Lesson no.9 Putting it together
.model medium,basic .stack 100h .code PUBLIC vmode vmode PROC mov ax,13h int 10h ret vmode ENDP ENDWhat the above code did was make a routine called vmode which switched to mode 13h. Compile it and Link it as a QuickLibrary and load it up in QuickBASIC. Enter this code:
DEFINT A-Z DECLARE SUB vmode vmodeRunning this code will call the asm routine that we defined before and switches the video mode to mode 13h (320x200x256). This is an example of a subroutine that is similar to one made in QB. Lets say we no longer want it simply to be called, but we want it to actually return a value. (i.e behave like a function) The below code shows how to do so:
.model medium,basic .stack 100h .code PUBLIC func func PROC mov ax,3 retn func ENDP ENDNow, the way QB retreives a returned value is via the AX register. Placing 3 in the AX register and returing to QB will return the value 3 if the above routine is defined as a function that returns an INTEGER:
DEFINT A-Z 'defines all names from A to Z as Integers DECLARE FUNCTION func PRINT funcThe above code would simply display the number 3. But now, this is rather boring really. These routines have to give you the same stuff time and time again ... or do they? =D
Now whenever you pass a variable to a function in QB it is placed on top of the stack. That pushes down the return segment and offset that is given to the routine. Lets look at the stack layout of a function we made before:
DECLARE SUB vmodeOffset Value 02 BASIC segment 00 BASIC offset <== Stack Pointer (SP)
Every time a function is called, the segment is pushed and then the offset. This is so the code knows where to go back once control has been regianed to QB. Lets say we modified vmode to become like so:
vmode PROC push ax mov ax,13h <== lets say we are at this command. int 10h pop ax retn vmode ENDPIf we are on the second line, the stack would look so this:
Offset Value 04 BASIC segment 02 BASIC offset 00 AX <== Stack Pointer (SP)
This is very important to realise because if not kept in mind, you might access values you don't want.
Lesson no.10 Extended mov commands
mov ax,[bx+02]This can only be done with BX,BP,SI and DI which are all pointer registers.
Lets say we make a hypothetical function addone. In QB, this is how we define addone:
DEFINT A-Z DECLARE FUNCTION addone(BYVAL x)This means that after calling addone the stack will look like this:
Offset Value 04 x 02 BASIC segment 00 BASIC offset
The arguments are always placed before the BASIC segment and offset. so if theres a hypothetical function xaddbyy(BYVAL x,BYVAL y)
The stack would be:
Offset Value 06 x 04 y 02 BASIC segment 00 BASIC offset <== Stack pointer (SP)
The arguments are added ontop of each other (remeber the stack starts from the bottom upwards). Let us code this xaddbyy function:
.model medium,basic .stack 100h .code PUBLIC xaddbyy xaddbyy PROC mov bx,sp ;moves SP into BX. mov ax,[bx+06] mov dx,[bx+04] add ax,dx retn 4 ;return 4??? what does that mean? well, put simply QB pushes 2 integers ;(x and y which are 16-bit thus 2*2=4 bytes) and leaves the routine to ;handel the rest. When you go back to QB it does not bother removing what ;you have'nt used. This would return the x and y and free up the stack. ;Thus if you had a routine xaddyaddz (x,y,z) then you would retn 6. xaddbyy ENDP ENDThis would return x+y in ax. It's very simple really, and once you get the concept the applications start following in. Next issue, we are looking at some of these applications and how to apply it to your programs! That's all for now, see you next time!
This article was written by abionnnn (firstname.lastname@example.org).