Shop OBEX P1 Docs P2 Docs Learn Events
Basic questions about PASM, round two — Parallax Forums

Basic questions about PASM, round two

Carl HayesCarl Hayes Posts: 841
edited 2009-02-12 16:21 in Propeller 1
Consider the following, abstracted from a much longer program:

CON
·_clkmode········ = xtal1 + pll16x
·_xinfreq········ = 5_000_000

PUB Main
·cognew (@Display,0)
DAT
Relbearing···· LONG········· 8
Heading······· LONG········· 7
Absbearing··· LONG········· 6

················· ORG·········· 0
Display
················· some code
···············
················· RDLONG······· DISrel,Relbearing
··············· · RDLONG······· DIShdg,Heading
················· RDLONG······· DISabs,Absbearing

················ ·more code

DISrel········· LONG········· 0··················· ' Relative bearing 0-359
DIShdg······· LONG········· 0··················· ' Vehicle heading
DISabs······· LONG········· 0··················· ' Absolute bearing

················ more stuff

The intent is that Relbearing, Heading, and Absbearing will eventually be set by another cog.

I expected that after the RDLONGs, the destination DISrel would have the contents of Relbearing, and so forth.· However, these destinations were not as expected.· Have I missed some (undocumented) requirement?

Also, I originally had WORDs and not LONGs for the source fields and used RDWORD instead of RDLONG.· I got an error message for the second one (Heading), but not for the other two, complaining that Heading was not a LONG.· I knew that; that's why I had used RDWORD instead of RDLONG.· What's going on here?
··

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
· -- Carl, nn5i@arrl.net

Post Edited (Carl Hayes) : 2/11/2009 3:36:18 AM GMT

