Shop OBEX P1 Docs P2 Docs Learn Events
Calling a Constant — Parallax Forums

Calling a Constant

pjvpjv Posts: 1,903
edited 2013-04-17 12:56 in Propeller 1
Hi All;

I need to have identical assembly code in several cogs, and of course the compilerI cannot have multiple assembler DAT blocks each having identical symbol names. So to rectify that I place several identical binary blobs in the editor, and use CONstants to define the various symbol names and their cog addresses. So far so good.

Then I have various pieces of assembler for each cog that must access it's binary blob at specific label locations as defined by the CONstants. That all works fine except for the CALL instruction which causes the compiler to throw an "expected a DAT symbol" error. I presume that is because the compiler can't find the call's _RET symbol in the binary blob eventhough it is listed in the CONstants.

It would be real nice if the assembler could be forced to use CONstants as arguments..... BST will also not do what I want, it recognizes and lists the symbol, but assigns a zero for it's value.

Does anyone know of a way to trick the compiler around this problem ? (I wish not to unfold the identical binary blobs and personalize the labels of each one)

Thanks for looking.

Cheers,

Peter (pjv)

Comments

  • Mike GMike G Posts: 2,702
    edited 2013-04-15 11:14
    You probably should post your code. As written it sounds like the PASM images are identical. What's stopping you from loading the images in several COGs? Why do you need multiple DAT sections if the code is the same?

    Is this because each PASM instance has it's own HUB workspace? If so, I believe, you could assign HUB addresses when the cog starts.
  • AribaAriba Posts: 2,690
    edited 2013-04-15 11:15
    You can do your calls with JMPRET instructions. This is what the compiler anyway generates for a CALL.
    You will need a constant for the RET position in the binary blob and then replace the call with:
    jmpret RET_LABEL, #SUBR_LABEL
    

    Andy
  • Heater.Heater. Posts: 21,230
    edited 2013-04-15 11:37
    If your PASM is the same in many COG you only need to define it once in one DAT section. As normal.
    If there is some configuration different to each instance why not pass than in via a par parameter block?
  • pjvpjv Posts: 1,903
    edited 2013-04-15 11:59
    Thanks for the answers.

    @Mike: The code is proprietary at this point so I can't post. To answer your question, for each cog, the binary blobs are identical, but the other assembler codes are different. So to load a blob followed by it's specific code requires a new org 0 for each instance, and each cognew instruction must reference each blob/specific section separately, hence their names must be different.

    @Andy: What you describe is precisely what I am doing, and that works fine, but it is a little cryptic, so I was hoping to somehow use the CALL/RET psuedocodes to make things clearer..... Sounds like a non-starter.

    @Heater: Same answer as Mike. The differences are assembly code programs.

    Looks like I'll have to stick with the less obvious approach. Thanks again guys,

    Cheers,

    Peter (pjv)
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-04-15 12:10
    Why not include just one binary blob and let each assembly cog load it as a block from the hub? By correctly setting the org of the blob to concide with its cog load location, each cog can refer to the labels in the blob and get their correct addresses.

    -Phil
  • pjvpjv Posts: 1,903
    edited 2013-04-15 12:57
    Hi Phil;

    I'm having a bit of a hard time to explain this properly... that probably means I don't fully understand it myself, although with the JMPRET method it does work properly, it just looks messy

    Each cog must have the universal binary blob, immediately followed by its specific assembler code. In order to load the various cogs from spin they each must have a unique starting address (set to org 0 as you suggest) which will then load the consecutive 512 (less SFRS) longs into the respective cog. This implies multiple copies of the identical binary blobs, yet they can all be accessed via a pre-determined list of CONstant addresses. And all this works just fine.

    The only trouble is with the compiler error when I use a CALL/RET instruction into the blob. It will work if I intersperse the blob with lables at salient points, but then again the labels mut be unique for each blob, and that becomes even messier than the JMPRET approach. So I guess I have my answer.

    Thanks for reading.

    Cheers,

    Peter (pjv)
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-04-15 14:15
    Here's an example of what I was talking about:
    PUB start
    
      cognew(@code0, @data0)
      cognew(@code1, @data0)    
    
    DAT
    
    '------[ Blob data ]-----------------------------------------------------------
    
                  org       1                       'Blob block that gets copied to each cog
    data0         long      12345
    data1         long      67890
    data2         long      1234567890
    
    '-------[ First cog program ]--------------------------------------------------
    
    code0         org       0                       'Beginning of first cog.
                  jmp       start0                  'Jump over blob block.
                  
                  long      0[data2 - data0]        'Cog location of copied blob data.
                  
    start0        movs      loop0,par               'Setup to read blob data into cog.
                  mov       cnt0,#3                 'Reading three longs.
    
    loop0         rdlong    1,#0-0                  'Read a long.
                  add       loop0,_0x204            'Increment both source and destination addresses.
                  djnz      cnt0,#loop0             'Back for another.
    
                  'From here, you can address data0 .. data2 using those lobels.
    
                  mov       cnt0,data0              'This loads from cog location 1.
                  
    _0x204        long      $204
    cnt0          res       1
    
    '-------[ Second cog program ]-------------------------------------------------
    
    code1         org       0
                  jmp       start1                  'Same as above.
                  
                  long      0[data2 - data0]
                  
    start1        movs      loop0,par
                  mov       cnt1,#3
    
    loop1         rdlong    1,#0-0
                  add       loop1,_1x204
                  djnz      cnt1,#loop1
    
                  'From here, you can address data0 .. data2 using those lobels.
    
                  mov       cnt1,data2              'This loads from cog location 3.
                  
    _1x204        long      $204
    cnt1          res       1
    

    Since you stated that you want ed the blob located at the beginning of the cog, you don't save any hub space doing it this way, but you can address the blob data by their common names in each cog. Now, if you were to read the blob into the end of the cog, instead of the beginning, you would save hub space.

    -Phil
  • pjvpjv Posts: 1,903
    edited 2013-04-15 15:40
    Phil,

    Thank you. I have not yet decided for sure if I want my blob (actually it is my Spin-friendly multi-tasking scheduler) to reside at the beginning or at the end of the cog there are pluses and minuses to each approach.

    I will need to try what you are suggesting, but I suspect that in the application code following the blob, the compiler will not let me do a CALL into the blob.

    Example: call #data1

    But all other instructions referencing data1 etc. ARE permitted.

    Cheers,

    Peter (pjv)
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-04-15 18:01
    pjv,

    I'm afraid my code includes a bug. The statement,
    loop0         rdlong    1,#0-0
    

    will work only if the blob is fully located within the first 512 bytes of hub space, which is unlikely. As a consequence, you would have to store the value in par into another variable and use it at the source of the rdlong without the #. In that case two separate address increments are necessary in the transfer loop.

    -Phil
  • pjvpjv Posts: 1,903
    edited 2013-04-15 21:07
    Hi Phil..

    The current blob (simple version scheduler) will just fit as it is 80 longs plus a dozen or so local variables. A next, more capable version will likely just be too large.

    I'm wondering if by chance you have tested this with a CALL instruction into the blob ? Everything else you describe is already familiar to me. It just this silly CALL issue. I can't test it until after tomorrow.

    Thanks for your interest.

    Cheers,

    Peter (pjv)
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-04-15 21:54
    I can see no reason that calling a subroutine would not work. This compiles:
    PUB start
    
      cognew(@code0, @data0)
      cognew(@code1, @data0)    
    
    DAT
    
    '------[ Blob data ]-----------------------------------------------------------
    
                  org       0                       'Blob block that gets copied to each cog
    data0         long      12345
    subr          nop
    subr_ret      ret
    data1         long      67890
    data2         long      1234567890
    
    '-------[ First cog program ]--------------------------------------------------
    
    code0         org       0                       'Beginning of first cog.
                  jmp       start0                  'Jump over blob block.
                  
                  long      0[data2 - data0]        'Cog location of copied blob data.
                  
    start0        movs      addr0,par               'Setup to read blob data into cog.
                  mov       cnt0,#data2 - data0 + 1 'Reading longs.
                  
    loop0         rdlong    0-0,addr0                  'Read a long.
                  add       loop0,_0x200            'Increment both source and destination addresses.
                  add       addr0,#4
                  djnz      cnt0,#loop0             'Back for another.
    
                  'From here, you can address data0 .. data2 using those labels.
    
                  mov       cnt0,data0              'This loads from cog location 1.
                  
    _0x200        long      $200
    cnt0          res       1
    addr0         res       1
    
    '-------[ Second cog program ]-------------------------------------------------
    
    code1         org       0
                  jmp       start1                  'Same as above.
                  
                  long      0[data2 - data0]
                  
    start1        movs      addr1,par
                  mov       cnt1,#data2 - data0 + 1
                  
    loop1         rdlong    0-0,addr1
                  add       loop1,_1x200
                  add       addr1,#4
                  djnz      cnt1,#loop1
    
                  'From here, you can address data0 .. data2 and call subr using those labels.
    
                  mov       cnt1,data2              'This loads from cog location 6.
                  call      #subr                   'This calls the subroutine at location 2
                  
    _1x200        long      $204
    cnt1          res       1
    addr1         res       1
    

    Note that I've fixed the rdlong ... #0-0 error and also am overwriting the jmp startx at the beginning of each cog.

    This is untested code, BTW, except for verifying compilation.

    -Phil
  • pjvpjv Posts: 1,903
    edited 2013-04-15 22:54
    Hello Phil

    I can see that I'm still failing to describe my issue properly..... or perhaps I'm too much of bonehead !

    The binary blob I have is just a DAT section of lines of hex bytes, as in byte $xx, $yy, $zz, etc for about 300 elements. Then in a CON section I have all the salient addresses defined in hex. So, there are no labels in the hex DAT section. I was hoping to CALL a routine in the blob via it's address in the CON section. This works for (I believe) all instructions, but not for a CALL.

    Cheers,

    Peter (pjv)
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-04-15 23:02
    Now you've lost me. What exactly are you CALLing in the blob if there is no code there?

    -Phil
  • Heater.Heater. Posts: 21,230
    edited 2013-04-15 23:28
    Starting from the from the title of this thread it's all very confusing. "Calling a constant" Makes no sense. It only makes sense to call code. which in PASM programming may not actually be constant.

    If you mean calling some code at some address given by a constant that's something we can think about.

    The problem here is that a CALL needs to save its return address somewhere. Most processors save return addresses on the stack, the propeller however stores it into the location of the return instruction of the subroutine being called. That is why you have:
    someFunction
        ...code
        ...code
        ...code
    someFunction_ret RET
    
        call #someFunction
    
    Here the return address is stored into the RET instruction at someFunction_ret

    Clearly if you are calling into a "binary blob" of code it is not possible to use a CALL instruction as it does not have any "..._ret" label at which to store a return address. That is to say the assembler cannot deal with:
        CALL #42
    
    (Which I believe is what you mean by "calling a constant".

    You would need to use JMPRET. With JMPRET you specify the lable of the function to JMP to and the lable of the place where the function can find its return address.
    someFunction
        ...code
        ...code
        ...code
        JMP returnAddress
    
        JMPRET retAddr, #someFunction
        ...' Returns to here.
        ...
        ...
    retAdder long 0
    
    Here the JMPRET stores the return address at retAddr and the jumps to the function. When the function is done it jumps via the return address back to the calling code.

    In this case you can use constants:
        JMPRET 99, #42
    
    Problem of course now is that the binary blob and the caller have to agree on a location of retAddr (99) which will have to be fixed some how.

    N.B. My PASM syntax may not be quite right here I have not hacked on this for a while.

    Does this sound like what you are trying to do?

    If so why do you need a binary "blob of" code with the resultant anonymous addresses fixed up by constant definitions?
  • kuronekokuroneko Posts: 3,623
    edited 2013-04-16 05:47
    @pjv: Instead of a black box CONstant section, would a black box DAT section be acceptable, e.g.
    DAT                                             ' black box section
                    org     10
    s0              res     4
    s0_ret
                    org     20
    s1              res     9
    s1_ret
    
    DAT             org     0                       ' active code
    
    entry           call    #s0
                    call    #s1
    
  • pjvpjv Posts: 1,903
    edited 2013-04-16 08:08
    Phil Heater, Kuroneko

    I'm truly sorry for all the confusion... this thread has turned into a bit of a mess.

    Heater has the right idea. I have code as a list of BYTEs in a DAT block. I have CONstants defined as address labels for some locations in the code (my binary blob). Several of those CONstants are named as CALL/RET pairs such as PAUSE and PAUSE_RET, or SUSPEND and SUSPEND_RET. Then further down, outside of the binary blob I wish to make calls to and returns from those PAUSE/PAUSE_RET etc. labels. And THAT'S the part that will not compile, and is the basis of my query. Only a CALL instruction into the blob using the CON defined labels will not compile, all others seem to be OK.

    My reason for enclosing the blob as anonymous hex in a DAT block is that it is a small scheduler intended for use by others, and should not be messed with because it is quite convoluted. So, as stated earlier, instead of CALLs to those blob locations, JMPRETs will work, its just more confusing for other users I think.

    Sorry again folks, I had not intended to abuse the forum or the respondents this way.

    Cheers,

    Peter (pjv)
  • Heater.Heater. Posts: 21,230
    edited 2013-04-16 08:36
    No worries about abuse. We like a challenge.
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-04-16 09:56
    pjv, instead of defining the blob addresses as a constant, define them as labels in the DAT section. So instead of this
    con
      blob1 = 10
      blob1_ret = 14
    
    do this
    dat
    blob1      org   10
    blob1_ret  org   14
    
  • Heater.Heater. Posts: 21,230
    edited 2013-04-16 10:07
    Pure genius!
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-04-16 10:08
    Dave,

    IIRC, orgs don't work that way, since the address pointer changes after the org. This might work, however:
    DAT
    
          org 10
    blob1
          org 14
    blob1_ret
    

    -Phil
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-04-16 10:21
    Phil, you are correct. I thought the label could be on the same line, but it picks up the cog address from the previous org in that case.
  • pjvpjv Posts: 1,903
    edited 2013-04-16 12:40
    SUCCESS !!!!!

    Dave and Phil, this is precisely the "trick" I was hoping for. It works perfectly.

    Many thanks to all contributors ! Oh how I love this forum and this chip. Yet another case of making it do what was not intended. Marvelous.

    Cheers,

    Peter (pjv)
  • kuronekokuroneko Posts: 3,623
    edited 2013-04-16 16:32
    This might work, however:
    DAT
    
          org 10
    blob1
          org 14
    blob1_ret
    
    It's before my morning coffee but how is org/org different from org/res (what I offered earlier)?
    DAT                                             ' black box section
                    org     10
    s0              res     4
    s0_ret
                    org     20
    s1              res     9
    s1_ret
    
  • pjvpjv Posts: 1,903
    edited 2013-04-16 17:28
    Kuroneko;

    I had not picked up sufficiently on your suggestion..... so far I have not (needed to) use the res directive.

    But what you offer will probably work, I will try it..... Your suggestions are always well thought out, and deserve serious consideration.

    Thank you.

    Peter (pjv)
  • pjvpjv Posts: 1,903
    edited 2013-04-17 12:56
    Hi Kuroneko;

    As expected, your suggestion works perfectly.

    Both, Dave's as well as yours produce identical results, as per:
    DAT             org     $37         
    Resume          org     $44
    Resume_Ret      org     $1D
    Pause           org     $4E
    Pause_Ret       org     $16
    Susp            org     $4E
    Susp_Ret        org     0
    
    
    DAT             org     $37         
    Resume          res     $0D     '$44-$37
    Resume_Ret      org     $1D
    Pause           res     $31     '$4E-$1D
    Pause_Ret       org     $16
    Susp            res     $38     '$4E-$16
    Susp_Ret        org     0
    

    All is well, and it does considerably visually clean up my applications that CALL into the binary blob.
    Thanks again all.

    Cheers,

    Peter (pjv)
Sign In or Register to comment.