StephenHermer.com
Writing, Iguanas, and Electronics

Front Panel Instruction Indicators - Cardboard Prototype

It is pretty rough, but this cardboard prototype of the "Instruction Indicators" panel will be pretty useful when I am working on control logic. I am working on the computer instructions / operations, and this will greatly speed development and allow easy confirmation that the control signals are correct.

Making a prototype was also helpful to identify some issues with the current design, including how impossibly bright the LEDs are. The illuminated LED in the above photo has two layers of opaque plastic covering it. I will be experimenting with dips and coating in the coming weeks, but the best option may be to power the LEDS from a separate 3-volt system to improve the lifespan of the LEDs.

Comments
Login to post comments.

Instructions and Indicator LEDS

I will go over the actual operations and flags in detail, in future posts. For now, I just want to talk briefly about the blocks as currently envisioned. Before I do, there are three colours of LEDs in the graphic, as follows:

Yellow   - Planned to be implemented in the first phase.
Orange - Planned to be implemented in the second phase.
Brown   - Set aside for future use.

ALU Block
The ALU takes a 5-bit control word and does not require any additional control or decoding logic, so it is trivial to implement ALU functionality. This block is basically broken into three sections:

Left      - Arithmetic...          A plus B
Centre - Logic                    A XOR B
Right   - Complex Logic     A AND NOT B

Command Block
This block contains indicators for non-ALU operations, and includes things like register copy, jumps, branches, and stack related functions

Flags Block
This block, to the right of the Command Block, displays the flag indicators. The carry flag can be cleared, and thus there is a separate indicator for that. Indicators for system halt and reset round this block out.

Program Counter Block
This block contains the four dedicated counters assigned for RAM and ROM addressing, in two pairs. Normally only one counter will be active at a time.

Overflow Block
This block contains three indicators that will be illuminated when RAM addressing overflows, when ROM addressing overflows, and when the Stack Pointer overflows. Note that an overflow error will be thrown for an "under flow" as well; any time an address counter rolls over or resets an error will be thrown.

Comments
Login to post comments.

Instructions, Decoding, and Timings - Part 1

For me to understand the fetch, decode, execute cycle... well, I need to work through it, I guess. So, here is my first crack at the clock timings for the four possible MOV operations. 
 
MOV Reg, Reg    ; Register to Register
MOV Reg, $0000  ; 16-bit Value to Register
MOV Reg, #0000  ; Register to Memory
MOV #0000, Reg  ; Memory to Register 
 
The above are planned assembly code instructions for moving data between registers, loading values into a register, and moving values between registers and memory. The ALU will output to registers and memory as well, but I will leave that until much later.
 
 
001-MOV_(R,R).jpg
The "Register to Register MOV" operation is pretty simple. The instruction is fetched and decoded, and the PC is incremented during the first step. The second step is the execute phase, where one register outputs and on the rising clock, the other register writes. I have provisions for delayed and inverted clocks in my design, but I am hoping they will not be needed to prevent timing issues.
 
 
 
002-MOV_(R,V).jpg
The "Value to Register MOV" instruction is basically the same as the Register to Register version. Because the PC was already incremented, the correct address is loaded and we need only output from memory and write to the selected register. The PC needs to be incremented a second time, to ensure the next fetch operation is on an instruction and not the value we just copied to a register.
 
 
 
003-MOV_(R,M).jpg
A "Memory Location to Register MOV" is a little more involved, as the address needs to be loaded into a separate pointer and made active. Like the Value to Register MOV, the PC needs to be incremented once to make sure it points to the next instruction. On the third step, the memory (as addressed by the temporary address register) outputs, and the selected register writes. The PC needs to be made active once the memory operation is completed.
 
 
 
004-MOV_(M,R).jpg
The "Register to Memory MOV" instruction is nearly identical to the "Memory to Register MOV", with only the final output and write targets switched. 
 
 
Comments
Login to post comments.

Bus Architecture - February 2020 Design

As I work through plans for the control logic and instructions, I realize that I need to simplify and streamline things. This does not mean lots of registers or segmented memory, or dropping a stack, but it does mean I am looking closely at how those things will work.

Six months ago, I was considering a two data bus, single address bus system with registers, pointers, memory, and even the ALU accessing at least two of the three buses. I like this because I could have an "A" and a "B" data bus that work as the inputs to the ALU. This simplified some things, and seemed like an elegant solution to the problems of moving data. Unfortunately, a three-bus system requires more control logic and a lot of transceivers, not to mention all of those extra traces that had to fit into two layers (I am not planning on moving to four-layer PCBs, lol).

Three months ago, I settled on a two bus system with address and data buses on the backplane. On paper this seemed the perfect solution, and seemed to be a common one in TTL based computers of the 70s and 80s. Again, there were difficulties with the two buses super-imposed on the backplane... complicated traces, extra transceivers, etc.

