Ok it is true that at this point OCC would take some extra work to retarget, as to the cross compiler issue it should be fairly simple to have a different target from the host. I think his goal is to have a fully optimizing variant of his CC68K/CC386. I should note that CC68K/CC386 can be recompiled fairly easily to run on 68k systems. see: http://ladsoft.tripod.com/ .
This will build XMM.binary with both the verification checks enabled:
WRITE_CHECK : read back after each Flash write and verify it. Rety up to 10 times on failure.
ERASE_CHECK : read back the entire Flash after erase. Retry up to 3 times on failure.
See if this improves your ability to load Flash programs correctly. Note that the ERASE_CHECK can take up to 15 seconds, so if you enable it you will have to use at least -t 4000 on your payload command (maybe even longer) - e.g, use a command like:
payload XMM bin\xbasic.binary -t 4000
Just enabling the WRITE_CHECK should not slow things down too much (unless it finds lots of failures).
I can't really check this as my C3 never seems to have a problem, so please let me know how it goes on yours.
Thanks for the new version with ERASE_CHECK and WRITE_CHECK. I'm assuming that it would display error messages if either check fails, right? Well, I've now run it three times in a row and gotten no errors and xbasic loaded and started fine. I haven't used my C3 in about a week though so maybe my problems have to do with leaving the C3 powered on constantly. I'll leave it on during the day today and try it again later. So it seems my problems have magically disappeared. I hate it when that happens! :-)
Did you use jazzed's JCACHE interface when you implemented the Catalina cache code? I'm trying to figure out if we can just substitute a different implementation of the JCACHE interface to get a new cached board working with Catalina.
I am really really sorry about this, but plugins to me are completely unintelligible. I don't know what it is - but I think there is a critical mass of terms in each explanation and each term assumes understanding of another term and as a group I just can't pull it together.
I am sorry but I could not decode the mouse driver. I ended up using the spin cogject, as it was simply a matter of loading it and then reading off 3 variables - par is x, par+1 is y and par+3 is the button status. This is now driving the GUI to the point you can click on a button with a mouse pointer (same bitmap as a windows pointer) and it then runs some code.
But I need to really focus on the plugin needed to stop Catalina. I either have to understand this or abandon the hardware for an SPI or I2C solution. It really comes down (I think) to two lines of code:
1) Stop Catalina
2) write a value to a long to restart Catalina.
First, here is the explanation that I can't understand.
It's much simpler than that. I posted earlier an example of code that will "pause" Catalina. I used the HMI plugin as an example, and posted the code that results from a t_char function call - specifically:
Code:
int _short_plugin_request (long plugin_type, long code, long param) {
return _sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF));
}
Any Catalina program that makes any _sys_plugin service request is "paused" in the _sys_plugin call itself until the plugin it calls tells it that it can continue. The parameter to the request (in this case (code<<24)+param & 0x00FFFFFF) ) is placed into the registry request block that belongs to the plugin with type plugin_type (in this case that would have to be LMM_HMI - see the plugin types defined in catalina_plugin.h). Specifically, the parameter is written to the request long of the request block, and if the plugin needs to return a result, it should be written to the response long.
The request value written must always be non-zero. All plugins must (at least occasionally) check their request long. The plugin can do whatever it likes with the request, but when it wants the kernel to continue from its paused state it does so by by writing a zero into the request long. Normally this indicates the request is complete, but this is not necessarilly the case - the plugin can carry on processing the request after it has allowed the kernel to continue if it needs to.
Note that you can also make a service call to a specific cog - just set bit 8 in the first parameter to the _sys_plugin function call - e.g:
Code:
int _cog_plugin_request (long cog, long code, long param) {
return _sys_plugin (cog + 0x80, (code<<24) + (param & 0x00FFFFFF));
}
I allow this to cater for cases where there may multiple instances of the same plugin type running.
Quote Originally Posted by Dr_Acula View Post
Once Catalina is paused, I am assuming that there is a location somewhere in hub ram where a cog can change a variable to restart Catalina.
Yes - as described above, this is the first long of the request block assigned to the plugin. Set it to zero to restart the kernel that made the service request
Taking that one line at a time
int _short_plugin_request (long plugin_type, long code, long param) {
return _sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF));
}
What values do I pass to:
1) "plugin_type"
2) "code"
3) "param"
For the purposes of just shutting down catalina and restarting it, there are no return values, so I'm not sure what the "return" value is going to be - as I understand it, Catalina is going to hang at this point, so if it gets to "return" then it restarted, and if it doesn't get there, then the cog didn't run, and there is no need to return any values as Catalina is no longer running. For this ultra simple demo, is this the correct logic?
Regarding the location of the value that the cog needs to change, you say
Yes - as described above, this is the first long of the request block assigned to the plugin
Is this any of 1), 2) or 3) above?
I am really sorry I can't understand plugins. One of the problems with writing any cog code is the whole debugging sequence, which I'm sure most authors don't tend to describe in every single step. For me, I am finding it easier to break every piece of cog code down into pieces, and the first part is to get it working from Spin, and then port the cogject code over to C. I described the process of creating a Spin Cogject over on another thread, and it is 20 discrete steps and every single one of those has to work (usually without much debugging help) before cog code will work. Creating plugins adds another couple of steps at least, as there is additional code to add in the cog to interface to the plugin.
But to me there seem to be too many variables to tackle at once. Consider:
The parameter to the request (in this case (code<<24)+param & 0x00FFFFFF) ) is placed into the registry request block that belongs to the plugin with type plugin_type (in this case that would have to be LMM_HMI - see the plugin types defined in catalina_plugin.h). Specifically, the parameter is written to the request long of the request block, and if the plugin needs to return a result, it should be written to the response long.
What is the "registry request block" and how does one find it in C?
Why is LMM_HMI mentioned? Does this imply that there are different methods for interfacing to plugins depending on whether one uses LMM or XMM?
I am wondering if it is possible to break this down to something much simpler.
Start a cog with some code. Pass a value via par which points to a group of plugin longs.
Stop Catalina
Write a (I think) zero to a hub location (par +/- n) which will restart Catalina.
Would it be possible to provide some C code to do this, and maybe pasm as well? I am fairly sure the pasm code will only a few lines - collect 'par', add a value, and do a 'wrlong' of zero to this location.
Thanks for the new version with ERASE_CHECK and WRITE_CHECK. I'm assuming that it would display error messages if either check fails, right? Well, I've now run it three times in a row and gotten no errors and xbasic loaded and started fine. I haven't used my C3 in about a week though so maybe my problems have to do with leaving the C3 powered on constantly. I'll leave it on during the day today and try it again later. So it seems my problems have magically disappeared. I hate it when that happens! :-)
Thanks,
David
Hi David,
Me too :frown:!
No, there is currently no indication when things fail. I'll think about how to add a return status that payload could display. I just didn't want to mess with the payload protocol unless I had to.
Did you use jazzed's JCACHE interface when you implemented the Catalina cache code? I'm trying to figure out if we can just substitute a different implementation of the JCACHE interface to get a new cached board working with Catalina.
Thanks,
David
Hi David,
I'm not sure, since but I couldn't find any documentation on the JCACHE interface. Can you point me to a definition?
My object uses the PASM interface implemented in Jazzed's SdramCache.spin module. Is JCACHE the SPIN interface implemented in this module? If so, you just need to add a slightly modified Spin wrapper around my PASM implementation to get the same interface.
I'm not sure, since but I couldn't find any documentation on the JCACHE interface. Can you point me to a definition?
My object uses the PASM interface implemented in Jazzed's SdramCache.spin module. Is JCACHE the SPIN interface implemented in this module? If so, you just need to add a slightly modified Spin wrapper around my PASM implementation to get the same interface.
Ross.
We shouldn't need any Spin code should we? ZOG just interfaces with a JCACHE cache driver using the mailbox protocol. If you've implemented the same mailbox protocol we should be able to substitute a different implementation and it should work with Catalina, right?
I am really really sorry about this, but plugins to me are completely unintelligible. I don't know what it is - but I think there is a critical mass of terms in each explanation and each term assumes understanding of another term and as a group I just can't pull it together.
No worries, Dr_A - if you are having trouble then no doubt others will as well. I'll persevere until it becomes clear
I am sorry but I could not decode the mouse driver. I ended up using the spin cogject, as it was simply a matter of loading it and then reading off 3 variables - par is x, par+1 is y and par+3 is the button status. This is now driving the GUI to the point you can click on a button with a mouse pointer (same bitmap as a windows pointer) and it then runs some code.
But I need to really focus on the plugin needed to stop Catalina.
Hmmm. You can't "stop" Catalina - you can't even ask it to "pause" - Catalina has to do the "pausing" - by making a plugin service request.
Perhaps this is the crux of the misunderstanding. You don't stop Catalina - that would be akin to stopping the SPIN interpreter but then expecting to communicate with the Spin program it was executing. It works the other way round - i.e. Catalina pauses itself whenever it makes a _sys_request call.
Another cog can certainly do work asynchrously from the Catalina program, but if it is a plugin, then it should still monitor the regsistry occasionally to see if Catalina wants to talk to it - it can't "interrupt" Catalina whenever it wants to.
However, if this is not a suitable mechanism, then there are other ways a plugin can send data back to Catalina - e.g. it can communicate via a specified memory location, passed to it by Catalina during initialization. This is how (for example) the serial IO plugin works.
I either have to understand this or abandon the hardware for an SPI or I2C solution.
First of all, I should say that what you are doing is perfectly fine - you don't need to use plugins - if what you are doing works for you, then just carry on doing it. Plugins would just make it easier for you to interact between your cogjects and Catalina. But if you can't use plugins, you can always use locks and/or Hub RAM to synchronize Catalina with your cogjects. The downside is that it will make your C programs more complex - but while this would bother me, it may not bother you!. However, it would certainly help you decide if you understood plugins better, so I'll carry on explaining them as long as you want - I never tire of hearing the sound of my own typing.
It really comes down (I think) to two lines of code:
1) Stop Catalina
2) write a value to a long to restart Catalina.
First, here is the explanation that I can't understand.
Taking that one line at a time
int _short_plugin_request (long plugin_type, long code, long param) {
return _sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF));
}
What values do I pass to:
1) "plugin_type"
2) "code"
3) "param"
The "plugin_type" is the type of plugin you are trying to send your service request to - these are defined in Catalina_Common.spin. For example, the type for a HMI plugin is LMM_HMI. In this parameter you can also pass a cog number by adding 0x80 to it - e.g. 0x80 + 7 for cog 7.
The "code" is just a constant number that you and the plugin agree to use to represent a specific service. For example, the codes for the services implemented by all the HMI plugins are the same - here are the ones for the mouse services:
'---------------------------------------------------------
' Mouse services:
'
'name: m_present
'code: 11
'type: short request
'data: (none)
'rslt: 0 = not present, > 0 = present
'name: m_button
'code: 12
'type: short request
'data: button = 0, 1, 2, 3, 4
'rslt: 0 = not pressed, > 0 = pressed
'name: m_buttons
'code: 13
'type: short request
'data: (none)
'rslt: 0 = not pressed, > 0 = pressed
'name: m_abs_x
'code: 14
'type: short request
'data: (none)
'rslt: absolute x value
'name: m_abs_y
'code: 15
'type: short request
'data: (none)
'rslt: absolute y value
'name: m_abs_z
'code: 16
'type: short request
'data: (none)
'rslt: absolute z value
'name: m_delta_x
'code: 17
'type: short request
'data: (none)
'rslt: absolute x value
'name: m_delta_y
'code: 18
'type: short request
'data: (none)
'rslt: absolute y value
'name: m_delta_z
'code: 19
'type: short request
'data: (none)
'rslt: absolute z value
'name: m_reset
'code: 20
'type: short request
'data: (none)
'rslt: 0
The "param" is what is identified as "data" in the list above - often it is nothing, since specifying the service itself is enough.
These services should look familiar to you if you have looked at the existing Parallax mouse drivers - but it is important to understand that Catalina uses the existing Parallax mouse, keyboard and screen drivers - but these are not themselves plugins!- to use them from Catalina you must call them via the HMI plugin, which provides the standard "plugin" interface to all the various underlying drivers - VGA drivers or TV drivers, Hydra mouse driver or Propterminal mouse driver etc etc. This interface replaces (and in some cases enhances) what the SPIN part of each of these drivers normally does - that's the main purpose of the HMI plugin.
In this case, we are now discussing the development of a stand-alone mouse plugin - this is fine, and I could have taken this approach (i.e. rewrite each driver as a separate plugin). The main reason I don't do things this way is that you then have to develop a different plugin for each type of driver for each platform. There is also the problem that each of these drivers (at least the ones in the OBEX) offer a slightly different set of services - and this means users would have to write different C code to use each one. This would kind of spoil the point of having an an ANSI C compiler!
For the purposes of just shutting down catalina and restarting it, there are no return values, so I'm not sure what the "return" value is going to be - as I understand it, Catalina is going to hang at this point, so if it gets to "return" then it restarted, and if it doesn't get there, then the cog didn't run, and there is no need to return any values as Catalina is no longer running. For this ultra simple demo, is this the correct logic?
You are not shutting down Catalina and restarting it. Catalina sits in a busy-wait loop, waiting for you to tell it to continue. And there are return values - you write them to the registry long after the one you read the service request from. But it is true that a simple demo probably won't need to use them.
Regarding the location of the value that the cog needs to change, you say
Is this any of 1), 2) or 3) above?
No - the registry is what you are looking for - and the registry tells you where to write those values for each plugin - but you don't have to figure this out for yourself - this is done for you by the internals of the _sys_plugin function.
It is slightly different on the plugin side of the interface. The common registry address is passed to each plugin on startup. From that address, the plugin can figure out the address of its own request block - which contains (normally) only two longs - a long for requests and a long for return values. Figuring this out is not very difficult - it only takes a few PASM instructions - one of which is to fetch your own cog id.
For example, this is code to figure out your registry block from within a plugin - you will see code like this at the beginning of all plugins:
entry
cogid t1 ' get ...
shl t1,#2 ' ... our ...
add t1,par ' ... registry entry
rdlong rqstptr,t1 ' get our ...
and rqstptr,low_24 ' ... request block from that entry
Some plugins then go on to register themselves, whereas others expect this to have been done for them by the Spin code that started them. If you expect to unload and reload the plugin, you need to decide whether the plugin should register itself, or whether you will do it from C.
I am really sorry I can't understand plugins. One of the problems with writing any cog code is the whole debugging sequence, which I'm sure most authors don't tend to describe in every single step. For me, I am finding it easier to break every piece of cog code down into pieces, and the first part is to get it working from Spin, and then port the cogject code over to C. I described the process of creating a Spin Cogject over on another thread, and it is 20 discrete steps and every single one of those has to work (usually without much debugging help) before cog code will work. Creating plugins adds another couple of steps at least, as there is additional code to add in the cog to interface to the plugin.
But to me there seem to be too many variables to tackle at once. Consider:
What is the "registry request block" and how does one find it in C?
From C, you don't mormally need to - see above. But you can if you want to - there is a function called _registry that will return the common registry address, and a macro called REQUEST_BLOCK that you can use to retrieve a specific cog request block - e.g REQUEST_BLOCK(7)
Why is LMM_HMI mentioned? Does this imply that there are different methods for interfacing to plugins depending on whether one uses LMM or XMM?
You need to give _sys_plugin a means of finding the plugin you are trying to call - either by type or by cog id. LMM_HMI is just the type of the plugin. Sorry about the LMM_ bit - I defined these before XMM mode was even thought of - maybe I should rename them all PLUGIN_ or something.
I am wondering if it is possible to break this down to something much simpler.
Start a cog with some code. Pass a value via par which points to a group of plugin longs.
Stop Catalina
Write a (I think) zero to a hub location (par +/- n) which will restart Catalina.
Would it be possible to provide some C code to do this, and maybe pasm as well? I am fairly sure the pasm code will only a few lines - collect 'par', add a value, and do a 'wrlong' of zero to this location.
But what would the C code look like?
This is exaclty the purpose of the various demo programs in the custom_demo directory!
I think the problem is you are trying to do too much at once - start with the generic Catalina_plugin.spin (in the custom target directory) and the simple_example.c program that uses it (in the custom_demo directory).
Once you understand that example everything else should fall into place. Perhaps you could then look at one of the stand-alone plugins such as the clock plugin. Then look at the HMI plugins - which are the most complex of all.
We shouldn't need any Spin code should we? ZOG just interfaces with a JCACHE cache driver using the mailbox protocol. If you've implemented the same mailbox protocol we should be able to substitute a different implementation and it should work with Catalina, right?
Hi David (& Jazzed)
Yes, from Jazzed's explanation, it seems I am implementing the correct mailbox protocol. I think the only difference is that my startup routine differs, since my mailbox address is fixed (e.g. XMM_CACHE_CMD in Catalina_Common.spin - currently $7FF4 - is used for all operations).
Ok. It differs according to the memory model and segment layout being used - but for Flash programs you only need to worrry about two of the seven supported layouts - for programs that are to be stored in Flash, layout 3 is used for LARGE programs, and layout 4 is used for SMALL programs.
Basically, the difference is that layout 3 arranges the segments as (init,data,code,cnst) and layout 4 arranges them as (cnst,init,data,code).
When LARGE programs are stored in Flash, the code and cnst segments are stored at their correct addresses for execution. Then, starting on the next sector boundary (i.e. hex $200 boundary) I store the sectors containing the init & data segments.
When SMALL programs are stored in Flash, the code segment is stored at its correct address for execution, then (again on the next sector boundary) I store the sectors containins the cnst, init & data segments.
The segments embedded in the stored sectors need to be relocated before the program can be run - this is the job of the Hub Flash loader, which is loaded into Hub RAM for execution once the Flash programming is complete. Alternatively, it can be run from EEPROM (this is really the main part of the Flash_Boot program - the remainder simply loads various device drivers the program might need).
I don't bother fully decoding the sectors containing the segments that need to be relocated - I just store them as they arrive serially, or as they are read from the SD card. This simplifies the process of storing them in Flash quite significantly, and allows the loader to fit it into a single cog. The Hub Flash loader will later extract and relocate the actual segments from the stored sectors - either to SPI RAM (LARGE) or Hub RAM (SMALL).
The segment layout being used and segment table itself is always stored in the first sector of the code segment. You'll see this referred to in the code as the "prologue". You need to use this information to figure out where in the binary data stream the segments start and finish. Interpreting the values in this table is also layout dependent - for examples of how to do this, see the code starting around line 2455 of the catbind program.
Ross.
I'm finally getting to this and I'd like to ask a few more questions to clarify how things are arranged in flash.
For LARGE programs you say that "code and cnst segments are stored at their correct addresses for execution". What does this mean? Does this mean that they are stored starting at flash address zero?
You talk about segments needing relocation but that is handled by the Flash_Boot.binary code, right? I don't need to worry about that if I'm just trying to write the flash image.
Yes you are right about the pausing vs stopping. What I want to do is allow a cog to gain access to pins P0-11while catalina is running in XMM mode. So this needs to put catalina into a loop, and when the cog has finished with those pins, it puts a zero into a hub location and catalina keeps going.
Will this pause catalina? I am not passing any parameters but I don't know if the default for "param" is zero or some other value. But what values should "plugin_type" and "code" be?
Also, what state will catalina leave those pins when it is paused? ie, if it does get a "pause" command, does it run an instruction to put all the pins high (or low, or HiZ), or does it immediately pause?
I'm finally getting to this and I'd like to ask a few more questions to clarify how things are arranged in flash.
For LARGE programs you say that "code and cnst segments are stored at their correct addresses for execution". What does this mean? Does this mean that they are stored starting at flash address zero?
Essentially, yes - but (as always with Catalina) it's not quite that simple
Its true that when accessing XMM RAM chip, the Catalina kernel starts at physical FLASH address zero (as it must, naturally). But Catalina always implements a flat memory map on top of the physical chips used, so there is sometimes (not always!) a difference between the physical address and the addresses as they appear in the compiled Catalina code.
The Hub is always addressed from $0000 to $7FFF. What happens after that is platform dependent. For FLASH plafroms (currently only C3 and Morpeheus) you will find two additional values defined in Catalina_Common.spin:
SPI_RW_BASE_ADDRESS = $0000_8000 ' SPI Read-Write Base address
SPI_RO_BASE_ADDRESS = $0001_8000 ' SPI Read-Only Base address
Note that I currently use the same values for both platforms even though MORPHEUS only has 32k of R/W SPI and the C3 has 64k - this makes it easier to load, and it just means the MORPHEUS has a hole in its memory map you have to avoid - no big deal.
These constants tell you that (from the code's viewpoint) the beginning of FLASH (which is where the read-only segments will go) is represented by address $18000. So you must subtract $18000 from any code address to figure out where it should go in FLASH.
You talk about segments needing relocation but that is handled by the Flash_Boot.binary code, right? I don't need to worry about that if I'm just trying to write the flash image.
I have spent a couple of hours inside the plugin code and a few bits here and there make sense, but the vast majority of it is unintelligible to me. I am at a point of needing to make a decision as to whether it is easier to redesign the dracblade hardware and get a new board made. Getting a board made will cost around $250, but another option might be to pay you to look at coding a software solution. I am convinced that this is less than 10 lines of code, so would you be interested in $250 for helping me to write a software solution?
The problem. I need access to pins 0 to 11 while Catalina is running in XMM mode.
The simplistic solution, as discussed over the last couple of weeks, is to issue a call to a catalina plugin request that then sends catalina into a loop waiting for a reply, and for some cog code to take over pins 0 to 11 and then when it has finished with the pins, write a value to somewhere in hub.
I assume that this is possible to do.
Here are some code that does not pause catalina:
void main ()
{
long plugin_type = 8;
long code = 22;
long param = 0;
printf("Shut down Catalina\n");
_sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF));
printf("End program\n");
while (1);
}
I initially tried setting the three values to zero. I then found some code you had posted earlier that referred to LMM_DUM, and looking at some #include code I found the value was 8, so this is the value above. I also found some other code that set the variable "code" to 22 but this does not work either.
So, going back to an earlier post #58 on this thread I found this:
For example, here is the entire C code for the t_char function:
As you can see, all this code does is call short_plugin_request. Here is that function in full:
Code:
int _short_plugin_request (long plugin_type, long code, long param) {
return _sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF));
}
This code actually executes the _sys_plugin service request that stops the kernel until the plugin says it can proceed again. I don't think you can come up with a mechanism that is much simpler than this
This does not appear to be all the code, as the variable "HMI" is not defined. It probably is a constant somewhere in an include file, but what I am looking for is the entire code.
Next I took a look inside a program called complex_test.c
There is some code in there that loads plugins but it does not appear to use the _sys_plugin service and I am assuming that only _sys_plugin will pause catalina. I tried to copy that code but it failed to compile due to leaving out the #includes. I checked out some of the #includes and they themselves had #includes.
This is where decoding the whole plugin concept gets very hard to follow. There is no single C program that I can find that has all the code, and tracking all the #includes inside the #includes makes it confusing. In addition, inside the folders are quite a number of spin programs, and I can't see how spin can be part of the whole plugin solution. Pasm of course, but not spin.
So these are some of the paths I have been down trying to work out what plugins do and how to use them.
To reiterate the problem - I need access to pins 0-11 while running a catalina program.
This is all I need and in fact, I don't think I really need much of the plugin system at all. But I think dummy plugins are one possible solution, and I say this because of this quote of yours from post #58:
For all plugins that accept service requests (and not all do) then the Catalina kernel is suspended from the time it sets up the request (in the request long) until the time the plugin sets that long back to zero. Then catalina reads the result (from the result long) and resumes executon of the kernel.
The fact that not all plugins will suspend catalina is another complicating variable.
Maybe there is another solution? For $250, I wonder if it would be possible for you to add another function to catalina. Let us call it "_suspend" and it has one parameter, which is a memory address (?int) in hub anywhere from 0x0000 to 0x7fff
use it thus:
int resume_pointer = 0x1000;
_suspend(resume_pointer);
and internally within catalina, that sets pins 0-11 high (or HiZ, it does not matter), and then goes into a loop checking the hub location of "resume_pointer", and then continues when this value is set to 0.
If it is possible to do this sort of thing, I can write the cog code in a cogject format, set the hub location to non-zero, load the cog and start it, then take control of those pins, and finally set the long in that hub location to zero.
I don't really mind - whichever solution works.
If this is not possible to do with catalina, that is fine too as I can look at using the SPI or I2C bus for real world I/O.
I'm apparently still not understanding how to write an image into the C3 flash that can be loaded by Flash_Boot.binary. I wrote code that reads the does the following:
layout 3:
writes code+cnst starting at physical offset zero in the flash
pads with zeros to the next 0x200 byte boundary
writes init+data to the flash
layout 4:
writes code starting at physical offset zero in the flash
pads with zeros to the next 0x200 byte boundary
writes cnst+init+data to the flash
What I'm noticing in this procedure is that the prolog is never written to the flash. Doesn't Flash_Boot.binary need that to determine the memory layout and where everything goes in SRAM or hub memory? If so, where should the prolog be written in the flash?
Yes you are right about the pausing vs stopping. What I want to do is allow a cog to gain access to pins P0-11while catalina is running in XMM mode. So this needs to put catalina into a loop, and when the cog has finished with those pins, it puts a zero into a hub location and catalina keeps going.
Will this pause catalina? I am not passing any parameters but I don't know if the default for "param" is zero or some other value. But what values should "plugin_type" and "code" be?
Also, what state will catalina leave those pins when it is paused? ie, if it does get a "pause" command, does it run an instruction to put all the pins high (or low, or HiZ), or does it immediately pause?
Hi Dr_A,
Yes, you have identiifed the correct line of code. Catalina will pause in this function until the plugin that was called writes a zero to the request long.
As for the values you pass this function, just pass zero for param if you don't use it. For code you will have pass a non-zero value, but if you only effectively implement one service, any value will do. The plugin_type wil have to be something that the kernel can find, which just means it must be unique, and must be the same value that the plugin used to register itself (and be in the range 1 .. 255). However, I suggest you define a value specific to your plugin type (if there is not already one defined) in both catalina_plugin.h (for use from C) and Catalina_Common.spin (for use from SPIN).
As for I/O pins, it differs between the LMM kernel and the XMM kernel:
The LMM kernel does not use or alter the state of any pins, so the pins are in whatever state your C program leaves them.
The XMM kernel generally uses I/O pins to access external RAM, so in this kernel I call a special function called XMM_Tristate before calling the plugin, and another called XMM_Activate afterwards - this is specifically designed to allow you to modify the state of the I/O pins if your plugin needs to access them (and they conflict with the kernels use of them for accessing XMM RAM). All you need to do is add suitable code into the versions of these routines for your platform (they are in XMM.inc - look for the #ifdef DRACBLADE section). You also need to define the SHARED_XMM symbol (e.g. on the command line via -D SHARED_XMM) to specify that these functions should be called.
I'm apparently still not understanding how to write an image into the C3 flash that can be loaded by Flash_Boot.binary. I wrote code that reads the does the following:
layout 3:
writes code+cnst starting at physical offset zero in the flash
pads with zeros to the next 0x200 byte boundary
writes init+data to the flash
layout 4:
writes code starting at physical offset zero in the flash
pads with zeros to the next 0x200 byte boundary
writes cnst+init+data to the flash
What I'm noticing in this procedure is that the prolog is never written to the flash. Doesn't Flash_Boot.binary need that to determine the memory layout and where everything goes in SRAM or hub memory? If so, where should the prolog be written in the flash?
Thanks,
David
I think I see the mistake I made. The prolog is supposed to be stored at the base of flash and the RO segments are supposed to follow that starting at offset 0x200. Is that correct?
I have spent a couple of hours inside the plugin code and a few bits here and there make sense, but the vast majority of it is unintelligible to me. I am at a point of needing to make a decision as to whether it is easier to redesign the dracblade hardware and get a new board made. Getting a board made will cost around $250, but another option might be to pay you to look at coding a software solution. I am convinced that this is less than 10 lines of code, so would you be interested in $250 for helping me to write a software solution?
The problem. I need access to pins 0 to 11 while Catalina is running in XMM mode.
Hi Dr_A,
You don't need to pay me for this - it really is very simple. I'll go through it step by step, starting with the example given in the custom_demo folder:
Look in the simple_test.c. This file "#includes" generic_plugin.h, which is the definition of the interface to the generic plugin. This file defines the value DUM, and also four service routines - service_1 to service_4. There no particular reason to have four - it's just an example.
Look in generic_plugin.c. This file is the imlementation of the interface to the generic plugin. It implements the four service routines. Ech of these routines calls either _short_plugin_request or _long_plugin request. Those functions are defined on page 41 of the Catalina Reference Manual. These library functions are simply wrappers around a _sys_plugin call. For example, here is the implementation of _short_plugin_request (I pulled this out of the library source code in Catalina\source\lib\catalina\catalina_plugin_short.c):
#include <catalina_plugin.h>
/*
* Short plugin request:
*/
int _short_plugin_request (long plugin_type, long code, long param) {
return _sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF));
}
So really - that's all there is to it. When you see the call to service_1(param) in simple_test.c it is actually a call to _sys_plugin(DUM, 1<<24 + (param & 0x00FFFFFF))
If this is done from a Catalina XMM program, the XMM_Tristate function will be called to release any I/O pins the kernel is currently using (see my previoius post in this thread for more details on XMM_Tristate), then the code 1 (plus the value of param) will be written to the request long of the plugin that registered itself as DUM (i.e. the generic plugin), and the kernel will pause (actually it will busy wait looking for the same request long to be set back to zero).
When the generic plugin overwrites the request long with the value zero, the kernel will resume - it will first call XMM_Activate to set the pins back to the way it needs them for accessing XMM RAM, and it can then continue executing the C program.
If this is still not clear, I can code up an even simpler generic plugin tonight - and a demo program that interacts with it - and post it here. It will take me about 15 minutes.
As for the values you pass this function, just pass zero for param if you don't use it. For code you will have pass a non-zero value, but if you only effectively implement one service, any value will do. The plugin_type wil have to be something that the kernel can find, which just means it must be unique, and must be the same value that the plugin used to register itself (and be in the range 1 .. 255). However, I suggest you define a value specific to your plugin type (if there is not already one defined) in both catalina_plugin.h (for use from C) and Catalina_Common.spin (for use from SPIN).
Ah, it appears there is more code required.
As stated above, the code that does *not* pause catalina is this:
void main ()
{
long plugin_type = 8;
long code = 22;
long param = 0;
printf("Shut down Catalina\n");
_sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF));
printf("End program\n");
while (1);
}
So the first step is to write some code that does not print "End program"
It appears from your comments that what we need is a plugin, even if it is fake or a dummy plugin.
This is where I am getting confused, because I have been assuming that if catalina made a call to _sys_plugin, and no plugin actually existed, then catalina would still enter that endless loop. But the code above shows this is not the case.
So - what is the minimum additional code that we need to setup a dummy plugin? (I don't want to use the plugin - all I want is the absolute minimum code to pause catalina).
I'm apparently still not understanding how to write an image into the C3 flash that can be loaded by Flash_Boot.binary. I wrote code that reads the does the following:
layout 3:
writes code+cnst starting at physical offset zero in the flash
pads with zeros to the next 0x200 byte boundary
writes init+data to the flash
layout 4:
writes code starting at physical offset zero in the flash
pads with zeros to the next 0x200 byte boundary
writes cnst+init+data to the flash
What I'm noticing in this procedure is that the prolog is never written to the flash. Doesn't Flash_Boot.binary need that to determine the memory layout and where everything goes in SRAM or hub memory? If so, where should the prolog be written in the flash?
Thanks,
David
Hi David,
Yes - the prologue must be written to the first 200 bytes of Flash. For flash programs, the code segment is always compiled to begin at $18200, which is done to leave space for the prologue. I may have missed mentioning that - sorry!
Yes - the prologue must be written to the first 200 bytes of Flash. For flash programs, the code segment is always compiled to begin at $18200, which is done to leave space for the prologue. I may have missed mentioning that - sorry!
Ross.
Thanks. I've added code to write the prolog to the start of flash but my code still doesn't boot correctly with Flash_Boot.binary. I'm wondering if somehow I'm not writing stuff to flash correctly. Do you know of a program I can used to dump what is in flash?
This is where I am getting confused, because I have been assuming that if catalina made a call to _sys_plugin, and no plugin actually existed, then catalina would still enter that endless loop. But the code above shows this is not the case.
No - the _sys_plugin call is just returning. It is actually returning you an error code (a non zero return value) to tell you that there is no such plugin registered, but you are not checking it.
So - what is the minimum additional code that we need to setup a dummy plugin? (I don't want to use the plugin - all I want is the absolute minimum code to pause catalina).
"Use the force, Luke!"- or in your case, "Use a plugin, Dr_A!"
If your cogject was a plugin, you'd be finished now!. Catalina would now be paused, the I/O pins would all have been released and your cogject can happliy go about executing whatever it wants to, releasing the kernel whenever it likes.
Thanks. I've added code to write the prolog to the start of flash but my code still doesn't boot correctly with Flash_Boot.binary. I'm wondering if somehow I'm not writing stuff to flash correctly. Do you know of a program I can used to dump what is in flash?
The RAM test program can do this. Compile it using a build_all command similar to the one you used for the utilities folder:
cd ram_test
build_all C3 CACHED_4K FLASH
Then run it and before it does a memory test it wil dump the contents of XMM RAM. It is easiest if you use the PC version of the ram_test program with a terminal emulator (ram_test_PC.binary), since you will have to skip through the first 64k (which is the SPI RAM) to get to the FLASH RAM. The program will print 64 bytes at a time and then ask More? - just keep pressing Y
Now I think I'm confused about LARGE and SMALL stored in flash on the C3.'
As I understand it, LARGE programs put their code and cnst segments in flash and init and data in SPI SRAM.
SMALL seems to put its code in flash but cnst, init, and data in hub memory.
Why doesn't SMALL also put cnst in flash? It seems like that would save some of the precious hub memory and also speed up program launching because cnst wouldn't have to be copied from flash to hub memory.
I'm not going to give up but boy, is this complicated.
I don't understand plugins and so I can't use them, and all I want to do is pause catalina but I'll use plugins if that is the only way to do this.
Going off on a slight tangent, why don't I understand plugins? I have identified three reasons. The first is the multiple nesting of code within #includes (these go 3 levels deep as far as I can tell), and the second is comments like in post #199 However, I suggest you define a value specific to your plugin type (if there is not already one defined) in both catalina_plugin.h (for use from C) and Catalina_Common.spin (for use from SPIN).where I do not understand why my C program needs something changed in a Spin program. The third reason is a comment I found in generic_plugin.h
"#ifndef __CATALINA_PLUGIN
// warn the user they have forgotten to load the plugin!
#error ERROR: This program must be compiled with -D PLUGIN
#endif"
and this suggests that there might be yet another thing that needs changing - the command line parameters for compiling catalina.
Let's take those points and explore them a little more, because maybe this might help someone else write a plugin.
1) Nesting of #includes. Here is the first few lines of the program "simple_test.c"
/******************************************************************************\
* Simple program to test the Generic Plugin *
* *
* This program simply toggles some outputs by calling *
* services provided by the Generic Plugin - the OUTPUTS *
* symbol specifies which output pins will be toggled *
* *
\******************************************************************************/
/*
* include the definition of the services provided by the generic plugin:
*/
#include "generic_plugin.h"
Now, if I copy that into my program and try to run it, I get an error "could not find #include file "generic_plugin.h"
What I think is happening here is that you are compiling from a different folder from me. So - there are three solutions here:
a) with any code, attach each and every #include file, including #includes mentioned in the #includes or
b) unravel where all the #includes are, by doing a windows search for all the files and copying them to a common directory or
c) take all code mentioned in an #include and copy it into a main program.
There is nothing wrong with #includes per-se, but the logical place for these would be in the /include folder and if they are not there it gets confusing.
Looking through the demo program simple_test.c, this includes "generic_plugin.h" [in the /custom_demo folder], and generic_plugin.h references catalina_cog.h, [in the /include folder]. There are some .c programs of the same name, I am not sure if these would need to be copied as well?
I now have a fairly good idea where all the files are, but only after realising that these files are all needed.
2) I still don't understand why spin keeps being mentioned. Sure, I can change something in a spin program, but then what? Do I need to re-run any "buildall" batch files that I might find in the same folder? Or does catalina recompile spin programs whenever it is run? To my simplistic way of thinking, the aim of catalina is to get away from spin.
3) With respect to the code I found in one of those #includes "#error ERROR: This program must be compiled with -D PLUGIN", do any command line parameters need changing?
Having said all this, it appears I am not loading up a plugin of some sort. I have looked at simple_test.c and I have gone into each #include, and into the #includes they mention, but I can't find anywhere that actually loads a plugin. I'm sure it is there, or maybe it is in another demo program?
I wonder if it might be worth thinking about taking all the #includes and the #include-includes and simply placing all the code at the beginning of a single C program?
Or can you just point me to the line of code that loads up that dummy plugin?
I think I'm getting confused again. What exactly is the "prolog"? Does it include the 0x18 bytes starting at .binary file offset 0x8000? I had thought that the prolog was just the part that starts with two longs of zero and is followed by the jmp table.
I'm not going to give up but boy, is this complicated.
Hi Dr_A,
I'm sorry it seems so complicated. It isn't really (honest!). Many of the answers to your questions are covered in the documentation. I realize now that I'll have to rewrite the documents to cover more of the basics, but they may make more sense to you now than they did earlier. Can I ask that you at least go back and re-read the Getting Started with Pluginsdocument?
Also, have you actually tried compiling and running any of the demo programs in the custom_demo folder, or read the README.txt file in that folder? The README describes every file in the folder, what it does and how you are supposed to compile and run it.
You are wondering why you might need to modify SPIN - this is because plugins are normally loaded from the target (which is a SPIN program) not from C. This is certainly true in the simple_test.c. In complex_test.c I show how to do the same from C, but I suggest you start with the simpler demo first.
It is important to note that the programs in the custom_demo folder are intended to work with the targets in the custom folder (not the normal target folder). In the custom folder you will find lmm_default.spin, which is the target designed to be used with the demo programs simple_test.c and complex_test.c. You will also find a README.txt that describes every file in that folder, what it does and how to use it.
Here are some addiitonal notes about the questions you raise in your post:
I'm afraid multiple nested plugins are the rule in C rather than the exception. Also, it's worth remembering that when using #include there are two separate forms:
#include <file.h> - means to include from a standard list of include directories (normally used to include library function headers). #include "file.h" - means to include it from the directory containing the file being compiled (normally used to include your own headers).
The line you found which says "#error ERROR: This program must be compiled with -D PLUGIN" is intended as a reminder that you must enable the loading of the plugin by the target. Like all Catalina plugins, you do this by defining a symbol to the command line when compiling the program. This is done for you automatically if you use the build_all.bat file, but here is an example command line that will compile simple_demo manually:
I don't want you to get too stuck on this issue, so if you want I will produce a very simple demo that does just what you need to do - i.e a really trivial plugin that just suspends the kernel and gives you a place to add some PASM code of your own that will execute while the kernel is suspended. If you don't want to load it from the target, I will show in the demo how to load it from C.
Comments
Attached is a replacement version of Catalina_SPI_Cache.spin that can optionally verify both the Flash erase and the Flash write (i.e. programming).
Just overrwrite your existing version (in the target directory) and then rebuild your utilities folder using a command like: This will build XMM.binary with both the verification checks enabled:
I can't really check this as my C3 never seems to have a problem, so please let me know how it goes on yours.
Ross.
Thanks for the new version with ERASE_CHECK and WRITE_CHECK. I'm assuming that it would display error messages if either check fails, right? Well, I've now run it three times in a row and gotten no errors and xbasic loaded and started fine. I haven't used my C3 in about a week though so maybe my problems have to do with leaving the C3 powered on constantly. I'll leave it on during the day today and try it again later. So it seems my problems have magically disappeared. I hate it when that happens! :-)
Thanks,
David
Did you use jazzed's JCACHE interface when you implemented the Catalina cache code? I'm trying to figure out if we can just substitute a different implementation of the JCACHE interface to get a new cached board working with Catalina.
Thanks,
David
I am really really sorry about this, but plugins to me are completely unintelligible. I don't know what it is - but I think there is a critical mass of terms in each explanation and each term assumes understanding of another term and as a group I just can't pull it together.
I am sorry but I could not decode the mouse driver. I ended up using the spin cogject, as it was simply a matter of loading it and then reading off 3 variables - par is x, par+1 is y and par+3 is the button status. This is now driving the GUI to the point you can click on a button with a mouse pointer (same bitmap as a windows pointer) and it then runs some code.
But I need to really focus on the plugin needed to stop Catalina. I either have to understand this or abandon the hardware for an SPI or I2C solution. It really comes down (I think) to two lines of code:
1) Stop Catalina
2) write a value to a long to restart Catalina.
First, here is the explanation that I can't understand.
Taking that one line at a time
What values do I pass to:
1) "plugin_type"
2) "code"
3) "param"
For the purposes of just shutting down catalina and restarting it, there are no return values, so I'm not sure what the "return" value is going to be - as I understand it, Catalina is going to hang at this point, so if it gets to "return" then it restarted, and if it doesn't get there, then the cog didn't run, and there is no need to return any values as Catalina is no longer running. For this ultra simple demo, is this the correct logic?
Regarding the location of the value that the cog needs to change, you say
Is this any of 1), 2) or 3) above?
I am really sorry I can't understand plugins. One of the problems with writing any cog code is the whole debugging sequence, which I'm sure most authors don't tend to describe in every single step. For me, I am finding it easier to break every piece of cog code down into pieces, and the first part is to get it working from Spin, and then port the cogject code over to C. I described the process of creating a Spin Cogject over on another thread, and it is 20 discrete steps and every single one of those has to work (usually without much debugging help) before cog code will work. Creating plugins adds another couple of steps at least, as there is additional code to add in the cog to interface to the plugin.
But to me there seem to be too many variables to tackle at once. Consider:
What is the "registry request block" and how does one find it in C?
Why is LMM_HMI mentioned? Does this imply that there are different methods for interfacing to plugins depending on whether one uses LMM or XMM?
I am wondering if it is possible to break this down to something much simpler.
Start a cog with some code. Pass a value via par which points to a group of plugin longs.
Stop Catalina
Write a (I think) zero to a hub location (par +/- n) which will restart Catalina.
Would it be possible to provide some C code to do this, and maybe pasm as well? I am fairly sure the pasm code will only a few lines - collect 'par', add a value, and do a 'wrlong' of zero to this location.
But what would the C code look like?
Any help here would be most appreciated
Hi David,
Me too :frown:!
No, there is currently no indication when things fail. I'll think about how to add a return status that payload could display. I just didn't want to mess with the payload protocol unless I had to.
Ross.
Hi David,
I'm not sure, since but I couldn't find any documentation on the JCACHE interface. Can you point me to a definition?
My object uses the PASM interface implemented in Jazzed's SdramCache.spin module. Is JCACHE the SPIN interface implemented in this module? If so, you just need to add a slightly modified Spin wrapper around my PASM implementation to get the same interface.
Ross.
USE_JCACHED_MEMORY is a #define in ZOG - it's all the same.
I'm so busy building and verifying new hardware that I haven't had time to test this in Catalina.
Sorry about that.
We shouldn't need any Spin code should we? ZOG just interfaces with a JCACHE cache driver using the mailbox protocol. If you've implemented the same mailbox protocol we should be able to substitute a different implementation and it should work with Catalina, right?
Perhaps this is the crux of the misunderstanding. You don't stop Catalina - that would be akin to stopping the SPIN interpreter but then expecting to communicate with the Spin program it was executing. It works the other way round - i.e. Catalina pauses itself whenever it makes a _sys_request call.
Another cog can certainly do work asynchrously from the Catalina program, but if it is a plugin, then it should still monitor the regsistry occasionally to see if Catalina wants to talk to it - it can't "interrupt" Catalina whenever it wants to.
However, if this is not a suitable mechanism, then there are other ways a plugin can send data back to Catalina - e.g. it can communicate via a specified memory location, passed to it by Catalina during initialization. This is how (for example) the serial IO plugin works.
To continue ... First of all, I should say that what you are doing is perfectly fine - you don't need to use plugins - if what you are doing works for you, then just carry on doing it. Plugins would just make it easier for you to interact between your cogjects and Catalina. But if you can't use plugins, you can always use locks and/or Hub RAM to synchronize Catalina with your cogjects. The downside is that it will make your C programs more complex - but while this would bother me, it may not bother you!. However, it would certainly help you decide if you understood plugins better, so I'll carry on explaining them as long as you want - I never tire of hearing the sound of my own typing. The "plugin_type" is the type of plugin you are trying to send your service request to - these are defined in Catalina_Common.spin. For example, the type for a HMI plugin is LMM_HMI. In this parameter you can also pass a cog number by adding 0x80 to it - e.g. 0x80 + 7 for cog 7.
The "code" is just a constant number that you and the plugin agree to use to represent a specific service. For example, the codes for the services implemented by all the HMI plugins are the same - here are the ones for the mouse services:
The "param" is what is identified as "data" in the list above - often it is nothing, since specifying the service itself is enough.
These services should look familiar to you if you have looked at the existing Parallax mouse drivers - but it is important to understand that Catalina uses the existing Parallax mouse, keyboard and screen drivers - but these are not themselves plugins! - to use them from Catalina you must call them via the HMI plugin, which provides the standard "plugin" interface to all the various underlying drivers - VGA drivers or TV drivers, Hydra mouse driver or Propterminal mouse driver etc etc. This interface replaces (and in some cases enhances) what the SPIN part of each of these drivers normally does - that's the main purpose of the HMI plugin.
In this case, we are now discussing the development of a stand-alone mouse plugin - this is fine, and I could have taken this approach (i.e. rewrite each driver as a separate plugin). The main reason I don't do things this way is that you then have to develop a different plugin for each type of driver for each platform. There is also the problem that each of these drivers (at least the ones in the OBEX) offer a slightly different set of services - and this means users would have to write different C code to use each one. This would kind of spoil the point of having an an ANSI C compiler!
You are not shutting down Catalina and restarting it. Catalina sits in a busy-wait loop, waiting for you to tell it to continue. And there are return values - you write them to the registry long after the one you read the service request from. But it is true that a simple demo probably won't need to use them. No - the registry is what you are looking for - and the registry tells you where to write those values for each plugin - but you don't have to figure this out for yourself - this is done for you by the internals of the _sys_plugin function.
It is slightly different on the plugin side of the interface. The common registry address is passed to each plugin on startup. From that address, the plugin can figure out the address of its own request block - which contains (normally) only two longs - a long for requests and a long for return values. Figuring this out is not very difficult - it only takes a few PASM instructions - one of which is to fetch your own cog id.
For example, this is code to figure out your registry block from within a plugin - you will see code like this at the beginning of all plugins:
Some plugins then go on to register themselves, whereas others expect this to have been done for them by the Spin code that started them. If you expect to unload and reload the plugin, you need to decide whether the plugin should register itself, or whether you will do it from C. From C, you don't mormally need to - see above. But you can if you want to - there is a function called _registry that will return the common registry address, and a macro called REQUEST_BLOCK that you can use to retrieve a specific cog request block - e.g REQUEST_BLOCK(7) You need to give _sys_plugin a means of finding the plugin you are trying to call - either by type or by cog id. LMM_HMI is just the type of the plugin. Sorry about the LMM_ bit - I defined these before XMM mode was even thought of - maybe I should rename them all PLUGIN_ or something. This is exaclty the purpose of the various demo programs in the custom_demo directory! I think the problem is you are trying to do too much at once - start with the generic Catalina_plugin.spin (in the custom target directory) and the simple_example.c program that uses it (in the custom_demo directory).
Once you understand that example everything else should fall into place. Perhaps you could then look at one of the stand-alone plugins such as the clock plugin. Then look at the HMI plugins - which are the most complex of all.
Ross.
Hi David (& Jazzed)
Yes, from Jazzed's explanation, it seems I am implementing the correct mailbox protocol. I think the only difference is that my startup routine differs, since my mailbox address is fixed (e.g. XMM_CACHE_CMD in Catalina_Common.spin - currently $7FF4 - is used for all operations).
Ross.
I'm finally getting to this and I'd like to ask a few more questions to clarify how things are arranged in flash.
For LARGE programs you say that "code and cnst segments are stored at their correct addresses for execution". What does this mean? Does this mean that they are stored starting at flash address zero?
You talk about segments needing relocation but that is handled by the Flash_Boot.binary code, right? I don't need to worry about that if I'm just trying to write the flash image.
Yes you are right about the pausing vs stopping. What I want to do is allow a cog to gain access to pins P0-11while catalina is running in XMM mode. So this needs to put catalina into a loop, and when the cog has finished with those pins, it puts a zero into a hub location and catalina keeps going.
I think the key is this line of code:
Will this pause catalina? I am not passing any parameters but I don't know if the default for "param" is zero or some other value. But what values should "plugin_type" and "code" be?
Also, what state will catalina leave those pins when it is paused? ie, if it does get a "pause" command, does it run an instruction to put all the pins high (or low, or HiZ), or does it immediately pause?
Its true that when accessing XMM RAM chip, the Catalina kernel starts at physical FLASH address zero (as it must, naturally). But Catalina always implements a flat memory map on top of the physical chips used, so there is sometimes (not always!) a difference between the physical address and the addresses as they appear in the compiled Catalina code.
The Hub is always addressed from $0000 to $7FFF. What happens after that is platform dependent. For FLASH plafroms (currently only C3 and Morpeheus) you will find two additional values defined in Catalina_Common.spin: Note that I currently use the same values for both platforms even though MORPHEUS only has 32k of R/W SPI and the C3 has 64k - this makes it easier to load, and it just means the MORPHEUS has a hole in its memory map you have to avoid - no big deal.
These constants tell you that (from the code's viewpoint) the beginning of FLASH (which is where the read-only segments will go) is represented by address $18000. So you must subtract $18000 from any code address to figure out where it should go in FLASH.
Correct.
Ross.
I have spent a couple of hours inside the plugin code and a few bits here and there make sense, but the vast majority of it is unintelligible to me. I am at a point of needing to make a decision as to whether it is easier to redesign the dracblade hardware and get a new board made. Getting a board made will cost around $250, but another option might be to pay you to look at coding a software solution. I am convinced that this is less than 10 lines of code, so would you be interested in $250 for helping me to write a software solution?
The problem. I need access to pins 0 to 11 while Catalina is running in XMM mode.
The simplistic solution, as discussed over the last couple of weeks, is to issue a call to a catalina plugin request that then sends catalina into a loop waiting for a reply, and for some cog code to take over pins 0 to 11 and then when it has finished with the pins, write a value to somewhere in hub.
I assume that this is possible to do.
Here are some code that does not pause catalina:
I initially tried setting the three values to zero. I then found some code you had posted earlier that referred to LMM_DUM, and looking at some #include code I found the value was 8, so this is the value above. I also found some other code that set the variable "code" to 22 but this does not work either.
So, going back to an earlier post #58 on this thread I found this:
This does not appear to be all the code, as the variable "HMI" is not defined. It probably is a constant somewhere in an include file, but what I am looking for is the entire code.
Next I took a look inside a program called complex_test.c
There is some code in there that loads plugins but it does not appear to use the _sys_plugin service and I am assuming that only _sys_plugin will pause catalina. I tried to copy that code but it failed to compile due to leaving out the #includes. I checked out some of the #includes and they themselves had #includes.
This is where decoding the whole plugin concept gets very hard to follow. There is no single C program that I can find that has all the code, and tracking all the #includes inside the #includes makes it confusing. In addition, inside the folders are quite a number of spin programs, and I can't see how spin can be part of the whole plugin solution. Pasm of course, but not spin.
So these are some of the paths I have been down trying to work out what plugins do and how to use them.
To reiterate the problem - I need access to pins 0-11 while running a catalina program.
This is all I need and in fact, I don't think I really need much of the plugin system at all. But I think dummy plugins are one possible solution, and I say this because of this quote of yours from post #58:
The fact that not all plugins will suspend catalina is another complicating variable.
Maybe there is another solution? For $250, I wonder if it would be possible for you to add another function to catalina. Let us call it "_suspend" and it has one parameter, which is a memory address (?int) in hub anywhere from 0x0000 to 0x7fff
use it thus:
and internally within catalina, that sets pins 0-11 high (or HiZ, it does not matter), and then goes into a loop checking the hub location of "resume_pointer", and then continues when this value is set to 0.
If it is possible to do this sort of thing, I can write the cog code in a cogject format, set the hub location to non-zero, load the cog and start it, then take control of those pins, and finally set the long in that hub location to zero.
I don't really mind - whichever solution works.
If this is not possible to do with catalina, that is fine too as I can look at using the SPI or I2C bus for real world I/O.
Your thoughts would be most appreciated.
layout 3:
writes code+cnst starting at physical offset zero in the flash
pads with zeros to the next 0x200 byte boundary
writes init+data to the flash
layout 4:
writes code starting at physical offset zero in the flash
pads with zeros to the next 0x200 byte boundary
writes cnst+init+data to the flash
What I'm noticing in this procedure is that the prolog is never written to the flash. Doesn't Flash_Boot.binary need that to determine the memory layout and where everything goes in SRAM or hub memory? If so, where should the prolog be written in the flash?
Thanks,
David
Hi Dr_A,
Yes, you have identiifed the correct line of code. Catalina will pause in this function until the plugin that was called writes a zero to the request long.
As for the values you pass this function, just pass zero for param if you don't use it. For code you will have pass a non-zero value, but if you only effectively implement one service, any value will do. The plugin_type wil have to be something that the kernel can find, which just means it must be unique, and must be the same value that the plugin used to register itself (and be in the range 1 .. 255). However, I suggest you define a value specific to your plugin type (if there is not already one defined) in both catalina_plugin.h (for use from C) and Catalina_Common.spin (for use from SPIN).
As for I/O pins, it differs between the LMM kernel and the XMM kernel:
- The XMM kernel generally uses I/O pins to access external RAM, so in this kernel I call a special function called XMM_Tristate before calling the plugin, and another called XMM_Activate afterwards - this is specifically designed to allow you to modify the state of the I/O pins if your plugin needs to access them (and they conflict with the kernels use of them for accessing XMM RAM). All you need to do is add suitable code into the versions of these routines for your platform (they are in XMM.inc - look for the #ifdef DRACBLADE section). You also need to define the SHARED_XMM symbol (e.g. on the command line via -D SHARED_XMM) to specify that these functions should be called.
Ross.I think I see the mistake I made. The prolog is supposed to be stored at the base of flash and the RO segments are supposed to follow that starting at offset 0x200. Is that correct?
Hi Dr_A,
You don't need to pay me for this - it really is very simple. I'll go through it step by step, starting with the example given in the custom_demo folder:
- Look in the simple_test.c. This file "#includes" generic_plugin.h, which is the definition of the interface to the generic plugin. This file defines the value DUM, and also four service routines - service_1 to service_4. There no particular reason to have four - it's just an example.
- Look in generic_plugin.c. This file is the imlementation of the interface to the generic plugin. It implements the four service routines. Ech of these routines calls either _short_plugin_request or _long_plugin request. Those functions are defined on page 41 of the Catalina Reference Manual. These library functions are simply wrappers around a _sys_plugin call. For example, here is the implementation of _short_plugin_request (I pulled this out of the library source code in Catalina\source\lib\catalina\catalina_plugin_short.c):
So really - that's all there is to it. When you see the call to service_1(param) in simple_test.c it is actually a call to _sys_plugin(DUM, 1<<24 + (param & 0x00FFFFFF))If this is done from a Catalina XMM program, the XMM_Tristate function will be called to release any I/O pins the kernel is currently using (see my previoius post in this thread for more details on XMM_Tristate), then the code 1 (plus the value of param) will be written to the request long of the plugin that registered itself as DUM (i.e. the generic plugin), and the kernel will pause (actually it will busy wait looking for the same request long to be set back to zero).
When the generic plugin overwrites the request long with the value zero, the kernel will resume - it will first call XMM_Activate to set the pins back to the way it needs them for accessing XMM RAM, and it can then continue executing the C program.
If this is still not clear, I can code up an even simpler generic plugin tonight - and a demo program that interacts with it - and post it here. It will take me about 15 minutes.
Just let me know.
Ross.
Ah, it appears there is more code required.
As stated above, the code that does *not* pause catalina is this:
So the first step is to write some code that does not print "End program"
It appears from your comments that what we need is a plugin, even if it is fake or a dummy plugin.
This is where I am getting confused, because I have been assuming that if catalina made a call to _sys_plugin, and no plugin actually existed, then catalina would still enter that endless loop. But the code above shows this is not the case.
So - what is the minimum additional code that we need to setup a dummy plugin? (I don't want to use the plugin - all I want is the absolute minimum code to pause catalina).
Hi David,
Yes - the prologue must be written to the first 200 bytes of Flash. For flash programs, the code segment is always compiled to begin at $18200, which is done to leave space for the prologue. I may have missed mentioning that - sorry!
Ross.
Thanks. I've added code to write the prolog to the start of flash but my code still doesn't boot correctly with Flash_Boot.binary. I'm wondering if somehow I'm not writing stuff to flash correctly. Do you know of a program I can used to dump what is in flash?
Yes - your code will pause Catalina if there is a plugin loaded that has registered itself as type 8.
No - the _sys_plugin call is just returning. It is actually returning you an error code (a non zero return value) to tell you that there is no such plugin registered, but you are not checking it.
"Use the force, Luke!"- or in your case, "Use a plugin, Dr_A!"
If your cogject was a plugin, you'd be finished now!. Catalina would now be paused, the I/O pins would all have been released and your cogject can happliy go about executing whatever it wants to, releasing the kernel whenever it likes.
Ross.
The RAM test program can do this. Compile it using a build_all command similar to the one you used for the utilities folder: Then run it and before it does a memory test it wil dump the contents of XMM RAM. It is easiest if you use the PC version of the ram_test program with a terminal emulator (ram_test_PC.binary), since you will have to skip through the first 64k (which is the SPI RAM) to get to the FLASH RAM. The program will print 64 bytes at a time and then ask More? - just keep pressing Y
Ross.
As I understand it, LARGE programs put their code and cnst segments in flash and init and data in SPI SRAM.
SMALL seems to put its code in flash but cnst, init, and data in hub memory.
Why doesn't SMALL also put cnst in flash? It seems like that would save some of the precious hub memory and also speed up program launching because cnst wouldn't have to be copied from flash to hub memory.
I'm not going to give up but boy, is this complicated.
I don't understand plugins and so I can't use them, and all I want to do is pause catalina but I'll use plugins if that is the only way to do this.
Going off on a slight tangent, why don't I understand plugins? I have identified three reasons. The first is the multiple nesting of code within #includes (these go 3 levels deep as far as I can tell), and the second is comments like in post #199 However, I suggest you define a value specific to your plugin type (if there is not already one defined) in both catalina_plugin.h (for use from C) and Catalina_Common.spin (for use from SPIN).where I do not understand why my C program needs something changed in a Spin program. The third reason is a comment I found in generic_plugin.h and this suggests that there might be yet another thing that needs changing - the command line parameters for compiling catalina.
Let's take those points and explore them a little more, because maybe this might help someone else write a plugin.
1) Nesting of #includes. Here is the first few lines of the program "simple_test.c"
Now, if I copy that into my program and try to run it, I get an error "could not find #include file "generic_plugin.h"
What I think is happening here is that you are compiling from a different folder from me. So - there are three solutions here:
a) with any code, attach each and every #include file, including #includes mentioned in the #includes or
b) unravel where all the #includes are, by doing a windows search for all the files and copying them to a common directory or
c) take all code mentioned in an #include and copy it into a main program.
There is nothing wrong with #includes per-se, but the logical place for these would be in the /include folder and if they are not there it gets confusing.
Looking through the demo program simple_test.c, this includes "generic_plugin.h" [in the /custom_demo folder], and generic_plugin.h references catalina_cog.h, [in the /include folder]. There are some .c programs of the same name, I am not sure if these would need to be copied as well?
I now have a fairly good idea where all the files are, but only after realising that these files are all needed.
2) I still don't understand why spin keeps being mentioned. Sure, I can change something in a spin program, but then what? Do I need to re-run any "buildall" batch files that I might find in the same folder? Or does catalina recompile spin programs whenever it is run? To my simplistic way of thinking, the aim of catalina is to get away from spin.
3) With respect to the code I found in one of those #includes "#error ERROR: This program must be compiled with -D PLUGIN", do any command line parameters need changing?
Having said all this, it appears I am not loading up a plugin of some sort. I have looked at simple_test.c and I have gone into each #include, and into the #includes they mention, but I can't find anywhere that actually loads a plugin. I'm sure it is there, or maybe it is in another demo program?
I wonder if it might be worth thinking about taking all the #includes and the #include-includes and simply placing all the code at the beginning of a single C program?
Or can you just point me to the line of code that loads up that dummy plugin?
But later on in the file if I look for "Catalina_Code" I find this:
This suggests that Catalina_Code is at address 0x18200 but the entry in segtable says it's at 0x181f0. Why the difference?
Hi Dr_A,
I'm sorry it seems so complicated. It isn't really (honest!). Many of the answers to your questions are covered in the documentation. I realize now that I'll have to rewrite the documents to cover more of the basics, but they may make more sense to you now than they did earlier. Can I ask that you at least go back and re-read the Getting Started with Plugins document?
Also, have you actually tried compiling and running any of the demo programs in the custom_demo folder, or read the README.txt file in that folder? The README describes every file in the folder, what it does and how you are supposed to compile and run it.
You are wondering why you might need to modify SPIN - this is because plugins are normally loaded from the target (which is a SPIN program) not from C. This is certainly true in the simple_test.c. In complex_test.c I show how to do the same from C, but I suggest you start with the simpler demo first.
It is important to note that the programs in the custom_demo folder are intended to work with the targets in the custom folder (not the normal target folder). In the custom folder you will find lmm_default.spin, which is the target designed to be used with the demo programs simple_test.c and complex_test.c. You will also find a README.txt that describes every file in that folder, what it does and how to use it.
Here are some addiitonal notes about the questions you raise in your post:
I'm afraid multiple nested plugins are the rule in C rather than the exception. Also, it's worth remembering that when using #include there are two separate forms:
- #include <file.h> - means to include from a standard list of include directories (normally used to include library function headers).
The line you found which says "#error ERROR: This program must be compiled with -D PLUGIN" is intended as a reminder that you must enable the loading of the plugin by the target. Like all Catalina plugins, you do this by defining a symbol to the command line when compiling the program. This is done for you automatically if you use the build_all.bat file, but here is an example command line that will compile simple_demo manually: Without the -D PLUGIN, you will get the error.#include "file.h" - means to include it from the directory containing the file being compiled (normally used to include your own headers).
I don't want you to get too stuck on this issue, so if you want I will produce a very simple demo that does just what you need to do - i.e a really trivial plugin that just suspends the kernel and gives you a place to add some PASM code of your own that will execute while the kernel is suspended. If you don't want to load it from the target, I will show in the demo how to load it from C.
Ross.