From: Mike McCarty (jmccarty_at_ssd.usa.alcatel.com)
Date: 2001-05-25 17:03:02
On Fri, 25 May 2001, Ullrich von Bassewitz wrote: > > On Fri, May 25, 2001 at 09:13:33AM -0400, shubel, paul wrote: > > Question: Can CC65 compile and link a segmented build? For example, > > can it call modules in "banked" areas of memory to exceed the 64K boundary? > > cc65 cannot call functions in other banks by itself, because the banking > mechanism is always hardware dependent. However, the linker is able to overlay > memory areas. This means that it is possible to write programs for banked > hardware with some help from the programmer. > > > Is this what is meant by segments? > > segments are just some hunks of code or data that have a name. The linker > combines all pieces that have the same name to one large chunk, and places it > into a memory area according to the rules in the configuration file. > > This means that by placing a function f1() into a segment with the name CODE1, > and a function named f2() into a segment CODE2, it is possible to tell the > linker to relocate both segments CODE1 and CODE2 to the same address, but > write it to different files. To support banking, the programmer has to supply > a short stub in common memory for each such function that enables the correct > bank and calls the function. Excellent description, Ullrich. Having done banked memory switching myself, I'd like to add to your statement. Banked memory switching is both a blessing and a curse. It is a blessing, in a sense, because it allows one to use much more memory than the processor can directly access. It is a curse for a multitude of reasons. One is the "short stub", also sometimes called a "trampoline". This is the bane of programmers. Debugging this stuff is a major pain. One has to be sure that the stack appears in all banks. Initializing the memory (loading the program) is a major pain. Single stepping in a debugger may or may not work. It may be impossible to set a break in code not in the present bank, and it may be impossible to step into it. Oh, another way to do it is to have the trampolines appear in each bank, rather than in common memory. I prefer not to use trampolines at all, but rather to put a dispatcher in common memory, along with a jump table and information on what bank each destination lies in. Macroes can hide the interface. It's something like this: #define SOME_FUNCTION 6 #define SomeFunction(Arg1,Arg2) BankCall(SOME_FUNCTION,Arg1,Arg2) where BankCall is a real routine in the common memory, the dispatcher. Its prototype looks like this int BankCall(int FunctionId,...); It uses FunctionId as an index into a table of entries giving the banked address (bank and offset) of the destination function. SomeFunction looks like this: int SomeFunction(SomeFunctionParmsStruct_t *Parms); BankCall computes the address of the argument with the lowest address, and passes that as the pointer to the parameter block accepted by the function. One could use <stdarg.h> and make the functions receive a va_list int SomeFunction(va_list Parms); similar to vfprintf(). BankCall looks in the function table, and checks the current hardware state against the table entry. If necessary, it first enables the chosen bank (or even just unconditionally enables it), saving the current bank in a bank stack (or in a local variable on the stack). Then it invokes the address in the table. On return, it re-enables the bank called from if necessary (or even just unconditionally) and then returns the value returned by the invoked routine. In this way, no additional code need be written for multiple routines, just add an entry in the table. Get the code right once, and then don't change it. Some prefer to do this #define SOME_BANK 3 #define SOME_FUNCTION 0x1234 int BankCall(SOME_BANK,SOME_FUNCTION,...); where the actual bank and function address get passed in. I don't like this, as one has to edit a header file somewhere to put the banks and addresses in. I prefer editing a jump table in a source file. YMMV Mike ---------------------------------------------------------------------- To unsubscribe from the list send mail to majordomo_at_musoftware.de with the string "unsubscribe cc65" in the body(!) of the mail.
This archive was generated by hypermail 2.1.3 : 2001-12-14 22:05:40 CET