Wednesday, March 5, 2025

7400 Logic Calculator: One ROM Design - More Ideas

Two years ago, after writing about my ideas for a calculator built from 7400 series logic, I posted a second time about shrinking that from three ROMs to a one-ROM design to save space. Last year, I had more ideas about how to improve the one-ROM design and made a lot of progress on a schematic. Laying everything out showed that there was still a lot to figure out. At that point, I stopped working on the schematic and started working on this blog post but didn't finish. When I came back a few months later, looking back over my notes to remember how the design works inspired me to come up with a separate second design! This posts explains the first design that didn't quite work and the second design that seems to have solved all the pending problems while being much smaller

First Design
The biggest difference in the first design is the register arrangement. Rather than two 74HC670 register file chips driving the address bus of an ALU EEPROM, this design uses two 8-bit latches to drive a single EEPROM used for everything. The two 74HC670s are still on the bus but serve as storage memory rather than driving the EEPROM address directly. The two latches in the new design can each read eight bits from the data bus and drive the address buses of the EEPROM and RAM. This allows data access to those two memories and also serves as the ALU since the single EEPROM fulfills that function as well. This simplifies things a little compared to prior designs since no separate RAM pointer chip is required. Half of each 8-bit latch is connected to the address bus through resistors to act as pull-ups and pull-downs. A separate ALU latch overcomes those values when activated. This allows the two latches to form a 16-bit pointer when the ALU latch is disabled by an instruction and to function as two 4-bit registers when the ALU latch is enabled. One of the big problems to solve in a 4-bit design like this is how to access each nibble of a byte fetched from memory, do calculations on the nibbles, then recombine the nibbles to write them back to memory. This design has the low nibble of one latch and the high nibble of the other latch wired directly to the address bus so those two nibbles are used for ALU operations. This allows access to the high and low nibbles of any byte but also complicates things a bit for instructions like increment or decrement that treat the combined nibbles as a single byte. Another complication is the carry bit which needs to be disabled when not fed to the ALU and annoyingly wastes a whole chip for a single bit.

Another big difference from the prior three-ROM design is the program counter. Rather than four 74HC193 counters, this design uses just two counters for the low byte of the program counter and an 8-bit latch for the high byte. This means the program needs to manually load the high byte of the program counter at the end of each 256 byte section of the program, but that's not a big price to pay if it reduces the chip count by one. All three program counter chips need to be disabled so they don't drive the address bus when the two latches used for data and ALU access are driving it. Looking back at the datasheet for the 74HC193, I realized that it has no OE pin to put the outputs in Z-state. This is a big problem since relying on these chips being Z-stated was a big part of my prior design. As an alternative, I decided to put resistors on the program counter lines so that the two latches can overcome them when they need to drive the address bus. It probably should have been a sign that the design was getting too complicated when I had to add more and more resistors to get it to work. I also ended up adding diodes in a lot of places to form OR gates without adding more chips which also overcomplicates things. One good thing was the addition of symbols for resistors and diodes to my circuit schematic program. Also, I played around with using a shift register for part of the instruction sequencing which was a useful discovery.

Second Design
Like the first design, the biggest change here is the register arrangement. While the prior three-ROM design used 74HC670s register file chips to drive the ALU and the design above uses them as storage, this design uses four of them to replace all of the program counter and register chips. Since there's no external program counter, each 16-bit instruction is followed by a second 16-bit instruction that sets the low byte of the program counter manually. This means half of the EEPROM is lost to program counter functionality, but the savings in chips is definitely worth it. Like the design above, a second instruction is needed to manually set the high byte of the program counter when it reaches the end of each 256 byte section of the program.

Each 74HC670 has separate two-bit addresses for reading and writing. The instruction byte is latched out on the first cycle of every instruction and contains two bits for the write address for any 74HC670s that the instruction writes to. Two bits for the read address of each of the four chips is too much to encode in the 8-byte instruction, so a separate latch holds those addresses and is set manually by an instruction. Another bit in the instruction controls whether the read address latch is Z-stated which is useful when an instruction needs to put the program counter value on the address bus. The only use of pull-ups/pull-downs in this design is reusing one of the two instruction bits for the 74HC670 write address to pull the address bus up or down. This means that all four 74HC670s driving the address bus will select the values they hold at either address 0 or address 3 when the address latch is Z-stated. Storing the program counter at address 0 and loading a new address piece by piece into address 3 as it's ready is an easy way to handle the tricky problems of jumping to a new address and also using the address bus to access memory without adding extra chips.

