Update Log
[ MainPage | UpdateLog | Downloads | BBS ]
Update log, or you can say it is just a memorandom. :-)Contiki supports ELF format. It is, however, too heavy for very memory-limited machine like PC-6001. Therefore, I'm designing a new file format for dynamic loading, which supports relocation. Currently I came up with a very light-weighted file format, which can be processed in one pass and work with very small additional memory.
Current conio library is exaggerated to some extent, because it was intended to support CTK library. I'm working on the conio library, which can provide minimal configuration of console as well as rich GUI on top of it. I hope it would be integrated with any I/O like Unix, which integrates file and network as well as console.
After enabling network support with a bit of unstableness, now I'm working on a dynamic loading library on my PC-6001 Contiki, which will be also available on any Z80-based machines. The biggest problem is memory limitation. For example, I can pick it ELF format, but loading mechanism itself would be too large to fit in small memory footprint. Therefore, I consider introducing another mechanism of dynamic loading. I don't want to reinvent the wheels, so if you know any good alternative, please inform me!
After struggling a bunch of problem, finally I added my PC-6001 support sources to the main Contiki CVS in Sourceforge.net. The last problem was an RS-232C driver, which is based on polling rather than interrupt as you can see as other ports.
I struggled with memory and finally made it! Web server is now on memory, I don't have any network hardware driver though.
My hard road was the following:
With these work, total 11,604 bytes reduced! Now this configuration could run on PC-6001, with some more effort regarding the network hardware support.
As for network hardware, I don't have RS-232C option on my PC-6001, so I need to get it.
A few days ago, I became a commiter of Contiki project at sourceforge. As a first step, I committed z80-depend code. Once I make the code clean, I will commit PC-6001 code as well.
Now I'm moving on to the networking. In contiki system, some functions, which calculate checksums, are intended to be overridden in assembler code by the performance reason. Therefore, I wrote the whole checksum routines in the native z80 code. Code size, however, is still too large to settle in RAM area. I need some breakthrough to make the networking work.
Finally, I made the multithreading function work!
The symptom and resolution was following:
After removed register save/restore of "I" and "R", everything works fine! Most of Z80-based computer can use this context switching mechanism, so I will commit this on cpu-dependent directory rather than machine-dependent directory.
Porting multithreading library is not going well. Contiki itself has two types of multithread libraries:
I know the enough mechanism of z80 for implementing the z80-specific thread switching according to the Contiki system, but it doesn't work somehow...
Now trying to implement z80-dependent multithread library. I implmented it by following existing architecture-dependent libraries. The context switch must include saving registers and a stack pointer, so I wrote this part by assembler. It doesn't work well yet actually. Definitely I miss something...
I posted a set of patch regarding z80 to the contiki developers mailing list, so I hope it would be applied soon.
Currently the biggest problem is the size of the load module, which enables networking and GUI.
The size exceeds the capacity of PC-6001, when the both of components are set to be available. The reason of this includes poor code generation of sdcc. For example, sdcc emits code for "switch" of the char type like this:
switch (c) { // suppose c is char type case 1: // do something A break; case 2: // do something B break; default: // do something C break; }Corresponding Z80 assembly code:
ld a,4(ix) // 3 bytes sub a,#0x01 // 2 bytes jp Z,00101$ // 3 bytes ld a,4(ix) // 3 bytes sub a,#0x02 // 2 bytes jp Z,00102$ // 3 bytes // do something C jp Z,00103$ // 3 bytes 00101$ // do something A jp 00103$ // 3 bytes 00102$ // do something B 00103$It costs 22 bytes for branches. As you see, the code size of each "case" would be bigger using destructive "sub" than using "cp". I suggest the following:
ld a,4(ix) // 3 bytes cp a,#0x01 // 2 bytes jp Z,00101$ // 3 bytes cp a,#0x02 // 2 bytes jp Z,00102$ // 3 bytes // do something C jp Z,00103$ // 3 bytes 00101$ // do something A jp 00103$ // 3 bytes 00102$ // do something B 00103$In this way, it costs 19 bytes. You don't see much difference for this small example, but if the number of case increases, the difference becomes bigger. If you have N "cases" plus a "default", you can calculate the size by the following formula:
size = 8 * (N - 1) + 3 * (N - 1) = (N - 1) * 11where my example shows:
size = 3 + 5 * (N - 1) + 3 * (N - 1) = 8N - 5The difference would be:
diff = ((N -1) * 11) - (8N - 5) = 3N - 6It doesn't makes a big difference, unless the variable N is big, but I can show some examples:
I know this is just a single case for "switch (char)" type of code generation. I wonder, however, it would be some other size optimization possibilities in sdcc. It also improves performance, because accessing index registers cost much state than other operators.