CoCo DMA: Missing Without a Trace

Radio Shack’s introduction of the Color Computer 3 introduced extensive changes to the Color Computer design. Gone were the 6847 VDG and 6883 SAM, functionally replaced and enhanced with the TCC1014 Advanced Color Video Chip (ACVC) which most folks reference as the GIME. Other additions included an additional 64kB of RAM with an option to upgrade all the way to 512kB, support for an additional joystick fire button, and composite and RGB video output options. Almost every addition brought new capabilities or an expansion of capabilities to the Color Computer…

Figure 1: 74LS245 Pinout

Interestingly, for a machine design that I understand focused on parts and cost reduction within TANDY, 1 part was added to the CPU’s data path along the memory bus, an addition that renders our previous work unusable, an addition that breaks the very idea of sharing the bus: the 74LS245 octal bus transceiver. Ironically, the ‘245 transceiver was designed to allow bus sharing. As the name suggests, it contains 8 logic elements, each able to pass one signal from the ‘A’ pin to the ‘B’ pin or vice versa, depending on the state of the “direction” pin. More importantly, when an “enable” pin is de-activated, the logic element effectively “removes” the signal from the pin on the IC. In the industry, the pin is said to be in high impedance mode or “Hi-Z” mode. Such pins are commonly called “tri-state” pins, as they can either output 0, 1, or Hi-Z. The mechanics vary, but the term implies the logic element effectively places such a large resistance in between the signal and the pin that the rest of the circuit can essential ignore or will have no awareness of the signal. The 8 elements, Hi-Z operation, and direction function fit the demands of an 8-bit CPU bidirectional data bus perfectly. We can’t blame the IC itself for this issue, so why does the inclusion of this IC in the Color Computer 3 design render bus sharing unusable?

Let’s peruse the CoCo3 schematic, located on page 103 (or 127 for PAL) of the TANDY Color Computer 3 Service Manual. A snippet is included below in Figure 2. The 74LS245 connects directly to the MC6809E CPU data bus, with the DIR line connected to the CPU R/W line. During normal operation, the CPU drives the ‘B’ lines during a write action, and the ‘245 reads those lines and drives the ‘A’ lines with the same value. On a read activity, the ‘245 reads the data bus ‘A’ lines and drives the ‘B’ lines with that value, which the CPU then reads on its data pins and processes.

Figure 2: CoCo3 CPU Data Bus Schematic

So far, so good. And, all works fine when we perform a DMA-based read action. After halting the CPU, The DMA engine places an address on the bus, and raises the R/W line to read data from memory, just like the CPU. Doing its part, the ‘245 transceiver pulls the data from the ‘A’ pins and places it on the ‘B’ pins, which are connected to the CPU. It’s a nice gesture, though unneeded, since the CPU isn’t running.

Writing, though, is where the issues arrive. Let’s run through the scenario. After halting the CPU, the DMA engine places an address on the address bus, places some data on the data bus, and pulls the R/W line low to signal a memory write. The ‘245, assuming the CPU is trying to write some data to memory, grabs the values on the ‘B’ pins and places the results on the ‘A’ pins, which are connected directly to the shared data bus. The first problem: The CPU is halted, so it is not outputting any data on the CPU data pins. The ‘245 is effectively pulling residual charge from the tri-stated CPU data bus, cleaning it up and driving the data bus. The second problem: Someone else is already driving the bus: the DMA engine. At the very least, the data bus represents an interdeterminate composite of the expected value from the DMA engine and the unknown value from the CPU data pins. More importantly (and more concerning), one output might be attempting to drive a data line low while the other tries to drive it high. In some sense, this is like connecting a battery’s positive post to its negative post. While the amperage involved is much lower, it’s no less damaging to the ICs.

Focus attention on pin 19 of the 74LS245, the “enable” pin, labeled “G”. (I have not yet been able to determine why “G” was used, maybe “gate”. Other versions of the IC use OE, which means “output enable”). Regardless of the name, the bar over the name indicates that it is “active low”. A logic zero (0) on the pin will enable the function. Ground the pin, and the data passes from A to B or B to A. Connect the pin to a “one” (1) signal and all transceiver channels switch into Hi-Z mode. Notice in Figure 2 that the enable line is connected to a symbol that just ends. That symbol is called “chassis ground”, representing a wire connected to a large sheet of metal (the “chassis” of old electronic equipment was made of metal). I won’t go into the specifics of various grounding options (signal ground, earth ground, and chassis ground), but we can all agree this pin is permanently tied to zero (0). Thus, the transceiver is permanently enabled. Good for the CPU, bad for DMA.

On previous Color Computer designs, the 74LS245 was not even included. I don’t know exactly why the functionality was added to the CoCo3, but we can theorize. While dedicated bus transceivers like the ‘245 clean up marginal signals, it’s highly doubtful that signals originating from the MC6809E showed any integrity loss. Bus transceivers like the 74LS245 can also act as “buffers”, protecting (in this case) the CPU from dangerous voltages or skipes on the data bus. Again, this seems dubious, since dangerous voltages on the address bus or other control lines could just as easily damage the CPU, and no buffers are placed on those lines. However, bus transceivers are also used to increase the “drive” capability of a signal. Think of the bus transceiver like an 8 channel amplifier. Each IC connected to the bus uses a bit of power, which must be supplied by the IC driving the bus. ICs thus often specify their drive characteristics in terms of Transistor to Transistor Logic (TTL) “load”, a current requirement of 1.6 milliampere (mA). A standard TTL IC input comprises one (1) TTL load, and a TTL output can typically drive ten (10) TTL loads (16mA). In electronics, this is called the “fanout” rating. Most ICs provide their fanout capability, and the MC6809E specifies a fanout capability of 4 LSTTL loads. A LSTTL (Low Power Schottky TTL), as the name suggests, requires less power than standard TTL. As such, an LSTTL load is equivalent to ¼ TTL load, or 0.4mA. Even if we simplify and consider everything on the CoCo3 data bus as requiring only 1 LSTTL load (0.4mA) each, the CoCo3 attaches 6 items besides the cartridge port and CPU to the databus, which exceeds the 4 LSTTL limit. For comparison, the CoCo1 attaches 5 items, again not including the CPU and the cartridge port. While the MC6809 can probably drive more than 4 LSTTL loads, and CMOS devices like the GIME probably consume less than 1 LSTTL of load, the ‘245 was most likely placed into the design to address this load issue. Now, some will ask, “But, what about the need to boost the drive on the address lines”? It turns out that the address lines are not connected to as many devices (excepting the cartridge port, most address lines only connect to GIME and the ROM, with A0,A1, and A5 signals connecting to 2 more devices).

We’ve determined the bus transceiver is designed to allow bus sharing, and our theory suggests it was a useful addition to the CoCo3 design. So, how should we proceed? As the title of this article suggests, the problem lies in a missing wire in the schematic. Such lines, called printed circuit board (PCB) traces or just traces, connect all of the IC pins in the CoCo3 design. As noted previously, we need one connected to the “enable” pin of the bus transceiver, one that will be zero (0) when the transceiver should be working, and one (1) when the transceiver should be turned off.

Figure 3: MPU States

It turns out that the MC6809E CPU “BA” (Bus Available) line appears to offer the correct operation and polarity. When zero (0), the CPU is utilizing the bus, and while one (1), the bus is “available” for others. Tying the “enable” line to the CPU BA line should allow all existing functionality to continue while enabling CoCo3 DMA operation. That’s the good news. The bad news: adding this trace in some fashion requires hardware modification. Take heart, though, there are a few different ways to proceed.

For reference, let’s look at an NTSC CoCo3 PCB in Figure 4, showing the 74LS245 bus transceiver. You will notice the transceiver sits in between the CPU and the cartridge port (the PAL PCB is slightly different):

Figure 4: CoCo3 PCB

