Shop OBEX P1 Docs P2 Docs Learn Events
Philosophical question... — Parallax Forums

Philosophical question...

Question: What is the difference between
if_c add    nxtptr, #4

and
if_c add    nxtptr, $4

in a 400 SLoC PASM routine?

Answer:

6 hours and a migraine.

Comments

  • yes, I have been there a lot. And one feels kind of stupid reading over it again and again not noticing.

    Enjoy!

    Mike
  • I do a strange thing when I’m hunting an “impossible” bug: I copy the code to a different editor and change the font. Why? Because it disrupts my “mental reference”. Completely. It makes my brain pay attention to each character. Especially when I change from a serif to a sans serif font. Yes, it is rather odd, but it works for me.
  • JonnyMacJonnyMac Posts: 8,912
    edited 2019-11-01 01:27
    I'm getting back to PASM after a bit of a break, but I am certain the first line adds the value four to nxtptr, and pretty sure the second line adds the value at address 4 (which holds the clock setting) to nxtptr. Edit: I was wrong about the second part.

    If nxtptr is pointing to a block of longs, the first approach is correct.

    A few minutes later...

    I decide to write a bit of test code -- I am sure about both assertions now. The first value returns 4, the second returns $80BC1404.
    dat
    
                            org     0
                            
    entry                   mov     t0, #0
                            add     t0, #4
                            
                            wrlong  t0, par                         ' write to arg0
    
                            mov     t0, #0
                            add     t0, $4
                            
                            mov     hub, par
                            add     hub, #4                         ' point to arg1
                            wrlong  t0, hub                         ' write to arg1
    
                            cogid   t0
                            cogstop t0
    
    
    t0                      res     1
    t1                      res     1
    hub                     res     1
    
  • Actually,
    if_c add    nxtptr, $4
    
    adds whatever is at location $004 in COG RAM, usually the 5th line of code.

    But ye, confusing absolute address vs. immediate data happens to me all the time when writing any assembly language.

    The weird custom PASM XMM assembler DSL uhm... thing I've been working on/with actually bypasses this problem by distinguishing between cog/hub/virtual addresses and literal numbers. It'd look like this
    if_c.add r0,4
    
    or this if you actually wanted to read from COG RAM
    if_c.add r0,cog(4)
    

    While that stops these inexplicable bugs, I keep forgetting to convert addresses into numbers when I load them into registers. At least that throws a compiler error.

    I feel like I should release that thing, but on the other hand, I don't think anyone else could really make any sense of it.
  • Thank you for the correction -- which makes perfect sense as we cannot get a value from the hub without a rdxxxx instruction.

    Told you I'd been on a PASM break! (lots of Python and C for work)
  • Using the standard PASM syntax, maybe the assembler could issue a warning if a constant is used in the source field without a #. A predefined comment could be used to disable the warning for that line. So the following code
            add nexptr, 4
            add nexptr, incr
            add nexptr, #4
            add nexptr, 4 ' No warning
    
    The first line would generate a warning. The last line wouldn't generate a warning because the assembler would interpret the "No warning" comment to disable the warning. There may be a few other cases that the assembler could warn about, such as "jmp label" instead of "jmp #label".
  • Dave Hein wrote: »
    Using the standard PASM syntax, maybe the assembler could issue a warning if a constant is used in the source field without a #. A predefined comment could be used to disable the warning for that line. So the following code
            add nexptr, 4
            add nexptr, incr
            add nexptr, #4
            add nexptr, 4 ' No warning
    
    The first line would generate a warning. The last line wouldn't generate a warning because the assembler would interpret the "No warning" comment to disable the warning. There may be a few other cases that the assembler could warn about, such as "jmp label" instead of "jmp #label".

    That's actually a very cleaver idea. I think 'No warning is a lot of typing, perhaps maybe something like 'nowarn or 'sptr (source is pointer)? It would probably be good to have a switch to turn off (or on) for people who find such warnings annoying. I'm sure this would have saved me many hours of debugging!
  • That's actually a pretty great idea indeed.
    Although "jmp label" is a lot more common than literal cog pointers, which may be annoying if you enable these warnings on pre-existing code.
    There's also the case of placeholder values for self-modifying code. Most people use "0-0", so that could also be detected, I guess?
  • Leave it to this group to take a complete shitpost and turn it into a legitimate technical analysis of microcontroller behavior. Never change my friends.
  • Dave Hein wrote: »
    Using the standard PASM syntax, maybe the assembler could issue a warning if a constant is used in the source field without a #. A predefined comment could be used to disable the warning for that line. So the following code
            add nexptr, 4
            add nexptr, incr
            add nexptr, #4
            add nexptr, 4 ' No warning
    
    The first line would generate a warning. The last line wouldn't generate a warning because the assembler would interpret the "No warning" comment to disable the warning. There may be a few other cases that the assembler could warn about, such as "jmp label" instead of "jmp #label".

    fastspin handles warnings for "jmp label" (no immediate) by looking at the label. If what follows "label" is code then it issues a warning, if it's data then no warning (it assumes you knew what you were doing and that the data is meant to hold an address). You can override this by making the operand a more complicated expression than just a label, so "jmp label+0" never issues a warning. We could implement something similar for literal constants, so:
        add nexptr, 4  ' gets a warning
        add nexptr, (4) ' no warning, not a plain literal
        add nexptr, 0-0 ' no warning, not a plain literal
    

    Another fastspin warning I've found useful is for instructions (other than nop) with no effect, e.g.:
        cmp  foo, #0  ' warning, instruction has no effect
        cmp  foo, #0 wz ' OK, instruction is setting Z flag
    
    I'm not sure how hard/easy that would be to add to p2asm, I haven't looked.
  • RaymanRayman Posts: 13,797
    This is an age old gotcha for PASM.
    I've learned to look for this when I have a bug...

    For me, I think the syntax is backwards...
    add nexptr, 4
    
    should add the number 4 and not register 4.

    But, you just have to learn to watch out for that...
  • BeanBean Posts: 8,129
    I really hate the use of # for immediate values.

    I like the Z80 style better. Where you put parens around the value if you want memory access.

    LD HL,123
    LD HL,(123)

    I think it makes it much clearer what you want to do.

    Actually square brackets would be even better then you could parens for math.

    Bean
  • The main times I've been bitten by forgetting # are in the JMP command. But before loading a program, I just do a global search for all my JMPs to make sure the #s are there in the ones that need them.

    -Phil
  • I like the idea of using parens to tell the assembler not to issue a warning if the # is missing. So "jmp #x" and "jmp (x)" would not issue warnings, but "jmp x" would issue a warning. The same thing would apply to other instructions like add or mov. x could be a label, number or an expression. It's a simple rule, and it doesn't create an incompatibility with old code. Of course, some old code would generate a lot of warnings. A command-line flag such as -nowarn could be use to disable warnings. Or maybe the default should be not to generate warnings, and -warn would be used to enable warnings.
  • escher wrote: »
    Question: What is the difference between
    if_c add    nxtptr, #4
    

    and
    if_c add    nxtptr, $4
    

    in a 400 SLoC PASM routine?

    Answer:

    6 hours and a migraine.
    Doh!

    Obviously the contents of register 4 was not always 4. I guess that line is followed by:
    rdlong data,nxtptr
    
    In that case it should be sufficient for the lower 16 bits to be $0004. That's somewhat unlikely, but it could happen if D was a multiple of 128 and S was 4.
    Uh, oh! Now you got me wondering what interesting things would happen if an instruction specified its own address for D, S, or both.


    BTW, I made a meme. forums.parallax.com/discussion/170706/meme-what-i-accomplish-on-social-media
Sign In or Register to comment.