A more pressing concern with a common address bus is bus contention. I plan on having a bank of RAM, a bank of ROM, and later one of two Stacks. Each of these will need their own addressing, and if I want to be able to push a value onto a stack from RAM, it would be nice to have separate addressing so we can perform a single clock-cycle transfer (similar to copying values between registers).

With the exceptions of the Instruction Register and Arithmetic Logic Unit, every device can read from and write to the data bus. With separate addressing for the memory based devices, we can copy values from any device (again, except the IR and ALU) in a single step. RAM to Register, Register to Pointer, Pointer to Stack, Stack to RAM, etc. The control logic is pretty simple, with each device having a write and load signal to control access to the data bus. In the case of RAM and ROM, I plan to have two pointers that can be selected from. Until a Stack is added, this will be the only efficient method to store a "return address" when performing a jump. Even after a Stack has been added, this will be more efficient when recursion is not evident.

The ALU has two inputs, labeled "A" and "B". In this design, these will have a choice of one of two inputs, much like the address lines for the memory cards. Multiple possible inputs mean we can save juggling data between registers, and if one of those registers is an address pointer, it means the ALU can calculate jumps and write them back to the address pointer very efficiently.

To start, we will only need one bank of memory with the pointers, the ALU with two input registers, one general purpose register (for output), and the Instruction Register. This will be enough to get started with.

Comments
Login to post comments.

Card Pans - Block Diagrams

This is the "planned" architectural design for my card-based computer. The Control logic will not be a card slotted into the backplane, but pretty much everything else will be. I need to learn more about the various sound chips to lay out a sound card, but I imagine it will be complicated. I have dropped the Address Bus from the design as too limiting, but have not reallocated those 16-lanes yet... perhaps an I/O bus?I am not including any real details about flags or control here, to keep things simple... this is basically just an overview with block diagrams laid out to kind of look like the cards.
 
 
Register.jpg
 
The general purpose register card is already designed and manufactured, with three of them assembled and working. These are very basic devices, and might end up being entirely replaced by counters or shift-registers for efficiency purposes (if any register can be incremented or shifted, we save having to copy values from the general purpose register to the special register, perform the operation, and copy back). The general purpose register will also act as an interface for I/O operations... buffering front-panel input and holding "output" values for 7-segment displays.
 
I expect there to be at least four general purpose registers.
 
 
Counter.jpg
 
The counter card can read and write the data bus via transceivers, as the ICs used are not 3-state. This allows the ALU to write directly to the counter, after a jump or branch calculation. The counter always outputs to a pair of headers and supports increment, decrement, and reset signals. I think this design needs to generate an out-of-bounds signal, when the counter rolls from 0000 to FFFF or from FFFF to 0000.

I expect there will be several counters, optimally two for RAM, two for ROM, and one for the Stack. If we include a separate "Return Address Stack", that will require a counter to drive the address as well.
 
Feb19_Counter_Plus.jpg
 
I am prototyping an alternate counter card that includes a dedicated adder and  "offset-register" to make relative jumps easy and efficient. This would require some extra controls to change the offset register, but could save a lot of clock cycles when compared to using the ALU to calculate relative jumps. This design would need e out-of-bounds signal generation based on overflow or underflow from the adder logic to detect when the address rolls over (the address being somewhat independent of the actual counter value).
 
I expect there will be several counters, optimally two for RAM, two for ROM, and one for the Stack. If we use two stacks, that would require a sixth counter for the second stack. Not all counters would need to support offsets, but in those cases the outputs from the 74LS193a can be jumpered directly to the address output headers.
 
 
Shift-Register.jpg
 
The shift register card is very similar to the counter card, with the exception being that bits are shifted left or right instead of values being incremented or decremented.
 
 I expect there to be only one shift register needed.
 
 
RAM.jpg
 
The RAM card can rad from or output to the data bus via transceivers. While the RAM is 3-state, it is CMOS based and the transceivers will provide needed buffering of the bus. Addressing has been moved from the backplane to a pair of headers, controlled by transceivers or "one of two 4-bit word selectors", allowing for efficient addressing changes.
 
I expect there to be at least one RAM card, but will need an additional one for the Stack, and possibly a third for a "Return Stack"... if the stack is divided for efficiency purposes. 
 
ROM.jpg
 
The ROM card is functionally identical to the RAM card, as the EEPROMs and SRAM ICs used have identical pinouts and control signal requirements. While technically writable, the plan is to have a firmware card that does not receive WE signals from the control logic. 
 
