Another (maybe) stupid question...

So I have been browsing the forums,
And came across this article Cogjects - load cog code from SD and save hub ram by Dr_Acula.

It was such an interesting read, and I promptly downloaded the code and tried to understand what's happening...
I'm at a bit at a loose end because I don't fully understand the code.

In the Main program there is this code
PUB Main | i,j,cols,rows,chrs
    
  fat.FATEngineStart(_SD_DO, _SD_CLK, _SD_DI, _SD_CS, _SD_WP, _SD_CD, _RTC_DAT, _RTC_CLK, -1)
  cogarray := fat.addressofcog                          ' get location of the fat cog array
  fat.mountPartition(0)                                 ' mount the sd card
  'ifnot(fat.partitionMounted)                          ' commented out - if the sd card isn't working, can't load a cog to be able to display this
  '  printstringcr(string("Card Not Mounted "))
  ReadCogFile(string("Serial.Cog"))                     ' cog 2
  serial.start(cogarray,31,30,0,38400)                  ' start the cog at this baud rate

  ReadCogFile(string("Keyboard.Cog"))                   ' cog 3
  kb.start(cogarray,26,27)                              'start the keyboard


So as I understand it, this is what's happening...

1 - Start the sdcard driver
  fat.FATEngineStart(_SD_DO, _SD_CLK, _SD_DI, _SD_CS, _SD_WP, _SD_CD, _RTC_DAT, _RTC_CLK, -1)


2 - Get address of where the DAT/PASM area is located (The 512x longs (cog ram area) of the sd card pasm driver)
  cogarray := fat.addressofcog                          ' get location of the fat cog array


3 - Mount the sd card
  fat.mountPartition(0)                                 ' mount the sd card


Skipping the commented out section, we continue to
  ReadCogFile(string("Serial.Cog"))                     ' cog 2


And THIS is where the confusion starts,
because at this point, aren't we reading the Serial.Cog file into the area where the sd card pasm driver resides?
doesn't his mean we will overwrite the the sd card pasm driver?
shouldn't cogarray just be a 2k buffer in main ram?


