Shop Learn
weird problem with rdlong — Parallax Forums

weird problem with rdlong

I am having a weird problem with rdlong. It dereferences one pointer correctly but fails on the next one. I think I'm handling both pointers the same, and could use an extra eye or two on the problem.

This is the PASM and the output of a SPIN diagnostic. The left column is diagnostics and the right column is the real code. Ft* are function temps.

On the red boxed line showing the contents of address $6210 (aCycleTraceBufferStart), you can see that ft1 in PASM read address 4B8C, and ft3 correctly got the value $BEEFDEAD at the end of that buffer. Ft3 correctly got the address $4C44, which you can verify two lines above. But when I do "rdlong ft2,ft3", ft2 gets the wrong value! The last value in paragraph $6210 is $01FC, which is incorrect. The correct value is $07F4, as shown in the dump two lines above, and the line above that with the '?' mark. I know the read value is incorrect because the following code does the wrong things, so it's not just an indication error.

Thinking that the variable is changing when I read it, I first made a shadow, which is why there are two identical values at $4C40. At one time, I also had stabilization code in PASM that forced made the code loop until it read the same value twice in a row. The ft* variables are at the end of PASM right before FIT, and there are 5 longs left in the cog.

Can some kind soul point out my error?


  • Hi,
    Without seeing the actual code it might be difficult to understand what is going on.

  • Larry MartinLarry Martin Posts: 60
    edited 2021-09-12 17:38

    This is as much as I can show (edited: replaced indented diagnostic code in ShiftSpinHistory):

      _CLKMODE = XTAL1 + PLL16X
      _XINFREQ = 5_000_000                     'Algorithms depend on code being >> faster than data
      CLK_FREQ = ((_CLKMODE-xtal1)>>6)*+_xinfreq
      MS_CNT   = CLK_FREQ / 1_000
      CC16ParamsReady     = $01 'limit constants to 8 bits for Assembly
      CC16ResultValid     = $02 'use for Feig as well since it has its own flag word
      'ToDo: move this out of common memory and into each cog's memory.  Needs access methods.
      kTxBuffSize       = 128 'BUFSIZE we only need about 96 bytes, but the mask scheme demands a power of 2
      kTxBuffMask       = $7F 'BUFSIZE
      kRxBuffSize       = 256 '128 'BUFSIZE we only need about 96 bytes, but the mask scheme demands a power of 2
      kRxBuffMask       = $FF '$7F 'BUFSIZE
      kLogSlots               = $20
      long  cog                     'cog flag/id
      long lSlotReaderHistoryOfTag_p '96
      long lTagHistoryAlloc_p       '100
    ''These methods execute in caller's address space and cog
    ''Only the assembler code below executes in a separate cog
    PUB start(rxpin, txpin, mode, baudrate, pCmdBuf_p, pCmdLen_p, pStartMs, pGapCount_p, pCmdBufFlags_p, pIndex, pHist_p, pActive_p) : okay | bix
      repeat bix from @rx_head to @tx_buffer
        BYTE[bix] ~
      'bytefill(@rx_buffer, 0, kRxBuffSize)
      CmdBufFlags_p := pCmdBufFlags_p
      longmove(@rx_pin, @rxpin, 3)
      'bit_ticks may be marginal for 115200.  Scope shows bit detection drifting into end of bit time
      bit_ticks := clkfreq / baudrate  'clqfreq is $04C4B400 == 80,000,000
                                       'should be 694.4 at 115200 baud
      buffer_ptr := @rx_buffer     ' read by PASM INIT
      rxtx_mode := mode                               'GlueLogix: mode not saved in published module
      kTICK_CNT := CLKFREQ / 1_000
      CmdBuf_p := pCmdBuf_p
      CmdLen_p := pCmdLen_p
      lCycleTraceNumSlots := kLogSlots 'for ASM
      lCycleTraceGuardWord := $EFBEEDFE 'comes out FEEDBEEF in dump, good landmark for rx queue
      StartMs := pStartMs
      RetryFlags := $00000004 ' default retries, no flags
      Index := pIndex  '     & $01 'aug20 back to alternate gaps
      GapCount_p := pGapCount_p
      lSlotReaderHistoryOfTag_p := pHist_p
      lTagHistoryAlloc_p := pActive_p
      okay := cog := cognew(@entry, @rx_head) + 1     '@entry is the assembly driver below
    '* Assembly language computation "driver" *
    ' Entry
                            mov     pSlotReaderHistoryOfTag_p,par
                            add     pSlotReaderHistoryOfTag_p,#96
                            mov     pTagHistoryAlloc_p,par
                            add     pTagHistoryAlloc_p,#100
    fast_gap                'FastGap
                            'Dec2020 Use global GapCount from CompuCog via pointers
                            rdlong t1,aGapCountAddress_p
                            cmp    t1,GapCountLocal         wz
            if_z            jmp    #fast_gap_done
                            mov    GapCountLocal,t1
                            'Jul2020 select edges by index
                            ' see also "180 degree trigger" Jan21 in CompuCog PASM and main SPIN.
                            mov      t3,GapCountLocal
                            'STAGGER: every 4 gaps
                            'and      t3,#$03 ' quickie //= 4
                            'cmp      t3,pasmIndex     wz
                            'STAGGER: every 2 gaps
                            xor      t3,pasmIndex
                            and      t3,#$01   wz ' //= 2
                            'end edge selection
            'STAGGER: comment to go every time:
            'if_nz           jmp      #:fast_gap_save
                            'end select edges by index
    :checkSpinShift         'Sep2021 avoid race condition in SPIN history.  CompuCog is full, so do it in the first active reader
                            call     #ShiftSpinHistory 'ASSUME this balis out on null pointer
                            'set up for the command chain
                            'mov     lCycleTraceOpcode, #$B3
                            'call    #CycleTraceAppend
                            test    SerialStatus,kTxingSequence  wz
                'if_nz       mov     lCycleTraceOpcode, #$97  'processing command sequence at gap time
                'if_nz       call    #CycleTraceAppend
                if_z        jmp     #:tryEnqueue
                'ok so we are still in a sequence.  Report Overrun
                            mov     SpinCmdFlags,#0
                            rdlong  t1,aGapCountAtRead      'save the low nibble of starting gap count
                            and     t1,#$0F
                            or      SpinCmdFlags,t1
                            shl     SpinCmdFlags,#4
                            or      SpinCmdFlags,pkC2cTidReadOverrun 'set the bad flag
                            call    #CmdFlagBufEnqueue
                            jmp     #:fast_gap_save 'Mar21: ALWAYS jump away, never send command if reader is still working
                            xor     SpinLengthCursor,SpinLengthCursor
                            xor     SpinCmdCursor,SpinCmdCursor
                            'mov     lCycleTraceOpcode, #$91 'Edge, new command
                            'call    #CycleTraceAppend
                            call    #EnqueueNextCommand 'sets kTxingSequence in SerialStatus
                            wrlong  GapCountLocal,aGapCountAtRead 'save the gap count at which the read started
                            'mov    LastInA, ThisInA
                            jmp     #computations
    ShiftSpinHistory        'FUNCTION
                            rdlong   ft1,pSlotReaderHistoryOfTag_p  wz
                            'cmp      ft1,#0 wz
                     if_z   jmp      #ShiftSpinHistory_Ret
       mov ft4,aCycleTraceBufferStart
       wrlong ft1,ft4
       add ft4,#4
       mov ft2,ft1
       add ft2,#$80
       rdlong ft3,ft2
       wrlong ft3,ft4
                            rdlong   ft3,pTagHistoryAlloc_p  wz
                            'cmp      ft3,#0 wz
                     if_z   jmp      #ShiftSpinHistory_Ret
                            nop 'tried nop since OP
                            rdlong   ft2,ft3
       add ft4,#4
       wrlong ft2,ft4  '<<<<< WRONG VALUE, SEE SCREENSHOT ABOVE
                            mov      ft3,#32 'kTagHistoryNumElem
                            test      ft2,#1 wz
                     if_z   jmp      #:ssh_loop_next 'commenting this works but all the values shift to 0
                            rdlong   ft4,ft1
                            shl      ft4,#4
                            wrlong   ft4,ft1
                            shr      ft2,#1
                            add      ft1,#4
                            djnz     ft3,#:ssh_loop_top
    ShiftSpinHistory_Ret    'Assembler checks for label <funcname>_RET
    pSlotReaderHistoryOfTag_p res   1
    pTagHistoryAlloc_p      res     1
    ft1                     res     1
    ft2                     res     1
    ft3                     res     1
    ft4                     res     1
      FIT 'Compile-time error if previous instructions/data exceed Address

    ShiftSpinHistory (diagnostic lines removed here) is called when FastGap sees a new sensor edge. It relies on initial setup of pointers to SPIN variables lSlotReaderHistoryOfTag and lTagHistoryAlloc. lTagHistoryAlloc tells what elements of lSlotReaderHistoryOfTag need to be shifted. If "if_z jmp #:ssh_loop_next " is commented, everything gets shifted every time. If it is not commented, the wrong cells get shifted because ft2 is wrong.

    This is the SPIN diagnostic:

          Fourrdrs.Hex(K4RdrHost, lTagHistoryAlloc, 8) 'deleteme
          Fourrdrs.Tx(K4RdrHost, "?") 'deleteme
          DumpMemoryToHost(@lTagHistoryAlloc, 8) 'deleteme
          DumpMemoryToHost(UidTid.GetLadderLogBufferAddress, 16) 'deleteme
          DumpMemoryToHost(@lSlotReaderHistoryOfTag, 33*4) 'deleteme
  • Just a shot in the dark, but do you have any bytes or words declared above lSlotReaderHistoryOfTag_p and lTagHistoryAlloc_p?

    From Prop manual, p212:
    Organization of Variables
    During compilation of an object, all declarations in its collective VAR blocks are grouped together by type.
    The variables in RAM are arranged with all the longs first, followed by all words, and finally by all bytes.
    This is done so that RAM space is allocated efficiently without unnecessary gaps.
    Keep this in mind when writing code that accesses variables indirectly based on relative positions to each other.

    You're passing the address of rx_head through par, then adding offsets to get the pointers to pSlotReaderHistoryOfTag_p and pTagHistoryAlloc_p.

  • Larry MartinLarry Martin Posts: 60
    edited 2021-09-13 12:03

    (edited 13Sep21) There are roughly 24 longs before lSlotReaderHistoryOfTag_p, spacing that variable out to address 96. That's the point of the ellipses and the comments '96 and '100. There are no variables of other sizes declared.

    The diagnostic screenshot shows that pSlotReaderHistoryOfTag_p ($4B8C) and its dereference ($beefdead at offset $80) are correct, and that the pointer to pTagHistoryAlloc_p ($4C44 in ft3) is correct as well. Only the dereference of the second pointer is bad: "rdlong ft2,ft3" places $0000_01FC in ft2, where the SPIN diagnostic shows that location holding $0000_07F4.

    You're passing the address of rx_head through par, then adding offsets to get the pointers to pSlotReaderHistoryOfTag_p and pTagHistoryAlloc_p.

    Is there another way to share addresses between SPIN and PASM? All the PASM examples I have seen do it more or less like that.

  • I should add that ShiftSpinHistory works correctly in that all 32 longs get shifted and the guard value $beefdead at the end is not touched. The point of *pTagHistoryAlloc_p in ft2 would be to shift only the currently allocated array cells, so I can inspect the data later to see status when the resource was consumed. That means an awful lot of things have already come together. It's just "rdlong ft2,ft3" messing up. I'm hoping someone will explain a condition where you can only rdlong so many times in a row or something. Although I added NOPs and they did not help.

  • Hi Larry,
    I have to admit, that I do not understand, what your code is doing. And that I did not invest too much time.
    As I never have heard, that rdlong does not work, I would search in other directions. Like silly things, which have happend to silly me.

    • Wrong file compiled, wrong includes or something like it.
    • Double code within long source file.
    • Timing issues: Dump shows data from other time.
    • rdlong from non-aligned address.
    • source and destination switched.
      I would try to go back to a simpler more direct way for debugging. For example load a 9bit constant into a register and wrlong this value to a known fixed destination. And I would try a second set of hardware...
      Good luck.
  • Thanks for trying, Christof.

  • Christof Eb.Christof Eb. Posts: 520
    edited 2021-09-15 08:27

    Hi, I seem to remember, that there was some issue with "FIT" at some time. So does your code reach $1F0 in cog ram?

  • Larry MartinLarry Martin Posts: 60
    edited 2021-09-16 20:26

    In the debug screenshot, the last line, commented, is "__testmem res 5". If I uncomment that, compile works. if I change 5 to 6, compile fails. I think that means that the DAT section is 5 longs smaller than $1F0. I moved the FT* variables further up and it did not help.

  • Larry MartinLarry Martin Posts: 60
    edited 2021-09-16 20:52

    I commented FIT and it did not help.

    This is what It's doing today:

    000060E8  00 0C 0C 0C 0C 0C 0C 00  00 00 00 00 00 00 00 00      ........ ........
    000060F8  00 00 00 00 00 00 00 00  00 00 00 00 00 0C 00 00      ........ ........
    00006108  00 00      ..
    00006454  80 4D 00 00 AD DE EF BE  E8 60 00 00 0C 0C 0C 0C      .M...... .`......

    I changed the PASM code to look at an array of ID lengths rather than the old bitmap, which expresses the nonzero lengths in the same array. My code captures several views of the data as it comes in, to save time when reporting (up to 33 times/sec: right now the system is running around half speed to allow time for debug prints). Note the pattern at the end of $6454. That is the result of "rdlong ft2,ft3" written to ft4. It is 4 bytes of $0C in a row. That can happen if my read from $60e8 really read from $60EA (or $60E9 or $60EB). I can't think of other memory in my application that would have that pattern. The book says that the address for rdlong is always rounded for you. The "E8 60 00 00" on line $6454 is the value of FT3, showing the correct address. So what can make rdlong "miss its target"?

    Should I replace the propeller 1 chip?

  • Just a general observation after more than 50 years experience: it's virtually never the hardware.


  • ersmithersmith Posts: 5,034

    @"Phil Pilgrim (PhiPi)" said:
    Just a general observation after more than 50 years experience: it's virtually never the hardware.


    I'll second Phil's observation. Some general things to watch for:

    (1) Using "res" is a bit risky, it creates uninitialized variables and is also a trap if you happen to put anything after it. Try changing "res 5" to "long 0[5]", at least until everything is debugged.

    (2) On the P1, rdlong expects a long address. If the lower 2 bits of the address are not 0, they'll be forced to 0.

    (3) Look carefully in the assembly code for missing "#" (especially on jumps, but sometimes on "mov" and other instructions). Also check all "cmp" instructions to make sure they set the flags. flexspin will help with detecting some of these kinds of bugs, but not all.

  • msrobotsmsrobots Posts: 3,459

    there is a Propeller Simulator named GEARS (written in C#) maybe you can try this one to single step your program.

    Else I think @Cluso99 wrote a simple debugger for PASM.

    sorry, have no links,


  • Thanks for all the suggestions, folks. I am going on travel tomorrow morning and will not be able to try anything for a week.

Sign In or Register to comment.