No announcement yet.

PB3.5's inline assembler

  • Filter
  • Time
  • Show
Clear All
new posts

  • PB3.5's inline assembler

    I hate to say it, but PB35's inline assembler is proving to be a source of considerable frustration... among other things, its syntax appears to be subtly different from that used in the books I have on 80x86 assembly code, so I keep getting errors. The documentation that comes with PB35 is of little help, as it pretty much glosses over the whole subject... is there a document anywhere (a tech bulletin, a PDF file, or even an article in a programming magazine) that documents the inline assembler IN DETAIL???

    Also - why does the inline assembler not support anything higher than 8086/8088 opcodes, or even 80x87 opcodes? The latter may be of critical importance, as the program I'm trying to put together has an interrupt-driven section which combines assembly and PowerBASIC code. I have, thanks to this forum, example code on how to do that, but the code doesn't seem to context-save the 80x87 registers, and I may need to perform a couple of floating-point operations during the interrupt. (Or does the PB runtime do this by itself? I can't imagine how it could, but...)


  • #2
    PB/DOS only supports 8086/8088 mnemonics, sorry.

    You can utilize non-supported mnemonics by using the !DB mnemonic followed by the hex code of the instruction and it's operands, etc.

    This is a common technique to "trick" PB/DOS inline-assember code into using 32-bit mnemonics, by inserting a single hex code before the 16-bit mnemonic. This way, !MOV AX,num can effectively become !MOV EAX,num.

    Sorry, I'm not at my Dev PC to look up the partcular code to handle this, but I'm sure another kind soul can help you with that!

    I don't have any information on the 8087 issue, but I'll ask R&D about this for you.

    PowerBASIC Support
    mailto:[email protected][email protected]</A>
    mailto:[email protected]


    • #3
      Just insert "!db &H66" to make a 32-bit instruction, so
      ! mov eax, num
      should be written as:
      ! db &H66
      ! mov ax, num

      This works in any high-level programming language supporting inline assembler (phew, nice sentence)

      Sebastian Groeneveld
      mailto:[email protected][email protected]</A>
      Sebastian Groeneveld
      mailto:[email protected][email protected]</A>


      • #4
        Thanks! yes, &H66 rings a bell...!

        !DB &H66
        !MOV AX,num

        PowerBASIC Support
        mailto:[email protected][email protected]</A>
        mailto:[email protected]


        • #5
          *SIGH* ... OK, I guess that sort-of answers the question about getting control of the 8087 to context-save its state during the ISR, if I can figure out the opcodes... (the book I have on 8087 programming is rather byzantine, to say the least.) I would still like to know just why PowerBASIC's inline assembler hasn't been updated to include the FPU or 286+ instruction set, though; it seems rather disappointing that, with an otherwise modern language like PB35, I have to go back to the old TRS-80 Model I days of hand-assembling machine codes byte-by-byte... could this, perhaps, be added to the list of improvements to be made for PB4?

          Also, I would still like to find some kind of COMPREHENSIVE documentation on the inline assembler's syntax...

          This raises another spectre, BTW - do PowerBASIC's internal routines make use of the extended 32-bit registers when the code is compiled for a 386/486 target? And, if so, does that mean I have to try to hand-assemble all of those PUSH/POP instructions as well? (Remember, I intend to mix assembly and PowerBASIC within the ISR, on a program targeted for a 486-based embedded-systems board, so presumably everything that the PB routines make use of has to be saved on entry and restored on exit...)



          • #6

            You can not use any BASIC-Language statements during hardware interrupt service unless there is absolutely no foreground activity of any kind. You do not have the capability to save and restore the state of the foreground code.

            Bob Zale
            PowerBASIC Inc.



            • #7
              ok, i am now thoroughly confused...

              i asked, on this forum, exactly this question some time ago. (i can't seem to find it in the archives now, though.) at the time, i explained exactly what i was up to, and what it was i intended to do. let me go through it again...

              i currently have a program (written "three engineers ago") which consists of about 75% fortran and 25% assembly, running under dos. the bulk of the program, including all of the foreground tasks such as user-interfaces and such, is in fortran. there is a 200hz, hardware-driven interrupt in the embedded system this runs on, which invokes an isr which is part of our program. this isr consists of just enough assembly to context-save the processor states, read the a/d converters (since fortran is relatively incompetent at hardware i/o), then transfter control to a block of fortran code which does some quick calculations for a proportional/integral servo-control loop. the fortran code then transfers control back to the assembly section, which puts the calculated values into the dacs controlling the servos, restores the processor states, and exits back to the main code loop.

              this code is in desperate need of updating (as is the whole system), and i had hoped to do it in powerbasic. i asked, specificially, whether it was possible to do the above with pb code; i was told, on this forum, that yes, it is possible, and i was pointed towards these two message threads in the source code forum:

              as examples of how to do it. based on that, i recommended to the higher-ups around here, over the objections of our resident "c++ uber alles" zealots, that we invest in pb compilers and do the project this way. (we subsequently had to shift gears to complete a different project - we're a small, scientific-instrument company without a large r&d staff - which is why i'm only now getting back to this project.)

              are you now telling me, bob, that i cannot do this? i sure hope not because, to be perfectly frank, this is gonna make me look really bad...



              • #8
                PowerBASIC programs may well use 32-bit registers, yes. Moreover,
                the operating system may also be expected to use these registers,
                so it will be necessary to save them in any event. However, you do
                not need to hand-code a long series of pops and pushes; instead,
                use the "push all" (PUSHAD) and "pop all" (POPAD) instructions.
                These will save/restore EAX, EBX, ECX, EDX, ESP, EBP, ESI, and
                EDI (although why Intel thought it useful to store ESP on the
                stack is beyond me).

                It is possible to service hardware interrupts using the PowerBASIC
                inline assembler. It is not possible to use BASIC code inside a
                hardware interrupt handler, because the BASIC runtime library is not
                reentrant. Yes, there's an example in the Source Code forum that
                seems to show otherwise. I presume it seems to work. At some point,
                though, the interrupt handler will conflict with the main
                program, and the best that will result is a program crash.

                Perhaps it will be practical to convert the FORTRAN part of your
                interrupt handler to pure assembly language?

                Tom Hanlin
                PowerBASIC Staff


                • #9
                  well, yeah, if i wanted to hand-code about fifty-odd floating-point calculations into assembly code, but the whole point of this exercise was to avoid doing that... given that i can't even use the 8087 mnemonics in the inline assembler, and i don't really understand how the ieee floating-point format works anyway (i've read that section of my 8087 book about five times now, and it still makes my eyes glaze over ), and that the main program loop also needs access to the results of the servo loop, that's about as hideous a prospect as i can imagine...

                  *sigh* ok, i guess my only hope of making this work is to try the set uevent trick described in and hope the servo loop can stand the resulting interrupt latency... or is there some hidden reason why that won't work, either?



                  • #10
                    Should work fine-- that's what UEVENT was designed for-- as long as
                    the latency isn't a problem.

                    Tom Hanlin
                    PowerBASIC Staff


                    • #11

                      Thanks for the links about executing power basic code through an
                      interrupt service routine. I want to do this for a project I
                      am programming for a customer who insists on using Power Basic,
                      (because that is what he is used to) and it is nice to know that
                      it is possible, as I've not used Power Basic yet (don't discredit
                      my contribution, yet!)

                      In return for the information, I wish to clear up the confusion
                      about the technique described and the insistance by Tom
                      that it is guaranteed to lock up because power basic is not
                      re-entrant. Both are correct, and both not exactly right.

                      First let's understand what re-entrant code is. Re-entrant
                      code can be called within itself and upon returning, the previous
                      state of it's variables are preserved. This means that upon
                      calling the subroutine/function, all local variables are
                      dynamically allocated on the stack, and that the actual machine
                      code which manipulates the variables is not accessing an
                      absolute memory address, but instead memory locations that are
                      indexed from a base pointer. Upon exiting the routine, the
                      stack will be released and the base pointer points to the old
                      set of local variables. You can see that this would have some
                      overhead associated with each invocation and ending of a
                      routine (and to a lesser extent the code itself), which would
                      be in direct violation what Power Basic seems to pride itself
                      in--the generation of quick code. There may, however be a
                      keyword to identify a routine as re-entrant however, as this
                      is quite a useful feature--i'd be surprised if you couldn't
                      specify a routine as being re-entrant.

                      "By using proper care", as indicated by the discussions in one
                      of links you've provided, is somewhat complicated to describe,
                      but here I'll try. It means that you must not call any
                      code which might execute during the main program. And conversely
                      your main code can not call any of the code that your interrupt
                      service routine might call. IF you do, your code IS guaranteed
                      to crash at some point because of the non-reentrant nature of
                      your code generated by Power Basic (unless you write code in the
                      beginning which checks
                      to see if you are already executing the routine, by using a flag,
                      and promply exiting before altering local static variables.) But
                      this is not all--you must also not use any Power Basic commands
                      in your interrupt service routine which use the run-time library.
                      Basic calculations, and looping structures and other relatively
                      "simple" commands in your ISR will be fine, as the power basic
                      compiler will compile it into straight assembly. Other higher
                      level commands which when compiled simply jump to a Power Basic
                      run-time library routine to execute (for example, because the
                      routine is long, and would take up significant space if the
                      code is directly inserted into the executable code every time
                      the instruction is called) must not be called, as the library,
                      as stated, not re-entrant. One way to be sure your ISR will work
                      would be to look at the ISR code Power Basic generates and make
                      sure no calls are made to the run-time library.

                      One thing that I see (or don't see) that is wrong with what is
                      otherwise some very good code, is that there is no acknowledgement
                      to the 8259 interrupt controller that the interrupt service
                      routine has finished execution. This is usually done at the end
                      of the ISR with an OUT instruction which sends a 0x20 to IO
                      location 0x20. (Haven't practiced 80x88 Assembly code in years,
                      so I don't have the exact inline assembly---I think it is something

                      MOV AL,20h
                      MOV DX,20h
                      OUT DX,AL

                      but not 100% sure--you get the idea though.)

                      This is sending a "non-specific end of interrupt" command to the
                      8259 chip.

                      The reason this is important is because I don't believe that
                      the same interrupt will be able to be executed two times in
                      a row without another interrupt routine executing. On low-
                      frequency routines like the one shown, that is ok, as it is
                      virtually certain that another interrupt service routine will
                      properly end with this code, which in effect re-enables yours
                      again before the interrupt request is attempted (because it
                      is a non-specific end of interrupt command).

                      On your servo updates, you would might have some
                      problems without sending this "non-specific end of interrupt"
                      command, as I assume they will be of relatively high frequency
                      to get a good control response for your motor.

                      In summary, yes you can do it safely, but only by using a subset
                      of the Power Basic commands which don't rely on the run-time
                      library for execution.

                      P.S. Also note that your code will need to be run in its
                      compiled form, and not interpreted.

                      [This message has been edited by James Lockwood (edited January 21, 2001).]


                      • #12
                        The problem with avoiding the BASIC runtime library is, virtually anything might you do in BASIC employs a runtime routine of one sort or another. Even some simple numeric calculations may involve runtime calls. Using strings is right out, as are all BASIC functions and probably 99% of BASIC commands.

                        To be scrupulously correct, yes, it is possible to do an ISR handler in PowerBASIC. However, you would need to use only the most incredibly minimal subset of BASIC, you'd have to know how the compiler works at an uncommon level of detail, and you'd probably need to run a debugger on the resulting code to make absolutely sure that no runtime calls were involved. This is not a terribly practical technique. It would be far easier just to do the work in assembly language to begin with.

                        Tom Hanlin
                        PowerBASIC Staff


                        • #13
                          So getting back to the subject of ISR's again... there is another
                          little problem I ran into short ago. I had an ISR hooked to interrupt &H1C
                          which just reads some data form a buffer and send the data to the PC speaker
                          in order to play a little muical tune in the background while the rest of the
                          program is running. The interrupt handler is completely written in inline
                          assembler, does not access any PB variables, only Code segment variables
                          (and the data buffer whose address is also read from a CS variable).
                          However, I found this code crashed as soon as the main program executed a
                          DEF SEG = X statement. Does DEF SEG in some way interfere with the interrupt
                          handler? And if this is so, are there possibly other PB statements which
                          could also interfere with an inline assembler ISR?
                          (My interrupt handler did not send acknowledge to port &H20 - I just read
                          about it this very moment - perhaps this is the problem?)

                          Hans Ruegg.


                          • #14
                            Interrupt 1Ch is one of the timer hooks, isn't it? You should not need
                            to send an EOI for that. Do make sure that you're chaining to the previous
                            INT 1Ch handler when your routine ends.

                            There's nothing particularly special about DEF SEG. It just saves the
                            specified segment value for use when doing PEEK/POKE commands. The first
                            suspect would be the ISR routine. Make sure you're saving and restoring
                            any CPU registers that you change, including the flags. Make sure you're
                            not making any unwarranted assumptions about the values of the registers
                            coming into the ISR routine.

                            Tom Hanlin
                            PowerBASIC Staff


                            • #15
                              Bug found!! Yes, I was wrong about the source of the error. (The original program
                              had over 2000 lines of code, so it was easy to overlook some details.) It was not
                              the DEF SEG statement which altered the interrupt handler, but it was rather the
                              routine hooking the interrupt which altered the value of an already active DEF SEG.
                              So after this fix, I am posting the code in the Source Code forum (see there
                              "PLAY music in the background").

                              Hans Ruegg