9

I have a vague recollection of some early software that extended the Apple II BASIC language, though I'm not sure if this was Integer or Applesoft BASIC.

It provided more features for the language by using commands such as &line x1, y1, x2, y2 to augment the rather primitive HLINE and VLINE drawing commands, or &circle x, y, radius for circles. I don't know if they were actual commands (it was forty-plus years ago) but that was the basic idea.

How this was done? Did it require that BASIC be loaded into RAM and patched or was it some sort of built-in hook already in the software? What was the process the BASIC interpreter followed to allow a command to use the new functionality?

1
  • 1
    My "fdraw" project provides ampersand extensions that draw lines and circles from Applesoft BASIC. Full source code here: github.com/fadden/fdraw (AMPERFDRAW.S implements the BASIC extensions).
    – fadden
    Mar 2 at 15:32

2 Answers 2

10

After a bit of research, it turns out it was Applesoft.

The interpreter had a feature where, if it encountered an ampersand during execution of the program, it would unconditionally jump to a subroutine at location $3F5.

Extension software could use BLOAD or BRUNto get some code to a specific location and modify the three bytes at that location. This would then cause the code to execute when & was seen.

When that code eventually returned, Applesoft would continue execution after the ampersand.

So, if all you wanted was one simple thing to happen when an ampersand was encountered, that would be enough.


In order to allow for more complicated things like &line 1, 1, 20, 50, the code had to access internal memory to both figure out what the command was (so it could read parameters), and to ensure Applesoft skipped those parameters when we returned. The TXTPTR Applesoft variable was used for this.

You could call specific functions from your code to parse the line after the ampersand, using TXTPTR, and adjust it as part of that process, such as with:

; Handles something like "& 12345 * 2, 41"

JSR   $DD67      ;FRMNUM - eval numeric expression -> FAC
JSR   $E752      ;GETADR - place FAC into memory (LINNUM)
JSR   $DEBE      ;CHKCOM - check for comma
JSR   $E6F8      ;GETBYT - eval byte -> X reg

; Do something in here with registers and memory populated above.

RTS

Granted that's fairly simple but you had ways to ensure that the string "line" was the first thing after the ampersand as well (or detect different commands), giving you a variety of options. There was a GETCHR which returned the next character (or token if it was a keyword).

1
  • Note that there were quite a few extensions using the ampersand. IIRC another one I used frequently was for renumbering BASIC lines.
    – dirkt
    Mar 2 at 12:17
6

While paxdiablo answered the question confirming that it was AppleSoft, I can point out three things related to it as an extension:

  1. When you load your extension, it should attempt to relocate itself as high as it can in the available memory to leave as much free RAM as possible behind. As such, it was common for ampersand extensions to be written with relative addressing if not using jump tables or self-modifying code.
  2. It was good practice to make sure that your extension chained control to whatever address was in place previously. In other words, make it possible that more than one ampersand extension could exist; if your extension didn't recognize (say) & FOO, then perhaps the next one in the chain could.
  3. There was another, lesser used AppleSoft command USR(x) which would call a machine language routine with the value of x in the accumulator (IIRC). Whatever the routine had in the accumulator when it finished would be passed as the lvalue (e.g. Y = USR(123)).

A few extensions off the top of my head: AmperWorks, ModemWorks, Beagle Basic, Beagle Graphics, and more recently I believe there was a text windowing library created by someone that used ampersand extensions.

5
  • For #1: True when it's about some larger extension. The vast majority were rather small routines placed in the usual ML scrap area at $300.
    – Raffzahn
    Mar 2 at 13:34
  • Out of curiosity, how often would code be relocatable to arbitrary addresses, and how often would it be relocatable on 256-byte boundaries? On the 6502, designing for the latter is pretty easy even with fairly primitive tools: assemble a program for two addresses, 256 bytes apart, compare, ensure that everything either matches or differs by one, and build a list of those differences.
    – supercat
    Mar 2 at 16:17
  • I had combined several ampersand extension programs from different magazines in one package. A line editor, several basic extensions (while/wend repeat/until, some graphic commands, etc). I still have the binary (probably also the source in some old floppy) but have completely forgotten how to use it. Mar 3 at 9:28
  • bjb, I appreciate the use of "themself" in light of the fact I haven't made my gender clear (male) but it seemed a little "strained". "Himself" would have been better (had you known the gender) but, when I edited, that felt weird as well. So I just took gender out of the equation. Hope you don't mind. Good answer BTW. I have a sudden hankering to go find all that Beagle Bros software I loved back in the day :-)
    – paxdiablo
    Mar 3 at 22:41
  • we also use the technique when submitting to the AppleIIBot, by POKEing directly into memory to set the handler and place our code. It saves some bytes. See here: pferrie.epizy.com/misc/appleii/a2bot.htm Mar 7 at 0:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.