-------------------------------------------------------- You probably often swore around because a working routine with REG(x) didn't work crrectly after conversion to the InLine-Assembler or when your Testroutine wouldn't do its job in a SUB/FUNCTION. The solution is relatively simple: You have to pass the variables to the InLine-Assembler BYVAL. Example: Demo 1 FUNCTION Demo(BYVAL i%) public ! mov ax, i% ! inc ax ! mov i%, ax PRINT i% END FUNCTION This little Demo simply adds the value '1' using the InLine-Assembler and then prints it on the screen. Simply leave out the BYVAL and then test the Demo again! 5.4. Problems with LDS/LES -------------------------- Compareable to the passing of the parameters is the function of the commands LDS/LES. It is also essential whether a variable is passed 'BY COPY', 'BY REFERENCE' or 'BY VALUE'. The followingcan be taken as rule of thumb: BY REFERENCE: - default in the main program - or when a variable is declared SHARED/PUBILC etc. BY COPY: - default in a SUB/FUNCTION, if the variables aren't passed BY VALUE. BY VALUE: - always interpreted by the InLine-Assembler as BY VALUE You should only pass variables of type BY COPY to LDS/LES, because only then the DS/ES Segmentaddresses will be loaded and the Offsetaddresses into the other Registers. When passing BY REFERENCE DS/ES will be loaded with the high value contents of the variable, if of type Long/DWord, else the DS/ES Register will contain an irrelevant value. The other Registers will contain the low value of the variable. Example: SHARED DemoSeg%, DemoOff% i& = &h12345678 Demo1 i& Demo2 i& Demo3 i& FUNCTION Demo1(i&) public PRINT "PB-Adresse : ";: PRINT HEX$(VARSEG(i&));":"; HEX$(VARPTR(i&)) END FUNCTION FUNCTION Demo2(i&) public ! les bx, i& ! mov DemoSeg%, es ! mov DemoOff%, bx PRINT "LES /BY COPY : ";: PRINT HEX$(DemoSeg%);":"; HEX$(DemoOff%) END FUNCTION FUNCTION Demo3(BYVAL i&) public ! les bx, i& ! mov DemoSeg%, es ! mov DemoOff%, bx PRINT "LES /BY VALUE: ";: PRINT HEX$(DemoSeg%);":"; HEX$(DemoOff%) END FUNCTION 5.5. Crash after calling own INT-Functions ------------------------------------------ You will ask yourself: Why this section in the FAQ? Does the PowerBASIC InLine-Assembler have any Bugs? The answer is definetly: NO. But many calls using INT-Functions of the BIOS/DOS are connected to some trouble, because they change important Segments or specially address them. Many buffers that have to be passed to a function look for their pointer in the Datasegment-Register (DS). PowerBASIC also addresses its variables using DS, so that conflicts are 'programmed' here. It should not be like this, for example: ! mov ax, &h3D90 ; Function File open ! mov ds, FileSeg?? ; Load segment of Filename, ! mov dx, FileOff?? ; First error, because FileOff?? ; can't be addressed using DS. DS ; is already pointing somewhere else. ! int &h21 ; INT-Call ! mov Handle%, ax ; Because DS still points to nowhere ; for PowerBASIC, this is wrong, too, ; and PowerBASIC will crash sooner or ; later. A clean listing should look like this: ! push ds ; Save DS ! mov ax, &h3D90 ! mov dx, FileOff?? ; Load Offset of Filename ! mov ds, fileSeg?? ; Load Segment of Filename, not needed ; by PowerBASIC anymore ! int &h21 ; INT-Call ! pop ds ; Restore PowerBASIC Segment ! mov Handle%, ax ; Save Handle% (Or Errorcode) ! jnc ... ; Check Carry-Flag 5.6. Fixup Overflow ------------------- The problem is relatively easy and simple: The 8086 CPU only allows jumps of type SHORT, meaning that you can only jump to labels within -127/+128 OpCodes directly. The following example also creates such an error: DemoLabel: ! jc DemoLabel To get around this, you'll just have to address the whole thing a little different. This is principally no problem once you know it: DemoLabel: ! jnc DemoWeiter ! jmp near DemoLabel DemoWeiter: But this can be found in any good Assembler book... 5.7. Dividing variables from WORD to BYTE ----------------------------------------- Should you still turn your 16bit variables into its 8bit parts with mathematical work, it is time to finally stop it! The CPU can do it by itsself: Example: DIM Demo AS WORD DIM DemoHigh AS BYTE DIM DemoLow AS BYTE Demo?? = &H1234 ! mov ax, Demo?? ! mov DemoLow? , al ! mov DemoHigh?, ah 5.8. Dividing variables frob DWORD to WORD ------------------------------------------ More often you have the problem that you have pointers of type DWORD in PowerBASIC, but you don't know how to pass them to the InLine- Assembler or turn them into WORD. Principally this is quite simple (When you know how): Example: DIM Demo AS DWORD DIM DemoHigh AS WORD DIM DemoLow AS WORD Demo??? = &H12345678 ! mov ax, Demo???[00] ! mov bx, Demo???[02] ! mov DemoLow??, ax ! mov DemoHigh??, bx 5.9. Access to Arrays / Structures with the InLine-Assembler ------------------------------------------------------------- Access to static Datastructures is relatively easy with the InLine- Assembler if you already know the correct Offsetaddresses. PowerBASIC allows the following Syntax: Example: ! mov ah, byte ptr es:[di][22] This copies the value to Offset 22 of the address ES:DI into the AH- Register. --- CrossPoint v3.11 R * Origin: PBSOUND, PBFILES (27MB), PBFAQ, PBRULES, PBHIVGA at: 2:2410/330.1) --------------- FIDO MESSAGE AREA==> TOPIC: 214 POWER BASIC Ref: EBC00010 Date: 07/01/97 From: THOMAS GOHEL Time: 12:00am \/To: ALLE (Read 1 times) Subj: FAQ: PowerBASIC 10/16 (Assembler Part 2)00:00:0007/01/97 5.10. Parameter return with the InLine-Assembler ----------------------------------------------- In opposite to true Assembler the return of a variable works slightly different in the PowerBASIC InLine-Assemble. PowerBASIC 3.0 for example does not allow the direct return from the InLine-Assembler to the FUNCTION, this is only possible with a little trick. Example: High% = &h1234 Low% = &h4578 PRINT HEX$(Demo1&(High%, Low%)) FUNCTION Demo1&(BYVAL High%, BYVAL Low%) LOCAL Dummy& ! mov dx, High% ! mov ax, Low% ! mov Dummy&[02], dx ! mov Dummy&[00], ax Demo1& = Dummy& END FUNCTION From PowerBASIC 3.1 on you can directly pass the return value to the FUNCTION, only with 32bit (and bigger) values have to be passed using a little trick: Example: High% = &h1234 Low% = &h4578 PRINT HEX$(Demo2&(High%, Low%)) FUNCTION Demo2&(BYVAL High%, BYVAL Low%) ! mov dx, High% ! mov ax, Low% ! mov FUNCTION[02], dx ! mov FUNCTION[00], ax END FUNCTION 5.11. Parameter return in Interrupt-Procedures --------------------------------------------- Very hard is the passing of variables from within an own Interruptroutine, because you can guess that the Datasegment isn't the same as the one used by PowerBASIC. But the developers of PowerBASIC have left us a big back door here. The addressing using the Codesegment, which is usually the same! Yet this trick only works with the InLine-Assembler, to pass from/ to true PowerBASIC-Routines you will have to recopy this variable. Example: ! mov ax, &h1234 ! mov Demo, ax ! mov bx, Demo ! retn Demo: ! dw 0 Should you look at this thing with a Debugger, you will notice that PowerBASIC will add the Prefix &h2E (addressing using the Codesegment) in front of the access to the variable and the '!dw 0' field will hold the value &H1234. 5.12. Creating 32Bit-Pointers