Comments

  • potatoheadpotatohead Posts: 10,261
    edited 2009-02-11 03:40
    You've got to communicate the address of Heading, etc... to the COG.

    This is normally done via the PAR register. When you start a COG, you get to pass it one 'long aligned' value, and that value appears in COG space via the PAR register.

    Typical simple use case is to declare all your HUB variables, to be used as a parameter block, sequentially in the calling SPIN program. I like to use an array, just because.

    In your case, the order is fine, just use it as is. The key here is that your HUB values exist in HUB address space, and that address isn't yet known, or communicated to the COG.

    You do that, via the PAR register, in your COGNEW thus:

    cognew(@display, @Relbearing)

    The first arg for the cognew is the location of the start of the COG assembly code. The second is an address for a block of memory to be used for passing values. There are other uses for the PAR register, but that's the most common.

    In your assembly language program, you then fetch those HUB values into the COG.

    Here's one way to do it:


    
    CON
     _clkmode         = xtal1 + pll16x
     _xinfreq         = 5_000_000
     
    PUB Main
     cognew (@Display,@Hub_Value1)
    
    DAT
    HUB_Value1       LONG          8
    HUB_Value2       LONG          7
    HUB_Value3      LONG          6
    
    'I'll often use more than one DAT to differentiate between different uses of the DAT storage area
    
    DAT
                            org 0
    
    display                 mov     temp, PAR               'Fetch address of HUB data
                         rdlong   value1, TEMP              'First address points to first value
                            add     TEMP, #4                'index to next long
                         rdlong   value2, TEMP              'Fetch second value
                            add     TEMP, #4                'index to next long
                         rdlong   value3, TEMP              'Fetch third value
    
    
    value1                  long    0              'COG storage
    value2                  long    0
    value3                  long    0
    
    TEMP                    long    0              'A working long
    
    
    



    When working in HUB address space, be sure and remember to add the right index; namely, 1, 2 or 4, depending on whether it's a byte, word or long. This gets me quite often, as I'll be thinking in COG space, and only add 1 for a long, when it should have been 4.

    TEMP is your index register for the duration of the fetching to be done, then can be used for other things as you see fit!

    In the SPIN portion, you can also just declare the variables and work that way too. I use arrays because the sequence and type are always consistent, as arrays are atomic.

    That could be then:

    Hub_Values

    HUB_Values := something

    etc...

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
    Safety Tip: Life is as good as YOU think it is!

    Post Edited (potatohead) : 2/11/2009 4:02:56 AM GMT

  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-11 03:59
    Good Lord, that's clumsy. I'll try it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net
  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-11 04:23
    Thanks, P'head -- that worked.· However, every assembler I've used before had a way to have the assembler compute those displacements automatically.· I coded #0, #4, and #8 for the displacements, but surely there's a way for the assembler to calculate those.

    In any other assembler, if I want the displacment (difference in address) between two locations A and B, I code (B-A) where here I coded #0 or #4 or #8.· Is there a way to do that with·this assembler?· It would be a drag to go back and recompute ever-so-many manually computed displacements every time I insert or remove a variable.


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net

    Post Edited (Carl Hayes) : 2/11/2009 4:40:53 AM GMT
  • potatoheadpotatohead Posts: 10,261
    edited 2009-02-11 04:40
    The problem is the address can't be an immediate value, unless you are talking about the first 9 bits of hub memory. The only option then is to use a COG long to contain the address!

    I suppose you could have the assembler add the base address, thus yielding absolute values. Still would have to pack them into a long though, so I'm not sure what, if anything you save.

    The 9 bits of immediate addressing space is a problem there. Otherwise, I'm sure it would handle something like (@HUB_Value1 + 4). This result will be more than 9 bits, unless you take care to actually locate things in the first two pages of HUB memory address space.

    There is also (@var - @another_var). I've done this to determine length of things, and have used that as an immediate address.

    Others are gonna be better at this than I currently am, so maybe they will chime in and we both learn something!

    [noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
    Safety Tip: Life is as good as YOU think it is!

    Post Edited (potatohead) : 2/11/2009 4:45:45 AM GMT
  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-11 04:44
    What I want to save is the necessity to hand-compute the displacements.· Computing displacements is the assembler's job, for it knows the address of every label in the program.· Hand-computing them·(a) is a drag, (b) is a source of needless error, and (c) would have to be redone every time I add or delete a variable.

    I'll experiment a bit.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net
  • potatoheadpotatohead Posts: 10,261
    edited 2009-02-11 05:01
    Well, there are arrays!

    They are all the same size. If you build a loop, all you really need to manage then is the number of values to be passed. Bet a clever subtract would tidy that up.

    On the SPIN side of things, the array is dead simple. Need another value? Just add an element, and off you go!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Propeller Wiki: Share the coolness!
    Chat in real time with other Propellerheads on IRC #propeller @ freenode.net
    Safety Tip: Life is as good as YOU think it is!
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-02-11 05:07
    Carl,

    There's a convenient shortcut you can use if your objective is only to transfer initial values into the cog's address space:

    [b]CON[/b]
     [b]_clkmode[/b]         = [b]xtal1[/b] + [b]pll16x[/b]
     [b]_xinfreq[/b]         = 5_000_000
     
    [b]PUB[/b] Main
      [b]longmove[/b](@value1, @HUB_Value1, 3)
      [b]cognew[/b] (@Display,0)
    
    [b]DAT[/b]
    HUB_Value1       [b]LONG[/b]          8
    HUB_Value2       [b]LONG[/b]          7
    HUB_Value3       [b]LONG[/b]          6
    
                            [b]org[/b] 0
    Display
    
    ...
    
    value1                  [b]long[/b]    0              'COG storage
    value2                  [b]long[/b]    0
    value3                  [b]long[/b]    0
    
    TEMP                    [b]long[/b]    0              'A working long
    
    
    



    or, even more simply

    [b]CON[/b]
     [b]_clkmode[/b]         = [b]xtal1[/b] + [b]pll16x[/b]
     [b]_xinfreq[/b]         = 5_000_000
     
    [b]PUB[/b] Main
     [b]cognew[/b] (@Display, 0)
    
    [b]DAT[/b]
                            [b]org[/b] 0
    
    Display
    
    ...
    
    value1                  [b]long[/b]    8             'COG storage
    value2                  [b]long[/b]    7
    value3                  [b]long[/b]    6
    
    TEMP                    [b]long[/b]    0              'A working long
    
    
    



    Also, unless you need to make sure that TEMP is initialized to zero, you can use RES for it, instead of LONG, to save hub space in your program.

    -Phil
  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-11 05:07
    Got it!

    Arrays are not the solution. I've found the solution. In the PASM program, I have now defined three longs:

    DISreloffset LONG (@Relbearing-@Sharedstuff) ' @Sharedstuff is what I passed in the parameter
    DIShdgoffset LONG (@Heading-@Sharedstuff)
    DISabsoffset LONG (@Absbearing-@Sharesstuff)

    Then, instead of #0, #4, and #8 for my offsets, I add the contents of these longs, which contain the offsets. Voila.

    It's clumsier than other assemblers, but at least the program will be maintainable.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net
  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-11 05:16
    Here's an expurgated version of what I did to solve that problem, which I could not have done without your help, Potatohead.· Thanks again.· I attach a file with just the lines I'm talking about.· It works.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net
  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-11 05:20
    Phil Pilgrim (PhiPi) said...
    Carl,

    There's a convenient shortcut you can use if your objective is only to transfer initial values into the cog's address space:
    Thanks, but I'm going to read these three values eight times per second forever.· In my immediately-preceding post I show how I solved it with Potatohead's help.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net
  • AribaAriba Posts: 2,690
    edited 2009-02-11 13:05
    You can spare 3 longs if you do it this way:
    ...
    DAT
    Sharedstuff     LONG          
    Relbearing      LONG          9
    Heading         LONG          7
    Absbearing      LONG          8
    
                    ORG           0
    Display
    '               -------------------------
    Show
    
    ' Get the relative bearing, heading, and absolute bearing
    
                    MOV           Data10,PAR
                    ADD           Data10,#(@Relbearing-@Sharedstuff)
                    RDLONG        Data10,Data10
    
                    MOV           Data11,PAR
                    ADD           Data11,#(@Heading-@Sharedstuff)
                    RDLONG        Data11,Data11
    
                    MOV           Data12,PAR
                    ADD           Data12,#(@Absbearing-@Sharedstuff)
                    RDLONG        Data12,Data12
    '               ------------------------------
                      
    DATA10          LONG          0 
    DATA11          LONG          0
    DATA12          LONG          0   
    
    


    this works as long as the offsets are not higher then 511.

    Andy
  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-11 14:25
    Thank you, Ariba. I thought I had tried that somewhere in my experiments, without success. But after your message I tried it again, and it works perfectly. My displacements will seldom or never be greater than 511.

    Your way is easier to maintain, too, which is the whole idea. Super!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net
  • heaterheater Posts: 3,370
    edited 2009-02-11 14:45
    Carl, you may want to forget about using "par" altogether. Check out Ken Peterson's post about setting parameters into a COG without par:

    http://forums.parallax.com/showthread.php?p=783988

    Doing it this way you don't have to worry about offset calculations and you don't waste any valuable LONGs in your COG fetching params from par.

    I start to wonder why we have "par" at all....

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-11 15:48
    heater said...
    Carl, you may want to forget about using "par" altogether. Check out Ken Peterson's post about setting parameters into a COG without par:

    http://forums.parallax.com/showthread.php?p=783988

    Doing it this way you don't have to worry about offset calculations and you don't waste any valuable LONGs in your COG fetching params from par.

    I start to wonder why we have "par" at all....

    Now that's neat too.· Thanks!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-02-11 18:43
    Carl.

    There's yet another way to do this. The "address plus" operator (@@) can be used with a zero argument to provide the object's base address (known only at runtime). This can be added to the offsets (known at compile time) to get the absolute argument addresses, viz:

    [b]CON[/b]
    
       [b]_clkmode[/b]       = [b]xtal1[/b] + [b]pll16x[/b]
       [b]_xinfreq[/b]       = 5_000_000
      
    
    [b]PUB[/b] Main
    
     [b]cognew[/b] (@Display, @@0)
     
    [b]DAT[/b]
    
    Display       [b]add[/b]       aRelbearing,[b]par[/b]
                  [b]add[/b]       aHeading,[b]par[/b]
                  [b]add[/b]       aAbsbearing,[b]par[/b]
    
                  '''
                  [b]rdlong[/b]    DISrel,aRelbearing
                  [b]rdlong[/b]    DIShdg,aHeading
                  [b]rdlong[/b]    DISabs,aAbsbearing 
    
                  '''
    aRelbearing   [b]long[/b]      @RelBearing
    aHeading      [b]long[/b]      @Heading
    aAbsbearing   [b]long[/b]      @Absbearing
    
    DISrel        [b]res[/b]       1                       ' Relative bearing 0-359
    DIShdg        [b]res[/b]       1                       ' Vehicle heading
    DISabs        [b]res[/b]       1                       ' Absolute bearing
    
    Relbearing    [b]long[/b]      0-0
    Heading       [b]long[/b]      0-0
    Absbearing    [b]long[/b]      0-0
    
    
    


    What results is code that may be preferred for readability, since the longs contain data with the @ notation. Also note that, typically, one must put all res pseudo-ops after any longs, but that's not necessary in this case since Relbearing, et al., do not need to exist in cog space. In fact, the way this is written, DISrel, et al., will be preinitialized with their complements in hub space, since they overlap one-for-one. Finally, it's become a convention for the Propeller that values that get filled in later be initialized with 0-0 to indicate that fact.

    -Phil
  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-11 21:41
    Thank you, Phil. I've settled upon Ariba's method, which to me seems easiest to read and maintain, being more localized.

    As for using 0-0 as a convention, it fits well with prior art -- the convention since Adam first taught Eve to program has been similar to that, usually *-* in machines in whose assembler languages "*" represents "address of this instruction". I'm going to adopt 0-0.

    And next I've got to start learning Spin, which I think will be much more difficult than PASM.· The code that fills in the heading and bearings (for DISplay to read and display on an LCD)·will run in another cog.· My display code now works as intended.· Pizza time!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net

    Post Edited (Carl Hayes) : 2/11/2009 9:48:23 PM GMT
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-02-11 21:59
    Yup, I used *-* with the IBM 1130/1800. I suppose one could use $-$ with the Propeller, but 0-0 became the de facto standard before Chip added the $ operand to the assembler.

    -Phil
  • JasonDorieJasonDorie Posts: 1,930
    edited 2009-02-12 01:40
    I think you'll find Spin relatively easy if you've used many other high-level languages. It generally makes sense, and bears similarity to C/C++, OO Pascal, etc. There are a couple gotchas to beware of - Read the 'operators' section of the manual carefully. I've been bitten by '>=' not being the same as '=>', and '>>' being unsigned shift while '~>' is an arithmetic shift.

    It'll probably take you a bit before you're using it to its full potential (I'm certainly not there yet) but it's a pretty easy language to learn.

    Jason
  • heaterheater Posts: 3,370
    edited 2009-02-12 08:46
    This may not be relevant but it just occurred to me that having SPIN write the parameters into your DAT and then loading the DAT into a COG is fine when the COG never stops. But if you want to change the parameters and restart the COG there could be a time window between setting the new parameters and restarting the COG where the running COG does something screwy with the new parameters or partially updated new parameters.

    Having the COG read its params from par on start up prevents this race condition. As would stopping the COG prior to param changes then starting it again.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-12 13:46
    Interesting, Heater, and thanks. But my cogs will start only when I turn on the power switch, and stop only when I turn it off.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net
  • Carl HayesCarl Hayes Posts: 841
    edited 2009-02-12 13:47
    Phil Pilgrim (PhiPi) said...
    Yup, I used *-* with the IBM 1130/1800. I suppose one could use $-$ with the Propeller, but 0-0 became the de facto standard before Chip added the $ operand to the assembler.

    -Phil
    What is the $ operand?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    · -- Carl, nn5i@arrl.net
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2009-02-12 16:21
    It's the current value of the location counter, as governed by the most recent org.

    -Phil
Sign In or Register to comment.