Programming with Ophis
<<< Previous | Ophis Command Reference | Next >>>

# Memory Model

In order to properly compute the locations of labels and the like, Ophis must keep track of where assembled code will actually be sitting in memory, and it strives to do this in a way that is independent both of the target file and of the target machine.

## Basic PC tracking

The primary technique Ophis uses is program counter tracking. As it assembles the code, it keeps track of a virtual program counter, and uses that to determine where the labels should go.

In the absence of an `.org` directive, it assumes a starting PC of zero. `.org` is a simple directive, setting the PC to the value that `.org` specifies. In the simplest case, one `.org` directive appears at the beginning of the code and sets the location for the rest of the code, which is one contiguous block.

## Basic Segmentation simulation

However, this isn't always practical. Often one wishes to have a region of memory reserved for data without actually mapping that memory to the file. On some systems (typically cartridge-based systems where ROM and RAM are seperate, and the target file only specifies the ROM image) this is mandatory. In order to access these variables symbolically, it's necessary to put the values into the label lookup table.

It is possible, but inconvenient, to do this with `.alias`, assigning a specific memory location to each variable. This requires careful coordination through your code, and makes creating reusable libraries all but impossible.

A better approach is to reserve a section at the beginning or end of your program, put an `.org` directive in, then use the `.space` directive to divide up the data area. This is still a bit inconvenient, though, because all variables must be assigned all at once. What we'd really like is to keep multiple PC counters, one for data and one for code.

The `.text` and `.data` directives do this. Each has its own PC that starts at zero, and you can switch between the two at any point without corrupting the other's counter. In this way each function can have a `.data` section (filled with `.space` commands) and a `.text` section (that contains the actual code). This lets our library routines be almost completely self-contained - we can have one source file that could be `.included` by multiple projects without getting in anything's way.

However, any given program may have its own ideas about where data and code go, and it's good to ensure with a `.checkpc` at the end of your code that you haven't accidentally overwritten code with data or vice versa. If your `.data` segment did start at zero, it's probably wise to make sure you aren't smashing the stack, too (which is sitting in the region from $0100 to $01FF).

If you write code with no segment-defining statements in it, the default segment is `text`.

The `data` segment is designed only for organizing labels. As such, errors will be flagged if you attempt to actually output information into a `data` segment.

## General Segmentation Simulation

One text and data segment each is usually sufficient, but for the cases where it is not, Ophis allows for user-defined segments. Putting a label after `.text` or `.data` produces a new segment with the specified name.

Say, for example, that we have access to the RAM at the low end of the address space, but want to reserve the zero page for truly critical variables, and use the rest of RAM for everything else. Let's also assume that this is a 6510 chip, and locations $00 and $01 are reserved for the I/O port. We could start our program off with:

    .data
    .org $200
    .data zp
    .org $2
    .text
    .org $800

And, to be safe, we would probably want to end our code with checks to make sure we aren't overwriting anything:

    .data
    .checkpc $800
    .data zp
    .checkpc $100

<<< Previous | Home | Next >>>
Compound Arguments | Up | Macros