Prof. Dr. rer. nat. Peer Johannsen

Weird Science - Tales from the Vectrex Academy Lab

Vectrex Project Title

  • An analysis of the original BEDLAM cartridge and source code

Project Status

  • Ongoing research

Synopsis

  • Digital Archeology - An investigation of the Bedlam cartridge
  • In a more general discussion of Vectrex wobble and flicker (see here), Malban mentioned that several of the original GCE games deliberately set the refresh timer to a value other than 50Hz. One of those games is Bedlam, running at ~30Hz, which results in a noticeable flicker on real consoles. I became interested in why that specific framerate was chosen in Bedlam. Especially, because in comparison to other games, there are not that many things drawn on the screen. So why such a low framerate?
  • Here is a summary of some interesting, yet probably utterly useless findings...

An analysis of the BEDLAM source code

  • These findings are deductions (and some speculations) based on a full disassembly of the original Bedlam cartridge code.
  • First of all, let me emphasize that I really like Bedlam. Liked it as a child, and still like it today. It was and still is one of my absolute favorite Vectrex games. And I hold the highest respect for all the designers and programmers who worked on the original Vectrex games back in the Eighties, and who were using development environments which are completely different than those of our modern times. So, if some of what I write here might sound negative or presumptuous, it is not meant like that at all.
  • The game code uses some strange(?) timing design. An interrupt handler routine for the refresh timer T2 is set up. The main action loop does not contain a Wait_Recal() call, but at some point halts by means of the "cwai" instruction and then waits for the T2 interrupt to fire. Then, inside the interrupt handler routine, Wait_Recal() is called, which does not make any sense at all, since the timer has already expired at this point, and there is no need for a Wait(). At this point, the wait loop immediately exits, and a mere Recalibrate() would have been sufficient. Also, all the other stuff done by the interrupt handler could just as well have been done in the main action loop, with a Wait_Recal() in place there. I tested that, and it works just the same. Well, actually, quicker.
  • I do not understand why such a complicated interrupt design was implemented, especially as it wastes some amount of CPU cycles for saving and restoring the processor state when servicing the interrupt routine. The interrupt handler also sets up its own distinct stack space, and on exit restores the stack to its entry state. Again, this is unnecessary and wastes some more CPU cycles.
  • The T2 refresh timer is set the odd value of 49407. Why? I do not know. A proper 30Hz would correspond to a value of 50000 (yes, minus some few cycles to account for the polling instructions, but certainly not minus 593 cycles). I have two theories on that: Either they simply tweaked this value until the resulting speed of the game action felt right, posing an acceptable challenge to the players (and customers). Or this is some kind of inside joke, as 49407 decimal corresponds C0FF hex, which could be read as "coff(ee)" ;-)
  • The interrupt design is the reason why Bedlam's cycle count shows up in Vide as a more or less constant 50000 cycles. When changed to a regular non-interrupt Wait_Recal() design, one gets much more accurate readings of how many cycles are effectively used for game logic and drawing. Bedlam averages around 33.000 cycles during the first stage, with some peaks going as high as 42000 cycles. The next stages avarage around 35.000 to 38.000 cycles.
  • I wrote a patched version, using a regular Wait_Recal() loop design, with the framerate set to the standard 50Hz. Wow, that looks great on a real console, almost no flicker! But also the speed of the action is now much faster, making the game really hard and even more challenging.
  • While disassembling and analyzing the source code, I noticed several things I have listed below. I think that the code can be optimized in various placed in order to come close to a true 50Hz framerate. I will likely do some of this and then put out some kind of "Speedlam" version. Update: done, see section below.
  • Several lines of assembly code can easily be optimized. Short branches instead of long branches, no need to reload a reg with the same value if the reg has not changed, "puls x + rts" can be combined to "puls x,pc", etc. Another example: "clrb + decb" is  quicker achieved by "ldb #$ff". Same with: "clra + coma". And "sta $00,y" is quicker done by "sta ,y". And all this is not done to achieve some specific timing, or to manipulate the processor flags in special ways. And there are many more examples of such type. Maybe it is just me not seeing the reasons for this. Or maybe the programmer was not yet that experienced at 6809 coding?
  • For storing the level number information, a 7(!) character score string is used and printed (separately) on the screen. Did anyone ever reach a 2-digit level in Bedlam? This printing wastes a lot of cycles, printing all the blank characters. Room for improvement.
  • The game just uses the X-axis of controller 1 only. However, the Y-axis, and also controller 2, are not disabled and also evaluated in each call of Joy_Digital(), wasting several hundred cycles in each round. Room for improvement.
  • All vector rotations are computed on-the-fly by means of Rot_VL_dft(), which explains where lots of the CPU cycles go. I think that precomputing and storing the vectors in ROM tables was not an option in those days, as ROM space was still rather expensive. However, the walls of the playfield are all computed (rotated) and drawn separately. This could have been done more efficiently with a one-go rotation of a complete vector list, and then also a one-go drawing of a complete vector list.
  • There is a by now well known easter egg hidden in Bedlam. Press buttons 1+2+4 during and until the end of the title screen, and then a short message will appear telling you the name of the programmer, accompanied by a dixie melody. Quite some effort was taken to hide this message in the ROM code. The ascii text has been XOR coded, so that it cannot easily be read in a hex monitor. It is copied and decoded to RAM before it is then displayed on the screen.
  • The small life-icons are actually drawn at different scales (4,3,2), depending on how many lifes are left (3,2,1). However, at such tiny scales, this goes (almost) unnoticed, and I wonder, if this was intended, as the corresponding part of code is unnecessarily complicated and also contains redundant instructions.
  • I never noticed that until I saw it in the code. As long as the zap weapon is still available, there is a small dot drawn inside the cannon.
  • The code also contains some dead code (functions that are not used), and also some dead data. There is a short melody which is apparently not used throughout the whole game. There are also two additional, but unused sound handlers. One implements an alternate firing sound, and the other one a background ringing noise.
  • The RAM is highly fragmented and not used contiguously, but with several gaps between chunks of used bytes. No idea why they did not simply put all their RAM data in sequence, just one after the other.
  • The code writes some RAM locations which are never read (and never used). There is also a counter set up, counting down in steps of 10, which is also not used at all for anything.
  • Some trivia: Up to 4 shots can be fired at once, and up to 6 enemies can be present on the screen.
  • To be continued. Comments are welcome!

