The Z80 processor is an old processor, and it's based on an even older one - the Intel 8080. These two processors are 8 bit accumulator based and can access an address space of 65536 bytes (or 64k).
Quite early on it was realised that this simply isn't enough address space to implement a comprehensive operating system and leave sufficient user RAM for their own programs.
The solution to this is quite straightforward, have more ROM/RAM in the system and page it in when required. This trick isn't just used on the Z80 but also for the 6500 series of processors from Motorola.
However, this isn't going to be a lecture on memory models and computer architecture (I'd end up in hot water for what I'd say, and probably will even for that small bit just there!) - it's a description of how the Small C+ compiler can access more than 64k and whats still left to do!
Those of you unlucky enough to have compilers for the x86 series of processors will know about the concept for far data and hence far pointers, however for those who own 68k based computers with their lovely 24/32 bit address space now have permission to start gibbering and get very confused as I attempt to unconfuse myself.
The far pointers used by Small C+ are 24 bits long i.e. 3 bytes, this enables the theoretical access of 4Mb of memory (if your program requires more than this then please tell me what you're trying to do on a Z80!).
The way I envisage this to be utilised on the Z88 is as follows:
bits
23-16 Memory Pool Number
15-0 Offset within pool
Or for computers where you can take over the entire machine and all it's memory!:
bits
23-16 Memory Bank/Page
15-9 Offset within bank/page
Though, this discussion will only cover the Z88, so you're on your own as to the other implementation!
Before I begin I should like to point out the for Small C+ far pointers are stored in the registers ehl where e contains bits 16-23 and hl bits 0-15 of the pointer. If e holds 0 then hl is taken to be an absolute address in the current memory configuration.
For this concept to work, it will be necessary to create an extremely well designed memory allocation system which will have to present in all programs that use far pointers.
Thus initially we need a malloc routine would far the prototype:
far *malloc(int)
Which would take a two byte integer, reserve this much space in the system, and return a pointer which would consist effectively of a memory pool number in e and 0 in hl. If enough space couldn't be reserved it should return with ehl=0.
Internally however it would have to create a memory pool within the Z88 and extend this until the size is that wished by the user. In returning a pointer in ehl it should internally bind whatever e is to the system memory pool (this maybe via a look up table or some other method) so that whenever access to the pool e is requested it can be calculated where exactly offset hl actually is.
I should obviously mention free which will free the memory pool e and deallocate all memory reserved by malloc. In addition to this there should be a cleanup function which will deallocate all the memory in all the memory pools. (This is an internal function and will be used by the startup code to clean up on exit of the program - and hence avoid leakage).
All access to the memory pools at C-level will be via a set of functions to read and write various types, which will now be described with entry parameters and projected exit conditions:
Reading routines, all these have entry ehl = memory pool address
lp_gchar - read char Exit: l = byte at that location
This routine should not bother with signedness - the compiler will sort this out
lp_gint - read 2 byte integer Exit: hl = word at that location (stored little endian) lp_gptr Exit: dhl = far pointer at that location lp_glong - read 4 byte integer Exit: dehl = long at that location (l=LSB) lp_gdoub - read 6 byte double Exit: Load FA -> FA+5 with the double stored at that location
FA -> FA+5 are 6 bytes presently located in the startup code, but will be relocated to the bad memory for applications. This routine may require some thought - there is a routine in the float package to place bcixde into the FA area.
Writing routines, all these have entry e'h'l' = memory pool address and the following additional entry parameters:
lp_pchar - write char Entry: l = byte to write lp_pint - write 2 byte integer Entry: hl = word to write lp_pptr - write far pointer Entry: ehl = far pointer to write lp_plong - write 4 byte integer Entry: dehl = long to write lp_pdoub - write double Entry: none
This routine will write the bytes stored in FA -> FA+5 to the memory pool address, once again this may require some thought.
None of these routines have been written as of yet, if someone would volunteer to do so or volunteer to alter a set of routines that they have taking up space on the harddrive I would be immensely grateful - I have a lot of work still to do on the compiler to ensure that all contingencies (stupidities!) are covered and that the code generation is both stable and sensible.
Of course, with the introduction of far pointers I am required to rewrite a large number of the existing library functions (strings.h stdio.h to name but two header files) to take account of this - as well as rewriting the function calling routines to call the appropriate library function - it really is just the start of the compiler!