Big Mess o’ Wires


A home-built CPU, and other messy electronics adventures

Archive for January, 2008

Schematics!

schematic The first draft of the BMOW schematics are finished, along with complete equation lists for the 11 unique GALs (18 GALs total). This is everything needed to actually build the machine. You can view it all on the technical info page, along with an updated block diagram.

Whew, what a job that was! The datasheets, the timing diagrams, the insomnia… I’m really beginning to question my own sanity. If some of the schematics seem a little confusing and convoluted, it’s probably because I was asleep while I drew them. Ditto for the spaghetti wire paths.

I’m going to step back now and review the whole system, looking for any blunders I’ve made, or any opportunities for improvement. I hope that the people who’ve been following my progress can find some time to review the plans as well. Your design feedback is welcome and appreciated!

No comments

Initial Schematics Complete

The first draft of the schematics are complete. It was a good exercise, as working out every connection for every chip forced me to consider a few points I’d glossed over before. I ended up having to introduce a few more components than I originally planned on, to help generate needed control signals, or work around timing problems.

The memory and device schematics were the most difficult. As I wrote about previously, the timing requirements for the memory and USB module required careful design in order to avoid constraining the clock speed too severely.

The LCD module proved even more troublesome. It has some truly horrible timing constraints, including an 80ns setup time for data, and a minimum 230ns pulse width for the write enable signal. I couldn’t find a way to connect it directly to the memory data bus without slowing the clock down to below 2MHz. Instead, data for the LCD is actually written to a special register, and then on the next clock cycle, dedicated control logic writes the register value to the LCD. During cycles where the LCD isn’t being written, I’ve configured things so that it will always read the LCD busy flag. That means it’s impossible to read any other data from the LCD, like what character is currently at each location on the screen, but I can’t imagine why you’d want to do that anyway.

Now I need to go back through all the schematics, clean them up a bit, and check for places where I’ve exceeded TTL fanout limits (generally each output can feed no more than 10 inputs). Then I need to write the equations for all the GALs called for in the schematics: 18 in all. Once everything’s ready, I’ll post it up here for feedback.

No comments

More Timing Analysis

The schematics are nearly done. I’ve finished all of them except the memory/device subsystem, which is proving to be difficult. Unlike the registers and all the other machine components, the RAM and the USB interface don’t use a clock. Instead, they have a write-enable signal that causes data to be written the instant the signal is asserted. That means I need to take extra care to prevent the write-enable signal from being momentarily asserted while the state of the machine is changing from one instruction to the next– something that’s not necessary for clocked components.

The common strategy I’ve seen is to combine these kinds of write-enable signals with another signal that’s guaranteed to be asserted only when the write-enable signal is sure to be valid. Typically, this is the clock signal itself, or something derived from the clock signal. For example, if the write-enable signal is active low, it can be OR-ed with the clock signal, and the result will only be low if write-enable is asserted and it’s the second (low) half of the clock cycle. This allows the write-enable signal to temporarily take on invalid values during the first half of the clock cycle without harm.

I did a static timing analysis, based on my schematics and the chip datasheets, and in the worst case it will be 233ns from the start of a clock cycle until the write-enable signal and memory address are guaranteed valid. If I use the clock signal to combine with the write-enable signal, then the clock period must be at least twice 233ns, so 466ns, or 2.14MHz. I’d like to go faster than that.

My clock module also generates a signal called Q1, that lags the main clock (Q0) by a quarter cycle. By OR-ing together Q0, Q1, and write-enable, the result will only be low if write-enable is asserted and it’s last quarter of the clock cycle. That implies a limit of 233ns for three-quarters of the clock cycle, so 310ns for the whole cycle, or 3.22MHz. That’s a little better.

