CRT Collective: APEX 27" AT2704S (June 2003)

(This is part of an ongoing effort to document the various CRT monitors and televisions that I acquire, with information that may be of relevance to others who Google the same model!)

This is a fairly bulky 27" curved television set, and one of the rare instances where it feels as back-heavy as it does front-heavy. It has spring-loaded side handles to make lugging it around marginally more bearable. The set weighs 88 pounds and measures 29.5 x 23.2 x 18.7 inches (852 x 692 x 580 mm). Internally it houses 5W stereo speakers. No component inputs, but it does have three composite inputs on the back and a fourth on the front, as well as s-video. The s-video signal is shared with the bottom-most composite input (Video 3) on the back. So for audio out while on the s-video input, you will want to connect the stereo cables to the bottom set of jacks on the back. There is also a composite output to feed another device. Read Full Article

Bally Arcade: Vintage Computing Christmas Challenge 2022 Breakdown


The Bally Arcade / Bally Astrocade / Bally Professional Arcade was an ambitious home computer and video game console combo released in 1978. It sported a 24-button calculator keypad, four joystick ports, a ROM with four built-in applications (Gunfight, Checkmate, Calculator, Scribbling), a light-pen connector and expansion bus and 256 possible colors (8 simultaneous or 2 in BASIC). The joysticks included a trigger button, directional joystick and a 256-position analog wheel on top. Unfortunately, the system was plagued by delays and manufacturing shuffles and never caught on compared to other systems at the time. Several planned add-ons and expansions never came to be, or were only produced through third parties including a full-featured keyboard. It made a cameo appearance in National Lampoon's Vacation and a few catalog appearances, but didn't get a lot of media fanfare beyond that. However, for many years there existed a very devoted group of users, newsletters and more.

45 years later, the system still has a small but ambitious group of enthusiasts involved in the preservation and advancement of the system. Major shout-out to Adam Trionfo and Paul Thacker who have done an incredible job scanning and preserving all artifacts of Bally on Much of the archives originate from the Bob Fabris collection, who ran the largest newsletter Arcadian for years and generously offered tens of gigabytes of materials for preservation. This is the polar opposite of many vintage systems where almost all traces of documentation have been lost or remain in some dusty corner of a basement.

Bally was impressive in that it packed a lot of functionality into a variant of Palo Alto Tiny Basic that also brought native BASIC support for interfacing with the controllers (including the analog dial), multi-voice sound control, a LINE and BOX command with several effect options and several other features that on other platforms required manual PEEK/POKE operations (Bally BASIC also supported poking and peeking including across the entire ROM to tap into handy machine language features). The system only had 4K of internal RAM and only 1.8KB available for user space, which is shared with the screen memory. This is achieved through some clever interweaving of both BASIC code and display output on even/odd bits. This limitation reduced the display possibilities to a single background and foreground and cut out some other advantages of raw machine language.

Vintage Computing Christmas Challenge 2022

The 2022 annual BASIC challenge by Logiker proved very popular, with many users working out an implementation of a Christmas star across many varieties of BASIC. The core objective was to reproduce the above 17x17 star pattern in as minimal code as possible. It was fun and educational to watch the evolutions and iterations of entries recreating the exact pattern above — the grand winner replicated it on a ZX81 in just 27 bytes thanks to its innovative single-byte commands. In fact, Bally replicates that one-byte command functionality for most of its limited BASIC commands, in the interest of both simplifying the typing on a calculator keypad and reducing the consumed space.

While the vast majority focused on the core competition, I grew more interested in the "wild" category. This wasn't part of the real challenge but allowed creative interpretation of the design without fixating on length or exact replication. Bally BASIC had been forgotten and I thought this would make a fun exercise to get my feet wet on this 1970s variant of BASIC. The wild category made sense to me since Bally BASIC doesn't even support enough on-screen lines to fit the original star without scrolling. But also because I wanted to see the potential of Bally's built-in graphic functionality.

You can see a video rundown of the snowflake challenge entrants above. My Bally contribution kicks in around 18:20. The live chat shows a few people enjoyed it as it played: "wow... awww cute... very nice..." The host of the challenge, Logiker, also said it was his first discovery of the Bally Astrocade and he enjoyed researching about it: "This is a fantastic release. To be honest, at the beginning, I even didn't know what a Bally Astrocade was. And now seeing how you have to type in the program: just wow! That's nostalgic pure!"

