Shop OBEX P1 Docs P2 Docs Learn Events
How does ORG work? — Parallax Forums

How does ORG work?

Dr_AculaDr_Acula Posts: 5,484
edited 2011-03-25 13:59 in Propeller 1
Over on the Kye SD thread I have posted a rather long question regarding building self contained cog code that can be loaded off an sd card and which can exist separately from its supporting high level code in Spin/C/Basic.

The 'standard' way to pass variables to a cog is with PAR and that usually points to a list of variables and/or arrays.

Kye is doing something different and is using Spin to poke variable values into the hub ram that contains the cog code, prior to loading a cog.

This has an intriguing advantage in that it saves a lot of moving PAR data around in the cog. Because there is more hub memory for spin than cog memory for pasm, memory in cog is more precious than in hub.

So I thought I would take this a bit further and write some cog code that has the program at the bottom of memory, and the data at the top of cog memory.
CON
  _clkfreq = 80_000_000
  _clkmode = xtal1 + pll16x

PUB Main
    coginit(1,@cogstart,0)  ' cog 1, cogstart, dummy value

DAT
                  org 0
cogstart          wrbyte  testvalue, testvariable ' test value A
                  jmp #cogstart
                 org 400

testvariable      long    5000           ' test memory location 5000
testvalue         long    65             ' ascii A
                  fit 496

but using F8, this does not seem to produce a whole lot of blank space in the middle of the program. Am I using ORG correctly?

And, going off on a tangent, if this is not possible, is it possible to put all the variables at the beginning of a program, so their location ends up in a known place?
CON
  _clkfreq = 80_000_000
  _clkmode = xtal1 + pll16x

PUB Main
    coginit(1,@cogstart,0)  ' cog 1, cogstart, dummy value

DAT
                  org 0
                        jmp cogstart

v1                      byte 65
v2                      byte 66
v3                      byte 67
v4                      byte 68
v5                      byte 69
v6                      byte 70
v7                      byte 71


cogstart          wrbyte  testvalue, testvariable ' test value A
                  jmp #cogstart

testvariable      long    5000           ' test memory location 5000
testvalue         long    65             ' ascii A
                  fit 496

This does seem to work, and it also pads out longs so that the 7 bytes above occupy 2 full longs.

But the disadvantage of this method is that it is more standard to put variables at the end of the program.