Unfortunately, using Q1 and Q0 to mask write-enable until the last quarter-cycle causes problems with the USB inteface. The USBMOD4 needs to have its read-enable input gated as well, because reading actually changes the state of the device by advancing its internal FIFO. Once read-enable is asserted, it can take up to 50ns for the USBMOD4 to put valid data on the output pins. Data must then pass through the 74LS245 bus driver (40ns), and arrive at the destination register 20ns before the end of the clock cycle to observe the setup time requirements. Therefore the quarter cycle must be at least 50 + 40 + 20 = 110ns, so 440ns for the whole cycle, or 2.27MHz. That’s hardly any better than the 2.14MHz achieved by using Q0 alone and ignoring Q1.

So for two different reasons, it appears that the machine will be limited to a top speed of 2MHz. With some redesigning, I could probably speed that up, but I’m more interested in just getting it working right now than in getting the fastest possible performance. It’s entirely likely that in practice I’ll be able to run faster than 2MHz, since all of my numbers are the worst-case figures from the datasheets. The listed “typical” numbers are generally about 1.5x faster than worst-case, so it might be possible to run as fast as 3MHz with the current design.

For the curious, the time-limiting path from beginning of a clock cycle to valid read/write-enable and memory address is:

Cumulative Time Delta Time Path
0 0 clock cycle begins
35 35 74LS194 condition code register’s new values are valid, and used as micro-ROM inputs
105 70 29F010 micro-ROM output
143 38 74LS139 decodes address register enable from micro-ROM output
168 25 22V10-based address register’s output is ready
193 25 22V10 address decoder determines if address is in program ROM, RAM, or memory-mapped hardware
233 40 74LS138 decodes read/write-enable signals for specific hardware devices

Follow up: After a more careful reading of the datasheets, things aren’t quite as bad as I’d first thought when combining Q1 and Q0 to mask the enable signals to the last quarter clock cycle. First, the worst-case data propagation delay for the 74LS245 is only 12ns, not 40. The 40ns figure is for the output-enable signal on the ‘245, which should already be set by the time the data is coming through. Second, the setup time at the data registers is actually 15ns, not 20. Add up the 50ns delay from the USBMOD4, 12ns at the ‘245 bus driver, and 15ns setup time, and you get 77ns. Coincidentally, that’s precisely the amount of time allowed by a 233ns time for three-quarters of the clock. So the limitation imposed to guarantee valid read-write/enable signals exactly matches the limitation imposed to guarantee valid data read from the USBMOD4, at a clock period of 310ns for the whole cycle, or 3.22MHz.

No comments

Logic Analyzer/Oscilloscope

My Hewlett-Packard 1631D logic analyzer / digital oscilloscope arrived today: the finest 1985 technology that $35 can buy. I bought it dirt cheap from eBay in “as is” condition, but it seems to be working great! With this acquisition, I can proudly say that I’ve crossed the line from ordinary run-of-the-mill nerd to super-nerd.

Holy cow, there are a lot of buttons and wires on this thing. What’s a trigger? Where’s the manual? My head hurts just thinking about it.

After some time spent jabbing hesitantly at buttons, I finally managed to get a scope trace working. Here it is, showing the output of a 1 MHz clock oscillator. Mmmm, square wavy goodness!

HP 1631D

2 comments

Piles of Hardware

I keep accumulating more and more hardware, and my office is beginning to overflow with boxes, tools, and wires. I need to start turning this pile of parts into an actual machine ASAP.

The first of my recent acquisitions was a replacement universal programmer, an EasyPro 90B to replace the TOP 2007 that had problems programming GALs. Yes, I’m replacing one no-name programmer from China with another, but in this case the EasyPro 90B seems to work fine. If I’d read reviews before making my original purchase, I could have saved myself a lot of hassle. The whole TOP line has received universally poor reviews, from what I’ve seen.  Both the EasyPro and the TOP programmers were ordered from www.mcumall.com, who offered to exchange the TOP programmer after I wrote about my problems in their online forums.

My second new hardware arrival was a USBMOD4 interface module, for connecting my computer to a PC via USB. It couldn’t be simpler to use. Install the driver, and it appears as an additional COM port on the PC. Connect a USB cable to the USBMOD4, launch a terminal program, and every keypress is transmitted and stored in the USBMOD4’s FIFO buffer. An output pin changes state when the FIFO has data in it, which the computer can sense and then enable the USBMOD4 to drive the next FIFO byte onto the data bus. I was able to put together a test circuit to read data from the PC using a protoboard in about 30 minutes.

