Shop OBEX P1 Docs P2 Docs Learn Events
PASM question — Parallax Forums

PASM question

Bobb FwedBobb Fwed Posts: 1,119
edited 2009-07-06 13:36 in Propeller 1
I want to do this:
  REPEAT idx FROM 0 TO 10
    long[noparse][[/noparse]block + idx] := 5




I want to do that (or similar) in PASM
example (probably wrong -- but it is what I was trying to do):
entry
                        MOV     idx, #10                ' set index to 10
                        MOV     ptr, #0                 ' set pointer to 0
:set_five               
                        MOV     block+ptr, #5           ' set block values to 5    
                        ADD     ptr, #4                 ' move pointer one long                                            
                        DJNZ    idx, #:set_five
                        
idx                     RES
ptr                     RES
block                   RES     10




Is the plus (+) symbol the correct thing to use? Is there a better/correct way to address a block? The plus symbol seems to be doing something...but I don't know if it is the correct something.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
April, 2008: when I discovered the answers to all my micro-computational-botherations!

Comments

  • RaymanRayman Posts: 14,844
    edited 2009-07-01 00:21
    This is one of the main limitations with PASM! You need self-modifying code to do something like that... But, it's not too hard.
    First, define a destination increment. I think it's:

    dlsb long 1<<9

    Then, before the loop do:

    movd :Set_Five #block
    nop

    Then after the mov, do:
    add :Set_Five dlsb

    I think this is right, but I'm really tired!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    My Prop Info&Apps: ·http://www.rayslogic.com/propeller/propeller.htm
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-07-01 05:59
    entry
                            MOV     idx, #10                ' set index to 10
                            MOV     ptr, #0                 ' set pointer to 0
    :set_five               
                            MOV     block+ptr, #5           ' set block values to 5    
                            [color=red]ADD     ptr, #4                 ' move pointer one long[/color]                                            
                            DJNZ    idx, #:set_five
                            
    idx                     RES
    ptr                     RES
    block                   RES     10
    

    You are aware that your SPIN-code works in HUB-RAM whereas the PASM-code you provided works in COG-RAM? So, to do exactly the same you would have to use the wrlong instruction.·Just·wanted to·point it out.
    So, assuming you know that:
    Add #4 in COG-RAM context is wrong. In COG-RAM the memory has long-adresses. In HUB-RAM the memory has byte adresses. So, in HUB-RAM you have to add by 4 if you want the next long, in COG-RAM you have to add 1!
    entry
                            MOVD    :set_five, #buffer      ' set destination of MOV to buffer (this is only needed if you might execute this code
                                                            ' more than once - if not :set_five destination is already initialized correctly)
                            MOV     idx, #10                ' set index to 10 AND DO IT AFTER MOVD!!! You need at least one instruction
                                                            ' between the modifying and the modified instruction. Otherwise the pipeline
                                                            ' already contains the unmodified instruction.
    
     
    :set_five               
                            MOV     block, #5               ' set block values to 5    
                            ADD     :set_five, dest_add_by1 ' move destination (which is inside of the mov instruction) to the next long
                            DJNZ    idx, #:set_five
    
     
    dest_add_by1            long    1<<9                        
    idx                     RES
    block                   RES     10
     
    For your understanding:
    An instruction looks like that, where c is the instruction opcode, d is the destination and s is the source
    %ccccccccccccccdddddddddsssssssss
    dest_add_by1 looks like that
    %00000000000000000000001000000000
    So, adding dest_add_by1 to the instruction stored in :set_five means to add 1 to the destination adress.
    

    ·
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2009-07-01 20:57
    Thanks. I understood the concept (of most of it anyway)...just the execution was escaping me. Thanks!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    April, 2008: when I discovered the answers to all my micro-computational-botherations!
  • Bobb FwedBobb Fwed Posts: 1,119
    edited 2009-07-02 15:17
    MagIO2 said...
                            MOVD    :set_five, #buffer      ' set destination of MOV to buffer (this is only needed if you might execute this code
                                                            ' more than once - if not :set_five destination is already initialized correctly) 
    
    

    Where did buffer come from? Is #buffer supposed to be equal to 0 (that's what it would be if I just add that register to the list), or is it supposed to actually be #block (that'd be my guess).
    I will probably have figured it out by trying (right now) before you are able to reply.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    April, 2008: when I discovered the answers to all my micro-computational-botherations!
  • MagIO2MagIO2 Posts: 2,243
    edited 2009-07-02 18:11
    sorry, not buffer, that's of course your block.
  • ericballericball Posts: 774
    edited 2009-07-06 01:01
    Assuming block[noparse]/noparse is in HUB RAM, your code would look something like this:
      block_addr = @block
      coginit( @cogstart, @parvalue ) 
                MOV     idx, #11
                MOV     ptr, block_addr
    :loop       WRLONG  five, ptr
                ADD     ptr, #4
                DJNZ    idx, #:loop
    block_addr  LONG    0
    five        LONG    5
    idx         RES     1
    ptr         RES     1
    
    

    The first part is SPIN code to write the address of block[noparse][[/noparse]0] to the data which gets copied to HUB RAM.· This could also be done via coginit( @cogstart, @block), or by some kind of parameter block which gets passed by address via coginit.· This way is easy, but requires caution if you have multiple cogs/objects which may be setting the variable at the same time.

    Next, the PASM code sets the idx (really a counter) to 11 since your REPEAT was 0 TO 10 which is 11 values.· Remember that DJNZ falls through when the counter is decremented to zero.· Also remember that DJNZ is a down counter if you are using it directly.· PTR is then set to the address of block[noparse][[/noparse]0]·and WRLONG is the equivalent of long[noparse][[/noparse]ptr] := 5.· Then PTR is advanced to the next long and the loop repeated.

    Now, if block[noparse]/noparse is stored in COG RAM then the instructions are completely different.
           MOVD  :loop, #block
           MOV   idx, #11
    :loop  MOV   block+0, #5
           ADD   :loop, d1
           DJNZ  idx, #:loop 
    d1     LONG  1<<9
    idx    RES   1
    block  RES   11
    
    

    The important instruction is :loop which writes the value 5 to register #block+0.· The +0 is there to remind me the value is changed.· Everything in PASM is evaluated at compile time to static values.· So MOV block+idx, #5 will be compiled to·"write value·5 to·register·#(register #block·+ register #idx)" which will write 5 to someplace in COG RAM.· But this is why PASM has instructions like MOVD.

    Okay, so now start at the top.· MOVD·writes the register # for block·into the destination register of :loop.· Because the Propeller is lightly pipelined this needs to be done at least 2 instructions before the instruction modified.· The MOV idx, #11·provides the necessary·pipeline gap.· The next MOV writes the desired value, the ADD advances the destination register of :loop and then the DJNZ completes the loop (and adds the necessary pipeline delay).


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Composite NTSC sprite driver: http://forums.parallax.com/showthread.php?p=800114
    NTSC & PAL templates: http://forums.parallax.com/showthread.php?p=803904
  • ericballericball Posts: 774
    edited 2009-07-06 13:36
    I just realized you have a bug in your SPIN code.
    REPEAT idx FROM 0 TO 10
        long[noparse][[/noparse]block + idx] := 5
    
    

    That doesn't make sense as LONG[noparse][[/noparse]BaseAddress] expects BaseAddress to be long aligned, but your REPEAT is (implicitly) STEP 1.· What you probably wanted is
    REPEAT idx FROM 0 TO 10
        long[noparse][[/noparse]block][noparse][[/noparse]idx] := 5
    
    

    So block is the BaseAddress of a set of 11 longs.· If block is a VAR or DAT array, then you want
    REPEAT idx FROM 0 TO 10
        long[noparse][[/noparse]@block][noparse][[/noparse]idx] := 5
    
    
    

    Note: my code assumes this last case.· If the second case is true then replace "block_addr = @block" with "block_addr = block" in the HUB RAM code and "MOVD· :loop, #block" with "MOVD· :loop, block" in the COG RAM code.


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Composite NTSC sprite driver: http://forums.parallax.com/showthread.php?p=800114
    NTSC & PAL templates: http://forums.parallax.com/showthread.php?p=803904
Sign In or Register to comment.