In May last year I wrote a forum post on Proboard (interrupt-driven-wangle). I always wanted to write a little bit in more detail about it, but somehow never did. Probably because of Vectorblade.
Wangle is a “game” by Graham Toal, which amongst other things has to do some intensive calculations. With intensive I mean in the range of a couple of hundred THOUSAND 6809 cycles.
The game itself worked nonetheless quite well, but it had some “screen blanking” during those calculation phases.
Now Graham and I had been talking about interrupt driven Vectrex output before (3 years before Wangle display-lists-direct-drawing) – and that game and the circumstances brought it back to our thoughts (routines-suspend-using-timer-interrupts and interrupt-driven-wangle)
The original discussion was about to build a programming environment using “C” in which an aspiring vectrex programmer would be able to “dispatch” drawings to a (vectrex-) software modul, which would represent some sort of DVG (Digital Vector Generator) unit (like in the arcade machines) – which would run in a different “thread” – and would thus seperate the vectrex “drawing” from the vectrex “programming”.
I did some sort of protoype (see links in forum), but somehow the project was lost in time and space.
(But IMHO the whole technique was more an experiment in what could be done, rather than a usable approach to vectrex programming).
Anyway, with Wangle in mind it would be good to:
- realize complex computations which take more than a usual vectrex round
- at the same time being able to display the “last completely computed output”
The 6809 CPU is not capable of multiple parallel working threads such as todays processors. The 6809 can only follow “serial” instruction flows.
However the 6809 is capapable of so called interrupts. As the name suggests an “interrupt” is an unplanned discontinuation of the current program flow.
Usually the states of all registers are saved, the program counter is set to a predefined position, the interrupt “program” is executed, the registers are restored to the settings before the interrupt occured and the program continues at exactly the same position where it was interrupted.
Causes for interrupts can include:
– timer reaches zero (periphal interrupts)
– user action (e.g. button press)
– programmed (software interrupts)
The different reasons for interrupts are handled by different program parts. These parts are usually called “interrupt handlers“.
The vectrex BIOS alows us to configure these interrupt handlers using special RAM locations.
Further for easier handling the 6809 processor has a special “interrupt flag” that by switching alows it to either ignore interrupts or to accept interrupts.
During interrupt “handling” usually all further interrupts are disabled.
Interlude: Vector drawing
Drawing vectors with the vectrex hardware needs to be very exact!
Depending on the circumstances the user can discern when vectors are drawn with a difference in the timing frame of only one processor cycle – 1/ 1500000 of a second!
Amongst other things – this means the programmer MUST ensure, that vector drawing is never “interrupted” otherwise a clean display can not be guaranteed.
Per default the BIOS and nearly all Vectrex programs have interrupts disabled – otherwise the clean display would suffer!
(Exceptions to the rule: Lightpen programs, 3d-imager programs)
Back to our “problem” – a little visualization:
With the explained background:
The plan to realize the above goes as follows:
- all vectrex output (vectors) is realized within an interrupt handler (which can not be interrupted and thus is able to cleanly display)
- the computation is realized as the main program, which can be interrupted
The program parts than execute as follows:
The execution “style” might be a bit counter intuitive. First initialization:
- initialize the program
– configure timer T2 to issue an interrupt when it reaches zero
(T2 times one vectrex round)
– set interrupt handler
– configure the 6809 processor to enable interrupts
– start main program
One vectrex “round” goes like this:
- the main program only computes “new values” and finished with a statement, that “waits for the next interrupt” (or gets interrupted during coomputation)
- while the main program executes it is interrupted each time the timer T2 reaches zero
- than it displays all vectors within the interrupt, when finished displaying
- it returns from the interrupt
- and thus continues the main program
Did I mention that we did all that in “C”?
… and a link to the proboard post, which includes a link to the sourcecode:
In wangle I set the vectrex round to be slower than 50Hz.
It must be assured, that the interrupt handler takes less time than one round – otherwise the computation would never finish!
Yes that’s a nice trick, I’m surprised it hasn’t been used more often, though I guess most arcade games don’t have long processes whilst still being interactive. I did a poor-mans multitasking hack with my Forth. At the terminal command prompt, the interpreter waits for a key press i.e. you’re entering commands. If there isn’t one (usual condition), it runs the main loop of the program once. If there is a key press, it puts it into the text input buffer – very quick process. Only when you hit Enter does Forth start executing what was typed (which would normally take much more than 50,000 cycles and the screen would blank). The code to do this hack is probably half a dozen words. Why do this? It allows you to inspect/modify RAM, dump out the serial port etc. in real-time, whilst your program is still running! If you were running a program from RAM (e.g. VecFever or early VecMulti), you could even change that program, whilst it was running. (Not sure how useful it would be, though!)
This is roughly what Battlezone does; I think it would work well with Stramash Zone on the Vectrex – screen update on a regular schedule, with computation taking maybe 2 frames worth of time for every one frame output. I never did put this logic into the released version of Wangle because the delay between moving a node and seeing the updated status was quite long and a little confusing. But the method is sound and I’m sure we’ll use it in another game someday. If the Vectrex had a *lot* more RAM, and we could save actual vectors in a double-buffer for redrawing later like an actual AVG/DVG but with the small amount of RAM available, that’s not practical.
The next iteration of my Forth serial port cart will probably have an 8k RAM option somewhere between $8000 and $BFFF, which would probably do the job for an interrupt-driven vector generator. It’d be useful for extending the Forth dictionary or any other program that needs more RAM (e.g. my current project).
I added Wangle and Wangle IRQ to VEXTREME v0.4 and I definitely prefer the IRQ version because it doesn’t blank out after each move. Even though you must understand there is a delay while it’s calculating, it’s much nicer to not have the screen constantly blanking out after each move while it calculates the nodes.