Announcement

Collapse
No announcement yet.

PB3.5's inline assembler

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Hans Ruegg
    replied
    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

    ------------------

    Leave a comment:


  • Tom Hanlin
    replied
    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

    Leave a comment:


  • Hans Ruegg
    replied
    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.

    Leave a comment:


  • Tom Hanlin
    replied
    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

    Leave a comment:


  • James Lockwood
    replied
    Gary,

    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
    like:

    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.

    James
    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).]

    Leave a comment:


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

    ------------------
    Tom Hanlin
    PowerBASIC Staff

    Leave a comment:


  • Guest's Avatar
    Guest replied
    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?

    ------------------

    Leave a comment:


  • Tom Hanlin
    replied
    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

    Leave a comment:


  • Guest's Avatar
    Guest replied
    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:
    http://www.powerbasic.com/support/pb...ad.php?t=22552
    http://www.powerbasic.com/support/pb...ad.php?t=22856

    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...

    ------------------

    Leave a comment:


  • Bob Zale
    replied
    Gary...

    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.


    ------------------

    Leave a comment:


  • Guest's Avatar
    Guest replied
    *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...)

    ------------------

    Leave a comment:


  • Lance Edmonds
    replied
    Thanks! yes, &H66 rings a bell...!

    Code:
    !DB &H66
    !MOV AX,num


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

    Leave a comment:


  • Sebastian Groeneveld
    replied
    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>

    Leave a comment:


  • Lance Edmonds
    replied
    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.

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

    Leave a comment:


  • Guest's Avatar
    Guest started a topic PB3.5's inline assembler

    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...)

    ------------------
Working...
X