The only problem I have with the USBMOD4 is that it appears to be hardwired to draw its power from the USB cable, rather than from the system’s power supply. This means that it’s “on” as soon as the USB cable is connected, regardless of whether BMOW is turned on or off. What’s worse, if I connect the USBMOD4’s power pin to BMOW’s power bus, BMOW will turn on as soon as the USB cable is connected. I need to isolate the USBMOD4’s power from the rest of the machine’s, while still allowing for data to be passed between them. This may be a little complicated. I’m assuming it’s OK to connect their grounds, even though theoretically the PC’s ground might not be at the same electrical potential as BMOW’s. The bigger problem is that the active low signal from the USBMOD4 that signals when there’s data in the FIFO will be low if no USB cable is connected, because there will be no power to it. This will make BMOW think there’s data to be read. I think I can solve this by using a pull-up resistor connected to BMOW’s +5 supply. If anyone’s ever done something similar before, I’d love to hear about it.

I also bought an HP 1631D logic analyzer off eBay, although it hasn’t arrived yet, and it was an extra cheap ($35) unit in as-is condition. It’s a combination 100MHz bandwidth digital oscilloscope and 48 channel logic analyzer. A logic analyzer records a history of the logical value (0 or 1) of a set of signals, like an address bus or data bus. It can be used to help debug hardware problems, like why a computer locks up when it reaches a certain address. Basically, it’s a hardware debugger.

I’m sure there was a point in my life (like 2 months ago) where I assumed anyone who had a personal oscilloscope in their home was the biggest nerd imaginable.

4 comments

Digital Memories

While hunting for my soldering iron, I found my first digital electronics project gathering dust in a box. I thought I’d thrown it out long ago, so I was happily surprised to see it. It’s not much to look at– just a 555 timer and a bunch of NAND gates wired to a row of LEDs, configured so that a single “blip” of light races up and down the row like Knight Rider’s front bumper. In fact Knight Rider was probably still on the air when I built this thing in the spring of 1991. I called it The Opinicus Blinker.

Opinicus blinker

Opinicus was the name of a fake technology company I pretended to work for during high school, so that I could get into trade shows and scam real companies for product samples.

Sadly, The Blinker broke a long time ago, which is why I thought I’d tossed it out. I hoped maybe I could troubleshoot the problem and fix it, but after cleaning the battery contacts and installing a new set of batteries, it fired right up. Woohoo! There it is with the second LED from the left illuminated. Not bad for a 17 year old piece of junk. And check out the legend on those chips: “SOVTEK 7400 11/88, MADE IN USSR”. Wow.

The rate of progress on BMOW has been slowing, as I prepare to begin actual construction. Everything is pretty much ready to go, and there are just a few more parts I need. The last real hurdle is working out the physical layout of the machine: where to fit the chips on the board, where to fit the board in the case, how to connect power, and so on. I’ve decided to mount everything on a piece of wooden shelving for the time being, rather than build a real case. I didn’t want to get so hung up on case design that it distracted me from the main task of getting the CPU built and running.

2 comments

Das ist kein 6502

I received an email from CPU-builder Dieter Müller, describing his very impressive M02 project to build a custom CPU binary compatible with the 6502, using standard 74LS and similar parts. In short, a project quite similar to my own, except that he’s already done it. Take a look at the photos and hardware description on his site http://freenet-homepage.de/dieter.02/m02.htm. He even got the Commodore 64 kernel and BASIC running on the M02.

No comments

7 Segment LED

Here’s a job that sounds reasonable enough: connect an 8-wide dip switch to a pair of 7 segment LED displays, so that the 8-bit binary number on the dip switch is displayed as a 2-digit hex number on the LED displays. I didn’t think it would take me too long to configure a GAL to control which segments of the LED displays to turn on, and then wire the whole thing up. Boy, was I wrong.

