pnut v34s assembler bug?

I took this code out of the docs and compiled it:
DAT
        ORGH    $01000
        ORG     0       'cog code

cog     JMP     #cog    '$FD9FFFFC      cog to cog, relative
        JMP     #\cog   '$FD800000      cog to cog, force absolute
        JMP     #@cog   '$FD801000      cog to hub, always absolute
        JMP     #\@cog  '$FD801000      cog to hub, always absolute

        JMP     #hub    '$FD802000      cog to hub, always absolute
        JMP     #\hub   '$FD802000      cog to hub, always absolute
        JMP     #@hub   '$FD802000      cog to hub, always absolute
        JMP     #\@hub  '$FD802000      cog to hub, always absolute

        ORGH    $02000  'hub code

hub     JMP     #cog    '$FD800000      hub to cog, always absolute
        JMP     #\cog   '$FD800000      hub to cog, always absolute
        JMP     #@cog   '$FD9FEFF4      hub to hub, relative
        JMP     #\@cog  '$FD801000      hub to hub, force absolute

        JMP     #hub    '$FD9FFFEC      hub to hub, relative
        JMP     #\hub   '$FD802000      hub to hub, force absolute
        JMP     #@hub   '$FD9FFFE4      hub to hub, relative
        JMP     #\@hub  '$FD802000      hub to hub, force absolute

The output I am getting for these instructions are:
FD9FFFFC    ' same
FD800000    ' same
FD801000    ' same
FD801000    ' same

FD803000    ' different. bad encoding?
FD803000    ' different. bad encoding?
FD802000    ' same
FD802000    ' same

FD800000    ' same
FD800000    ' same
FD9FEFF4    ' same
FD801000    ' same

FD900FCC    ' different. bad encoding?
FD802FE0    ' different. bad encoding?
FD9FFFE4    ' same
FD802000    ' same

