Thornton 2 dot Com

GEOS Development

Ariel's GEOS Programmer's Reference Guide
Back: Preface Up: Contents Next: GEOS Kernal Routines

GEOS Development
Back: First Up: This Next: GEOS: Graphics

Table of Contents

  1. GEOS: Graphics
    1. Common Graphics (TODO)
    2. Bitmap Graphics (TODO)
    3. Commodore 64 Graphics (TODO)
    4. Commodore 128 Graphics (TODO)
    5. Apple IIe Graphics (TODO)
  2. GEOS: Environment (WIP)
  3. GEOS: Operating (WIP)
  4. GEOS: System (TODO)

GEOS in a Nutshell for Programmers

Developing for GEOS is usually done in 6502 Assembly language, and GEOS programming documentation is written with that assumption in mind.

GEOS is a complete event-driven operating system, not just a GUI shell. It works by spending most of its time checking for an event to happen, then dispatching the servicing routine for that event. Instead of writing your own wait/polling loop and meticulously checking for something to happen, all your program's initializing routine has to do is install event service routines then let GEOS wait and watch and dispatch for you.

In most cases, your GEOS program is nothing more than a collection of event service routines, some data structures, and a single short initialization routine that transfers control to the GEOS Main Loop once your event-handling routines are installed.

There are three broad categories of events in GEOS: user, interrupt, and timed. User events are things like typing and clicking on menus and icons. Interrupt events are events that happen every time GEOS switches to Interrupt Level. Timed events are events that happen on a regular schedule but less frequently than every Interrupt Level.

GEOS provides not just a graphics library but a user interface library:

GEOS spends its time in one of two contexts, Main Loop and Interrupt Level. The switch from Main Loop to Interrupt Level is triggered by the CPU's IRQ line (while interrupts are enabled), and the switch back from Interrupt Level to Main Loop is made by Interrupt Level itself. On the Apple II, GEOS switches contexts without an actual hardware IRQ source, but it still takes care of both contexts itself.

GEOS also provides a system for managing timed events, which it calls processes, and each process can be individually controlled. Processes can be enabled or disabled, have their timers stopped, resumed, restarted, and reset, and be made to run before the timer runs out. Like with other GEOS events, all you have to do is give GEOS a table of processes and their service routines.

GEOS includes a library of routines simplifying the task of giving your programs the same UI as any other GEOS program. GEOS also relieves you of the burden of creating your own library of device drivers to integrate into your programs, instead relying on GEOS device drivers to access disk drives, printers, and input devices. GEOS also allows you to make your own drivers for devices GEOS doesn't include support for, and those drivers can be used with any GEOS programs, not just your own.

Accessing the GEOS API

In GEOS, accessing the API is done in one or both of two parts: changing system memory locations, and calling kernel functions with the jsr (and sometimes jmp) instruction to a jump table. In GEOS, the kernel is called the GEOS Kernal [sic], the API's functions are called Kernal routines, and the programmer-accessible system memory locations are called variables.

Using a Kernal routine consists of storing parameters in system variables (usually r0 through r15), then executing jsr RoutineName. Some Kernal routines are "inline" routines; using them consists of storing parameters in your code, in the bytes immediately following the jsr instruction. Inline routines are named with a leading lowercase I and underscore.

An example API call that clears the screen by filling it with the default light-dark hash:

; Clear the screen

       lda   #2                    ; Pattern #2
       jsr   SetPattern            ; Set as current pattern
       LoadB r2L, 0                ; Top
       LoadB r2H, SC_PIX_HEIGHT-1  ; Bottom
       LoadW r3, 0                 ; Left
       LoadW r4, SC_PIX_WIDTH-1    ; Right
       jsr   Rectangle             ; Draw a filled rectangle
       nop                         ; Next instruction here

An example API call that does the same thing but using the inline version of the Rectangle routine:

; Clear the screen

       lda   #2                    ; Pattern #2
       jsr   SetPattern            ; Set as current pattern
       jsr   i_Rectangle           ; Draw a filled rectangle (inline)
       .byte 0                     ; Top
       .byte SC_PIX_HEIGHT-1       ; Bottom
       .word 0                     ; Left
       .word SC_PIX_WIDTH-1        ; Right
       nop                         ; Next instruction here