DIP switchLED displayLED display

My basic plan was to connect the dip switch to the GAL’s inputs, and the LED displays to the GAL’s outputs. Easy cheesy.

pull-up resistor circuit

Problem 1. A dip switch doesn’t provide logical 0 or 1 values (0 or +5 volts) that can be connected right to the GAL’s inputs. It’s just 8 switches, each one either open or closed. A simple pull-up resistor circuit is needed to generate a 0 or +5 volt input from the switch position. When the switch is open, no current flows through the resistor, so there’s no voltage drop, and the output terminal is at +5 volts. When the switch is closed, the output terminal is tied directly to ground (0 volts).

One problem with this design is that when the switch is closed, current is constantly flowing from +5 through the resistor to ground. With a 440 Ohm resistor (the largest I had on hand), 11 milliamps (5 / 440) flows through the resistor. With all eight switches closed, that’s 88 mA wasted. My hack-tastic power supply can probably only supply a few hundred milliamps, so that’s a big fraction of the total available supply.

Problem 10. Decoding a 4-bit number is fairly simple: 4 inputs from the dip, the GAL decodes the data, 7 outputs to the LED display. An 8-bit number using the same approach would require 8 inputs and 14 outputs, but the GAL only has 10 outputs. Doh!

My solution is to share the same 7 outputs between two different LED displays, with an 8th and 9th output to enable one or the other display. Only one display can be illuminated at a time, but if you switch between the displays rapidly enough, it looks as if they’re both illuminated. I used a 1 MHz clock oscillator to switch back and forth between the two displays. The 7 data outputs from the GAL are connected to the positive terminal of the 7 LED segments on each display. The 8th data output is connected to the shared negative terminal of the LED segments in the first display, and the 9th data output is connected to the shared negative terminal of the second display.

To illuminate a display, its shared negative terminal is set to 0, and the appropriate data outputs are set to 1, generating a positive voltage across the LED segments. To deactivate a display, its shared negative terminal is set to a high-impedance (disconnected state), so none of the LED segments will light up regardless of what the data outputs are doing. It would also be possible to deactivate a display by setting its shared negative terminal to 1 (+5 volts), but this would put a reverse voltage across the LED segments. That’s best to avoid, since too large of a reverse voltage can damage a diode.

Problem 11. Writing the logic equations for the GAL to decode 8 input bits into 2*7 LED segments proved more difficult than I expected. My first attempt had way too many product terms per output, and was too complex to fit in the GAL. I did some hand optimization, but it was tedious and error-prone. Finally I found a website with an interactive Java applet for making Karnaugh maps, and used it to simplify the equations enough to fit the GAL. The Java app was nearly as tedious as hand optimization, though, and it took me a long time to finish the simplification.

220 Ohms

Problem 100. You can’t just connect a chip’s output pin directly to an LED. Since the diode offers nearly zero resistance, it would be like shorting the power supply to ground if the output pin’s value were a logic 1. Instead, a resistor must be put in series with the LED, to limit the current. Larger resistances will limit the current more, but will also diminish the LED’s brightness. I used 220 Ohm resistors in series with each LED segment, which should result in a current of 23 mA (5 / 220). Most LED’s appear designed to hit their advertised brightness level at about 10-20 mA.

Problem 101. There are a lot of wires to connect! OK, this isn’t really a problem, but I was still surprised at how many wires I needed to cut, strip, and push into the protoboard for such a simple project. 8 from the power supply to the 440 Ohm resistors, 8 from the resistors to the dip switch, 8 from the dip switch to the GAL, 7 from the GAL to the 220 Ohm resistors, 14 from those resistors to the two 7 segment displays, plus the 2 shared negative terminal connections, the 1 MHz oscillator, and a handful of other miscellaneous wires. Ugh.

