Shop Learn
Pnut arrays? — Parallax Forums

Pnut arrays?

I'm trying to re-write a program to take advantage of the P2 block moves instead of just moving individual values into and out of Hub ram.

However... I can't figure out how to manipulate values indexed from a start location with Pnut.

I can reserve blocks of cog memory with RES for instance:
VALSX res 8 ( which I THINK reserves 8 longs in memory)

but I've tried various combinations of VALSX[1], VALSX+1, @VALS etc and haven't managed to make it work. Is there an example of how to access a value indexed from a starting cog memory location?


  • I am not sure what you are asking for I need some clarification

    you have code in a cog needing indexed access into a HUB array or indexed access into a COGram array or indexed access into the LUTram

    because all work different

    more input,

  • ElectrodudeElectrodude Posts: 1,438
    edited 2019-02-14 21:53
    Your declaration to reserve 8 longs is correct. Use alts/altd/altr to access a cogram array. Those three instructions modify the next instruction by replacing its s field, replacing its d field, or redirecting its result, respectively. For example, if you wanted to do x += valsx[index], you'd do this:
    alts    index, #valsx ' replace next instruction's S field with valsx+index
    add     x,     $-$    ' turns into add x, {substituted valsx+index from previous instruction}
    The $-$ (or 0-0) is a conspicuous placeholder value that's often used to denote fields that get replaced by alt[sdr] or by self-modifying code.
  • Hi Mike,

    I need to move data in blocks, first from Hub memory to CogA's ram memory ( blocks of about 25 variables. Let's say they are going from hub ram locations 5000 - 5024 to CogA ram locations 475-499 )

    I'm currently doing this with individual RDLONG instructions into individual variables but I know I'm wasting a lot of program space.

    I do calculations on that data then move the "Answers" into 20 variables in the shared LUT and set a LUT "flag" that triggers CogB into action.

    CogB loads those 20 variables from the shared LUT into it's RAM using individual RDLUT instructions then uses those variables to do its operation. When done, CogB puts the resulting data back into another location in the LUT which CogA uses for feedback on it's next setup for CogB.

    This is what I'm doing now: setting up pointers, moving the data individually, then using those values in my control routine. What I'd LIKE to do is have my variables moved into memory in a block, then only change a base pointer to the data for the next operation. This would let me "Hot Swap" data eliminating the several microsecond delays I have now from one operation to the next.
                             ' first set up pointers to all the input data                      
            MOV	spd_ptr,   	##3010          '  spd_ptr points to the current speed value variable.  Hub data > Speed
            mov	maxspd_ptr,	##3014
    	mov minspd_ptr,	##3018
            mov ramp1steps_ptr,         ##3022
            mov ramp1rate_ptr, 	  ##3026
            mov ramp2steps_ptr,         ##3022
            mov ramp2rate_ptr, 	  ##3026
            mov ramp5steps_ptr,         ##3054
            mov ramp5rate_ptr, 	  ##3058
            mov ramp6steps_ptr,         ##3062
            mov ramp6rate_ptr, 	  ##3066
                           ' now load the data pointed to by the pointers
          rdlong speed,          spd_ptr 
          rdlong maxspeed,   maxspd_ptr

    Doing this same thing in a block move should save time and memory

    To USE that data, In spin, it would just be something like:
    Pub Doit 
       VALS[1] - VALS[6] := Xsteps 
       VALS[2] - VALS[7] := Ysteps 
       VALS[3] - VALS[8] := Zsteps 

    I'm not sure how to index from the start of the block (VALS[0] +1, +5, etc. ) in P2 assembly to use the values in the other variables.

    I just saw your info Electrodude, I'll see if I can decipher how to use it to do what I need. Thanks!

    ( but if you know of any sample code that does some of the things I mentioned, I'd love to see some working examples)

  • msrobotsmsrobots Posts: 3,324
    edited 2019-02-15 09:18
    I do not really get what VALS[1] - VALS[6] := Xsteps should do, but if you want to read a block of hubmemory into a block of COG memory you can do funny things with PTRA

                    mov PTRA, ##3010          '  spd_ptr points to the current speed value variable.  Hub data > Speed
                    rdlong speed, PTRA++
                    rdlong maxspeed, PTRA++

    there is also another way I havn't tested yet, but it is from @Cluso99 so it will probably work
                    mov PTRA, ##3010          '  spd_ptr points to the current speed value variable.  Hub data > Speed
                    setq    #numbers of longs -1
                    rdlong  speed, PTRA

    It looks like you are wasting a lot of code space...


  • Cluso99Cluso99 Posts: 17,472
    Instead of
    MOV PTRA,##$3010 (missing $)
    LOC PTRA,#$3010
    as it saves an instruction, and that's what LOC is for.
  • aah, cool, no AUGS, havn't thought of that.



  • I managed to get a program indexing to data in an array using the alts instruction. I thought I was good to go when I tried to comment out some unused code at the end of the program. When I did this, the program stopped working correctly. ( unusual delays got added to the operation ) Also, if I comment out the unused MOV loopcnt, #0 in line 76, the operation changes also.

    I have tried this same program compiled with Pnut AND the spin2 compiler. I have tried it running in cog 0 and
    ( as here ) running it from an initializing cog. All work the same. I suspect the problem is my understanding of the ALTS instruction, but for the life of me, I don't understand why commenting out unused code would change the functionality of the "Running" code. Can anyone spot what I'm missing? I'd like to post (correctly working ) code as an example of how to use ALTS Base + index but it's obvious I'm missing something. Any clues what?

    ( the program blinks LEDs on the P2-EV board according to a group of variables with the LED port addresses in them )
        This is a sample program using  the "alts" instruction to index to data in an array 
        or  a variable indexed in a sequential group of variables. 
        A pointer called "PBASE"  points to the start of the memory where you want to pull variables from 
        PBASE is initialized by moving the address of the first value into it using: " MOV PBASE, #V "
           (V being a variable name at the start of the block of data to be indexed into. 
        an index value called "INDX" is added to the PBASE location to let you pull values 
        There is an oddity that I haven't been able to fix or understand: When you comment out the (unused) movedatain function, 
        the overall operation changes.  
      Ken B
      _XTALFREQ     = 20_000_000                                    ' crystal frequency
      _XDIV         = 4             '\                              '\ crystal divider                      to give 5.0MHz
      _XMUL         = 72            '| 180MHz                       '| crystal / div * mul                  to give 360MHz
      _XDIVP        = 2             '/                              '/ crystal / div * mul /divp            to give 180MHz
      _XOSC         = %01                                   'OSC    ' %00=OFF, %01=OSC, %10=15pF, %11=30pF
      _XSEL         = %11                                   'XI+PLL ' %00=rcfast(20+MHz), %01=rcslow(~20KHz), %10=XI(5ms), %11=XI+PLL(10ms)
      _XPPPP        = ((_XDIVP>>1) + 15) & $F                       ' 1->15, 2->0, 4->1, 6->2...30->14
      _CLOCKFREQ    = _XTALFREQ / _XDIV * _XMUL / _XDIVP            ' internal clock frequency                
      _SETFREQ      = 1<<24 + (_XDIV-1)<<18 + (_XMUL-1)<<8 + _XPPPP<<4 + _XOSC<<2  ' %0000_000e_dddddd_mmmmmmmmmm_pppp_cc_00  ' setup  oscillator
      _ENAFREQ      = _SETFREQ + _XSEL                  
              org 0
    '+-------[ Set Xtal ]----------------------------------------------------------+ 
    entry           hubset  #0                              ' set 20MHz+ mode
                    hubset  ##_SETFREQ                      ' setup oscillator
                    waitx   ##20_000_000/100                ' ~10ms
                    hubset  ##_ENAFREQ                      ' enable oscillator
                    waitx   ##_clockfreq*5                  ' just a delay to get pc terminal running
      coginit   cognum1, #@blinkrun  ' init  cog1 for the movement function
                    cogstop #0                 ' terminate the startup cog. 
      cognum1 long 2
             ORG 0
                    drvh #60
                    drvh #61          ' TURN OFF THE TWO LED'S THAT TEND TO STAY HIGH FOR A WHILE  
                    MOV P1, #56
                    MOV P2, #57
                    MOV P3, #58
                    MOV P4, #59
                    MOV P5, #60
                    MOV P6, #61
                    MOV P7, #62
                    MOV P8, #63
                    '*** note, these above variables must be defined sequentially ( AT THE END OF THE CODE ) for the lookup to work correctly
                    ' Set up your memory pointers:
                    MOV INDX, #0 
                    MOV PBASE, #p1   ' this sets the base address to the address of p1  
                    ' Set up your counters :
                    MOV blinkcount, #3    ' do the main loop 3 times 
                    MOV loopcnt, #0       ' used to index the data to another position. 
    '   drvnot #63          ' TOGGLE THE P63 LED  (just to show the loop is working)  
                    MOV INDX, #0        ' set the base +pointer to zero each time through the loop 
        ' blink the first LED pointed to:
                    alts    PBASE,  INDX    ' replace next instruction S field with PBASE+index 
                    mov      pt,    $       ' $ is replaced with the value pointed to by PBASE + index  in this case p1 which is set to #57
                    drvl pt                 ' turn the LED on. 
                    waitx waitime           '   pause for a while
                    drvh  pt                ' now turn the LED off
                    waitx waitime           ' and wait again.  
                              ' now point to the next port location and do the same thing 
        ' blink the second LED pointed to:
                    add INDX, #1        ' incriment the index pointer to point to the value in p2 
                    alts    PBASE,  INDX    ' replace next instruction source field with valsx+index 
                    mov      pt,    $        
                    drvl pt         ' LED on             
                    waitx waitime
                    drvh  pt       ' LED off            
                    waitx waitime        
                              '  point to the next port location and do the same thing 
                              ' blink the third LED pointed to:
                    add INDX, #1        ' incriment the index pointer to point to the value in p3             
                    alts    PBASE,  INDX    ' replace next instructions S field with valsx+index 
                    mov      pt,    $        
                    drvl pt         ' LED on                             
                    waitx waitime                     
                    drvh  pt        ' LED off                            
                    waitx waitime        
                    sub blinkcount, #1          ' subtract 1 from the blinkcount counter
                    cmp blinkcount, #0 wcz      ' see if you're at zero yet
                 IF_NE  jmp #blinkitloop        ' if you ARE NOT at zero, jump back to the start of the 3 led blink function again.
                    ' otherwise pause a moment ane reset the blinkcount counter
                  ' waitx ## 50000000          
                    mov blinkcount, #4     ' this dertermines how many times the inner 3 led blink function loops 
                    add pbase, #1
                    cmp pbase, #61 wcz
              if_a jmp #blinkitstart       ' if you're above port 61 restart everything again
                    jmp #blinkitloop       ' otherwise do the loop again
           cogstop #2                 ' terminate the cog if you get this far    . 
             ' none of the following code  SHOULD make any difference to  the program operation, but it does.  
             ' { '  if you remove the  ' to comment out this line and the one in front of the pairing bracket, the program works oddly . 
       add loopcnt, #1
       cmp loopcnt, #8 wcz
       IF_b jmp #setnext        ' if the loopcnt is < 4, index to the next value group
        ' otherwise, 
        jmp #blinkitstart        ' to reset everything
           mov pbase, #p2
    ' drvnot #62
        mov loopcnt, #9
        add pbase, #1          ' otherwise, incriment the base of the pointer and do the loop again. 
       jmp #blinkitloop 
       ' }  ' other bracket to remove 
     waitime  long 10000000 
    pt long  0
    PBASE long 0
    INDX long 0
    p1 long 0
    p2 long 0
    p3 long 0 
    p4 long 0
    p5 long 0
    p6 long 0 
    p7 long 0
    p8 long 0 
    p9 long 0
    p10 long 0
    p11 long 0
    blinkcount long 0
    loopcnt    long 0
  • This line:
                    cmp pbase, #61 wcz
    looks wrong, because "pbase" is a pointer (initialized to #p1). Probably you should compare to #p8 or something like that instead of #61?
  • Thanks ersmith ! I knew it was something like that but I was just wasn't seeing it.

    It's been years (decades) since I've done pointers in Assembly. I'm trying to get the hang of the P2's instruction set before I start working with the P2 in Spin or C++.

    With minimal documentation ( that I know is being diligently worked on ) and new tools, some of this doesn't click the first time through my brain.
Sign In or Register to comment.