After the instruction latch is set on the first cycle, three bits of the instruction drive a 74HC138 demultiplexer to select which device reads the data bus. Two more bits drive a second 74HC138 and select which device drives the bus. On the second cycle, the program counter advances and the second byte of the instruction is available as data if the EEPROM is selected to drive the bus. Halfway through the second cycle, a pulse to the selected device latches the value on the bus. Here are the devices that read and write the bus:    

    Outputs to Bus
    Bit 0: RAM
    Bit 1: Keypad Input
    Bit 2: Buffer register
    Bit 3: EEPROM
    Inputs from Bus
    Bit 0: Low byte of 74HC670s
    Bit 1: High byte of 74HC670s
    Bit 2: Register address selector
    Bit 3: Buffer register
    Bit 4: LCD
    Bit 5: RAM

After the two-cycle process described above where the instruction is latched out on the first cycle and the bus is read and written on the second cycle, execution proceeds to the next instruction which always sets the low byte of the program counter to point to the next instruction. Since the 74HC670s handle pointers, ALU arguments, and the program counter, setting program counter bytes is a regular instruction like any other. The only counter chip in the system is a single 74HC193 that drives A14 and A13 of the 32K EEPROM with outputs Q2 and Q1. These two bits allow the program to cycle between the two bytes of each instruction followed by the two bytes that set the next program counter value. Q0 of the counter is OR'ed with Q1 to get the write pulse for the instruction latch and OR'ed with the inverse of Q1 for the write pulse for the bus. The same 74HC32 and 74HC04 chips that provide the OR gates and inverters for this are also combined with De Morgen's law to build the equivalent of an AND gate so that the EEPROM always drives the bus on the first cycle when the instruction latch is written and on the second cycle if the EEPROM is selected to drive the bus by an instruction.

Since address 0 in the 74HC670s is used for the program counter and address 3 is used for jump addresses, address 1 and 2 are free to use for pointers and ALU operations. Address 3 can also be used temporarily as long as it's free when it's time to load a new address into the program counter. This arrangement solves the third really tricky problem with these designs in addition to handling the carry and accessing nibbles in bytes which is indirect memory access using a pointer stored in RAM. The challenge for this is juggling the address of the pointer, both fetched bytes that make up the pointer, and the fetched value. Having three nibbles in each of the four 74HC670s is more than enough for this. Each pair of 74HC670s is loaded at the same time with a whole byte which is required for the program counter to work as described above. For ALU computations, a whole byte is fed into each pair but the address selector latch mentioned above can output a different nibble for each 74HC670 in the low byte. This allows an ALU lookup in the EEPROM using either nibble from two bytes fetched from memory (or even both nibbles from the same byte) in the low byte and the address of an ALU table in the high byte. Since the 74HC670s have separate two-bit read and write addresses, the lookup result can either be written to a different address than is currently being read from or into a latch added to buffer values and write them back later.

The last piece of the puzzle is the carry bit. Unlike all the previous designs, this one does not have a physical carry bit. For addition, there is one instruction to calculate the sum and carry and another that takes that result as an argument and generates a value that is itself an instruction. This value can be copied directly from the EEPROM like any other ALU result and written directly to the latch holding the high byte for the address bus where ALU operations go. It's a bit odd to have an ALU operation return an ALU lookup address but this is relatively efficient and reduces the chip count even further.

It was very satisfying to build the second design since the first design took so much time and turned out to be flawed. I don't plan on building this design anytime soon, but I'm glad I have all my ideas down so I'm ready if the time ever comes. Best of all, this design only takes 15 chips which is the smallest design yet. As with the other designs, it was also a lot of fun to lay out the design in my schematic CAD program:

Click the picture below for full SVG image



No comments:

Post a Comment