Problem 110. After I’d finished everything and turned on the power, it didn’t come even remotely close to working. LED segments light up in totally random ways. The same dip settings didn’t even always generate the same results. Changing the MSB of the input changed which display was illuminated. Even just touching the circuit with my hand sometimes caused things to change. I was totally confused. At first I thought maybe I was drawing too much power from my power supply, and the voltage levels were getting out of spec, causing erroneous behavior in the GAL. A lot of poking and probing with a multimeter suggested everything was OK in the voltage department. Then I hunted for wiring errors, but found none. I rechecked all my logic equations as well.

After a very long time, I discovered that the GAL had been misprogrammed somehow, and some of the outputs were using the clock input as if it were a data input. I have no idea how that happened– is the chip failing? Is my chip programmer faulty? Sun spots? I reprogrammed the GAL, and things started working much better. It was still broken, but at least now it was broken in a deterministic way, and it sometimes displayed recognizable digits on the LED displays.

Eventually I discovered several errors in my logic equations that I’d overlooked the first ten times. In one place I’d used an AND instead of an OR, and in another I’d omitted an entire term from the equation. It’s amazing how many times I looked at those equations without seeing the mistakes.

After fixing those, the whole thing was almost working, except for:

Problem 111. Strange things happen with long (and not so long) wires involving cross-talk and noise. I never did satisfactorily explain how the MSB of the data input seemed to be acting like a clock input. When I wired the clock input pin straight to ground, the GAL would still often appear to have been clocked (the active LED display would switch) when I changed the MSB. The problem went away when I used a shorter wire to connect the clock pin to ground, so I suspect it was some kind of cross-talk from the neighboring wire. When I later connected the clock pin to the 1 MHz oscillator, it seemed to work fine.
The disconcerting thing is that the clock wire was not especially long (3 inches) nor close to the MSB wire, except that they happened to connect to adjacent pins on the GAL. If it’s truly that easy to accidentally perform false clocking, then I’m going to have a lot of problems building the full machine.

Problem 1000. Everything was finally working, but I wanted to examine the circuit behavior in more detail. Earlier I mentioned the 220 Ohm resistors I put in series with the LEDs, which should have resulted in a 23 mA current through each LED. I measured the current, and it was only about 6 mA. I also measured the voltage at the GAL’s data output pins, and rather than +5 volts, it was only 3.2 volts. This suggests a problem.

I can’t explain why I saw 6 mA of current specifically, but after reading the GAL datasheet more carefully, I decided I was lucky (?) to get even that much. The chip’s maximum output current per pin at a high (logic 1) output voltage is only 3.2 mA. Exceeding that by nearly 2X explains why the output voltage was dragged down from 5 to 3.2 volts. It’s possible that could damage the chip. At the very least, it doesn’t seem like a good design. I’m still curious why I saw 6 mA and not 3.2 or 23, though. Maybe I reached the maximum amount of current that my power supply can deliver, or maybe the diode itself has some current limiting effect?

The math tells me a 1562 Ohm resistor in parallel with the LED would give me the maximum rated current of 3.2 mA per LED segment. Would that be enough current to get sufficient brightness, though?

Although I didn’t measure it, I think I’m running into similar problems with the shared negative terminal of the LEDs, which is also connected to a GAL output pin. The datasheet says the max current per pin at a low (logic 0) output voltage is 16 mA. If I’m sending 6 mA per LED segment through seven segments with a shared negative terminal, then that’s 42 mA (6 * 7), way more than the rated maximum.

Problem 1001. Now I have something that works, but feels iffy. I wouldn’t incorporate it into a finished computer design, due to concerns about greatly exceeding the GAL’s rated maximum output current. The trouble is, I’m not sure how to fix it without introducing more parts between the GAL and the LEDs to provide and regulate current. I’ve seen ready-made LED driver chips, but they’re always binary coded decimal rather than hex. Whatever the ultimate solution, it feels like an awful lot of work just to display a single byte on a pair of LED displays.

To put a positive spin on this experience, I learned more about the kinds of difficulties and pitfalls I’m likely to encounter when I begin to build the machine on the wire wrap board. It’s much better to face them here on the protoboard, where alternative solutions are easy to try, than on the more unforgiving wire wrap board.

No comments