The current plan is to have two ROM cards, one as firmware (to contain useful functions that can be called from user programs in RAM), and one that can act as storage (with the WE signal enabled to store programs).
 
 
Feb19_ALU_fixed.jpg
 
The ALU can write to the data bus via a buffer register (the 74LS181 is not 3-state). It receives inputs via sets of headers for the "A" input and the "B" input. The design was to have "A" and "B" simply be registers, but I plan to experiment with making them selectable, so that one input could toggle between a register and a counter (like the PC), while the other could toggle between a pair of registers. This would allow for more efficient calculations and comparisons without needing to spend cycles moving values between registers).
 
There will be a single ALU in the computer, but it may be cost-effective to design the ALU in halves for PCB manufacture (minimum orders are five PCBs).
Comments
Login to post comments.

EEPROM Test



I know it looks like a mess, and it is, but this test of the 74LS193 counters driving an eeprom was a success. The counters and eeprom are located on the breadboards, the left display is showing the current address (the output of the 74LS193 counters), and the right display is showing the stored value in the "A" register. Because the "A" register is latching with the clock, it always contains the output of the eeprom (the eeprom writes to the data bus, and the "A" register is reading from it).

Comments
Login to post comments.

16-bit Counter PCB Design

I have been struggling with planning the control logic of the computer, and a big part of that was handling the two buses. Some ICs, for example, the 74LS574 I use for registers, are 3-state. With a 3-state IC, the output can be disabled, and thus the inputs and outputs can be tied directly to a bus. In the case of the 74LS574 based registers, I want them to always output to a separate header, so I use transceivers to control access to the bus. With ICs that are not 3-state, we have no choice but to use transceivers, or they would always be outputting to the bus...even when we did not want them to. A second issue is that we need to separate the input from the output, otherwise these ICs output would interfere with the input values we want to store. Because of this, we need transceivers on both the input and output of our "card" to ensure that the card does not cause problems for other devices in the computer.

With a 16-bit data bus and a 16-bit address bus, I need four 74LS245 transceivers for 3-state devices, and six for the others. The cost of the extra transceiver ICs is not an issue (I have nearly sixty of them lol), but the PCB traces quickly get out of hand and the control logic to enable, disable, and set direction for all of them is complex.

The address bus has always been problematic in my design. I want to have multiple counters that can be enabled and disabled (for jumps, returns, etc), and I have multiple blocks of RAM and ROM that I want to be able to access. To that end, I have made the difficult decision to dispense with the address bus. This means that counter cards will need output headers (similar to the register cards), and new RAM or ROM cards will need to accept addressing from a similar header.

