3

Chapter 3 of the Apple II Reference Manual describes the machine-language Monitor. On page 41 it describes certain remembered locations:

The Monitor remembers the addresses of up to five locations. Two of these are special: they are the addresses of the last location whose value you inquired about, and the location which is next to have its value changed. These are called the last opened location and the next changable location.

However, the further description of how these are used is not exactly correct:

Each time the Monitor displays a value contained in a location, it remembers that location as the last opened location.
...
If you type a period (.) on an input line to the Monitor, followed by an address, the Monitor will dispaly a memory dump: the values contained in all locations from the last opened location to the location whose address you typed following the period.

Typing 0 and hitting Return (which produces 0000- 4C) followed by .2 and Return produces 0001- 3C D4. Either the "last opened" location was actually set to the location after the last displayed location or the . command displays from last opened location plus one to the following address.

And of course there are the mysterious other three "remembered" locations.

I would like an exact (and ideally, clear) description of how all this actually works, including what these five remembered locations are and how the various commands set and use them.

Additional technical information that would be helpful is where these remembered locations are stored in memory (presumably A1L, A1H, A2L, ..., A5H at locations $3C through $45?) and what other commonly available software (the Mini-assembler, Programmer's Aid #1, DOS 3.3, etc.) uses and/or changes them.

2
  • 1
    The most exact/clear description is of course the source, which has pretty good comments like "move (A1 to A2) to A4" (MOVE at $fe2c). The trick is decoding the command parser, which you can see parsing numbers into A2 but copying elsewhere depending on mode (around NXTBAS at $ff98). The table entry at $ffdf has ':' and '.' set the mode ($fe18). It's a pretty good exercise if you want to dig in to 6502 code.
    – fadden
    Mar 27, 2020 at 15:05
  • @fadden I'm afraid I'm going to disagree with you that terms such as "A1" and "A2" are clearer than "last opened location" and "next changable" location.
    – cjs
    Mar 27, 2020 at 15:15

2 Answers 2

5

The model of how the Monitor command line works in the Apple II Reference Manual, and most other documentation, isn't really in line with how it does work. It doesn't help that the Monitor itself, at least as far as command line parsing goes, is more a set of hacks than anything truly coherent.

The following is an excerpted and edited copy of my personal notes on the Monitor.

Monitor Commands

Input to the monitor is a sequence of hexadecimal addresses and commands, with multiple addresses and commands allowed on a line. (Note that there are no "separators"; space is a valid command and other whitespace will be read as invalid commands.)

  • Addresses are any sequence of 0-9 and A-F. Only the lowest sixteen bits of an address will be used; the higher bits are ignored.
  • Commands are any other character. Unrecognized commands terminate processing of the input line. Note that this means commands that take an argument must be followed immediately by the argument.

Remembered Locations and Number Entry

There are three addresses that the monitor remembers and uses as default addresses for its commands:

  • next: the default address for dumping data, and some other commands. (Stored at A1L $3C,A1H $3D.)
  • load: the default address at which data entry will start with the : command. (Stored at A3L $40,A3H $41.)
  • PC: the saved program counter providing the default address for the G and L commands. (Stored at PCL $3A, PCH $3B.)

Entering an address will set both next and load to that address. Commands will update these as described below.

Commands

Hexadecimal data dumps:

  • Following an address addr with a space or CR will print addr followed by its contents and set next to addr+1. A space not preceded by an address does nothing.
  • A CR at the start of a line prints address next only if it is a multiple of 8, dumps memory contents from next up to (but not including) the next multiple of 8, and sets next to the last dumped address + 1.
  • ., when followed by an address addr will print the address next, dump memory from next through addr, and set next to addr+1. . not followed by an address does nothing.
  • Ctrl-E displays the register values A,X,Y,P,S from locations $45‥49 and sets load to $45. (next is unaffected.)

Disassembly and running code:

  • L disassembles 20 lines of code and sets PC to the next address after the disassembly. When immediately preceded by an address it first sets PC to that address. (A preceding address also still sets next and load.)
  • G loads the registers from the saved values (ACC, XREG, YREG, STATUS and SPNT at $45-$49) and does a JSR to PC. When immediately preceded by an address, it first sets PC to that address. (A preceding address also still sets next and load.)

Depositing data into memory:

  • : takes a sequence of data bytes and deposits them into memory starting at load. The data bytes are space-separated hexadecimal numbers; only the lowest 8 bits of each number are used. Any command will terminate the list of bytes. (N is a convenient command to terminate the list if you want to continue the line with an address.)
  • dest<addr: Sets A4L,A4H $42,$43 and A5L,A5H $44,$45 to dest (note that A5H is also ACC, overwriting the saved A register) and A2L,A2H $3E,$3F to addr. (addr also has the normal effect of setting next and load.) Does nothing if not followed by an address. (This is not normally used alone, but to set up M and V commands, and could also be used to set up a Ctrl-Y command.
  • dest<start.endM moves memory from start through end to locations starting at dest (the dest range may overlap the source range), sets load to dest and next to end+1.
  • dest<start.endV compares ("verifies") memory. Non-matching source/dest bytes will be displayed like 02FB-0B (0A).

Misc. commands:

  • + and - do 8-bit two's-complement arithmetic on the low 8 bits of next and the address following the command. They do nothing if not immediately followed by an address.
  • N, I: Change character output to normal and inverse, respectively.
  • Ctrl-P and Ctrl-K set output resp. input to the lowest three bits of next. These are the equivalent of PR#n and IN#n in BASIC.
  • Ctrl-Y calls $3F8; RTS returns to monitor.

How This Was Done

Though I did look a bit through the Monitor source, it wasn't very helpful. The design is confusing, at best, though it can give a few hints.

Mainly I worked this all out through experimentation, assisted by a custom Ctrl-Y Monitor command that prints PCL/PCH and A1L/A1H through A5L/A5H. (These are the main locations in the zero page that store addresses or, more generally, numbers used as parameters by the monitor routines.) The code is as follows:

          ;   dumpmonvar: print monitor UI variables
          ;
          ;   This prints the saved PC and the addresses/16-bit values stored in  A1
          ;   through A5 These are variables used by the monitor user interface for
          ;   command handling and "remembered" addresses.
          ;
          ;   This depends on COUT preserving X and Y. This is true for the screen
          ;   (PR#0), but may not be for other char switch (CSW) routines.
          ;
          ;   This is position-independent code and may be loaded anywhere. $300 is a
          ;   usual place for it. Use `3F8: 4C LL HH`, where $HHLL is the start of
          ;   this routine, to set the Monitor Ctrl-Y command to run this.
          ;
          dumpmonvar
                      ;   Print PC, A1, ..., A5
A0 06                 ldy #6              ; 6 words to display
A2 3A                 ldx #PCL            ; first word to display
A9 A0     .nextA      lda #AA(' ')
20 ED FD              jsr COUT
B5 01                 lda 1,x             ; high byte
20 DA FD              jsr PRBYTE
B5 00                 lda 0,x             ; low byte
20 DA FD              jsr PRBYTE
E8                    inx                 ; next word
E8                    inx
88                    dey                 ; decrement count
D0 EC                 bne .nextA
20 8B FD              jsr CROUT1
60                    rts

If you want to try it out, you can just type in the hex code at the left with 300: A0 06 A2 3A ... and then set the Ctrl-Y command to call it with 3F8: 4C 00 03. Remember that CR following an address will change next, so if you want to see what the address set, as opposed to the CR following it, type the Ctrl-Y immediately after the address, before entering CR.

2
  • Better than my answer and matches what I found going through the source code. I would like to point that there is a bit of logic in the hex address parser that sets a flag if any hexdigits are found which is checked just before the G or L commands and copies the value of A1 into PC if the flag is set.
    – PeterI
    Mar 30, 2020 at 21:21
  • @PeterI Thanks. Yes, I had noticed that logic (first in testing, then confirmed with a glance at the code, though I never did figure out how the code does what it does) and mentioned it in the L and G command descriptions. But still, I've clarified that slightly further.
    – cjs
    Mar 31, 2020 at 0:58
2

Okay stealing text from the Apple Monitor unpeeled:

$31 MODE - This byte is used by the Monitor command processing routines to control parsing and to control operations when a blank is encountered after the hex digits. For example, a hex address followed by a colon causes setting of MODE so that during further processing of the input line each blank encountered signifies end of a hex value to be placed in memory. During parsing, the contents of MODE indicate where the hex values should be stored for use when the command itself is encountered. MODE is set to appropriate values by plus, minus, colon, and period.

$3C A1L - Multipurpose Monitor work area:
$3D A1H - May be clobbered by Instruction Trace in Old Monitor; see XQT above.
When the Monitor begins processing a command, MODE is initiailized to zero. As the input line scanned, hex digits are first place into A2L,H. From there they are moved also to A1L,H and A3L,H as long MODE remains zero. When a plus, minus, colon or period is encountered, MODE is modified to indicate which, and A1L,H will continue to contain the value, terminated by the operator encountered.
A1L,H is the primary index for the BLANK monitor command, memory examine or display.
A1L,H contains the addend for the Monitor ADD command.
A1L,H contains the minuend for the Monitor SUBTRACT command.
A1L,H is the source field pointer during the Monitor MOVE command.
A1L,H is one of the two indices used in the Monitor VERIFY command.
A1L.H is the source field from which PCL.H is set on L and G Monitor commands, and the Old Monitor commands S and T, if an address is specified. If no address is used in the input line, then PCL.H is the residue of the last command which maintained or used it.
A1L,H is the memory pointer used for cassette tape READ and WRITE Monitor operations.
Monitor routine NXTA1 increments A1L,H by one and then compares the result to A2L,H. If A2L.H is less than A1H,L, then Carry is set when control is returned to the calling program.

$3E A2L - Multipurpose Monitor work area:
$3F A2H - May be clobbered by Instruction Trace in Old Monitor; see XQT above.
This field is the receiving field into which hex data is stored during Monitor Command parsing. When the command itself is encountered, A2L,H contains the last parameter entered. While MODE contains zero (until a plus,minus, colon or period is encountered) A2L,H is continually copied into A1L,H and A3L,H. If a "less than" sign is encountered, A2L,H is immediately copied to A4L,H and A5L,H A2L,H is used to terminate examine (memory display), tape write, tape read, memory move, and memory verify operations.
A2L,H contains the subtrahend in a Monitor SUBTRACT command operation.
A2L,H contains the augend in a Monitor ADD command operation.
A2L,H is the source field and A3L,H is maintained as the pointer for the Monitor STORE command.
A2L,H contains the port number in an input port select or output port select (control K or P) command.
Monitor routine NXTA1 increments A1L,H by one and then compares the result to A2L,1I. If A2L,H is less than AIL,H then Carry is set when control is returned to the calling program.

$40 A3L - Multipurpose Monitor work area:
$41 A3H - May be clobbered by Instruction Trace in Old Monitor; see XQT above.
A1L,H and A3L,H are both filled from A2L,H during Monitor Command processing scan of the input line as described above regarding A1L,H.
A3L,H is used as the destination pointer during Monitor STORE command processing.
A3L,H is used as a work area by the Register Display routine, which is called by the control-E Monitor command, or as part of the single cycle or trace operations of the Old Monitor.

$42 A4L - Multipurpose Monitor work area:
$43 A4H - May be clobbered by Instruction Trace in Old Monitor; see XQT above.
This field (and A5L,H) are loaded from A2L,H during Monitor Command Processor scan of the input area when a "<" character is encountered.
A4L,H is the receiving field pointer during a Monitor MOVE command execution.
A4L,H is the second field pointer during a Monitor VERIFY operation.
Monitor routine NXTA4 increments A4L,H by one, and then drops into NXTA1 , which increments A1L,H by one and then compares the result to A2L,H. If A2L,H is less than A1L,H then Carry is set when control is returned to the calling program.

$42 A5L - Multipurpose Monitor work area: $43 A5H - This field is not within the bounds of the area of XQT, which, in the Old Monitor overlays A1L through A4H.
Note A5H = $45 = ACC This field is filled from A2L,H as described above for A4L,H. However the field is not otherwise referenced within the monitor, except that ACC (below) is also A5H.

5
  • There's a lot of information in here, but it doesn't seem really to address the question. (E.g., does the user even see or care about the $31 MODE variable, as opposed to just the syntax of the monitor commands?) How about if you edit it to start with a summary of the user-visible variables (i.e., the ones that change the behaviour of commands when set differently) and how they operate?
    – cjs
    Mar 27, 2020 at 17:44
  • I think the point is that A1,A2 are used for multiple purposes depending on the command. So the single comand line "30+43 30-43 30.43" all use A1L,H & A2L,H in three different ways.
    – PeterI
    Mar 27, 2020 at 22:52
  • Yes, that's the kind of thing I'm looking for in a summary! (I don't think it's easy to see from your original text that it's used in three different ways for that line.) So how do the + and - commands affect the last remembered addresses? And how does A2 fit in there at all? Doing a bit of playing with it, neither a start address nor the . command even seemed to change A2, though perhaps I missed something there. But it looks like you can do n+0 to set one of the memorized addresses (which one?) without doing a dump of it? If so, that's something not at all obvious from the Apple docs.
    – cjs
    Mar 28, 2020 at 0:57
  • I think the description in the manual is actually confusing things, I need to read the source code a bit more to clarify a couple of bits and pieces and then I'll edit this a bit more.
    – PeterI
    Mar 28, 2020 at 8:46
  • I have one more bit of code to port on this and then I will have a fuller explanation PCL/H zero page locations are involved as well.
    – PeterI
    Mar 30, 2020 at 10:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .