Subject: How to create another running Cog in pfth (substantial revision) DATE: Sat 25 Jan 2014 03:45:56 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 and to verify which cogs are active by using CogStop to shut down designated cogs. Reading the Propeller Manual for sections in PASM on starting and stopping cogs is also helpful, but not of critical importance if the users feels PASM code is beyond their abilities. Consider this as simply an introduction to a few PASM instructions deployed in Forth. It is best to explore the use of the Toggle.fth code to verify that an independent cog is working, how an independent cog works AND then to read the PASM sections of the Propeller Manual ver 1.20 for what is required to stop and start cogs. See the text sections on CogNew, CogInit, CogStop, and CogId as the Forth are merely direct calls to the PASM machine code. Such direct calls to PASM provide useful insight in how to reach non-ANSI Forth features in the Propeller. This pfth code is very close to the PASM in terms of what it requires for operation. Reading the PASM pfth code in the .spin file for its Forth kernel which starts at the "org 0" line and ends at the "fit $1f0" line can be useful. The first 10 or 11 lines after "org 0" involve the passing of 4 parameters to link the Data Stack and Return Stack (in hubram) to the Forth Kernel in Cogram. To start a new cog, four parameters -- the stactptr, stackptr0, returnptr, and returnptr0 are required and CREATE is used to designate a separate DataStack and ReturnStack as variable arrays, while CREATE COGCONFIGURE ...' sets up the right information for CogNew to call. If CogInit is used, which the addition of which cog needs to be designated before it is called, so this example may need modification. So Cognew requires just four parameters of which two the empty DataStack address (for stackptr and stackptr0, which represent the Top of Stack and the active stack postition) and two are the empty ReturnStack address (for returnptr and returnptr0, used similarly). Since the actual hubram addresses are passed, the changeover in names in .spin to different Forth names does not affect anything. StartToggle versus Toggle 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 that can be started from any cog, not just the one attached directly to the active serial terminal. 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). Tracking which cogs are active At first, it may be a bit unclear to you which cogs are active. At startup, the Propeller always uses Cog 0 temporarily with Spin interpreter software to load the other cogs as required, so pfth's first 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 pfth has become active on Cog 1 and Cog 0 is free to use along with Cogs 2-7. You can identify your active interfacing cog in pfth with the word CogId. In this case it is Cog 1. But is will not show you all the active cogs because they are independent of the terminal interface in Cog 1. Starttoggle will start with the lowest available cog, in this case Cog 0; but that can only be verified destructively by using CogStop as CogId -- in this context -- only works for the one Cog that is linked to your serial i/o. You may use CogStop to turn off the active StartToggle on Cog 0 that was started with Starttoggle or to crash the terminal on Cog 1. Use of CogId from the terminal is very different that its use from within a Forth word that starts another Cog. To use CogStop within a Forth definition, you must always first provide a Cog number, and CogId is the means to provide it. This feature allows you to deploy a task to a separate cog in Forth and then to abandoned the cog after the tast is completed. Toggle.fth only shows example cog for an infinite loop use. One can stop infinite loops use, but has to either know or search for the active Cog number. 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. Avoid stopping Cog 1 as everything will be shut out of communications. 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 as a user interface feature it would have to be created in software as an overlay that monitors CogNew, CogStop, and CogInit activity. 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 as Cog 1 is occupied with running the infinite blink loop. The only way out is to reset the Propeller. You cannot use CogStop to cease direct operation of Toggle because this is on Cog 1 and you no longer have the keyboard input due to the infinite loop. To repeat, 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 externally from a cog that has the interpreter interface active. pfth currently only provides the active interface in Cog 1. The wise thing to do is to retain Cog 1 for a master control of other cogs from your serial terminal keyboard AND to avoid using it for an infinite loop. General concepts So how does one write code to achieve this in general? A. Establish two arrays to describe the Data Stack and Return Stack space in HubRam within the Forth Dictionary space. 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 for each in the Forth dictionary space for one of each for each cog you start up. Pfth already did so for the first cog. Each stack has two parameters, the top of stack and the currently active stack position. So the create a new cog has four entries, not merely two. If you want to run more than one cog, the DataStack and ReturnStack can NOT be shared by other cogs, so a new pair of arrays with unique names are required for each new cog. create cogstack 80 allot \ 80 is in bytes, actually 20 longs/40 words create returnstack 80 allot \ 80 is in bytes, actually 20 longs/40 words {Note -- Previously, I was confused and thought the Data and Return Stacks were inside the cog. Disregard any documents that claim such.} What is inside each cog? The compiled PASM cog between Org 0 and Fit $190. If you desire to study the pfth Kernel's PASM code, find this section of the .spin file to read. The additional .spin code is about creating and loading the Forth Dictionary into Hubram. The binary of the Forth Kernel is inside each Cog including serial i/o, while the Data and Return Stacks are in the Dictionary space and can be made smaller or larger as required by a project. While the serial i/o code exists in each cog, under this scheme it 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. Since the Forth kernel works fine inspite of this waste of code space within the Cog, there is no reason to remove this, and doing so would requre have a special second cog image retained in hubram. That would actually waste up to 2K of additional hubram. So this is simply a tradeoff between utility of a feature and ram resources. One might get fancy and use other serial i/o by some modifications to the .spin file. But please leave that for more advanced study as a separate topic when a real need arises. (But I cannot actually see any real need evolving.) B. Provide Forth code that is specific to the cog you desire to use. Such code is global and could be used on any cog. In some cases that is useful to avoid unnecessary duplication of useful code. {This is where the toggle code that was included in the example mentioned would be replaced by your desired project.} C. Provide a proper cog configuration to be read by Cognew. This is a Forth word to configure the startup of the cog. But the rest of the words created are global, even though they may not be globally useful. This is a special case for starting another cog, but the same words (CREATE, FORTH, body>, , and can do other useful things and are high-power lower-level Forth words intended for more sophisticated dictionary entries. And though, we have only discussed starting other cogs from the Terminal keyboard, code used in any cog might start another cog or you can establish an automatic run that deploys on power up. COGCONFIG is an array of five items that are always required to start the pfth hubram binary in another cog. {Note that the apostrophe and comma are significant Forth words and very important to properly setting up this array. 'Starting Forth' by Leo Brodie and other ANS Forth texts explains them. FORTH may be unique to pfth for starting cogs. } The body> word finds the address of the useful code within the Toggle word definition 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 , Multiple active cogs If you are going to start more than one additional cog, cogconfig needs to be modified to cogconfig_A, cogconfig_B, and so on. D. Use Cognew to start up the Forth code in a defined Forth word : starttoggle forth @ cogconfig cognew ; {FORTH simply 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 a unique configuration 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. If the program scheme is to start and many cogs with Forth tasks, CogNew permits the Propeller to manage the selection of an available cog. When starting a lot of cogs, the names can get messy if you are not careful. It may be best to avoid CogInit. Cognew and Coginit are Very Powerful tools that allow the user to create complex programs that activate and deactivate cogs very quickly. Using CogNew and CogID, CogStop properly together, seems eliminate the need to use CogInit and tracking active cogs to avoid potential crashes. ~~~~~ 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. Similarities in names can be helful, but at times may lead to great confusion. When in doubt, revise your lexicon. Often similarities in Forth word names make debugging harder.