Without an address bus to worry about, we only need four transceivers, and because of that, we can stack them above the data bus and run all of the controls without any difficulty.  The 74LS08 (quad AND gates) is used to gate the clock signals. If the WE signal is set, the CLK and !CLK signals are allowed through, otherwise no clock signals are available to the card. This has several benefits, including reducing the "fan out load" on the clock. All of the other signals and controls are passed through without buffering. The left controls (Flags and ALU lines) are only used on some cards, so buffering will only be added on appropriate cards. The right controls are not bused, so they do not need buffering. To keep things consistent, the "Write Enable" signal is active low (same as the Output Enable", but we need to invert it if we want to AND it with the clock. If the AND gate received a low "WE" signal, it would not pass the clock through, and thus no write would occur. We also need to and the Increment and Decrement signals with the clock, but those are already active high so we can bypass the hex inverter (74LS04). I have added some additional labels in green to make it easier to follow in the closeup shot.

Comments
Login to post comments.

16-bit Counter Prototype - Round Two



The 16-bit counters are successfully driving registers and displays attached to the backplane. I did some testing with the "autorouted" SRAM card, but I only had the data bus connected. For this test, I was running the 10Hz clock and all controls were via the appropriate connections (i.e. the backplane), except where the breadboard was involved. 

The display on the left is connected directly to the outputs of the four 74LS193 counters on the breadboard. The counters get power and the clock (via the 74LS08 "gate") from the development card (at the front of the backplane). The red lines between the breadboard and the development card link to the backplane's data bus. The development card has the 555 timer circuit providing the clock to the backplane and the breadboard. The display on the right is attached to the monitor header of a 16-bit register card, and displays the output from the register. The ram card (not visible in the photo) was storing the data bus value at whatever random addresses the 16-unconnected wires was generating. 

This test was to ensure the bus was working correctly, and that timing issues do not appear (at low frequencies, anyway). The next step will be to test writing to memory, then reading the values back. I do not have an input rig setup, so I will probably end up using an arduino for data reading and later checking.

Comments
Login to post comments.

16-bit Counter Prototype Testing

I made some modifications to the counter prototype, including gating the clock with a 74LS08 (quad AND gates), but it seems to have picked up some quirks. I was not able to adequately test at 10Hz... it was just fast enough to make it hard to catch errors with the naked eye, but just too slow for my oscilloscope. I ended up soldering up a second 555 based clock, this time running at a sedate 0.5Hz, giving me nearly two seconds to see each increment or decrement.

At the slower speed the issue became clear. The low 4-bits were displaying values out of order, and the issue turned out to be a couple of crossed jumper wires between the first counter IC and the first mc14995 display driver. Those crossed wires should have been an obvious place to start, but at 10Hz I could not tell the first digit was displaying values out of order, I was barely able to see that it seemed to skip values.

The interesting part to all of this is I learned of a limitation of oscilloscopes (or at least, the Siglent 1104X-E), namely they cannot "scope" frequencies below 10Hz. I honestly had no idea there was a lower limit.

BONUS CONTENT

I tested my first live-stream on Sunday, Feb 2nd, and while the stream is boring (and I do not recommend you watch much of it), the working counter is displayed for the first portion. The distortion and feedback was caused by a friend's video-chat.

I may do live-streams in the future, but they will be planned... I'll be prepared.

Comments
Login to post comments.

16-bit Counter Prototype

The original 8-bit computer design used the 74LS561 counter for the program counter. The 561 is definitely capable, but it is also a bit complex with synchronous and asynchronous operation in a 20-pin package. I tried using a few counters, but the ones I settled on are the 74LS193. This little 16-pin IC allows for loading, resetting to zeros, increment, and decrement. Most of the counter I tried are increment only, including the 561, so I ordered twently 193s and started prototyping when they arrived.

As you can see from the video (or the thumbnail, I won't judge), the 16-bit 193-based counter is working. I tested with load, clear, increment, and decrement successfully. This was with a 10Hz clock provided by the development board (middle, right, with all of the unconnected red wires), and I used one of the 4-digit hex displays for output.

The breadboard wiring looks complicated, but it worked almost perfectly from the start. A problem I did have was with the first 193 not counting. I eventually replaced it to the same effect and finally removed it. This necessitated adding a new forth IC to the left and moving the display wires, but the result was a successful prototype.

 

TTL 74LS193 up/down counter pinout

This IC is pretty simple, with a decent pin out. My preference would be for the data pins to be together and in order, but that is seldom the case with TTL components. The main things to look at with this IC are the count up/down pins, and the borrow/carry pins, as these are used to chain the ICs together to create a bigger counter... four of them, for a 16-bit version.

The increment and decrement signals are connected to the count up/down pins of the first (lowest 4-bits) counter IC. The carry from that counter is connected to the count up pin of the next IC, while the borrow is connected to the count down of the next IC. This is the same for the next two ICs, as they carry pin of one is connected to the count up of the next, and so on.

When incrementing, the counter will count to 15 before rolling back to a zero. When it does this, it sends a signal on the carry pin, which acts as the count up for the next IC. So, the first IC increments on every clock (10 times per second, in my prototype), but the second IC increments sixteen times slower.

Comments
Login to post comments.

New Modular Card Design

I have discovered some issues with the PCB designs I have had manufactured, and part of the issue is a lack of consistency. Take bus access, for example. The register card has placement for soldered wires or DIP switches to connect the register to the data or address bus. This is a bit limiting, but works and greatly reduces complexity. The memory card is even less complex, with the data pins linked to the data bus and the address pins linked to the address bus. When it comes to the counters, I want more flexibility to use them on either bus and as transfer registers between the buses. If the ALU can write to either bus, it can act as a partial transfer register... but it will need to be able to read from either bus for this to be useful.

The shared components for all future cards...

 

Comments
Login to post comments.

Status and Control Register

There are various flags that need to be set for the computer to work correctly, such as a carry flag when an arithmetic operation results in a value larger than 16-bits.

Halt / Run
This flag is used to determine in the clock run or not. When the clock is not running, the user can single-step through a program manually. Useful at the end of a program to preserve output, or during execution for breakpoints. Can be set by the user, by an instruction, or perhaps by an error (hopefully),

Normal / Input
In normal mode, the PC increments via the clock (or the single step button, if the clock is halted). When in input mode, the user is able to program the computer via front-panel controls.

Instruction Mode
This mode determines how an instruction is processed by the control logic. If the first digit of an instruction in RAM is a zero, the instruction is decoded from the instruction register. If the first digit of an instruction in RAM is a one, the remaining 15-bits are treated as an address, loaded into the firmware counter, and this flag is set. This flag will keep the firmware counter in control until a return instruction causes the PC to become active and continue executing instructions in RAM.

Active Counter
This 4-bit register indicates which counter is in charge of the address bus (effectively, which counter is the current program counter).

 

 

Comments
Login to post comments.