I'm unable to just take the code and try since I don't have a working propeller board lol (i'm still working on the board)

Comments

  • There are two completely separate areas of memory in the P1. One is hub memory which consists of 32K bytes of RAM and 32K bytes of ROM. The other is 8 x 512 32-bit words, one 512 word area for each cog. When you (or someone else) writes a pasm driver, it is compiled / assembled into a block of hub memory. When your program starts up that driver, it is copied (by a COGNEW or COGINIT instruction) from the hub memory to a cog memory and starts to execute. At this point, the copy in hub memory is no longer needed and that space can be used for something else ... like an area for reading in a different pasm driver prior to its being copied to a different cog for execution.
  • Hiya Mike,

    Thank you for trying to help me understand what's going on in the program...
    The program I downloaded was Cogjects 24 March 2011

    So I understand from the manual, docs and what you wrote above as follows...

    If I have a program MAIN and in that program are objects such as FULL-SERIAL or VGA or MOUSE or KEYBOARD
    When I compile the program those objects are INSIDE the compiled (binary/eprom file (executable).
    And then when I load the object into PASM it is copied from the Hub Ram to the Cog ram for the relevant cog its going to run in...


    But the code from that program doesn't have/contain that PASM program, its loaded into the cog ram at run time from the SD Card.

    And in the main program where it says/contains..
    cogarray := fat.addressofcog                          ' get location of the fat cog array
    

    Looking at the function/method "addressofcog"
    we see it says/contains the following...
    PUB addressofcog
      return @initialization  
    
    DAT
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       SDC Driver
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
                            org     0
    
    ' //////////////////////Initialization/////////////////////////////////////////////////////////////////////////////////////////
    
    initialization          mov     ctra,                 clockCounterSetup            ' Setup counter modules.
                            mov     ctrb,                 dataInCounterSetup           '
    
                            jmp     #instructionWait                                   ' Skip to instruction handle.
    
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    '                       Command Center
    ' /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    

    So the cogarray variable is pointing at address where initialization starts in the cog ram...
    Is'nt that right?


    And what I thought or expected was for cogarray to be a physical array 2KB in size in hub ram, not a pointer pointing to the start of the cog ram address that it does point to.
    Which on its own may be okay(?)
    but when I want to load the next driver into another cog, cogarray is still pointing at the beginning of cog ram in whichever cog is was inside...
    and therefore, my understanding that the next driver would overwrite the sd card driver (as thats where cogarray pointed to?


    I'm obviously missing something as the penny is not dropping...
    What am I missing?






  • Cluso99Cluso99 Posts: 17,179
    IIRC there is a 2KB buffer in hub that is used each time a pasm coglet is loaded from SD. This is then used to start a pasm cog which loads this 2KB from that hub buffer into the cog and the cog starts. This buffer is no longer required, and is then free for the next coglet load. Now, probably the original SD pasm driver was loaded (positioned) at this buffer location, and as it was originally started (loaded) into its own cog, its now a free buffer.

    Note spin code always resides in hub, so you cannot reuse that space unless that code is no longer required.
  • AribaAriba Posts: 2,409
    edited 2020-12-24 12:55
    JaanDoh wrote: »
    .....

    So the cogarray variable is pointing at address where initialization starts in the cog ram...
    Is'nt that right?
    No, it points to the begin of the image of the cog code in hubram.

    When you start a cog with COGNEW the cog memory gets loaded from an image of the code in hubram. You point to this image with the first parameter of cognew.
    Once the cog ram is loaded, the image in hubmemory is no longer needed, and can be used for other purposes. Here it is used to load other PASM images into hubmemory and then start other cogs with it.
    And what I thought or expected was for cogarray to be a physical array 2KB in size in hub ram, not a pointer pointing to the start of the cog ram address that it does point to.
    Which on its own may be okay(?)
    but when I want to load the next driver into another cog, cogarray is still pointing at the beginning of cog ram in whichever cog is was inside...
    and therefore, my understanding that the next driver would overwrite the sd card driver (as thats where cogarray pointed to?
    ...

    Again it points to a hub address not "the start of the cog ram", that would be always 0 (zero), because cog ram has its own address space from 0 to 511 in longs.

    Andy
  • Well Thank you, Cluso and Ariba, too

    Mike obviously explained it but I didn't understand,
    I can't help but feel that *important * information like this ought to be in the documentation, and especially little facets like how to load a cog dynamically should also be in the documentation, with solid examples and further explanation , since this all helps the newbies.

    Surely gems like these are *very* important in helping leveraging the full power of the P8x32a microcontroller.


    And I take away from this conversation thread the following:

    Somewhere in the hub ram (not necessarily at at a fixed/specific location) there is a 2k space which is re-used to load pasm code in to the cog ram (pasm area) and if pasm code is not used by the program then that space can be used by the program as just extra space.

    And that 2k space is in the executanle/compiled program image, held in hub ram, and after the relavent data/image is loaded that space is wasted...


    Cheers guys
    And Merry Christmas to one and all 🎄🎅🍻☃️
  • Cluso99Cluso99 Posts: 17,179
    JaanDoh wrote: »
    Well Thank you, Cluso and Ariba, too

    Mike obviously explained it but I didn't understand,
    I can't help but feel that *important * information like this ought to be in the documentation, and especially little facets like how to load a cog dynamically should also be in the documentation, with solid examples and further explanation , since this all helps the newbies.

    Surely gems like these are *very* important in helping leveraging the full power of the P8x32a microcontroller.


    And I take away from this conversation thread the following:

    Somewhere in the hub ram (not necessarily at at a fixed/specific location) there is a 2k space which is re-used to load pasm code in to the cog ram (pasm area) and if pasm code is not used by the program then that space can be used by the program as just extra space.

    And that 2k space is in the executanle/compiled program image, held in hub ram, and after the relavent data/image is loaded that space is wasted...


    Cheers guys
    And Merry Christmas to one and all 🎄🎅🍻☃️
    No, and not quite.

    First, this is an advanced feature that most users will never need to know. It's only important when you are running out of hub ram.

    Next. When code is compiled to a binary, and then after reset, that binary is loaded into hub ram beginning at $0. Any of this code that is in pasm and gets loaded into its' own cog to run using coginit or cognew will have a copy of its' pasm code in hub ram. This space in hub ram is then re-usable provided its' not going to reloaded into cog again.

    Now, the pasm code loaded into cog is always 512-16 = 496 longs, which is just under 2KB. However, this code isn't necessarily 2KB. Some pasm programs are short, being much less that magical 496 longs (includes register/data space). So if I have a 1KB program then only 1KB gets compiled into hub space. Now when I load that to run in cog, 2KB will be loaded into cog, but only the first 1K is valid and the remainder is rubbish being whatever was compiled after that 1KB. So the re-usable space in hub is actually only the size of the loaded pasm code that is required in the cog, and not the whole 2KB.
  • Well @JaanDoh,

    close but not cigar.

    There is no specific RAM area in the HUB to load Cogs. This is just the way 'Coglets' are designed by the Author of the drivers you use. It is sort of a trick to be able to dynamicly load and change Cogs at runtime.

    Usually the Code for Cogs will be included in DAT sections and therefore will be included into the HUB ram image the compiler creates.

    Each Cog has own RAM of 2K where it executes code and store its register values. This 2K RAM can be just accessed by that single COG the RAM belongs to.

    All Cogs have common shared access to the 32K of HUB ram and that HUB ram is what you can load into the P1.

    When you start a COG it will load up to 2K from a given HUB address into its own RAM and start executing it. Does not need to be 2K, if the COG program is shorter it will need less space in HUB, not always 2K.

    If you would have 8 full blown 2K DAT sections for 8 COGS you indeed would need 16K of HUB ram to store the needed CODE to load into them. Usually they are not 2K each but smaller, still that memory in HUB is sort of free after starting the COG.

    But the point is that the COG COPIES the content from the HUB into its own memory and after doing so that memory in HUB is not used except you need to restart the COG again.

    There are different strategies to reuse that memory if you do NOT need to restart the COG. Some serial drivers for example use the HUB space of their original Code as a buffer thus overwriting their own code in HUB since they already copied it and do not need it anymore.

    But not all COG code needs buffers in HUB, so sometimes you think it is wasted space because one can run out of the 32K when the program gets bigger.

    The idea with 'Coglets' is to have just one area in HUB to load Cog Code, start the Cog (it copies) and use the same hub Area to load the code for the next Cog.

    It is a bad **** trick but normally not needed, except you really run out of HUB memory.

    hope this helps your understanding,

    Mike
  • potatoheadpotatohead Posts: 10,144
    edited 2020-12-27 07:39
    Maybe this helps: (oops, I did not see msrobots good reply! Well maybe it all helps!)

    Each COG has 2K of RAM that is not shared and not addressed in any way by any other COG and that is not part of the shared HUB RAM.

    In fact, this 2K of RAM is the only place where a COG can actually execute assembly language program instructions! That is in the docs, but gets glossed over pretty easily. It is very different from how most multi core machines work.

    People have made machines that fetch instructions from the HUB to execute, and that is called LMM, but for the purposes of this discussion, each COG is an independent CPU that runs programs in its own memory space.

    All programs originate in the HUB, which gets loaded at boot up time by COG 0, which runs a program in ROM designed for that purpose.

    When that process is complete, COG 0 runs the SPIN interpreter, which proceeds to run a SPIN program.

    That program may contain one or more PASM programs, and instructions for one or more COGS to run them, after first loading them from HUB RAM.

    Again, the only place a COG executes instructions directly is from its own unique, private RAM.

    Sometimes we talk about multi core.

    This can be confusing because there are multiple cores in a Propeller Chip. However, on the Propeller 1, each core runs independently of the others and none of them execute programs from shared memory.

    One can instruct a COG to load and run a program in the HUB, then overwrite that program once the COG is running it. This is done regularly to use the memory space for other purposes once all the intended COGS are running their intended programs.

    And finally, that gets to this example code. It fetches COG programs from storage and once they are in the HUB, instructs a COG to run them. This can be done repeatedly, due to the fact that the COG RAM is private to the COG and not shared.

    One 2K buffer in the HUB can be filled with COG programs sequentially. Fetch one, COGSTART, fetch another, COGSTART, etc.
  • Peter JakackiPeter Jakacki Posts: 9,949
    edited 2020-12-28 12:38
    I used a similar technique in Tachyon to load cogs with named binary images in upper EEPROM at runtime. The software can ask for "SIDCOG" to be loaded into cog 4 for instance or "VGA" into cog 7 etc. But the image cannot be loaded directly from EEPROM into the cog and so a 2k buffer area is used to read the EEPROM and then coginit from that buffer. The buffer is also used for up to four 512 byte file sectors if SD is available. Since this normally happens after a reset then these buffers are available.

    BTW - it's always a good idea to have a subject line that actually mentions what you are talking about such as "another question about cogjets" for instance.
  • Thank you all, Cluso, msrobots, potato head and Peter,

    For taking the time to explain it all to me.
    Apologies for the thread subject title too


    I'm back at work now, but hope to put all your advice to good use very soon...


Sign In or Register to comment.