[cc65] Apple2 file io - here: memory management questions

From: Oliver Schmidt <ol.sc1web.de>
Date: 2004-07-30 00:26:21
Hi,

as memory is always a very precious resource on the Apple2 I'd like to shed
some light on the memory management side of file io...

The Apple2 has lower memory from $0000 to $BFFF (48 k). At least for text
mode programs $0800 to $BFFF (46 k) is available. Then there is a memory
mapped io area from $C000 to $CFFF (4 k). From $D000 to $FFFF (12 k) we have
upper memory.


1. scenario: DOS 3.3

DOS 3.3 normally occupies $9600 to $BFFF (10,5 k). This includes buffers for
the default of three concurrently opened files. Reducing this to one file
("MAXFILES 1") results in $9AA6 to $BFFF (9,3 k). A program calling DOS 3.3
may reuse those buffers or supply memory for file i/o on its own. I'd opt
for supplying own buffers for two reasons:

- The maximum number of concurrently opend files is dynamic.
- In scenario 2. described below reuse of buffers is very difficult.

If the calling program doesn't reuse DOS 3.3 buffers it can destroy them all
after loading and rebuild them on exit. Without any buffers DOS 3.3 uses
$9D00-$BFFF (8,7 k).


2. scenario: DOS 3.3 in upper memory

Several DOS 3.3 variants may be moved into upper memory. There they occupy
all of the upper memory (12 k) and a little amount of lower memory from
$BF00 to $BFFF (0,25 k) or $BE00 to $BFFF (0,5 k). The number of buffers of
concurrently opend files is typically fixed to five. Unfortunately there's
no "official" standard for accessing the buffers so a program is better off
supplying its own buffers.


Results for DOS 3.3

Sceanrio 1. gives an text mode application a total of 49,2 k (37,2 k + 12 k)
memory but unfortunately the current cc65 linker isn't able to span a
segment accross several memory areas. Therefore it's impossible to make use
of the upper memory in a generic way. Therefore we have to stick to scenario
2. with ~ 45,6 k of _CONTIGIOUS_ memory left for the application. BTW: This
does _NOT_ mean that we become incompatible scenario 1. It just means that a
memory intensive application won't use it.

Pro's:
- No special startup/cleanup code
- Bank switching to ROM is done by moved DOS 3.3

Con's:
- ~ 3,6 k less memory
- User needs movable DOS 3.3 (not too popular)


3. scenario: ProDOS 8 with command interpreter

The ProDOS 8 kernel uses the same memory as DOS 3.3 being moved into upper
memory: The whole upper memory (12 k) plus $BF00 to $BFFF (0,25 k) of lower
memory. The ProDOS 8 command interpreter additionally occupies $9600 to
$BEFF (10,2 k). These values don't include any buffers so they have always
to be provided by the application.

A word on these buffers: While a DOS 3.3 file buffer occupies only 557 bytes
a ProDOS 8 file buffer needs 1024 bytes of memory _ALIGNED_TO_A_PAGE
BOUNDARY_. Assuming that file buffers are allocated on the cc65 heap and
that there is no "aligned malloc" this makes up 1024 + 255 = 1279 bytes per
file buffer !

@Jim: Do you agree with this or did I miss a point?
@Ullrich: Do you see an option to provide some memory allocation mechanism
suitable for ProDOS 8 file buffers?

This scenario is compatible with DOS 3.3 for all application that don't do
file i/o themselves. This means that:

- The application binary is loaded directly to its target location
(typically $0800 for text mode programs)
- The application simply quits with a JMP to DOS (which means the command
interpreter for ProDOS 8)


4. scenario: ProDOS 8 without command interpreter

The assembly language file io APIs of ProDOS 8 are part of the ProDOS 8
kernel thus there is no need for the command interpreter to be present while
an application is running. In fact all "profesional" ProDOS 8 programs use
this scenario. Unfortunately - but not surprisingly - this doesn't come for
free:

- The application binary is always loaded at $2000. The application has
basically two options a) move the loaded binary to its target location or b)
provide a small loader to load the "real" binary directly to the target
location using the file i/o API.

- The application has to call a special quit API on exit. The called quit
routine will then allow the user to load the next application (for example
the command interpreter).


Results for ProDOS 8

As scenario 3. leaves only 35,5 k for a text mode program it is desirable to
support scenario 4. with 45,7 k of available memory. For applications with
large amounts of CODE + RODATA + DATA (in other words a large binary file)
it may simply be impossible to load the file at $2000. Therefore the
approach with a small loader seems to be appropriate.

The major part of this loader could be written in C and use the new file io
library to load the main binary at $0800 and jump to it. It would have a
custom startup code relocating the loader from $2000 to let's say $B000.
This area would then wiped out later by the BSS, heap or stack of the main
executable.

The loader would be identical for all cc65 applications and just have a
different name. ProDOS 8 supports "argv[0]" so the loader could detect from
that the path of the main binary with a pattern like MYAPP.SYSTEM for the
loader and MYAPP.BINARY for the main binary.

A benefit of this approach would be that the startup code for DOS 3.3
binaries and ProDOS 8 main binaries could be shared. Just the last call at
the very end of the startup code would have to go into the file i/o
libraries instead of being hardcoded in crt0.s. A destructor which never
returns doesn't look like a clean solution - does it?

Setting up a RESET handler for closing files (as requested by the ProDOS 8
tech ref manual) could be done from a constructor in the ProDOS 8 file i/o
library. This handler would call exit() after doing its job. Or we decide
that we generally (for all kind of Apple2 binaries) want a RESET handler
only calling exit(). Then the ProDOS 8 file i/o library would just need an
atexit() hook...

Oliver

----------------------------------------------------------------------
To unsubscribe from the list send mail to majordomo@musoftware.de with
the string "unsubscribe cc65" in the body(!) of the mail.
Received on Fri Jul 30 00:25:50 2004

This archive was generated by hypermail 2.1.8 : 2004-07-30 00:25:59 CEST