Thoughts would be most appreciated.

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-03-21 22:50
    The only thing org does is to reset the cog's location counter (i.e. $) during assembly to the new value. It does not affect where items from the hub get placed in the cog when the cog is started. All transfers from the hub to the cog upon a cognew occur sequentially, without regard to any assembled cog addresses. IOW, your assembly code will adress the transferred block the way you want it to, but the block copied from the hub will not exist at that location but, rather, immediately after the block which begins at location 0.

    -Phil
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-03-22 00:10
    Thanks Phil. Maybe we might be pushing the language to do things it wasn't originally designed to do.

    I guess I grew up with ORG in 8080 and Z80 where it then started compiling from that location. I had a look through other instructions but I am not sure there is a way to put the variables at a known offset from the beginning of the assembly code.

    So there is still plan B where the variables go at the beginning and the code comes after?
  • Heater.Heater. Posts: 21,230
    edited 2011-03-22 00:51
    Dr_A,

    Plan B where the variables go at the beginning and the code comes after.

    Yep, you mean like this:

    1) Put the variables that must be initialized prior to COG loading at the beginning of your DAT section. Except location 0.
    2) Follow those variables with your PASM instructions.
    3) Make the location zero a JMP to the start of your code.

    For example something like this:

    PUB startMyCog(parParams)
    
        P0 := 1234                    'Set up parameter variables in DAT for loading with COG code
        P1 := 5678
        P2 := 0912
        P3 := 3456
        
        cognew(@enter, parParams)    'Start a COG for this object with PAR params
    
    DAT
                org        0
    enter
    useMeLater    jmp        #start       'This location can be used as a variable when running  
    
    P0            long     0            'These variables are "parameters" to to be set prior to COG load. 
    P1            long    0
    P2            long    0
    P3            long    0
    
    start    'PASM code goes here
            'Start fetching PAR params maybe
    
  • Andrey DemenevAndrey Demenev Posts: 377
    edited 2011-03-22 01:10
    Dr_Acula, why do you want them at the beginning?
  • Heater.Heater. Posts: 21,230
    edited 2011-03-22 01:34
    I think that the idea is that when such a PASM code is used from a different language than Spin that language has no "linkage" to the PASM and so does not know where the variables to be set up are. Therefore such variables must be placed at known locations that can then be compiled into the "foriegn" language. Having them grouped at the beginning is just convenience.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-03-22 02:38
    Yes that is right heater. All that the C/Basic program knows is that there is list of hex data - it does not know anything about the variables. However, if it knows where the variables are, it can change them, which is what Kye's code does.

    All you really need to know is the start of the variable list. And it does help if all the variables are grouped together.

    A problem that might arise is that you change the pasm program and add one line of code. If the variables come after the pasm code, that changes the location (ie the offset from org 0).

    I had an idea that you could always put the variables at a known location, eg at 400. Or maybe count down from the top if that is possible. But putting them at the beginning might be the best answer - then you know that however much you change the pasm code, the variables start at long number 1.

    This concept could become useful for Andreys IDE, where you might use the same PASM binary for C, Spin and Basic, and all that changes is the supporting code.
  • Andrey DemenevAndrey Demenev Posts: 377
    edited 2011-03-22 04:19
    Hmmmm. Then I do not see what the problem is. Placing vars starting at offset 1 and jmp #vars_end at offset 0 is pretty straightforward and absolutely "legal". It just not what how it is used to be done. Or I am missing something?
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2011-03-22 08:07
    Andrey:
    That is correct.
    To be extremely precise: ORG does not affect anything on the Prop side, ORG just specifies the offset that the assembler uses to calculate address in the resulting machine code.
  • ericballericball Posts: 774
    edited 2011-03-22 10:31
    Just to elaborate on one gotcha. The following code will not work:
    	org	0
    start	jmp	#next
    	org	16
    next	jmp	#start
    
    In other assemblers the second ORG changes where the code is placed in RAM. Thus the code would assemble to a jump instruction at address 0 and a jump instruction at address 16 with a bunch of zeros or FFs in between. Not true for the Prop Tool, which would generate the following:
    HUB[+0]	COG[0]	jmp	#16
    HUB[+4]	COG[1]	jmp	#0
    
    So the second instruction is stored immediately after the first instruction in HUB RAM, thus gets loaded into register 1 in COG RAM. But the ORG 16 means the "next" label gets translated to 16.

    Therefore, unless you are doing dynamic overlays, there is no reason to use anything other then ORG 0.
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2011-03-22 12:44
    ericball wrote:
    Therefore, unless you are doing dynamic overlays, there is no reason to use anything other then ORG 0.
    Or dynamic loading of code sections. (Yeah code could be thought of as an array, though generally is not).
  • davidsaundersdavidsaunders Posts: 1,559
    edited 2011-03-22 12:45
    Sorry about that I miss read your post. Yes for Dynamic overlays (eg Dynamic code loading).
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-03-22 15:58
    @ericball, thanks for that very helpful gotcha.

    I love this forum - thanks++ to everyone for the prompt help!
  • AribaAriba Posts: 2,690
    edited 2011-03-22 16:01
    If you want the variables at a known location at the end you can reserve the space in between with a
    long 0[number]:
    org 0
         'code
         long 0[$400-$]  'an "org $400" with right address in cog 
    var1 res 1
    var2 res 1
    ...
    
    But this needs more HubRam than putting the variables at begin.

    Andy
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-03-22 16:07
    Hang on, that looks interesting!

    What are you doing there - is $ a pointer to the current program counter?

    No problem with taking more hub ram - I've actually made all 'cogjects' 496 longs in size so even short programs are this long.

    There is no real cost in terms of hub ram, because the data comes off the sd card and is put in a temporary array which ends up on the stack, and this array is discarded when the function ends. That is the C solution, and an equivalent Spin solution could poke the data to a common 2k space in hub ram and load all 7 cogs through that one common code space.

    I need to check out your $ code!
  • AribaAriba Posts: 2,690
    edited 2011-03-22 16:22
    Yes $ stands for the current address in cog memory. You can also write it like that:
    here long 0[$400-here]

    Andy
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-03-23 03:07
    That works. Just one minor change with the code on post #14 - left out a $

    I haven't quite got the code on post #16 working - I need to test the numbers.
    CON
      _clkfreq = 80_000_000
      _clkmode = xtal1 + pll16x
    
    PUB Main
        coginit(1,@cogstart,0)  ' cog 1, cogstart, dummy value
    
    DAT
                      org 0
    cogstart          wrbyte  testvalue, testvariable ' test value A
    '                        nop
    '                        nop
    '                        nop
    '                        nop
                      jmp #cogstart
    
                      long $FFFFFFFF[494-$]        ' pad with FF, n=494 which is 496 minus the two variables below
    
    testvariable      long    5000           ' test memory location 5000
    testvalue         long    65             ' ascii A
                      fit 496
    

    F8, note that the variables start at hex $7D0, uncomment the NOPs and F8 again and the variables are still at $7D0.

    Uses 494 because this is 496 minus the two longs at the end. So just add up the number of longs and this is the number.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-03-23 08:26
    Drac: Take a look at my Overlay loader. There are a couple of examples of using the $ in there, and also my 1pin TV code plays with the program counter too.

    With loading a self-contained object directly from the SD card, there is no problem about filling unused cog space as there would be if it resided in hub.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2011-03-25 13:46
    Ariba wrote: »
    Yes $ stands for the current address in cog memory. You can also write it like that:
    here long 0[$400-here]

    Andy

    Don't you need a #?

    here long 0[$400-#here]

    I've never used a # this way but I thought you needed one if you're referring the location and not what's in the location.

    Duane
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-03-25 13:59
    The # is only necessary when used in the source field of an instruction to signal that it's an immediate operand. The pseudo-op long is not an instruction.

    -Phil
Sign In or Register to comment.