There seems to be a bug with BCX - the instructions say that if you declare a variable with STATIC it uses static, and if you declare with DIM or LOCAL, it declares with the standard declaration "int a;"
But the actual program puts static in regardless of what you use. I am awaiting confirmation I have joined the BCX forum so I can ask about this. There are some threads about command line switches that can change this, but I can't find any formal documentation of those command line switches.
If I get time, I'll have a look a the BCX source - but you may get a faster answer from the BCX support group.
As to your other question (at least I think it was a question) your final code could look something like this ...
void mycogject(int cognumber, long *parameters) {
unsigned long mycogject_array[] = {
0x003c0602, 0x5c7c0000, 0x00001388, 0x00000041
};
_coginit((int)parameters>>2, (int)mycogject_array>>2, cognumber);
}
void main() {
long parameters[] = { ... whatever you want ... };
mycogject(7, parameters);
}
That code you posted even saves defining a local array for parameters. No need to - just keep passing the pointer. You could extend that concept to another function that put the values in the array. So that keeps the main free of clutter - all that is in the main is a definition of the array, then a call to a function "fill_cog1_parameters(parameters), then a call to load it.
I've been watching, kind of wondering about when / how it would get here. Am I correct in reading that it is now possible to have a larger program running XMM style, some binary loaded drivers in COG space, operating with HUB data, and or communicating / receiving instruction from that XMM program in a shared HUB space?
Would it also be possible then to have LMM code running on one of those COGS as well?
In terms of speed, how does the XMM code compare to LMM code, and LMM to say, SPIN?
Would I, for example, be able to fetch my TV driver COG images from SD card, using a SD routine written in C, running as LMM, or even XMM launch them, and have a C program see that HUB buffer space as a display screen?
I've been watching, kind of wondering about when / how it would get here. Am I correct in reading that it is now possible to have a larger program running XMM style, some binary loaded drivers in COG space, operating with HUB data, and or communicating / receiving instruction from that XMM program in a shared HUB space?
Yes, that's been possible for quite a while now. For a non-trivial example, see the graphics program in Catalina\demos\graphics - you can run this demo as an XMM program, but the graphics object (which is a modified version of the standard Parallax one) runs as a cog program, and the graphics buffers in Hub RAM (as they have to be, to be accessible to both the XMM program and the graphics object)
Would it also be possible then to have LMM code running on one of those COGS as well?
Yes, that's possible - one XMM program could co-exist with multiple LMM programs - but the memory management is currently be a bit tricky. You would have to embed your LMM program as a binary blob within the main XMM program (as Dr_A does above for cog programs) and that blob must include its own copy of the LMM kernel. Also, that blob would have to have been compiled in advance to run in a specific area of Hub RAM (a bit like an overlay) since PASM is not relocatable. I could probably do this, but I'd have to do some work to make this sufficiently simple for others to do.
In terms of speed, how does the XMM code compare to LMM code, and LMM to say, SPIN?
On a Propeller platform with fast parallel SRAM (and on a good day and with the wind behind it) Catalina can execute C code from XMM RAM at around the same speed as Spin executes from Hub RAM.
Would I, for example, be able to fetch my TV driver COG images from SD card, using a SD routine written in C, running as LMM, or even XMM launch them, and have a C program see that HUB buffer space as a display screen?
Yes.
Ross.
POSTEDIT: I must emphasise again that the execution speed of XMM programs is extremely dependent on the speed of the XMM RAM itself. To get an XMM C program to execute at around Spin speeds is only possible on platforms like the RamBlade. Just for amusement value, I just compiled the graphics demo as an XMM program for the C3 (which has serial XMM RAM, not parallal) - the good news is that it runs (I'd never tried it before). But the bad news is that it runs at about one graphics refresh per second - i.e. 20 or 30 times slower than either the LMM C or Spin version!
The moral is to choose your XMM platform with care!
Would I, for example, be able to fetch my TV driver COG images from SD card, using a SD routine written in C, running as LMM, or even XMM launch them, and have a C program see that HUB buffer space as a display screen?
I'll second Ross' Yes.
And you can do it in Basic too now.
It is all about being able to control where data ends up. I think I've cracked this one in Basic (C has been able to do this for some time).
I have no idea why BCX is putting all the variables as "static" in local functions - for one that is going to fill up the stack fairly quickly, but maybe since it was designed for use on a PC the stack size does not matter. In any case, I've written another little post processor to remove this (there are now eight of these post processor routines).
Sub RemoveStatic(ByVal Source As String, ByVal Destination As String)
' the C compiler is putting "static" in front of everything
' this will fill up the stack very quickly
' so in all the user subs, any 'static' variables need to be removed
Dim LineOfText As String
Dim StaticFlag As Boolean
StaticFlag = False
FileOpen(1, Source, OpenMode.Input) ' open the files
FileOpen(2, Destination, OpenMode.Output)
While EOF(1) = False
LineOfText = LineInput(1) ' get the line
If LineOfText = "// User Subs and Functions" Then
StaticFlag = True ' from now on do the replace
End If
If Strings.Left(LineOfText, 11) = " static " Then
LineOfText = " " + Strings.Mid(LineOfText, 12) ' remove the static part
End If
PrintLine(2, LineOfText) ' save the line
End While
FileClose(1) ' close the files
FileClose(2)
End Sub
So we end up with a program that still has static variables that are defined at the beginning. I think this is what we want...
Ross said
We'll make a C programmer of you yet, Dr_A!
ha ha. Yes, and to write this sort of code you have to start thinking in C. The "simple" solution is to define everything as global, but this is not the way "real" programmers work. I'm still guilty though of putting some variables as global, eg ones that get used all over the program and mainly ones that are 'read only' eg the current baud rate. If nothing ever changes it, surely that is allowed????!
VB.NET has been gently guiding programmers down this road for some time, with the "byref" and "byval" being automatically inserted into subroutines.
So, there is a nifty PTR command in BCX basic, which gets translated to *. I find it a bit easier to understand PTR than to understand *, maybe because to me, * means multiply. But it is being translated directly to the C pointer type, so one finds oneself thinking more in C.
This is my test program in Basic.
' BCX help file http://www.bcxgurus.com/help/index.html
' demonstration of pointers to show where variables are being stored
' XMM program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
$COMMAND
catalina -lcx -lm -x5 -M 128k -D DRACBLADE -D VGA_HIRES
' library cx, library maths (slow, doesn't use a cog), memory size, board, high res vga, mouse, keyboard
$COMMAND
' ************ main **********
Dim GlobalArray[10] as Integer
Dim GlobalArrayPointer as Integer PTR ' set up a pointer
GlobalArrayPointer=GlobalArray
print GlobalArrayPointer
Call TestSub()
Do
Loop Until 0=1 ' infinite loop
' *********** end main *******
Sub TestSub()
Dim LocalArray[10] As Integer
Dim LocalArrayPointer as Integer PTR ' set up a pointer
LocalArrayPointer=LocalArray
print LocalArrayPointer
End Sub
and after running this through BCX and the eight post processor routines, we get
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
// *************************************************
// Typedef
// *************************************************
typedef unsigned char UCHAR;
typedef unsigned long DWORD;
typedef unsigned long UINT;
// *************************************************
// User Global Variables
// *************************************************
static int *GlobalArrayPointer;
static int GlobalArray[10];
// *************************************************
// User Prototypes
// *************************************************
void TestSub (void);
// *************************************************
// User Global Initialized Arrays
// *************************************************
// *************************************************
// Main Program
// *************************************************
int main(int argc, char *argv[])
{
GlobalArrayPointer=GlobalArray;
printf("% d\n",(int)GlobalArrayPointer);
TestSub();
for(;;)
{
if(0==1)
{
break;
}
}
return 0; // End of main program
}
// *************************************************
// Runtime Functions
// *************************************************
// ************************************
// User Subs and Functions
// ************************************
void TestSub (void)
{
int LocalArray[10];
int* LocalArrayPointer;
memset(&LocalArray,0,sizeof(LocalArray));
memset(&LocalArrayPointer,0,sizeof(int *));
LocalArrayPointer=LocalArray;
printf("% d\n",(int)LocalArrayPointer);
}
And when you run this on the propeller, it prints two numbers
69592
27192
and I think that is exactly what we want. The global array is in external memory, and the local array is in hub memory.
Only one thing I don't understand. I tried making the pointer a 'long' variable instead of an integer. But the C compiler got upset with that. However, how is it managing to print an integer value more than 65535?
Only one thing I don't understand. I tried making the pointer a 'long' variable instead of an integer. But the C compiler got upset with that. However, how is it managing to print an integer value more than 65535?
An int in Catalina is 32 bits - same as a long. What was the code and the error you got when you tried printing it as a long?
Can you please take a look at this code. It compiles ok with TinyC but in Catalina I'm getting errors in the last function, starting with the line
" static FILE* MyFileHandle;"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
// *************************************************
// Typedef
// *************************************************
typedef unsigned char UCHAR;
typedef unsigned long DWORD;
typedef unsigned long UINT;
// *************************************************
// System Variables
// *************************************************
// *************************************************
// User Global Variables
// *************************************************
static FILE *FP1;
// *************************************************
// Standard Prototypes
// *************************************************
int EoF (FILE*);
char* BCX_TmpStr(size_t);
// *************************************************
// User Prototypes
// *************************************************
void ReadFile (char *);
void CreateFile (char *);
// *************************************************
// User Global Initialized Arrays
// *************************************************
// *************************************************
// Main Program
// *************************************************
int main(int argc, char *argv[])
{
CreateFile("new.txt");
ReadFile("new.txt");
return 0; // End of main program
}
// *************************************************
// Runtime Functions
// *************************************************
char *BCX_TmpStr (size_t Bites)
{
static int StrCnt;
static char *StrFunc[2048];
StrCnt=(StrCnt + 1) & 2047;
if(StrFunc[StrCnt]) free (StrFunc[StrCnt]);
return StrFunc[StrCnt]=(char*)calloc(Bites+128,sizeof(char));
}
int EoF (FILE* stream)
{
register int c, status = ((c = fgetc(stream)) == EOF);
ungetc(c,stream);
return status;
}
// ************************************
// User Subs and Functions
// ************************************
void ReadFile (char *Filename)
{
char a;
memset(&a,0,sizeof(a));
printf("%s\n","now read file back as a binary file");
if((FP1=fopen(Filename,"rb"))==0)
{
fprintf(stderr,"Can't open file %s\n",Filename);exit(1);
}
fseek(FP1,0,0);
while(!EoF(FP1))
{
a=getc(FP1);
printf("% d\n",(int)a);
}
if(FP1)
{
fclose(FP1);
FP1=NULL;
}
}
void CreateFile (char *Filename)
{
printf("%s\n","Open file and create file");
static FILE* MyFileHandle;
memset(&MyFileHandle,0,sizeof(MyFileHandle));
if((FP1=fopen(Filename,"w"))==0)
{
fprintf(stderr,"Can't open file %s\n",Filename);exit(1);
}
MyFileHandle=FP1;
fprintf(MyFileHandle,"%s\n","Hello World");
if(FP1)
{
fclose(FP1);
FP1=NULL;
}
printf("%s\n","Closing file");
}
I've been staring at that for an hour and never spotted it. Thank++!
Ah well, now it changes from an 8 pass post-compiler to a 9 pass one. I'll nail these bugs eventually *grin*.
I'm not sure about the 'static" bit either. Ross has said that "static" means that it ends permanently in hub ram, and ideally variables in a function should be released once the function finishes. I'm not sure what to replace "static" with in this instance.
I'm not sure what to replace "static" with in this instance.
Just remove the "static" keyword. You normally want a local variable in a function. There are times when it's desirable (I never do it) to have a variable keep its state from one call of the function to the next, and static provides that capability at the cost of taking up permanent space in memory. The static keyword had different meanings based on context of course.
I'm just starting to work with Catalina 2.9 and have a very basic question. Does Catalina accept forward slashes in file pathnames under Windows? I'm using it under the Cygwin shell so I can use the Cygwin make utility to control the building of my project and I'm wondering if forward slashes will work in filenames.
Catalina and LCC generally accept forward slashes under Windows - but I think it would be unwise to rely on this capability, since you're also relying on the other programs that Catalina uses (such as Homespun) doing so in all cases - and I'm just not sure about those.
Ross.
P.S. I started out using Cygwin, but ended up using MinGW and MSYS instead to get "make" and various other Linux type utilities under windows - much easier!
So far I haven't had any trouble with Cygwin. There is probably something wrong with my makefile. I just hacked it from a previous attempt to get some code running under Catalina and probably missed an edit somewhere. Thanks for the info on forward slashes.
... it also works for me. You can try it if you like - but I expect you'll still get an error. The annoying this is that I have seen this error before (and fixed it) but I can't remember how!
There may be some difference in our execution environments. Some questions may help narrow it down:
Are you executing under Cygwin or DOS?
What version of Windows are you using?
Did you rebuild Catalina from source, or are you using the binaries from the 2.9 distribution?
Do you have by any chance an old copy of LCC in your path? Can you try the above command but explicitly specify the execution path to lcc? (e.g. "C:\Program Files\Catalina\bin\lcc ..."
1. Cygwin
2. Windows 7 Home Premium
3. I used the 2.9 distribution
4. Maybe. I'll have to check. But I think when I typed 'catalina' at the Cygwin command prompt it said version 2.9.
I wonder if this has anything to do with the terminator at the end of the command line? Is it possible that Cygwin is adding a \n to the end of the line but LCC expects \r\n?
Edit: just checked and this is the only installation of Catalina on this machine.
Well, I ran the 'make' command from a DOS command line instead of Cygwin with the same result. I guess it's the Cygwin version of 'make' that is causing the trouble.
Comments
As to your other question (at least I think it was a question) your final code could look something like this ... Is that what you had in mind?
Ross.
That code you posted even saves defining a local array for parameters. No need to - just keep passing the pointer. You could extend that concept to another function that put the values in the array. So that keeps the main free of clutter - all that is in the main is a definition of the array, then a call to a function "fill_cog1_parameters(parameters), then a call to load it.
We'll make a C programmer of you yet, Dr_A!
I've been watching, kind of wondering about when / how it would get here. Am I correct in reading that it is now possible to have a larger program running XMM style, some binary loaded drivers in COG space, operating with HUB data, and or communicating / receiving instruction from that XMM program in a shared HUB space?
Would it also be possible then to have LMM code running on one of those COGS as well?
In terms of speed, how does the XMM code compare to LMM code, and LMM to say, SPIN?
Would I, for example, be able to fetch my TV driver COG images from SD card, using a SD routine written in C, running as LMM, or even XMM launch them, and have a C program see that HUB buffer space as a display screen?
Yes, that's been possible for quite a while now. For a non-trivial example, see the graphics program in Catalina\demos\graphics - you can run this demo as an XMM program, but the graphics object (which is a modified version of the standard Parallax one) runs as a cog program, and the graphics buffers in Hub RAM (as they have to be, to be accessible to both the XMM program and the graphics object) Yes, that's possible - one XMM program could co-exist with multiple LMM programs - but the memory management is currently be a bit tricky. You would have to embed your LMM program as a binary blob within the main XMM program (as Dr_A does above for cog programs) and that blob must include its own copy of the LMM kernel. Also, that blob would have to have been compiled in advance to run in a specific area of Hub RAM (a bit like an overlay) since PASM is not relocatable. I could probably do this, but I'd have to do some work to make this sufficiently simple for others to do. On a Propeller platform with fast parallel SRAM (and on a good day and with the wind behind it) Catalina can execute C code from XMM RAM at around the same speed as Spin executes from Hub RAM. Yes.
Ross.
POSTEDIT: I must emphasise again that the execution speed of XMM programs is extremely dependent on the speed of the XMM RAM itself. To get an XMM C program to execute at around Spin speeds is only possible on platforms like the RamBlade. Just for amusement value, I just compiled the graphics demo as an XMM program for the C3 (which has serial XMM RAM, not parallal) - the good news is that it runs (I'd never tried it before). But the bad news is that it runs at about one graphics refresh per second - i.e. 20 or 30 times slower than either the LMM C or Spin version!
The moral is to choose your XMM platform with care!
I'll second Ross' Yes.
And you can do it in Basic too now.
It is all about being able to control where data ends up. I think I've cracked this one in Basic (C has been able to do this for some time).
I have no idea why BCX is putting all the variables as "static" in local functions - for one that is going to fill up the stack fairly quickly, but maybe since it was designed for use on a PC the stack size does not matter. In any case, I've written another little post processor to remove this (there are now eight of these post processor routines).
So we end up with a program that still has static variables that are defined at the beginning. I think this is what we want...
Ross said
ha ha. Yes, and to write this sort of code you have to start thinking in C. The "simple" solution is to define everything as global, but this is not the way "real" programmers work. I'm still guilty though of putting some variables as global, eg ones that get used all over the program and mainly ones that are 'read only' eg the current baud rate. If nothing ever changes it, surely that is allowed????!
VB.NET has been gently guiding programmers down this road for some time, with the "byref" and "byval" being automatically inserted into subroutines.
So, there is a nifty PTR command in BCX basic, which gets translated to *. I find it a bit easier to understand PTR than to understand *, maybe because to me, * means multiply. But it is being translated directly to the C pointer type, so one finds oneself thinking more in C.
This is my test program in Basic.
and after running this through BCX and the eight post processor routines, we get
And when you run this on the propeller, it prints two numbers
and I think that is exactly what we want. The global array is in external memory, and the local array is in hub memory.
Only one thing I don't understand. I tried making the pointer a 'long' variable instead of an integer. But the C compiler got upset with that. However, how is it managing to print an integer value more than 65535?
An int in Catalina is 32 bits - same as a long. What was the code and the error you got when you tried printing it as a long?
Ross.
error operands of = have illegal types 'pointer to unsigned long' and 'pointer to int'
I didn't realise int is the same as long. That might simplify some of my demo code.
Can you please take a look at this code. It compiles ok with TinyC but in Catalina I'm getting errors in the last function, starting with the line
" static FILE* MyFileHandle;"
In my defence, this isn't my code. A computer program wrote that code!
Fair enough, it looks kind of machine'ish
Ah well, now it changes from an 8 pass post-compiler to a 9 pass one. I'll nail these bugs eventually *grin*.
I'm not sure about the 'static" bit either. Ross has said that "static" means that it ends permanently in hub ram, and ideally variables in a function should be released once the function finishes. I'm not sure what to replace "static" with in this instance.
Yes, C is picky about pointer types - you need to cast it, such as (int *)ptr.
Ross.
Thanks,
David
Catalina and LCC generally accept forward slashes under Windows - but I think it would be unwise to rely on this capability, since you're also relying on the other programs that Catalina uses (such as Homespun) doing so in all cases - and I'm just not sure about those.
Ross.
P.S. I started out using Cygwin, but ended up using MinGW and MSYS instead to get "make" and various other Linux type utilities under windows - much easier!
catalina -DPROPELLER -DHYDRA -DNTSC -DNO_MOUSE -c src/xbasic.c -o obj/xbasic.obj
Catalina Compiler 2.9
lcc: ☺: Invalid argument
Hi David,
I just created a src and obj directory, and put an xbasic.c in there so I could execute the same command. It works for me.
Can you add the -v switch to the command and post the output?
Ross.
Thanks. I just wanted to confirm Catalina was issuing the correct LCC command (it is!). When I execute the lcc command itself directly .... ... it also works for me. You can try it if you like - but I expect you'll still get an error. The annoying this is that I have seen this error before (and fixed it) but I can't remember how!
There may be some difference in our execution environments. Some questions may help narrow it down:
2. Windows 7 Home Premium
3. I used the 2.9 distribution
4. Maybe. I'll have to check. But I think when I typed 'catalina' at the Cygwin command prompt it said version 2.9.
I wonder if this has anything to do with the terminator at the end of the command line? Is it possible that Cygwin is adding a \n to the end of the line but LCC expects \r\n?
Edit: just checked and this is the only installation of Catalina on this machine.
Yes, from memory it is something like the line termination issue, or perhaps a need to quote some section of the path or other.
Can you try executing the LCC command directly in a DOS box?
Ross.
HI David,
Can you execute just the LCC command directly in a DOS box, and add a -v to that command - i.e.:
Just cut and paste! Also, you didn't add the final -v
Ross.