The “enable” pin on the 74LS245 has been denoted with the red arrow, as has the BA pin on the MC6809E (this particular CoCo3 has had the CPU removed and a socket installed).

NOTE: While testing suggests this modification will not adversely affect any current CoCo3 usage, more testing is needed to conclusively prove the point. The below instructions are designed for those who want to modify and confirm operation. Make these modifications at your own risk.

Option 1:

This option requires the least amount of work, but also looks the least pleasing. Simply snip the 74LS245 pin 19 at the spot where it goes into the PCB, bend it up off the PCB, and solder a small wire from it to pin 6 of the CPU. To return to stock, simply remove the wire, bend the pin down, and resolder to the stub in the PCB. Alternatively, desolder and replace the 74LS245.

Option 2:

This option looks neater, but does require cutting a trace.

For this option, remove the PCB from the case, remove the little retaining clips on the shield under the board, and locate pin 19 of the 74LS245. Cut the trace going to that pin, and then solder a wire from pin 19 to pin 6 of the CPU on the bottom of the PCB. To return to stock, unsolder the wire and create a small solder bridge over the cut trace.

Option 3:

This option requires the most work, but it is easiest to convert back to stock.

Figure 5: DMAEnabler PCB

Desolder and socket the 74LS245. Build and populate the DMEnabler PCB shown below, installing the ‘245 into the adapter PCB and then installing the adapter into the CoCo3. Attach a test grabber lead to the BA pin on the adapter PCB and clip the test lead to pin 6 of the CPU. (Enterprising PCB designers could also create a dual-header PCB that fits in both the CPU and the 74LS245 sockets, removing the need for the test lead)

With one of these alterations, normal CoCo3 operation should continue as before, and DMA functionality will be enabled. As teased in last week’s article, with this modification in place, our test application now transfers data from the CoCo3 to external RAM and back:

Figure 6: CoCo3 Transfer to External RAM

While running in FAST mode (poke &hffd9,0), we can see the double read of $ff67/68 trigger the DMA transfer, which then pulls data from $4000-$4003 at ~2MBps.

Figure 7: External RAM transfer to CoCo3

Going the other way, the two cycle $ff67/68 read triggers the engine to push our data to $5000-$5003, again at ~2MBps.

Given that the addition of a single PCB trace into the CoCo3 circuit board would have added no cost and that the inclusion of that trace appears to maintain full compatibility with earlier CoCo systems while also fully enable bus sharing, one can only assume TANDY did not foresee DMA or other bus sharing activities being needed on the cartridge bus or they did not care to support such functions. Alas, requiring a hardware modification to support CoCo3 bus sharing severely limits adoption of this technique. At this point, folks socketing their CPU to upgrade to the Hitachi 63C09 CPU could also start socketing the 74LS245 or otherwise asking this modification be performed, but the majority of CoCo3 units remain unable to utilize this DMA technique.

Still, one cannot help but wonder… What if there were a way to coax an unmodified CoCo3 into sharing the bus? 🙂

CoCo DMA: Invisible RAM

Now that we’ve learned a bit about how the 6809E wants to be treated during a direct memory access (DMA) request, we can put all we’ve learned into action. But, before we launch into the details, let’s address some questions that arose during previous article discussions:

Some asked why the logic doesn’t just watch for M6809E signals BA and BS to both equal 1 (this condition indicates that the CPU is halted), commencing DMA actions at that point. This is my fault. As I started the project effort, I didn’t make it clear that I am trying to determine what DMA capabilities exist at the external side of the TANDY Color Computer expansion port (game cartridge port). I did comment about the expansion port initially, but I should have called that out in more detail. It’s worthwhile to also answer how one enables DMA when inside the computer, but that effort requires modifying the internals of the machine (at least plugging and unplugging ICs, which might not be socketed), and thus trades design complexity for end user complexity. The lowest entry point for DMA exploration (as with most things) is the expansion port, so I’ve concentrated my efforts there. But, for the record, we now know that an internal DMA engine need only pull HALT low, watch for BA=BS=1, and then transfer data as desired.

Others asked if halting the CPU and performing data transfers can really be called “DMA”. Instead of just answering the question by articulating the literal definition of DMA, I believe the question speaks more about how the term “DMA” has evolved over the years. In the beginning, DMA actions made no promises about CPU activity. The act of offloading memory access from the CPU and the act of running the CPU while that alternative access occurred were completely different efforts. In fact, Motorola manufactured and sold a DMA controller IC (the 6844 DMAC) that performed DMA actions by stopping the CPU (in various ways). That said, in today’s IBM PC-based world, where the memory bus, the peripheral bus, and the CPU bus are all separated and tied together with “bridge” ICs, it’s expected that a DMA action will not impact CPU operations. That’s the question being asked. I still believe the answer is “yes”, not only because of the literal definition but also that period-correct implementations would have stopped the CPU. But, I will agree that performing data transfers while not impacting CPU performance would be ideal. The conversation did bring up some neat ideas on how one might share the memory bus, not stop the CPU and perform DMA activities, which we can consider in later installments.

Concerning our primary objective, we now know how to safely stop the CPU and gain control of the bus, and we also know how to manipulate the bus to transfer data from one place to another. But, transferring a single piece of data is boring, so let’s add some more value. On the Color Computer 1 and 2, a fully expanded machine would include 64kB of RAM. Expanding RAM beyond 64kB typically takes 1 of 2 paths:

  • Internal RAM expansion. While CoCo systems were being manufactured, some vendors offered internal memory expansion options that “paged” RAM in 32kB banks. The RAM was easy to access, but the granularity was poor (if you needed 1 byte from another bank, you had to swap out 32kB of code and/or data to access it). Internal expansion solutions also had to contend with motherboard layout differences and lack of socketed ICs.
  • External RAM expansion using the cartridge port. Since the entire address and data bus resides on the expansion port, we can place additional on the bus there. However, due to technical reasons, only 32kB of internal memory can be protected from external memory writes, and I believe external memory cannot be seen by the video subsystem. The currently produced MOOH expansion memory and SD card interface by Tormod Volden represents this category.

There may be value in supporting a third option: DMA memory expansion. Place a large amount of memory external to the machine and enable DMA actions to swap that external memory with the data inside the machine.

Pros:

  • 1 byte granularity. If you need to map in 1 data value, DMA expansion can support that. No 16kB or 32kB banking granularity.
  • No restrictions on memory location. Map in new data anywhere internal RAM exists.
  • No restrictions for video. Map in new data anywhere and the MC6847 VDG can see it.

Cons

  • Slower than banked memory. Each mapped byte takes ~1uS to map.
  • Still limited by internal RAM size. If the CoCo has 4kB of RAM, one can only map in 4kB of data at a time.

Still, in spite of the potential drawbacks, we should implement the idea, if only to use as a stepping stone to more expansive capabilities.

We’ll implement this invisible memory idea by adding some IO registers to our test logic:

  • 3 bytes to hold the memory location in external memory we wish to transfer to/from
  • 2 bytes to hold the memory location in internal memory we wish to transfer from/to
  • 2 bytes to hold the length of memory to transfer
  • 1 byte to configure what type of transfer we want (and some other flags), like:
    • Transfer from internal memory to external?
    • Transfer from external memory to internal?
    • Use a constant address for internal memory (don’t increment internal address after each transfer)?
    • Use a constant address for external memory (don’t increment external address after each transfer)?
    • Enable DMA transfers?

As presented during the last discussion, let’s use the 2 byte “length” parameter as our trigger to start a DMA transfer. This allows the programmer to make most efficient use of code, by leveraging the 16 bit length register as both information sharing and process initiation.

Let’s get into the Verilog code now:

