diff --git a/doc/ophismanual.pdf b/doc/ophismanual.pdf index 0f58bad..c587636 100644 Binary files a/doc/ophismanual.pdf and b/doc/ophismanual.pdf differ diff --git a/doc/ophismanual.sgm b/doc/ophismanual.sgm index c251529..fc31d25 100644 --- a/doc/ophismanual.sgm +++ b/doc/ophismanual.sgm @@ -20,7 +20,7 @@ Programming with Ophis MichaelMartin - 2006-2014Michael Martin + 2006-2024Michael Martin &pre1; diff --git a/doc/preface.sgm b/doc/preface.sgm index bda7791..420776d 100644 --- a/doc/preface.sgm +++ b/doc/preface.sgm @@ -6,7 +6,7 @@ consoles. Its primary design goals are code readability and output flexibility - Ophis has successfully been used to create programs for the Nintendo Entertainment System, the Atari 2600, and various - 8-bit Commodore machines. + 8-bit Commodore and Apple machines. Ophis's syntax is noticably different from the formats @@ -39,20 +39,20 @@ cross-assembler for the 6502 chip the C64 used in both. - The Perl one—uncreatively - dubbed Perl65—was quickly abandoned, but - the Python one saw more work. When it came time to name it, one - of the things I had been hoping to do with the assembler was to + The Perl one—uncreatively dubbed + Perl65—was quickly abandoned, but the + Python one saw more work. When it came time to name it, one of + the things I had been hoping to do with the assembler was to produce working Apple II programs. Ophis is Greek for snake, and a number of traditions also use it as the actual name of the serpent in the Garden of Eden. So, Pythons, snakes, and stories involving really old Apples all combined to name the assembler.Ironically, cross-platform development - for the Apple II is extremely difficult, and while Ophis has - been very successfully used to develop code for the Commodore - 64, Nintendo Entertainment System, and Atari 2600, it has yet to - actually be deployed on any of the Apples which inspired its + for the Apple II is much less straightforward than for the + Commodore 8-bits or ROM-based consoles, and it took many years + after its release before it was actually used to write code + deployed on any of the Apples which inspired its name. @@ -68,18 +68,38 @@ After its release Ophis 2 was picked up by a number of - developers work with actual hardware from the period, including - prototype machines that never saw production. Some of their - contributions have refined the code generators for version 2.1. + developers working with actual hardware from the period, + including prototype machines that never saw production. Some + of their contributions have refined the code generators for + version 2.1. - This is an updated edition of Programming With - Ophis, including documentation for all new features - introduced and expanding the examples to include simple - demonstration programs for platforms besides the Commodore - 64. It also includes updated versions of the To HLL - and Back essays I wrote using Ophis and Perl65 as - example languages. + At that point, the program was basically done, and very little + changes for about five years. The world, however, moved on, and + Python 2, my implementation language, was deprecated and + rendered obsolete. That didn't change much about the 2.1 + release—Python 2 was still installed on non-Windows + machines by default, and the Windows distribution was as a + bundled .EXE file—but it threatened the viability of the + program overall. In 2019, then, I converted the source base to + the backwards-incompatible Python 3, in the hopes of + future-proofing the system. Five years after + that, enough bug reports and bug fixes had + trickled in to justify a fresh release, and 2.2 was published in + 2024—a lightly polished update that now fit more neatly + into the Python toolchains of the 2020s. + + + In the twenty years since I first started this project, I've + gained quite a bit more experience with programming the computer + systems of the 1970s and 1980s. I have left this manual largely + as it was in its 2014 edition, including its versions of the + To HLL and Back essays I wrote using Ophis + and Perl65 as example languages. I don't think I stand behind my + design decisions back then as firmly as I did when I wrote those + essays, but there's noting wrong with them + either so I'm happy to leave them as a testament to my younger, + brasher self. diff --git a/doc/samplecode.sgm b/doc/samplecode.sgm index b8b0120..ea6ed4d 100644 --- a/doc/samplecode.sgm +++ b/doc/samplecode.sgm @@ -708,7 +708,7 @@ _done: rts .checkpc $D000 .data zp -.checkpc $80 +.checkpc $90
diff --git a/doc/tutor1.sgm b/doc/tutor1.sgm index 4bfb9be..459b0fc 100644 --- a/doc/tutor1.sgm +++ b/doc/tutor1.sgm @@ -58,11 +58,11 @@ We SAVE this program to a file, then - study it in a debugger. It's 15 bytes long: + study it with a hex dumper. It's 15 bytes long: -1070:0100 01 08 0C 08 0A 00 9E 20-32 30 36 34 00 00 00 +00000000 01 08 0c 08 0a 00 9e 20 32 30 36 34 00 00 00 |....... 2064...| @@ -72,29 +72,32 @@ BASIC program breakdown - + + File Offsets Memory Locations Value - $0801-$08022-byte pointer to the next line of BASIC code ($080C). - $0803-$08042-byte line number ($000A = 10). - $0805Byte code for the SYS command. - $0806-$080AThe rest of the line, which is just the string 2064. - $080BNull byte, terminating the line. - $080C-$080D2-byte pointer to the next line of BASIC code ($0000 = end of program). + 0-1Nowhere2-byte pointer to where in memory to load the rest of the file ($0801). + 2-3$0801-$08022-byte pointer to the next line of BASIC code ($080C). + 4-5$0803-$08042-byte line number ($000A = 10). + 6$0805Byte code for the SYS command. + 7-11$0806-$080AThe rest of the line, which is just the string 2064. + 12$080BNull byte, terminating the line. + 13-14$080C-$080D2-byte pointer to the next line of BASIC code ($0000 = end of program).
- That's 13 bytes. We started at 2049, so we need 2 more bytes of - filler to make our code actually start at location 2064. These - 17 bytes will give us the file format and the BASIC code we need - to have our machine language program run. + That's 15 bytes, of which 13 are actually loaded into memory. + We started at 2049, so we need 2 more bytes of filler to make + our code actually start at location 2064. These 17 bytes will + give us the file format and the BASIC code we need to have our + machine language program run. @@ -176,6 +179,16 @@ next: .word 0 ; End of program
+ + + We can do better still, though. That initial starting address + of 2064 was only ever a guess; now that we know that we overshot + by two bytes, we can simply change the starting address to 2062 + and omit the .advance directive entirely. In + fact, we can even remove the space before the number and make it + 2061 instead—BASIC doesn't need that space in its + instruction and it's arguably a wasted byte. +
diff --git a/doc/tutor2.sgm b/doc/tutor2.sgm index 806246b..124e42a 100644 --- a/doc/tutor2.sgm +++ b/doc/tutor2.sgm @@ -25,9 +25,9 @@ - We can thus rewrite our header data using temporary labels, thus - allowing the main program to have a label - named next if it wants. + We can rewrite our header data using temporary labels, allowing + the main program to have a label named next + if it wants. diff --git a/doc/tutor3.sgm b/doc/tutor3.sgm index 5b59323..36e2819 100644 --- a/doc/tutor3.sgm +++ b/doc/tutor3.sgm @@ -24,7 +24,8 @@ A related directive, .require, will include the file as long as it hasn't been included yet elsewhere. It - is useful for ensuring a library is linked in. + is useful for ensuring a library is present somewhere in the + final code. @@ -132,11 +133,6 @@ _done:
Macro invocations - - Macros may be invoked in two ways: one that looks like a - directive, and one that looks like an instruction. - - The most common way to invoke a macro is to backquote the name of the macro. It is also possible to use diff --git a/doc/tutor4.sgm b/doc/tutor4.sgm index 190ebdb..7abe852 100644 --- a/doc/tutor4.sgm +++ b/doc/tutor4.sgm @@ -104,4 +104,12 @@ target10: .byte "Universe", 0 provided with the sample programs as petscii.map. + + + Versions of Ophis prior to 2.2 have a bug where only the first + argument to .byte would be translated. That's + fine for our example code here, with only one string per line, but + a more text-heavy title that relied on this should confirm their + version before getting too far in. + diff --git a/doc/tutor5.sgm b/doc/tutor5.sgm index 735033e..6a84b64 100644 --- a/doc/tutor5.sgm +++ b/doc/tutor5.sgm @@ -91,7 +91,11 @@ delay: sta _tmp ; save argument (rdtim destroys it) using are .org and .space commands. Ophis will not complain if you use .space inside a .text - segment, but this is nearly always wrong. + segment, but this is nearly always wrong. Remember, + both .org and .space only + ever alter the way that Ophis computes labels. They do not output + any bytes, nor do they change where in the output file the bytes + are actually written. diff --git a/doc/tutor6.sgm b/doc/tutor6.sgm index c4f048b..d877462 100644 --- a/doc/tutor6.sgm +++ b/doc/tutor6.sgm @@ -110,8 +110,8 @@ _done: rts Note that brackets, not parentheses, are used to group arithmetic - operations. This is because parentheses are used for the indirect - addressing modes, and it makes parsing much easier. + operations. Parentheses are reserved for the indirect addressing + modes. diff --git a/doc/tutor7.sgm b/doc/tutor7.sgm index f8e7e51..f65cabf 100644 --- a/doc/tutor7.sgm +++ b/doc/tutor7.sgm @@ -130,7 +130,7 @@ _done: rts .data zp -.checkpc $80 +.checkpc $90 diff --git a/doc/tutor8.sgm b/doc/tutor8.sgm index 7ff3b9e..13e2a87 100644 --- a/doc/tutor8.sgm +++ b/doc/tutor8.sgm @@ -1,5 +1,5 @@ - Platform-Specific Techniques + Included Platform Support Ophis is intended to produce cross-assembled binaries that will @@ -18,9 +18,7 @@ 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. It's also one where the developer needs to take the - most care about exactly what kind of program they are - writing. + support. @@ -166,27 +164,33 @@ The Nintendo Entertainment System - The NES development community is somewhat more fragmented than - the others. A skeletal nes.oph file is - provided, but memory locations are not as consistently - named. Much sample code doesn't provide aliases for control - registers at all. + 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. - Conveniently creating runnable NES programs is somewhat - involved. Any given product was generally burned onto several - chips that were affixed to one of a large number of circuit - boards. These are often 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 "Hello World" - sample program ships with Ophis. It does not use a bankswitcher, - but it does split its contents into a program chip and a - graphics chip, with one of two wrapper files to knit them - together into a file that other software will recognize. Samples - are given for the common iNES format and the defunct UNIF - format. + 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.
@@ -194,18 +198,66 @@ The Atari 2600 VCS - Of all the 8-bit development communities, the Atari developers - seem to be the most cohesive. The development documents - available are universal, and analysts and developers alike all - use the register names in the Stella Developer's - Guide. Ophis follows their lead, providing these - names in the header stella.oph. + 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. - The stella.oph header also replicates two - macros that appear in the header files distributed to budding - VCS developers. They are documented in the file. + 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.
diff --git a/examples/hello7.oph b/examples/hello7.oph index be2e3d6..ed5d1cc 100644 --- a/examples/hello7.oph +++ b/examples/hello7.oph @@ -94,4 +94,4 @@ _done: rts .checkpc $D000 .data zp -.checkpc $80 +.checkpc $90 diff --git a/examples/hello_a800.oph b/examples/hello_a800.oph new file mode 100644 index 0000000..2066dde --- /dev/null +++ b/examples/hello_a800.oph @@ -0,0 +1,34 @@ + .outfile "hello.obj" + .word $ffff ; Binary file + .word start ; start of code + .word end-1 ; end of code + + .org $0600 ; Load into page 6 + + ;; `iostob OFFSET, VALUE + ;; `iostow OFFSET, VALUE + ;; Store value in OFFSET in I/O control block X>>4. +.macro iostob + lda #_2 + sta $340+_1,x +.macend + +.macro iostow + `iostob _1,<_2 + `iostob _1+1,>_2 +.macend + +start: ldx #$00 ; Channel 0 (E:) + + ;; Write message with one I/O call, and exit + `iostob 2,11 ; WRITE command + `iostow 4,msg ; buffer pointer + `iostow 8,msgend-msg ; buffer length + jmp $e456 ; Do I/O call and quit + +msg: .byte "Hello, world!",$9b +msgend: ; End of message +end: ; End of code block + + ;; Autostart at start + .word $02e0,$02e1,start diff --git a/examples/hello_apple2.oph b/examples/hello_apple2.oph new file mode 100644 index 0000000..afec144 --- /dev/null +++ b/examples/hello_apple2.oph @@ -0,0 +1,31 @@ +;;; ---------------------------------------------------------------------- +;;; HELLO WORLD for the Apple II +;;; This is a ProDOS 8 program. Its output should be importable by +;;; CiderPress without incident. +;;; ---------------------------------------------------------------------- + + .outfile "HI.SYSTEM#ff2000" + .org $2000 + + ;; Write message + ldx #$00 +* lda msg,x + beq wait + ora #$80 ; Disable inverse + jsr $fded ; CHROUT + inx + bne - + + ;; Wait for keypress +wait: bit $c000 ; Check keypress bit + bpl wait + bit $c010 ; Acknowledge keypress + + ;; Return to ProDOS + jsr $bf00 + .byte $65 + .word + + brk ; Unreachable +* .byte 4, 0, 0, 0, 0, 0, 0 + +msg: .byte "HELLO, WORLD!",13,"PRESS ANY KEY TO EXIT",0 diff --git a/examples/stella/README.txt b/examples/stella/README.txt index c755b1d..340dd9c 100644 --- a/examples/stella/README.txt +++ b/examples/stella/README.txt @@ -1,9 +1,9 @@ -"Hi Stella" is a simple "Hello World" program for the "Stella" chip, -more famously known as the Atari 2600. Simply running +"Hi Stella" is a simple "Hello World" program for the "Stella" +system, more famously known as the Atari 2600. Simply running ophis hi_stella.oph -should produce hi_stella.bin, a 256-byte file that prints "HI" on +should produce hi_stella.bin, a simple demo that prints "HI" on the screen with some rolling color bars. A more sophisticated program is colortest, which lets the user diff --git a/src/Ophis/CmdLine.py b/src/Ophis/CmdLine.py index ec3760c..f253dc0 100644 --- a/src/Ophis/CmdLine.py +++ b/src/Ophis/CmdLine.py @@ -36,7 +36,7 @@ def parse_args(raw_args): parser = optparse.OptionParser( usage="Usage: %prog [options] srcfile [srcfile ...]", - version="Ophis 6502 cross-assembler, version 2.1") + version="Ophis 6502 cross-assembler, version 2.2") parser.add_option("-o", default=None, dest="outfile", help="Output filename (default 'ophis.bin')")