Downloading v3.0 at the moment. One ultra minor little thing for my IDE - would it be possible to have a copy of the file "xmm.binary" in both the c:\program files\utilities folder, and the c:\program files\demos folder ?
Many thanks - it was the only hangup I came across in porting from 2.6 to 3.0
Ross - you broke my program. It is 12:30am and I couldn't be happier! (hmm Dr_Acula works better at night?)
The secret to all this was to download version 3.0. This program hangs as expected. Registry is now at 7fd4
#include <stdio.h>
// compile with catalina -lcx -D PLUGIN -lm -x5 -M 256k -d DRACBLADE -D HIRES_VGA myprog.c
void main ()
{
long plugin_type = 8;
long code = 22;
long param = 0;
int return_value;
unsigned reg;
int cog;
printf("Test program to pause catalina\n");
reg = _registry(); // address of registry
printf("Registry is at %x \n",reg);
_register_plugin(7, 8); // register a fake cog number eg 7 is free, and with 8=DUM
cog = _locate_plugin(8);
printf("Cog number = %i \n",cog); // should print 7
return_value = _sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF)); // program should hang here
printf("Return value = %i \n",return_value); // and not print this unless some sort of cog code has restarted catalina
printf("End program\n");
while (1); // Prop reboots on exit from main()
}
Ross - you broke my program. It is 12:30am and I couldn't be happier! (hmm Dr_Acula works better at night?)
The secret to all this was to download version 3.0. This program hangs as expected. Registry is now at 7fd4
[
Glad you got it not working!
I'm a bit puzzled as to why it didn't not work on under 2.6 (actually, I'm even more amazed that you were still using a version of Catalina is now four releases old! I cringe whenever I have to go back even just one release and see all the silly mistakes I made - but I may have a look and see if I can figure out why).
As to your other question - yes, you can have a local copy of XMM.binary wherever you like - if it exists in the local directory when you call payload, it will be used in preference to the one in the Catalina bin directory.
Ok, next step is to build a minimalist pasm program capable of restarting catalina. To do this I think I need to write a certain value back to the registry. This is my working program, with an additional line at the beginning that does absolutely nothing as I'm trying to debug another error at the moment. I'll remove that loop shortly. I changed one value #ptype to 8 - would that be correct?
' Plugin demo for Catalina - pass the location of the registry and it places a value in the registry
' that restarts Catalina
CON
_clkfreq = 80_000_000 ' 5Mhz Crystal
_clkmode = xtal1 + pll16x ' x 16
PUB Main
coginit(1,@entry,0) ' cog 1, cogstart, dummy value
DAT
org 0
entry
jmp #loop ' do nothing
cogid t1 ' get ...
shl t1,#2 ' ... our ...
add t1,par ' ... registry block
rdlong rqstptr,t1 ' register ...
and rqstptr,low_24 ' ... this ...
wrlong zero,rqstptr ' ... plugin ...
mov t2,#8 ' Addit - CHANGED PTYPE TO 8 (not able to find a ref to ptype)
shl t2,#24 ' ... the ...
or t2,rqstptr ' ... appropriate ...
wrlong t2,t1 ' ... type
loop jmp #loop ' loop forever
'---------------------------------- Storage ------------------------------------
'
zero long 0 ' handy value (zero)
low_24 long $00FFFFFF ' handy value (lower 24 bits)
rqstptr long 0 ' request address
'rqst long 0 ' service request
'rslt long 0 ' service result
t1 long 0 ' temporary variable
t2 long 0 ' temporary variable
't3 long 0 ' temporary variable
'
param long 0 ' saved initialization data
'
fit $1f0
My complete C program is here and I'll describe where the bug is below:
#include <stdio.h>
#include <string.h> // need this for block memory moves
// compile with catalina -lcx -D PLUGIN -lm -x5 -M 256k -d DRACBLADE -D HIRES_VGA myprog.c
// compile using XMM
// cogjects - sd card driver in catalina is a little slow so load up once into external ram then (re) load quicker from external ram
unsigned long cogject_plugin[512]; // external memory for plugin
// *************** functions ***************************************
void sleep(int milliseconds) // sleep function
{
_waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
}
char peek(int address) // function implementation of peek
{
return *((char *)address);
}
void poke(int address, char value) // function implementation of poke
{
*((char *)address) = value;
}
void external_memory_cog_load(int cognumber, unsigned long cogdata[], unsigned long parameters_array[]) // load a cog from external memory
{
unsigned long hubcog[511]; // create a local array, this is in hub ram, not external ram
int i;
for(i=0;i<512;i++)
{
hubcog[i]=cogdata[i]; // move from external memory to a local array in hub
}
_coginit((int)parameters_array>>2, (int)hubcog>>2, cognumber); // load the cog
}
int EoF (FILE* stream)
{
register int c, status = ((c = fgetc(stream)) == EOF);
ungetc(c,stream);
return status;
}
void readcog(char *filename,unsigned long external_cog[]) // read in a .cog file into external memory array
{
int i;
FILE *FP1;
i = 0;
if((FP1=fopen(filename,"rb"))==0) // open the file
{
fprintf(stderr,"Can't open file %s\n",filename);
exit(1);
}
fseek(FP1,0,0);
for(i=0;i<24;i++)
{
getc(FP1); // read in the first 24 bytes and discard
}
i = 0;
while(!EoF(FP1) & (i<505)) // run until end of file or 511-6
{
external_cog[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24); // get the long
i+=1;
}
if(FP1)
{
fclose(FP1); // close the file
FP1=NULL;
}
//printf("external array cog first long = 0x%x \n",external_cog[0]); // hex value
}
void main ()
{
long plugin_type = 8;
long code = 22;
long param = 0;
int return_value;
unsigned reg;
int cog;
unsigned long plugin_parameters[2]; // plugin parameters (usually just passes the registry address)
printf("Test program to pause catalina\n");
printf("Read plugin cogject into external ram array cogject_plugin\n");
readcog("plugin.cog",cogject_plugin);
reg = _registry(); // address of registry
printf("Registry is at %x \n",reg);
_cogstop(7); // stop cog 7 (it already is stopped)
plugin_parameters[0] = (unsigned long) _registry;
external_memory_cog_load(7, cogject_plugin, plugin_parameters); // start cog 7 with the plugin cogject, pass the registry
printf("Cog plugin loaded \n",reg);
_unregister_plugin(7); // unregister cog 7 but don't stop it running
printf("Unregister cog 7\n");
_register_plugin(7, 8); // register a fake cog number eg 7 is free, and with 8=DUM
printf("Reregister cog 7 as a dummy plugin\n");
cog = _locate_plugin(8);
printf("Cog number = %x \n",cog); // should print 7
return_value = _sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF)); // program should hang here
printf("Return value = %i \n",return_value); // and not print this unless some sort of cog code has restarted catalina
printf("End program\n");
while (1); // Prop reboots on exit from main()
}
The pasm program is compiled with F8 on the spintool, and saved as a binary file "plugin.cog" and copied over to the sd card. As it is - it does absolutely nothing at all.
Then the program runs up to the point of printing "Cog number = 7" and then hangs as expected.
However, if I add that line in C and it loads up the pasm code (which is doing nothing at the moment), then it prints
"Cog number = a63f1e37"
I tested this with some other cogjects and it is the same.
Given that this pasm code does nothing at all, and that other cogjects repeat the cog number error, I think that means the problem is in the C code.
What I think I need to do is to load up a cog and then somehow get catalina to forget that it ever loaded that cog. I tried unregistering the cog but that doesn't seem to work.
This is the strange bit. I even tried running a cogstop and that doesn't work either. The cog number still prints out that long hex number instead of 7.
I am wondering if I am somehow corrupting the registry by calling external_memory_cog_load which in turn calls this
void external_memory_cog_load(int cognumber, unsigned long cogdata[], unsigned long parameters_array[]) // load a cog from external memory
{
unsigned long hubcog[511]; // create a local array, this is in hub ram, not external ram
int i;
for(i=0;i<512;i++)
{
hubcog[i]=cogdata[i]; // move from external memory to a local array in hub
}
_coginit((int)parameters_array>>2, (int)hubcog>>2, cognumber); // load the cog
}
I dumped both my bad load and the one generated by payload and there are differences. It seems like payload is putting another copy of the prolog right after the padding that follows the stuff the code. Also, it looks like the segments may not be written in the order that I expect. I am writing cnst, init, data for layout 4 but it seems like payload may be writing cnst after one or both of the others (maybe last). Would it be possible for you to verify the actual order you're writing these segments in and also whether there is supposed to be a second copy of the prolog following the padding?
By the way, I did these dumps by using an old test program I wrote for my cache driver. I modified it so it can dump as many flash blocks as needed all in one command.
Edit: I just looked more closely at the data that follows the padding and second prolog in the dump I generated after using payload to load the xbasic.binary file and I can't find that data anywhere in the xbasic.binary file. Does the payload loader put data into fhe flash that did not come from the binary file it is loading? Maybe data from the Spin part of the loader itself?
Thanks,
David
Hi David,
Not sure how you're getting on with your loader, but I've checked the actual code, and also loaded programs and dumped the resulting Flash.
Here is what you should see in Flash when payload has loaded a program:
For Layout 3 (FLASH equivalent of XMM LARGE):
Prologue ($0000 .. $01FF) Read-Only Segments (i.e. Code+Cnst) ($0200 .. $0200 + Code Size + Cnst Size - 1)
<-- zeroes till the next $200 boundary --> Read-Write Segments (i.e. Init+Data)
<-- zeroes till the next $200 boundary -->
For Layout 4 (FLASH equivalent of XMM SMALL):
Prologue ($0000 .. $01FF) Read-Only Segments (i.e. Code) ($0200 .. $0200 + Code Size - 1)
<-- zeroes till the next $200 boundary --> Read-Write Segments (i.e. Cnst+Init+Data)
<-- zeroes till the next $200 boundary -->
Recall that I mentioned that I do not fully decode the read/write segments when I store them in Flash - I just store the actual disk sectors containing them - this means you may indeed see another copy of the prologue preceeding the Cnst segment - but only when using layout 4 (XMM SMALL).
I'm not sure how or why you would be seeing data in Flash that did not come from the binary file. If you can find a case where this occurs, please post the binary that causes it and I will investigate.
I'm not sure how or why you would be seeing data in Flash that did not come from the binary file. If you can find a case where this occurs, please post the binary that causes it and I will investigate.
Thanks for the additional information on flash layout. I think I was wrong about my comment that I found data in flash that didn't come out of the binary file. I made that claim before I realized that my dump program was messing up the endianness of the data it was displaying. I'm pretty sure that the data did come from the file but it was byte-swapped so I didn't recognize it. Sorry for the false alarm!
My whole reason for playing with this loader is that I think it will be significantly faster than payload. I guess I'll try to measure its performance before I continue much further to verify if that is really true. If it isn't, there is no real reason to continue since payload already works well.
I think largely by accident I have managed to get it working. This gets to the end of the program. However, I have had a great deal of trouble with "par" and I do not seem to be able to pass anything to the cog with "par". It is all most strange because I have got all the other cogjects to work passing parameters via par. In amongst this code is a lot of commented out code trying all sorts of things but nothing seems to work. It probably is something obvious!
Spin code
' Plugin demo for Catalina - pass the location of the registry and it places a value in the registry
' that restarts Catalina
CON
_clkfreq = 80_000_000 ' 5Mhz Crystal
_clkmode = xtal1 + pll16x ' x 16
PUB Main
coginit(1,@entry,0) ' cog 1, cogstart, dummy value
DAT
org 0
' wrlong valueb,memorytest ' write value to hub memory
' mov storepar,par
mov storepar,memorytest ' use this or the one above
' wrlong valueb,storepar
mov t3,par ' test sending par
' mov t3,memorytest
wrlong t3,storepar ' write par back to 7fd4
' cogid t1 ' this works - sends back 7
' wrlong t1,memorytest2 ' write something back to 7f00
mov t3,par
wrlong t3,memorytest2 ' store the par back to 7f00
loop jmp #loop
entry
cogid t1 ' get ...
shl t1,#2 ' ... our ...
add t1,storepar ' ... registry block
rdlong rqstptr,t1 ' register ...
and rqstptr,low_24 ' ... this ...
wrlong zero,rqstptr ' ... plugin ...
mov t2,#8 ' Addit - CHANGED PTYPE TO 8 (not able to find a ref to ptype)
shl t2,#24 ' ... the ...
or t2,rqstptr ' ... appropriate ...
wrlong t2,t1 ' ... type
jmp #entry ' loop forever
'---------------------------------- Storage ------------------------------------
'
zero long 0 ' handy value (zero)
low_24 long $00FFFFFF ' handy value (lower 24 bits)
rqstptr long 0 ' request address
'rqst long 0 ' service request
'rslt long 0 ' service result
t1 long 0 ' temporary variable
t2 long 0 ' temporary variable
t3 long 0 ' temporary variable
memorytest long $7Fd4 ' to test memory
memorytest2 long $7F00
valueb long 66 ' a B
storepar long 0 ' store par
'
param long 0 ' saved initialization data
'
fit $1f0
and C code
#include <stdio.h>
// compile with catalina -lcx -D PLUGIN -lm -x5 -M 256k -d DRACBLADE -D HIRES_VGA myprog.c
// compile using XMM
// cogjects - sd card driver in catalina is a little slow so load up once into external ram then (re) load quicker from external ram
unsigned long cogject_plugin[512]; // external memory for plugin
// *************** functions ***************************************
void sleep(int milliseconds) // sleep function
{
_waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
}
char peek(int address) // function implementation of peek
{
return *((char *)address);
}
void poke(int address, char value) // function implementation of poke
{
*((char *)address) = value;
}
void external_memory_cog_load(int cognumber, unsigned long cogdata[], unsigned long parameters_array[]) // load a cog from external memory
{
unsigned long hubcog[512]; // create a local array, this is in hub ram, not external ram
int i;
for(i=0;i<512;i++)
{
hubcog[i]=cogdata[i]; // move from external memory to a local array in hub
}
printf("first cog long is %x \n",hubcog[0]);
printf("first parameter is %x \n",parameters_array[0]);
_coginit((int)parameters_array>>2, (int)hubcog>>2, cognumber); // load the cog
}
int EoF (FILE* stream)
{
register int c, status = ((c = fgetc(stream)) == EOF);
ungetc(c,stream);
return status;
}
void readcog(char *filename,unsigned long external_cog[]) // read in a .cog file into external memory array
{
int i;
FILE *FP1;
i = 0;
if((FP1=fopen(filename,"rb"))==0) // open the file
{
fprintf(stderr,"Can't open file %s\n",filename);
exit(1);
}
fseek(FP1,0,0);
for(i=0;i<24;i++)
{
getc(FP1); // read in the first 24 bytes and discard
}
i = 0;
while(!EoF(FP1) & (i<505)) // run until end of file or 511-6
{
external_cog[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24); // get the long
i+=1;
}
if(FP1)
{
fclose(FP1); // close the file
FP1=NULL;
}
//printf("external array cog first long = 0x%x \n",external_cog[0]); // hex value
}
void print_registry() // 32 bytes
{
int reg;
int i;
char peekbyte;
reg = _registry();
printf("0x%x = ",reg);
for (i=0;i<32;i++)
{
peekbyte = peek(reg+i);
if (peekbyte < 16)
{
printf("0");
}
printf("%x",peekbyte);
}
printf ("\n"); // carriage return
}
void plugin_engine_start(int cognumber, unsigned long cogarray[], unsigned long plugin_parameters[])
{
_cogstop(cognumber); // stop this cog
external_memory_cog_load(cognumber,cogarray,plugin_parameters); // load from external ram to this cog, pass location of the array
}
void print7f()
{
int i;
char peekbyte;
printf("4 bytes from 7f00 to 7f03 are ");
for (i=0;i<4;i++)
{
peekbyte = peek(0x7f00+i);
if (peekbyte < 16)
{
printf("0");
}
printf("%x ",peekbyte);
}
printf ("\n"); // carriage return
}
void main ()
{
long plugin_type = 8;
long code = 22;
long param = 0;
int return_value;
unsigned reg;
int cog;
unsigned long plugin_parameters[2]; // plugin parameters (usually just passes the registry address)
unsigned long plug_parms[3];
printf("Test program to pause catalina\n");
reg = _registry(); // address of registry
printf("Registry is at %x \n",reg);
print_registry();
readcog("plugin.cog",cogject_plugin);
//plugin_parameters[0] = (unsigned long) reg; // get the registry location
_cogstop(7);
plug_parms[0] = 0x12345678;
external_memory_cog_load(7, cogject_plugin, plug_parms); // start cog 7 with the plugin cogject, pass the registry
//plugin_engine_start(7,cogject_plugin,plugin_parameters);
sleep(1000); // time for cog to load and start running ? not needed
print7f();
printf("Cog plugin loaded \n",reg);
print_registry(); // print again, should have changed
_unregister_plugin(7); // unregister cog 7 but don't stop it running
printf("Unregister cog 7\n");
_register_plugin(7, 8); // register a fake cog number eg 7 is free, and with 8=DUM
printf("Reregister cog 7 as a dummy plugin\n");
cog = _locate_plugin(8);
printf("Cog number = %x \n",cog); // should print 7
return_value = _sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF)); // program should hang here
printf("Return value = %i \n",return_value); // and not print this unless some sort of cog code has restarted catalina
printf("End program\n");
while (1); // Prop reboots on exit from main()
}
With a plugin, you don't pass anything via par. The par variable always holds the address of the registry, which is common to all plugins.
Whatever you specify as the second parameter to _sys_plugin is written to the request long of the specified plugin in the registry, and the plugin can read it from there.
UPDATE: A small patch release (3.0.1) is now available, and is attached to the top post in this thread. This update must be installed over an existing Catalina 3.0 installation. It contains several minor improvements for all platforms, as well as significant bug fixes and improvements related to loading programs into Flash on the C3. Here are the main changes:
Fix a bug in the HUB Flash loader (used on the C3 and Morpheus) which meant the read/write sectors were not being correctly copied from Flash to SPI RAM. This caused mysterious failures such as the SD card file system not working correctly.
The default behaviour when programming SPI FLASH (e.g. on the C3 and the Morpheus platforms) is now to erase each 4k block just before programming (instead of initially doing a full chip erase). The previous behaviour can be reinstated by defining the symbol CHIP_ERASE when compiling (e.g. when compiling the utilities or Catalyst folders). One result of this is that when using Payload to load a program on the C3, it is no longer necessary to extend the payload timeout by adding an option like '-t 1000' to the command. Another benefit is that loading programs into SPI FLASH is faster when using both Payload and the Catalyst loader.
Added ERASE_CHECK and WRITE_CHECK optons to the caching SPI driver. These options can help improve reliability when programming the SPI FLASH (e.g. on the C3 or Morpheus). Note that ERASE_CHECK is only applied to the whole flash chip erase, not the block erase. Only the WRITE_CHECK is enabled by default, since it does not take much time (the erase check, on the other hand, can take around 15 seconds!). To enable the erase check, define the symbol ERASE_CHECK when compiling (e.g. when compiling the utilities or Catalyst folders). Doing so may require even longer timeouts when using Payload (e.g. -t 4000).
For details on other changes, see the README.WhatsNew attached to the top post of this thread.
I've almost cracked it. It works now, but I have a question at the bottom of this.
With a plugin, you don't pass anything via par. The par variable always holds the address of the registry, which is common to all plugins.
Whatever you specify as the second parameter to _sys_plugin is written to the request long of the specified plugin in the registry, and the plugin can read it from there.
Not quite because I want to gain access to the pins but not via a plugin. So I don't want the plugin to register with catalina, otherwise catalina will restart. So I am passing the address of the registry but in a more roundabout way.
Looking back there were quite a number of problems:
1) How do you debug cogs when you can't print anything?
2) Little endian vs big endian. Only found that one once 1) was working.
3) Pointers vs variables. It gets me every time!
4) Copying cog code multiple times to an sd card. Must remember to use windows/shutdown on the sd card before pulling it out.
5) RDLONG and WRLONG both are value,address. For some reason I keep thinking one of them is the opposite to the other.
Getting cog code working from scratch is not easy and I have even more admiration for those that wrote the original code that we take for granted in the obex. Particularly the video code. I ended up making no progress at all starting from a clean sheet of pasm code, so I ended up reverse engineering an existing cogject and changing one line at a time. Hence I've ended up with the slightly esoteric cogject standard - viz, start with an array in C, put a variable in element 1,2,3 and leave element 0 blank. When loading this cog via the common cog loader from high ram, the cog loader puts a pointer to the array in element 0.
Hence, to pass the registry, put it in element 1, call the cog loader, then in pasm, add 4 to par and rdlong from this location.
And finally, why bother? Well, the 12 lines for access to external memory are also incredibly easy to use to access multiple parallel digital I/O. Just keep adding latches or buffers. So to me it makes sense to give those 12 lines a dual purpose in catalina, a) to access external memory to run XMM programs and b) to talk to the real world fast and without using any more prop pins.
Four things spring to mind - 20x4 LCD display, a parallel port, LED driver, and as a way of enabling multiple SPI devices in turn.
' Plugin demo for Catalina - pass the location of the registry and it places a value in the registry
' that restarts Catalina
CON
_clkfreq = 80_000_000 ' 5Mhz Crystal
_clkmode = xtal1 + pll16x ' x 16
PUB Main
coginit(1,@entry,0) ' cog 1, cogstart, dummy value
DAT
org 0
entry
mov t1,par ' start of the array = array[0]
add t1,#4 ' array[1]
rdlong registry,t1 ' value,address read this value from hub ram, equals the registry
wrlong zero,registry 'value,address store a zero to the registry first 4 bytes
cogid t1 ' get ...
shl t1,#2 ' ... our ...
add t1,registry ' ... registry block
rdlong rqstptr,t1 ' register ...
and rqstptr,low_24 ' ... this ...
wrlong zero,rqstptr ' ... plugin ...
mov t2,#8 ' Addit - CHANGED PTYPE TO 8 (not able to find a ref to ptype)
shl t2,#24 ' ... the ...
or t2,rqstptr ' ... appropriate ...
wrlong t2,t1 ' ... type
loop2 jmp #loop2 ' loop forever
'---------------------------------- Storage ------------------------------------
'
zero long 0 ' handy value (zero)
low_24 long $00FFFFFF ' handy value (lower 24 bits)
rqstptr long 0 ' request address
'rqst long 0 ' service request
'rslt long 0 ' service result
t1 long 0 ' temporary variable
t2 long 0 ' temporary variable
t3 long 0 ' temporary variable
arraylocation long 0
registry long 0
sevenf long $7F00 ' location for debugging
param long 0 ' saved initialization data
'
fit $1f0
and C code
#include <stdio.h>
// compile with catalina -lcx -D PLUGIN -lm -x5 -M 256k -d DRACBLADE -D HIRES_VGA myprog.c
// compile using XMM
// cogjects - sd card driver in catalina is a little slow so load up once into external ram then (re) load quicker from external ram
unsigned long cogject_plugin[512]; // external memory for plugin
// *************** functions ***************************************
void sleep(int milliseconds) // sleep function
{
_waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
}
char peek(int address) // function implementation of peek
{
return *((char *)address);
}
void poke(int address, char value) // function implementation of poke
{
*((char *)address) = value;
}
void external_memory_cog_load(int cognumber, unsigned long cogdata[], unsigned long parameters_array[]) // load a cog from external memory
{
unsigned long hubcog[512]; // create a local array, this is in hub ram, not external ram
int i;
for(i=0;i<512;i++)
{
hubcog[i]=cogdata[i]; // move from external memory to a local array in hub
}
_coginit((int)parameters_array>>2, (int)hubcog>>2, cognumber); // load the cog
}
int EoF (FILE* stream)
{
register int c, status = ((c = fgetc(stream)) == EOF);
ungetc(c,stream);
return status;
}
void readcog(char *filename,unsigned long external_cog[]) // read in a .cog file into external memory array
{
int i;
FILE *FP1;
i = 0;
if((FP1=fopen(filename,"rb"))==0) // open the file
{
fprintf(stderr,"Can't open file %s\n",filename);
exit(1);
}
fseek(FP1,0,0);
for(i=0;i<24;i++)
{
getc(FP1); // read in the first 24 bytes and discard
}
i = 0;
while(!EoF(FP1) & (i<505)) // run until end of file or 511-6
{
external_cog[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24); // get the long
i+=1;
}
if(FP1)
{
fclose(FP1); // close the file
FP1=NULL;
}
//printf("external array cog first long = 0x%x \n",external_cog[0]); // hex value
}
void print_registry() // 32 bytes
{
int reg;
int i;
char peekbyte;
reg = _registry();
printf("0x%x = ",reg);
for (i=0;i<32;i++)
{
peekbyte = peek(reg+i);
if (peekbyte < 16)
{
printf("0");
}
printf("%x",peekbyte);
}
printf ("\n"); // carriage return
}
void plugin_engine_start(int cognumber, unsigned long cogarray[], unsigned long plugin_parameters[])
{
plugin_parameters[0] = (unsigned long) &plugin_parameters[0]; // the first long of the array points to the location of the array itself
_cogstop(cognumber); // stop this cog
external_memory_cog_load(cognumber,cogarray,plugin_parameters); // load from external ram to this cog, pass location of the array
}
void print7f()
{
int i;
char peekbyte;
printf("4 bytes from 7f00 to 7f03 are ");
for (i=0;i<4;i++)
{
peekbyte = peek(0x7f00+i);
if (peekbyte < 16)
{
printf("0");
}
printf("%x ",peekbyte);
}
printf ("\n"); // carriage return
}
void main ()
{
long plugin_type = 8;
long code = 22;
long param = 0;
int return_value;
unsigned reg;
int cog;
int i;
unsigned long plugin_parameters[2]; // plugin parameters (usually just passes the registry address but could pass other things)
printf("Test program to pause catalina\n");
reg = _registry(); // address of registry
printf("Registry is at %x \n",reg);
print_registry();
readcog("plugin.cog",cogject_plugin);
plugin_parameters[1] = (unsigned long) reg; // array[0] is always a pointer to the array itself, so start at 1
printf("plugin_parameters is at %x \n",&plugin_parameters[0]);
plugin_engine_start(7,cogject_plugin,plugin_parameters);
//print7f();
printf("Cog plugin loaded \n",reg);
print_registry(); // print again, should have changed
_unregister_plugin(7); // unregister cog 7 but don't stop it running
printf("Unregister cog 7\n");
_register_plugin(7, 8); // register a fake cog number eg 7 is free, and with 8=DUM
printf("Reregister cog 7 as a dummy plugin\n");
cog = _locate_plugin(8);
printf("Cog number = %x \n",cog); // should print 7
return_value = _sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF)); // program should hang here
printf("Return value = %i \n",return_value); // and not print this unless some sort of cog code has restarted catalina
printf("End program\n");
while (1); // Prop reboots on exit from main()
}
And now the problem. The pasm code is borrowed from an existing plugin and I think it is supposed to read the registry, add an offset (14 for cog #7), logical AND with 0x00ffffff and then write back to the registry.
This doesn't seem to allow catalina to restart.
But what does seem to restart catalina is writing a long 0x00000000 to the location registry+0 (ie to 0x7fd4)
Is this the location _sys_plugin is scanning to restart catalina?
I've almost cracked it. It works now, but I have a question at the bottom of this.
With a plugin, you don't pass anything via par. The par variable always holds the address of the registry, which is common to all plugins.
Whatever you specify as the second parameter to _sys_plugin is written to the request long of the specified plugin in the registry, and the plugin can read it from there.
Not quite because I want to gain access to the pins but not via a plugin. So I don't want the plugin to register with catalina, otherwise catalina will restart. So I am passing the address of the registry but in a more roundabout way.
Looking back there were quite a number of problems:
1) How do you debug cogs when you can't print anything?
2) Little endian vs big endian. Only found that one once 1) was working.
3) Pointers vs variables. It gets me every time!
4) Copying cog code multiple times to an sd card. Must remember to use windows/shutdown on the sd card before pulling it out.
5) RDLONG and WRLONG both are value,address. For some reason I keep thinking one of them is the opposite to the other.
Getting cog code working from scratch is not easy and I have even more admiration for those that wrote the original code that we take for granted in the obex. Particularly the video code. I ended up making no progress at all starting from a clean sheet of pasm code, so I ended up reverse engineering an existing cogject and changing one line at a time. Hence I've ended up with the slightly esoteric cogject standard - viz, start with an array in C, put a variable in element 1,2,3 and leave element 0 blank. When loading this cog via the common cog loader from high ram, the cog loader puts a pointer to the array in element 0.
Hence, to pass the registry, put it in element 1, call the cog loader, then in pasm, add 4 to par and rdlong from this location.
And finally, why bother? Well, the 12 lines for access to external memory are also incredibly easy to use to access multiple parallel digital I/O. Just keep adding latches or buffers. So to me it makes sense to give those 12 lines a dual purpose in catalina, a) to access external memory to run XMM programs and b) to talk to the real world fast and without using any more prop pins.
Four things spring to mind - 20x4 LCD display, a parallel port, LED driver, and as a way of enabling multiple SPI devices in turn.
' Plugin demo for Catalina - pass the location of the registry and it places a value in the registry
' that restarts Catalina
CON
_clkfreq = 80_000_000 ' 5Mhz Crystal
_clkmode = xtal1 + pll16x ' x 16
PUB Main
coginit(1,@entry,0) ' cog 1, cogstart, dummy value
DAT
org 0
entry
mov t1,par ' start of the array = array[0]
add t1,#4 ' array[1]
rdlong registry,t1 ' value,address read this value from hub ram, equals the registry
wrlong zero,registry 'value,address store a zero to the registry first 4 bytes
cogid t1 ' get ...
shl t1,#2 ' ... our ...
add t1,registry ' ... registry block
rdlong rqstptr,t1 ' register ...
and rqstptr,low_24 ' ... this ...
wrlong zero,rqstptr ' ... plugin ...
mov t2,#8 ' Addit - CHANGED PTYPE TO 8 (not able to find a ref to ptype)
shl t2,#24 ' ... the ...
or t2,rqstptr ' ... appropriate ...
wrlong t2,t1 ' ... type
loop2 jmp #loop2 ' loop forever
'---------------------------------- Storage ------------------------------------
'
zero long 0 ' handy value (zero)
low_24 long $00FFFFFF ' handy value (lower 24 bits)
rqstptr long 0 ' request address
'rqst long 0 ' service request
'rslt long 0 ' service result
t1 long 0 ' temporary variable
t2 long 0 ' temporary variable
t3 long 0 ' temporary variable
arraylocation long 0
registry long 0
sevenf long $7F00 ' location for debugging
param long 0 ' saved initialization data
'
fit $1f0
and C code
#include <stdio.h>
// compile with catalina -lcx -D PLUGIN -lm -x5 -M 256k -d DRACBLADE -D HIRES_VGA myprog.c
// compile using XMM
// cogjects - sd card driver in catalina is a little slow so load up once into external ram then (re) load quicker from external ram
unsigned long cogject_plugin[512]; // external memory for plugin
// *************** functions ***************************************
void sleep(int milliseconds) // sleep function
{
_waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
}
char peek(int address) // function implementation of peek
{
return *((char *)address);
}
void poke(int address, char value) // function implementation of poke
{
*((char *)address) = value;
}
void external_memory_cog_load(int cognumber, unsigned long cogdata[], unsigned long parameters_array[]) // load a cog from external memory
{
unsigned long hubcog[512]; // create a local array, this is in hub ram, not external ram
int i;
for(i=0;i<512;i++)
{
hubcog[i]=cogdata[i]; // move from external memory to a local array in hub
}
_coginit((int)parameters_array>>2, (int)hubcog>>2, cognumber); // load the cog
}
int EoF (FILE* stream)
{
register int c, status = ((c = fgetc(stream)) == EOF);
ungetc(c,stream);
return status;
}
void readcog(char *filename,unsigned long external_cog[]) // read in a .cog file into external memory array
{
int i;
FILE *FP1;
i = 0;
if((FP1=fopen(filename,"rb"))==0) // open the file
{
fprintf(stderr,"Can't open file %s\n",filename);
exit(1);
}
fseek(FP1,0,0);
for(i=0;i<24;i++)
{
getc(FP1); // read in the first 24 bytes and discard
}
i = 0;
while(!EoF(FP1) & (i<505)) // run until end of file or 511-6
{
external_cog[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24); // get the long
i+=1;
}
if(FP1)
{
fclose(FP1); // close the file
FP1=NULL;
}
//printf("external array cog first long = 0x%x \n",external_cog[0]); // hex value
}
void print_registry() // 32 bytes
{
int reg;
int i;
char peekbyte;
reg = _registry();
printf("0x%x = ",reg);
for (i=0;i<32;i++)
{
peekbyte = peek(reg+i);
if (peekbyte < 16)
{
printf("0");
}
printf("%x",peekbyte);
}
printf ("\n"); // carriage return
}
void plugin_engine_start(int cognumber, unsigned long cogarray[], unsigned long plugin_parameters[])
{
plugin_parameters[0] = (unsigned long) &plugin_parameters[0]; // the first long of the array points to the location of the array itself
_cogstop(cognumber); // stop this cog
external_memory_cog_load(cognumber,cogarray,plugin_parameters); // load from external ram to this cog, pass location of the array
}
void print7f()
{
int i;
char peekbyte;
printf("4 bytes from 7f00 to 7f03 are ");
for (i=0;i<4;i++)
{
peekbyte = peek(0x7f00+i);
if (peekbyte < 16)
{
printf("0");
}
printf("%x ",peekbyte);
}
printf ("\n"); // carriage return
}
void main ()
{
long plugin_type = 8;
long code = 22;
long param = 0;
int return_value;
unsigned reg;
int cog;
int i;
unsigned long plugin_parameters[2]; // plugin parameters (usually just passes the registry address but could pass other things)
printf("Test program to pause catalina\n");
reg = _registry(); // address of registry
printf("Registry is at %x \n",reg);
print_registry();
readcog("plugin.cog",cogject_plugin);
plugin_parameters[1] = (unsigned long) reg; // array[0] is always a pointer to the array itself, so start at 1
printf("plugin_parameters is at %x \n",&plugin_parameters[0]);
plugin_engine_start(7,cogject_plugin,plugin_parameters);
//print7f();
printf("Cog plugin loaded \n",reg);
print_registry(); // print again, should have changed
_unregister_plugin(7); // unregister cog 7 but don't stop it running
printf("Unregister cog 7\n");
_register_plugin(7, 8); // register a fake cog number eg 7 is free, and with 8=DUM
printf("Reregister cog 7 as a dummy plugin\n");
cog = _locate_plugin(8);
printf("Cog number = %x \n",cog); // should print 7
return_value = _sys_plugin (plugin_type, (code<<24) + (param & 0x00FFFFFF)); // program should hang here
printf("Return value = %i \n",return_value); // and not print this unless some sort of cog code has restarted catalina
printf("End program\n");
while (1); // Prop reboots on exit from main()
}
And now the problem. The pasm code is borrowed from an existing plugin and I think it is supposed to read the registry, add an offset (14 for cog #7), logical AND with 0x00ffffff and then write back to the registry.
This doesn't seem to allow catalina to restart.
But what does seem to restart catalina is writing a long 0x00000000 to the location registry+0 (ie to 0x7fd4)
Is this the location _sys_plugin is scanning to restart catalina?
And now the problem. The pasm code is borrowed from an existing plugin and I think it is supposed to read the registry, add an offset (14 for cog #7), logical AND with 0x00ffffff and then write back to the registry.
This doesn't seem to allow catalina to restart.
But what does seem to restart catalina is writing a long 0x00000000 to the location registry+0 (ie to 0x7fd4)
Is this the location _sys_plugin is scanning to restart catalina?
The PASM code you borrowed and modified was probably code to register the plugin. Here is the sequence of events a plugin would typically go through to register itself on startup (for an example of the actual code, see the generic plugin):
Get the registry address. This is passed to every plugin in its par parameter.
Get your cog id and multiply it by 4. Add this value to the registry address.The result is a pointer to your registration long. We will use this pointer at least once more, so hang on to it temporarily.
Read the value in your registration long. The bottom 24 bits of this value is a pointer to your request block. Most plugins will use this pointer many times, so it is useful to save it.
Initialize the first long in your request block (by writing a zero to it).
Replace the top 8 bits of the value in your registration block with the non-zero value that represents your plugin type. By doing this, you are registering your plugin. This enables the kernel to find plugins by type when it needs to request a service. After this, most plugins no longer need the pointer to their registration block, and can simply discard it.
Then the plugin typically sits in a loop, reading the value in the first long of its request block occasionally (this is why we saved a pointer to this value earlier). Catalina will write a non-zero value to this long to indicate it has paused itself and is waiting for the plugin to perform a service indicated by the value it wrote to the request block. When the plugin has finished the service, it writes a zero to this long. This tells the Catalina kernel it can continue.
# Read the value in your registration long. The bottom 24 bits of this value is a pointer to your request block. Most plugins will use this pointer many times, so it is useful to save it.
# Initialize the first long in your request block (by writing a zero to it).
# Replace the top 8 bits of the value in your registration block with the non-zero value that represents your plugin type. By doing this, you are registering your plugin. This enables the kernel to find plugins by type when it needs to request a service. After this, most plugins no longer need the pointer to their registration block, and can simply discard it.
I am dumping the registry with 32 bytes so my longs come out in reverse order. Taking your points then, before registering I've got a value in the last long of cc7f00ff
Afterwards it gets changed to cc7f0008
So allowing for the swap in order, the 08 is me registering a plugin of type 8?
Taking the next bytes and reading them in reverse, does that mean I need to write something to location 007fcc?
I am dumping the registry with 32 bytes so my longs come out in reverse order. Taking your points then, before registering I've got a value in the last long of cc7f00ff
Afterwards it gets changed to cc7f0008
So allowing for the swap in order, the 08 is me registering a plugin of type 8?
Taking the next bytes and reading them in reverse, does that mean I need to write something to location 007fcc?
Yes, 0x00007fcc is the address of your request block. The long at this address is your request long. The next long (at 0x00007fd0) is your response long. Catalina will write a non-zero service request to your request long. You write a zero to this long to indicate you have completed the service. You may also have previously written a value you want returned by the service to the response long.
Ross.
P.S. The prop is a little-endian architecture, so when you print memory containing longs as bytes, the least significant byte of each long appears first. You'll get used to it
I guess this is a dumb question since Catalina C is ANSI compatible but can I assume that fseek works correctly under Catalina and that I can overwrite parts of a file I open in "w+" mode? My xbasic compiler may need to go back and fill in pointers to forward references and I don't want to assume that random access works and run into trouble later. I only really implemented sequential access in ZOG.
I guess this is a dumb question since Catalina C is ANSI compatible but can I assume that fseek works correctly under Catalina and that I can overwrite parts of a file I open in "w+" mode? My xbasic compiler may need to go back and fill in pointers to forward references and I don't want to assume that random access works and run into trouble later. I only really implemented sequential access in ZOG.
Hi David,
Yes, it is a dumb question you can assume fseek works correctly.
Thanks! I thought that would probably be the answer but I wanted to make sure. My original xbasic compiler wrote temporary "files" to RAM in an effort to run on boards that don't have an SD card but I'm beginning to think that I should just require an SD card or something that can hold at least a small flash filesystem in order to do self-hosted development. The xbasic VM can run on any Propeller chip like the Spin VM can. It's just the compiler that will likely require an SD card. This will allow me to write temporary files on the SD card filesystem instead of wasting valuable RAM.
@David - your discussion thread is looking very interesting - keep up the good work. WRT sd card, I am thinking that as a minimum any propeller system ought to have an SD card. The cards are so cheap and also kind of make flash ram and eeprom irrelevant.
@Ross - new avatar? Cool!
I've gone off on a slight tangent as I needed a rapid development system for writing both C and PASM at the same time. I've put both in the VB IDE. My propeller board always boots to Kyedos, and within Kyedos are several standalone .exe programs, one of which is XMODEM. So to compile a pasm program and download it, just click the "compile" button and it reboots the prop (resets from what is usually a C program running), runs Kyedos, does an xmodem transfer, then returns to Kyedos. Then hit F12 in the C window and that downloads and runs C. So any changes to pasm code and C code just need a couple of keypresses to download and run them.
Now back to the task at hand!
I have narrowed the bug down to three lines of code in pasm:
wrlong zero,sevenfdfour ' value, address write a zero to 7FD4
wrlong zero,sevenfcc ' value, address write a zero to 7FCC
wrlong zero,sevenfdzero ' value, address write a zero to 7FD0
I can then comment one or more out to see whether catalina restarts. And what I have found is that the first of those three is the only one that allows catalina to restart. The last one is the one that (I think) is the registry response, and this is not restarting Catalina.
I'm sure this is just a simple thing now!
Complete pasm code below:
' Plugin demo for Catalina - pass the location of the registry and it places a value in the registry
' that restarts Catalina
CON
_clkfreq = 80_000_000 ' 5Mhz Crystal
_clkmode = xtal1 + pll16x ' x 16
PUB Main
coginit(1,@entry,0) ' cog 1, cogstart, dummy value
DAT
org 0
entry
mov t1,par ' start of the array = array[0]
add t1,#4 ' array[1]
rdlong registry,t1 ' value,address read this value from hub ram, equals the registry
' wrlong zero,registry 'value,address store a zero to the registry first 4 bytes
' the line above does work and is replicated with the next line
wrlong zero,sevenfdfour ' value, address write a zero to 7FD4
wrlong zero,sevenfcc ' value, address write a zero to 7FCC
wrlong zero,sevenfdzero ' value, address write a zero to 7FD0
loop1 jmp #loop1 ' skip the next bit
' ************** end test program ***********************
cogid t1 ' get ...
shl t1,#2 ' ... our ...
add t1,registry ' ... registry block
rdlong rqstptr,t1 ' register ...
and rqstptr,low_24 ' ... this ...
wrlong zero,rqstptr ' ... plugin ...
mov t2,#8 ' Addit - CHANGED PTYPE TO 8 (not able to find a ref to ptype)
shl t2,#24 ' ... the ...
or t2,rqstptr ' ... appropriate ...
wrlong t2,t1 ' ... type
loop2 jmp #loop2 ' loop forever
'---------------------------------- Storage ------------------------------------
'
zero long 0 ' handy value (zero)
low_24 long $00FFFFFF ' handy value (lower 24 bits)
rqstptr long 0 ' request address
'rqst long 0 ' service request
'rslt long 0 ' service result
t1 long 0 ' temporary variable
t2 long 0 ' temporary variable
t3 long 0 ' temporary variable
arraylocation long 0
registry long 0
sevenf long $7F00 ' location for debugging
sevenfdzero long $7FD0 ' catalina registry
sevenfcc long $7FCC ' catalina registry
sevenfdfour long $7FD4 ' catalina registry
param long 0 ' saved initialization data
'
fit $1f0
{{
????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
? TERMS OF USE: MIT License ?
????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
?Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation ?
?files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, ?
?modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software?
?is furnished to do so, subject to the following conditions: ?
? ?
?The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.?
? ?
?THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE ?
?WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR ?
?COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ?
?ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ?
????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
}}
Your code is corrupting the registry, so the results will be unpredictable. I have attached a very simple example of how to load and call a PASM plugin from a C program. This working example will give you a base you can play around with.
Both the C program and the PASM plugin are only a page of code each. The C program just loads the plugin, and then calls it. This call pauses the kernel. When it is called, all the plugin does is wait 5 seconds, then release the kernel again.
To compile and load the example, unzip the attached file somewhere and enter the commands (for the DRACBLADE):
build_all DRACBLADE
payload test_plugin
The build_all batch file simply compiles the plugin using homespun, then uses the spinc utility to convert the resulting binary into a C array (called plugin_array.h) which is included in the C program, then it compiles the C program.
The C program loads the plugin using _coginit, then calls it using _sys_plugin. Just note that because I am loading the plugin from C (and not via a target) I must manually pass the registry location to the plugin when I start it (if the plugin were being loaded by the target, this would happen automatically).
I'm sure that if you study this example, you will see exactly what you need to do to pause the kernel (i.e. call _sys_plugin) and also restart it again (i.e. write a zero to the request block that belongs to the plugin that the kernel has just called).
In this demo it is the plugin itself that restarts the kernel after waiting for 5 seconds - but there is nothing to stop any other program (running in another cog) from monitoring the same hub RAM location and restarting the kernel instead.
Ross.
P.S. I just realized that because the plugin_array is a global array, this example will only work in TINY or SMALLL mode (i.e. where global variables are in Hub RAM) - in LARGE mode the array will be in XMM RAM, and the _coginit call will not work correctly. In a LARGE program you need to first copy plugin_array to a local array (e.g. one declared within the main function) and then pass the address of that array to the _coginit call instead!
So, analysing that code, this is the line that restarts C
wrlong zero,rqstptr ' release the kernel
Going back to what rqstptr is, it seems to be a hybrid of a value passed to it, and 00ffffff
rdlong rqstptr,t1 ' register ...
and rqstptr,low_24 ' ... this ...
wrlong zero,rqstptr ' ... plugin ...
I'm at the point where I think I can understand how to write a value to a certain location to tell catalina to restart. It seems I need to modify my code a little so there is an "and" with 0x00ffffffff
I get a bit lost though with the next part of the code and whether it is important or not for the purposes of restarting catalina:
mov t2,#DUM ' ... as ...
shl t2,#24 ' ... the ...
or t2,rqstptr ' ... dummy ...
wrlong t2,t1 ' ... type
This code is code that appears in a number of places in the demos, and is the code I started with when I tried to write some code to restart catalina. The steps I have been through over the last week are:
1) To try adding this code to my program and see if it works (it didn't)
2) To deconstruct it to some fixed locations in hub ram, and to write constants to those fixed locations (didn't work)
3) To try writing zeros to all locations in the registry and to see what happens (none of the recommended locations did anything, but writing to "registry+zero" does restart catalina)
So I have an answer that works (writing to registry plus zero) but I suspect this is working for some reason I don't understand, and I have the code that should work but doesn't, for reasons that I need to narrow down.
How relevant is the difference between writing a zero to the registry locations vs writing a combination value of the exsiting value "anded" with 0x00ffffff?
and how relevant is the registering of the dummy type?
I have a question though if you don't mind. I wasn't sure if this was intended or not, but I thought I would ask (I'm new to catalina so take it easy ).
In catalina_icc.h there is the following:
//
// waitpne(mask, pins) : wait for pins not equal
//
#ifdef __CATALINA__
#define waitne(mask, pins) _waitpne(mask, pins, 0)
#else
#define waitpne(mask, pins) waitpne(mask, pins)
#endif
Is this correct or should it be:
//
// waitpne(mask, pins) : wait for pins not equal
//
#ifdef __CATALINA__
#define waitpne(mask, pins) _waitpne(mask, pins, 0)
#else
#define waitpne(mask, pins) waitpne(mask, pins)
#endif
How relevant is the difference between writing a zero to the registry locations vs writing a combination value of the exsiting value "anded" with 0x00ffffff?
and how relevant is the registering of the dummy type?
Very relevant. Zeroing a plugin's registry block (rather than the first long of the request block pointed to by the registry block) will deregister that plugin (and also lose its request block!). Since the kernel can only find registered plugins, and will also expect the registered plugin to have a valid request block, it is important that the plugin be registered correctly.
I have re-commented (line by line) the code that seems to be causing you confusion:
cogid t1 ' get our own cog id
shl t1,#2 ' multiply our cog id by 4
add t1,par ' add in the registry base address (t1 now points to our registry block)
rdlong rqstptr,t1 ' read the current value in our registry block
and rqstptr,low_24 ' extract the request block addr (mask off the top 8 bits)
wrlong zero,rqstptr ' initialize our request long (just in case it is not already zero)
mov t2,#DUM ' get our plugin type (DUM = 8)
shl t2,#24 ' put it in the top 8 bits
or t2,rqstptr ' 'or' back in out request block addr
wrlong t2,t1 ' update our registry block (our cog is now registered as a DUM plugin!)
I have a question though if you don't mind. I wasn't sure if this was intended or not, but I thought I would ask (I'm new to catalina so take it easy ).
I'm afraid the code in post #263 does not work, so I am going to need to analyse this code right down line by line and value by value.
I now have an IDE working such that I can rapidly test pasm plugin code and the associated C code and this is greatly assisting debugging. This means I can start to narrow down actual hex values and compare them with the values that are expected.
The line in question is the line of code that restarts the kernel. It is this line in code:
wrlong zero,rqstptr ' release the kernel
But this line of code is not quite as simple as it seems, because a few lines earlier we have this line of code:
wrlong zero,rqstptr ' ... plugin ...
and this line of code is identical except for the comment. So, when I ask you what the value of rqstptr ought to be, this question is not so simple, because there are actually two values it needs to be:
1) the value after and rqstptr,low_24 ' ... this ...
2) the value after or t2,rqstptr ' ... dummy ...
Hang on, no that isn't right either.
or t2,rqstptr changes the value of t2, not of rqstptr. So...
consider this block of code
cogid t1 ' get ...
shl t1,#2 ' ... our ...
add t1,par ' ... registry block
rdlong rqstptr,t1 ' register ...
and rqstptr,low_24 ' ... this ...
wrlong zero,rqstptr ' ... plugin ...
mov t2,#DUM ' ... as ...
shl t2,#24 ' ... the ...
or t2,rqstptr ' ... dummy ...
wrlong t2,t1 ' ... type
service_loop
rdlong t1,rqstptr wz ' service request?
if_z jmp #service_loop ' no - just keep waiting
mov time,cnt ' yes - wait ...
add time,five_seconds ' ... for ...
waitcnt time,#0 ' ... five seconds
wrlong zero,rqstptr ' release the kernel
if rqstptr does not change after the line and rqstptr,low_24 ' ... this ...
then what is the difference between the first
wrlong zero,rqstptr
and the second one?
Whe doesn't the first one ( the line with the comment wrlong zero,rqstptr ' ... plugin ...) restart the kernel?
Ah, maybe the kernel can't be restarted until it is registered as a dummy type, even if the zero write is to the same location?
Well, if that is the case, then why isn't this code restarting the kernel? (and why, for that matter, <is> a write to 0x7fd4 restarting the kernel?)
So, we come back to the actual hex values and where they are written. I think this is the only way it is going to be possible to explain this code. Can I take you through each line of code as I think the values should be, and you can correct any of these that are not right?
cogid t1 ' get ...
I think cogid is 7, and so t1 contains 0x7
shl t1,#2 ' multiply our cog id by 4
I think t1 now contains 28
add t1,par ' ... registry block
par for me is 0x7fd4, so add 28 and I get 0x7ff0. I have a memory dump of this location and I know it contains the value 0xff007fcc
rdlong rqstptr,t1 ' register ...
I think rqstptr should contain the value 0xff007fcc
and rqstptr,low_24 ' ... this ...
low_24 contains the value 0x00ffffff so I think rqstptr should now contain the value 0x00007fcc
wrlong zero,rqstptr ' ... plugin ...
This writes a zero to hub memory location 0x00007fcc
mov t2,#DUM ' get our plugin type (DUM = 8)
dum is 8, so the value of t2 is 0x8
shl t2,#24 ' ... the ...
t2 should now be 0x08000000
or t2,rqstptr ' ... dummy ...
t2 should now be 0x08007fcc
wrlong t2,t1 ' ... type
this is a bit complicated. I think it writes the value 0x08007fcc to the hub memory location 0x00007fcc
The next bit is where I get lost though and where the code fails to work:
rdlong t1,rqstptr wz ' service request?
if_z jmp #service_loop ' no - just keep waiting
What I am wanting to do is for the pasm code to restart catalina. What this code is doing is waiting for catalina to send something through. BUT - the code I have written has already paused catalina earlier, so catalina is not going to send anything through.
So as far as I can see, this is never going to escape from the loop, and hence won't ever enter the 5 sec delay and restart catalina. And indeed this is what is happening.
So my questions now are:
1) are the hex values above correct and
2) Going right back to basics, is it possible to pause catalina, and for a pasm program to write a specific value (maybe zero, maybe something else) to a specific location in hub ram to restart catalina? If yes, and assuming the registry is at 7fd4, the cog id is 7 and the plugin value is DUM=8, what is that hub location in hex?
I'm afraid the code in post #263 does not work, so I am going to need to analyse this code right down line by line and value by value.
Yes, it does. I just downloaded it, unzipped it, compiled it and loaded it on my DRACBLADE again. Here is what I see on the screen ...
press any key to start ...
this should take 5 seconds...
... done!
press any key to try again ...
... with a 5 second wait at the point indicated.
What do see when you run this test program? If you don't see the above, please post what you do see, plus the output of executing the build_all command, plus the resulting binary file (i.e. test_plugin.binary).
Whe doesn't the first one ( the line with the comment wrlong zero,rqstptr ' ... plugin ...) restart the kernel?
Because when the first one is executed, the kernel isn't stopped. The first instruction is executed (once) when the plugin loads. The kernel is still running at this point. The first instruction simply makes sure the request block does not contain any rubbish that may have been left over from whatever was previously running in this cog.
Well, if that is the case, then why isn't this code restarting the kernel? (and why, for that matter, <is> a write to 0x7fd4 restarting the kernel?)
Writing to 0x7fd4 is overwriting the registry. I can't tell you precisely what the consequences of doing that will be, since I don't know what you are running in the cog whose registry block you are overwriting. This depends on how you started your program, and what other plugins you loaded.
So, we come back to the actual hex values and where they are written. I think this is the only way it is going to be possible to explain this code. Can I take you through each line of code as I think the values should be, and you can correct any of these that are not right?
cogid t1 ' get ...
I think cogid is 7, and so t1 contains 0x7
shl t1,#2 ' multiply our cog id by 4
I think t1 now contains 28
add t1,par ' ... registry block
par for me is 0x7fd4, so add 28 and I get 0x7ff0. I have a memory dump of this location and I know it contains the value 0xff007fcc
rdlong rqstptr,t1 ' register ...
I think rqstptr should contain the value 0xff007fcc
and rqstptr,low_24 ' ... this ...
low_24 contains the value 0x00ffffff so I think rqstptr should now contain the value 0x00007fcc
wrlong zero,rqstptr ' ... plugin ...
This writes a zero to hub memory location 0x00007fcc
mov t2,#DUM ' get our plugin type (DUM = 8)
dum is 8, so the value of t2 is 0x8
shl t2,#24 ' ... the ...
t2 should now be 0x08000000
or t2,rqstptr ' ... dummy ...
t2 should now be 0x08007fcc
wrlong t2,t1 ' ... type
this is a bit complicated. I think it writes the value 0x08007fcc to the hub memory location 0x00007fcc
No - it writes it to address 0x7ff0, since this is what t1 contains.
The next bit is where I get lost though and where the code fails to work:
rdlong t1,rqstptr wz ' service request?
if_z jmp #service_loop ' no - just keep waiting
What I am wanting to do is for the pasm code to restart catalina. What this code is doing is waiting for catalina to send something through. BUT - the code I have written has already paused catalina earlier, so catalina is not going to send anything through.
If you have paused Catalina by calling _sys_plugin specifying a plugin of type 8 and a non-zero parameter, then the plugin is no longer in this loop - it will have received a request already (i.e. the parameter to _sys_plugin), the test in this loop will already have failed, and the plugin will now be executing the instructions after this loop.
So as far as I can see, this is never going to escape from the loop, and hence won't ever enter the 5 sec delay and restart catalina. And indeed this is what is happening.
It works on my DRACBLADE. We need to find out why it is not working on yours.
and
2) Going right back to basics, is it possible to pause catalina, and for a pasm program to write a specific value (maybe zero, maybe something else) to a specific location in hub ram to restart catalina?
Yes - this is exactly what the test program does. We need to find out why this program fails on your DRACBLADE.
If yes, and assuming the registry is at 7fd4, the cog id is 7 and the plugin value is DUM=8, what is that hub location in hex?
$7FCC - but before you race off and hardcode this value somewhere, can you first build and run the test program I posted - exactly as I posted it - and then ...
Tell me what output you see. If it is not what I have posted at the top, then tell me what it is, and also ...
Post the output of the build_all script, and also the executable test_plugin.binary.
UPDATE: I have attached a new version of catalina_icc.h to the top post in this thread - this corrects some typos in the waitpne and waitpeq macros (thanks to James Dougherty for spotting them!).
You only need this file if you are writing C code you need to compile under both the Catalina and ICC compilers.
Just copy the new version of this file over the existing version in the include directory. I will also incorporate it into the next Catalina release.
$7FCC - but before you race off and hardcode this value somewhere, can you first build and run the test program I posted - exactly as I posted it - and then ...
ok, compiling on my IDE I get this. I don't know what to do with the batch program and it probably has to be run from a particular directory which has a particular include in it, which may or may not be the same as your include, which may introduce other variables. But here is the error of that C code as it is, compiled with catalina -lcx -D PLUGIN -x5 -M 256k -D DRACBLADE -D HIRES_VGA NEW.C
===================
SETTING UP CATALINA
===================
CATALINA_DEFINE = [default]
CATALINA_INCLUDE = [default]
CATALINA_LIBRARY = [default]
CATALINA_TARGET = [default]
CATALINA_LCCOPT = [default]
CATALINA_TEMPDIR = [default]
LCCDIR = [default]
Catalina Compiler 3.0
cpp: NEW.C:8 Could not find include file "plugin_array.h"
cpp: NEW.C:39 No newline at end of file
Press any key to continue . . .
But of course we are going backwards a little here, because in getting to where I have already got, I had to pull apart the three #includes to find code that was critical to getting the one bit of code working - which is the write of a zero to 7fd4.
A write to 7fcc does not work on my board. But of course I have hardcoded some things to try to get as much as possible out of any #includes so it is clearer what is going on. EG DUM is 8, and ANY_COG is 7
Can we eliminate any variables by thinking about code with no #includes?
Comments
Many thanks - it was the only hangup I came across in porting from 2.6 to 3.0
The secret to all this was to download version 3.0. This program hangs as expected. Registry is now at 7fd4
Glad you got it not working!
I'm a bit puzzled as to why it didn't not work on under 2.6 (actually, I'm even more amazed that you were still using a version of Catalina is now four releases old! I cringe whenever I have to go back even just one release and see all the silly mistakes I made - but I may have a look and see if I can figure out why).
As to your other question - yes, you can have a local copy of XMM.binary wherever you like - if it exists in the local directory when you call payload, it will be used in preference to the one in the Catalina bin directory.
Ross.
Ok, next step is to build a minimalist pasm program capable of restarting catalina. To do this I think I need to write a certain value back to the registry. This is my working program, with an additional line at the beginning that does absolutely nothing as I'm trying to debug another error at the moment. I'll remove that loop shortly. I changed one value #ptype to 8 - would that be correct?
My complete C program is here and I'll describe where the bug is below:
The pasm program is compiled with F8 on the spintool, and saved as a binary file "plugin.cog" and copied over to the sd card. As it is - it does absolutely nothing at all.
If I comment out this line in the C program
Then the program runs up to the point of printing "Cog number = 7" and then hangs as expected.
However, if I add that line in C and it loads up the pasm code (which is doing nothing at the moment), then it prints
"Cog number = a63f1e37"
I tested this with some other cogjects and it is the same.
Given that this pasm code does nothing at all, and that other cogjects repeat the cog number error, I think that means the problem is in the C code.
What I think I need to do is to load up a cog and then somehow get catalina to forget that it ever loaded that cog. I tried unregistering the cog but that doesn't seem to work.
This is the strange bit. I even tried running a cogstop and that doesn't work either. The cog number still prints out that long hex number instead of 7.
I am wondering if I am somehow corrupting the registry by calling external_memory_cog_load which in turn calls this
Hi David,
Not sure how you're getting on with your loader, but I've checked the actual code, and also loaded programs and dumped the resulting Flash.
Here is what you should see in Flash when payload has loaded a program:
For Layout 3 (FLASH equivalent of XMM LARGE):
Read-Only Segments (i.e. Code+Cnst) ($0200 .. $0200 + Code Size + Cnst Size - 1)
<-- zeroes till the next $200 boundary -->
Read-Write Segments (i.e. Init+Data)
<-- zeroes till the next $200 boundary -->
Read-Only Segments (i.e. Code) ($0200 .. $0200 + Code Size - 1)
<-- zeroes till the next $200 boundary -->
Read-Write Segments (i.e. Cnst+Init+Data)
<-- zeroes till the next $200 boundary -->
I'm not sure how or why you would be seeing data in Flash that did not come from the binary file. If you can find a case where this occurs, please post the binary that causes it and I will investigate.
Ross.
Well spotted, kuroneko! Does this change the behvaiour, Dr_A?
Thanks for the additional information on flash layout. I think I was wrong about my comment that I found data in flash that didn't come out of the binary file. I made that claim before I realized that my dump program was messing up the endianness of the data it was displaying. I'm pretty sure that the data did come from the file but it was byte-swapped so I didn't recognize it. Sorry for the false alarm!
My whole reason for playing with this loader is that I think it will be significantly faster than payload. I guess I'll try to measure its performance before I continue much further to verify if that is really true. If it isn't, there is no real reason to continue since payload already works well.
Spin code
and C code
With a plugin, you don't pass anything via par. The par variable always holds the address of the registry, which is common to all plugins.
Whatever you specify as the second parameter to _sys_plugin is written to the request long of the specified plugin in the registry, and the plugin can read it from there.
Ross.
- Added ERASE_CHECK and WRITE_CHECK optons to the caching SPI driver. These options can help improve reliability when programming the SPI FLASH (e.g. on the C3 or Morpheus). Note that ERASE_CHECK is only applied to the whole flash chip erase, not the block erase. Only the WRITE_CHECK is enabled by default, since it does not take much time (the erase check, on the other hand, can take around 15 seconds!). To enable the erase check, define the symbol ERASE_CHECK when compiling (e.g. when compiling the utilities or Catalyst folders). Doing so may require even longer timeouts when using Payload (e.g. -t 4000).
For details on other changes, see the README.WhatsNew attached to the top post of this thread.Ross.
I've almost cracked it. It works now, but I have a question at the bottom of this.
Not quite because I want to gain access to the pins but not via a plugin. So I don't want the plugin to register with catalina, otherwise catalina will restart. So I am passing the address of the registry but in a more roundabout way.
Looking back there were quite a number of problems:
1) How do you debug cogs when you can't print anything?
2) Little endian vs big endian. Only found that one once 1) was working.
3) Pointers vs variables. It gets me every time!
4) Copying cog code multiple times to an sd card. Must remember to use windows/shutdown on the sd card before pulling it out.
5) RDLONG and WRLONG both are value,address. For some reason I keep thinking one of them is the opposite to the other.
Getting cog code working from scratch is not easy and I have even more admiration for those that wrote the original code that we take for granted in the obex. Particularly the video code. I ended up making no progress at all starting from a clean sheet of pasm code, so I ended up reverse engineering an existing cogject and changing one line at a time. Hence I've ended up with the slightly esoteric cogject standard - viz, start with an array in C, put a variable in element 1,2,3 and leave element 0 blank. When loading this cog via the common cog loader from high ram, the cog loader puts a pointer to the array in element 0.
Hence, to pass the registry, put it in element 1, call the cog loader, then in pasm, add 4 to par and rdlong from this location.
And finally, why bother? Well, the 12 lines for access to external memory are also incredibly easy to use to access multiple parallel digital I/O. Just keep adding latches or buffers. So to me it makes sense to give those 12 lines a dual purpose in catalina, a) to access external memory to run XMM programs and b) to talk to the real world fast and without using any more prop pins.
Four things spring to mind - 20x4 LCD display, a parallel port, LED driver, and as a way of enabling multiple SPI devices in turn.
and C code
And now the problem. The pasm code is borrowed from an existing plugin and I think it is supposed to read the registry, add an offset (14 for cog #7), logical AND with 0x00ffffff and then write back to the registry.
This doesn't seem to allow catalina to restart.
But what does seem to restart catalina is writing a long 0x00000000 to the location registry+0 (ie to 0x7fd4)
Is this the location _sys_plugin is scanning to restart catalina?
I've almost cracked it. It works now, but I have a question at the bottom of this.
Not quite because I want to gain access to the pins but not via a plugin. So I don't want the plugin to register with catalina, otherwise catalina will restart. So I am passing the address of the registry but in a more roundabout way.
Looking back there were quite a number of problems:
1) How do you debug cogs when you can't print anything?
2) Little endian vs big endian. Only found that one once 1) was working.
3) Pointers vs variables. It gets me every time!
4) Copying cog code multiple times to an sd card. Must remember to use windows/shutdown on the sd card before pulling it out.
5) RDLONG and WRLONG both are value,address. For some reason I keep thinking one of them is the opposite to the other.
Getting cog code working from scratch is not easy and I have even more admiration for those that wrote the original code that we take for granted in the obex. Particularly the video code. I ended up making no progress at all starting from a clean sheet of pasm code, so I ended up reverse engineering an existing cogject and changing one line at a time. Hence I've ended up with the slightly esoteric cogject standard - viz, start with an array in C, put a variable in element 1,2,3 and leave element 0 blank. When loading this cog via the common cog loader from high ram, the cog loader puts a pointer to the array in element 0.
Hence, to pass the registry, put it in element 1, call the cog loader, then in pasm, add 4 to par and rdlong from this location.
And finally, why bother? Well, the 12 lines for access to external memory are also incredibly easy to use to access multiple parallel digital I/O. Just keep adding latches or buffers. So to me it makes sense to give those 12 lines a dual purpose in catalina, a) to access external memory to run XMM programs and b) to talk to the real world fast and without using any more prop pins.
Four things spring to mind - 20x4 LCD display, a parallel port, LED driver, and as a way of enabling multiple SPI devices in turn.
and C code
And now the problem. The pasm code is borrowed from an existing plugin and I think it is supposed to read the registry, add an offset (14 for cog #7), logical AND with 0x00ffffff and then write back to the registry.
This doesn't seem to allow catalina to restart.
But what does seem to restart catalina is writing a long 0x00000000 to the location registry+0 (ie to 0x7fd4)
Is this the location _sys_plugin is scanning to restart catalina?
The PASM code you borrowed and modified was probably code to register the plugin. Here is the sequence of events a plugin would typically go through to register itself on startup (for an example of the actual code, see the generic plugin):
- Get the registry address. This is passed to every plugin in its par parameter.
- Get your cog id and multiply it by 4. Add this value to the registry address.The result is a pointer to your registration long. We will use this pointer at least once more, so hang on to it temporarily.
- Read the value in your registration long. The bottom 24 bits of this value is a pointer to your request block. Most plugins will use this pointer many times, so it is useful to save it.
- Initialize the first long in your request block (by writing a zero to it).
- Replace the top 8 bits of the value in your registration block with the non-zero value that represents your plugin type. By doing this, you are registering your plugin. This enables the kernel to find plugins by type when it needs to request a service. After this, most plugins no longer need the pointer to their registration block, and can simply discard it.
Then the plugin typically sits in a loop, reading the value in the first long of its request block occasionally (this is why we saved a pointer to this value earlier). Catalina will write a non-zero value to this long to indicate it has paused itself and is waiting for the plugin to perform a service indicated by the value it wrote to the request block. When the plugin has finished the service, it writes a zero to this long. This tells the Catalina kernel it can continue.Ross.
I am dumping the registry with 32 bytes so my longs come out in reverse order. Taking your points then, before registering I've got a value in the last long of cc7f00ff
Afterwards it gets changed to cc7f0008
So allowing for the swap in order, the 08 is me registering a plugin of type 8?
Taking the next bytes and reading them in reverse, does that mean I need to write something to location 007fcc?
Yes, 0x00007fcc is the address of your request block. The long at this address is your request long. The next long (at 0x00007fd0) is your response long. Catalina will write a non-zero service request to your request long. You write a zero to this long to indicate you have completed the service. You may also have previously written a value you want returned by the service to the response long.
Ross.
P.S. The prop is a little-endian architecture, so when you print memory containing longs as bytes, the least significant byte of each long appears first. You'll get used to it
Yes, it is a dumb question you can assume fseek works correctly.
Or at least that it is supposed to!
Ross.
@Ross - new avatar? Cool!
I've gone off on a slight tangent as I needed a rapid development system for writing both C and PASM at the same time. I've put both in the VB IDE. My propeller board always boots to Kyedos, and within Kyedos are several standalone .exe programs, one of which is XMODEM. So to compile a pasm program and download it, just click the "compile" button and it reboots the prop (resets from what is usually a C program running), runs Kyedos, does an xmodem transfer, then returns to Kyedos. Then hit F12 in the C window and that downloads and runs C. So any changes to pasm code and C code just need a couple of keypresses to download and run them.
Now back to the task at hand!
I have narrowed the bug down to three lines of code in pasm:
I can then comment one or more out to see whether catalina restarts. And what I have found is that the first of those three is the only one that allows catalina to restart. The last one is the one that (I think) is the registry response, and this is not restarting Catalina.
I'm sure this is just a simple thing now!
Complete pasm code below:
Your code is corrupting the registry, so the results will be unpredictable. I have attached a very simple example of how to load and call a PASM plugin from a C program. This working example will give you a base you can play around with.
Both the C program and the PASM plugin are only a page of code each. The C program just loads the plugin, and then calls it. This call pauses the kernel. When it is called, all the plugin does is wait 5 seconds, then release the kernel again.
To compile and load the example, unzip the attached file somewhere and enter the commands (for the DRACBLADE): The build_all batch file simply compiles the plugin using homespun, then uses the spinc utility to convert the resulting binary into a C array (called plugin_array.h) which is included in the C program, then it compiles the C program.
The C program loads the plugin using _coginit, then calls it using _sys_plugin. Just note that because I am loading the plugin from C (and not via a target) I must manually pass the registry location to the plugin when I start it (if the plugin were being loaded by the target, this would happen automatically).
I'm sure that if you study this example, you will see exactly what you need to do to pause the kernel (i.e. call _sys_plugin) and also restart it again (i.e. write a zero to the request block that belongs to the plugin that the kernel has just called).
In this demo it is the plugin itself that restarts the kernel after waiting for 5 seconds - but there is nothing to stop any other program (running in another cog) from monitoring the same hub RAM location and restarting the kernel instead.
Ross.
P.S. I just realized that because the plugin_array is a global array, this example will only work in TINY or SMALLL mode (i.e. where global variables are in Hub RAM) - in LARGE mode the array will be in XMM RAM, and the _coginit call will not work correctly. In a LARGE program you need to first copy plugin_array to a local array (e.g. one declared within the main function) and then pass the address of that array to the _coginit call instead!
So, analysing that code, this is the line that restarts C
Going back to what rqstptr is, it seems to be a hybrid of a value passed to it, and 00ffffff
I'm at the point where I think I can understand how to write a value to a certain location to tell catalina to restart. It seems I need to modify my code a little so there is an "and" with 0x00ffffffff
I get a bit lost though with the next part of the code and whether it is important or not for the purposes of restarting catalina:
This code is code that appears in a number of places in the demos, and is the code I started with when I tried to write some code to restart catalina. The steps I have been through over the last week are:
1) To try adding this code to my program and see if it works (it didn't)
2) To deconstruct it to some fixed locations in hub ram, and to write constants to those fixed locations (didn't work)
3) To try writing zeros to all locations in the registry and to see what happens (none of the recommended locations did anything, but writing to "registry+zero" does restart catalina)
So I have an answer that works (writing to registry plus zero) but I suspect this is working for some reason I don't understand, and I have the code that should work but doesn't, for reasons that I need to narrow down.
How relevant is the difference between writing a zero to the registry locations vs writing a combination value of the exsiting value "anded" with 0x00ffffff?
and how relevant is the registering of the dummy type?
For this line of code
could you tell me the value in hex of "rqstptr"?
I have a question though if you don't mind. I wasn't sure if this was intended or not, but I thought I would ask (I'm new to catalina so take it easy ).
In catalina_icc.h there is the following:
//
// waitpne(mask, pins) : wait for pins not equal
//
#ifdef __CATALINA__
#define waitne(mask, pins) _waitpne(mask, pins, 0)
#else
#define waitpne(mask, pins) waitpne(mask, pins)
#endif
//
// waitpeq(mask, pins) : wait for pins equal
//
#ifdef __CATALINA__
#define waitne(mask, pins) _waitpne(mask, pins, 0)
#else
#define waitpne(mask, pins) waitpne(mask, pins)
#endif
Is this correct or should it be:
//
// waitpne(mask, pins) : wait for pins not equal
//
#ifdef __CATALINA__
#define waitpne(mask, pins) _waitpne(mask, pins, 0)
#else
#define waitpne(mask, pins) waitpne(mask, pins)
#endif
//
// waitpeq(mask, pins) : wait for pins equal
//
#ifdef __CATALINA__
#define waitpeq(mask, pins) _waitpeq(mask, pins, 0)
#else
#define waitpeq(mask, pins) waitpeq(mask, pins)
#endif
Again thank you.
That's correct.
Very relevant. Zeroing a plugin's registry block (rather than the first long of the request block pointed to by the registry block) will deregister that plugin (and also lose its request block!). Since the kernel can only find registered plugins, and will also expect the registered plugin to have a valid request block, it is important that the plugin be registered correctly.
I have re-commented (line by line) the code that seems to be causing you confusion: I hope this makes it a bit clearer.
No - because I don't know the cog id your plugin will be loaded in. This is what the first five instructions of the code above calculates.
Ross.
Oops! You are quite correct. I'll post a fixed version when I get home.
Ross.
I'm afraid the code in post #263 does not work, so I am going to need to analyse this code right down line by line and value by value.
I now have an IDE working such that I can rapidly test pasm plugin code and the associated C code and this is greatly assisting debugging. This means I can start to narrow down actual hex values and compare them with the values that are expected.
The line in question is the line of code that restarts the kernel. It is this line in code:
But this line of code is not quite as simple as it seems, because a few lines earlier we have this line of code:
and this line of code is identical except for the comment. So, when I ask you what the value of rqstptr ought to be, this question is not so simple, because there are actually two values it needs to be:
1) the value after and rqstptr,low_24 ' ... this ...
2) the value after or t2,rqstptr ' ... dummy ...
Hang on, no that isn't right either.
or t2,rqstptr changes the value of t2, not of rqstptr. So...
consider this block of code
if rqstptr does not change after the line and rqstptr,low_24 ' ... this ...
then what is the difference between the first
wrlong zero,rqstptr
and the second one?
Whe doesn't the first one ( the line with the comment wrlong zero,rqstptr ' ... plugin ...) restart the kernel?
Ah, maybe the kernel can't be restarted until it is registered as a dummy type, even if the zero write is to the same location?
Well, if that is the case, then why isn't this code restarting the kernel? (and why, for that matter, <is> a write to 0x7fd4 restarting the kernel?)
So, we come back to the actual hex values and where they are written. I think this is the only way it is going to be possible to explain this code. Can I take you through each line of code as I think the values should be, and you can correct any of these that are not right?
cogid t1 ' get ...
I think cogid is 7, and so t1 contains 0x7
shl t1,#2 ' multiply our cog id by 4
I think t1 now contains 28
add t1,par ' ... registry block
par for me is 0x7fd4, so add 28 and I get 0x7ff0. I have a memory dump of this location and I know it contains the value 0xff007fcc
rdlong rqstptr,t1 ' register ...
I think rqstptr should contain the value 0xff007fcc
and rqstptr,low_24 ' ... this ...
low_24 contains the value 0x00ffffff so I think rqstptr should now contain the value 0x00007fcc
wrlong zero,rqstptr ' ... plugin ...
This writes a zero to hub memory location 0x00007fcc
mov t2,#DUM ' get our plugin type (DUM = 8)
dum is 8, so the value of t2 is 0x8
shl t2,#24 ' ... the ...
t2 should now be 0x08000000
or t2,rqstptr ' ... dummy ...
t2 should now be 0x08007fcc
wrlong t2,t1 ' ... type
this is a bit complicated. I think it writes the value 0x08007fcc to the hub memory location 0x00007fcc
The next bit is where I get lost though and where the code fails to work:
rdlong t1,rqstptr wz ' service request?
if_z jmp #service_loop ' no - just keep waiting
What I am wanting to do is for the pasm code to restart catalina. What this code is doing is waiting for catalina to send something through. BUT - the code I have written has already paused catalina earlier, so catalina is not going to send anything through.
So as far as I can see, this is never going to escape from the loop, and hence won't ever enter the 5 sec delay and restart catalina. And indeed this is what is happening.
So my questions now are:
1) are the hex values above correct and
2) Going right back to basics, is it possible to pause catalina, and for a pasm program to write a specific value (maybe zero, maybe something else) to a specific location in hub ram to restart catalina? If yes, and assuming the registry is at 7fd4, the cog id is 7 and the plugin value is DUM=8, what is that hub location in hex?
What do see when you run this test program? If you don't see the above, please post what you do see, plus the output of executing the build_all command, plus the resulting binary file (i.e. test_plugin.binary).
Because when the first one is executed, the kernel isn't stopped. The first instruction is executed (once) when the plugin loads. The kernel is still running at this point. The first instruction simply makes sure the request block does not contain any rubbish that may have been left over from whatever was previously running in this cog.
True, because if the plugin is not registered the kernel will not be able to find it to send it a request, so the kernel will not pause. Writing to 0x7fd4 is overwriting the registry. I can't tell you precisely what the consequences of doing that will be, since I don't know what you are running in the cog whose registry block you are overwriting. This depends on how you started your program, and what other plugins you loaded. No - it writes it to address 0x7ff0, since this is what t1 contains. If you have paused Catalina by calling _sys_plugin specifying a plugin of type 8 and a non-zero parameter, then the plugin is no longer in this loop - it will have received a request already (i.e. the parameter to _sys_plugin), the test in this loop will already have failed, and the plugin will now be executing the instructions after this loop. It works on my DRACBLADE. We need to find out why it is not working on yours. No - see above. Yes - this is exactly what the test program does. We need to find out why this program fails on your DRACBLADE. $7FCC - but before you race off and hardcode this value somewhere, can you first build and run the test program I posted - exactly as I posted it - and then ...
- Tell me what output you see. If it is not what I have posted at the top, then tell me what it is, and also ...
- Post the output of the build_all script, and also the executable test_plugin.binary.
Ross.You only need this file if you are writing C code you need to compile under both the Catalina and ICC compilers.
Just copy the new version of this file over the existing version in the include directory. I will also incorporate it into the next Catalina release.
Ross.
ok, compiling on my IDE I get this. I don't know what to do with the batch program and it probably has to be run from a particular directory which has a particular include in it, which may or may not be the same as your include, which may introduce other variables. But here is the error of that C code as it is, compiled with catalina -lcx -D PLUGIN -x5 -M 256k -D DRACBLADE -D HIRES_VGA NEW.C
But of course we are going backwards a little here, because in getting to where I have already got, I had to pull apart the three #includes to find code that was critical to getting the one bit of code working - which is the write of a zero to 7fd4.
A write to 7fcc does not work on my board. But of course I have hardcoded some things to try to get as much as possible out of any #includes so it is clearer what is going on. EG DUM is 8, and ANY_COG is 7
Can we eliminate any variables by thinking about code with no #includes?