Included Platform Support Ophis is intended to produce cross-assembled binaries that will run in a variety of contexts. The expectation is that most users will be writing for emulated versions of hardware from when the 6502 chip was current, and producing files either for those emulators or for devices that will transfer the results to real hardware. This chapter describes the support routines and examples to make those tasks easier.
The Commodore 64 and VIC-20 In a real sense, the Commodore 64 is the "native" target platform for Ophis. It was the first platform targeted and it's the one that has received the most additional support. c64kernal.oph actually defines no code. It merely sets up the customary names for the KERNAL jump table routines so that you may refer to routines like chrout and rdtim by name. c64header.oph is an absolutely minimal C64 header program; it contains the one-line BASIC program and nothing else. Smaller programs that do not require more than four bytes of zero page do not need to do any bankswitching or zero page caching and don't need any more than this. The aliases provided in c64kernal.oph may be useful, but are not included in this header. c64_0.oph is suitable for larger and more sophisticated programs. It is an enhancement of the header file developed in the previous chapter. It stores the saved zero page values in the RAM shadowed by the KERNAL ROM, and it also uses a different mechanism for returning to BASIC when done that is more robust in the face of self-modifying programs such as those produced by self-extracting compressed executables or onefiled multipart programs. It is used like the other header files—just include it at the top of your source file and use RTS to end your program—but programs that use this header file will have all of the zero page from $02-$8F and a contiguous chunk of program RAM from $0800-$CFFF. libbasic64.oph is an experimental set of macros and routines to permit the assembly programmer to make use of the software floating point routines provided by BASIC. It is, for obvious reasons, not compatible with c64_0.oph, because it needs to make use of BASIC's workspace and the ROM itself. If you wish to use this file you should include it near the end of your program. vic20.oph is a header that will work for the unexpanded VIC-20. Memory expansion slots change where BASIC programs load, and since these headers load in the machine language program in as the suffix to a BASIC program, that also changes where they are themselves loaded. There is no trickery with bankswitching ROMs in and out—the VIC-20 does not have enough RAM to gain anything from these techniques. vic20x.oph does the same, but for a VIC-20 with one or more memory expansions.
Using LIBBASIC64 The 6502's arithmetic capabilities are rather limited. To counteract this, BASICs of the era did floating point in software and gave BASIC programmers the full suite of arithmetic operations. These operations are largely unavailable to machine language programmers. The libbasic64.oph library is an attempt to address this. It is currently considered highly experimental, but initial results are very promising. BASIC stores floating point numbers in a five-byte format, but translates them into a seven-byte format to do actual work in two Floating Point Accumulators (FAC1 and FAC2). Ophis will let you specify 5-byte constants with the .cbmfloat directive, which takes a string and produces the requisite five-byte value. The floating point functions in BASIC all operate on FAC1 and are relatively reliable. The functions abs_fac1, atn_fac1, cos_fac1, exp_fac1, int_fac1, log_fac1, rnd_fac1, sgn_fac1, sin_fac1, and tan_fac1 are all provided. Routines that touch the FACs tend to be extremely finicky. This system defines a set of macros and routines to manage that for you: `f_move dest, source: Copy a five-byte floating point value from source to dest. `fp_load src: Loads FAC1 with the floating point constant specified by src. `fp_store dest: Saves the value of FAC1 to the named memory location. `fp_print src: Prints out the value of FAC1 to the screen. You may want to call int_fac1 first to round it. Unlike BASIC's PRINT statement, this routine will not bracket the number with blanks. `fp_read ptr: Attempts to convert a string to a floating point value in FAC1, in a manner similar to BASIC's VAL function. `fp_add operand: Adds the operand to FAC1. `fp_subtract operand: Subtracts the operand from FAC1. `fp_multiply operand: Multiplies the operand by FAC1. `fp_divide operand: Divides FAC1 by the operand. `fp_pow operand: Raises FAC1 to the operand's power. `fp_and operand: Juggles floating point-to-integer conversions to do a bitwise AND. `fp_or operand: Likewise, but for OR. jsr randomize: Calls RND(-TI) and leaves the (useless) result in FAC1. This seeds BASIC's random number generator with the number of clock ticks since poweron. jsr rnd: Calls RND(1) and leaves the result in FAC1, providing a random number between 0 and 1. jsr fac1_sign: Loads the SGN(FAC1) into the accumulator. This will be $01 if the accumulator is positive, $00 if it is zero, and $FF if it is negative. This routine is useful for branching based on the result of a floating point computation. Other functions are available, but their preconditions are hazier. The source file is commented with the current state of knowledge. To see some of these functions in action, the examples directory includes a program kinematics.oph, which reads numbers in from input and computes trajectories based on them.
The Nintendo Entertainment System The NES development community in 2024 has standardized on the sophisticated ca65 assembler for major homebrew projects, but Ophis's simpler output model has advantages of its own. A skeletal nes.oph file is provided in the platform support directory, but most NES code you'll find in the wild doesn't use aliases for control registers at all—it just sticks with the register numbers. Creating output files that emulators or other tools will recognize as complete NES programs is somewhat involved. Any given product was generally one of a large selection of circuit boards with several ROM or support-logic chips affixed to it. These circuit board configurations are generally referred to as "mappers" by developers because their effect is to implement various bankswitching schemes. The result is a program built out of parts, each with its own origin. A simple Hello World sample program ships with Ophis. It is configured to use "Mapper Zero", or a simulation of the NROM circuit board, which had no special bankswitching logic and simply wired the program chip and the graphics chip directly into the address bus. The sample code includes one source file for each chip, and then two wrapper files to knit them together into a file that other software will recognize. As of 2024, the UNIF format is entirely abandoned in favor of the backwards-compatible iNES 2.0 format.
The Atari 2600 VCS Ophis provides a stella.oph header that names the system's registers to match the documentation in the Stella Programmer's Guide. It also replicates two macros that were widely shared on mailing lists and other tutorial documents at the time Ophis was first released. See the file itself for details. Atari 2600 ROM images are simple ROM dumps and do not require any more sophisticated organization in the Ophis source files than an .advance directive to pad the output to the appropriate size. Two sample programs ship with Ophis 2.2; a tiny hello-world program, and a more sophisticated interactive program that explores the system's color palette.
Other Atari 8-bits The Atari 2600's successor, the Atari 5200, shares much of its architecture with the Atari 400/800/1200/XL/XE line. Atari DOS had an executable format that divided itself up into chunks that were independently loaded, with some chunks being special and identifying program entry points or intervening processing to be done mid-load. A simple Hello World program compatible with Atari DOS is included in the examples directory. The output file may be loaded and run directly in many emulators, or may be copied into a disk image with a tool like atr or Altirra and executed from the DOS prompt.
The Apple II series For most of its lifespan, Apple II systems ran either a primitive system named "DOS 3.3" or more sophisticated one named ProDOS. ProDOS 8 is as of 2024 still under active development, and its superior support for machine-language interfacing with the disk drive makes it the preferable choice for Ophis-based development. A simple Hello World program is included in the examples directory. To actually run the resulting binary, it must be added to a ProDOS-formatted disk using a tool such as CADIUS or CiderPress.