Multi-Memory Model (MMM) support. ================================= MMM is new for Catalina 4.1. It allows the Propeller to simultaneously execute LMM, CMM and XMM or NMM Catalina programs. Each program is executed on a separate cog and essentially runs independently. However, all programs share the same registry and all programs can use any of the loaded plugins. There is only one program binary, which contains all the programs. When this binary is loaded and started, it starts the "primary" program, which must explicitly start each of the "secondary" programs, which are stored either in the memory space of the primary program (useful if you have XMM RAM) or on SD Card (useful if you do not have XMM RAM), and only loaded into Hub RAM when they are to be executed. For this reason, on the Propeller 1, MMM is generally most useful when the primary program is an XMM (SMALL or LARGE) program, otherwise it is wasteful of precious Hub RAM. On the Propeller 2, the best option is to store the secondary programs on the SD Card. In either case, the secondary programs will then use no precious Hub RAM until executed by the primary program. Each secondary program can share a variable with the primary program - this variable can either be a simple variable or a structure, if a single variable is not sufficient. Each secondary program can use a different variable, or they can all share the same variable. The compilation process for MMM requires that each secondary program be compiled first, as either a TINY (LMM), COMPACT (CMM) or (on the Propeller 2) a NATIVE (NMM) program, with all the usual command-line options, plus the following additional options: -R XXXXXX -C NO_ARGS -M64k A binary file must be generated for each secondary program. However, this binary is not executed directly - it must be processed for inclusion either as an array in the primary program or as an overlay file that can be loaded off SD Card by the primary program. This is done using an updated version of the 'spinc' utility. The XXXXXX value represents the address at which the secondary program is to be loaded for execution, and must be determined according to the size of each secondary program, its run-time space requirements, and also by the necessity to not interfere with the reserved memory at the top of Hub RAM - i.e. the registry, cache, plugin data etc. This value may have to be established partly by trial and error, but it can also be done by simply reserving a suitable amount of Hub RAM as a local variable in the main function of the primary program, determining where the Hub RAM address of that local variable is, and then using that value for the -R parameter. An example of doing this is provided in the Multi-Memory Model demo programs. The -C NO_ARGS is required to disable the usual C command-line argument processing in the secondary program (but not the primary program). Command-line arguments are not supported for secondary programs that are to be dynamically loaded, and it would also interfere with the passing of the parameter that specifies the shared variable address from the primary program to the secondary program. On the Propeller 1, the -M64k option may be required to allow CMM or LMM code to be compiled in areas of upper Hub RAM that would not normally be permitted for primary program code, but are permitted for secondary programs. Without this option, specifying a -R option in high Hub RAM can make the secondary program's binary size exceed the usual 32k limit - which is not normally supported for LMM or CMM programs on the Propeller 1, but is for secondary programs that are to be dynamically loaded. There is no problem in simply always including this option when compiling programs intended to be dynamically loaded on the Propeller 1. The -M option is not required on the Propeller 2. To run MULTIPLE subsidiaries simultaneously you must calculate a different value of XXXXXX for each secondary, and ensure they will not overlap when loaded. The runtime size of each secondary can be determined as described below. Each secondary program must be compiled and then turned into a "blob" (i.e. a "binary large object", or "binary loadable object") for inclusion in the primary program. The blob can be an array in the include file generated by spinc, or as a separate binary file. Producing an array blob: ======================== Building a blob as an array in an include file on the Propeller 1 is done using an updated version of the "spinc" utility, using a new command-line option (-B). For example: spinc -B2 -c secondary_1.binary >blob_1.inc spinc -B2 -c secondary_2.binary >blob_2.inc (etc) The new option (-B) specifies that a blob is to be created from one of the objects in the binary. It accepts a parameter to specify the object number, which (for Catalina Propeller 1 binaries) should generally be the SECOND object within the binary. For Catalina binaries the second object will be Catalina.spin - i.e. the object produced by the Catalina compiler from the C source code. So this option should (currently) always be specified as -B2. Building a blob on the Propeller 2 is also done using the "spinc" utility, but using an additional -p2 command-line option to specify that the binary file being processed is a Propeller 2 binary (i.e. -B2 -p2). For example: spinc -B2 -p2 -c secondary_1.binary >blob_1.inc spinc -B2 -p2 -c secondary_2.binary >blob_2.inc The parameter to the -B option is not currently used on the Propeller 2, but it is recommended it always be specified as 2. The -c option specifies that a suitable 'start' function will be generated in the include file, suitable for starting the C program from the primary program. The name used for the function will be the name of the binary (i.e. "start_<>"). This can be overridden using the -n option if required (for instance, if you are generating multiple loadable programs from the same secondary binary). So, for example, if your binary file name is hello_world.binary, the start program generated would be: int start_hello_world(void* var_addr, int cog) This function accepts the address of a shared variable and a cog number on which the secondary program will be run (which can be the special constant ANY_COG). The function will return the actual cog number used, which can be used later to stop the secondary program. If the object cannot be found or does not have the correct type (it must be an LMM or CMM object on the Propeller 1, or an LMM, CMM or NMM object on the Propeller 2) then an error message will be issued. Additional runtime space to be allocated for the blob can be specified using the -s option. If no size is specified, 80 bytes (20 longs) is the default. For example, to instead specify run-time space of 200 bytes (50 longs): spinc -B 2 -s 200 -n my_blob secondary.binary >blob.inc As shown above, the -n option can be used to specify a name for the secondary, otherwise the binary file name is used. This name will be used for the start function, the blob itself, and all the constants defined for the blob. The output is a C source file, suitable for inclusion in the primary program. This process must be repeated for each secondary program (each one must have a unique name, even if the same binary is used to create them). For examples of producing and loading blobs, see the demos\multimodel directory. Multi-Memory Models and Multi-threading ======================================= The new Multi-Memory Model support works with the existing multi-threading support, but things can get a little complicated. First of all, note that if a primary or secondary program is multi-threaded, then ALL the dynamic kernels started by that program using the existing _thread_cog() function or the new _threadstart_C() functions will also be multi-threaded, and use the same memory model. However, threads cannot be shared between primary and secondary programs. So while each primary or secondary program can share threads with any kernels they start using the _thread_cog() or _threadstart_C() functions, they cannot share threads with other primary or secondary kernels started with the new multi-model start functions, even if the programs are identical and use the same memory model. Each primary and secondary program (and any additional kernels they start) constitute a separate and isolated "world" as far as threads are concerned. However, it is perfectly feasible for a threaded primary program to start a non-threaded secondary program, or vice versa. To facilitate this, additional threaded start functions have been added to explicitly start a secondary program as a multi-threaded program, corresponding to the various _cogstart functions: On the Propeller 1 and Propeller 2: _threaded_cogstart_CMM_cog() - start a blob as a threaded CMM program on a specific cog _threaded_cogstart_LMM_cog() - start a blob as a threaded LMM program on a specific cog On the Propeller 2 only: _threaded_cogstart_NMM_cog() - start a blob as a threaded NMM program on a specific cog Since the most likely case is that the primary and secondary programs will both be threaded, or both be non-threaded, by default the spinc utility will use the threaded or non-threaded start functions based on whether the primary program is threaded or non-threaded. However, if your primary program is threaded and your secondary program is not (or vice-versa) then you can override the default using one of two methods: 1. You can manually specify which start function to use using the -f command-line option to the spinc utility. For example, to specify the non-threaded start function be used, even though the primary program is threaded: catalina -lc -C NO_ARGS secondary.c spinc -B2 -f _cogstart_LMM_cog -c secondary.bin >secondary.inc catalina -lc -lthreads primary.c Or, to specify the threaded start function be used, even though the primary program is non-threaded: catalina -lc -lthreads -C NO_ARGS secondary.c spinc -B2 -f _threaded_cogstart_LMM_cog -c secondary.bin >secondary.inc catalina -lc primary.c See the build_all script in the demos\multimodel directory, and the instructions for building run_dining_philosophers.c for an example of this method. 2. You can specify which start function to use in the program itself, by defining one of the following two symbols prior to including the output of the spinc utility: #define COGSTART_THREADED /* use threaded start functions */ Or #define COGSTART_NON_THREADED /* use non-threaded start functions */ See the file "run_dining_philosophers.c" in the demos\multimodel directory for an example of this method. Note that the use of the first method (described above) overrides the use of this second method. Multi-Memory Models and Overlays ================================ When using XMM modes on the Propeller 1, it makes perfect sense to create secondary programs in XMM RAM and use them as "overlays". The secondary programs occupy no valuable Hub RAM until they are needed. When they are needed they are loaded from XMM RAM into Hub RAM for execution, and they can be terminated and the same Hub RAM used for other purposes - such as loading another secondary program. However, Catalina (as yet) does not support XMM RAM on the Propeller 2, which means all secondary programs would exist in Hub RAM even when not being used. Worse, when they are executed, TWO copies of the programs will exist in Hub RAM, since the blob must be copied to the Hub RAM location it was compiled at for execution. This would seem to make multi-memory model support somewhat less useful on the Propeller 2 than on the Propeller 1. However, Catalina also allows programs to load overlays from files on an SD Card. This is supported on both the Propeller 1 and the Propeller 2. Producing a file blob: ====================== To make use of the MMM feature to load overlays from a file, the spinc program is used with a new option specified (-o 'name'), which will generate an output file (called 'name') containing the binary blob instead of an array. Using this option will also generate a start function that will load the blob from the named file at run time. For example: For a non-threaded overlay: catalina -lc -R 0x4000 -C NO_ARGS secondary.c spinc -B2 secondary.bin -o blob.ovl >secondary.inc catalina -lcx primary.c For a threaded overlay: catalina -lc -lthreads -R 0x4000 -C NO_ARGS secondary.c spinc -B2 -f _threaded_cogstart_LMM_cog secondary.bin -o blob.ovl >secondary.inc catalina -lcx -lthreads primary.c Note that an include file is still generated, and must still be included in the primary program even though the blob itself is written to the overlay file. The include file contains the start function that will load the blob from the named file on the SD Card at run-time. Of course, the primary program must be built with an SD Card file system to be able to load the overlays (in the cases above, this is accomplished by linking with the extended libraries via the -lcx command line option), and that the overlay files must exist on an SD Card which is inserted into the Propeller when the primary program is started (in the examples above, that file will be called 'blob.ovl'). An overlay file is not a normal Catalina binary - it is just the code and initialized data segments of the secondary program. The secondary program must be compiled to run at the correct address when loaded, and the start function will load the overlay file into this location in Hub RAM. A simple example of overlays is included in the demos\multimodel directory.