Shop OBEX P1 Docs P2 Docs Learn Events
Few questions in one thread.. What is a register? How to access variables used in one spin program? — Parallax Forums

Few questions in one thread.. What is a register? How to access variables used in one spin program?

Hello all,

I have a couple of questions to ask,
At the expense of my seeming stupid...



Question 1
========
Please can someone explain what a register is?
I'm not sure, but from what I can understand...
Is that a Register is the Byte, Word or Long where data received from or sent to a PIN on the micro-controller is stored?
So this could be any memory location within the available memory space.

For example:
========
Say I have written a mouse driver,
And the mouse driver has the variables MouseX, MouseY and Buttons...
And I allocate these variables into WORD variables named as above (MouseX, MouseY and Buttons)
So would the data that is coming from the mouse into the Propeller chip via the Input pins be saved into the Variables MouseX, MouseY and Buttons?
And in a sense these variables ARE the REGISTERS?
So is that a correct assumption?


Question 2
========
If I want to access a variable I have created in one program,
from another program, how is this possible?

And taking the example mouse driver above,
Taking the following for granted:
- Mouse driver program is called MyMouse.Spin
- Inside MyMouse.Spin there as PUBLIC procedures for each of those variables:
GetMyMouseX()
SetMyMouseX(NewX)
GetMyMouseY()
SetMyMouseY(NewY)
GetMyButtons()
SetMyButtons(NewButtonsState)
- Parent Program is called MyFramework.Spin

Inside MyFramework.Spin I would use something like?
- MouseXPos:= MyMouse#GetMyMouseX
- MouseYPos:= MyMouse#GetMyMouseY
- MouseButtonStates:= MyMouse#GetMyButtons

If all of the above is correct....

How do I shorten the calls:
- MouseXPos:= MyMouse#GetMyMouseX
- MouseYPos:= MyMouse#GetMyMouseY

into :
- MousePosNow:= MyMouse#GetMyMouseXY()
and return TWO values instead of the normal one RESULT value?


Thank You In Advance.

JD