Bally Snowflake Entry: Line-by-Line

Line 1: Comment

In Bally BASIC, comments are designated with a . as the first character following the line number and optional space. This differs from most variants that opted for REM but also makes a lot of sense in the interest of saving precious bytes of space.

Line 10: Variable Declarations and Clear

The BC and FC variables are built-in to Bally BASIC and represent the background color and foreground color. Bally has 256 possible colors, but in vanilla BASIC you can only select a singular ink and paper for the entire screen display. The screen immediately updates whenever either of these values are updated, opening the doors from some interesting transitions and effects from the large bank of available colors. For the initial appearance I use a red background color (0x48 = 72) and black foreground color. The best way to review the Bally colors is through the Astrocade Pallette available on Bally Alley (you'll have to convert the hex values to decimal).

The D variable is indicative of the initial draw mode. The LINE and BOX commands available in Bally BASIC support four different draw effects passed as the final parameter:

  • 1: Draw using foreground color (FC)
  • 2: Draw using background color (BC)
  • 3: Draw using reverse color (inverts whatever is drawn over)
  • 4: Draw using no color (useful for moving the point without drawing).

The variable is the initial step size that the start shape will be drawn at, essentially how many pixels of blank padding will appear between each iteration.

Both D and the will be randomized later on to create the everlasting animated appearance.

Lines 20-70: Defining the Basic Star Pattern

This section rather cryptically defines the mathematical pattern of the overall shape. I first brainstormed how the star could be reduced down to some basic repeating values and symmetry based on the mannerisms of the LINE operation.

In the world of Bally, coordinate (0, 0) is the center of the screen. The horizontal (X) bounds run from -80 LEFT to 79 RIGHT, while the vertical (Y) bounds run from 43 TOP to -44 BOTTOM. The LINE command begins in the center of the screen at (0, 0), or where the previous line ended unless manually set beforehand. The destination points are also relative to the center origin of (0, 0). With that in mind, I picked an arbitrary start point for the star. I decided to start from the right-center and drawing up and around, counter-clockwise. So the numbers below indicate the X/Y offset from the start point to draw the top half of the star in its smallest form factor.

  • X: 2, 1, 1, 0, -1, -1, -2, -1
  • Y: 1, 1, 2, 1, 2, 1, 1, 0

This can be likened to the old days of LOGO/TURTLE. To construct the basic design, consider we start at offset (1, 0). To draw the first diagonal bit of the star toward the top-right, we would use an offset of (2, 1).  From the end of that point, we'd draw to offset (1, 1) and from that to (1, 2) and so on based on the mapping above. When all eight offsets are drawn to, we'd have something similar to below, which completes one half of the star.

From the pattern above it becomes evident that we only need to store those eight values, and then reverse the order and multiply the Y axis by -1 to draw the bottom half.

I begin by creating a 7 value loop, which will iterate to store the offset data that we need. Even though it takes eight points to draw half the star, we can take some more shortcuts as will be described next.

Bally BASIC does not support AND/OR/THEN/ELSE operations. Instead, we can mimic that behavior by adding multiple IF statements to the same line. Line 30 instructs the program to run the computation of N=(I+1)/2 when I is 2-5, so it will not run on the first two nor the last iteration.

is a newly defined variable that at this point is not useful itself, but the computation it is assigned is. Based on the iteration, the result of this operand will be equal to 3/2 (1 remainder 1), 4/2 (2 remainder 0) and 5/2 (2 remainder 1) as the loop progresses. The remainders are the important part here, as described next.

Bally has two fixed arrays that can store integer values. They are defined as @() and *(); in the actual system the asterisk is a unique character separate from the multiplication symbol. The @() array consumes the space in memory directly following the BASIC program, while the *() array begins in the final available bytes of memory and goes in reverse order (so is less susceptible to being overwritten if the program expands). I utilize both of them, one for Y and one for X, starting with the @() array on line 40.

The RM variable is built into Bally BASIC and returns the remainder of the last division operation, in this case from in line 30. The division at line 30 divides (I+1) by 2 so the remainder will either be 0 or 1 depending on the iteration.

At the end of the final loop, the @() array will consist of: [1, 1, 2, 1, 2, 1, 1, 0]. This matches the Y plotted points brainstormed above, but without having to explicitly define each in code.

Line 50 utilizes the second available array and, starting from its 4th index on, assigns it the inverse of what had been assigned to the @() index in the preceding line. There's no reason why I couldn't had just used the @() array for all of this, except part of the challenge was thinking differently and stretching our BASIC interpreters as far as they can take us in the interest of potentially saving some bytes.

If we ignore the following line 60 for the moment, if the loop completed at this point the *() array would consist of: [0, 0, 0, 0, -1, -1, -2, 0]. You can see the second half of the array is beginning to match the second half of the X plotted points brainstormed above.

This line goes back and alters the first half of the second array that was skipped in line 50, starting with index 0 when I = 4. Here we directly assign the value stored in @(I) to *(I). This is part of the inverse pattern discovered previously. It only executes from interval 4-6 of the loop, so will only alter indices 0, 1 and 2. Since *(3) = 0 in our pattern, we didn't need to do anything with that spot.

With all of that said, the final *() array will consist of: [2, 1, 1, 0, -1, -1, -2, -1]. Success! We have successfully carved out the full X plotted points brainstormed above, and all of this was able to be done in just 7 loop iterations instead of 8 😉

This completes the loop. At the end of the cycle based on the above conditions and allocations, we have two arrays ready for use:

  • X PLOT POINTS: *() = [2, 1, 1, 0, -1, -1, -2, -1]
  • Y PLOT POINTS: @() = [1, 1, 2, 1, 2, 1, 1, 0]

Comparing the data above to the graph paper image previously, it starts to become clear how we will offset the line points by these values and a given multiplier to draw the star in any size we want.

Lines 80-150: Drawing the Star

With the heavy lifting done in the pattern calculation section previously, the subsequent lines put those points into action.

I decided arbitrarily to establish the outer loop from 2 to 21. This loop value U corresponds to the multiplier used for scaling the current iteration of the star shape. A value of will plot the first star as a small shape in the center of the screen, while the value of 21 will stretch the shape close to the boundaries of the available screen space, which is limited to 43-44 pixels above and below the center point. Depending on the step value (default 3) it will skip that number of pixels between each increasingly enlarging star shape to give it more interest than a purely solid star shape.

In line 90, the XY variable is assigned to the current loop iteration. XY is another in-house variable that Bally BASIC provides, and it corresponds to the position of the last LINE command. Likewise, it can be set to a new value to indicate where the next LINE command should start from.

Since XY uses a WORD value (double byte) it has to pack both the x and y coordinate into one. To quote from the manual, "=&0=&" I utilize this feature to offset the start of the line from center. Since I always begin drawing the star from the center-right, it is possible to assign XY the value of U which will set the start point to the matching coordinate to the immediate right of the (0, 0) center.

If you're looking to use this command to plot elsewhere on the screen where Y is not zero, it gets more sophisticated to calculate. An exhaustingly detailed guide on using XY and practical cases for it can be found in this XY Tutorial (PDF) by Timothy Hayes from 1980, courtesy of Bally Alley. An alternative approach to moving the line without drawing is to pass the value 4 as the end line parameter, but this is less performance optimal than direct XY assignment.

I reset to 0 so it can be used as a sort of multiplier to manage drawing the upper half and then the inversed lower half later on based on where we are in the loop.

The new variable M is also initialized as part of the upper-to-lower translation later on.

The inner loop consists of 16 interval segments to inclemently plot the X/Y data to the line command. Remember, we only defined eight values in the arrays so once we reach midway through the loop, we'll need to switch things up a little to draw the inverse for the lower half.

When I is greater than 7, it will have completed the eight line calls that comprise the upper half of the star. So we now inverse and M to be negative to influence the subsequent draw calls.

The magic of all lines, we finally have reached the LINE command itself. The syntax itself is simple, taking in a singular X, Y and D (draw mode) value.

  • X: *(I+(8*N))*U*M
  • Y: @(I+(8*N))*U*M
    • Both X and Y use the same formula for plotting.
    • (8*N) will equate to 0 for the first half of the loop, and -8 for the second half. We add this value to the current interval I to retrieve that value from the X plot array. Effectively, we are telling the program to go back to the beginning of the array to read it again for the lower half.
    • U will equate to the outer loop's current interval, and acts as a multiplier for the plotted coordinate/offset. If the outer loop is at 10, then each value in the *() array will be multiplied by 10 to scale the lines by that amount.
    • M is the end multiplier that will be either 1 or -1 depending on if we are on the first half or second half of the loop. Since the second half of the star is drawn in negative Y-space, multiplying everything by -1 when necessary gets us what we need.

    The D value at the end is what tells the line whether it should draw using the foreground color (1), background color (2), reverse the existing color (3), or don't draw anything (4). The default value is 1 because I always want to draw a baseline star when the program first runs.

    This line smoothly fades in the background from red to blue and the foreground from black to white, by incrementing FC and decrementing BC by a given amount with each iteration. This transition happens within moments as the first star is drawn, but adds a touch of polish. This line could easily be adapted to slowly evolve the background color, even cycling through all 256 colors with each star iteration, which could then act as a true screensaver without fear of color burn-in on the old style CRTs!

    Alas, we repeat the inner loop followed by the outer loop. This order ensures that all 16 strokes for the given star are drawn before the radius is expanded and the next one begins. This will repeat while U is 21 or less.

    Line 160: A Flair of Randomness

    As the program concludes, I give the value of D (draw mode) a random value between 1 and 4, and (star radius step size) a random value between 2 and 11. The RND() command in Bally BASIC will range from 1 to the value passed, inclusively. It's always worth checking any BASIC or non-BASIC variant for how the randomizer works, as many are 0-based or exclusive to the value passed.

    Initially I had constrained the D value to between 1 and 3 so that every cycle would either draw, invert or erase. But I found that allowing for the invisible line mode enabled the design to stick around for a while on occasion before morphing into another style, which I found more elegant.

    The combination of these draw effect modes and varying step size leads to some really nice glistening-style snowflake designs. At times when the mode is inverted there will even leave residual snowflake particles in or around the overall star shape, which makes for a creative appearance.

    Line 170: Repeat Endlessly

    The final line of the program sends the user back to line 80 to begin the drawing cycle all over again. The program can be halted by pressing the HALT key on the keypad, which is located on the same key as RUN.

    Cassette Saving Characteristics

    The original iteration of Bally BASIC used the common Kansas City Standard 300 baud transmission rate to save and load data from ordinary cassettes. It had a separate interface adapter that plugged into the light gun and 3rd person controller port. You'd hook an ordinary cassette recorder into the IN/OUT ports to write data and read it back. The revamped version known as Astro BASIC  (or AstroBASIC) supported the much faster 2000 baud transmission speed and had an all-inclusive interface that ran directly from the BASIC cartridge. One mild inconvenience with it is that you have to swap connectors if you are reading or writing, as it has only a single 3.5mm jack.

    Input/Output Commands

    Writing data is done by pressing record on the cassette player, and then executing the :PRINT command. The colon in front signals to send the data to the interface out, rather than the screen. This transmits the data to the cassette and returns to the cursor prompt when complete. Bally even included a form of data verification, if you run the command :INPUT and then play the saved cassette data back, it will compare the checksum to your code and alert you with a '?' if there are any data inconsistencies.

    Reading the data is done similarly, except you call the command :INPUT and then play the cassette back with its audio out jack connected to the Bally BASIC interface. In the 300 baud version of BASIC, the data lists in real-time as it loads so you can quickly detect any errors caused by improper volume or other circumstances. The 2000 baud version loads everything invisibly.

    The original version of Bally BASIC also had a :RETURN option to automatically stop the cassette interface when that command was reached. Developers would include this at the start of their program. If a user would then load the program using ":INPUT;RUN" it'd load everything and then run, while stopping the interface automatically.

    Astro BASIC also introduced a :RUN option for loading machine language applications more easily. "The load will begin at the top of the screen (4000H or 16384D). When the load is completed control will be transferred to this first address. The block loaded is limited in size only by the need to avoid interference with the stack area."

    Screen Capturing

    Since the BASIC code and screen data share the same memory address within the Bally (interleaving even and odd bits), saving the data to cassette transfers all of those bytes over as-is. This means that anything on the visible screen when saving the data will be reflected when you reload the program. At 2000 baud, this takes around 20 seconds, or more than two minutes at 300 baud.

    As the data loads, the screen will update in real-time with whatever bytes have been fetched. This incidental effect results in developers being able to get more creative and display a title or loading screen of sorts, before the user runs the app. This can be used to display instructions, graphics or other elements as part of the data load itself. A similar technique exists on the Interact Home Computer, where cassette data first loads a title screen as part of the memory dump before loading and executing the actual program.

    I use it in the Bally Snowflake program to display a red/green color combination and one of the snowflakes generated from the program. I achieved this simply by running the program, halting it when a desired shape was on screen, and then entering the commands seen in the load screen. You can get much more crafty than this, by embedding the :PRINT command within part of the code execution so it doesn't appear on the screen itself. I could had triggered a cleaner end by wrapping the follow commands into a line on a manual trigger from the running program: "BC=72; FC=165; :PRINT" and then you'd only see the star in the final output. But I also felt it was cool to see a few artifacts like that as part of the initial load.


    Typing on the original 24-key calculator pad on the Bally is not the most enduring of experiences. For development of this program, I relied largely on MAME and as part of it began developing a front-end keypad that would allow more natural keyboard input than what's currently possible. I also created a custom 24-key control pad overlay for the Genovation CP24 that I could hook to my computer and map to MAME's inputs to facilitate a somewhat more comforting but not any less tedious vanilla typing experience.
    In the video above, you can see me coding this entire program out using my custom vinyl control pad. The woodgrain trim came from Walmart for under $10 as shelf wrap, which I fed into a thrift find and subsequently "hacked" Cricut to print custom vector that conformed to the pad. I 3D printed the text on another second hand Resin printer.

    In the works is a front-end keypad that I am currently developing and testing in-house for use on MAME. It will support:

    • The full 24-key emulation just like the real machine
    • Single-click direct entry so you can click on any symbol or command without having to first press a SHIFT modifier.
    • Direct line input where you can type a line on your normal keyboard and press ENTER to send it to MAME.
    • Batch script execution where you can type or paste in multiple lines into a text area and send it to the emulator.

    This is quite a revolutionary enhancement to what previously required archaic coding mechanisms. One exception are the useful but generally dated tools for 300 baud typing and conversion available on Bally Alley. Not all of them will run on 64-bit operating systems and some are DOS or command-line based. I used those tools when porting an old type-in (Munch) to 300 baud, in addition to my own front-end for porting and saving via 2000 baud Astro BASIC in MAME. The emulator supports 2000 baud cassette emulation including saving and playback for making clean digital WAV files, but lacks a 300 baud feature set.

    More on this front-end interface in another blog post.

    If you're interested in the full bundle of my Bally Snowflake entry with additional documentation and the WAV file to play on a real or emulated device, you'll find it over here:


Retro Fix: Packard Bell Platinum Pro 755 (1996-1997)

The first Windows-based PC I was introduced to in the early-1990s was a Packard Bell Legend 660 or comparable. It had the Microsoft Entertainment Pack 2 bundle featuring Rodent's Revenge and Rattler Race, two games I grew very fond of and would later develop a few games and variants heavily inspired by that. In that era I'd often ride my bike to the local Radio Shack to top the scores on their demonstration computers.

Decades later, I still appreciate that creative age of desktop computing even if these systems are collectively referred to as "Packard Hell" by select groups. At some point in time I found a Packard Bell Platinum Pro 750/755 tower on the curb to giveaway. I brought it back and eventually set it up in another retro corner. Since I planned to use it as an intermediary machine for creating and archiving old floppy media, I swapped out the Iomega zip drive with a 5.25" drive instead, knowing I also have some external ZIP drives if ever needed (although zip disks were short-lived and notoriously prone to click-of-death failure). Read Full Article

Retro Exploration: MDT-870 Mobile Data Terminal (1986-1996)

I recently impulse bought an ElectroCom Communication Systems MDT-870 radio car terminal for $5 at a surplus sale. Never knew much about these sort of computers but learned a lot since, and yet remain largely in the dark about this particular model given the complete absence of any documentation or schematics online.

This model in particular was common in squad cars in the 1980s-1990s. Some metadata extracted from a ROM that I dumped when troubleshooting indicated "COPYRIGHT 1986-1996 ELECTROCOM AUTOMATION INC." and the particular ROM in this unit had a generation date of March 25, 1996. Based on this, the department may well have used it for the better part of a decade before phasing it out in favor of more contemporary solutions.

This exact model appears in an early scene of Terminator 2: Judgment Day, where T-1000 uses it within a police car to query the details of John Connor. Having now used the real device the movie depicts, other than the simulated sound effects in the film the actual on-screen display appears to have been produced and filmed on the actual MDT-870. Of course the one on the set was not wired to actual police databases, but the text on it was typed within one of its free-type interfaces.

Initial Power-up and Short Glimmer of Life

When these were actively used, they had a variety of hookups to police radios, databases and similar. The one I received was barebones aside from some of the wiring that itself appeared cut and severed at various points. It runs on 2A 12V DC power, typically wired to the vehicle's battery/alternator. After a little bit of review I traced the original positive/negative wires and reworked them into a simple AC-DC power converter adapter and spliced a new cord to go along with it, from a typical computer adapter.

I was able to power up the unit and heard some remarkably 80s-sounding beeps as it booted up. It initially read "SIGNOFF ACCEPTED" and then took me to some integrated applications. This included a MEMO WRITER, QUERY DRIVER STATUS, and some others that I can't recall.

Alas, this was a short-lived effort as after typing some keystrokes and photographing the images above, something fizzled out and I lost all display and signs of activity.

Hardware Analysis

Unfortunately, not a single trace of documentation, schematics or ROM dumps for this system exist online. I found very few references to it at all. There were sporadic mentions of it appearing in movies, a fan-made STL model of the device citing Robocop 1, and other users looking for any documentation in hopes of setting one up in their own personal vehicles for nostalgia or show. I found one post from more than 15 years ago where someone did have the full gauntlet of schematics, programming guides, service manuals and even hardware-based interface adapters for PC communication. Alas I wasn't sure how to even approach contacting that user at this point in time.

Disassembly was not too difficult. In fact there exists plastic doors on the back of the unit for direct access and swapping of the CDVR and ROAM ROMs. The entire unit promotes itself as "Proudly Made in the U.S.A." Several of the ICs including all ROMs, CPU (OKI M80C85A-2 x2) and Graphics Controller (Intel P8725) were pre-socketed using machine pin sockets. I know many advocate for such sockets, but when wanting to quickly remove and replace ICs when troubleshooting and testing, I still find the flat leaf-type DIP sockets much easier to work with and less prone to bent and broken pins. That said, I did eventually swap the three machine pin sockets for the ROMs with leaf style to make my own life easier as I was burning and testing all of those ROMs continuously.

To actually get at the core ICs, you have to unscrew the back (and any brackets that may be attached) and carefully separate the two halves. The back half houses the small amber-lit Clinton Electronics 798P1NGLP picture tube and a simple speaker. Underneath this is the video sub-board and on the other side the main logic board. A ribbon cable transmits data from the logic board to the CRT board and ultimately into the display. The front half houses the membrane-based keyboard, LEDs, variable controls for adjusting Sound Volume, Light (Front LEDs) and Display Brightness. A side control also allows you to adjust the keyboard-based light brightness.

The system has two 80C85A CPUs (8085-based, the minor successor to 8080 and comparable to Z80 except with syntax I find to be much more cumbersome to decipher). The CRT is driven by the Intel 8275 (P8275) video controller. It has two banks of Sharp LH5168 CMOS SRAM and oneM81C55-5 CMOS SRAM a variety of other controllers and ICs. It also has a TMP82C55AP CMOS Programmable Peripheral InterfaceI noticed pin one of the uppermost CPU was bent underneath itself when inspecting the chips, but that didn't seem to have any impact.

ROM Summary and Dumps

There are three ROMs installed in the logic board, with only one of them providing a checksum value to compare clean ROM dumps. They are all programmed onto common 27CXX EPROM chips. Through trial and error, I made the following educated conclusions:

  • 502.87003.51 MDT870 CKSMC7B3 MDX-ROAM V2.2 (27C256) - This is the core ROM / OS. It is designed to interface with special frequencies/radios and other input/output devices for querying data, recording memos and otherwise communicating in a pre-mobile, pre-WWW era.
  • 501.64519.51 641.07910.00 V1.1 U4 CHRGEN (27C64)- This is the character generator. Mine wound up corrupt before I was even able to get a proper dump, so I am unaware of the precise layout of the original. However, after experimenting I was able to reconstruct a usable CGROM derived from the HD44780 controller after reversing and reordering them. If this chip is corrupt or removed from the set, the screen displays solid blocks as typical when no character generator exists.
  • 501.64520.51 641.07900.00 U16 V1.1 CDVR (27C64) - Originally I was unclear what CDVR stood for in this context. But it became clear as soon as I removed it from circuit that it is the CRT Driver. With it removed, the CRT cannot render anything but a high-pitch raster or several as if suffering vertical collapse.

I made ROM dumps of all three of these on my vintage EP-1 programmer. I verified the checksum of the ROAM firmware matched, but had no basis to compare the other two in the event they were corrupt. I later concluded the CHRGEN ROM had indeed corrupted for reasons unknown, whereby once I had fixed the display issues itself that chip would show mostly solid blocks and EPROMS I burned from the dump did the same. Trying the original in my more modern TL866-II programmer detected faulty pin(s), and comparing a dump made from it to any on either programmer always yielded errors. However, I'm confident the ROAM and CDVR dumps are functional and precise.

Below is a ZIP file containing the complete collection of ROM dumps I made in various formats (BIN, Intel Hex, Mitsubishi Hex and another format or two). It also includes my usable 2022-created character generator ROM, one variant with underlines and one without.

  • MDT-870 ROM Dumps .zip file (MDX-ROAM, CHRGEN [Corrupted], CDVR, CUSTOM CHRGEN 2022)

Character Generator Woes

After a lot of testing, trial and error I eventually wound up with a semi-bootable MDT-870 again. I believe there was one bad CPU, a few dry solder joints, at least one shorted/dislodged socket, and something astray in an SRAM chip (and am still not convinced the two SHARP chips are not damaged, this will take more testing).

The beep codes were back and the display was, well, showing something or other but basically all corruption.

I recognized even when typing that the glitches correlated to the keys typed, which is usually a sign of bad video RAM or a failed character generator. More testing of the original EPROM proved it to be a problem. I tried a fresh 2764 EPROM with the prior dump and experienced the same symptoms. Peaking into the ROM dump itself and I found almost entirely FFs or 00s, which definitely seemed peculiar compared to other ones I'm familiar with.

Typically character generators define the character sets using 8x8 (or 5x8 or 5x7 or some variant) where each single HEX value depicts one byte-row of character data. So FF would mean "fill in the entire row solid" and 00 would be "keep the entire row blank" but usually you'd see intermediary hex values, such as 3C to indicate "fill only the inner four bits) and this is how basic characters can be defined. Row-by-row. With this in mind, I created a dummy character generator filled with FFs but also randomly changed some values, as an experiment. This yielded the following:

That confirmed to me that the display problem was indeed just a wonky character generator. And, after some additional experimenting with patterns and characters I concluded the CGROM for this set is a pure data dump of constructed characters, it contained no additional logic or coding. This was fortunate as if it intermixed coding and byte data as some do it'd be vastly more difficult to guess the structure going forward.

I then went on a roundabout manner of creating some new character generator that'd at least satisfy the need to see what text is showing up on the screen. As a foundation I used the binary data constructs of the HD44780 and pasted them into a new binary file, repeating the entire set multiple times until padded at 01FF to match the original ROM size. When I tested this new ROM in the machine, I could tell we were headed down the right path.

Seen above was the initial run of a new character dump. I was in some input screen that allowed me to free type. The characters in the middle were me starting with ABC...890. You can see firstly how they are all inverted. This is because the CRT itself is mounted upside down then reflected off a tilted mirror to project through the front of the terminal. The other problem is that one letter gets skipped with each one I press. So A=B, B=D, C=F and so on. This was an immediate clue that the layout of the original CGROM repeated each character twice, AABBCC...889900. Eventually I realized that the most-significant bit (leftmost in a row of 8) determined whether the character would have an underline or not. If padded with "FF" there'd be an underline, otherwise there wouldn't be. This likely explains the need for replicated lines/characters. To my knowledge, lowercase characters were never displayable or included.

To resolve the reflected issue, I passed the binary format into a reverse line script. I then pass that into a binary-to-hex script. This could then be sit out into another binary file to appear the correct orientation when viewed through the terminal's mirrored screen. It was then a matter of comparing keystrokes with what the screen depicted, and swapping around the ordering to ultimately end up with a version depicting all characters successfully. You can see below how the mirror affects the display, both on the raw CRT and when viewed from the front with the redone character set.

It Lives Again, But How To Initialize?

Through the various iterations of it working, not-working then working again, any and all previously preserved data seems to have been wiped clean. Some of that likely happened while I was making contact with various pin-outs of the numerous memory-related ICs.

Before I had a proper character display again, I actually wound up with a different start screen. It would throw the error "NO HOME CHANNEL IN LIST" and then enter an empty typing screen. Periodically it would then interrupt with the error: "CHECK CONNECTIONS TO RADIO" Still, being able to type was interesting itself, at least it was something!

But after the final cleaning of the keyboard and another loss of power, then some more IC tinkering, the new screen is different once more. I'm not stuck at the "INITIALIZE MDT" screen and no characters have any affect.

It is evident based on the text data extracted from the ROM dump (see below) that the ROM has some internal way to define channels and so on. Somewhere in the code lies the string: PRESS "C" TO ENTER RAD. CHANNELS and related ones as well including ENTER RADIO CHANNELS and PRESS "X" TO EXIT. What I'm not sure of is how to achieve this, or if that by itself also requires interfacing with an external system.

If I make any further progress on this, I'll update this post. One interesting discovery worth checking into more thoroughly is the Open Hardware Driver for CRTs. This seems like a promising approach to easily hacking this or similar sets to display typical video output on its crisp amber display. "The driver circuit takes a 0-3.3V analog signal for deflecting the beam along the X and Y axis. The amplifier has enough bandwidth to handle NTSC video, so displaying video along with vector letters and shapes is also a possibility with this circuit."

Extracted Strings from ROM Dump Metadata

As part of the main ROM dump (502.87003.51 MDT870 CKSMC7B3 MDX-ROAM V2.2) I parsed through identified strings. They are included below, as well as their relative memory location at least as laid out in a decompiled Z80-derived version of the 8085 source. The fact that I was unable to find any references to the applications I had initially observed, may indicate that those along with the radio codes and data were still cached in some form of non-volatile memory but ultimately wiped out.

  • 0005: Generated 3/25/96
  • 04D5: WARM
  • 156F: MD:4
  • 1699: <FORM>
  • 24BD: @ZXCVBNM,.
  • 24CD: 1234567890
  • 2EF7: 99RESET
  • 2F2F: SET ?
  • 2F99: TX LEVEL ADJUST (R49) TEST 2
  • 3249: (FOR CHANNELS 1-9)
  • 3267: (FOR CHANNELS 10-16)
  • 327E: XMIT TIME IS MINUTES (03-25)
  • 32A4: PRESS "X" TO EXIT
  • 333C: MDT-870
  • 334E: FIRMWARE SERIES 20 V1.2
  • 336E: REV. DATE 3/25/96
  • 5405: <ERROR>
  • 5415: <PASS>
  • 5420: <TEST>
  • 64F8: LED TABLE

Bally Arcade: New Life with SD Card Solution from BackBit

I received my BackBit with Bally adapter this week and it is excellent, as the first solution that allows loading and managing applications direct from Micro SD. The previous longstanding solution (UltiMulti) had a fixed number of programs and you'd have to toggle a variety of dipswitches to load any given one. There are still benefits to the UltiMulti and Lil White RAM, in particular for BASIC programs. BackBit is for ROM/binary image loading so can't natively load PRG/WAV format files.

A Note About +5V Requirements

For the Bally adapter, the important point to keep in mind is that it requires the external +5V feed, done through the light gun port. This is equivalent to the way Lil White RAM gets its power or the original BASIC adapter. Read Full Article