What if (most of) propeller2.h wasn't included in any C compiler, but instead was a library that everyone included in their projects?
I guess we've been a bit sloppy with our definitions earlier. Yes, you're quite right that propeller2.h doesn't really belong in the compiler proper. But it should be included with every compiler package for the P2 as part of the Propeller 2 standard C library.
PropGCC actually is already set up this way. When people say "PropGCC" they usually refer to the whole package, but that package is made up of a number of pieces:
- the GCC compiler itself
- binutils (assembler, linker, and other utilities)
- standard library for Propeller
- propeller-load loader for running things on the Propeller
Each of these is a separate repository, but none of them are really very useful on their own (well, except for propeller-load!). The PropGCC's <propeller.h> file is in the library, the repo for which is probably mirrored in the parallaxinc git repo but originally was in github.com/totalspectrum/proplib.
Of course other compilers will be distributed and set up differently -- RossH has his own structure for Catalina, and fastspin is different still. The main thing is that in any full distribution of a Propeller 2 C compiler there should be a propeller2.h with some minimum set of functions for manipulating the P2 hardware. That way some amount of hardware specific C code can be moved easily between compilers, and we can all benefit from a growing ecosystem.
If we use "polar_t" then it is guaranteed not to conflict with any user variables (assuming the user follows the rules)
This implies (and is confirmed on https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html) that users should not be using the "_t" naming convention for types, and my above proposal would make the Propeller 2 C standard library just a normal "user" excluding it from the "_t" convention. Not sure what to do about that.
It's reasonable to call propeller2.h part of the "system" on P2. The functionality there (or something equivalent) is required in order to implement other standard library functions, so in practice something like that will have to exist in order to get anything other than a trivial libc.
If Ross implements it for Catalina, I implement it for fastspin and the RiscV emulator, and you use it in the PropWare system for P2, then it'll be a "de facto" standard. If Parallax officially blesses it then it'll become "de jure". Either way we should be careful to make it sufficiently generic that any future P2 C compiler can also provide it.
(a) Since we're the compiler/library writers, we're allowed to use the "_t" name space, and in fact I read the C99 standard as encouraging this. If we use "polar_t" then it is guaranteed not to conflict with any user variables (assuming the user follows the rules), whereas POLAR doesn't have this guarantee. It's a minor point, since the new header file is Propeller specific anyway, but I guess it could come up if we ever find it useful to include <propeller2.h> in the implementation of some other standard header file.
I don't agree with point A, because the reason why it won't collide with user defined types it is because "_t" types are system reserved types, normally defined in "stddef.h" and "stdint.h". Users won't typically create variable types ended in "_t" because of this.
Perhaps I didn't express myself well. My view is that for C libraries written for the Propeller 2, the "propeller2.h" file will be a part of the system. The reason for this is that "stdio.h" is part of the system (although it is not part of the GCC compiler itself, it is part of the standard library) and that in order to implement the functions in "stdio.h" one needs to use functions from "propeller2.h". So I think we can use "_t" types in propeller2.h.
Thoughts on using Linaro's ARM GCC distribution as an example? If we treat that as the golden standard of GCC ports, we end up with the following guidelines that I can glean:
* It is okay to use _t suffixes, and indeed the exact same naming convention as what we find in stdint.h. Take arm_neon.h as an example, containing "typedef __simd64_int8_t int8x8_t;"
* Header(s) should go in the root of the header search path
* Inclusions are limited to C wrappers around assembly instructions
* I don't actually know how you set interrupts in ARM with GCC... but whatever is necessary to make this possible for the Propeller should probably be included
One of the big changes I think I'd like to see happen is that a PropGCC distributable package become available without a stdio implementation, loader, etc. It should be GCC, binutils, and "standard" libs (libc, pthread, etc). I do not think that a user who downloads GCC should expect a working version of putchar - if they are carrying that assumption, they should be downloading SimpleIDE not PropGCC. They shouldn't be expecting a loader either, or spin2cpp.
I have no qualms providing another package, with a similar toolset as current PropGCC packages, but I do not think it should be called "PropGCC" but perhaps "PropGCC-SDK" or some such. Then a third package would exist - something to replace SimpleIDE - which combines PropGCC-SDK with an editor and build system.
Providing a stripped down version of PropGCC, as described above, makes things more flexible and helps draw well-defined line components. It helps everyone say "this is part of the GCC/binutils/libs port for the Propeller" and "this a HAL/tool/etc separate from your compiler."
With luck, that may even aid in the porting of LLVM someday, right?
Oh, another thing: I would probably skip _STRSIZE and _STRCOMP, since C already has strlen and strcmp. Again, not a big deal if we have them in, it won't hurt anything, but my preference is to encourage use of the standard library functions over Propeller specific ones.
Eric
Maybe Spin2 should just rename them to STRLEN and STRCMP.
I agree with ersmith. It's be nice if I could include propeller2.h no matter what C/C++ compiler I am using, and have the same "builtins" and such.
Also, agree with DavidZemon. Your proposed PropGCC stuff will also make it easier to migrate to newer versions of GCC. Which is a big issue right now with the existing mess.
I wish Parallax was in a better place financially, such that it could officially support updating PropGCC and/or supporting ersmith, RossH, and others work. As it stands right now, we are going to get the exact same thing with Spin2 written in x86 hidden inside a closed source PropTool, and no official anything else.... very frustrating.
I agree with ersmith. It's be nice if I could include propeller2.h no matter what C/C++ compiler I am using, and have the same "builtins" and such.
Also, agree with DavidZemon. Your proposed PropGCC stuff will also make it easier to migrate to newer versions of GCC. Which is a big issue right now with the existing mess.
I wish Parallax was in a better place financially, such that it could officially support updating PropGCC and/or supporting ersmith, RossH, and others work. As it stands right now, we are going to get the exact same thing with Spin2 written in x86 hidden inside a closed source PropTool, and no official anything else.... very frustrating.
This is how Spin2 will start out, but that is not the terminal case.
I am happy to drop the upper case for function names - for myself, I tend not to use them. But again, I thought we were trying for some kind of Spin compatibility here, where they are generally written as upper case (at least in the documentation).
The problem here is that Spin/PASM is not case-senstive, whereas C is. So in C we have to make a definite decision one way or the other that you don't have to make in Spin. However, Parallax tends to document Spin/PASM keywords and pre-defined functions in upper case.
Perhaps we should leave this one to Parallax themselves to decide?
On the "_t" thing, if you are going to consider these as "system" libraries then we can probably use "_t". I doubt anyone is ever going to insist on POSIX compliance for the Propeller compilers.
Like eric, I considered using just plain "int" for values (like cog and lock numbers) which don't actually need to be 32 bits. It is just that in Spin all parameters are effectively a LONG, and I was trying for Spin compatibility.
Again, it comes down to whether the header file is primarily aimed at C users, or Spin users who may also use C.
But perhaps it is also worth asking what other languages intend to do. AFAIK Java, Python and Forth case are all sensitive. So what conventions are used in those languages? And of course they would not use type names like uint32_t (that's a cross that only C programmers have to bear ).
So what types would they use to match Spin BYTE, WORD and LONG?
I am happy to drop the upper case for function names - for myself, I tend not to use them. But again, I thought we were trying for some kind of Spin compatibility here, where they are generally written as upper case (at least in the documentation).
The problem here is that Spin/PASM is not case-senstive, whereas C is. So in C we have to make a definite decision one way or the other that you don't have to make in Spin. However, Parallax tends to document Spin/PASM keywords and pre-defined functions in upper case.
Perhaps we should leave this one to Parallax themselves to decide?
On the "_t" thing, if you are going to consider these as "system" libraries then we can probably use "_t". I doubt anyone is ever going to insist on POSIX compliance for the Propeller compilers.
Like eric, I considered using just plain "int" for values (like cog and lock numbers) which don't actually need to be 32 bits. It is just that in Spin all parameters are effectively a LONG, and I was trying for Spin compatibility.
Again, it comes down to whether the header file is primarily aimed at C users, or Spin users who may also use C.
But perhaps it is also worth asking what other languages intend to do. AFAIK Java, Python and Forth case are all sensitive. So what conventions are used in those languages? And of course they would not use type names like uint32_t (that's a cross that only C programmers have to bear ).
So what types would they use to match Spin BYTE, WORD and LONG?
The consensus on naming conventions seems to be that we should stick with language standards first, then conformity across languages.
My personal opinion is that this philosophy - language standards first, cross-language consistency second - should carry forward to types used in function parameters/return values as well.
Further, I strongly believe that Spin should not be the golden standard. I don't think anyone has asked for that, and all it does is put unnecessary limitations the libraries for other languages.
The golden standard needs to be language agnostic. Each language can (and should) then implement that golden standard making any small changes as necessary to conform to language standards.
This is where https://github.com/DavidZemon/ParallaxAbstractionLayer/ comes into play. Let's define an agnostic API first, detailing what functions and objects should be available, and then expand that into Spin, C, C++, Python, etc.
The consensus on naming conventions seems to be that we should stick with language standards first, then conformity across languages.
Normally, I would tend to agree with you. But in this case I think consistency across languages is an equally important consideration.
I would like to get some input from people who are more familiar with how it would look in other languages - notably Java, Forth and Python (any others?) - before making any final decisions.
The consensus on naming conventions seems to be that we should stick with language standards first, then conformity across languages.
Normally, I would tend to agree with you. But in this case I think consistency across languages is an equally important consideration.
I would like to get some input from people who are more familiar with how it would look in other languages - notably Java, Forth and Python (any others?) - before making any final decisions.
I know Java and Python quite well. No new types need to be specified for Python because polar coordinates and the like can just be passed/returned as a 2-tuple:
Python naming conventions are: variables and functions and methods are lower snake_case, objects and types are PascalCase (source: https://www.python.org/dev/peps/pep-0008/#naming-conventions)
Java uses PascalCase for all classes (that means all types) and method/variable/parameter names are most often camelCase. Java does not have multiple returns, so we'll likely want to define a PolarCoordinate class:
public class PolarIntegerCoordinate {
private final int x;
private final int y;
public PolarIntegerCoordinate(final int x, final int y) {
this.x = x;
this.y = y;
}
public int getX () {
return this.x;
}
public int getY () {
return this.y;
}
}
I know Java and Python quite well. No new types need to be specified for Python because polar coordinates and the like can just be passed/returned as a 2-tuple
Given that we will probably define a type in Java and C/C++, could we also do so in Python? It would be preferrable to keep consistency between languages where possible, and it also helps to have the compiler detect programming errors (e.g. using a result as polar coordinates when it is actually cartesian etc etc)?
Are there no Forth speakers willing to throw their hat in the ring?
I am happy to drop the upper case for function names - for myself, I tend not to use them. But again, I thought we were trying for some kind of Spin compatibility here, where they are generally written as upper case (at least in the documentation).
I think it's just a typographical convention in the documentation. In practice everyone seems to type them in lower case, it'd be rare to see functions typed in upper case in a Spin program.
Like eric, I considered using just plain "int" for values (like cog and lock numbers) which don't actually need to be 32 bits. It is just that in Spin all parameters are effectively a LONG, and I was trying for Spin compatibility.
Again, it comes down to whether the header file is primarily aimed at C users, or Spin users who may also use C.
To me it seems the most important thing is to have a simple mapping between the languages. That is, it's pretty easy for a programmer to figure out that in C we use "int" instead of "LONG", and that the P2 specific function names are lower case with an underscore in front. But figuring out that "WAITX" in Spin is actually "_WaitCycles" in C, or something like that, would be a lot trickier. I don't think we need to duplicate everything Spin does, just provide the same features with similar (consistent) names.
But perhaps it is also worth asking what other languages intend to do. AFAIK Java, Python and Forth case are all sensitive. So what conventions are used in those languages? And of course they would not use type names like uint32_t (that's a cross that only C programmers have to bear ).
In micropython it appears that variables and methods are generally lower case, and types start with an upper case letter (so we have a Pin class and methods named something like Pin.high()). The types are just whatever type a literal would naturally have, so you can write "Pin.high(0)" to set pin 0 to high.
I may go back and re-do the method names for the Pin class to match whatever C does (I think I used the names in the STM32 port as a basis for the P2 port, but we can change them).
Thoughts on using Linaro's ARM GCC distribution as an example?
I think that may be the wrong package to look at -- what we have here is a library, rather than a compiler.
The distinction is similar to that in the Linux world. There are C compilers (GCC, Clang, etc.) and then there are C libraries (glibc, uclibc, musl, etc.). The libraries are generally written to be portable to multiple compilers. We're in a similar boat here, in that we're creating (a part of) a library. Actually I guess it's more accurate to say that we're creating an API, similar to how Posix specifies an API that glibc, musl, and other Linux libraries then use to implement the features in the C standard library.
We may also want to see a portable standard C library for the Propeller2 that implements all of the usual string, math, and stdio functions. It'd be great if we had such a library that could compile with all of the compilers. We could perhaps merge proplib and the C library that Catalina uses, taking the best idea from each and updating with features for the Propeller2. But that's much more ambitious than what I was proposing at the start of this thread, which is just to make sure that all the various C distributions for P2 have a common way to access the hardware.
One of the big changes I think I'd like to see happen is that a PropGCC distributable package become available without a stdio implementation, loader, etc. It should be GCC, binutils, and "standard" libs (libc, pthread, etc). I do not think that a user who downloads GCC should expect a working version of putchar - if they are carrying that assumption, they should be downloading SimpleIDE not PropGCC.
I'm not sure how useful a C compiler that can't compile "hello world" would be . I'm being extreme there: I see your point, in that a raw C compiler with no library at all might be useful. but that would really be a raw compiler with no standard C library or pthread library at all, just the libgcc support libraries. That's basically what you get if you compile the basic PropGCC repo without binutils or proplib.
In general though the standard C library (including stdio) is part of what people expect from a C compiler distribution.
In general though the standard C library (including stdio) is part of what people expect from a C compiler distribution.
Aside from PropGCC, I'm not sure I've ever downloaded a compiler for bare-metal that has a putchar implementation. I don't think the 8051 had it back when I was in college, and I confirmed yesterday before writing my post that MSP430 doesn't, and I know gcc-arm-none-* doesn't. In all of those, you have to write your own serial routines.
In general though the standard C library (including stdio) is part of what people expect from a C compiler distribution.
Aside from PropGCC, I'm not sure I've ever downloaded a compiler for bare-metal that has a putchar implementation. I don't think the 8051 had it back when I was in college, and I confirmed yesterday before writing my post that MSP430 doesn't, and I know gcc-arm-none-* doesn't. In all of those, you have to write your own serial routines.
avr-libc does provide the following putchar() implementation:
I agree with the reasoning behind the avr-libc approach (namely that "avr-libc has no knowledge about applicable devices") and like the implementation though I can see Parallax wanting to supply a default implementation that targets education/hobbyists.
I agree with the reasoning behind the avr-libc approach (namely that "avr-libc has no knowledge about applicable devices") and like the implementation though I can see Parallax wanting to supply a default implementation that targets education/hobbyists.
Thanks for the extra perspective. This is why I think it makes the most sense to provide three packages:
* GCC: GCC, binutils, standard GNU libraries; capable of targeting P2 and building P2 binaries
* GCC-SDK: GCC + GDB + Parallax-supported HAL in C + loader + any other useful CLI tools
* NewFancyIDE: GCC-SDK + GUI editor + build system (build system may well be built into the editor - not try bring that into the discussion here)
I agree with the reasoning behind the avr-libc approach (namely that "avr-libc has no knowledge about applicable devices") and like the implementation though I can see Parallax wanting to supply a default implementation that targets education/hobbyists.
Thanks for the extra perspective. This is why I think it makes the most sense to provide three packages:
* GCC: GCC, binutils, standard GNU libraries; capable of targeting P2 and building P2 binaries
* GCC-SDK: GCC + GDB + Parallax-supported HAL in C + loader + any other useful CLI tools
* NewFancyIDE: GCC-SDK + GUI editor + build system (build system may well be built into the editor - not try bring that into the discussion here)
I agree. If I ever end up using the Propeller 2 I'd only care about the first 2 (minus a Parallax supported HAL) since I just use CMake, vim, and other command line tools for development.
So, going back over this thread, I believe we are still waiting on answers to the following:
1. Does Parallax have a preference for upper case or lower case names for the Spin functions?
2. What data type would Java and Python use to map to Spin's LONG, WORD and BYTE?
3. Does Python have structures or classes (similar to C "struct") we can use for coordinates?
4. How would any of this look in Forth?
5. Are there any other languages we should be considering?
1. Does Parallax have a preference for upper case or lower case names for the Spin functions?
In PropGCC and the C Simple Libraries they used lower case for function names, so they don't seem to mind lower case.
2. What data type would Java and Python use to map to Spin's LONG, WORD and BYTE?
A hypothetical Java port would use int, short, and byte respectively (those are the Java 32 bit, 16 bit, and 8 bit integral types).
Python only has "int" (a variable length integer, may be longer than 32 bits) and "bytes" (8 bit quantities used in certain circumstances). "int" would be what gets used in most cases, bytes are mostly used for holding arrays of data.
3. Does Python have structures or classes (similar to C "struct") we can use for coordinates?
Python has classes, but it also has tuples and those would be the most natural thing for the _rotxy() and similar functions to return.
5. Are there any other languages we should be considering?
BASIC and Lisp (these exist on the P2 already); for the future Rust, Go, Fortran... we could go on forever
BASIC has "integer", "ushort", and "ubyte" types that would map most closely to LONG, WORD, and BYTE. PropLisp doesn't specify data types for any functions, but internally only has 30 bit numbers, strings of 8 bit characters, and lists.
@DavidZemon has started a project for creating a language agnostic API, which is definitely the appropriate project for what you're discussing above. But the scope is somewhat larger than just propeller2.h.
My feeling is, let's make a sensible propeller2.h for C that at least looks somewhat similar to what Spin2 provides, and that's natural for the C language. Later we can build more APIs on top of that (and other languages that come along can mimic what Spin2 and C have done). If we make propeller2.h as minimal as possible it'll be a good foundation for other things, and also be less likely to get something wrong. So let's not include functions that are provided elsewhere in the standard language definition, and let's minimize any introduced types or macros.
My feeling is, let's make a sensible propeller2.h for C that at least looks somewhat similar to what Spin2 provides, and that's natural for the C language. Later we can build more APIs on top of that (and other languages that come along can mimic what Spin2 and C have done). If we make propeller2.h as minimal as possible it'll be a good foundation for other things, and also be less likely to get something wrong. So let's not include functions that are provided elsewhere in the standard language definition, and let's minimize any introduced types or macros.
Sounds good.
How much is needed to compile the output of Blockly ?
... I doubt anyone is ever going to insist on POSIX compliance for the Propeller compilers...
Actually this is something I wanted to ask you about Catalina and forgot to do so. Obviously you don't support this. My main reason for using C on the P2 would be to get GnuCobol running. It is a 'transpiler' compiling COBOL to C source and as much as I can understand the whole thing it is heavily Linux centered, uses Mingw on windows and gcc, but is able to use VS on windows to produce windows binaries.
So one can choose the used C compiler. gcc/clang/vs … It uses ncurses/pdcurses for display, but has a hard time to compile static links, it relays on dynamic linking, at least it prefers to do so, they are working on that, once in a while. But it also seems to relay on some POSIX support, just to some extend since it runs on Windows and Windows is not complete POSIX compatible as far as I understand the discussions.
But someone got a hello world compiled for a PIC, with tricks an such, so there is still hope!
I am aware that except me nobody will have much interest in COBOL.
I do agree that this effort should be C centric, changing SPIN to use STRCOMP and STRLEN like Chip said would make sense, getting a common set, even with minor differences in syntax would make porting and erics life in supporting multiple languages in fastspin more easy.
Programming almost 5 decades now for a living, I am quite multilingual and it usually just takes me a day or two to adjust to a new one, most of them are really based on ALGOL concepts, that is why I like COBOL a lot, it does things different from the nowadays common concepts of programming.
But having a common HAL for the P2 is a very good goal, taking a C listing and reformatting it a bit to get it running in SPIN (remove leading underscores, replacing braces by indention, etc) would be way much more fun if the names match or are at least alike.
I am still unsure about multiple return values. I do really like the idea, it is a common concept in some languages and to me it is more natural to write return values at the end of a routine as at the beginning but as far as I understood Chips description of PASM calls in SPIN he intends to write parameters back so effectively doing calls by reference? That would allow manipulation of parameters, thus making multiple return values easy.
My feeling is, let's make a sensible propeller2.h for C that at least looks somewhat similar to what Spin2 provides, and that's natural for the C language. Later we can build more APIs on top of that (and other languages that come along can mimic what Spin2 and C have done). If we make propeller2.h as minimal as possible it'll be a good foundation for other things, and also be less likely to get something wrong. So let's not include functions that are provided elsewhere in the standard language definition, and let's minimize any introduced types or macros.
Sounds good.
How much is needed to compile the output of Blockly ?
I believe the full suite of Simple libraries are used by Blockly. Blockly would in and of itself be considered an option for package #3: GCC + tools + libs + editor + build system.
- Leading underscores and lower case for function names, and upper case for constants and macros (unless Parallax expresses a preferences for upper case function names to match their documentation).
- Function declarations will use uint32_t for parameters and return types where the value has to be a long (i.e. 32 bits), uint16_t where the value is a word, and uint8_t where it is a byte. Numeric parameters and return values where size or type is not important will use int (e.g. cog numbers, lock numbers, pin numbers).
- The polar and cartesian coordinate type names will simply be polar and cartesian (this allows for future POSIX compliance if anyone should ever need that).
I think this complies with "best practice" for C coding.
Probably not much point in doing much more until we get the complete list of functions - which I imagine will be forthcoming soon once Chip finishes the Spin implementation.
...
- Function declarations will use uint32_t for parameters and return types where the value has to be a long (i.e. 32 bits), uint16_t where the value is a word, and uint8_t where it is a byte. Numeric parameters and return values where size or type is not important will use int (e.g. cog numbers, lock numbers, pin numbers).
..
Sounds good, but the last one is sounding more dangerous, as int has no defined size.
For the mentioned cases, why not use smallest sensible size, unless otherwise overruled ? Here that's uint8_t ?
Are there speed/align cases where 32b return values might be used instead (even if only passing 0..63) ?
...
- Function declarations will use uint32_t for parameters and return types where the value has to be a long (i.e. 32 bits), uint16_t where the value is a word, and uint8_t where it is a byte. Numeric parameters and return values where size or type is not important will use int (e.g. cog numbers, lock numbers, pin numbers).
..
Sounds good, but the last one is sounding more dangerous, as int has no defined size.
An int has no defined maximum size, but it is guaranteed to be at least 16 bits.
- Leading underscores and lower case for function names, and upper case for constants and macros (unless Parallax expresses a preferences for upper case function names to match their documentation).
- Function declarations will use uint32_t for parameters and return types where the value has to be a long (i.e. 32 bits), uint16_t where the value is a word, and uint8_t where it is a byte. Numeric parameters and return values where size or type is not important will use int (e.g. cog numbers, lock numbers, pin numbers).
- The polar and cartesian coordinate type names will simply be polar and cartesian (this allows for future POSIX compliance if anyone should ever need that).
I think this complies with "best practice" for C coding.
That all sounds good to me, except that I'd like to distinguish the types in some way. If we're not going to use "_t" then perhaps we should make POLAR and CARTESIAN all upper case as well, or captialize at least the first letter, and/or put an underscore in front of them to avoid conflicts with user variables.
Sounds good, but the last one is sounding more dangerous, as int has no defined size.
For the mentioned cases, why not use smallest sensible size, unless otherwise overruled ? Here that's uint8_t ?
Are there speed/align cases where 32b return values might be used instead (even if only passing 0..63) ?
As Ross said, int is guaranteed to be at least 16 bits, and in general should be the most efficient type for the compiler. So it's the natural type to use if the exact bit size of the value isn't important.
All of the existing C compilers for P1 and P2 use 32 bits for "int" anyway. Using types of other sizes imposes a performance penalty in some cases. So we should use "uint16_t" and "uint8_t" only when we really need to.
That all sounds good to me, except that I'd like to distinguish the types in some way. If we're not going to use "_t" then perhaps we should make POLAR and CARTESIAN all upper case as well, or captialize at least the first letter, and/or put an underscore in front of them to avoid conflicts with user variables.
My vote is ignore posix and use polar_t, as arm/linaro does
I've re-read parts of this thread and read through the Spin2 interpreter thread (aka: the editor war thread) as well. I want to address something directly that I may have been saying (thinking?) too subtly.
I do not think propeller2.h should take Spin into consideration. This header should not be about providing Spin compatibility in C. It should be about providing access to all of the P2's hardware from C. IF that happens to be the same feature set as Spin, so be it, but if Spin offers extra features that are not hardware-specific - maybe some string manipulation extra trig functions outside the scope of what the hardware does - I think it should be left out of propeller2.h. It can go elsewhere.
But it's this idea of bringing Spin to C that I want to address. It should not be the goal of propeller2.h. It's a valiant goal, but this is the wrong place for it.
I've re-read parts of this thread and read through the Spin2 interpreter thread (aka: the editor war thread) as well. I want to address something directly that I may have been saying (thinking?) too subtly.
I do not think propeller2.h should take Spin into consideration. This header should not be about providing Spin compatibility in C. It should be about providing access to all of the P2's hardware from C. IF that happens to be the same feature set as Spin, so be it, but if Spin offers extra features that are not hardware-specific - maybe some string manipulation extra trig functions outside the scope of what the hardware does - I think it should be left out of propeller2.h. It can go elsewhere.
But it's this idea of bringing Spin to C that I want to address. It should not be the goal of propeller2.h. It's a valiant goal, but this is the wrong place for it.
I agree, but there are a lot of Spin instructions which relate to PASM instructions which will be needed in C. They are going to need names and Spin has names for them. Might as well harmonize those names. I'm thinking about the obvious RDPIN/WRPIN and pin-related instructions. Most CORDIC operations don't conform to any industry standard, so maybe QLOG/QEXP are appropriate.
Comments
PropGCC actually is already set up this way. When people say "PropGCC" they usually refer to the whole package, but that package is made up of a number of pieces:
- the GCC compiler itself
- binutils (assembler, linker, and other utilities)
- standard library for Propeller
- propeller-load loader for running things on the Propeller
Each of these is a separate repository, but none of them are really very useful on their own (well, except for propeller-load!). The PropGCC's <propeller.h> file is in the library, the repo for which is probably mirrored in the parallaxinc git repo but originally was in github.com/totalspectrum/proplib.
Of course other compilers will be distributed and set up differently -- RossH has his own structure for Catalina, and fastspin is different still. The main thing is that in any full distribution of a Propeller 2 C compiler there should be a propeller2.h with some minimum set of functions for manipulating the P2 hardware. That way some amount of hardware specific C code can be moved easily between compilers, and we can all benefit from a growing ecosystem.
It's reasonable to call propeller2.h part of the "system" on P2. The functionality there (or something equivalent) is required in order to implement other standard library functions, so in practice something like that will have to exist in order to get anything other than a trivial libc.
If Ross implements it for Catalina, I implement it for fastspin and the RiscV emulator, and you use it in the PropWare system for P2, then it'll be a "de facto" standard. If Parallax officially blesses it then it'll become "de jure". Either way we should be careful to make it sufficiently generic that any future P2 C compiler can also provide it.
* It is okay to use _t suffixes, and indeed the exact same naming convention as what we find in stdint.h. Take arm_neon.h as an example, containing "typedef __simd64_int8_t int8x8_t;"
* Header(s) should go in the root of the header search path
* Inclusions are limited to C wrappers around assembly instructions
* I don't actually know how you set interrupts in ARM with GCC... but whatever is necessary to make this possible for the Propeller should probably be included
One of the big changes I think I'd like to see happen is that a PropGCC distributable package become available without a stdio implementation, loader, etc. It should be GCC, binutils, and "standard" libs (libc, pthread, etc). I do not think that a user who downloads GCC should expect a working version of putchar - if they are carrying that assumption, they should be downloading SimpleIDE not PropGCC. They shouldn't be expecting a loader either, or spin2cpp.
I have no qualms providing another package, with a similar toolset as current PropGCC packages, but I do not think it should be called "PropGCC" but perhaps "PropGCC-SDK" or some such. Then a third package would exist - something to replace SimpleIDE - which combines PropGCC-SDK with an editor and build system.
Providing a stripped down version of PropGCC, as described above, makes things more flexible and helps draw well-defined line components. It helps everyone say "this is part of the GCC/binutils/libs port for the Propeller" and "this a HAL/tool/etc separate from your compiler."
With luck, that may even aid in the porting of LLVM someday, right?
Maybe Spin2 should just rename them to STRLEN and STRCMP.
Also, agree with DavidZemon. Your proposed PropGCC stuff will also make it easier to migrate to newer versions of GCC. Which is a big issue right now with the existing mess.
I wish Parallax was in a better place financially, such that it could officially support updating PropGCC and/or supporting ersmith, RossH, and others work. As it stands right now, we are going to get the exact same thing with Spin2 written in x86 hidden inside a closed source PropTool, and no official anything else.... very frustrating.
This is how Spin2 will start out, but that is not the terminal case.
The problem here is that Spin/PASM is not case-senstive, whereas C is. So in C we have to make a definite decision one way or the other that you don't have to make in Spin. However, Parallax tends to document Spin/PASM keywords and pre-defined functions in upper case.
Perhaps we should leave this one to Parallax themselves to decide?
On the "_t" thing, if you are going to consider these as "system" libraries then we can probably use "_t". I doubt anyone is ever going to insist on POSIX compliance for the Propeller compilers.
Like eric, I considered using just plain "int" for values (like cog and lock numbers) which don't actually need to be 32 bits. It is just that in Spin all parameters are effectively a LONG, and I was trying for Spin compatibility.
Again, it comes down to whether the header file is primarily aimed at C users, or Spin users who may also use C.
But perhaps it is also worth asking what other languages intend to do. AFAIK Java, Python and Forth case are all sensitive. So what conventions are used in those languages? And of course they would not use type names like uint32_t (that's a cross that only C programmers have to bear ).
So what types would they use to match Spin BYTE, WORD and LONG?
The consensus on naming conventions seems to be that we should stick with language standards first, then conformity across languages.
My personal opinion is that this philosophy - language standards first, cross-language consistency second - should carry forward to types used in function parameters/return values as well.
Further, I strongly believe that Spin should not be the golden standard. I don't think anyone has asked for that, and all it does is put unnecessary limitations the libraries for other languages.
The golden standard needs to be language agnostic. Each language can (and should) then implement that golden standard making any small changes as necessary to conform to language standards.
This is where https://github.com/DavidZemon/ParallaxAbstractionLayer/ comes into play. Let's define an agnostic API first, detailing what functions and objects should be available, and then expand that into Spin, C, C++, Python, etc.
Normally, I would tend to agree with you. But in this case I think consistency across languages is an equally important consideration.
I would like to get some input from people who are more familiar with how it would look in other languages - notably Java, Forth and Python (any others?) - before making any final decisions.
I know Java and Python quite well. No new types need to be specified for Python because polar coordinates and the like can just be passed/returned as a 2-tuple:
Will print out
Python naming conventions are: variables and functions and methods are lower snake_case, objects and types are PascalCase (source: https://www.python.org/dev/peps/pep-0008/#naming-conventions)
Java uses PascalCase for all classes (that means all types) and method/variable/parameter names are most often camelCase. Java does not have multiple returns, so we'll likely want to define a PolarCoordinate class:
Can't help with the Forth though
Given that we will probably define a type in Java and C/C++, could we also do so in Python? It would be preferrable to keep consistency between languages where possible, and it also helps to have the compiler detect programming errors (e.g. using a result as polar coordinates when it is actually cartesian etc etc)?
Are there no Forth speakers willing to throw their hat in the ring?
To me it seems the most important thing is to have a simple mapping between the languages. That is, it's pretty easy for a programmer to figure out that in C we use "int" instead of "LONG", and that the P2 specific function names are lower case with an underscore in front. But figuring out that "WAITX" in Spin is actually "_WaitCycles" in C, or something like that, would be a lot trickier. I don't think we need to duplicate everything Spin does, just provide the same features with similar (consistent) names.
In micropython it appears that variables and methods are generally lower case, and types start with an upper case letter (so we have a Pin class and methods named something like Pin.high()). The types are just whatever type a literal would naturally have, so you can write "Pin.high(0)" to set pin 0 to high.
I may go back and re-do the method names for the Pin class to match whatever C does (I think I used the names in the STM32 port as a basis for the P2 port, but we can change them).
I think that may be the wrong package to look at -- what we have here is a library, rather than a compiler.
The distinction is similar to that in the Linux world. There are C compilers (GCC, Clang, etc.) and then there are C libraries (glibc, uclibc, musl, etc.). The libraries are generally written to be portable to multiple compilers. We're in a similar boat here, in that we're creating (a part of) a library. Actually I guess it's more accurate to say that we're creating an API, similar to how Posix specifies an API that glibc, musl, and other Linux libraries then use to implement the features in the C standard library.
We may also want to see a portable standard C library for the Propeller2 that implements all of the usual string, math, and stdio functions. It'd be great if we had such a library that could compile with all of the compilers. We could perhaps merge proplib and the C library that Catalina uses, taking the best idea from each and updating with features for the Propeller2. But that's much more ambitious than what I was proposing at the start of this thread, which is just to make sure that all the various C distributions for P2 have a common way to access the hardware.
I'm not sure how useful a C compiler that can't compile "hello world" would be . I'm being extreme there: I see your point, in that a raw C compiler with no library at all might be useful. but that would really be a raw compiler with no standard C library or pthread library at all, just the libgcc support libraries. That's basically what you get if you compile the basic PropGCC repo without binutils or proplib.
In general though the standard C library (including stdio) is part of what people expect from a C compiler distribution.
Regards,
Eric
Aside from PropGCC, I'm not sure I've ever downloaded a compiler for bare-metal that has a putchar implementation. I don't think the 8051 had it back when I was in college, and I confirmed yesterday before writing my post that MSP430 doesn't, and I know gcc-arm-none-* doesn't. In all of those, you have to write your own serial routines.
avr-libc does provide the following putchar() implementation: However, stdout (and the other standard streams) are not initialized at startup. The user is required to setup a FILE struct with appropriate callbacks and point the desired stream to it.
https://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html
Keil C51 provides a default implementation that uses a serial port but this can be overridden by the user.
http://www.keil.com/support/man/docs/c51/c51_stdio_h.htm
http://www.keil.com/support/man/docs/c51/c51_ap_basicio.htm
http://www.keil.com/support/docs/788.htm
I agree with the reasoning behind the avr-libc approach (namely that "avr-libc has no knowledge about applicable devices") and like the implementation though I can see Parallax wanting to supply a default implementation that targets education/hobbyists.
Thanks for the extra perspective. This is why I think it makes the most sense to provide three packages:
* GCC: GCC, binutils, standard GNU libraries; capable of targeting P2 and building P2 binaries
* GCC-SDK: GCC + GDB + Parallax-supported HAL in C + loader + any other useful CLI tools
* NewFancyIDE: GCC-SDK + GUI editor + build system (build system may well be built into the editor - not try bring that into the discussion here)
I agree. If I ever end up using the Propeller 2 I'd only care about the first 2 (minus a Parallax supported HAL) since I just use CMake, vim, and other command line tools for development.
1. Does Parallax have a preference for upper case or lower case names for the Spin functions?
2. What data type would Java and Python use to map to Spin's LONG, WORD and BYTE?
3. Does Python have structures or classes (similar to C "struct") we can use for coordinates?
4. How would any of this look in Forth?
5. Are there any other languages we should be considering?
Anyone?
Ross.
A hypothetical Java port would use int, short, and byte respectively (those are the Java 32 bit, 16 bit, and 8 bit integral types).
Python only has "int" (a variable length integer, may be longer than 32 bits) and "bytes" (8 bit quantities used in certain circumstances). "int" would be what gets used in most cases, bytes are mostly used for holding arrays of data.
Python has classes, but it also has tuples and those would be the most natural thing for the _rotxy() and similar functions to return.
BASIC and Lisp (these exist on the P2 already); for the future Rust, Go, Fortran... we could go on forever
BASIC has "integer", "ushort", and "ubyte" types that would map most closely to LONG, WORD, and BYTE. PropLisp doesn't specify data types for any functions, but internally only has 30 bit numbers, strings of 8 bit characters, and lists.
@DavidZemon has started a project for creating a language agnostic API, which is definitely the appropriate project for what you're discussing above. But the scope is somewhat larger than just propeller2.h.
My feeling is, let's make a sensible propeller2.h for C that at least looks somewhat similar to what Spin2 provides, and that's natural for the C language. Later we can build more APIs on top of that (and other languages that come along can mimic what Spin2 and C have done). If we make propeller2.h as minimal as possible it'll be a good foundation for other things, and also be less likely to get something wrong. So let's not include functions that are provided elsewhere in the standard language definition, and let's minimize any introduced types or macros.
Sounds good.
How much is needed to compile the output of Blockly ?
Actually this is something I wanted to ask you about Catalina and forgot to do so. Obviously you don't support this. My main reason for using C on the P2 would be to get GnuCobol running. It is a 'transpiler' compiling COBOL to C source and as much as I can understand the whole thing it is heavily Linux centered, uses Mingw on windows and gcc, but is able to use VS on windows to produce windows binaries.
So one can choose the used C compiler. gcc/clang/vs … It uses ncurses/pdcurses for display, but has a hard time to compile static links, it relays on dynamic linking, at least it prefers to do so, they are working on that, once in a while. But it also seems to relay on some POSIX support, just to some extend since it runs on Windows and Windows is not complete POSIX compatible as far as I understand the discussions.
But someone got a hello world compiled for a PIC, with tricks an such, so there is still hope!
I am aware that except me nobody will have much interest in COBOL.
I do agree that this effort should be C centric, changing SPIN to use STRCOMP and STRLEN like Chip said would make sense, getting a common set, even with minor differences in syntax would make porting and erics life in supporting multiple languages in fastspin more easy.
Programming almost 5 decades now for a living, I am quite multilingual and it usually just takes me a day or two to adjust to a new one, most of them are really based on ALGOL concepts, that is why I like COBOL a lot, it does things different from the nowadays common concepts of programming.
But having a common HAL for the P2 is a very good goal, taking a C listing and reformatting it a bit to get it running in SPIN (remove leading underscores, replacing braces by indention, etc) would be way much more fun if the names match or are at least alike.
I am still unsure about multiple return values. I do really like the idea, it is a common concept in some languages and to me it is more natural to write return values at the end of a routine as at the beginning but as far as I understood Chips description of PASM calls in SPIN he intends to write parameters back so effectively doing calls by reference? That would allow manipulation of parameters, thus making multiple return values easy.
Not sure about that one
.
Enjoy!
Mike
I believe the full suite of Simple libraries are used by Blockly. Blockly would in and of itself be considered an option for package #3: GCC + tools + libs + editor + build system.
- Leading underscores and lower case for function names, and upper case for constants and macros (unless Parallax expresses a preferences for upper case function names to match their documentation).
- Function declarations will use uint32_t for parameters and return types where the value has to be a long (i.e. 32 bits), uint16_t where the value is a word, and uint8_t where it is a byte. Numeric parameters and return values where size or type is not important will use int (e.g. cog numbers, lock numbers, pin numbers).
- The polar and cartesian coordinate type names will simply be polar and cartesian (this allows for future POSIX compliance if anyone should ever need that).
I think this complies with "best practice" for C coding.
Probably not much point in doing much more until we get the complete list of functions - which I imagine will be forthcoming soon once Chip finishes the Spin implementation.
Ross.
For the mentioned cases, why not use smallest sensible size, unless otherwise overruled ? Here that's uint8_t ?
Are there speed/align cases where 32b return values might be used instead (even if only passing 0..63) ?
An int has no defined maximum size, but it is guaranteed to be at least 16 bits.
As Ross said, int is guaranteed to be at least 16 bits, and in general should be the most efficient type for the compiler. So it's the natural type to use if the exact bit size of the value isn't important.
All of the existing C compilers for P1 and P2 use 32 bits for "int" anyway. Using types of other sizes imposes a performance penalty in some cases. So we should use "uint16_t" and "uint8_t" only when we really need to.
My vote is ignore posix and use polar_t, as arm/linaro does
I do not think propeller2.h should take Spin into consideration. This header should not be about providing Spin compatibility in C. It should be about providing access to all of the P2's hardware from C. IF that happens to be the same feature set as Spin, so be it, but if Spin offers extra features that are not hardware-specific - maybe some string manipulation extra trig functions outside the scope of what the hardware does - I think it should be left out of propeller2.h. It can go elsewhere.
But it's this idea of bringing Spin to C that I want to address. It should not be the goal of propeller2.h. It's a valiant goal, but this is the wrong place for it.
I agree, but there are a lot of Spin instructions which relate to PASM instructions which will be needed in C. They are going to need names and Spin has names for them. Might as well harmonize those names. I'm thinking about the obvious RDPIN/WRPIN and pin-related instructions. Most CORDIC operations don't conform to any industry standard, so maybe QLOG/QEXP are appropriate.