always @(negedge e_cpu or negedge _reset_cpu)
begin
   if(!_reset_cpu)
   begin
      flag_write <= 0;
      flag_mem_hold <= 0;
      flag_sys_hold <= 0;
      flag_active <= 0;
   end
   else if(ce_ctrl & !r_w_cpu)
   begin
      flag_write <= data_cpu[0];
      flag_mem_hold <= data_cpu[5];
      flag_sys_hold <= data_cpu[6];
      flag_active <= data_cpu[7];
   end     
end

  • flag_write = Are we doing a read from internal memory or a write to internal memory?
  • flag_mem_hold = Do not increment the external memory address after every transfer
  • flag_sys_hold = Do not increment the internal memory address after every transfer
  • flag_active = Enable DMA engine

This code just sets the operational flags from the various data bits, or resets them during a reset activity.

always @(posedge e_cpu or negedge _reset_cpu)
begin
   if(!_reset_cpu)
      begin
         flag_halt <= 0;
         flag_knock <= 0;
         flag_run <= 0;
      end
   else if(!flag_dma & ce_knock)
      begin
         flag_halt <= 1;
         flag_knock <= 1;
      end
   else if(!flag_dma & ce_knock2 & flag_knock)
      begin
         flag_knock <= 0;
         flag_run <= 1;
      end
   else if(!flag_dma & !ce_knock2 && flag_knock)
      begin
         flag_knock <= 0;
         flag_halt <= 0;
      end
   else if(flag_dma && (!len))
      begin
         flag_halt <= 0;
         flag_knock <= 0;
         flag_run <= 0;
      end
end

  • flag_knock = access to $ff67
  • flag_run = access to $ff68 after an immediately preceding access to $ff67

This represents a finite state machine with 3 states (IDLE, KNOCK, RUN). I will later optimize this to use a 2 bit “state” value instead of 3 binary bits. Still, I think you can see the sequence. On reset, reset the flags. If $ff67, set flag_knock. If we next see $ff68 (ce_knock), set run flag. The additional check for flag_dma is simply to prevent retriggering a DMA activity while performing a DMA activity that accesses $ff67:68 😊.

always @(negedge e_cpu)
begin
   flag_dma <= flag_active & flag_run;
end

We quantize DMA actions to begin and end on the falling edge of E, and DMA can only occur if the criteria is met and the DMA engine is enabled.

always @(*)
begin
   if(e_cpu & r_w_cpu & ce_addre)
      data_cpu_out = address_mem_out[23:16];
   else if(e_cpu & r_w_cpu & ce_addrh)
      data_cpu_out = address_mem_out[15:8];
   else if(e_cpu & r_w_cpu & ce_addrl)
      data_cpu_out = address_mem_out[7:0];
   else if(e_cpu & r_w_cpu & ce_addrh_sys)
      data_cpu_out = address_sys[15:8];
   else if(e_cpu & r_w_cpu & ce_addrl_sys)
      data_cpu_out = address_sys[7:0];
   else if(e_cpu & r_w_cpu & ce_lenh)
      data_cpu_out = len[15:8];
   else if(e_cpu & r_w_cpu & ce_lenl)
      data_cpu_out = len[7:0];
   else if(flag_dma & !r_w_cpu)
      data_cpu_out = data_mem;
   else
      data_cpu_out = 8'bz;
end

