Shop OBEX P1 Docs P2 Docs Learn Events
sasm label address assignment error — Parallax Forums

sasm label address assignment error

Peter VerkaikPeter Verkaik Posts: 3,956
edited 2005-02-23 22:09 in General Discussion
To PJM,

Sasm generates wrong addresses for labels when using macros.
I attached a listfile that has 3 jump macros that generate
either a jmp or a jmp @ based on current address ($).
I let the macros calculate the correct address but other labels
(after label user where the macros are used) also get the
wrong value (like _test2 and _test3 that are at the end of the listing).

Is it possible to correct this?

regards peter

Comments

  • PJMontyPJMonty Posts: 983
    edited 2005-01-24 18:29
    Peter,

    Post the source file instead of the list file and I can at least try and figure out what is going on. Also, please edit the source down to something tiny that demonstrates the problem. A 4000 plus line assembly code example is not very useful to me. A ten line source code example is very useful.
      hanks, PeterM

    Post Edited (PJMonty) : 1/24/2005 6:32:00 PM GMT
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-01-24 18:58
    Here is the source.
    regards peter
  • PJMontyPJMonty Posts: 983
    edited 2005-01-24 19:15
    Peter,

    Seriously, can you create something tiny as I requested? Sending me a 2476 line assembly source code listing (generated by a compiler no less!) as an example is almost a surefire way to guarantee it ends up at the bottom of my "To Do" list. As I mentioned in the previous post, a ten line example is far more useful than a 4000 line example.

    I'd like to see something that clearly and simply shows the problem, and is well commented to explain where the problem lies and what the problem is. I don't want to spend time trying to understand what is going on with your code and how it works. I want to spend time trying to understand why SASM is doing something wrong.
      Thanks, PeterM
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-01-24 20:18
    Ok,

    Here is a tiny file. What I want to do is to have either

    a jmp label or a jmp @label, based on wether label is in the current

    page or not. For that purpose there is a macro called dojmp.

    Problem is that label values get the wrong value after generated

    jmp label. The difference between the true address and the assigned address

    appears to be the number of times jmp label is generated, so this

    difference increases for every generated jmp label. Somehow sasm

    calculates label values using the maximum codewords for a macro,

    rather than assigning the current address where the label is defined.

    Note that labels test1 and test2·are correct, labels test3, test4 and

    test5 are incorrect.

    regards peter
  • PJMontyPJMonty Posts: 983
    edited 2005-01-24 20:50
    Peter,

    Excellent! Now I have a chance at getting to the bottom of the problem.
      Thanks, PeterM
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-01-25 08:03
    PeterM,

    Here is an updated file that has no org statements inside the code.

    I also found out that the macro does work while in code page 0.

    (my compiler generated code for pages 1, 2 and 3)

    regards peter
  • PJMontyPJMonty Posts: 983
    edited 2005-01-25 17:54
    Peter,

    Thanks for the updated source code. Let me see what I can find...
      Thanks, PeterM
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-02-21 12:25
    Has this issue been resolved?

    regards peter
  • PJMontyPJMonty Posts: 983
    edited 2005-02-22 01:22
    Peter,

    I believe this is not a solvable problem with a 2 pass assembler. You have this macro...

    dojmp macro address
      myAddress = address
      if myAddress/$200 == $/$200
        jmp ??\1
      else
        jmp @??\1
      endif
    endm
    



    ...which inserts an @ in front of the jmp if it is needed. You then call it in code like this:

    test1
                nop
                dojmp    test2
                nop        ;just some code
    test2
                nop
                nop
    




    In a two pass assembler (such as SASM), the first pass is used to build the symbol table. In other words, when a label like "test2" is present in the code, the assembler has to figure out what address "test2" corresponds to. If the code didn't use any macros, and looked like this...

    test1
                nop
                jmp    test2
                nop        ;just some code
    test2
                nop
                nop
    



    ...then SASM wouldn't be able to fill in the address for "test2" in the line that reads "jmp test2" until the second pass of assembly? Why? Because the code is assembled sequentially from first line to last. The definition of "test2" doesn't occur until two lines after "jmp test2". Thus, SASM has no way of knowing the value of "test2" on the first pass until it encounters the "test2" label in the code. When it does find "test2", it calculates the address and puts it in the symbol table. On the second pass, when it generates the actual code for the line "jmp test2", SASM will look up the value of "test2" in the symbol table and use that for the generated machine code.

    Ok, are you still with me? Now lets look at what happens when your macro is present. On pass one, the symbol table is being built. When SASM hits the line "dojmp test2", it recognizes it is a macro, and tries to figure out what to do. However, your macro has an "if/else" in it. Furthermore, the "if/else" answer depends on knowing the value of the passed parameter. In this case, the passed parameter is "test2". The problem (as we know from the earlier explanation) is that on pass one, SASM has no way of knowing what the value of "test2" is going to be since it won't discover the definition of the "test2" label until it parses a few more lines of source code.

    So, SASM has to figure out the answer to the "if/else" statement without knowing the actual values involved. On pass one, the macro looks like this to SASM:

    dojmp            macro    address
      myAddress = [i][b]unknown value[/i][/b]
      if [i][b]unknown value[/i][/b]/$200 == $/$200
        jmp    ??\1
      else
        jmp    @??\1
      endif
    endm
    



    As you can see, on pass one, the value of the passed parameter is unknown. The problem is that your macro will expand to either one byte or two depending on whether we do the "if" or the "else". This means that if SASM figures out the wrong answer (which it will because it doesn't know the value of the passed parameter yet), then it will increment its internal program counter the wrong number of bytes and thus calculate the future addresses wrong.

    If you assemble your short test file ("test16e.src"), you see that even with the ORG set to $1F0, the addresses get screwed up starting with the invocation of the line "dojmp test3". Why? Because on that line, the value of "test3" will cause SASM to ultimately generate two bytes of machine code since it has to add the "bank" command. Remember, while it's just adding an "@" in the source code, that "@" turns into the "bank" command, and generates another byte of machine code. However, SASM won't know it's generating two bytes of machine code until pass two, but it is building up the symbol table during pass one. Since it incorrectly assumes that it will use the single byte version of the code, all the addresses get mis-calculated from that point on.

    In know this is a ton of info to try and absorb. If you have any questions, please let me know. Unfortunately, I currently don't see any way for SASM to correctly handle the situation where a forward declared label is passed to your macro as the parameter.
      Thanks, PeterM
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-02-22 07:37
    PeterM,

    Thanks for the info. In an other thread someone else mentioned

    this miscalculation without using a macro (but involved a jmp@).

    I know the working of a two-pass compiler and the forward reference

    is the problem.

    From what I observed, SASM does use the expression with

    the wrong value (which is unknown at pass one) and therefore

    most probably increments the program counter with the wrong value.

    One solution might be:

    In pass one: Assume each macro will expand to zero instructions

    (i.e do not increment $) (in fact, assume all conditonal assembly

    takes 0 instructions)

    and assign $ to labels as you encounter them, (as it is done currently).

    In pass two:

    Generate code and expand macros (conditional assembly), but expanding macros requires

    that all labels that are greater than $, must be incremented by the

    storage words for the macro (i.e adjust symbol table values).

    If labels are already in another page than $, this

    will not change due to the increment.

    In pass three:

    Repeat pass 2, until labels match $ (they will at the end)

    This must be because forward referenced lables may change

    with each macro.



    Is this doable with the current compiler source?



    regards peter
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-02-22 08:02
    PeterM,
    This was the other thread
    http://forums.parallax.com/showthread.php?p=525216

    regards peter
    ·
  • PJMontyPJMonty Posts: 983
    edited 2005-02-22 08:18
    Peter,

    I wasn't sure how intimate you were with assemblers, so I'm afraid I was a bit pedantic.

    Anyway, as for turning the current version of SASM from a two pass assembler into an "n-passes as needed" assembler, it would be a seriously big undertaking. The idea of constantly updating and changing the symbol table on multiple passes is almost a guarantee that bad code will get generated. Of course, the current version is generating bad code, but at least I know the rest of it works.

    I also took a closer look at the original SASM documention (it's included as a .PDF when you install the IDE), and it mentions a number of places where expressions need to be "well defined" in pass one. In other words, if SASM doesn't know the value of something in pass one, it isn't "well defined". I did a brief experiment where I tweaked SASM to require well defined expressions on "=" and "set" (like it says SASM requires in the documentation) and it gives a warning with your macro. However, a change like this could end up breaking all sorts of code that is counting on SASM letting "=" and "set" use expressions in pass one that are not well defined. It's not the sort of change that I want to make lightly.

    So, the short answer for now is that I don't believe Parallax is going to want to fund the sort of work required to convert SASM into a arbitrary multi-pass assembler.

    Ironically, the other forum thread you mentioned is a bug I actually fixed tonight. After fixing that one, I then started to work on your bug, only to realize that the problem wasn't really a bug as much as it was a limitation of the assembler.
      Thanks, PeterM

    PS - We have a PeterJ, a Peter Verkaik, and a PJV on this forum (all names which sound like they could be the same person), and trying to remember which Peter I am responding to can get pretty weird at times...
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-02-22 08:44
    PeterM,

    Ok,

    So for now I should always use jmp@, which will

    always occupy 2 words, correct?



    regards peter
  • PJMontyPJMonty Posts: 983
    edited 2005-02-23 02:57
    Peter,

    I think that's the best alternative right now. I have one other idea to experiment with, but I don't know if it will work. It might be possible to use a line like...

    org $ + 1
    



    ...in the macro to adjust the program counter. However, I think it will still get the address calculations incorrect.
      Thanks, PeterM
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-02-23 07:17
    PeterM,

    I tried something like that but it leads to errors, as you expected.

    Here is another idea.

    Suppose I use jmp label initially everywhere.

    When SASM issues a warning being a target address not in the

    current page, I correct the line to jmp @label and recompile.

    (That's how I fix it manually)

    I repeat this step until no more warnings.

    Could this be automated (through an option to autofix jumps)?

    Of course this also applies to·jc, jnc, jz, jnz and djnz label

    Could also apply to calls if target address is in first half of page.



    regards peter
  • PJMontyPJMonty Posts: 983
    edited 2005-02-23 19:44
    Peter,

    The idea is sound. While it is technically possible to implment auto-fixing of jmps, I can't really see the benefit to the general community. It would also require multiple passes through the assembler to do the corrections. The problem is that when an error occurs, you really can't trust the rest of any assembly that follows it. Thus, the assembler would have to start assembling until it found an error, make a correction to the first error (since the rest may be bogus), try assembling again, fix the next error that is found, etc, etc.
      Thanks, PeterM
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-02-23 20:53
    PeterM,

    I know, that's why I don't fix jumps until that is the only warnings

    I get. If there is any other type of error or warning the fix must not

    be applied.

    regards peter
  • James NewtonJames Newton Posts: 329
    edited 2005-02-23 22:09
    I've been following this without really commenting. Often people have to explore all the possibilities before they decide something can't be done. And I always have hope that someone smart like Peter... well... all the Peters... will be the one who is "too uneducated to know it can't be done" and actually find a way to do it.

    Having said that, the only solutions that I have found are to try to limit the use of the page instruction in constructs were there are many jumps. E.g. binjump and GotoW macros near the end of
    http://www.sxlist.com/techref/ubicom/sasmcond.src There is a prior newsletter issue that describes this in more detail
    http://www.sxlist.com/techref/new/letter/news0201.htm and another issue that summarizes the ways that a select case construct can be made
    http://www.sxlist.com/techref/new/letter/news0302.htm

    I avoid using jmp PC+W type lookup tables in favor of IREAD tables. I'm amazed at the number of times the extra 4 bits comes in handy.

    Anyway, other than a custom assembler, I see no way to get rid of the page instruction.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ---
    James Newton, Host of SXList.com
    james@sxlist.com 1-619-652-0593 fax:1-208-279-8767
    SX FAQ / Code / Tutorials / Documentation:
    http://www.sxlist.com Pick faster!



Sign In or Register to comment.