The names of the constants, variables, macros, and routines used in this guide are those defined by the "geosSym" and "geosMac" files included with the boxed version of the geoProgrammer macro assembler program. (They came as geoWrite 1.1 files with geoAssembler v1.1, geoLinker v1.1, and geoDebugger v1.0, applications all dated 1987-11-02.) Names not found in geosSym or geosMac but used in this guide anyway are names used in Berkeley Softworks (BSW) literature; their absence from those files is noted where described in detail.

In GEOS for the Commodore 64, the first example above would compile to the byte sequence:

a9 02    ;lda #$02  - Pattern #2
20 39 c1 ;jsr $c139 - Set as current pattern (SetPattern)
a9 00    ;lda #$00  - Top (LoadB r2L,0)
85 06    ;sta $06
a9 c7    ;lda #$c7  - Bottom (LoadB r2H,199)
85 07    ;sta $07
a9 00    ;lda #$00  - Left (LoadW r3,0)
85 08    ;sta $08
a9 00    ;lda #$00
85 09    ;sta $09
a9 3f    ;lda #$3f  - Right (LoadW r4,319)
85 0a    ;sta $0a
a9 01    ;lda #$01
85 0b    ;sta $0b
20 24 c1 ;jsr $c124 - Draw a filled rectangle (Rectangle)
ea       ;nop       - Next instruction here

And the second example above would compile to the byte sequence:

a9 02    ;lda #$02  - Pattern #2
20 39 c1 ;jsr $c139 - Set as current pattern (SetPattern)
20 9f c1 ;jsr $c19f - Draw a filled rectangle (i_Rectangle)
00       ;          - Top
c7       ;          - Bottom (199)
00 00    ;          - Left
3f 01    ;          - Right (319)
ea       ;nop       - Next instruction here

GEOS Application Structure

GEOS files are in one of two broad structures, neither one of which matches CBM DOS file structures. The simpler structure is Sequential (not to be confused with CBM DOS SEQ files), and is usually a CBM DOS USR file with a single data stream and a non-DOS resource fork stream. The other broad structure is VLIR, which stands for "variable length indexed records." A VLIR file is usually a CBM DOS USR file with a non-DOS resource fork stream and up to 127 non-DOS data streams. The resource fork stream common to both structures is the GEOS file header.

A GEOS application is a Sequential or VLIR GEOS file. If you compile your application into a Sequential file, GEOS will load the entire data stream into memory and run your program when the user opens it. If you compile your application into a VLIR file, GEOS will load the data stream of the first record into memory as your program's resident module and run it when the user opens it.

Writing a simple GEOS application consists of compiling your program's source code, compiling your program's file header separately, and putting the two parts together into a single GEOS file.

If you use a non-GEOS assembler, then it could consist of leading off your program's source code by defining 252 bytes (a disk sector's worth of data after compilation) for the GEOS file header, following it with your program's actual source code, assembling it, and transforming it into a GEOS file with a specialized disk/directory editing program.

The start of application RAM is at address $0400 (1024), and that's typically the start address as well. GEOS programs also need to give an end address, but GEOS only enforces it for desk accessories; all other programs typically give $03ff (1023, one byte below the start address) as the end address.

Ways to Develop for GEOS

The main SDK that Berkeley Softworks made available for third-party programmers is geoProgrammer, consisting of a 6502 assembler, a linker, a debugging tool, and a comprehensive user's manual. Although the minimum requirements are the same as for GEOS itself, the practical minimum requirements are a at least two disk drives and a RAM expansion unit (REU). Uniquely, geoProgrammer takes source code in the form of geoWrite documents, and it translates any bitmap images pasted in source code documents into binary data ready for the GEOS bitmap image routines.

Before geoProgrammer's debut, however, programmers were making GEOS programs by cleverly using non-GEOS assemblers and altering the program files to conform to one of the GEOS file formats. The Official GEOS Programmer's Reference Guide dedicates a chapter to a CBM Basic program that alters a PRG program file compiled from a C64 assembler into a GEOS Application file, making this the interim official way.

A small variety of other GEOS-specific assemblers, compilers, and interpreters were also ultimately available. Some of the better known are geoBASIC, BeckerBasic, geoCOM, geoCOPE, and Concept.

The other way to develop for GEOS, and the way Berkeley Softworks used in-house, is with a cross-assembler or cross-compiler. In the 21st Century, a fairly accessible 6502-series cross-compiler with GEOS support is cc65 with GEOSLib.