Thanks Ross. I hope you had a good time away from the internet et al.
I'm making slow and steady progress with the Catalina IDE and writing this huge C program that can run multiple obex cog code. The progress on the C code is somewhat slower than I'd like as I keep having to improve the IDE - eg recently it started getting very slow with big programs so needed a massive rewrite to get it up to Catalina speeds.
I'm reading through your post above and I think I can grasp some of the concepts there.
First thing - there are integer values, and in C89 I see code with pointers to integer values, maybe this is a hangover from 64k memory?
In any case, much of the spin code to be translated deals with longs. Even some values that are never more than bytes are declared as longs as it is easier to do this in Spin. So most of the C code is going to end up with 'unsigned longs', maybe even where only byte values are used.
So - I have this routine:
void start_vga1280(unsigned long base_pin, unsigned long array_ptr, unsigned long color_ptr, unsigned long cursor_ptr, unsigned long sync_ptr, unsigned long mode)
{
unsigned long i;
unsigned long j;
unsigned long dira_;
unsigned long dirb_;
unsigned long vcfg_;
unsigned long cnt_;
unsigned long array_ptr_;
unsigned long color_ptr_;
unsigned long cursor_ptr_;
unsigned long sync_ptr_;
unsigned long mode_;
// need to pass these to the cog loader function
}
where those values need to be passed to this routine:
void vga1280(char cognumber, unsigned long parameters) // function name copied from .spin name above CON section
{
unsigned long vga1280_array[] =
{
0xa0bfdefd, 0x84bc0088, 0xe4fd1200, 0xa0ffe050 ... more data
};
unsigned long par_cogject[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // data to pass to cog - ignore if not used
_coginit((int)par_cogject>>2, (int)vga1280_array>>2, cognumber); // load into cog
}
So in the first one, say I declare an array, unsigned long, 9 parameters.
Put dira, dirb etc into that array in elements 0 to 8.
Can I declare a pointer to that array and pass it to the vga1280 function, as the value in "parameters"? Is it possible to do this with unsigned longs?
If so, then instead of filling par_cogject with dummy data, one could fill it with the array found at the location "parameters".
Or does one still use pointers as integers?
To be more specific, in the
void vga1280(char cognumber, unsigned long parameters)
change parameters to an integer value eg
void vga1280(char cognumber, int parameters)
, and pass a pointer from the unsigned long array in the start_vga1280 function?
Thanks Ross. I hope you had a good time away from the internet et al.
First thing - there are integer values, and in C89 I see code with pointers to integer values, maybe this is a hangover from 64k memory?
In any case, much of the spin code to be translated deals with longs. Even some values that are never more than bytes are declared as longs as it is easier to do this in Spin. So most of the C code is going to end up with 'unsigned longs', maybe even where only byte values are used.
In C this is all compiler dependent, but in Catalina (as in most 32 bit C compilers) an int is 32 bits, and so is a long (signed or unsigned), and so is a pointer. A short is 16 bits and a char is 8 bits. I suppose there may be still some C compilers around where int is 16 bits, but they would be few and far between these days.
void start_vga1280(unsigned long base_pin, unsigned long array_ptr, unsigned long color_ptr, unsigned long cursor_ptr, unsigned long sync_ptr, unsigned long mode)
{
unsigned long i;
unsigned long j;
unsigned long dira_;
unsigned long dirb_;
unsigned long vcfg_;
unsigned long cnt_;
unsigned long array_ptr_;
unsigned long color_ptr_;
unsigned long cursor_ptr_;
unsigned long sync_ptr_;
unsigned long mode_;
// need to pass these to the cog loader function
}
where those values need to be passed to this routine:
void vga1280(char cognumber, unsigned long parameters) // function name copied from .spin name above CON section
{
unsigned long vga1280_array[] =
{
0xa0bfdefd, 0x84bc0088, 0xe4fd1200, 0xa0ffe050 ... more data
};
unsigned long par_cogject[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // data to pass to cog - ignore if not used
_coginit((int)par_cogject>>2, (int)vga1280_array>>2, cognumber); // load into cog
}
So in the first one, say I declare an array, unsigned long, 9 parameters.
Put dira, dirb etc into that array in elements 0 to 8.
Can I declare a pointer to that array and pass it to the vga1280 function, as the value in "parameters"? Is it possible to do this with unsigned longs?
You don't need to declare a pointer to the array - just use the name of the array, which in C is a pointer to the first element.
If so, then instead of filling par_cogject with dummy data, one could fill it with the array found at the location "parameters".
Or does one still use pointers as integers?
To be more specific, in the
void vga1280(char cognumber, unsigned long parameters)
change parameters to an integer value eg
void vga1280(char cognumber, int parameters)
, and pass a pointer from the unsigned long array in the start_vga1280 function?
[/QUOTE]
Not sure what you're asking here. Perhaps you meant to declare the argument as "unsigned long *parameters"? In which case you can just pass the argument directly, with an appropriate cast (i.e. "(int)parameters")?
In any case, much of the spin code to be translated deals with longs. Even some values that are never more than bytes are declared as longs as it is easier to do this in Spin. So most of the C code is going to end up with 'unsigned longs', maybe even where only byte values are used.
Be careful. In Spin all longs are signed values. When translating Spin code to C if you make the LONGs into unsigned long or unsigned int some things may not work as expected anymore. Mostly it makes no difference but comparison operators "<", ">" etc will fail for numbers that are supposed to be signed in Spin.
For example as a signed number -1 is less than 1 but for unsigned it is greater.
If everything is long and you can pass pointers to arrays with the array name, that will be both simple and neat.
@heater - good point. I see in C there are 'unsigned long', and 'unsigned long int'. I was using the latter but I see Ross uses the former so I recently changed my code. Both seemed to work for what I was doing but I haven't done any equality tests in my code. Which one is the best match for Spin, in terms of > and <? I can see the -1 issue coming up as a possibility in Spin.
Like I said in Spin all operations on LONGs are signed. So in C I would use int, or long int. Of course in many cases it does not matter so int would do. Pays to inspect the original Spin code.
However in any production code I write I always define some types like int32_t and unit32_t when it is important things are the right size. For example if you were to test your code on a 64 bit machine all your int's would now be 64 bits which might not give the correct results.
typedef int int32_t;
typedef unsigned int uint32_t;
//etc etc for bytes and words
These type definitions can be changed when moving from machine to machine.
Perhaps Catalina has them defined already somewhere, such definitions are part of some recent C standard or other.
Like I said in Spin all operations on LONGs are signed. So in C I would use int, or long int. Of course in many cases it does not matter so int would do. Pays to inspect the original Spin code.
However in any production code I write I always define some types like int32_t and unit32_t when it is important things are the right size. For example if you were to test your code on a 64 bit machine all your int's would now be 64 bits which might not give the correct results.
typedef int int32_t;
typedef unsigned int uint32_t;
//etc etc for bytes and words
These type definitions can be changed when moving from machine to machine.
Perhaps Catalina has them defined already somewhere, such definitions are part of some recent C standard or other.
Hi Heater, Dr_Acula ...
Catalina also now includes a version of stdint.h which defines all the C99 standard types, such as int32_t and uint32_t etc. Here is an example:
Some experiments:
uint32_t c;
c=4294967295;
printf("value of c = %d\n",c);
all the following run and print -1.
Warning message "overflow in converting constant expression from unsigned long to int" with:
int c;
long c;
int32_t c;
ones that compile with no warning messages:
unsigned long c;
uint32_t c;
unsigned long int c;
I'd prefer not to have warning messages, so which of the last 3 do you think matches Spin the best? I'm inclined towards uint32_t as it fixes longs as being 32 bits.
Also, as an aside, I can't seem to get math.h functions to work
error = undefined or redefined symbols, pow not defined
Jumping ahead here, assuming the equivalent of a spin 'Long' is uint32_t, then
const unsigned long myvariable = 5000;
becomes
const uint32_t myvariable = 5000;
and
void mycogject(int cognumber, unsigned long parameters) // this name copied from the .spin name in the pasm section - names must match eg void mycogject matches mycogject.spin. Also first code after this must be the .h array file. Put your code after the };
{
/**
* @file mycogject_array.h
* Created with spin.binary PASM to C Array Converter.
* Copyright (c) 2011, John Doe
*/
unsigned long mycogject_array[] = // dummy data or compiled above code or #include file.h
{
0x003c0602, 0x5c7c0000, 0x00001388, 0x00000041
};
unsigned long par_cogject[] = { 1, 2, 3 }; // data to pass to cog - ignore if not used
_coginit((int)par_cogject>>2, (int)mycogject_array>>2, cognumber); // array name built from spin file name
}
becomes
void mycogject(int cognumber, uint32_t parameters) // this name copied from the .spin name in the pasm section - names must match eg void mycogject matches mycogject.spin. Also first code after this must be the .h array file. Put your code after the };
{
/**
* @file mycogject_array.h
* Created with spin.binary PASM to C Array Converter.
* Copyright (c) 2011, John Doe
*/
uint32_t mycogject_array[] = // dummy data or compiled above code or #include file.h
{
0x003c0602, 0x5c7c0000, 0x00001388, 0x00000041
};
uint32_t par_cogject[] = { 1, 2, 3 }; // data to pass to cog - ignore if not used
_coginit((int)par_cogject>>2, (int)mycogject_array>>2, cognumber); // array name built from spin file name
}
4294967295 is 0xffffffff which is -1 for a signed 32 bit int and 4294967295 for an unsigned 32-bit int. As I'm sure you know.
Signed 32 bit ints run from minus two billion and something to plus two billion and something.
So, if you try to assign 4294967295 to a signed 32 bit int (int, long or int32_t) you should expect that warning as it is too big.
I prefer to have warnings when I'm doing something weird:)
...so which of the last 3 do you think matches Spin the best? I'm inclined towards uint32_t as it fixes longs as being 32 bits.
But so do "long c", "int32_t c" and "signed long int c".
The problem is not what you like best but what actually works. If you have some Spin code doing comparisons on signed numbers, the only kind of LONG Spin knows, then that code will fail if you use uint32_t in the C version.
Of course if the code is only working with numbers from zero to two billion and something then it makes no difference.
...I can't seem to get math.h functions to work
The functions in math.h work on floating point numbers.
"pow" works on double precision floats. "powf" works on 32 but single precision floats, I guess you want the latter.
So heater, you are thinking that "signed long int" best matches a Spin long? Or int32_t but don't go above 2^31 (or 2^31-1)?
Of those 6 options, I'm not that concerned but it would help to make a decision as the C precompiler that integrates pasm and C does so by searching for specific strings. I'm not an expert on Spin so I think I need some guidance on how one uses spin, eg hex values are pretty unambiguious but -1 can be evaluated to all sorts of things (255 for Z80, 65535 for integer variables in early versions of basic but sometimes the magic number is 32768 ie -32767 to 32768, and above 2^16 my brain starts to steam a little *grin*)
re
"pow" works on double precision floats. "powf" works on 32 but single precision floats, I guess you want the latter.
I found that code on the internet and noted that it deliberately does not define the type of variable before using it. Maybe this is the problem? It was on a C89 website but maybe one has to explicitly define a variable as a float rather than passing constants to printf?
printf ("7 ^ 3 = %lf\n", pow (7,3));
Ok if the variables have to be floats. I was just trying to define 2^32 as a value in math.h using a 'pow' but it didn't work out. I used windows calculator instead.
So heater, you are thinking that "signed long int" best matches a Spin long? Or int32_t but don't go above 2^31 (or 2^31-1)?
I would think for most Spin translated to C using int32_t is just the ticket.
After all, if your code has A := 4 and B := -2 then "A > B" should be true. If you translate to unsigned ints then B is $FFFFFFFE (a very big number) and it will be FALSE and things will go wrong.
re: pow. Thing is I would be surprised if Catalina has a "pow" function. In standard C pow is defined to operate on doubles. I would imaging Catalina does not support floating point ops on doubles or more likely if it does they are the same size as floats anyway (allowed by the standards).
I would be surprised if Catalina has a "pow" function. In standard C pow is defined to operate on doubles. I would imaging Catalina does not support floating point ops on doubles or more likely if it does they are the same size as floats anyway (allowed by the standards).
Catalina has the C89 standard pow() function, which works on doubles. In Catalina a double is 32 bits, same as a float - as you pointed out, this is allowed by the standards, and is quite common on 32 bit platforms (many of which - like the Propeller - have no provision for 64 bit floating point). powf() is a platform dependent function designed to accept single precision floats - but on Catalina, powf() is unnecessary as it would be identical with pow(). If you want powf(), include the following in your program:
#define powf(x,y) pow(x,y)
As to the other discussion - a spin LONG is probably best equated to a C long. A SPIN WORD should be equated to a C short and a SPIN BYTE should be equated to a C char.
You mght decide to include something similar to the following at the top of your translated program (or in a common header file):
#define LONG long
#define WORD short
#define BYTE char
Then if you decide to use a different type mapping, it is a trivial one line change.
Comments
I'm making slow and steady progress with the Catalina IDE and writing this huge C program that can run multiple obex cog code. The progress on the C code is somewhat slower than I'd like as I keep having to improve the IDE - eg recently it started getting very slow with big programs so needed a massive rewrite to get it up to Catalina speeds.
I'm reading through your post above and I think I can grasp some of the concepts there.
First thing - there are integer values, and in C89 I see code with pointers to integer values, maybe this is a hangover from 64k memory?
In any case, much of the spin code to be translated deals with longs. Even some values that are never more than bytes are declared as longs as it is easier to do this in Spin. So most of the C code is going to end up with 'unsigned longs', maybe even where only byte values are used.
So - I have this routine:
where those values need to be passed to this routine:
So in the first one, say I declare an array, unsigned long, 9 parameters.
Put dira, dirb etc into that array in elements 0 to 8.
Can I declare a pointer to that array and pass it to the vga1280 function, as the value in "parameters"? Is it possible to do this with unsigned longs?
If so, then instead of filling par_cogject with dummy data, one could fill it with the array found at the location "parameters".
Or does one still use pointers as integers?
To be more specific, in the
change parameters to an integer value eg , and pass a pointer from the unsigned long array in the start_vga1280 function?
In C this is all compiler dependent, but in Catalina (as in most 32 bit C compilers) an int is 32 bits, and so is a long (signed or unsigned), and so is a pointer. A short is 16 bits and a char is 8 bits. I suppose there may be still some C compilers around where int is 16 bits, but they would be few and far between these days.
You don't need to declare a pointer to the array - just use the name of the array, which in C is a pointer to the first element.
[/QUOTE]
Not sure what you're asking here. Perhaps you meant to declare the argument as "unsigned long *parameters"? In which case you can just pass the argument directly, with an appropriate cast (i.e. "(int)parameters")?
Be careful. In Spin all longs are signed values. When translating Spin code to C if you make the LONGs into unsigned long or unsigned int some things may not work as expected anymore. Mostly it makes no difference but comparison operators "<", ">" etc will fail for numbers that are supposed to be signed in Spin.
For example as a signed number -1 is less than 1 but for unsigned it is greater.
Probably better to use int in C for LONG in Spin.
@heater - good point. I see in C there are 'unsigned long', and 'unsigned long int'. I was using the latter but I see Ross uses the former so I recently changed my code. Both seemed to work for what I was doing but I haven't done any equality tests in my code. Which one is the best match for Spin, in terms of > and <? I can see the -1 issue coming up as a possibility in Spin.
However in any production code I write I always define some types like int32_t and unit32_t when it is important things are the right size. For example if you were to test your code on a 64 bit machine all your int's would now be 64 bits which might not give the correct results.
These type definitions can be changed when moving from machine to machine.
Perhaps Catalina has them defined already somewhere, such definitions are part of some recent C standard or other.
Hi Heater, Dr_Acula ...
Catalina also now includes a version of stdint.h which defines all the C99 standard types, such as int32_t and uint32_t etc. Here is an example:
In general, you should use these types rather than relying on platform dependent types such as int and short - I'm just too lazy to do so!
Ross.
uint32_t c;
c=4294967295;
printf("value of c = %d\n",c);
all the following run and print -1.
Warning message "overflow in converting constant expression from unsigned long to int" with:
int c;
long c;
int32_t c;
ones that compile with no warning messages:
unsigned long c;
uint32_t c;
unsigned long int c;
I'd prefer not to have warning messages, so which of the last 3 do you think matches Spin the best? I'm inclined towards uint32_t as it fixes longs as being 32 bits.
Also, as an aside, I can't seem to get math.h functions to work
error = undefined or redefined symbols, pow not defined
Jumping ahead here, assuming the equivalent of a spin 'Long' is uint32_t, then becomes and
becomes
4294967295 is 0xffffffff which is -1 for a signed 32 bit int and 4294967295 for an unsigned 32-bit int. As I'm sure you know.
Signed 32 bit ints run from minus two billion and something to plus two billion and something.
So, if you try to assign 4294967295 to a signed 32 bit int (int, long or int32_t) you should expect that warning as it is too big.
I prefer to have warnings when I'm doing something weird:)
But so do "long c", "int32_t c" and "signed long int c".
The problem is not what you like best but what actually works. If you have some Spin code doing comparisons on signed numbers, the only kind of LONG Spin knows, then that code will fail if you use uint32_t in the C version.
Of course if the code is only working with numbers from zero to two billion and something then it makes no difference.
The functions in math.h work on floating point numbers.
"pow" works on double precision floats. "powf" works on 32 but single precision floats, I guess you want the latter.
Of those 6 options, I'm not that concerned but it would help to make a decision as the C precompiler that integrates pasm and C does so by searching for specific strings. I'm not an expert on Spin so I think I need some guidance on how one uses spin, eg hex values are pretty unambiguious but -1 can be evaluated to all sorts of things (255 for Z80, 65535 for integer variables in early versions of basic but sometimes the magic number is 32768 ie -32767 to 32768, and above 2^16 my brain starts to steam a little *grin*)
re
I found that code on the internet and noted that it deliberately does not define the type of variable before using it. Maybe this is the problem? It was on a C89 website but maybe one has to explicitly define a variable as a float rather than passing constants to printf?
Ok if the variables have to be floats. I was just trying to define 2^32 as a value in math.h using a 'pow' but it didn't work out. I used windows calculator instead.
I would think for most Spin translated to C using int32_t is just the ticket.
After all, if your code has A := 4 and B := -2 then "A > B" should be true. If you translate to unsigned ints then B is $FFFFFFFE (a very big number) and it will be FALSE and things will go wrong.
re: pow. Thing is I would be surprised if Catalina has a "pow" function. In standard C pow is defined to operate on doubles. I would imaging Catalina does not support floating point ops on doubles or more likely if it does they are the same size as floats anyway (allowed by the standards).
Catalina has the C89 standard pow() function, which works on doubles. In Catalina a double is 32 bits, same as a float - as you pointed out, this is allowed by the standards, and is quite common on 32 bit platforms (many of which - like the Propeller - have no provision for 64 bit floating point). powf() is a platform dependent function designed to accept single precision floats - but on Catalina, powf() is unnecessary as it would be identical with pow(). If you want powf(), include the following in your program:
As to the other discussion - a spin LONG is probably best equated to a C long. A SPIN WORD should be equated to a C short and a SPIN BYTE should be equated to a C char.
You mght decide to include something similar to the following at the top of your translated program (or in a common header file): Then if you decide to use a different type mapping, it is a trivial one line change.