I'm sorry. Timesharing the serial line is unreasonable unless it's one of those old style BBS programs. I'm off my game today since I was up all night. It's just curious to me that anyone needs a display on the target during the loader stage in the first place ... updating loader status on the PC should be good enough. It's OK for debugging I guess, and it's your effort so I should be more supportive of that.
I did it for debugging. When I first wrote the helper program it didn't work correctly for quite a while (no surprise!). Having debugging output independent of the serial connection helped me debug it. You're right that there isn't really a need for it once the system is working. I'll put all of the TV stuff under a USE_DEBUG conditional.
I've been slogging away at cleaning up my ZOG toolchain for the C3 and I think I'm making some progress. I now have a PC loader program that builds for Windows (both Win32 and cygwin) and Linux. I suspect getting it to build on the Macintosh would be easy. After all, it's just a simple command line tool. It can write files to an SD card, directly to C3 flash or to RAM on either the C3 or jazzed's SDRAM board. I've tested the C3 downloads but I don't have the hardware required to test the SDRAM board support so I'll have to wait for jazzed to let me know if it is working.
My next task is to try to make the runtime code more flexible. Right now I always load a serial driver and use it for stdin/stdout/stderr I/O. I want to change that to allow stdio to be redirected to other drivers like the TV driver or the higher res Tv2 driver that jazzed has been working on. My question now is how to do that. The easiest way I can come up with is to have all stdio (console and file) redirected to /dev/null by default and then to have functions you can call to redirect it to a device. The idea would be to have the C program load the required driver (serial, TV, etc.) and then call a function to redirect stdio to that driver. This is pretty easy to do but it means that you'd have to modify every C program with code to load the driver and call the redirect function. That means you couldn't run unmodified generic C code without adding these calls.
Another approach would be to use build-time switches to load the appropriate drivers. This has the advantage that it doesn't require modifications to standard C code but it also complicates the build process.
I have a question about the memory layout of a ZOG program. It seems that the start address is at location zero but it is my understanding that there are also pseudo-registers located at location zero as well (return values for syscalls for instance). How is this conflict resolved? Is there a jmp instruction at location zero initially and then it gets overwritten by the register values after initialization?
It can write files to an SD card, directly to C3 flash or to RAM on either the C3 or jazzed's SDRAM board. I've tested the C3 downloads but I don't have the hardware required to test the SDRAM board support so I'll have to wait for jazzed to let me know if it is working.
Downloads appear to work but nothing will run. Guess i'll be doing those zog.spin diffs soon.
Downloads appear to work but nothing will run. Guess i'll be doing those zog.spin diffs soon.
The easy thing to do is overload putchar and use driver methods for cases like TV where users may want to read/write screen memory.
The problem with overloading putchar is that it only allows the stdio functions to work. It doesn't allow open/close/read/write functions to address the console. Those are lower level functions that work with file descriptors instead of stdio FILE variables. Of course, your point is still valid if I instead allow the user to redefine the read/write functions. I've not wanted to do that because it makes it more difficult for the user to just redirect console I/O and not file I/O. I'll come up with a proposal tomorrow (Sunday).
It seems that the start address is at location zero but it is my understanding that there are also pseudo-registers located at location zero as well
The start of a ZPU binary contains the following at address zero:
_start:
_memreg:
; intSp must be 0 when we jump to _premain
im ZPU_ID
loadsp 0
im _cpu_config
store
config
jmp _premain
No idea where the _memreg gets initialised though. Have a look in crt0.S
After that is an interrupt vector and a table of vectors for instruction emulation. The later should really be removed as we don't use the ZPU EMULATE instruction.
Thanks for the information on memreg and how it relates to the startup code. Unfortunately, I didn't get to creating an SDRAM linker script today. I ended up spending most of the day trying to come up with an easy way to select console and file I/O drivers at build time. My plan was to split my libprop.a library into a number of smaller libraries, one for each type of console I/O (none, serial, TV, etc) and one for each type of file I/O (none, SD, etc). Unfortunately, that didn't work. I couldn't control which files were pulled out of each library accurately enough. I'm going to have to come up with some other approach, possibly including actual code in main() to select the appropriate console and file I/O code. I wanted to avoid that to make it possible to compile and run unmodified generic C source code on the Propeller but I'm out of ideas on how to do that at the moment.
One thing I did realize today is that once I get past this library issue I *do* have the ability to test the linker script that will ultimately be used with jazzed's SDRAM board. Since it maps RAM starting at zero it can use the same linker script as the C3 uses when it runs entirely out of SRAM and not flash. That will let me test things before sending them to jazzed which will probably make it more likely that when I do release my code it will actually work on his SDRAM board. :-)
Unfortunately, I won't have anywhere near as much time to work on this now since my week long holiday break is over. :-(
I ended up taking advantage of a feature of the current ZPU runtime code. If an application defines the function _initIO it gets called before main(). I'm using that as a hook to setup console and file I/O so that the original generic C code doesn't have to be modified. You just add another file to your project that defines how I/O is done under ZOG. I've attached a simple sample of how this can be used to setup either serial or TV console I/O.
Heater: Have you ever tried setjmp and longjmp? I don't think they're working. At least, that's the simplest explanation for why my basic interpreter can't recover from errors. I looked at the code and it doesn't look obviously wrong to me but I don't really know the ZPU instruction set. Have you tried these?
Edit:
Sometimes it seems like I'm talking to myself in here! :-)
I just wrote a test program and at least simple cases of setjmp/longjmp seem to be working. I guess I'll have to look for my basic bug elsewhere...
Sorry for the absence of heat. Seems I'm kicking off the new year with 12 hour working days and general panic all around. I have a lot of Zogging to catch up on now.
Actually I don't think I've ever used setjmp/longjmp on any machine but it looks like you have it working in some way.
Speaking of heat, it's still 14 degrees C below here and a serious lot of snow.
Where is the best description of the ZPU instruction set? I'm finding that I sometimes need to try to read ZPU assembly code and I'd like to understand the instruction set better.
My ZPU emulator written in C is a good reference, it does exactly what the ZPU HDL does, tested and compared over millions of instruction steps. You can find it attached to the first post of this thread.
Else its dig out the ZPU simulator in Java from the ZPU git repository, which is the reference zpu_in_c and ZOG were written against.
Why do you store the address of the ZOG dispatch table in io_command at startup?
As far as I know ZOG does not do any such thing! Which bit of code are you thinking of?
ZOG is given the address of his own dispatch table during start up via a PAR parameter block. Is that what you mean?
The idea here is that the dispatch table is in HUB and can be relocated to any HUB location prior to starting ZOG. For example run_zog puts it at the end of HUB.
I thought you had already done something like that?
[QUOTE=Heater.;966658As far as I know ZOG does not do any such thing! Which bit of code are you thinking of?
ZOG is given the address of his own dispatch table during start up via a PAR parameter block. Is that what you mean?
The idea here is that the dispatch table is in HUB and can be relocated to any HUB location prior to starting ZOG. For example run_zog puts it at the end of HUB.
I thought you had already done something like that?[/QUOTE]
The line I commented out is at the end of the initialization code just before the jmp to #execute.
Edit: I just checked my copy of zog.spin from your release 1.6 and don't find that line. Maybe I added it in my sleep one night? :-)
Anyway, I'll remove it. Sorry for the false alarm!!
Yes, I'm relocating the zog dispatch table to high hub memory. In fact, I stole my code from your run_zog.spin file! :-)
I have ZOG running pretty well on the C3 now and I've written a loader that makes it pretty easy to develop programs using GCC and then load them into the C3 without having to edit any Spin code. I can do all of my development with just the cygwin toolset using make and gcc as well as zogload (my loader program) without having to use either BST or the Parallax Spin tool. I can support sending files from the PC to the SD card or directly to either C3 flash or SRAM. This loader also works with jazzed's SDRAM board as of yesterday.
C programs can use getchar/putchar and the associated stdio library functions to handle console I/O to either a serial port or the TV/keyboard. The stdio functions can also be used for file SD card file I/O.
So, I have a question for you. I'd like to put together a toolset to upload to the C3 FTP directory. This will consist of a version of ZOG.spin and my loader program as well as the ZPU toolset and maybe some pieces from cygwin (make mostly). I don't think there is any license statement in ZOG.spin at the moment. What license would you like to use? Is the MIT license okay?
I'm trying to tie up some loose ends before releasing a C3 version of ZOG and I have a couple of questions about the flags passed to the C compiler.
CFLAGS=-g -Wall -Os
I'm assuming none of those are actually necessary for proper operation. Certainly the -Wall just controls warning messages and -g controls the generation of debug information in the object file. Is -Os required or does it just provide better space optimization?
LDFLAGS=-phi -Wl,--relax -Wl,--gc-sections
What do these do and which are necessary? I think -phi selects a linker script. Do I need it if I supply my own linker script explicitly? What do the --relax and --gc-sections options to the linker do and are they necessary?
I don't know if -phi selects a linker script but if you leave it out or get it wrong you get an error about undefined reference to `ZPU_ID'. See crt0.S.
These ids are used to select different versions of the ZPU processor depending on the subset of instructions they implement. The Java ZPU simulator uses this id, delivered by the "config" instruction in order to perform the correct cpu level simulation. I guess we could live with out it. Or just ignore it as we do now:)
-g we can drop as we don't have a debugger to use its output.
-Wall is always good.
-Os is optimize for size. Removing -Os makes my hello.c 500 bytes bigger.
-Wl,--gc-sections Not sure what this does but again it adds 500 bytes to hello.bin if it is not there.
-Wl,--relax IS VERY IMPORTANT!!!!
As you know the IM instruction loads immediate values to the stack. It does it 7 bits at a time. The bigger the number you want to load the more IM instructions you need to build it up. It takes 5 IM's in a row to build a 32 bit number.
The compiled and assembled modules will always have 5 IM instructions in a row for each immediate that is loaded. This is very wasteful of space and time as a lot of numbers used in code are only one or two bytes wide so one or two IM's would be enough.
It is the linker that checks the use of all these IM's and reduces the number of them used wherever possible. That is "relaxing"
This is probably the most important optimization option as it has a huge effect on code size and execution speed. e.g. hello.bin is 23K without it but 18K with it!!
I'm trying to put together a ZOG package for the C3 and I'm having trouble figure out a minimal environment necessary for running the ZPU tools under Windows. I know they work under Cygwin but I'd like to avoid having to tell people to go through the whole gory Cygwin installation process just to run the ZPU compiler. I've tried just copying the Cygwin DLLs to the ZPU executables directory but they don't seem to work correctly. For instance, trying to compile a C program using the command:
zpu-elf-gcc -c hello.c
Produces the following error message:
zpu-elf-gcc: installation problem, cannot exec 'cc1': No such file or directory
There is no 'cc1' program that comes with the ZPU tools. There isn't even a 'zpu-elf-cc1'. Any idea how I can get around this problem? I want to provide a simple batch file to compile and link a ZPU program for ZOG under the Windows command prompt.
I thought it might be good to move this discussion to the forum instead of email since others may have opinions on this. I have two proposals for revising the ZOG memory map. One is a minor change in what we already have to make space for the hub ROM as well as the larger hub RAM in Propeller 2. The other is more dramatic providing much a larger space for external memory. Both have the virtue that they do not use negative addresses.
First proposal:
0x00000000 - 0x0fffffff for external RAM/ROM (256mb max)
0x10000000 - 0x17ffffff for hub memory (I'm sure Propeller 3 will have 128mb of hub memory!)
0x18000000 - 0x1fffffff for COG memory and any I/O registers (although my version of ZOG doesn't use them)
Second proposal:
0x00000000 - 0x3fffffff External RAM/ROM (1gb max)
0x40000000 - 0x403fffff Hub RAM/ROM (4mb max)
0x40400000 - 0x404001ff COG RAM (2k but top could be expanded)
Heater pointed out in the email thread that the larger addresses require more IM instructions. I think this suggests that the more modest first proposal might be best but will that leave enough external RAM/ROM space for future Propeller boards. I think jazzed is already planning a 128mb board. Is 256mb too little address space for external RAM/ROM?
As far as SDRAM size, I've decided to use a single chip solution which means maximum 64MB.
So I guess that means that the current 256mb of space for external RAM/ROM is sufficient. Now that you've decided not to use a second SDRAM chip, any chance you'll make a version of the MicroPropPC with 64mb of SDRAM and 64mb of flash? :-)
Heater: Do you have any idea how big a job it would be to make a little endian version of ZOG? It seems that the latest ZPU toolchain can support generating little endinan object files using the -mno-bytesbig compiler option. Would recompiling newlib using that option be all that is needed to make a complete little endian ZPU toolchain? Then, of course, ZOG itself would need to be modified but I suspect that isn't much more than deleting a bunch of XOR with %11 instructions, right? I think ZOG would work much better with PASM drivers if we could make it little endian like the rest of the Propeller world. When you just run simple C programs like fibo it doesn't matter much but when you start trying to interact with drivers it becomes a pain to have to byte and word swap all of the place.
Intriguing, I have never heard of no-bytesbig before. Google knows nothing except what the ZPU guys have been doing. My current version of zpu-gcc does not accept it.
Anyway, if it works I guess removing the byte reversal step from the Makefiles and those XORs from the byte and word access routines is enough to change Zogs endianness. So not a big job there.
Then we only have to worry about any endianness issues that might show up in newlib and the crt0.S etc.
If it can be made to work that would be very convenient, as you say. I'll try and get my zpu-gcc up dated and try some experiments.
Try typing "zpu-elf-gcc --target-help" to get the target-specific options. If you don't find that you have "-mno-bytesbig" then you might have an old version. I notice that the binary version I downloaded doesn't have it but the version I built from sources does.
Just built the latest zpugcc from git. It accepts -mnobytes-big.
But I can't see that it does anything. I added -mnobytes-big to both the compile and link flags in the Makefile for my old endian.c test. In the resulting listing file I see:
Comments
My next task is to try to make the runtime code more flexible. Right now I always load a serial driver and use it for stdin/stdout/stderr I/O. I want to change that to allow stdio to be redirected to other drivers like the TV driver or the higher res Tv2 driver that jazzed has been working on. My question now is how to do that. The easiest way I can come up with is to have all stdio (console and file) redirected to /dev/null by default and then to have functions you can call to redirect it to a device. The idea would be to have the C program load the required driver (serial, TV, etc.) and then call a function to redirect stdio to that driver. This is pretty easy to do but it means that you'd have to modify every C program with code to load the driver and call the redirect function. That means you couldn't run unmodified generic C code without adding these calls.
Another approach would be to use build-time switches to load the appropriate drivers. This has the advantage that it doesn't require modifications to standard C code but it also complicates the build process.
Any thoughts?
The easy thing to do is overload putchar and use driver methods for cases like TV where users may want to read/write screen memory.
The problem with overloading putchar is that it only allows the stdio functions to work. It doesn't allow open/close/read/write functions to address the console. Those are lower level functions that work with file descriptors instead of stdio FILE variables. Of course, your point is still valid if I instead allow the user to redefine the read/write functions. I've not wanted to do that because it makes it more difficult for the user to just redirect console I/O and not file I/O. I'll come up with a proposal tomorrow (Sunday).
The start of a ZPU binary contains the following at address zero:
No idea where the _memreg gets initialised though. Have a look in crt0.S
After that is an interrupt vector and a table of vectors for instruction emulation. The later should really be removed as we don't use the ZPU EMULATE instruction.
One thing I did realize today is that once I get past this library issue I *do* have the ability to test the linker script that will ultimately be used with jazzed's SDRAM board. Since it maps RAM starting at zero it can use the same linker script as the C3 uses when it runs entirely out of SRAM and not flash. That will let me test things before sending them to jazzed which will probably make it more likely that when I do release my code it will actually work on his SDRAM board. :-)
Unfortunately, I won't have anywhere near as much time to work on this now since my week long holiday break is over. :-(
Edit:
Sometimes it seems like I'm talking to myself in here! :-)
I just wrote a test program and at least simple cases of setjmp/longjmp seem to be working. I guess I'll have to look for my basic bug elsewhere...
It feels like summer in my office. Long, slow days minus the heat.
Still working on that integrated package here.
Good luck with setjmp/longjmp.
Actually I don't think I've ever used setjmp/longjmp on any machine but it looks like you have it working in some way.
Speaking of heat, it's still 14 degrees C below here and a serious lot of snow.
Be warned it has a few errors.
My ZPU emulator written in C is a good reference, it does exactly what the ZPU HDL does, tested and compared over millions of instruction steps. You can find it attached to the first post of this thread.
Else its dig out the ZPU simulator in Java from the ZPU git repository, which is the reference zpu_in_c and ZOG were written against.
As far as I know ZOG does not do any such thing! Which bit of code are you thinking of?
ZOG is given the address of his own dispatch table during start up via a PAR parameter block. Is that what you mean?
The idea here is that the dispatch table is in HUB and can be relocated to any HUB location prior to starting ZOG. For example run_zog puts it at the end of HUB.
I thought you had already done something like that?
ZOG is given the address of his own dispatch table during start up via a PAR parameter block. Is that what you mean?
The idea here is that the dispatch table is in HUB and can be relocated to any HUB location prior to starting ZOG. For example run_zog puts it at the end of HUB.
I thought you had already done something like that?[/QUOTE]
The line I commented out is at the end of the initialization code just before the jmp to #execute.
Edit: I just checked my copy of zog.spin from your release 1.6 and don't find that line. Maybe I added it in my sleep one night? :-)
Anyway, I'll remove it. Sorry for the false alarm!!
Yes, I'm relocating the zog dispatch table to high hub memory. In fact, I stole my code from your run_zog.spin file! :-)
I have ZOG running pretty well on the C3 now and I've written a loader that makes it pretty easy to develop programs using GCC and then load them into the C3 without having to edit any Spin code. I can do all of my development with just the cygwin toolset using make and gcc as well as zogload (my loader program) without having to use either BST or the Parallax Spin tool. I can support sending files from the PC to the SD card or directly to either C3 flash or SRAM. This loader also works with jazzed's SDRAM board as of yesterday.
C programs can use getchar/putchar and the associated stdio library functions to handle console I/O to either a serial port or the TV/keyboard. The stdio functions can also be used for file SD card file I/O.
So, I have a question for you. I'd like to put together a toolset to upload to the C3 FTP directory. This will consist of a version of ZOG.spin and my loader program as well as the ZPU toolset and maybe some pieces from cygwin (make mostly). I don't think there is any license statement in ZOG.spin at the moment. What license would you like to use? Is the MIT license okay?
CFLAGS=-g -Wall -Os
I'm assuming none of those are actually necessary for proper operation. Certainly the -Wall just controls warning messages and -g controls the generation of debug information in the object file. Is -Os required or does it just provide better space optimization?
LDFLAGS=-phi -Wl,--relax -Wl,--gc-sections
What do these do and which are necessary? I think -phi selects a linker script. Do I need it if I supply my own linker script explicitly? What do the --relax and --gc-sections options to the linker do and are they necessary?
Thanks,
David
I don't know if -phi selects a linker script but if you leave it out or get it wrong you get an error about undefined reference to `ZPU_ID'. See crt0.S.
These ids are used to select different versions of the ZPU processor depending on the subset of instructions they implement. The Java ZPU simulator uses this id, delivered by the "config" instruction in order to perform the correct cpu level simulation. I guess we could live with out it. Or just ignore it as we do now:)
-g we can drop as we don't have a debugger to use its output.
-Wall is always good.
-Os is optimize for size. Removing -Os makes my hello.c 500 bytes bigger.
-Wl,--gc-sections Not sure what this does but again it adds 500 bytes to hello.bin if it is not there.
-Wl,--relax IS VERY IMPORTANT!!!!
As you know the IM instruction loads immediate values to the stack. It does it 7 bits at a time. The bigger the number you want to load the more IM instructions you need to build it up. It takes 5 IM's in a row to build a 32 bit number.
The compiled and assembled modules will always have 5 IM instructions in a row for each immediate that is loaded. This is very wasteful of space and time as a lot of numbers used in code are only one or two bytes wide so one or two IM's would be enough.
It is the linker that checks the use of all these IM's and reduces the number of them used wherever possible. That is "relaxing"
This is probably the most important optimization option as it has a huge effect on code size and execution speed. e.g. hello.bin is 23K without it but 18K with it!!
zpu-elf-gcc -c hello.c
Produces the following error message:
zpu-elf-gcc: installation problem, cannot exec 'cc1': No such file or directory
There is no 'cc1' program that comes with the ZPU tools. There isn't even a 'zpu-elf-cc1'. Any idea how I can get around this problem? I want to provide a simple batch file to compile and link a ZPU program for ZOG under the Windows command prompt.
Thanks,
David
./toolchain/install/libexec/gcc/zpu-elf/3.4.2/cc1
That's interesting. I guess it must be a path problem then. Thanks!
First proposal:
0x00000000 - 0x0fffffff for external RAM/ROM (256mb max)
0x10000000 - 0x17ffffff for hub memory (I'm sure Propeller 3 will have 128mb of hub memory!)
0x18000000 - 0x1fffffff for COG memory and any I/O registers (although my version of ZOG doesn't use them)
Second proposal:
0x00000000 - 0x3fffffff External RAM/ROM (1gb max)
0x40000000 - 0x403fffff Hub RAM/ROM (4mb max)
0x40400000 - 0x404001ff COG RAM (2k but top could be expanded)
Heater pointed out in the email thread that the larger addresses require more IM instructions. I think this suggests that the more modest first proposal might be best but will that leave enough external RAM/ROM space for future Propeller boards. I think jazzed is already planning a 128mb board. Is 256mb too little address space for external RAM/ROM?
As far as SDRAM size, I've decided to use a single chip solution which means maximum 64MB.
So I guess that means that the current 256mb of space for external RAM/ROM is sufficient. Now that you've decided not to use a second SDRAM chip, any chance you'll make a version of the MicroPropPC with 64mb of SDRAM and 64mb of flash? :-)
Intriguing, I have never heard of no-bytesbig before. Google knows nothing except what the ZPU guys have been doing. My current version of zpu-gcc does not accept it.
Anyway, if it works I guess removing the byte reversal step from the Makefiles and those XORs from the byte and word access routines is enough to change Zogs endianness. So not a big job there.
Then we only have to worry about any endianness issues that might show up in newlib and the crt0.S etc.
If it can be made to work that would be very convenient, as you say. I'll try and get my zpu-gcc up dated and try some experiments.
But I can't see that it does anything. I added -mnobytes-big to both the compile and link flags in the Makefile for my old endian.c test. In the resulting listing file I see:
00003ca4 <a_number>:
3ca4: 76 loadsp 24
3ca5: 54 storesp 16
3ca6: 32 xor
3ca7: 10 addsp 0
The bytes are in the same order whether I have nobytes-big or not.