Reading the 6502 Break Mark – And, how fast was the 6502 back in the day?

As is indicated, the most typical use for the break instruction is during program debugging. …

When I saw you brought this up, this is along the lines of what I was thinking. I’ve done 6502 assembly on the Atari (through emulation). I use BRK just to stop execution of my assembly program, because I don’t think there’s any other way to do it, unless you want to JMP back into the OS somewhere.

There is an END instruction in the assemblers I’ve used, but that’s just a directive to the assembler to stop. It doesn’t insert any termination code in your program.

Though, BRK happens automatically if your termination point is the last byte in your program, since the memory after that is typically all zeros, and the CPU reads that as BRK.

This seems to be the preferred method of ending execution of your machine language program on the Atari. When I’ve used it, control returns back to whatever started my program’s execution (the assembler, or DOS). Though, it is interesting to learn that it’s actually used as a kind of interrupt, and that there are a bunch of things that need to be done to “read” what was actually intended with it.

I also assumed for a while that BRK was used by software debuggers as a means to step through each line of your assembly code as your program executes. Though, I’ve started to wonder if the debuggers I’ve used aren’t actually using a regularly invoked interrupt to do this. I got suspicious of this when I tried to use a VBI (vertical blank interrupt) in my assembly code, and the assembler quietly disallowed it (no warning, no error, no nothing. The vector redirect to my code was ignored, and I only got it to work by rebooting the machine without running the assembler). This finally gave me a clue as to why 8-bit programmers wanted a machine monitor. The emulator I use has a monitor function, and I’ve used it quite a bit!

1 Like

As I understand it, the professional debugging tool in the day was a logic analyzer, which would provide timing and data diagrams directly from the hardware. (E.g., this was used to trace and debug Atari VCS/2600 games.)

Regarding that vertical blank interrupt, another possibility may be that it came just a bit to late. Typically, 8-bit systems set them on their own to manage things involving the video RAM and to address I/O tasks, like reading the keyboard. And, one of the first things this interrupt routine will do is setting the interrupt disable bit. It could have well been that your interrupt was set just after the system interrupt (or whatever was listening for this) and was thus missed.

On the Atari, there’s an OS routine for setting the VBI vector, since it’s a two-byte address, and the vector gets used frequently (every 60th of a second). The OS routine is there to set the bytes at just the right time, to avoid a system crash. That’s what I use.

There was no inconsistency in the behavior. Any time I tried to set the vector from within the assembler, the set-vector action was ignored, and my VBI handler never got called. If I took out the assembler, and just loaded and ran the code from DOS, the vector got set, and the VBI handler was called.

I don’t know, but what I suspect is that the assembler has its own VBI handler it uses for some function, and it does not allow the vector to be reset.

I know a little about how the logic goes. There are two phases to the VBI, each using different vectors. The first phase is usually not used (I recall it’s used if you want to do some I/O with DOS, or interact with some other system functions), and doesn’t allow many cycles to be used (3,000 IIRC). The second phase is what’s usually used by programmers (what I’ve used), and is very generous with cycles, 10,000. The OS does a little housekeeping before the first and second phases, and then control returns to the OS after the second phase is finished (you do a JMP to an OS routine at the end of each phase).

Interestingly, what I read is, “The longer your VBI routine takes to execute, the slower your program executes.” Reading more about how the display chip (Antic) in the Atari operates gave me a clue about this. It shares the address bus with the 6502. So, when Antic is drawing the screen, it sends a halt signal to the 6502 (except when a DLI (display list interrupt) is active), so it can read the current display list, and screen memory. Once the screen is drawn, the 6502 resumes address bus control, and that’s when the VBI is triggered, while the electron gun resets to the upper-left corner, to draw the next frame. So, what really happens is most of your program logic is executed during this vertical blank cycle, some of the time of which may be taken up by a VBI handler! Interesting stuff.