Comments

  • Parallax has used the term "register" in a somewhat confusing way. Except for the upper 16 longs ($1F0-$1FF) in each cog's memory, all other cog addresses are just memory locations that are part of the cog itself and are not accessible from other cogs. The upper 16 longs actually correspond to 16 "shadow memory" locations some of which can be accessed as destination operands in some instructions. Most of the time though, these addresses reference special hardware registers like PAR, CNT, the two cog counters, video registers, I/O control registers, etc.

    You can't directly references variables in a child object from the parent or other child objects. To reference a public (PUB) function in a child object from the parent, you'd use <object>.<function> like:

    XPos := MyMouse.GetMyMouseX

    If there are no parameters, leave out the parentheses in both the declaration and reference.

    The "#" notation is only used to reference named constants in the child object.

    As is true of functions in general, you can't really return two values, only a single value. That said, you could probably pack both an X and Y value into one 32-bit long like this (in the child):

    PUB GetMyMouseXY
    return (GetMyMouseX << 16) | (GetMyMouseY & $FFFF)

    and this in the parent:

    MousePosNow := MyMouse.GetMyMouseXY
    MouseXPos := MousePosNow ~> 16 ' extend sign of upper half
    MouseYPos := ~~MousePosNow ' extend sign of lower half

    Read the Propeller Manual for details. It's downloadable from Parallax.
  • Cluso99Cluso99 Posts: 18,069
    JD - Welcome to the forums.

    Q1:

    Lets start at the beginning. It is how I remember it, so it could be a little off, but the basics are there.

    Original micros had an accumulator. Whenever you needed to do something, you read your value in from memory ("load"ed) into the accumulator, did something with it (eg added 1 to it), and then you wrote it back out to memory ("store"d). The accumulator was a register. Soon, micros added more accumulators and named them A, B, X, Y, etc. These were all registers. The memory at this time was for either the program (usually EPROM) or data (usually RAM).

    Next, micros and peripherals (chips such as 6820 which were parallel expanders) had internal registers for configuring the I/O pins. Often, these configuration registers were mapped into memory space. But the micro could not directly use these register to perform ALU operations. Instead, it was necessary to write to these registers using the "store" instruction which wrote the value from an accumulator register to the memory-mapped register.

    Then, as chips got smarter, the external peripheral chips were included internally in the micro. So the registers became both the accumulator registers (which could be operated on by the ALU and instructions) and the configuration registers which configured the I/O and any other internal blocks such as counters etc.

    Next came the RISC (reduced instruction set computer). They had a lot less instructions that did the basics fast. These RISC processors added a number of addressable accumulators called registers. 16 and 32 registers were common. The instruction set had special bits used to select which register would be used in the instruction, rather than one or a few accumulators. This saved a lot of load/store instructions being executed (faster) by keeping a number of effective accumulators with values/data.

    Generally, registers are used for operating on, or storing, data. They usually cannot be used for the physical program, which is usually stored in ROM/EPROM/EEPROM/FLASH. Some micros (and all general computers - mainframe, minis, micros such as PCs, tablets, phones) can have their running program stored in RAM/SRAM/DRAM.

    Propeller
    The propeller has
    * Internal shared ROM (called HUB) where fixed programs and some fixed data values are stored
    * Internal shared RAM (called HUB) where programs and data can be stored
    * Internal RAM (called COG RAM) exclusive to each processor core (COG)

    The internal shared HUB RAM is loaded at boot time (after a reset) from either
    * A serial connection to Pins P30 & P31
    * An external EEPROM
    Then one core/cog (Cog #0) is started by loading its internal RAM from a section of HUB RAM and then this core/cog begins execution from its' COG RAM at address $000.

    COG RAM
    The COG RAM is 512 x 32bits. In a Propeller, this is all addressable by the instruction set, as well as it contains the program (a set of instructions). So, these 512 longs contain both the program and data. As such, these 512 longs can also be used as registers.
    Therefore, the propeller has 8 cores/cogs, each with its' own 512 shared registers & program space. The last 16 longs are "special registers" that under normal operation cannot be used for program space. They are used to configure things such as the counters, I/O, video, etc.

    Where does your data reside
    Your data may reside inside the cog (COG RAM) or outside in the HUB RAM where it can be read and/or written by any core. You move HUB RAM locations into your registers by reading (RDBYTE/RDWORD/RDLONG) hub ram locations, and move back to HUB RAM by writing (WRBYTE/WRWORD/WRLONG) to hub ram locations.
  • There are some examples of how to access a child object's variable in this thread. Mike Green already mentioned some of these.

    The whole cog vs hub thing was intensely confusing when I first started programming the Propeller. I just kept reading the descriptions like those offered above and it slow sunk in.

    The only time you need to worry about cog RAM is when you're using PASM. All Spin variables are located in the hub.
  • Cluso99Cluso99 Posts: 18,069
    Yes, when you are running spin in a cog, the whole cog is consumed by the spin interpreter which is in reality a PASM program. All your program, stack and variables, reside in hub ram.
  • Mike Green wrote: »
    Parallax has used the term "register" in a somewhat confusing way. Except for the upper 16 longs ($1F0-$1FF) in each cog's memory, all other cog addresses are just memory locations that are part of the cog itself and are not accessible from other cogs. The upper 16 longs actually correspond to 16 "shadow memory" locations some of which can be accessed as destination operands in some instructions. Most of the time though, these addresses reference special hardware registers like PAR, CNT, the two cog counters, video registers, I/O control registers, etc.

    You can't directly references variables in a child object from the parent or other child objects. To reference a public (PUB) function in a child object from the parent, you'd use <object>.<function> like:

    XPos := MyMouse.GetMyMouseX

    If there are no parameters, leave out the parentheses in both the declaration and reference.

    The "#" notation is only used to reference named constants in the child object.

    As is true of functions in general, you can't really return two values, only a single value. That said, you could probably pack both an X and Y value into one 32-bit long like this (in the child):

    PUB GetMyMouseXY
    return (GetMyMouseX << 16) | (GetMyMouseY & $FFFF)

    and this in the parent:

    MousePosNow := MyMouse.GetMyMouseXY
    MouseXPos := MousePosNow ~> 16 ' extend sign of upper half
    MouseYPos := ~~MousePosNow ' extend sign of lower half

    Read the Propeller Manual for details. It's downloadable from Parallax.



    Hello Mike,

    Thank You for your explanation. it has helped clear up some of the questions in my mind.
    And I also have some more questions..

    I understand from what you state above,
    That its not possible to DIRECTLY reference variables in a child object from the parent object
    But its possible to INDIRECTLY reference them via PUB(lic) function.
    So does this mean that the opposite is true too?
    And the child can access variables INDIRECTLY in the parent object via PUB(lic) functions too?

    Thank You too for explaining how to PACK more than one return value into larger sized variables like LONGS.

    I have already downloaded the Propeller Manual.
    It is because I am new-ish to electronics and micro-controllers,
    that I struggle to comprehend some of the stuff.
    I feel like my programming is up to par,
    Having used visual studio with visual basic to design stuff.
    But it is my lack of electronics which fails me.
    And hence leaves me with my back against the wall and a complete lack of understanding.

    Once again,Thank You for your help and explanation.

    JD



  • Cluso99 wrote: »

    JD - Welcome to the forums.

    Q1:

    Lets start at the beginning. It is how I remember it, so it could be a little off, but the basics are there.

    Original micros had an accumulator. Whenever you needed to do something, you read your value in from memory ("load"ed) into the accumulator, did something with it (eg added 1 to it), and then you wrote it back out to memory ("store"d). The accumulator was a register. Soon, micros added more accumulators and named them A, B, X, Y, etc. These were all registers. The memory at this time was for either the program (usually EPROM) or data (usually RAM).

    Next, micros and peripherals (chips such as 6820 which were parallel expanders) had internal registers for configuring the I/O pins. Often, these configuration registers were mapped into memory space. But the micro could not directly use these register to perform ALU operations. Instead, it was necessary to write to these registers using the "store" instruction which wrote the value from an accumulator register to the memory-mapped register.

    Then, as chips got smarter, the external peripheral chips were included internally in the micro. So the registers became both the accumulator registers (which could be operated on by the ALU and instructions) and the configuration registers which configured the I/O and any other internal blocks such as counters etc.

    Next came the RISC (reduced instruction set computer). They had a lot less instructions that did the basics fast. These RISC processors added a number of addressable accumulators called registers. 16 and 32 registers were common. The instruction set had special bits used to select which register would be used in the instruction, rather than one or a few accumulators. This saved a lot of load/store instructions being executed (faster) by keeping a number of effective accumulators with values/data.

    Generally, registers are used for operating on, or storing, data. They usually cannot be used for the physical program, which is usually stored in ROM/EPROM/EEPROM/FLASH. Some micros (and all general computers - mainframe, minis, micros such as PCs, tablets, phones) can have their running program stored in RAM/SRAM/DRAM.

    Propeller
    The propeller has
    * Internal shared ROM (called HUB) where fixed programs and some fixed data values are stored
    * Internal shared RAM (called HUB) where programs and data can be stored
    * Internal RAM (called COG RAM) exclusive to each processor core (COG)

    The internal shared HUB RAM is loaded at boot time (after a reset) from either
    * A serial connection to Pins P30 & P31
    * An external EEPROM
    Then one core/cog (Cog #0) is started by loading its internal RAM from a section of HUB RAM and then this core/cog begins execution from its' COG RAM at address $000.

    COG RAM
    The COG RAM is 512 x 32bits. In a Propeller, this is all addressable by the instruction set, as well as it contains the program (a set of instructions). So, these 512 longs contain both the program and data. As such, these 512 longs can also be used as registers.
    Therefore, the propeller has 8 cores/cogs, each with its' own 512 shared registers & program space. The last 16 longs are "special registers" that under normal operation cannot be used for program space. They are used to configure things such as the counters, I/O, video, etc.

    Where does your data reside
    Your data may reside inside the cog (COG RAM) or outside in the HUB RAM where it can be read and/or written by any core. You move HUB RAM locations into your registers by reading (RDBYTE/RDWORD/RDLONG) hub ram locations, and move back to HUB RAM by writing (WRBYTE/WRWORD/WRLONG) to hub ram locations.


    Hello Cluso99,

    Thank You for your explanation too...

    Your historical interlude into how processors have evolved helped a LOT in understanding some things

    And the explanation of how to access variables from MAIN (HUB) RAM into LOCAL (COG) RAM has REALLY helped.
    I guess the main thing I am struggling with is, which Command to use to do what I want.

    I have noted down those commands you mentioned above:
    RDBYTE/RDWORD/RDLONG
    WRBYTE/WRWORD/WRLONG

    These are exactly what I needed,
    So Now I know how to shadow/transfer a variable in main ram to cog ram
    This will help me out lots.

    Thanks again, because sometimes a scholarly explanation is much better than reading pages of text,
    which simply confuse a new mind even more.


    JD







  • Duane Degn wrote: »
    There are some examples of how to access a child object's variable in this thread. Mike Green already mentioned some of these.

    The whole cog vs hub thing was intensely confusing when I first started programming the Propeller. I just kept reading the descriptions like those offered above and it slow sunk in.

    The only time you need to worry about cog RAM is when you're using PASM. All Spin variables are located in the hub.


    Thank You Duane,
    That link was great,

    And yes the whole things with Cog Vs Hub is very confusing,
    But i'm trying as you stated above, to keep reading and re-reading the manual /descriptions until the penny drops lol


    JD


  • Cluso99Cluso99 Posts: 18,069
    JD,
    You might be better to just jump in feet first. As you come to problems, just ask (on the Propeller 1 forum).
    There is a good set of examples to work through that come with downloading PropTool. There is also a sticky in the Propeller forum that has lots of good beginner info.
  • One way to access variables between parent and child (or even between children) is to pass the address of a variable (or group of variables) from parent to child, usually during initialization of the child. You can also have a public function in a child that returns the address of a variable in the child. Given an address, you can reference the value or change the value by using LONG[<address>] or WORD[<address>] or BYTE[<address>]. Remember that the variables in an object are rearranged with longs first, then words followed by byte variables. DAT sections are kept in order, but with padding added as needed to ensure proper addressing boundaries.
Sign In or Register to comment.