Shop OBEX P1 Docs P2 Docs Learn Events
Stumped by instruction in PASM — Parallax Forums

Stumped by instruction in PASM

AGCBAGCB Posts: 327
edited 2014-12-11 17:13 in Propeller 1
I'm learning PASM, tables at the moment and came across this instruction in a tutorial

MOV data, 0-0

I've searched all the normal documents but haven't been able to figure this out (the 0-0 part). Help needed!

Thanks
Aaron

Comments

  • SapphireSapphire Posts: 496
    edited 2014-12-09 14:38
    The 0-0 part is just a placeholder for the compiler. PASM is uses self-modifying code, and elsewhere in the program is an instruction to modify this one and put a "real" value in the source field. That "real" value probably changes during execution, which is why it can't be coded directly here.
  • AGCBAGCB Posts: 327
    edited 2014-12-09 14:43
    Thanks Sapphire

    With that info I'll study some more. May be back w/ another ?

    Aaron
  • kwinnkwinn Posts: 8,697
    edited 2014-12-09 15:07
    AGCB wrote: »
    Thanks Sapphire

    With that info I'll study some more. May be back w/ another ?

    Aaron

    Just to be 100% clear, you don't need to use 0-0 in the address that will be modified by the program. When the program is assembled/compiled that probably ends up being an address of 0 initially, and gets changed to another address before the instruction is executed. It is used so it is apparent when looking at the source code that the address for this instruction is modified by the program.
  • mmowenmmowen Posts: 38
    edited 2014-12-09 15:24
    kwinn wrote: »
    Just to be 100% clear, you don't need to use 0-0 in the address that will be modified by the program. When the program is assembled/compiled that probably ends up being an address of 0 initially, and gets changed to another address before the instruction is executed. It is used so it is apparent when looking at the source code that the address for this instruction is modified by the program.

    100% correct. It is worth mentioning that two instructions are designed for the purpose of modifying another instruction's destination and source fields: MOVD and MOVS respectively; although you can also do things like ADD, OR, XOR, etc given a suitable mask for your purpose.
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-12-09 15:58
    Cog Code is running from RAM (not flash etc) so you can change any code or value as you want , but due to pipeline-technics just not the next one in front of you.

    What the complier puts there is 0, as it actual do the math on zero-minus-zero
    That codes run in ram allows you to self-modify it on the fly, you will need to know the address of it so you put a label in front of it (maybe already be one there for other loop purposes)

    Adding and Subtraction can be done, and for D field you use ±1<<9 and it kind of auto-mask as you will not get overflow as you would normally never have values+values that would point outside 512 longs anyway..
    Doing a reset of values have to be done with MOVS and MOVD (MOVI is not used often)

    Why not put the first real value there instead of 0-0?
    Self-modifying code is mostly inside a loop that is used many times so you have to reset it anyway and do it before the loop and not after it, so give yourself a visual cue with this 0-0 placecard
  • AGCBAGCB Posts: 327
    edited 2014-12-09 17:07
    As I said in post #1, I'm trying to learn PASM. I'm starting to get it
    tonyp12 wrote: »
    you will need to know the address of it so you put a label in front of it (maybe already be one there for other loop purposes)

    Like this?
                  movs   :inline,data    ' have to use instruction modification
                  nop                    ' need pause here for pipelining
               
    :inline    mov    data,  0-0
    

    I searched to find where I got this tutorial. It was from an old forum thread (2006) and a post by Mike Green #19. I've included it here

    {'' Here's a simple example of table lookup in assembly.
    '' This particular example takes a table index in "ptr"
    '' and sets the "data" to the word value from the table.
    '' There's no range checking. If you want long values,
    '' just eliminate the shifts and masks (*). You can use
    '' the same kind of logic for byte values.
    DAT
                org   0
    test      mov   ptr,#2        ' for an example, get third value
                call  #look            ' note table indices are 0 to n-1
    :stop     jmp   #:stop        ' no checking for out of range
    
    look         mov    data,ptr      ' ptr is a table index (0 to n-1)
                  shr   data,#1       ' divide input value by 2 to get (*)
                  add    data,#table    '   long word index, add table address
                  movs   :inline,data   ' have to use instruction modification
                  nop                        ' need pause here for pipelining
    :inline    mov    data,0-0         ' get long value from table
                  test   ptr,#1   wz     ' do we want odd or even half  (*)
        if_z     and    data,mask       ' if even, take lower 16 bits (*)
        if_nz   shr    data,#16         ' if odd, take upper 16 bits  (*)
    look_ret   ret
    table       word    $0000
                  word    $C0C1
                  word    $C181
                  word    $0140
                  word    $C301
                  word    $03C0
                  word    $0280
    mask        long   $FFFF
    data        res     1
    ptr          res     1
    

    I tried to put it in a complete program, had to change it slightly to compile. But all I get is $0000 on the display. Here is my code
    CON 
            _clkmode        = xtal1 + pll16x
            _xinfreq        = 5_000_000
    
    OBJ
      tv  :  "tv_text"
    
    VAR
      long  _data
    PUB  go   
      tv.start(0)
      tv.str(string($A,1,$B,1))
      tv.hex(_data,4)
      cognew(@test1,@_data)
    DAT
               org     0
    test1      
               rdlong  p,     par    'get hub address into p
               mov     ptr,   #2     ' for an example, get third value
               call    #look         ' note table indices are 0 to n-1'
    ':stop      jmp     #:stop        ' no checking for out of range
               wrlong  data,  par
               jmp     test1
    look       mov     data,  ptr     ' ptr is a table index (0 to n-1)
               shr     data,#1        ' divide input value by 2 to get (*)
               add     data,  #table  '   long word index, add table address
               movs   :inline,data    ' have to use instruction modification
               nop                    ' need pause here for pipelining
               
    :inline    mov    data,  0-0      ' get long value from table
               test   ptr,#1   wz     ' do we want odd or even half  (*)
      if_z     and    data,mask       ' if even, take lower 16 bits (*)  '
      if_nz    shr    data,#16        ' if odd, take upper 16 bits  (*)
              
               
    look_ret   ret
    
    table         long    $0000
                  long    $C0C1
                  long    $C181
                  long    $0140
                  long    $C301
                  long    $03C0
                  long    $0280
    mask          word    $FFFF
    data          res     1
    ptr           res     1
    p             res     1
    

    A little more help is appreciated.
    Aaron
  • AGCBAGCB Posts: 327
    edited 2014-12-09 17:10
    As I look over my post I see that I need to repeat the TV display part. Might that be the only bug??

    edit; NOPE!
  • Cluso99Cluso99 Posts: 18,069
    edited 2014-12-09 21:39
    The
    movs :inline,data
    nop
    :inline mov data,0-0
    will become
    :inline mov data,data

    So you will be actually moving the value at data to data, which does nothing.
    What you most likely are after is
    movs :inline,#data
    nop
    :inline mov data,0-0
    which becomes
    :inline mov data,#data
    which moves the address of data into data. Normally they would be different labels.

    Hope this helps.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-12-09 21:49
    Um, no. The # bit lies outside of the source field and is not affected by a MOVS instruction.

    -Phil
  • kuronekokuroneko Posts: 3,623
    edited 2014-12-09 22:42
    AGCB wrote: »
    A little more help is appreciated.
    Works for me. Displaying _data repeatedly gives me $C0C1 (the third word in your long table). What doesn't matter right now but will bite you later is the jmp test1 which should be a jmp #test1.
  • AGCBAGCB Posts: 327
    edited 2014-12-10 04:43
    Thanks for looking at this. I got the single table entry to display any one I want. Then I wrote a program to cycle through the entries in sequence and start over. It displays all entries the 1st time through but after that skips the 1st one. I've tried all kinds of ways to correct it to no avail.
    CON 
            _clkmode        = xtal1 + pll16x
            _xinfreq        = 5_000_000
    
    OBJ
      tv  :  "tv_text"
    
    VAR
      long  _data
    PUB  go   
      tv.start(0)
      cognew(@test1,@_data)
      repeat
        tv.str(string($A,1,$B,1))
        tv.hex(_data,4)
      
    DAT
              org     0
    test1     mov       p2,       #0    'initialize pointer counter
              mov       t,        cnt      'set up delay
              add       t,        #9          '  "
    :loop     waitcnt   t,        delay     
               
               mov     ptr,   p2        ' 
               add     p2,    #1      ' note table indices are 0 to n-1
               call    #look            
    
               'add     p2,    #1
               test    p2,    #6  wz    'done w/ all table entries?
      if_z     mov     p2,    #1      'start over
               jmp     #:loop
    look       mov     data,  ptr      ' ptr is a table index (0 to n-1)
               'shr    data,#1       ' divide input value by 2 to get (*)
               add     data,  #table    '   long word index, add table address
               movs   :inline,data   ' move data to source field at :inline
               nop                        ' need pause here for pipelining
               
    :inline    mov     data,  0-0         ' get long value from table
              ' test   ptr,#1   wz     ' do we want odd or even half  (*)
      'if_z     and    data,mask       ' if even, take lower 16 bits (*)
      'if_nz    shr    data,#16         ' if odd, take upper 16 bits  (*)
               
               wrlong  data,  par
    look_ret   ret
    
    table         long    $0001     ' !!!! can't seem to read this entry   !!!!
                  long    $C0C1                         '  after 1st time
                  long    $C181
                  long    $0140
                  long    $C301
                  long    $03C0
                  long    $0280
                  long    $0007
    'mask          long    $FFFF
    delay         long            160_000_000
    data          res     1
    ptr           res     1
    p2            res     1    'for cycling through table
    t             res     1    'for waitcnt inst
    

    Thanks
    Aaron
  • kuronekokuroneko Posts: 3,623
    edited 2014-12-10 05:00
    if_z     mov     p2,    [color="red"]#1[/color]      'start over
    
    Does that ring a bell? Also. I wouldn't use test for the range check but some form of cmp, e.g. (incomplete)
    mov     ptr, p2
            call    #look
            add     p2, #1
            cmpsub  p2, #number_of_table_entries
            jmp     #:loop
    
  • AGCBAGCB Posts: 327
    edited 2014-12-10 05:42
    kuroneko

    If I put a 0 in there the code hangs up and stops working
  • kuronekokuroneko Posts: 3,623
    edited 2014-12-10 06:12
    AGCB wrote: »
    If I put a 0 in there the code hangs up and stops working
    Yes, I know. Your test instruction effectively does an AND and sets the relevant flags (zero in your case). So you start with 0, increment p2 (now 1) and do an AND 6 (%001 & %110) which is 0 (zero set). IOW you keep reloading p2 with 0. Just try the example I mentioned earlier (using cmpsub). The way it works is that - assuming 10 entries - you start with 0 and keep incrementing p2. From 0 to 9 cmpsub #10 is a nop, for 10 we get destination => source which means destination is decremented by source, i.e. 10-10 = 0 (wrap). HTH
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-12-10 06:24
    This particular item comes up from time to time.

    And it has been one reason that I've been a bit shy of Spin PASM from the start.

    It would be wonderful it a white paper was available. Or is this already mentioned somewhere in the PASM documents out there?

    ah... Page 3 of this ===> forums.parallax.com/attachment.php?attachmentid=49618
    (It is the Parallax Propeller Tips & Traps.pdf)
  • AGCBAGCB Posts: 327
    edited 2014-12-10 10:34
    Thanks again kuroneko.

    I was just headed out the door and didn't have time to absorb your entire post this morning. I'll look at it in detail this evening.

    Aaron
  • Heater.Heater. Posts: 21,230
    edited 2014-12-10 13:51
    Loopy,

    Don't be so shy of PASM.

    PASM must be the simplest assembly language I have ever used. I mean how is:
        add x, y
    
    any much more difficult than:
        x := x + y
    
    On top of that, the way writing PASM is seamlessly integrated into Spin makes it really easy to get started and experiment with.

    That little quirk about using self modifying code is not so hard and perhaps not even necessary for a lot of jobs.

    PASM is fun. Jump in there.
  • tomcrawfordtomcrawford Posts: 1,126
    edited 2014-12-10 14:31
    Heater. wrote: »
    Loopy,

    That little quirk about using self modifying code is not so hard and perhaps not even necessary for a lot of jobs.

    PASM is fun. Jump in there.

    The only reason I ever need to use self modifying code (for PASM) is to access tables in cog memory. Here's hoping that Prop II will have some indexing or indirect addressing capability.
  • AGCBAGCB Posts: 327
    edited 2014-12-10 16:18
    [QUOTE=Heater
    PASM must be the simplest assembly language I have ever used[/QUOTE]

    I don't know very much but I first used PICs and taught myself asm. If you want to see involvement Check out the pdf data sheet for a PIC18F43k20 (my favorite PIC)

    I'm lov'n Propeller
  • AGCBAGCB Posts: 327
    edited 2014-12-11 05:15
    Thanks for all the replies and info. As usual I learned more that I asked for.

    Once you put together some forum posts and look at some other tutorials or whatever and then go back and read the manual "again for the very first time". It makes complete sense that you couldn't see before. Like a person born blind being told what a flower looks like. Even though the explanation is perfect, something else is needed.

    Aaron
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-12-11 17:13
    I do know that Propeller assembly is simpler than all the ISR and special register stuff that PIC or AVR devices go for. But it does take a bit of effort to absorb the rather unique approach to both the assembler and compiler.

    But I suspect the bottom line is that by understanding both alternatives, one really does master programing in a way that holding on to only one approach will never achieve.

    I've never doubted the claims that once learned, PASM is simpler than other assembly languages as the Propeller architecture is simpler to manage.
Sign In or Register to comment.