Nothing, Catalina is a not a native Prop program. It is a cross compiler.
I guess one could compile Catalina with Catalina on a PC resulting in a Catalina that will run on the Prop.
Provided the Prop has a big enough external RAM and file store to run it.
I also guess bootstrapping a native Catalina like that is not so easy. I believe RossH already this idea in mind.
Nothing, Catalina is a not a native Prop program. It is a cross compiler.
I guess one could compile Catalina with Catalina on a PC resulting in a Catalina that will run on the Prop.
Provided the Prop has a big enough external RAM and file store to run it.
I also guess bootstrapping a native Catalina like that is not so easy. I believe RossH already this idea in mind.
Yes, very early on I compiled Catalina with Catalina and produced a compiler that would run on the Prop. The trouble is that there was no point in going any further - for three reasons:
1. Insufficient RAM on any Prop plaform. I can't recall how big the result was, but it was certainly too large for any platform I had at the time. Maybe now that we have boards with 32Mb RAM we might be able to run it.
2. Catalina requires a PASM assembler, and (again, at the time) there was no assembler that could run on the Propeller. Maybe now that we have Sphinx this might be possible.
3. Although everybody says they would like to see this, nobody actually has any practical use for it!
Nothing, Catalina is a not a native Prop program. It is a cross compiler.
I guess one could compile Catalina with Catalina on a PC resulting in a Catalina that will run on the Prop.
Provided the Prop has a big enough external RAM and file store to run it.
I also guess bootstrapping a native Catalina like that is not so easy. I believe RossH already this idea in mind.
Yes, very early on I compiled Catalina with Catalina and produced a compiler that would run on the Prop. The trouble is that there was no point in going any further - for three reasons:
Though yet in response to my earlier statement about Catalina not being very useful because it is not Prop native you said:
You should read the Catalina documentation. Catalina runs "out of the box" on any Propeller, including all the boards you mentioned!
So 32k is insufficient, even though many ANSI C compilers have been made that can run in 12K or less with out overlays and without accessing external storage. You definitely have me wondering about how a C compiler could so big (even with the LMM stuff), I guess I am going to be looking at the source very closely.
And as for a Practical use; How about developing a true Propeller computer, or not being tied to Linux or Windoze to use it with out a lot of work in porting it? It is not fully ANSI C from the little bit of code that I have already browsed, and GCC is not as universal as they would like to be.
So 32k is insufficient, even though many ANSI C compilers have been made that can run in 12K or less with out overlays and without accessing external storage. You definitely have me wondering about how a C compiler could so big (even with the LMM stuff), I guess I am going to be looking at the source very closely.
Could you please point me to even a single ANSI C compiler that can run in 12k or less without overlays? You seem to be talking about the compiler itself running in that amount of memory not the code that it generates. Catalina can certainly generate code that will run in 12k of memory without overlays. It's just that the compiler itself can't run in that little space. I seriously doubt that even with hand crafted assembly language you'd be able to get a full ANSI C compiler to fit in 12k. However, I'd love to be proved wrong! :-)
David Betz:
I will try to track down one or more of these old compilers for you (I no longer have a 5.25 inch floppy drive). Many of them did not include support for wide string libs, also many of them relied on the program not having to many dependencies on static Libs, though they still fit in 12k (plus 4KB to 8KB for the source file plus 2KB to 8KB for the generated binary), and were 100% ANSI compliant. They did this by using a single pass compiler that directly generated binary executable object or linkable object code, if they needed to do any linking other than the standard lib this did require access to mass storage (of course), and they did not support inline assembly (which is not part of the standard anyway).
David Betz:
I will try to track down one or more of these old compilers for you (I no longer have a 5.25 inch floppy drive). Many of them did not include support for wide string libs, also many of them relied on the program not having to many dependencies on static Libs, though they still fit in 12k (plus 4KB to 8KB for the source file plus 2KB to 8KB for the generated binary), and were 100% ANSI compliant. They did this by using a single pass compiler that directly generated binary executable object or linkable object code, if they needed to do any linking other than the standard lib this did require access to mass storage (of course), and they did not support inline assembly (which is not part of the standard anyway).
Thanks! I'll be looking forward to seeing one of these. I know there were small C compilers back in the early micro days. Certainly there was Small C but I don't think it fit in 14k. It is more likely that BDS C would fit in that much memory but I think it was multi-pass and was written in assembly language and it was not an ANSI C compiler since the ANSI standard didn't exist back then. I'm sure there are many others that I am not familiar with.
David Betz: http://floppysoftware.vacau.com/c_compilers.html
I think this page may interest you, it does not fully answer the question (though many of these came close to ANSI C before the standard existed). I wish I could remember the names of some of those early ANSI C compilers, they were truly works of eloquence (in the mathematical since of eloquence), very small and efficient.
Catalina runs "out of the box" on any Propeller, including all the boards you mentioned!
I think the misunderstanding here is that instead of "Catalina runs on any propeller' it should perhaps be reworded "Programs compiled with Catalina run on any propeller".
However, having said that, it is possible to compile C programs on a propeller that have been written totally on the propeller. This has been done within the CP/M emulation, with the program written in Wordstar and compiled using BDSC. It does work, but it is slow (several minutes to compile "Hello World"). Having used this, I think that the hard part may not be the compiler, but rather the text editor.
Dr_Acula:
Thank you. I supose that a good text editor would be difficult to implement in this space, though a simple screen editor based text file editor should do, or maybe a COPY CON, ECHO >, or EDLIN style editor . Has any one attempted a full blown text editor on the prop yet??? It would not have to run at the same time as the compiler, which in turn would not have to run at the same time as the linker.
So 32k is insufficient, even though many ANSI C compilers have been made that can run in 12K or less with out overlays and without accessing external storage. You definitely have me wondering about how a C compiler could so big (even with the LMM stuff), I guess I am going to be looking at the source very closely.
Hi David,
Sorry if I misled you. As Dr_A points out, I should have said "Catalina can compile programs that can run on any Propeller" - my mistake!
However, I don't think you will find an ANSI C compiler that can run in 12k. You may be thinking of the original Tiny C - this program had a code size under 12k (on x86), but it implemented only a small fraction of the original C language (which is in turn smaller than the current ANSI C).
In any case, even if a C compiler had a code size of 12k (and for various reasons I will go into later, the code size would be much larger than that on the Prop), you still need more space than that to actually compile anything - e.g. to store the symbol table. Exactly how much space you need depends on the program being compiled, but you aren't going to be able to compile much in the way of non-trivial programs in only 32kb of non-virtual, non-overlaid memory.
I believe ANSI C compilers would take more like hundreds of kb of code size, plus whatever data size is required for the program being compiled. The smallest C compiler I know of is probably the current version of the original Tiny C compiler (http://bellard.org/tcc/) - this claims to be ANSI compliant, but weighs in with a code size of around 100kb (on x86). But again you need more memory than that to actually compile anything - although perhaps not much more since it claims to be single-pass.
Another thing to remember is that these compilers all run under an operating system - i.e. they do not need to carry around their own file system and SD card drivers just to be able to read the C source! A propeller compiler has to do all that and more. Out of interest, I just used Catalina to compile the original version of the Tiny C compiler (remember it has a code size of 12k on x86) and its size on the Propeller (including all the file system and I/O drivers necessary to run it) ends up with a code size of 66k! And this for a compiler that implements only a fraction of ANSI C. I didn't try compiling the current version of Tiny C, but my guess would be it would end up with a code size of at least 300k on the Propeller.
And it gets worse, of course - very few modern compilers are single pass, because such compilers offer little or no opportunity for code optimization. I don't know what the code produced by Tiny C is like, but it is probably terribly inefficient. Most C compilers are multi-pass to allow for useful things like register optimization, common sub-expression re-use and dead code elimination. Even LCC has fairly sophisticated capabilities in this area. But with a multi-pass compiler you also need to store the intermediate parse trees - and this needs quite a lot of additional memory space for a non-trivial program.
From memory, I think I figured out that LCC would require something like 3 to 4Mb to compile itself from C down to PASM on the Propeller - and even if it could, there is currently no assembler that can run on the Prop capable of assembling that PASM into a final binary.
Dr_Acula:
Thank you. I supose that a good text editor would be difficult to implement in this space, though a simple screen editor based text file editor should do, or maybe a COPY CON, ECHO >, or EDLIN style editor . Has any one attempted a full blown text editor on the prop yet??? It would not have to run at the same time as the compiler, which in turn would not have to run at the same time as the linker.
Hi David,
Catalyst (Catalina's SD card loader) comes with a version of the vi text editor.
And as for a Practical use; How about developing a true Propeller computer, or not being tied to Linux or Windoze to use it with out a lot of work in porting it? It is not fully ANSI C from the little bit of code that I have already browsed, and GCC is not as universal as they would like to be.
I'm not sure what you mean here. Do you mean a Propeller-based operating system? There are several groups working on one - search these forums and you'll find several ongoing projects (plus lots of idle speculations about porting linux etc).
As to being "not fully ANSI C" - what are you referring to? LCC itself is certainly ANSI C, and so is the Catalina back-end code generator. So are the Catalina libraries. But of course the Propeller run-time support package is not, since that would presume the existence of an ANSI compliant C compiler and associated run-time support package (chicken, meet egg!).
RossH:
By saying 'it is not fully ANSI C' I am referring to the source of Catalina that I have looked at, some of the extensions seem to be gcc style extensions. And my point in saying this is that Catalina can not be ported to every possible platform that has a C compiler with out first porting a different C compiler.
RossH:
If Catalina will run well in not to much XMM, I think even that could be useful, assuming that the XMM driver can be easily modified by the user to use a variety of different memories, as not every one is going to have the same preferences, and many are likely to be adding there own memory to a board that comes with none.
Sorry I ignored this thread for a week - had a family trip to Melbourne and it was a "no internet" holiday!
Back coding now. I thought I would tackle the graphical mouse next, mainly so I could answer the question as to whether Catalina is fast enough to draw and refresh a 273 pixel mouse pointer in real time. And the good news is that it can!
At the moment I'm redrawing the mouse pointer from external ram but it probably would be faster again if the array was in hub ram.
This code is not fully debugged - the bounds checking is not working so the mouse goes a bit haywire at the edges of the screen.
It also demonstrates loading in another cogject (this program is now using 3 cogjects). I'm not sure if there is a "right" or "wrong" method in terms of plugins vs cogjects and I guess I would like to see both methods available for use. What is nice though is to be able to use the same cogject for a spin program and a C program.
I have found that the sd card driver in Catalina is a little slow compared with Kye's SD driver. For the moment, the optimum speed solution is to load all cogjects into XMM at bootup, as it is faster to load a cogject from XMM into a cog than it is to load from SD into cog. That could change down the track.
At the moment it boots up, displays some text messages on the Catalina VGA text driver, then shuts down cogs 1 and 3, reuses cog 1 for two other VGA displays and puts the mouse in cog 7. This leaves cog 3 free.
I am starting to see some real advantages to coding in a way that reuses cogs over and over. Want to do some floating point math and no cogs left? Simply overwrite the mouse cog with the floating point code, do the sums, then reload the mouse.
Next step is to click on a button and redraw the button as a "clicked" button. Then it is time to tackle text boxes, which end up being de-facto word processors.
/* PASM cogject demonstration, see also cogject example in spin*/
#include <stdio.h>
#include <string.h>
// cogjects - sd card driver in catalina is a little slow so load up once into external ram then (re) load quicker from external ram
unsigned long cogject_color[512]; // external memory for color vga driver
unsigned long cogject_gray[512]; // external memory for gray vga driver
unsigned long cogject_mouse[512]; // external memory for mouse driver
unsigned long mouse_mask[21] = { // mask 00=pixel, 11=transparant
0xfffffff0,0xffffffc0,0xffffff00,0xfffffc00,0xfffff000,0xffffc000, // order is reversed in each long
0xffff0000,0xfffc0000,0xfff00000,0xffc00000,0xff000000,0xfc000000,
0xfffc0000,0xfffc0000,0xfff00300,0xfff003c0,0xffc00ff0,0xffc00fff,
0xff003fff,0xff003fff,0xffc0ffff
};
unsigned long mouse_icon[21] = { // icon, 00, 01, 10 or 11=pixel, 00 = transparent if transparent above
0x00000004,0x00000010,0x0000004c,0x0000013c,0x000004fc,0x000013fc,
0x00004ffc,0x00013ffc,0x0004fffc,0x0013fffc,0x004ffffc,0x01003ffc,
0x00013cfc,0x00013c3c,0x0004f04c,0x0004f010,0x0013c004,0x0013c000,
0x004f0000,0x004f0000,0x00100000
};
unsigned long screen_external[4800] ; // external memory for a screen buffer
// 128 rows, one for each ascii character 0 to 127
// first long is 0000HHWW where HH is the height in hex and WW is the width in hex
unsigned long sans_serif_font[1664] =
{
0x00000c00,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c00,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
0x00000c00,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c00,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c00,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c00,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000000, 0x00000002, 0x00000000, 0x00000000,
0x00000c05,0x00000000, 0x00000009, 0x00000009, 0x00000009, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x00000012, 0x00000012, 0x0000003f, 0x00000012, 0x00000012, 0x00000012, 0x0000003f, 0x00000012, 0x00000012, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000004, 0x0000000e, 0x00000015, 0x00000014, 0x0000000c, 0x00000006, 0x00000005, 0x00000015, 0x0000000e, 0x00000004, 0x00000000,
0x00000c08,0x00000000, 0x00000030, 0x00000049, 0x00000032, 0x00000004, 0x00000008, 0x00000010, 0x00000026, 0x00000049, 0x00000006, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000008, 0x00000014, 0x00000014, 0x00000008, 0x00000008, 0x00000015, 0x00000012, 0x00000012, 0x0000000d, 0x00000000, 0x00000000,
0x00000c02,0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000001, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000001,
0x00000c03,0x00000000, 0x00000002, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000002,
0x00000c04,0x00000000, 0x00000005, 0x00000002, 0x00000005, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x0000001f, 0x00000004, 0x00000004, 0x00000000, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000002, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00000000,
0x00000c05,0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000002, 0x00000002, 0x00000004, 0x00000004, 0x00000008, 0x00000008, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x0000000e, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x0000000e, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000004, 0x0000001c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x0000000e, 0x00000011, 0x00000001, 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x0000001f, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x0000000e, 0x00000011, 0x00000001, 0x00000001, 0x00000006, 0x00000001, 0x00000001, 0x00000011, 0x0000000e, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000002, 0x00000006, 0x00000006, 0x0000000a, 0x0000000a, 0x00000012, 0x0000001f, 0x00000002, 0x00000002, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x0000001f, 0x00000010, 0x00000010, 0x0000001e, 0x00000011, 0x00000001, 0x00000001, 0x00000011, 0x0000000e, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x0000000e, 0x00000011, 0x00000010, 0x00000010, 0x0000001e, 0x00000011, 0x00000011, 0x00000011, 0x0000000e, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x0000001f, 0x00000001, 0x00000002, 0x00000002, 0x00000004, 0x00000004, 0x00000008, 0x00000008, 0x00000008, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x0000000e, 0x00000011, 0x00000011, 0x00000011, 0x0000000e, 0x00000011, 0x00000011, 0x00000011, 0x0000000e, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x0000000e, 0x00000011, 0x00000011, 0x00000011, 0x0000000f, 0x00000001, 0x00000001, 0x00000011, 0x0000000e, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000002, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000008, 0x00000004, 0x00000002, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000001f, 0x00000000, 0x0000001f, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000010, 0x00000008, 0x00000004, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x0000000e, 0x00000011, 0x00000001, 0x00000001, 0x00000002, 0x00000004, 0x00000004, 0x00000000, 0x00000004, 0x00000000, 0x00000000,
0x00000c0b,0x00000000, 0x00000078, 0x00000186, 0x00000102, 0x00000239, 0x00000249, 0x00000249, 0x00000237, 0x00000100, 0x00000180, 0x0000007c, 0x00000000,
0x00000c07,0x00000000, 0x00000008, 0x00000008, 0x00000014, 0x00000014, 0x00000022, 0x00000022, 0x0000003e, 0x00000041, 0x00000041, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x0000003c, 0x00000022, 0x00000022, 0x00000022, 0x0000003c, 0x00000022, 0x00000022, 0x00000022, 0x0000003c, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x0000001e, 0x00000021, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000021, 0x0000001e, 0x00000000, 0x00000000,
0x00000c08,0x00000000, 0x00000078, 0x00000044, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000044, 0x00000078, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x0000003e, 0x00000020, 0x00000020, 0x00000020, 0x0000003c, 0x00000020, 0x00000020, 0x00000020, 0x0000003e, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x0000001f, 0x00000010, 0x00000010, 0x00000010, 0x0000001e, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000000, 0x00000000,
0x00000c08,0x00000000, 0x0000003c, 0x00000042, 0x00000040, 0x00000040, 0x0000004e, 0x00000042, 0x00000042, 0x00000046, 0x0000003a, 0x00000000, 0x00000000,
0x00000c08,0x00000000, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x0000007e, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000000, 0x00000000,
0x00000c05,0x00000000, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000012, 0x00000012, 0x0000000c, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x00000022, 0x00000024, 0x00000028, 0x00000030, 0x00000030, 0x00000028, 0x00000024, 0x00000022, 0x00000021, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x0000001f, 0x00000000, 0x00000000,
0x00000c09,0x00000000, 0x00000082, 0x00000082, 0x000000c6, 0x000000c6, 0x000000aa, 0x000000aa, 0x00000092, 0x00000092, 0x00000082, 0x00000000, 0x00000000,
0x00000c08,0x00000000, 0x00000042, 0x00000062, 0x00000062, 0x00000052, 0x00000052, 0x0000004a, 0x00000046, 0x00000046, 0x00000042, 0x00000000, 0x00000000,
0x00000c08,0x00000000, 0x0000003c, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x0000003c, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x0000003e, 0x00000021, 0x00000021, 0x00000021, 0x0000003e, 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000000, 0x00000000,
0x00000c08,0x00000000, 0x0000003c, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x0000004a, 0x00000046, 0x0000003c, 0x00000002, 0x00000000,
0x00000c08,0x00000000, 0x0000007c, 0x00000042, 0x00000042, 0x00000042, 0x0000007c, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x0000001c, 0x00000022, 0x00000020, 0x00000020, 0x0000001c, 0x00000002, 0x00000002, 0x00000022, 0x0000001c, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x0000003e, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000000, 0x00000000,
0x00000c08,0x00000000, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x00000042, 0x0000003c, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x00000041, 0x00000041, 0x00000022, 0x00000022, 0x00000022, 0x00000014, 0x00000014, 0x00000008, 0x00000008, 0x00000000, 0x00000000,
0x00000c0b,0x00000000, 0x00000401, 0x00000401, 0x00000222, 0x00000222, 0x00000222, 0x00000154, 0x00000154, 0x00000088, 0x00000088, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x00000041, 0x00000041, 0x00000022, 0x00000014, 0x00000008, 0x00000014, 0x00000022, 0x00000041, 0x00000041, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x00000041, 0x00000041, 0x00000022, 0x00000014, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000000, 0x00000000,
0x00000c07,0x00000000, 0x0000007f, 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x0000007f, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000003, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000003,
0x00000c05,0x00000000, 0x00000008, 0x00000008, 0x00000008, 0x00000004, 0x00000004, 0x00000002, 0x00000002, 0x00000001, 0x00000001, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000003, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000003,
0x00000c06,0x00000004, 0x0000000a, 0x00000011, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000003f,
0x00000c03,0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000e, 0x00000001, 0x0000000f, 0x00000011, 0x00000011, 0x0000000f, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000010, 0x00000010, 0x00000010, 0x0000001e, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x0000001e, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000e, 0x00000011, 0x00000010, 0x00000010, 0x00000011, 0x0000000e, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x0000000f, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x0000000f, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000e, 0x00000011, 0x0000001f, 0x00000010, 0x00000011, 0x0000000e, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000001, 0x00000002, 0x00000002, 0x00000003, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x0000000f, 0x00000001, 0x0000001e,
0x00000c06,0x00000000, 0x00000010, 0x00000010, 0x00000010, 0x00000016, 0x00000019, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x00000000, 0x00000000,
0x00000c02,0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000000,
0x00000c02,0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001,
0x00000c06,0x00000000, 0x00000010, 0x00000010, 0x00000010, 0x00000012, 0x00000014, 0x00000018, 0x00000014, 0x00000012, 0x00000011, 0x00000000, 0x00000000,
0x00000c02,0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000, 0x00000000,
0x00000c08,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000076, 0x00000049, 0x00000049, 0x00000049, 0x00000049, 0x00000049, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000016, 0x00000019, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000e, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x0000000e, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000001e, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x0000001e, 0x00000010, 0x00000010,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x0000000f, 0x00000001, 0x00000001,
0x00000c03,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000000, 0x00000000,
0x00000c05,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000006, 0x00000009, 0x00000004, 0x00000002, 0x00000009, 0x00000006, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000002, 0x00000002, 0x00000003, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000001, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000011, 0x00000011, 0x00000011, 0x00000011, 0x00000013, 0x0000000d, 0x00000000, 0x00000000,
0x00000c06,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000011, 0x00000011, 0x0000000a, 0x0000000a, 0x00000004, 0x00000004, 0x00000000, 0x00000000,
0x00000c08,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000049, 0x00000049, 0x00000055, 0x00000055, 0x00000022, 0x00000022, 0x00000000, 0x00000000,
0x00000c05,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009, 0x00000009, 0x00000006, 0x00000006, 0x00000009, 0x00000009, 0x00000000, 0x00000000,
0x00000c05,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009, 0x00000009, 0x00000009, 0x00000009, 0x00000006, 0x00000004, 0x00000004, 0x00000018,
0x00000c05,0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f, 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x0000000f, 0x00000000, 0x00000000,
0x00000c04,0x00000001, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000004, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000001, 0x00000000,
0x00000c02,0x00000000, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000000,
0x00000c04,0x00000004, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000001, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000004, 0x00000000,
0x00000c07,0x00000000, 0x00000000, 0x00000019, 0x00000026, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000c03,0x00000000, 0x00000000, 0x00000007, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000005, 0x00000007, 0x00000000, 0x00000000,
};
// start of C functions
void text_clearscreen() // white text on dark blue background
{
int i;
for (i=0;i<40;i++)
{
t_setpos(0,0,i); // move cursor to next line
t_color(0,0x08FC); // RRGGBBxx eg dark blue background 00001000 white text 11111100
}
}
void sleep(int milliseconds) // sleep function
{
_waitcnt(_cnt()+(milliseconds*(_clockfreq()/1000))-4296);
}
char peek(int address) // function implementation of peek
{
return *((char *)address);
}
void poke(int address, char value) // function implementation of poke
{
*((char *)address) = value;
}
// *************************************************
// Runtime Functions from BCX
// *************************************************
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));
}
char *str (double d)
{
register char *strtmp = BCX_TmpStr(24);
sprintf(strtmp,"% .15G",d);
return strtmp;
}
char *hex (int a)
{
register char *strtmp = BCX_TmpStr(16);
sprintf(strtmp,"%X",a);
return strtmp;
}
// *************************************************************
void external_memory_cog_load(int cognumber, unsigned long cogdata[], unsigned long parameters_array[]) // load a cog from external memory
{
unsigned long hubcog[511]; // create a local array, this is in hub ram, not external ram
int i;
for(i=0;i<512;i++)
{
hubcog[i]=cogdata[i]; // move from external memory to a local array in hub
}
_coginit((int)parameters_array>>2, (int)hubcog>>2, cognumber); // load the cog
}
int EoF (FILE* stream)
{
register int c, status = ((c = fgetc(stream)) == EOF);
ungetc(c,stream);
return status;
}
void readcog(char *filename,unsigned long external_cog[]) // read in a .cog file into external memory array
{
int i;
FILE *FP1;
i = 0;
if((FP1=fopen(filename,"rb"))==0) // open the file
{
fprintf(stderr,"Can't open file %s\n",filename);
exit(1);
}
fseek(FP1,0,0);
for(i=0;i<24;i++)
{
getc(FP1); // read in the first 24 bytes and discard
}
i = 0;
while(!EoF(FP1) & (i<505)) // run until end of file or 511-6
{
external_cog[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24); // get the long
i+=1;
}
if(FP1)
{
fclose(FP1); // close the file
FP1=NULL;
}
//printf("external array cog first long = 0x%x \n",external_cog[0]); // hex value
}
void pix_clearscreen(unsigned long screen[])
{
int i;
for (i=0;i<4800;i++)
{
screen[i] = 0x00000000; // fill with black, use longs rather than bytes so 4 pixels per loop
}
}
void pix_pixel(unsigned long screen[], int x, int y, char color)
{
poke((y*160+x+(unsigned long)&screen[0]),color);
}
void pix_readscreen(char *filename, unsigned long screen[]) // read a full screen 19200 byte file into the screen
{
int i;
FILE *FP1;
i = 0;
FP1=fopen(filename,"rb"); // open the file
fseek(FP1,0,0);
for(i=0;i<=4800;i++)
{
screen[i] = getc(FP1) | (getc(FP1)<<8) | (getc(FP1)<<16) | (getc(FP1)<<24); // get the long
}
fclose(FP1); // close the file
FP1=NULL;
}
char pix_color(char red,char green,char blue) // pass red,green,blue 0-3, returns a combined value
{
return ((red & 0x3) << 6 ) | ((green & 0x3) << 4) | ((blue & 0x3) << 2);
}
void pix_screengray(unsigned long screen[]) // whole screen gray
{
int i;
for(i=0;i<4800;i++)
{
screen[i] = 0xa8a8a8a8; // same as pix_color(2,2,2)
}
}
void pixenginestart(int cognumber, unsigned long cogarray[], unsigned long screen[], unsigned long pingroup, char color_parameters[])
{
int i;
unsigned long frequencystate;
screen[2] = (0xff << (8*pingroup));
screen[3] = (0x300000ff | (pingroup << 9));
frequencystate = ((25175000 + 1600) / 4);
screen[4] = 1;
for(i=0;i<32;i++)
{
frequencystate = frequencystate << 1;
screen[4] = (screen[4] << 1) | (screen[4] >> 31);
if (frequencystate >= _clockfreq())
{
frequencystate -= _clockfreq();
screen[4] += 1;
}
}
color_parameters[0] = 1; // displayindicator
color_parameters[1] = 0; // syncindicator
screen[0] = (unsigned long) &color_parameters[0]; // pointer to displayindicator
screen[1] = (unsigned long) &color_parameters[1]; // pointer to syncindicator
_cogstop(cognumber); // stop just before starting the next one
external_memory_cog_load(cognumber,cogarray,screen); // load from external ram, pass some values in screen[]
//pix_clearscreen(screen); // clear the screen to black
pix_screengray(screen); // screen gray
}
void pix_colorbar(unsigned long screen[])
{
int x;
int c;
x = 0;
for (c=0;c<64;c++)
{
pix_pixel(screen,x+10,6,(c<<2)); // print all the colors in a bar
x++;
}
}
void pix_line(unsigned long screen[], int startx, int starty, int endx, int endy, char color)
{
int row; // also does an unfilled box
int col;
for(col=startx;col <= endx ;col++)
{
pix_pixel(screen,col,starty,color); // horizontal lines
pix_pixel(screen,col,endy,color);
}
for(row=starty;row <= endy;row++)
{
pix_pixel(screen,startx,row,color);
pix_pixel(screen,endx,row,color);
}
}
void pix_box_fill(unsigned long screen[], int startx, int starty, int endx, int endy, char color)
{
int row;
int col;
for(row =starty;row <= endy; row++)
{
for(col=startx;col <=endx; col++)
{
pix_pixel(screen,col,row,color); // horizontal line
}
}
}
void copyscreen(unsigned long source[],unsigned long destination[])
{
memcpy(destination,source,19200); // a strings.h function
}
void color_demo(unsigned long screen[],char color_parameters[],int cognumber) // kye graphics demo
{
pixenginestart(cognumber,cogject_color,screen,2,color_parameters); // start the driver
pix_pixel(screen,3,3,0x44);
pix_pixel(screen,4,4,0xFF);
pix_pixel(screen,5,5,pix_color(1,2,3)); // rgb each 0,1,2 or 3
pix_line(screen,0,0,159,119,pix_color(3,0,0)); // red border for screen
pix_colorbar(screen); // a color bar
pix_line(screen,10,10,30,30,pix_color(3,3,0)); // a yellow box
pix_box_fill(screen,10,50,40,60,pix_color(3,0,3)); // magenta filled rectangle
//pix_readscreen("wallaby.vga",screen); // display whole screen image
//copyscreen(screen,screen_external); // copy to external ram
//pix_readscreen("Giraffe.vga",screen); // display whole screen image
//copyscreen(screen_external,screen); // copy back to hub
//pix_readscreen("prop160.vga",screen); // display whole screen image
//pix_box_fill(screen, 0, 0, 159,119,pix_color(2,2,2)); // whole screen gray
}
// ****************** end color screen code *********************************
// ****************** begin gray screen code ********************************
void gray_pixel(unsigned long screen[], unsigned long x, unsigned long y, unsigned long color)
{
// unsigned long bitsperpixel = gray_parameters[3];
unsigned long bitsperpixel = 1; // always is 1
unsigned long i;
i = (x >>4) + (20 * y); // i = the long that contains our pixel
x = ((x & (0x1f >> bitsperpixel)) << bitsperpixel);
//mask = (0x3 << xpixel); // xpixel holds the number of bits to shift to the left, and invert this
//mask = ~mask; // invert this
screen[i] = (( screen[i] & ~(0x3 << x)) | (color << x)); // do the and with a mask and the or in one line
}
int gray_printf(unsigned long screen[],int startx, int starty, char lineoftext[])
{
int height = sans_serif_font[0] >> 8; // read from the font data the height
int width,ascii,a,x,y,i,curx;
unsigned long font;
curx=startx; // cursor
for(i=0;i<strlen(lineoftext);i++) // get each letter in the string
{
ascii=lineoftext[i];
a=ascii * 13; // calculate the address of the character
width = sans_serif_font[a] & 0x000000FF; // mask out the height
for(y=0;y<height;y++) // one row at a time
{
font=sans_serif_font[a+y+1]; // get the font long
for(x=0;x<width;x++) // do each pixel
{
if((font & 0x00000001) == 1) // test if a 1
{
gray_pixel(screen,curx+(width-1-x),starty+y,0x00);
}
font = font >> 1; // shift in the next bit
}
}
curx += width; // move cursor along by width amount
}
return curx-startx; // return the width of all the text
}
void gray_debug_hex(unsigned long screen[],unsigned long hexnumber) // print a debug hex value on the screen at x=10, y=200
{
int i,j;
char lineoftext[20];
for(j=0;j<12;j++)
{
for(i=4000;i<4006;i++) // clear the previous text
{
screen[i+(20*j)]=0xaaaaaaaa; // light gray
//screen[i+(20*j)]=0xffffffff; // white
}
}
strcpy(lineoftext,hex(hexnumber));
gray_printf(screen,10,200,lineoftext);
}
void gray_debug_dec(unsigned long screen[],unsigned long decnumber) // print a debug decimal value on the screen at x=10, y=212
{
int i,j;
char lineoftext[20];
for(j=0;j<12;j++)
{
for(i=4240;i<4246;i++) // clear the previous text
{
screen[i+(20*j)]=0xaaaaaaaa; // light gray
//screen[i+(20*j)]=0xffffffff; // white
}
}
strcpy(lineoftext,str(decnumber));
gray_printf(screen,10,212,lineoftext);
}
void gray_horizontal_line(unsigned long screen[], int startx, int starty, int sizex, char color)
{
int col;
for(col=startx;col <= startx+sizex ;col++)
{
gray_pixel(screen,col,starty,color); // horizontal line
}
}
void gray_vertical_line(unsigned long screen[], int startx, int starty, int sizey, char color)
{
int row;
for(row=starty;row <= starty+sizey;row++)
{
gray_pixel(screen,startx,row,color); // vertical line
}
}
void gray_box_fill(unsigned long screen[], int startx, int starty, int sizex, int sizey, char color)
{
int row,col;
for(row =starty;row <= starty+sizey; row++)
{
for(col=startx;col <= startx+sizex; col++)
{
gray_pixel(screen,col,row,color); // fill in pixels
}
}
}
void gray_groupbox(unsigned long screen[], int startx, int starty, int sizex, int sizey, char lineoftext[])
{
int textwidth;
gray_horizontal_line(screen,startx,starty,10,0x1); // dark gray horizontal line
gray_horizontal_line(screen,startx+1,starty+1,9,0x3); // white horizontal line
gray_vertical_line(screen,startx,starty,sizey,0x1); // dark gray vertical
gray_vertical_line(screen,startx+1,starty+1,sizey-1,0x3); // white vertical
gray_horizontal_line(screen,startx,starty+sizey,sizex,0x1); // dark gray horizontal line
gray_horizontal_line(screen,startx,starty+sizey+1,sizex+1,0x3); // white horizontal line
gray_vertical_line(screen,startx+sizex,starty,sizey,0x1); // dark gray vertical
gray_vertical_line(screen,startx+sizex+1,starty,sizey,0x3); // white vertical
textwidth = gray_printf(screen, startx+14,starty-4,lineoftext); // print the frame title
gray_horizontal_line(screen,startx+18+textwidth,starty,sizex-textwidth-18,0x1); // dark gray horizontal line
gray_horizontal_line(screen,startx+18+textwidth,starty+1,sizex-textwidth-19,0x3); // white horizontal line
}
void gray_button(unsigned long screen[],int startx, int starty, int sizex, int sizey, char lineoftext[])
{
gray_vertical_line(screen, startx, starty, sizey, 0x3); // white vertical line
gray_horizontal_line(screen, startx, starty, sizex, 0x3); // white horizontal line
gray_vertical_line(screen, startx+sizex, starty+1, sizey-1, 0x1); // vertical dark gray line
gray_horizontal_line(screen, startx+1, starty+sizey, sizex, 0x1); // horizontal dark gray line
gray_vertical_line(screen, startx+sizex+1, starty, sizey+1, 0x0); // vertical black line
gray_horizontal_line(screen, startx, starty+sizey+1, sizex+1, 0x0); // horizontal black line
gray_printf(screen,startx+4,starty+4,lineoftext); // print the button text
}
void gray_text(unsigned long screen[], int startx, int starty, int sizex, int sizey, char lineoftext[])
{
gray_box_fill(screen, startx+1, starty+1, sizex-2, sizey-2,0x3); // white centre
gray_vertical_line(screen, startx, starty, sizey-1, 0x0); // black vertical line
gray_horizontal_line(screen, startx, starty, sizex-1, 0x0); // black horizontal line
gray_vertical_line(screen, startx+sizex, starty+1, sizey,0x2); // vertical light gray line
gray_horizontal_line(screen, startx, starty+sizey, sizex, 0x2); // horizontal light gray line
gray_vertical_line(screen, startx-1, starty-1, sizey+1, 0x1); // dark gray vertical line
gray_horizontal_line(screen, startx-1, starty-1, sizex+1, 0x1); // dark gray horizontal line
gray_vertical_line(screen, startx+sizex+1, starty-1, sizey+2, 0x3); // vertical whiteline
gray_horizontal_line(screen, startx-1, starty+sizey+1, sizex+1, 0x3); // horizontal whiteline
gray_printf(screen,startx+2,starty+2,lineoftext); // print the text
}
void gray_radio(unsigned long screen[], int startx, int starty, char check,char lineoftext[])
{
char radio[144] = { // black = 0x0, dark gray = 0x1, light gray = 0x2, white = 0x3
0x2,0x2,0x2,0x2,0x1,0x1,0x1,0x1,0x2,0x2,0x2,0x2, // a radio button
0x2,0x2,0x1,0x1,0x0,0x0,0x0,0x0,0x1,0x1,0x2,0x2,
0x2,0x1,0x0,0x0,0x3,0x3,0x3,0x3,0x0,0x0,0x3,0x2,
0x2,0x1,0x0,0x3,0x3,0x3,0x3,0x3,0x3,0x2,0x3,0x2,
0x1,0x0,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x2,0x3,
0x1,0x0,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x2,0x3,
0x1,0x0,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x2,0x3,
0x1,0x0,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x2,0x3,
0x2,0x1,0x0,0x3,0x3,0x3,0x3,0x3,0x3,0x2,0x3,0x2,
0x2,0x1,0x2,0x2,0x3,0x3,0x3,0x3,0x2,0x2,0x3,0x2,
0x2,0x2,0x3,0x3,0x2,0x2,0x2,0x2,0x3,0x3,0x2,0x2,
0x2,0x2,0x2,0x2,0x3,0x3,0x3,0x3,0x2,0x2,0x2,0x2
};
int x;
int y;
int i = 0;
if(check !=0)
{
radio[53]=radio[54]=0x00;
radio[64]=radio[65]=radio[66]=radio[67]=0x00; // draw the circle in the middle
radio[76]=radio[77]=radio[78]=radio[79]=0x00;
radio[89]=radio[90]=0x00;
}
for(y=0;y<12;y++)
{
for(x=0;x<12;x++)
{
gray_pixel(screen,startx+x, starty+y, radio[i]); // draw a radio button, white centre
i++;
}
}
gray_printf(screen,startx+16,starty,lineoftext); // print the text
}
void gray_mousepointer(unsigned long screen[],unsigned long mousebuffer[],int x, int y) // 21 high, 13 wide = 1 long wide
{
// mousebuffer 0-41 is the screen to restore, 42 is 0 for startup, 1 for redraw, 43 = oldx, 44=oldy
int i,j,n,m,r,s;
unsigned long pixels;
if (mousebuffer[42] ==1) // restore. Skip first time if is zero
{
m=(mousebuffer[44]*20)+(mousebuffer[43]/16); // oldy and oldx
for(i=0;i<21;i++) // store the longs behind the mouse
{
screen[m]=mousebuffer[i];
screen[m+1]=mousebuffer[i+21];
m = m+20;
}
}
mousebuffer[42] = 1; // always restore from now on
mousebuffer[43]=x; // store current x
mousebuffer[44]=y;
n=0;
m=(y*20)+(x/16); // get the screen long - 20 longs per row
r=x%16; // work out the bitshift remainder - 16 pixels per long
//gray_debug_dec(screen,r);
for(i=0;i<21;i++) // store the longs behind the mouse
{
mousebuffer[i]=screen[m];
mousebuffer[i+21]=screen[m+1];
m = m+20;
}
m=(y*20)+(x/16); // recalculate m
if (r==0) // no remainder so fits exactly in a long
{
for (i=0;i<21;i++) // rows
{
{
screen[m] = screen[m] & mouse_mask[n]; // mask out pixel bits, ignore transparent bits
screen[m] = screen[m] | mouse_icon[n]; // draw the icon
n++;
}
m = m+20; // next row
}
}
else
// bitshift so fits
{
s=r<<1; // multiply by 2
for (i=0;i<21;i++) // rows
{
{
// move mask and icon value into pixels. Shift. Leave bits on left as 11 for mask(transparent) and 00 for icon
// note also the order is reversed so shifts to the left move bits to the right. Very confusing!
pixels = mouse_mask[n] << s; // shift s=2 to 30 step 2
pixels = pixels | (0xffffffff >> (32-s)); // leave in transparent bits
screen[m] = screen[m] & pixels; // mask out pixel bits, ignore transparent bits
pixels = mouse_mask[n] >> (32-s); // shift in next long to the right
pixels = pixels | (0xffffffff << s);
screen[m+1] = screen[m+1] & pixels; // finished drawing the mask, now the icon
pixels = mouse_icon[n] << s; // shift s=2 to 30 step 2
screen[m] = screen[m] | pixels; // mask out pixel bits, ignore transparent bits
pixels = mouse_icon[n] >> (32-s); // shift in next long to the right
screen[m+1] = screen[m+1] | pixels;
n++;
}
m = m+20; // next row
}
}
}
void gray_clearscreen(unsigned long screen[])
{
int i;
for (i=0;i<4800;i++)
{
screen[i] = 0xaaaaaaaa; // fill with light gray, use longs rather than bytes so 4 pixels per loop
}
}
void gray_engine_start(int cognumber, unsigned long cogarray[], unsigned long screen[], unsigned long gray_parameters[])
{
unsigned long pingroup = 2; // pins 16 to 23
int i;
unsigned long frequencystate;
gray_parameters[0] = 0xfca85400; // pixelcolors in reverse order
gray_parameters[1] = 1; // displayindicator
gray_parameters[2] = 0; // syncindicator
gray_parameters[3] = 2; // bitsperpixel, starts at 2 but gets changed later to 1
screen[0] = (unsigned long) &screen[0]; // the first long in the screen array now points to the location of itself
screen[1] = (unsigned long) &gray_parameters[1]; // pointer to displayindicator
screen[2] = (unsigned long) &gray_parameters[2]; // pointer to syncindicator
screen[3] = (0xff << (8*pingroup));
screen[4] = (0x200000ff | (pingroup << 9) | ((gray_parameters[3] -1) << 28)); // (0x200000ff | (pingroup << 9) | ((bitsperpixel-1) << 28)); this one not working
gray_parameters[3] = gray_parameters[3] - 1; // bitsperpixel now equal to 1, used below
frequencystate = ((25175000 + 1600) / 4); // calculate frequencystate
screen[5] = 1;
for(i=0;i<32;i++)
{
frequencystate = frequencystate << 1;
screen[5] = (screen[5] << 1) | (screen[5] >> 31);
if (frequencystate >= _clockfreq())
{
frequencystate -= _clockfreq();
screen[5] += 1;
}
}
screen[6] = 2; // horizontal scaling
screen[7] = 2; // vertical scaling
screen[8] = 320; // horizontal pixels
screen[9] = 240; // vertical pixels
screen[10] = ((screen[6] << 12) + (((640 * 32) >> gray_parameters[3] ) / screen[8])); // visible scale
screen[11] = (((8 << gray_parameters[3] ) << 12) + 160); // invisible scale
screen[12] = (screen[8] / (32 >> gray_parameters[3] )); // horizongal longs
screen[13] = screen[12] * 4; // horizontal loops
screen[14] = (unsigned long) &gray_parameters[0]; // pixel colors
_cogstop(cognumber); // stop graphics cog
external_memory_cog_load(cognumber,cogarray,screen); // load from external ram to this cog, pass some values in screen[]
gray_clearscreen(screen);
}
void gray_demo(unsigned long screen[], unsigned long mousebuffer[], unsigned long gray_parameters[],unsigned long mouse_parameters[], int cognumber)
{
unsigned long oldx,oldy = 1; // previous mouse pointers, set to anything except 0 so draws the mouse on startup
gray_engine_start(cognumber,cogject_gray,screen,gray_parameters);
gray_debug_hex(screen,m_present()); // is the mouse present?
gray_printf(screen, 8,8,"File Edit Program"); // print menu text on the screen
gray_button(screen, 10, 40,50,19,"Button1"); // a button
gray_button(screen, 100,40,50,19,"Button2"); // a button
gray_text(screen, 10, 70, 70,16, "Textbox1"); // a text box
gray_text(screen, 100,70, 70,16, "Textbox2"); // a text box
gray_radio(screen, 10,100,1,"Radio1"); // a checked radio button
gray_radio(screen, 10,120,0,"Radio2"); // an unchecked radio button
gray_groupbox(screen,140,110,100,85,"GroupBox1"); // draw groupbox
gray_printf(screen, 150,125,"Label1"); // print text on the screen
gray_printf(screen, 150,145,"Label2"); // print text on the screen
gray_printf(screen, 150,165,"Label3"); // print text on the screen
gray_printf(screen,10,186,"Debug value");
// gray_debug_hex(screen,123456); // print a debug hex value on the screen at 10,200
// gray_debug_dec(screen,123456);
// gray_mousepointer(screen,mousebuffer,21,45); // print a mouse pointer
// gray_mousepointer(screen,mousebuffer,25,48); // move the mouse pointer
while(1)
{
if ((oldx != mouse_parameters[0]) | (oldy != mouse_parameters[1]))
{
gray_mousepointer(screen,mousebuffer,mouse_parameters[0]+160,120 - mouse_parameters[1]); // start in middle of screen
//gray_debug_hex(screen,mouse_parameters[0]); // print the value
oldx = mouse_parameters[0]; // store the previous value
oldy = mouse_parameters[1];
}
}
}
void mouse_engine_start(int cognumber, unsigned long cogarray[], unsigned long mouse_parameters[], int dpin, int cpin)
{
mouse_parameters[0] = (unsigned long) &mouse_parameters[0]; // the first long of the array points to the location of the array itself
mouse_parameters[5] = (unsigned long) dpin; // data pin
mouse_parameters[6] = (unsigned long) cpin;
_cogstop(cognumber); // stop this cog
external_memory_cog_load(cognumber,cogarray,mouse_parameters); // load from external ram to this cog, pass location of the array
mouse_parameters[7] = 0; // xmin
mouse_parameters[8] = 0; // ymin
mouse_parameters[9] = 0; // zmin
mouse_parameters[10] = 319; // xmax
mouse_parameters[11] = 239; // ymax
mouse_parameters[12] = 0; // zmax
}
void main ()
{
char color_parameters[1]; // displayindicator and syncindicater are permanent hub variables
unsigned long screen[4800]; // graphics and text video buffer in hub - eg 19200 bytes = 4800 longs
unsigned long gray_parameters[4]; // permanent hub variables for the gray 320x240 driver
unsigned long mousebuffer[45]; // pixels behind the mouse cursor 42 longs then some data
unsigned long mouse_parameters[19]; // group of 7 plus 12 longs in par_x in the spin version
int i;
mousebuffer[42] = 0; // mouse 0 if startup, 1 if redraw
//m_bound_limits(0,300,0,0,220,0); // set the mouse limits
text_clearscreen(); // white on blue vga clearscreen
printf("Clock speed %u \n",_clockfreq()); // see page 28 of the propeller manual for other useful commands
printf("Catalina running in cog number %i \n",_cogid()); // integer
printf("Read vga color cogject into external ram array cogject_color\n");
readcog("vgagraph.cog",cogject_color); // read in kye's graphics driver
printf("Read vga gray cogject into external ram array cogject_gray\n");
readcog("vga320.cog",cogject_gray);
printf("Read mouse cogject into external ram array cogject_mouse\n");
readcog("mouse.cog",cogject_mouse);
mouse_engine_start(7, cogject_mouse, mouse_parameters, 24, 25); // start the mouse driver
printf("Finished reading cogjects into external ram \n");
_cogstop(3); // stop cog 3 = one of the two default graphics cogs
color_demo(screen,color_parameters,1); // start in cog 1 (stops cog 1 prior to restarting)
sleep(1000); // so can see it
gray_demo(screen, mousebuffer, gray_parameters, mouse_parameters, 1); // gray screen demo in cog 1
while (1); // endless loop as prop reboots on exit from main()
}
RossH:
By saying 'it is not fully ANSI C' I am referring to the source of Catalina that I have looked at, some of the extensions seem to be gcc style extensions. And my point in saying this is that Catalina can not be ported to every possible platform that has a C compiler with out first porting a different C compiler.
Hi David,
Catalina has no non-ANSI extensions. As for porting to another platform, it is not the C compiler that will constrain you, it is the availability of a PASM assembler. What platform did you have in mind?
RossH:
If Catalina will run well in not to much XMM, I think even that could be useful, assuming that the XMM driver can be easily modified by the user to use a variety of different memories, as not every one is going to have the same preferences, and many are likely to be adding there own memory to a board that comes with none.
Hi David,
Yes, at one stage I thought this would be true as well. But it turns out that almost no-one outside these forums (and very few within them) uses XMM to extend the memory capacity of the Propeller - so the number of potential users of a native Catalina compiler is fairly close to zero.
However, if someone ever does write a fully functional SPIN/PASM compiler that runs natively on the Propeller (Sphinx is too limited), I may do it just for fun - porting the Catalina compiler and linker is a fairly simple exercise.
Amiga 68K, Atari TT/Falcon (with out MiNT), Haiku OS, Amiga PowerPC, AROS, Minix, FreeDOS, MrOS, Symbian, and the other commonly used OSes that do not have any prop development tools, as well as the Prop.
Back coding now. I thought I would tackle the graphical mouse next, mainly so I could answer the question as to whether Catalina is fast enough to draw and refresh a 273 pixel mouse pointer in real time. And the good news is that it can!
This code is not fully debugged - the bounds checking is not working so the mouse goes a bit haywire at the edges of the screen.
It also demonstrates loading in another cogject (this program is now using 3 cogjects). I'm not sure if there is a "right" or "wrong" method in terms of plugins vs cogjects and I guess I would like to see both methods available for use. What is nice though is to be able to use the same cogject for a spin program and a C program.
There is not really a "right" or "wrong" way. I would like to encourage the use of plugins because it will make it much simpler for others to follow in your footsteps - but it may indeed make your job slightly harder!
I have found that the sd card driver in Catalina is a little slow compared with Kye's SD driver. For the moment, the optimum speed solution is to load all cogjects into XMM at bootup, as it is faster to load a cogject from XMM into a cog than it is to load from SD into cog. That could change down the track.
Yes, I'm aware of this one. It's on my list of things to do at some point. It may even be possible to do a fairly simple drop in replacement - if someone else wants to look a this, feel free to do so!
Amiga 68K, Atari TT/Falcon (with out MiNT), Haiku OS, Amiga PowerPC, AROS, Minix, FreeDOS, MrOS, Symbian, and the other commonly used OSes that do not have any prop development tools, as well as the Prop.
Hi David,
Your first step to adding Propeller support to any platform is porting a PASM assembler. You can live without a SPIN compiler when compiling Catalina XMM programs since the current reconfigurable SPIN targets can be entirely replaced by a set of precompiled binary targets specific to each target Propeller platform - but you can't get by without a PASM assembler since Catalina generates PASM as output.
If you don't have an ANSI C compiler on your platform, then the next step is to port a self-hosted C compiler (remember, Catalina is a cross-compiler) - but that compiler can be LCC itself (which can be either). Compiler bootstrapping techniques are described here: http://en.wikipedia.org/wiki/Bootstrapping_%28compilers%29 - but the cost of doing this for each specific platform is going to be high, and would normally only be contemplated by a vendor (who expects to recoup the cost by selling product).
The final (and easiest!) step is porting Catalina itself. This is simply a matter of compiling it using the self-hosted C compiler. Catalina currently compiles with gcc, but I have in the past compiled it with lcc, and it should compile correctly with any ANSI C compiler.
Sphinx does work on a single Prop with an SD card, keyboard, and TV display. It can compile itself and, like other Prop Tools, includes an assembler. There's also a simple compiler-compiler called Meta2 which is optimized to produce Spin source and compiles itself using Sphinx. Meta2 was used many years ago to bootstrap an AlgolW compiler for the PDP-10 and a Pascal compiler for the Datapoint 5500.
Issues include the lack of a good editor for the Prop (there's a minimal one that's part of Sphinx), the limitations of a TV display, and tight memory constraints for the Prop. A two Prop system could be used to offload the I/O including a reasonably wide VGA display yet not impacting the available memory for the compiler. There are 64 and 80 column TV drivers available as well that could be used in an I/O Prop. The various tables (like the symbol table) could be kept on the SD card with caching used to reduce the speed impact of not keeping them resident.
C could probably be bootstrapped through such a system, maybe producing Spin bytecodes initially, then later using a customized Spin interpreter that might use some LMM and some native overlays for speed.
Porting Catalina to the Prop by cross compiling does have a lot of advantages since you can produce LMM and XMM programs. It would be a preferred path for use with the Prop II because of the increased native memory and better support for external memory.
Sphinx does work on a single Prop with an SD card, keyboard, and TV display. It can compile itself and, like other Prop Tools, includes an assembler. There's also a simple compiler-compiler called Meta2 which is optimized to produce Spin source and compiles itself using Sphinx. Meta2 was used many years ago to bootstrap an AlgolW compiler for the PDP-10 and a Pascal compiler for the Datapoint 5500.
Issues include the lack of a good editor for the Prop (there's a minimal one that's part of Sphinx), the limitations of a TV display, and tight memory constraints for the Prop. A two Prop system could be used to offload the I/O including a reasonably wide VGA display yet not impacting the available memory for the compiler. There are 64 and 80 column TV drivers available as well that could be used in an I/O Prop. The various tables (like the symbol table) could be kept on the SD card with caching used to reduce the speed impact of not keeping them resident.
C could probably be bootstrapped through such a system, maybe producing Spin bytecodes initially, then later using a customized Spin interpreter that might use some LMM and some native overlays for speed.
Sphinx does work on a single Prop with an SD card, keyboard, and TV display. It can compile itself and, like other Prop Tools, includes an assembler.
...
C could probably be bootstrapped through such a system, maybe producing Spin bytecodes initially, then later using a customized Spin interpreter that might use some LMM and some native overlays for speed.
Hi Mike,
True. However, while I haven't looked at Sphinx recently, the early versions were way too limited (size-wise). Compiling a C program to PASM, and then using Sphinx to compile the PASM would be fairly certain to blow Sphinx's capacity just on the C symbol table alone - compilers tend to generate many more symbols than the equivalent hand-coded PASM would need.
From memory you need 64 characters for the name of each symbol to conform to the ANSI C standard (not to mention whatever other data you need to store about each symbol, such as its type and value). This means in 32k you could never have more than a few hundred symbols. But a compiler typically generates dozens of symbols for each C function, so you would probably find yourself runing out of memory space after defining just a few functions.
In the very early versions of Catalina I used the Parallax compiler as my PASM compiler, but I very quickly ran into all sorts of limits like this and had to move to a SPIN/PASM compiler with larger capacity. Thank goodness for bst and Homespun!
But an LMM version of Sphinx would probably overcome this particular problem - any volunteers?
From memory you need 64 characters for the name of each symbol to conform to the ANSI C standard
Has ANSI C changed since I last read up on it??
ANSI C only requires that the first 6 characters of a symbol be significant, ANSI C does not include the '//' remark symbol (although most compilers due), and ANSI C does not require any libs beyond stdio (even though it does RECOMMEND others), as such not all ANSI C compilers provide all the recommended libs. And I am aware that ANSI C does RECOMMEND (though NOT require) that internal symbols be handled with the first 32 characters significant. As to types, these should not show up as symbols in assembly. Though I do thank you for your recommendations on compiling Catalina on other platforms.
RossH,
Meta2 has its own symbol table so it can keep various attributes of the symbols around to control compilation. Typically, the output uses generated symbols or the meta-compiler does its own storage allocation for data variables and those symbols never make it into the generated Spin code. The current version uses a 32K section of a 128K EEPROM for the symbol table. Each entry is rarely changed once written, so a compilation doesn't have much effect on EEPROM wear-out.
Has ANSI C changed since I last read up on it??
ANSI C only requires that the first 6 characters of a symbol be significant, ANSI C does not include the '//' remark symbol (although most compilers due), and ANSI C does not require any libs beyond stdio (even though it does RECOMMEND others), as such not all ANSI C compilers provide all the recommended libs. And I am aware that ANSI C does RECOMMEND (though NOT require) that internal symbols be handled with the first 32 characters significant. As to types, these should not show up as symbols in assembly. Though I do thank you for your recommendations on compiling Catalina on other platforms.
Hi David,
I think you'll find it has changed quite a lot. C89 standardized many things, and C99 extended the standard a little more. I shouldn't really say "ANSI C" without being more specific, but it is a convenient shorthand that seems to be generally understood.
ANSI C now allows 6 characters is for external identifiers only. it requires a minimum of 32 characters for internal identifiers. However, since the Propeller assembler is not case sensitive (but C identifiers are) it turns out you need up to 64 characters to represent each C identifer in PASM.
ANSI C includes the // in C99 - but it is a common extension for C89 compilers to include it as well.
ANSI C requires a full suite of libraries in addition to stdio - the minimum C89 set also includes assert, ctype, errno, float, locale, math, stdlib, stdarg, string, time, setjmp, signal & stddef. C99 adds a few more, some of which are included with Catalina (but Catalina is really only C89 compliant).
It's true that types will not appear in the final assembly code, but they certainly appear in the symbol table, along with all the other symbols that need to be tracked during a compilation, such as variables, functions & labels. These may be user or compiler generated, and in some cases (particularly labels) the compiler will typically generate many, many more of them than the user ever defines (this is where I ran into problems with the Parallax tools!). Also, types will appear in the debugger output that is associated with the program, since the debugger needs to know about them.
RossH:
Thank you. I am familiar with the rules laid down in C89, while I am aware of C99, I did not realize that it changed that much.
A couple of thoughts:
With the prop assemblers net being case sensitive, would it not be more efficient to compile directly to binary? Also is there a reason to use a multi-pass compiler for the prop, does optimization provided in this way actually make a difference on the Propeller?
Perhaps a K&R C subset Catalina compiler is in order (with the extensions on function declaration, and void)?
RossH,
Meta2 has its own symbol table so it can keep various attributes of the symbols around to control compilation. Typically, the output uses generated symbols or the meta-compiler does its own storage allocation for data variables and those symbols never make it into the generated Spin code. The current version uses a 32K section of a 128K EEPROM for the symbol table. Each entry is rarely changed once written, so a compilation doesn't have much effect on EEPROM wear-out.
Hi Mike,
Intriguing - I'll have to check it out. You say Meta2 can compile itself using Sphinx, but I'm not sure if that means that you are guaranteed that the output of Meta2 will aways be compilable with Sphinx. I know Sphinx does not implement the full SPIN language, but I'm not really sure just how much of Spin you would have to avoid (or how you would do so) when using Meta2 to generate the Spin code. Is this likely to be a problem?
With the prop assemblers net being case sensitive, would it not be more efficient to compile directly to binary?
Not really - not unless you also want to define your own object format and also write your own binary linker. Catalina sidesteps all these issues quite neatly by binding the program components together at the source level rather than the binary level. This saves a heck of a lot of work.
Also is there a reason to use a multi-pass compiler for the prop, does optimization provided in this way actually make a difference on the Propeller?
Yes it does. Without the kind of optimization a multi-pass compiler can easily do, I'd estimate the code size would go up by 50% - possibly more in some cases. Catalina could really do with more optimization, not less!
Perhaps a K&R C subset Catalina compiler is in order (with the extensions on function declaration, and void)?
Please, no! It took 20 years to get C into reasonable shape - who'd want to go back to the days where every C compiler you ever used was slightly different?
Comments
I guess one could compile Catalina with Catalina on a PC resulting in a Catalina that will run on the Prop.
Provided the Prop has a big enough external RAM and file store to run it.
I also guess bootstrapping a native Catalina like that is not so easy. I believe RossH already this idea in mind.
Yes, very early on I compiled Catalina with Catalina and produced a compiler that would run on the Prop. The trouble is that there was no point in going any further - for three reasons:
1. Insufficient RAM on any Prop plaform. I can't recall how big the result was, but it was certainly too large for any platform I had at the time. Maybe now that we have boards with 32Mb RAM we might be able to run it.
2. Catalina requires a PASM assembler, and (again, at the time) there was no assembler that could run on the Propeller. Maybe now that we have Sphinx this might be possible.
3. Although everybody says they would like to see this, nobody actually has any practical use for it!
Ross.
So 32k is insufficient, even though many ANSI C compilers have been made that can run in 12K or less with out overlays and without accessing external storage. You definitely have me wondering about how a C compiler could so big (even with the LMM stuff), I guess I am going to be looking at the source very closely.
And as for a Practical use; How about developing a true Propeller computer, or not being tied to Linux or Windoze to use it with out a lot of work in porting it? It is not fully ANSI C from the little bit of code that I have already browsed, and GCC is not as universal as they would like to be.
I will try to track down one or more of these old compilers for you (I no longer have a 5.25 inch floppy drive). Many of them did not include support for wide string libs, also many of them relied on the program not having to many dependencies on static Libs, though they still fit in 12k (plus 4KB to 8KB for the source file plus 2KB to 8KB for the generated binary), and were 100% ANSI compliant. They did this by using a single pass compiler that directly generated binary executable object or linkable object code, if they needed to do any linking other than the standard lib this did require access to mass storage (of course), and they did not support inline assembly (which is not part of the standard anyway).
Thanks! I'll be looking forward to seeing one of these. I know there were small C compilers back in the early micro days. Certainly there was Small C but I don't think it fit in 14k. It is more likely that BDS C would fit in that much memory but I think it was multi-pass and was written in assembly language and it was not an ANSI C compiler since the ANSI standard didn't exist back then. I'm sure there are many others that I am not familiar with.
http://floppysoftware.vacau.com/c_compilers.html
I think this page may interest you, it does not fully answer the question (though many of these came close to ANSI C before the standard existed). I wish I could remember the names of some of those early ANSI C compilers, they were truly works of eloquence (in the mathematical since of eloquence), very small and efficient.
http://compilers.iecc.com/crenshaw/
I think the misunderstanding here is that instead of "Catalina runs on any propeller' it should perhaps be reworded "Programs compiled with Catalina run on any propeller".
However, having said that, it is possible to compile C programs on a propeller that have been written totally on the propeller. This has been done within the CP/M emulation, with the program written in Wordstar and compiled using BDSC. It does work, but it is slow (several minutes to compile "Hello World"). Having used this, I think that the hard part may not be the compiler, but rather the text editor.
Thank you. I supose that a good text editor would be difficult to implement in this space, though a simple screen editor based text file editor should do, or maybe a COPY CON, ECHO >, or EDLIN style editor . Has any one attempted a full blown text editor on the prop yet??? It would not have to run at the same time as the compiler, which in turn would not have to run at the same time as the linker.
Hi David,
Sorry if I misled you. As Dr_A points out, I should have said "Catalina can compile programs that can run on any Propeller" - my mistake!
However, I don't think you will find an ANSI C compiler that can run in 12k. You may be thinking of the original Tiny C - this program had a code size under 12k (on x86), but it implemented only a small fraction of the original C language (which is in turn smaller than the current ANSI C).
In any case, even if a C compiler had a code size of 12k (and for various reasons I will go into later, the code size would be much larger than that on the Prop), you still need more space than that to actually compile anything - e.g. to store the symbol table. Exactly how much space you need depends on the program being compiled, but you aren't going to be able to compile much in the way of non-trivial programs in only 32kb of non-virtual, non-overlaid memory.
I believe ANSI C compilers would take more like hundreds of kb of code size, plus whatever data size is required for the program being compiled. The smallest C compiler I know of is probably the current version of the original Tiny C compiler (http://bellard.org/tcc/) - this claims to be ANSI compliant, but weighs in with a code size of around 100kb (on x86). But again you need more memory than that to actually compile anything - although perhaps not much more since it claims to be single-pass.
Another thing to remember is that these compilers all run under an operating system - i.e. they do not need to carry around their own file system and SD card drivers just to be able to read the C source! A propeller compiler has to do all that and more. Out of interest, I just used Catalina to compile the original version of the Tiny C compiler (remember it has a code size of 12k on x86) and its size on the Propeller (including all the file system and I/O drivers necessary to run it) ends up with a code size of 66k! And this for a compiler that implements only a fraction of ANSI C. I didn't try compiling the current version of Tiny C, but my guess would be it would end up with a code size of at least 300k on the Propeller.
And it gets worse, of course - very few modern compilers are single pass, because such compilers offer little or no opportunity for code optimization. I don't know what the code produced by Tiny C is like, but it is probably terribly inefficient. Most C compilers are multi-pass to allow for useful things like register optimization, common sub-expression re-use and dead code elimination. Even LCC has fairly sophisticated capabilities in this area. But with a multi-pass compiler you also need to store the intermediate parse trees - and this needs quite a lot of additional memory space for a non-trivial program.
From memory, I think I figured out that LCC would require something like 3 to 4Mb to compile itself from C down to PASM on the Propeller - and even if it could, there is currently no assembler that can run on the Prop capable of assembling that PASM into a final binary.
Ross.
Hi David,
Catalyst (Catalina's SD card loader) comes with a version of the vi text editor.
Ross.
I'm not sure what you mean here. Do you mean a Propeller-based operating system? There are several groups working on one - search these forums and you'll find several ongoing projects (plus lots of idle speculations about porting linux etc).
As to being "not fully ANSI C" - what are you referring to? LCC itself is certainly ANSI C, and so is the Catalina back-end code generator. So are the Catalina libraries. But of course the Propeller run-time support package is not, since that would presume the existence of an ANSI compliant C compiler and associated run-time support package (chicken, meet egg!).
Ross.
By saying 'it is not fully ANSI C' I am referring to the source of Catalina that I have looked at, some of the extensions seem to be gcc style extensions. And my point in saying this is that Catalina can not be ported to every possible platform that has a C compiler with out first porting a different C compiler.
If Catalina will run well in not to much XMM, I think even that could be useful, assuming that the XMM driver can be easily modified by the user to use a variety of different memories, as not every one is going to have the same preferences, and many are likely to be adding there own memory to a board that comes with none.
Back coding now. I thought I would tackle the graphical mouse next, mainly so I could answer the question as to whether Catalina is fast enough to draw and refresh a 273 pixel mouse pointer in real time. And the good news is that it can!
At the moment I'm redrawing the mouse pointer from external ram but it probably would be faster again if the array was in hub ram.
This code is not fully debugged - the bounds checking is not working so the mouse goes a bit haywire at the edges of the screen.
It also demonstrates loading in another cogject (this program is now using 3 cogjects). I'm not sure if there is a "right" or "wrong" method in terms of plugins vs cogjects and I guess I would like to see both methods available for use. What is nice though is to be able to use the same cogject for a spin program and a C program.
I have found that the sd card driver in Catalina is a little slow compared with Kye's SD driver. For the moment, the optimum speed solution is to load all cogjects into XMM at bootup, as it is faster to load a cogject from XMM into a cog than it is to load from SD into cog. That could change down the track.
At the moment it boots up, displays some text messages on the Catalina VGA text driver, then shuts down cogs 1 and 3, reuses cog 1 for two other VGA displays and puts the mouse in cog 7. This leaves cog 3 free.
I am starting to see some real advantages to coding in a way that reuses cogs over and over. Want to do some floating point math and no cogs left? Simply overwrite the mouse cog with the floating point code, do the sums, then reload the mouse.
Next step is to click on a button and redraw the button as a "clicked" button. Then it is time to tackle text boxes, which end up being de-facto word processors.
Hi David,
Catalina has no non-ANSI extensions. As for porting to another platform, it is not the C compiler that will constrain you, it is the availability of a PASM assembler. What platform did you have in mind?
Ross.
Hi David,
Yes, at one stage I thought this would be true as well. But it turns out that almost no-one outside these forums (and very few within them) uses XMM to extend the memory capacity of the Propeller - so the number of potential users of a native Catalina compiler is fairly close to zero.
However, if someone ever does write a fully functional SPIN/PASM compiler that runs natively on the Propeller (Sphinx is too limited), I may do it just for fun - porting the Catalina compiler and linker is a fairly simple exercise.
Ross.
Yes, I'm aware of this one. It's on my list of things to do at some point. It may even be possible to do a fairly simple drop in replacement - if someone else wants to look a this, feel free to do so!
Ross.
Hi David,
Your first step to adding Propeller support to any platform is porting a PASM assembler. You can live without a SPIN compiler when compiling Catalina XMM programs since the current reconfigurable SPIN targets can be entirely replaced by a set of precompiled binary targets specific to each target Propeller platform - but you can't get by without a PASM assembler since Catalina generates PASM as output.
If you don't have an ANSI C compiler on your platform, then the next step is to port a self-hosted C compiler (remember, Catalina is a cross-compiler) - but that compiler can be LCC itself (which can be either). Compiler bootstrapping techniques are described here: http://en.wikipedia.org/wiki/Bootstrapping_%28compilers%29 - but the cost of doing this for each specific platform is going to be high, and would normally only be contemplated by a vendor (who expects to recoup the cost by selling product).
The final (and easiest!) step is porting Catalina itself. This is simply a matter of compiling it using the self-hosted C compiler. Catalina currently compiles with gcc, but I have in the past compiled it with lcc, and it should compile correctly with any ANSI C compiler.
Ross.
Issues include the lack of a good editor for the Prop (there's a minimal one that's part of Sphinx), the limitations of a TV display, and tight memory constraints for the Prop. A two Prop system could be used to offload the I/O including a reasonably wide VGA display yet not impacting the available memory for the compiler. There are 64 and 80 column TV drivers available as well that could be used in an I/O Prop. The various tables (like the symbol table) could be kept on the SD card with caching used to reduce the speed impact of not keeping them resident.
C could probably be bootstrapped through such a system, maybe producing Spin bytecodes initially, then later using a customized Spin interpreter that might use some LMM and some native overlays for speed.
Porting Catalina to the Prop by cross compiling does have a lot of advantages since you can produce LMM and XMM programs. It would be a preferred path for use with the Prop II because of the increased native memory and better support for external memory.
Issues include the lack of a good editor for the Prop (there's a minimal one that's part of Sphinx), the limitations of a TV display, and tight memory constraints for the Prop. A two Prop system could be used to offload the I/O including a reasonably wide VGA display yet not impacting the available memory for the compiler. There are 64 and 80 column TV drivers available as well that could be used in an I/O Prop. The various tables (like the symbol table) could be kept on the SD card with caching used to reduce the speed impact of not keeping them resident.
C could probably be bootstrapped through such a system, maybe producing Spin bytecodes initially, then later using a customized Spin interpreter that might use some LMM and some native overlays for speed.
Hi Mike,
True. However, while I haven't looked at Sphinx recently, the early versions were way too limited (size-wise). Compiling a C program to PASM, and then using Sphinx to compile the PASM would be fairly certain to blow Sphinx's capacity just on the C symbol table alone - compilers tend to generate many more symbols than the equivalent hand-coded PASM would need.
From memory you need 64 characters for the name of each symbol to conform to the ANSI C standard (not to mention whatever other data you need to store about each symbol, such as its type and value). This means in 32k you could never have more than a few hundred symbols. But a compiler typically generates dozens of symbols for each C function, so you would probably find yourself runing out of memory space after defining just a few functions.
In the very early versions of Catalina I used the Parallax compiler as my PASM compiler, but I very quickly ran into all sorts of limits like this and had to move to a SPIN/PASM compiler with larger capacity. Thank goodness for bst and Homespun!
But an LMM version of Sphinx would probably overcome this particular problem - any volunteers?
Ross.
ANSI C only requires that the first 6 characters of a symbol be significant, ANSI C does not include the '//' remark symbol (although most compilers due), and ANSI C does not require any libs beyond stdio (even though it does RECOMMEND others), as such not all ANSI C compilers provide all the recommended libs. And I am aware that ANSI C does RECOMMEND (though NOT require) that internal symbols be handled with the first 32 characters significant. As to types, these should not show up as symbols in assembly. Though I do thank you for your recommendations on compiling Catalina on other platforms.
Meta2 has its own symbol table so it can keep various attributes of the symbols around to control compilation. Typically, the output uses generated symbols or the meta-compiler does its own storage allocation for data variables and those symbols never make it into the generated Spin code. The current version uses a 32K section of a 128K EEPROM for the symbol table. Each entry is rarely changed once written, so a compilation doesn't have much effect on EEPROM wear-out.
Hi David,
I think you'll find it has changed quite a lot. C89 standardized many things, and C99 extended the standard a little more. I shouldn't really say "ANSI C" without being more specific, but it is a convenient shorthand that seems to be generally understood.
ANSI C now allows 6 characters is for external identifiers only. it requires a minimum of 32 characters for internal identifiers. However, since the Propeller assembler is not case sensitive (but C identifiers are) it turns out you need up to 64 characters to represent each C identifer in PASM.
ANSI C includes the // in C99 - but it is a common extension for C89 compilers to include it as well.
ANSI C requires a full suite of libraries in addition to stdio - the minimum C89 set also includes assert, ctype, errno, float, locale, math, stdlib, stdarg, string, time, setjmp, signal & stddef. C99 adds a few more, some of which are included with Catalina (but Catalina is really only C89 compliant).
It's true that types will not appear in the final assembly code, but they certainly appear in the symbol table, along with all the other symbols that need to be tracked during a compilation, such as variables, functions & labels. These may be user or compiler generated, and in some cases (particularly labels) the compiler will typically generate many, many more of them than the user ever defines (this is where I ran into problems with the Parallax tools!). Also, types will appear in the debugger output that is associated with the program, since the debugger needs to know about them.
Ross.
Thank you. I am familiar with the rules laid down in C89, while I am aware of C99, I did not realize that it changed that much.
A couple of thoughts:
With the prop assemblers net being case sensitive, would it not be more efficient to compile directly to binary? Also is there a reason to use a multi-pass compiler for the prop, does optimization provided in this way actually make a difference on the Propeller?
Perhaps a K&R C subset Catalina compiler is in order (with the extensions on function declaration, and void)?
Hi Mike,
Intriguing - I'll have to check it out. You say Meta2 can compile itself using Sphinx, but I'm not sure if that means that you are guaranteed that the output of Meta2 will aways be compilable with Sphinx. I know Sphinx does not implement the full SPIN language, but I'm not really sure just how much of Spin you would have to avoid (or how you would do so) when using Meta2 to generate the Spin code. Is this likely to be a problem?
Ross.
Ross.