This code looks complicated, but it’s just allowing the developer to read various values. The only condition of interest is the one where flag_dma is active and R/W is 0 (a write to internal memory. In this case, we want to bridge the external memory data bus to the internal memory databus.

always @(*)
begin
   if(!flag_write & flag_dma)
      data_mem_out = data_cpu;
   else
      data_mem_out = 8'bz;
end

Conversely, if we are transferring data from internal memory to external, bridge the CoCo data bus to the external memory data bus.

always @(negedge e_cpu or negedge _reset_cpu)
begin
   if(!_reset_cpu)
      address_mem_out <= 0;
   else if(ce_addre & !r_w_cpu)
      address_mem_out[23:16] <= data_cpu;
   else if(ce_addrh & !r_w_cpu)
      address_mem_out[15:8] <= data_cpu;
   else if(ce_addrl & !r_w_cpu)
      address_mem_out[7:0] <= data_cpu;
   else if(flag_dma & !flag_mem_hold)
      address_mem_out <= address_mem_out + 1;
end

Again, the Verilog looks complicated but is not. We’re simply storing the various pieces of the starting memory address via writes from the CoCo, in 8 bit chunks. During a DMA activity without the address being held, we increment during each falling edge of E.

always @(negedge e_cpu or negedge _reset_cpu)
begin
   if(!_reset_cpu)
      address_sys <= 0;
   else if(ce_addrh_sys & !r_w_cpu)
      address_sys[15:8] <= data_cpu;
   else if(ce_addrl_sys & !r_w_cpu)
      address_sys[7:0] <= data_cpu;
   else if(flag_dma & !flag_sys_hold)
      address_sys <= address_sys + 1;
end

Same story here. We store the internal starting memory address in registers in 8 bit chunks, and we increment the counter by 1 during each cycle if the internal memory address is not being locked into position.

always @(negedge e_cpu or negedge _reset_cpu)
begin
   if(!_reset_cpu)
      len <= 0;
   else if(ce_lenh & !r_w_cpu)
      len[15:8] <= data_cpu;
   else if(ce_lenl & !r_w_cpu)
      len[7:0] <= data_cpu;
   else if(flag_run)
      len <= len - 1;
end

Finally, perform the same action for the length, storing in 8 bit chunks and incrementing while the DMA activity is occurring.

always @(*)
begin
   if(flag_dma)
      begin
         address_cpu_out = address_sys;
         r_w_cpu_out = !flag_write;
      end
   else
      begin
         address_cpu_out = 16'bz;
         r_w_cpu_out = 'bz;
      end
end

Normally, we don’t mess with the address bus, preferring to read it for information. But, during a DMA cycle, we need to place an address on the CoCo bus.

assign _halt = (flag_active & flag_halt ? 0 : 'bz);
assign _ce_ram =!flag_dma;
assign _we_mem =!(flag_dma & !flag_write);

One would think we could use flag_run to configure HALT, but flag_run only goes active after both trigger accesses have happened. Thus, using flag_halt lets us start the HALT condition after the first trigger (access to $ff67) if the DMA engine is active. External memory is selected only during DMA cycles, while the !WE signal to external memory is only enabled if we are reading from internal memory (this signal is overqualified, in that the external memory won’t be active unless flag_dma is active, which means this signal could be simplified to assign _we_mem = flag_write;

After compiling and downloading the firmware into our test cartridge (which contains 512kB of static RAM), let’s see what we can do. We’ll enable the DMA engine (128 => $ff69), set the external address to $000000, internal address to $4000, and length to $0004:

I’d like to interrupt for a second and express appreciation to David Wood (jbevren on IRC and Discord) for pointing me to the VNC server capabilities on my HP logic analyzer. Starting VNC allows me to capture better screenshots and remotely control the logic analyzer.

In this case, we performed a read from $ff67:68, since the program was written primarily in BASIC with a small EXEC to perform LDD $ff67:rts. We can see the $ff67:68 reads, the HALT line going low after the $ff67 access, the wait for $ff68 access, and then 4 reads from internal memory. Before issuing the DMA transfer, I populated $4000-$400a with the ascending values 0-10, and we see them pulled across the data bus in the trace above.

Now, let’s got the other way, transferring those external values back into internal memory at $5000 by turning the DMA engine on, switching transfer direction (129 => $ff69), setting the external address to $000000, setting the internal address to $5000, and keeping the length at $0004:

Again, we see the trigger condition $ff67:68, the HALT condition, and the transfer of our 4 data values from external memory to internal locations, and we see the address incrementing with each transfer. Additional tests show “pinning” an address works as well, which can be useful in the following situations:

  • setting memory to a constant value at 1byte/us by pinning the source address at a location that contains that value
  • Dumping data to the Orchestra 90 or other CoCoSDC at 1MB/s (Yes, the DMA action works even if both the DMA device and the peripheral are external to the CoCo!)

This invisible memory implementation nicely illustrates the DMA capability available on the TANDY Color Computer 1 and 2. Perhaps this knowledge triggers a fellow enthusiast to develop software that will play to the advantages of this memory expansion option. To that end, all resources associated with this effort have been placed under the Creative Commons Share-Alike 4.0 license and uploaded to a GitHub project repository:

https://github.com/go4retro/PhantomRAM/

If interest warrants, PhantomRAM can be turned into a technology solution, though that is outside the scope of this research effort.

Next time, we turn our attention to the 3rd system in the Color Computer lineup and the challenges it poses concerning DMA functionality. Until next time, I present the following two screen shots (hint: check the timestamps 😊)

CoCo DMA: “Fighting on the bus”

Picking up from last time, we were able to successfully place a byte into the internal CoCo memory from the cartridge port without the use of the CPU by utilizing a direct memory transfer procedure. However, after the transfer, BASIC programs would stop with errors at times, machine language programs would simply lock up, and the IO registers of the cartridge device would be corrupted. Clearly, our initial implementation has issues. Since education and understanding drive this effort, we need to dig deeper into the actual bus activity. For that, we must turn to the digital logic designer’s tool of choice: the logic analyzer

For anyone who has even a passing interest in digital circuitry, I (and so many others) strongly recommend obtaining a 10-20MHz dual channel oscilloscope. A multimeter may be the first tool purchased, but an economical dual channel scope should be next on the list. That said, while oscilloscopes are great to see transients and strange signals (like NTSC or audio), they don’t handle digital logic investigation as well. Enter the logic analyzer. Instead of trying to replicate the shape of a signal like a scope, the LA simply detects whether a signal is 0 or 1 (typically using TTL voltage levels as a reference, where 0 = 0-0.8V, and 1= 2.1V-5V). It performs this limited action across many channels, as opposed to the 2 or 4 of a scope. After a scope, I strongly recommend obtaining a small 8-channel USB-based analyzer. They are inexpensive, easy to use, and 8 channels supports simple parallel testing and a plethora of serial protocol testing (RS232, SPI, I2C, etc.). That said, debugging a single board computer or large interface card can take a long time with 8 (or even 16 or 34) analyzer channels. Thus, I also keep a larger professional grade logic analyzer (it used to be the only option, before the USB analyzer options came on the market). Found on eBay from test equipment manufacturers like Tektronix and HP/Agilent/Keysight at reasonable pricing, these units support dozens and sometimes hundreds of analysis channels at frequencies far beyond what the 1980’s computer enthusiast will regularly see.

HP/Agilent/Keysight 16702A Logic Analysis System
Picture 1 of 1
3M 40 pin Test Clip

I’ve recently upgraded my bench analyzer from a 1980’s era HP 1650b (great unit, cheap to buy and own, now passed onto a fellow hardware designer to continue its usefulness) to a 2000’s era HP modular system (HP 16702a). This project gives me my first opportunity to learn how this unit works. I first connect the individual analyzer channels to the various 6809E signals using a 40-pin 3M Test Clip. I highly recommend adding this to your toolbox for signal inspection (the units are expensive if purchased new, but they never wear out, and eBay has more reasonable pricing), as they simplify moving the signal investigation to a new IC or new system. Since we want to investigate all of the bus activity, I place address lines 0-15 under test, as well as data lines 0-7, R/W (read/write), HALT, and the clock signals (E and Q). As we want to know what happens after the access of $ff61, we set a trigger on access to that memory location.

To more accurately pinpoint the issue, we’ll use a hastily (and terribly, I’ll add) written 6809 assembly application to exercise the test device and which exhibits the crashing behavior. A snippet is included below:

lda LOC* grab initial data at $4000
jsr CONVERT * convert binary to hexadecimal and return in D
std SCREEN * store at $0400
lda DMA * execute the DMA action ($ff61)
lda DATA * grab data at $ff60 (the external IO data location)
jsr CONVERT * convert binary to hexadecimal and return in D
std SCREEN+2 * store at $0402
lda LOC * grab data at $4000 (the internal IO data location)
jsr CONVERT * convert binary to hexadecimal and return in D
std SCREEN+4 * store at $0404

Since the application originates at $0e00, the lda DATA instruction after our $ff61 access resides at $0e4c. When we run the test program, the logic analyzer triggers and the program crashes. But, the evidence surfaces. On the logic analyzer, we see the following:

Address Data R/W HALT Notes
0e49 b611
0e4a ff11
0e4b6111
ffff2711Dead Cycle
ff612710Nothing at $ff61, but bus rests at $27
40002d01 Our data write ($2d = 45)
We sample on falling E, so HALT=1
0e4d ff11 Why did we jump to $0e4d?

Folks probably start to see what is going on, but it pays to be sure. The Verilog is modified to not activate the address bus or R/W line, hold HALT low forever, and the test is repeated. Here is the result:

Infinite HALT condition

The problem begins to show itself. Even though the device has pulled HALT low before the end of the instruction execution, the CPU reads and executes one more instruction before releasing the bus. We can tell because of the state of the BS and BA lines. The 6809 datasheet notes that BS=BA=1 signifies a HALT condition in the CPU. Further attempts to pull HALT low earlier in the $ff61 read cycle make no difference.

Darren Atkinson (of CoCoSDC design fame) emailed after hearing about the project effort, asking about HALT line triggering. I initially misread his email as inquiring whether I had pulled HALT low early enough in the instruction cycle. But, Darren responded again and pointed to a key portion of the datasheet I had misinterpreted:

6809E Datasheet HALT Condition Specifics

Hint: It’s the text at the top of the page. I noticed the “2nd to Last Cycle of Current Instruction” notation, but interpreted it to be illustrating to the reader that activating the HALT line before the last cycle of an instruction would not cause an immediate reaction. From my days working with the 6502, I knew that 8-bit processors are not designed to maintain an intermediate instruction state for any length of time. The CPU assumes that once an instruction is started, it must complete before anything else will be processed. While this doesn’t seem to be a concern for the HALT condition (just simply stop the processor, wait for HALT to become inactive, and continue on), it makes sense that HALT would use the same sense logic and internal handling logic as interrupts, and stopping the CPU in mid-instruction to handle an interrupt would require saving an intermediate instruction state. Thus, for that reason, the simpler 8-bit CPUs just don’t do that. Once an instruction opcode is fetched, the CPU will fully execute the current instruction before handling any event. If the datasheet showed the HALT line going low on the last cycle, it could imply that execution would stop at the end of the current instruction cycle. Thus, I thought this text was simply reinforcing the text describing the HALT pin: “A low level on this input pin will cause the MPU to stop running at the end of the present instruction and remain halted indefinitely without loss of data”.

However, my assessment was plain wrong. As Darren pointed out, the “2nd to last instruction” text carries crucial significance. As well, it’s the key to the problem we are experiencing. The Verilog is activating HALT on the last cycle of the current instruction, which is actually too late. The CPU moves ahead to read and process the next instruction, only then latching and acting on the HALT condition. I wish this prerequisite had been noted somewhere in the datasheet, but I checked the 6809E, the 6809, the 63C09E and the 63C09 datasheets online and in my possession and found no mention of the constraint. That said, a Facebook commenter also pointed out this requirement, so perhaps everyone in CoCo land knows this tidbit of information.

Now that we know the issue, how do we solve it? I first added a NOP to the code, thinking that doing so would allow the next real instruction to be read correct (the lda $ff60). However, before testing, I quickly realized that would not work. Since the CPU is still reading an opcode, it would interpret any data on the databus during that cycle as the next opcode, potentially altering the program anyway. I next added Verilog code to wait an arbitrary 8 cycles after HALT activation before accessing memory:

HALT with 8 wait states
  • The read from $ff61 happens, and HALT is activated
  • A NOP is read
  • The next instruction is read (the second cycle of a NOP instruction appears to read and discard the next opcode)
  • Then the CPU is halted (as shown by the BS=BA=1 condition
  • The Verilog waits a few more cycles (shown as $ffff:$27 read cycles)
  • Then the data is transferred to 4000 (in this test, the written value was $27) while HALT is deactivated.
  • The CPU takes a cycle to acknowledge the deactivation
  • The CPU takes another cycle to prepare for startup
  • Then, the $b6 opcode (of lda $ff60 instruction) is read

Success! BASIC test applications begin running to completion with no unexpected errors, and the test machine language application no longer crashes the machine, instead it runs to completion and illustrates that all 256 values can be transferred from outside the machine to internal memory locations.

That said, adding dead cycles to the DMA engine is far from ideal. In fact, after Darren noted that a full register stack-up could take 20+ cycles on a 63C09, I quickly found the dead cycle wait idea untenable. Clearly, we need to find a better way to trigger a DMA transfer. I quickly sketched out a few requirements and some preferences:

  1. The action must pull HALT low prior to the second to last instruction cycle
  2. The condition must not occur over two consecutive opcodes (interrupt could occur in between)
  3. The condition must not require scanning the databus for specific opcode/operand sequences (i.e. watch the databus for $b6,$ff,$61)
    1. Doing so requires constantly activating the SLENB line when installed in an MPI, since the data bus is hidden from MPI slots unless an IO access is made or SLENB is activated. And, SLENB being activated on arbitrary memory locations would cause other problems
    2. There’s no guarantee such a sequence would never occur in any other way.
  4. Ideally, the “trigger” action should be an instruction that would be otherwise needed (so as to not waste any time performing some action JUST to start the transfer)
  5. If a memory address trigger, the address should be constant

I just as quickly decided that CPU instructions that perform 2 memory accesses in a single instruction would ideally suit these constraints. HALT could be triggered to go low on the first memory access, and if the second memory access did not occur 1 or 2 cycles later, the HALT condition would become inactive and the system would not perform the transfer. If the condition was met, the system initiate a transfer after the second memory access. I first gravitated to INC $ff61, which performs a ®ead-(M)odify-(W)rite action (reading the memory location, adding 1 to the value, and writing it back to memory). Since INC $ff61 performs a read cycle, then takes an internal cycle to perform arithmetic (ALU) operations, and finally writes the new value back, the Verilog state engine needed to detect the initial access, wait a cycle, and then detect the second access. That’s not hard to support, but it’s wasteful. Supporting preference #4 proves the larger challenge. Rarely would someone need to increment a value in the DMA engine register set. While I was debating options, fellow enthusiast and Nitros9 developer L. Curtis Boyle suggested LDD, which performs 2 consecutive memory accesses in 2 consecutive cycles. While LDD may not be of great use, STD (store D) would often be used to place a 16 bit value in the registers, as would other 16-bit memory store operations. Since it also simplifies the Verilog, we will utilize it as the DMA transfer start mechanism. In essence:

  • Once the lower IO register is accessed, bring HALT low and set flags
  • In the immediate next cycle:
    • If the next higher IO address is accessed in the next cycle, continue to hold HALT low and prepare for a DMA transfer
    • If not, release the HALT line and do not prepare for a DMA transfer

If the first condition is met but not the second, the CPU will likely notice the HALT condition and stall for 2 cycles after the current instruction, but no harm will arise. To prevent accidental DMA activity while setting register values, we should also add a bit in the eventual control register to enable or disable DMA transfers.

More testing is needed to understand other issues, if any, with assuming a transfer can begin immediately following an LDD/STD type instruction. Since Darren Atkinson already broached the subject of interrupt handling, he performed a test that activated NMI and HALT at the same time, attempting to understand which behavior took precedence. Darren utilized the following circuit and program snippet:

By organizing the stack right above screen memory and driving NMI and HALT low with an SCS access to $ff40, NMI precedence would show as characters on screen (stack values). When executed, no such values appeared, which strongly suggests HALT takes precedence over interrupts.

Now that we have verified the ability to safely transfer data from outside the CoCo to internal memory without disrupting program execution and a way to reliably and atomically trigger such a transfer, we will put all of the pieces together into action. Many thanks to those following along on this journey so far, and a special thanks to Mr. Atkinson for his insights.

CoCo DMA Early Efforts

As referenced in http://www.go4retro.com/2020/02/26/direct-memory-access-possibilities-on-the-tandy-color-computer/, I am attempting to coax some direct memory access functionality from a TANDY Color Computer. I’ll be utilizing a TANDY Color Computer 1 for initial testing, as I feel it most closely matches the Motorola 6809 reference architecture and this year is the 40th anniversary of the machine’s introduction.

As noted in the last article, the !HALT signal is key to enabling DMA functionality (if possible at all) on the 6809. The datasheet stipulates that this line must fall no later than 200nS (for a 1MHz CPU) before the falling edge of the Q clock to ensure correct operation. As well, the signal must rise 200nS prior to the Q clock falling edge of the last DMA cycle. It turns out that, for a ~1MHz system, each of the 4 clock phases exhibited by the two clock signals (E and Q) last 250nS:

  • eq = 250nS
  • eQ = 250nS
  • EQ = 250nS
  • Eq = 250nS

Thus, to ensure our signal becomes active 200+nS before the fall of Q, we can simply enable the signal at the rising edge of E. Coupled with the fact that the CoCo 1 runs a bit slower than 1MHz (.89MHz), we have over 40nS of buffer.

As previously noted, I am utilizing a Complex Programmable Logic Device to simplify the hardware portion of these tests. To make the device perform work, I write the logic in the Verilog Hardware Description Language (HDL). Since I develop in the C programming language, I chose Verilog since it resembles C in some respects (functions, assignment, case statements, etc.). One can also program in VHDL, which is often compared to ADA (its verbosity reminds me of COBOL, actually), but these can spark religious debates. Suffice it to say that Verilog works well for me, and others may find other solutions. Cue the Verilog writing-style comments 🙂

I’ll dispense with the module definition, since it’s pretty standard (it resembles a C function definition), and get right to the important parts:

assign ce_reg = (address_cpu[15:4] == 12'hff6);
assign ce_test = ce_reg & (address_cpu[3:0] == 0);
assign ce_start = ce_reg & (address_cpu[3:0] == 1);

I’ve situated the hardware registers in the CoCo IO range, and moved them out of the way of a floppy drive controller. This allows me to test my hardware with a floppy drive using a simple ‘Y’ cable. We’ll set up a storage register at $ff60 for a value to DMA back to the CoCo, and we’ll use $ff61 to start a transfer.

register #(.WIDTH(8)) reg_test(
q_cpu,
!_reset_cpu,
ce_test & !r_w_cpu,
data_cpu,
data_test
);

This just points to a user developed module defined elsewhere that creates little 74ls574-like devices to hold data, clocked on the falling edge of Q, using data_cpu as the input, and placing the result in data_test.

always @(*)
begin
if(e_cpu & r_w_cpu & ce_test)
data_cpu_out = data_test;
else if(flag_dma)
data_cpu_out = data_test;
else
data_cpu_out = 8'bz;
end

When one has a bunch of assignment options in Verilog, this is an ideal way to compose the logic. Essentially, since I dislike “write-only” registers, the first condition checks if someone is trying to read the value from $ff60 or not. The second condition is our DMA transfer condition, and the third (default) condition places the output lines in a tri-stated configuration. Yes, I could combine the first and second conditions, but I’ll not do that.

always @(posedge e_cpu)
begin
if(ce_start)
flag_halt <= 1;
else
flag_halt <= 0;
end

As discussed earlier, we want !HALT to go low at the rising edge of E, and go high in the same spot when the DMA cycle is concluding. Since we’re only doing a single DMA transfer, this code works fine.

assign _halt = (flag_halt ? 0 : 'bz);

We’ll use our flag to push the !HALT line low or keep it tristated (!HALT is like !IRQ and !FIRQ and !NMI, in that they are all “wired-or” type signals.

always @(negedge e_cpu)
begin
if(flag_halt)
flag_dma <= 1;
else
flag_dma <= 0;
end

While we have to handle the !HALT line essentially in the middle of the cycle prior to the DMA, we can’t start the actual DMA cycle that early. This Verilog allows us to position the DMA cycle at the beginning and ending boundaries of the E cycle, which defines the CPU clock cycle.

always @(*)
begin
if(flag_dma)
begin
address_cpu_out = 16'h4000;
r_w_cpu_out = 0;
end
else
begin
address_cpu_out = 16'bz;
r_w_cpu_out = 'bz;
end
end

If we’re in a DMA cycle, place $4000 on the address bus (arbitrary testing address) and set R/W to 0. Otherwise, tri-state both sets of signals.

All that remains is to compile the Verilog into a suitable JEDEC bit file and download into the Xilinx 95288XL-6 144 pin CPLD 5 volt tolerant CPLD. Yes, it’s overkill for this test (just a few IO would have been plenty), but it’s what was close at hand, and using a large part for initial development allows on to focus on the code rather than the size of the code. This unit has a 6nS latency, which must be added to all signal timings.

On the CoCo1 side, we need to write a small test program. In this case, let’s just place 45 in the CPLD register, issue the DMA cycle, and see if it made it’s way to $4000.

1 poke &hff60, 45: poke &h4000,0
2 ? peek(&hff60);
3 a = peek(&hff61): rem don't care, just need something to hit that address
4 ? peek (&h4000)

After downloading the Verilog firmware, writing the CoCo BASIC program, and executing, we see the following on the logic analyzer:

Figure 1: 6809 DMA Example

We see the !HALT line going low right as the E clock goes high, and then we see the R/W line falling just as the previous cycle end and the next cycle starts. In the midst of the DMA cycle, we see the !HALT line rise, which meets the timing requirements.

The results? Promising. After running the test, location $4000 contains the expected 45, so the write completed successfully. However, all is not right as yet.

  1. After a transfer, the value in $ff60 is corrupted. Not sure why that would be, but I suspect it related to #2
  2. For some test values, BASIC will return an error during the A=peek(&hff61) line and stop the program.

Removing the line that places the test data on the data bus during a DMA cycle eliminates the issue, which means the mere presence of data on the data bus during a DMA cycle is an issue. The next step is to wire up the CPU to a larger logic analyzer, one that can consume all of the address and data lines of the 6809 at one time. The good news is that I have just recently purchased a HP 16702A Logic Analysis System economically (from eBay) and outfitted it with 2 16717A 68-channel 333MHz timing logic analysis cards (134 logic channels in total, though 1 will suffice for this CPU). Now, I just need to learn how to use it (it’s a sight more complex than my older HP 1650B logic analyzer). Off to debug!

Direct Memory Access Possibilities on the TANDY Color Computer

As part of my continuing efforts to understand direct memory access (DMA) capabilities of various 80’s home computer systems, I decided I should figure out what, if any, DMA capabilities are possible on the TANDY Color Computer systems. There are 3 essential models in the lineup, though from a technical perspective, I feel there are 2 main variants: The CoCo1 and 2, which share very similar features and capabilities (mainly, the difference is in some cost reduced circuitry in the 2 and more memory in the later machines) and the CoCo3, which contains a more capable video processor, substantially more memory, and a memory management unit (MMU). Most folks also consider the Dragon Data Dragon machines as part of this lineup, and those are roughly similar to the CoCo1/2 systems (both systems seem to be based on a Motorola reference design. The CP1400 might also qualify, but I don’t have one and know little about the design, so I will consider the 4 above machines inclusively

A pre-requisite for DMA operation is an ability to stop the running CPU in some fashion and a way to access internal memory and/or IO from the cartridge or expansion port. The VIC-20, for example, has no way to stop the running CPU, so DMA is not possible. However, TANDY (and Dragon Data) helpfully provided a pin on the expansion port that will temporarily shut off the internal Motorola M6809E CPU and remove its address and data signals from the system bus (this part is essential, because if the CPU is not running but it still outputs address and data on the system bus, the bus is not available for other users). On the M6809E, that signal is called !HALT and is active low. To “halt” the 6809 CPU, simply bring this line low on the expansion port during a cycle. Of course, nothing is that simple, so here’s some more detail:

Figure 8: HALT behavior

!HALT can be pulled low anytime, but will only take effect if it falls 200nS or more before the falling edge of Q (Q is 1 half of the 4 phase clock system used by the 6809 and typically is high during the middle of the CPU clock “cycle”). This consideration is called tPCS on the timing diagram, and is 200nS for a 1MHz CPU, 140nS for a 1.5MHz, and 100nS for a 2MHz CPU. As well, one can bring !HALT high at a later time, but it again must occur tPCS nS before the fall of the Q clock signal. Still, if one adheres to those rules, the entire address and data bus (on the CoCo1 and 2, anyway) is available at the expansion port for reading from and writing data to the internal memory.

One must crawl, then walk, and then run in these efforts, so the first thought is to figure out the !HALT signalling and attempt to transfer a single value from the expansion port to an internal memory location. Testing would then involve setting the internal memory location to a value other than the one expected, triggering the DMA functionality, and then looking at the internal memory location. If the value has been changed, one can be confident a DMA transfer has occurred. Once that is in place, it can be used as a foundation to expand the functionality to support the transfer of many data values to many locations, and then digress into the various useful DMA use cases (fast floppy emulator, extra memory on demand, feeding audio data to a DAC, etc.). But, it’s a tall order to transfer that first byte, so let’s focus on the task at hand.

Many years ago, I would approach this by grabbing a perfboard and wiring up some 74LS TTL logic ICs on the board to approximate the functionality desired. Of course, it would be wrong, so many hours of rewiring and soldering up new ICs would be involved. Now, though, as much as some retro enthusiasts object, I utilize a suitable Complex Programmable Logic Device (CPLD) attached to a small cartridge PCB to efficiently design the required logic. While soldering and deciding on the correct TTL IC has value, if you’re trying to make something work, those activities can get in the way of the design process. A CPLD allows one to change the design simply by modifying the “software”, downloading it into the IC, and testing. Once the design is working, one can translate back into TTL ICs if desired, or (in many of my recent designs), simply continue to utilize a CPLD. CPLDs are the children of PLDs like the 16v8 PAL used in the 1980’s, and some CPLD variants were available in the era of these machines. These complex devices can replace dozens of ICs in a design, decreasing finished unit costs consderibly and bringing these types of functions well within the grasp of hobbyists to manufacture and enthusiasts to buy. Since I’ve always desired to create economical solutions for these classic machines, the CPLD provides significant value. Still, for the moment, I’m most interested in the design efficiencies, especially since there’s no guarantee anything will work in the end.

RAM Expansion for the C64

RAM expansion was a common topic in the Commodore 64 community in the 1980’s.  Everyone seemed to need or want more RAM:

  • Soon after the unit arrived in stores, Paul Bosacki published a way to upgrade the unit to 512kB
  • Later, he pushed the expansion to 1MB
  • Berkeley Softworks (later GeoWorks), jumped into the fray with the 512kB GeoRAM
  • After the C128 arrived, Commodore got in the act, coming out with the 1700, 1764, and 1750 RAM Expansion Units, providing 128kB, 256kB, and 512kB of RAM, respectively.
  • Lots of people soon determined all 17XX units could be upgraded to 512kB
  • And, then, Andrew Mileski furthered that idea by piggybacking DRAM and pushing the 17XX to 2MB

Over time, RAM expansion options for the C64 have coalesced around two types: REU and GeoRAM.  The REU is much faster, but the GeoRAM is easier to create and use.

Still, both suffer from a serious issue.  Neither one makes RAM immediately available.  Both contain RAM outside the CPU’s direct access.  The Commodore REU can transfer memory from the unit to main system RAM around 1 million bytes/sec, while the GeoRAM has more humble speeds around 125KB/sec.  Sometimes, though, one would like RAM to be instantly available.

Cartridges like EasyFlash and EasyFlash 3 map FLASH ROM directly into the C64 memory map to simplify writing cartridge data.  Along those lines, it should be possible to map RAM directly into the C64 memory map as well, using the impressively capable and mysterious “Ultimax” mode.

The idea:

  • Treat the C64 memory map as 16 slices of memory, each 4KB in size. 
  • Allow the developer to select which portion of external RAM will “reside” in each 4kB slice.
  • If the developer maps a slice of RAM, any read or write access to that RAM will trigger Ultimax mode and place the external RAM onto the system bus during a CPU cycle.

The functionality shares a lot with UltiMem, a product we offer for the VIC-20.  But, the programmer can grow weary of manually configuring and reconfiguring each 4kB slice each time he/she wants to move to a different piece of RAM.  For that, we should take a page from the C128 MMU and create the idea of a “mapping set”.  A mapping set comprises 16 values, one for each slice of main memory.  The C128 supports 4 different mappings, which makes the developer’s job easier.  Set up the mapping and then just use it when needed.

So, let’s add a few more features:

  • Support a “mapping set” of 16 values
  • Support multiple mapping sets, which can be selected by storing a value into a specific register to denote the mapping set “ID”

Finally, though the Commodore REU may be too complicated to implement:

  • Support GeoRAM registers for backwards compatibility

One should be wary of announcing success too early, but initial development shows this functionality is possible.  At this point, the following functionality appears to be working:

  • 512kB of SRAM
  • GeoRAM register support
  • Support for 128 “mapping sets”
  • All memory slices except slice 0 and slide ‘D’ can reside externally

Of course, at this point, once something works, one needs to determine if anyone cares 🙂 

VCF-MW/ECCC

RETRO Innovations Booth
Glenn Holmer captured me talking to friends about something of interest at the ECCC 2014 show

It’s interesting to be a part of the continuing “growth” of the classic computer scene.  And, perhaps it is just me, but it does appear the classic machines are seeing more interest now than since they were first placed on the market.  It has been over 25 years, which is a common metric for “classic” status in other arenas (cars, coins, etc.), so perhaps this is the new reality.

Back in the day, I lived too far away from a metropolitan area that held computer shows, so I missed out on the thrill of those years.  And, after passing into adulthood, I had only previously attended 1 show, around 1997, put on by a Commodore user group in Lansing, MI.  While Maurice Randall showed off GeoFAX or some new GEOS app, another exhbitor showed off a way to control audio CDs from the 64, and everyone picked through the consignment table, I hawked printed copies of “Commodore Hacking”, an online magazine I was editing at the time.  As I recall, I did not sell many, and for good reason.  Why buy something you can dload online for free (true, the Internet was not as ubiquitous as today, but Compuserve, Delphi, GEnie, and others had copies, and the mag was in ASCII text, a mere few hundred K of data).

Yet, as I re-invested myself in these machines around 2004, I was invited to attend Commodore computer shows, including the World of Commodore 2004 in Toronto, ON, CA, LUCKI Expo 2005 near Louisville, KY, the C=4 (CCCC) Expo south of Cincinnati, OH, and SWRAP Expo 2005 in Chicago, IL.  As a new attendee, I was surprised so many people remembered me from the Commodore Hacking and even earlier Commodore FAQ days.  I also met luminaries like Jim Butterfield and Jeri Ellsworth.

Sadly, it appears some of the shows were not to continue.  LUCKI shut down first, as I recall, while SWRAP discontinued its show soon thereafter, and CCCC continued on for a few years and then folded when their “castle” venue closed its doors.  I worried I had witnessed the end of the show scene, just as I was starting to enjoy the friendships and witness all of the great hardware and software projects.

Luckily, World of Commodore continued on, while Jason Compton and a group of friends decided they needed to have a time each year to come together and enjoy friendship over Commodore computer discussions, and so the Emergency Chicagoland Commodore Convention (ECCC) came into being on the heels of SWRAP’s decision to forego another show.

ECCC, in particular, was somewhat the “anti-show”.  No table fees, no concrete organization, owing to the primary goal of just having a place for Commodore enthusiasts to hang out and enjoy company.  But, all things change, and a few years back, Jason Timmons asked if other computing platforms could co-located with the ECCC show under the Vintage Computer Festival – Midwest (VCF-MW) banner. There was already a well established VCF-East show in New Jersey, and there had been previous attempts for a VCF-MW in Indianapolis, as I recall. West Lafayette. But, VCF-MW had withered, and so it came to Chicago.

At first, VCF-MW was a small portion of the complete show, but each year, the VCF-MW contigent grew and brought more exhibits and attendees to the combined event.  At other shows, I suspect the primary sponsors would have either disallowed sharing the event date and location, or the organizers would have grown significantly concerned about the changing dynamic of the show, but Jason and the initial contributors seemed unconcerned about such things, probably owing to the fact that the ECCC show was created to enable a meeting place for enthusiasts, not as a formal marketing effort or a club sponsored idea.  I’m not sure a dual show idea would not have been as successful elsewhere, but it thrived in Chicago.

For the last few years, VCF-MW has continued to grow, but there’s still a significant Commodore presence.  While there’s value in having single-platform shows like World of Commodore, KansasFest, or CocoFEST!, such shows can be somewhat insular, as all of the attendees are already aligned with the platform.  And, though one hopes we’ve all matured a bit, there’s some fun in crowing about platform features or enduring a bit of ribbing over platform weaknesses among friends who own competing systems.  More importantly, there are some classic machines too obscure to command a full community, and shows like VCF allow those folks to show off these all-but-forgotten gems (or stinkers, but they are always interesting).

Thus, my hat is off to those who organize the various shows; truly unsung heroes doing lots of work so lazy bums like myself can drive in, grab a room, shoot the breeze, sell a few things, pack up, and leave.  And, thanks to those folks who take the time to document the events, via photos or video, or both.  It’s nice to be able to look back and see how far we have come. Finally, thanks for Jason Timmons and Jason Compton, for ensuring VCF-MW/ECCC continues.

RETRO Innovations will be once again exhibiting and offering products for sale at VCF 12, September 9-10, 2017

Glenn Holmer’s Galleries:  http://www.lyonlabs.org/commodore/

VCF-MW Galleries: http://vcfmw.org/past.html

 

 

 

Back from the Vintage Computer Festival – East 9.1!

I just returned from a 2102 mile roundtrip excursion to the Vintage Computer Festival – East 9.1 at InfoAge in Wall Township, NJ.  Having been prevented from holding the show in 2013, the VCF-E organizers went all out for the 2014 show, supporting 2 exhibit halls and a separate speaker presentation tent.  I camped out in the vendor hall with our products on display.

IMG_6555 (Large)IMG_6556 (Large)Though this is the first VCF-E I have attended, others remarked that this was the largest Expo they have held.  Thus, I am glad I was able to participate.  Unlike the other shows I have attended, VCF-E is much more structured.  Vendor tables are in their own room, the mornings are dedicated to speaker presentations and vendor sales, and the show floor does not open until the afternoon. Like many of the other more recent events, VCF-E is a 2-day event (Saturday and Sunday), and they even created a special VCF University event on the Friday before the main event.  I didn’t specifically count, but I was told 26 different exhibits were available for viewing in the 2 (yes, two) exhibit halls.

As you can see, I spruced up the vendor tables with some colorful tablecloths, and I brought a vintage CMD-era JiffyDOS wall poster (I purchased it from Click Here SW a few years back).  I brought all of the main store items, though I left some of the more esoteric adapters and such behind as they rarely sell. Sales were not overwhleming, but were satisfactory, especially in light of the fact that most of the day’s action revolved around the “consignment” tables.  I loved the consignment idea (VCF even accepts items for sale, with pricing information from the owners.  They then handle the financial aspects and man the sales table, taking 15% of the sales value).  One individual made over $1600 in sales through this solution.  I even joined in the rush, picking up a TRS80 MC-10 and a Compaq luggable.

Concerning exhibits, there were too many to mention.  I’m not that much into the 60-80’s DEC HW, but it was well represented at the show.  The early microcomputer options were on display, along with some early UNIX workstation options.  Closer to my world, Jeff Brace and Dan Roganti borrowed a number of uIEC/SD and 64NIC+ devices to present their “Artillery Duel”-like multi-player C64 game.  The graphics and such looked awesome, but they were plagued by code issues through the weekend.  They kept the loaner items in hopes of better luck during a June exhibition.  Elsewhere, Michau Pleban and Rob Clarke (An Australian Brit from Switzerland, no joke) were on hand to show off a Commodore 264, a 232, a 116, a Max Machine, and their new cartridge for it called “MultiMax”.  Rob also tried to talk Bil Herd (on site over the weekend) into firing up the V364 Prototype board that Bil had delivered to Rob at the show.  Rob talks more about the unit in his Youtube smoke test for the unit, but it was Bil’s dev board back in the day.

It’s not the same as being there, but here are some galleries to show what was on display and the participants who gathered in NJ:

Heading to the Vintage Computer Festival East!

The ninth “annualish” Vintage Computer Festival East will be held April 4-6, 2014, at the InfoAge Science Center, in Wall, New Jersey.

VCF East is a celebration of computer history from the 1940s-1980s. The schedule includes a hands-on exhibit hall, technical workshops, lectures, a marketplace, tours of the InfoAge museum complex, a dollar-per-pound book sale, prizes, more.

This year’s show will be bigger than ever. New attractions include Friday’s “VCF East University” which is a full day of technical classes. Friday attendees can win an oscilloscope courtesy of Tektronix!

The main show on Saturday-Sunday will have lectures/workshops and dozens of exhibits.

Keynotes include former IBM archivist Paul Lasewicz and IEEE 802 LAN/MAN committee founder Maris Graube. Other lectures topics include software preservation, the history of Franklin Computer Corp., and many more, all scheduled for the morning. In the workshops you can learn hands-on vintage computer repair skills or even build a working replica of something exotic.

This year there will be two exhibit halls instead of one. Exhibits open in the afternoon – imagine an antique car show, but instead of “no touching” signs, everyone has to take you for a ride! Registered exhibits so far cover everything from a real Apple 1 to the M.I.T.S. Altair to DEC minicomputers. In addition, the event’s main sponsor MARCH (Mid-Atlantic Retro Computing Hobbyists) will debut its UNIVAC 1219-B military mainframe computer, circa 1965.

Tickets for VCF East University are just $20 and include a pizza lunch. Tickets for the main show are $15/day and $25/both days. Saturday/Sunday tickets are free for ages 17 and younger. A three-day adult admission is $40.

Proceeds benefit MARCH. Official sponsors include the InfoAge Science Center, VintageTech, Tektronix, the Trenton Computer Festival, Eli’s Software Encyclopedia, and Vintage-computer.com. Archive.org, IBM, and the IEEE History Center are providing informal assistance.

• Steve Wozniak, co-founder of Apple: “Seeing the early equipment at VCF is an amazing experience. For many of us, it’s better than a museum. It touches on all the hopes and dreams of the time and the many efforts to achieve what others thought would never happen. It brings back memories of a revolution in the making. … The people you meet at the VCF are amazing.”

• Lee Felsenstein, moderator of the legendary Homebrew Computer Club and creator of the Osborne 1 portable computer: “In 35 years the personal computer grew from nothing into the most important device shaping everyday life. It should be part of everyone’s education to see how it grew and to learn from the people who grew it in ways they wanted to see it grow. VCF is the place to be where not only the equipment can be seen and tried out but, perhaps more importantly, where the people who rose to the challenge offered by these machines can be met and heard from.”

• Gordon Bell, top DEC engineer and co-founder of the Computer History Museum: “As a speaker at the first September 1998 VCF, I have been delighted to see it grow and flourish. The Vintage Computer Festival is an important institution for computing history simply by getting everyone together for collecting, sharing, and trading all form of bits. Having a forum, gathering, and market for old stuff a.k.a. vintage computers and the software that made them live is an essential way to preserve and expand the history of computing — for some of us, the greatest invention.”

• Dave Ahl, founder/editor, Creative Computing magazine: “Vintage Computer Festival East celebrates the hard work and vision of all the volunteers who have made the InfoAge Science Center –- now a National Historic Landmark — a place where one can learn from the past to live for the future. Oh, and it’s great fun too!”

Full details are online at http://www.vintage.org/2014/east/ and http://www.facebook.com/vcfeast. Contact: Evan Koblentz (President, MARCH; VCF East Producer): evan@snarc.net / (646) 546.9999(646) 546.9999 …. thank you and happy computing!

New(ish) Project: VIC-MIDI

VIC-MIDI Prototype
VIC-MIDI Prototype

This project had its start in a late 2009 discussion between Leif Bloomquist, a Canadian Commodore enthusiast and musician, and myself.  Leif had been playing with a hand-built 6850-based VIC-20 MIDI cartridge designed off a 1980’s era Maplin “Electronics” article, and wondered if a production run could be arranged.  I took a look at the design, and noted that the 6850 UART would be hard to source.  I suggested some design changes to bring costs down, and plans were made to refine the design.

To further the design, I wired up a newer UART (16450-based) to a daughtercard that could plug into the 6850 socket on the original board.  That allowed Leif to refine the software, and provide out the redesign.  Once that was done and successful, we discussed a final production version.  Changes included offering a built-in user-flashable ROM function.

That brings us up to late 2012.  I purchased the parts for a completely new prototype board, but could not get it assembled by World of Commodore, so I brought the parts to the show and hired the assembly done.

Well, the assembly resource took longer than expected to finish the construction, but I did receive this same exact board mid-Feburary 2013.  I fixed a few small design issues, only to discover the board expansion port was wired 100% backwards.  Commodore, for reasons known to them only, named the pins on the VIC-20 expansion port in reverse from the industry standard.  Since the prototype PCB pins were named according to the standard, every one would need modification.

I packaged up the board and sent it back to the assembler, but I must have messed up the address, as it did not arrive in a timely fashion.  Since I had shipped it from the Post Office directly, I didn’t get tracking information, and thus had no idea of its location.  After a few weeks, I resigned myself to the loss of the unit, and started gathering parts for a second unit to be shipped via trackable shipment to the assembler.  As it turns out, the assembler and I were both planning to attend the 2013 Midwest Gaming Classic in WI, so I made plans to transfer a new set of parts during the show.

No sooner than the show ended and parts were transferred, the original package showed up at my office, undeliverable.  I quickly saw the addressing issue, created a new trackable label with the correct address, and sent it on its way.  Which brings us to last week, when the unit arrived, after the rewiring effort.

After all of that effort, I could now begin the potentially laborious task of debugging a “paper design”.  I had designed the entire unit on paper, but had not previously proven out any of the elements on a breadboard.  Though the original UART design was working on Leif’s PCB, the new design was marked different, owing to the additional decoding logic needed for the FLASH ROM.  As such, it was almost a completely new design.   I’m not sure if credit is deserved and who deserves it, but the UART and FLASH ROM read access worked out of the box.  Bank selection for the FLASH ROM did not work, but that’s a minor issue.

And, we’re almost to the point of creating a VIC-20 MIDI production design.