Comments

  • Also, slightly related to this, but a general question: Is the first instruction encoding incorrect? Should it be FD9FFFFF (-1 instead of -4)? Comparatively, if I change the "ORG 0" to "ORG 1", the encoding is FD800001 (instead of FD800004), which seems correct.
  • Okay. After playing a bit, it seems that for the above instructions, the relative addresses are always byte-count, regardless of execution mode. So, when executing in cog mode, the actual relative value is "A >> 2" (instruction format is "JMP #{\}A").

    Here's a small program that demonstrates the pattern:
    DAT
            org
            not     dirb            ' F623F7FB
            setbyte outb, #$F, #3   ' F8DFFA0F
    lp      not     outb            ' F623FBFD
                                    ' FF802625
            waitx   ##20_000_000/4	' FD66801F
            jmp     #lp             ' FD9FFFF0
    

    (note: I realize others may already know this, but it's not documented in the the Google Doc, doesn't match the documentation in the spreadsheet, and seems to follow a different encoding rule than the other relative branch instructions. I'm trying to nail this all down so that I can get the docs updated appropriately.)
  • SeairthSeairth Posts: 2,465
    edited 2020-06-26 - 17:38:14
    Here's a variant that runs the loop in hub mode:
    DAT
            org
            not     dirb            ' F623F7FB
            setbyte outb, #$F, #3   ' F8DFFA0F
            jmp     #\@lp           ' FD800400
    
            orgh    $400
    lp      not     outb            ' F623FBFD
                                    ' FF802625
            waitx   ##20_000_000/4	' FD66801F
            jmp     #@lp            ' FD9FFFF0
    

    If I remove the "@" from the last line, the program breaks. This seems to match the encoding issue in the 13th JMP in the original post. More generally, it seems that the hub address is not being calculated correctly unless "@" is used.
  • And one more version:
    DAT
            org
            not     dirb            ' F623F7FB
            jmp     #\@hp           ' FD800400
    lp      not     outb            ' F623FBFD
                                    ' FF802625
            waitx   ##20_000_000/4	' FD66801F
            jmp     #lp             ' FD9FFFF0
    
            orgh    $400
    hp      setbyte outb, #$F, #3   ' F8DFFA0F
            jmp     #\lp            ' FD800002
    

    Here, you will notice that the absolute jump from cog to hub was the hub's byte address ($00400), whereas the jump from from hub to cog was the cog's address ($002). For cog address, absolute is the actual address, but relative (as seen above) must be (cog_address << 2).
  • SeairthSeairth Posts: 2,465
    edited 2020-06-26 - 20:17:46
    So given this, here are the rules I'm seeing:
    • For all absolute addresses, the address is the instruction's location in memory: $000..$3FF for cog/lut, $400..$7FFFF for hub
    • For relative addresses in hubexec mode, the value is: address_of(hub_label) - address_of(instruction) + 4
    • For relative addresses in cogexec mode, the value is: (address_of(cog_label) - address_of(instruction) + 1) << 2

    (edit: corrected relative equations.)
  • evanhevanh Posts: 9,642
    edited 2020-06-26 - 21:31:34
    Hub to hub is broken since v34M. Pnut v34L was the last working version.

    EDIT: It's interesting that adding an @ makes it work ...
    Yep, that's fixed the crashes with calling hubexec->hubexec ...
    and now same for lutexec->hubexec ...
    and also true for LOC instruction in same conditions.

    Here's the non-broken one:
  • evanh wrote: »
    Hub to hub is broken since v34M. Pnut v34L was the last working version.

    Good to know. It looks like is's more generally the handing of hub labels when @ isn't used.

  • Seairth wrote: »
    It looks like is's more generally the handing of hub labels when @ isn't used.
    Yes, symbol handling. Specifying an address works no problem.

  • evanhevanh Posts: 9,642
    edited 2020-06-27 - 00:49:22
    Here's my earlier report in the Pnut topic - https://forums.parallax.com/discussion/comment/1496344/#Comment_1496344 which in-turn references a topic where Chip became aware of the bug.

    EDIT: Attached an example testing of the bug. And my old loc-bug test code also trips up on it:
  • JMPREL seems to have the problem as well:
    DAT
            org
            not     dirb            ' F623F7FB
            setbyte outb, #$F, #3   ' F8DFFA0F
    lp      not     outb            ' F623FBFD
                                    ' FF802625
            waitx   ##20_000_000/4	' FD66801F
            jmprel  #lp             ' FD640430
    

    This means #D was encoded as $002. But I think it should be encoded as FD67F830, making #D = $1FC (-4).

    (note also that I happen to have an outstanding comment/question on the docs for JMPREL that's somewhat related.
  • ozpropdevozpropdev Posts: 2,696
    edited 2020-06-27 - 04:39:34
    jmprel #lp will jump forward 3 instructions because lp's cog address is 2.
    This is correct behaviour.
  • Oh, duh, I'd always struggled with what use JMPREL was. I'd pretty much ignored it. It's for when using register direct addressing mode for the branching distance, because with JMP D the value in D is always an absolute address! Only JMP #D immediate addressing mode can do relative addressing.

  • I'm sorry I haven't fixed this, yet. When I release the next PNut.exe, I'll have this repaired. I've almost got the Spin2 debugger working so that it reports expressions and variables.
  • Good to know you've not forgotten it. :)
  • SeairthSeairth Posts: 2,465
    edited 2020-06-27 - 13:08:50
    ozpropdev wrote: »
    jmprel #lp will jump forward 3 instructions because lp's cog address is 2.
    This is correct behaviour.
    evanh wrote: »
    Oh, duh, I'd always struggled with what use JMPREL was. I'd pretty much ignored it. It's for when using register direct addressing mode for the branching distance, because with JMP D the value in D is always an absolute address! Only JMP #D immediate addressing mode can do relative addressing.

    Ok, so this prompted me to try some other variants. The result is:
    • The register-mode value can be positive or negative.
    • The immediate-mode value can only be positive. (this is not apparent from the spreadsheet docs.)
    In which case, the use of a label in an immediate value seems risky and not what the user wants, most of the time. At the very least, the labels should be calculated using their relative address, so that my code above would throw the same error that's thrown if I try:
    JMPREL  #-4     '<-- Constant must be from 0 to 255.
    
    At the same time, this would likely result in the correct forward-relative offset for the most common use case. Admittedly, this is just like JMP #A at that point, but less flexible.

    So, I'm going to go out on a limb, and suggest that the documentation for JMPREL be changed to remove mention of the relative-mode addressing (and hardcode the L field to zero). This would make it clear that there is exactly one instruction used for relative immediate-mode jumps.
  • evanhevanh Posts: 9,642
    edited 2020-06-27 - 22:00:42
    Yes, emphasise register direct use. And say it's to fill the addressing mode gap in JMP instruction.

    Not sure about removing mention of immediate addressing though. Maybe stating its limit and referring readers to JMP #A as a superior equivalent.

Sign In or Register to comment.