Wow you got fancy there at the end with GUI tools and everything
- Something I always did wonder about chip design. How accurately do you feel like you understand a chip's performance characteristics when you just have the design specs for it, vs. a manufactured chip? Do you need intermediate prototyping physically manufactured implementations to test design ideas or can you pretty easily stay on the abstract level right up to the point you begin manufacturing what will effectively be the final chips barring minor revisioning changes subject to final testing?
We were always pretty accurate, keeping in mind that in the real world the performance of manufactured parts forms a bell curve - some always run better than others. You typically try to model the performance of where you think the middle of the distribution will be, and you miss by a bit, but you’re usually not too far off.
The way it works is you have SPICE models that describe the mathematical behavior of transistors. For the full-custom parts of the chip (oscillators, RAMs, PLLs, I/O drivers) you use SPICE as your tool to confirm the performance.
For the rest, we use “standard cells,” each of which is a specific logic gate with a specific layout. For example, you might have a dozen different 2-input NAND cells, each with a different set of transistor sizes and different layouts. You “characterize” these cells using automated tools with the spice models, to create tables. One column of the table is the 20%-80% rise or fall time for a particular input. The next column is the 20-80% rise or fall time for a particular output. There may be different tables corresponding to different alternate inputs. In other words, the behavior with respect to a transition on pin A may vary depending on the state of input pin B. Some people use percentages other than 20-80%.
Anyway, you make these tables.
You do your placement of the cells and route all the wires between them, then you do parasitics extraction. This involves an automatic tool that calculates resistances and capacitances due to the wires, and creates, effectively, a giant model of the circuit with pins of cells connected by RC networks.
You feed that into a ”static timing analyzer” that calculates how fast each cell output transitions based on its load, how long it takes the signal to propagate to the inputs of the next cell, and what the waveform looks like at that next input. It involves calculating the moments of the circuit equation. We used a tool from Synopsys called Primetime to do this. You feed that tool your constraints - “this signal has to be ready by such and such a time, or the chip won’t work.” It spits out a list of paths that take too long.
I came up with my own static timing algorithm, roughly based on an algorithm called AWE (asymptotic waveform evaluation) and built it into my graphical tool. I also built in a rough parasitics extractor (based on some work I had done years earlier at RPI), so when you moved cells around, it would guess at the new wiring, and very roughly estimate the new RC network. It would then tell you the new timing. You could even click on a cell and say “optimize size” and it would figure out the size of cell that would produce the best timing - making it bigger speeds up downstream logic, but means you put more load on upstream logic, so it was a fun optimization problem. It worked very well, and matched Primetime exactly as long as you gave it the same input (e.g. your extraction was accurate). It was pretty good considering I was a solid state physics guy and had never coded much in C in my life (and, in fact, I had never finished a coding or computer science class. I tested out in high school, and in grad school I enrolled in a bunch, but when I passed my doctoral oral exam on computer science I dropped them all).
Anyway, we also had tools to automatically add repeaters, etc. etc.
At a higher level, say you owned the integer ALUs (which, for some chips, I did). What happened was me and a couple others would floorplan the chip, creating an outline for that block. As we designed our block, we’d have “pins” on the edge, that abutted our neighbors. You’d route your wires to the pins, as would your neighbor. Moving a pin was like a nuclear submarine - both you and your neighbor had to agree in order for it to take effect. Anyway, you would have timing constraints at the pins. If you were receiving a signal, your neighbor might say “i can get it to you 50ps into the timing cycle,” and then you’d explain that to the timing tool. Similar when you are sending a signal to a neighbor.
So you are always working with these constraints, so in theory you are always “correct by construction.” Except it was massively difficult to fight the rules of physics to actually meet the constraints. You’d move logic across cycle boundaries, mess around with clocks to make some pipeline stages have a little more time than others, duplicate signals to avoid loading effects, duplicate logic, get very clever with logic design, sometimes create custom cells or custom circuits, force the metal router to do what you want by pre-routing a bunch of wires by hand, adjust where cells are located, etc. etc.