Subject: How to create another running Cog in pfth DATE: Sat 12 Apr 2014 05:21:31 PM CST AUTHOR: GKH ++++++ Study Lexicon in pfth ___________________ CogNew CogInit CogStop CogId Forth Create Allot @ ' , body> ______________________ Pfth has provided a reference example in a file called Toggle.fth that you are strongly advised to explore. Reading the Propeller Manual for sections in PASM on starting and stopping cogs is also helpful, but not of critical importance. It is best to explore the use of the Toggle.fth code to verify that an independent cog is working, AND to read the PASM sections of the Propeller Manual ver 1.20 for what is required to stop and start cogs. The pfth code is very close to the PASM in terms of what it requires for operation. Evoking the word "starttoggle" starts a Pin 15 Led blink in a separate cog, and thus demonstrates an infinite loop on a separate cog using the Toggle code. All the elements included in the "starttoggle" colon definition are required to start a new cog AND to run a particular Forth word (in this case, Toggle). It may be a bit unclear to you which cogs are active. If you evoke Toggle, instead of StartToggle from the terminal, a separate Cog is NOT started and you will find the infinte loop will shut out keyboard input, which output to your serial terminal will remain active. (This may be useful for debugging with serial port reporting.) At startup, the Propeller always uses Cog 0 temporarily with Spin interpreter software to load the other cogs as required, so pfth interpreter gets loaded to Cog 1 and since no other cogs are loaded in the .spin file, Cogs 2-7 are not running. After loading Cog 0 is abandoned by the Spin interpreter and stopped, so it also becomes available for use in pfth. Herein, we are starting a second cog after all that has been done. You can identify your active interfacing cog in pfth with the word CogId. In this case it is Cog 1. Starttoggle will start with the lowest available cog, in this case Cog 0; but that can only be verified by using CogStop as CogId only works for the one Cog that is linked to your serial i/o. So, to verify where Starttoggle put Toggle, use "0 CogStop" to cease the blinking. If that doesn't work, seek out the running cog for yourself by stopping Cogs 2 through 7. Note - The Propeller doesn't inherently provide a feature that will tell the user all the cogs that are active at any one time, though it has a register that knows. To have this feature it would have to be created in software as an overlay that monitors CogNew, CogStop, CogId, and CogInit. You may also call Toggle directly in your active interface cog which will cause Pin 15 Led to blink from Cog 1, but you loose your terminal keyboard interface. So be aware that Toggle and Starttoggle evoke running is different cogs. And, Starttoggle will NOT successfully receive Terminal input or send Terminal output. First, use CogStop to turn off any active Toggle on Cog 0 that was started with Starttoggle, then evoke Toggle. But you will now be shut out of serial interface as the Cog 1 is tied up in an infinite loop for the blinking. You cannot use CogStop to cease this operation as you nolonger have keyboard input, you must reset the Propeller to change configuration (not so handy). It is important to fully understand that the additional cogs run on their own and can only be stopped and started from a cog that has the interpreter interface active. pfth currently only provides the active interface in Cog 1. ++++++ So how does one write code to achieve this in general? A. Establish arrays to describe the Data Stack and Return Stack space in HubRam within the Forth Dictionary space. Each cog has its own Stack, and the length can be shorter if hubram is in short supply. Please note that the actual Forth Data Stack and Forth Return Stack are never in the Cogs, so it is necessary to create an array in the Forth dictionary space for one of each for each cog you start up. Pfth already did so for the first cog. If you want to run more than one cog, the DataStack and ReturnStack can not be shared, so a new pair of arrays with unique names are required for each cog. create cogstack 80 allot \ 80 is in bytes, so this is actually 20 longs create returnstack 80 allot \ 80 is in bytes, so this is actually 20 longs {Note -- Previously, I was confused and thought the Data and Return Stacks were inside the cog. The binary of the Forth machine is inside each Cog with serial i/o, but the Data and Return Stacks are in the Dictionary space and can be made smaller or larger as required. The serial i/o code exists in each cog, but sits dormant and unused as there is no simple way to reach it without conflicting with the one cog that the user interface is using. One could get fancy and use it by some modifications to the .spin file. But please leave that for more advanced study as a separate topic.} B. Provide Forth code that is specific to the cog you desire to use. {This is where the toggle code that was included in the example mentioned would be replaced, along with a delaycnt constant which was required. Replace with your new code and any constants and variables.} C. Provide a proper cogconfiguration to be read by Cognew. This is an array of five items that are always required to start the pfth Forth binary. {Note that the apostrophe and comma are significant Forth words and very important to properly setting up this array. Starting Forth by Leo Brodie explains them. The body> word finds address of the useful code in the Toggle word which is not the same as the address for the name Toggle itself, so we are provided with this word to find the body of the word Toggle after we find the location of its name.} create cogconfig ' toggle >body , cogstack , cogstack , cogreturn , cogreturn , D. Use Cognew to start up the Forth code in a defined Forth word : starttoggle forth @ cogconfig cognew ; { Forth simply is a variable that provides the address pointer of the beginning of the Forth binary that is going to be copied into another cog by cognew. @ pops it off the stack for ready use. cogconfig is unique to just this new cog. If you want to start more cogs, another name needs to be used for another additional cog. Cognew locates and inactive cog evokes the PASM Cognew installation. } Further thoughts. Propeller PASM and pfth also provide Coginit, which will allow you to desigante which Cog you want to install and start. But unlike Cognew, it can overwrite a running cog. And unlike Cognew, it requires you also to provide a number from 0 to 7 for it to run. CogInit can be used instead of CogNew, but the programmer has to be a bit more careful to properly use it. When starting a lot of cogs, the names can get messy if you are not careful. The choice of using CogNew versus CogInit tends to be related to the temporary use of cogs. The example proivded in Toggle.fth is an infinite loop, but the user may use CogStop inside a Forth word to release the cog after the task is done. The cleanest way to stop a cog is to have the main routine on that cog first call CogID and then CogStop. Since these are running inside the the started cog, the ID number is correctly placed on the stack for CogStop. This is a Very Powerful tool that allows the user to create complex programs that activate and deactivate cogs very quickly. By using CogNew and CogStop together, there seems to be few cases where CogInit is required with its additional requirment that the program track which cogs are active. ~~~~~ For Data Stack and Return Stack, it might be best to use lettered pairs, cogstackA and returnstackA, cogstackB and returnstackB, and so on if you are starting several subsidiary cogs. And the same goes for Cogconfig, it might be best to use CogconfigA, CogconfigB, and so on. Be tidy and the code will be easier to work with.