That’s interesting information on the VBI vector on Atari computers. I guess, this is really a matter of how the assembler is implemented in the emulator. (It seems, this trap is implemented in the emulation and not in the emulated machine, as I don’t see, how this override would work on a real machine. Am I missing anything?)

Regarding the Antic chip halting the CPU, this is a special feature of the 6502C “SALLY”, which comes with an extra pin connection for this halt signal.
(This is replicating a scheme already found in the VCS/2600, where you can instruct the TIA chip to halt the CPU until the next horizontal blank in order to synchronize the CPU with the trace of the screen image. In the VCS, however, this was implemented by the TIA chip providing the clock pulses for the CPU. What’s interesting about these designs in a more general sense is that the CPU is not that central – as in a von Neumann architectural sense of the term – but more a “slave” to the display hardware.)

This was how the real Atari worked, as well.

It seems like the order of execution on it really is: The vertical blank interrupt actually calls an OS housekeeping routine. Optional user routines are run during this process (what’s called “the VBI” to us programmers). Once OS housekeeping is done, the program counter goes back to executing the main user program, wherever it left off, for the remainder of the vertical blank period. Once that cycle ends, the CPU is turned off by Antic, and it takes over to draw the screen. Once that’s done, the vertical blank is triggered, which takes the program counter back to the same entry point in the OS, taking the cycle back to where this started.

The part of the VBI you get to use (I’m referring to the VBI vector I talked about) looks to me like a system hook, in reality, since the OS is the one that calls it, not the CPU (the CPU interrupt vector is actually set to call the OS routine).

Yes, it’s reminiscent of how the 2600 operated. The game logic was executed during the vertical blank, but each frame of the game screen was also drawn by your code, line by line, as the screen was being drawn.

I’ve listened to the history Joe Decuir gave for designing the Atari 400 and 800, and he said the 400 was originally intended to be Atari’s next video game console, to replace the 2600. The reason Atari added a keyboard to it was solely because one of Atari’s engineers created the game “Star Raiders” during the computer’s early development. The game required keyboard input. Atari’s executives were so impressed with it that they added a membrane keyboard to the 400’s design just so people could play that game on it.

My impression from looking at the architecture is that the Antic chip was supposed to make designing games easier for developers, because now they didn’t have to worry about drawing the screen line by line, since the Antic chip would do that work for them. The CTIA/GTIA chip handled the hardware sprites and character set rendering, IIRC. It also managed the color palette. Knowing the history of the 2600, I can see that the concept for these chips came out of what they learned from creating the 2600’s TIA chip.

Many years ago, the Antic, GTIA, and Pokey chips were described in such a way that gave me the impression they worked concurrently with the CPU. They were described as “taking a load off of the CPU.” While that’s technically true, because they do work that the CPU would otherwise have to do, they don’t work concurrently, since they all share the same bus. It’s really like they work in shifts. Once the handoff happens, the other chips “take a nap.”

“IRQ / NMI / reset done internally with the BRK circuit” suggests that the circuit was designed to handle IRQ / NMI and reset, and then BRK overlayed on top with the minimum of additional logic. Since the interrupts push the P register to the stack, setting the BRK recognition in what was pushed into the stack is plausible as the “least additional logic”.

Of course, it’s a least logic added to the whole SYSTEM, so the RTI needs to use the same logic as RTS return, so the return vector has to be the ordinary JSR return vector, pointing to the last byte of the JSR instruction, not the first byte of the following instruction. Therefore, to have the interrupts push the equivalent address on the stack, the circuitry that checks interrupt status to trigger the interrupt circuit has to occur before the PC is incremented to pre-fetch the following instruction.

So the Occam’s Razor explanation for the “signature byte” is that at the point that the BRK process is EXECUTED, the PC happens to already be pointing to the byte following the BRK opcode, so that is the PC address pushed onto the stack by the BRK opcode, so that just from not adding any circuitry to decrement the PC before pushing it, the result is that an RTI{+} would return to the second address after the BRK opcode.

{+ Or if you pull the P register from the stack to check for BRK and only replace it on the stack on the IRQ leg of the process, an RTS}