Source Code

  • Annotated bedlam source code: bedlam.s
  • Though almost fully analyzed and commented, this is still ongoing work. I did no make the code disassembly beautiful in any way. Some comments might be outdated. If you spot any mistakes, or if you have additional insight, please let me know.

Patched 50Hz Version

  • Patched 50Hz Bedlam version: bedlam_50hz.bin, contains the following modifications:
  • Interrupt scheme changed to standard Wait_Recal() loop, refresh rate set to 50Hz
  • Title text changed to "Bedlam 50Hz"
  • Title melody changed to unused melody hidden in the source code
  • Firing sound changed to unused alternate firing sound hidden in the source code
  • Background sound changed to unused alternate background sound hidden in the source code
  • Only X-axis of controller 1 is evaluated (speedup)
  • Printing of level message and level number combined (speedup)
  • Redundant stack scheme removed (speedup), unused counter removed (speedup)
  • Drawing of tiny life icons simplified (speedup)
  • Lots of low-level code optimizations, replacing instructions by quicker alternatives (speedup)
  • I strongly suggest that you play this on a real console, and that you play the original Bedlam first and then this patched version, in order to fully experience the difference. Let me know what you think!
  • Downloads are free and for non commercial use only. Use at your own risk.
  • Please respect the copyright and credit the author and the origin of this game.

Online Playing

  • Link to Dr. Snuggles' online emulator to directly play the game in your browser: Bedlam 50Hz
  • For comparison (though comparing this on real consoles is much more telling): original Bedlam

Author

  • Peer Johannsen

Latest modification on 06/31/2024, 09:30
  • Page updated