Two weeks ago I listed basic components necessary to build a simple computer. In this week's tutorial I'm going to design the parts of brainfuck computer that work outside of the BPU: memory and communication with the user. Today's work will involve designing a flag circuit and learning a simple handshake protocol.
This is, sans CPU, the most important part of the computer. Memory is used to store both the program which is run by the CPU and data used in computation. As a consequence, a standard RAM chip will not require too much additional hardware to work with the BPU: the BPU will be designed to communicate with memory, not vice versa.
A memory chip is divided into cells which hold integer values, just like brainfuck memory. A BPU memory is connected to two buses: data bus, from which it will load and in which it will store it's contents, and address bus which selects a memory cell to interact with. To implement conditional jumps I also need a "Zero flag" line separate from the data bus. It will check if the currently addressed memory cell is zero even if memory isn't broadcasting its contents to the data bus.
Memory should connect to the following lines:
|Address bus||Input||Used to address cells|
|Data bus||Input/Output||Used to communicate with other components|
|Zero flag||Output||Used by the BPU in conditional jumps|
||Control||Enables storing data from the data bus|
||Control||Enables loading data to the data bus|
|Reset||Control||Sets all cells to 0; connected to the computer's reset switch|
|Clock||Clock||Data is stored on rising edges of the clock if enabled with D->RAM|
RAM->D doesn't connect to
ld input of the RAM chip which would normally be used for this purpose. Instead
ld is permanently set to 1 so that data is always broadcasted, but bridged off from the data bus by a buffer controlled by the
RAM->D signal. This way it is possible to check if a cell is zero without broadcasting it's contents to the data bus. The small "=0" circuit which calculates the flag is just a single multi-input NOR gate.
Memory is just one of many circuits that a BPU might need to communicate with, but other ones don't get separate interfaces and signals: they all share the same lines and signals and may require an additional circuit to figure out which device the BPU is trying to communicate with.
Fortunately I will not need such a thing because I will only implement the simplest possible I/O for debugging and as an example of the handshake protocol.
The handshake is used when two devices (possibly running on different clocks so they are not synchronised) need to communicate. Except from any lines they need to send data two one-bit lines are required to perform a handshake: a "Start" flag controlled by the device that initialises the connection (the processor) and a "Ready" flag controlled by the other one (the device). The handshake proceeds as follows:
|0||0||The processor and the device are doing their separate things. When the processor wants to connect, it broadcasts relevant data on the data lines, sets "Start" to 1 and waits.|
|1||0||When the device is ready it starts processing data broadcasted on the data lines. It may take any amount of time. The processor waits, still broadcasting data and "Start". After the device is done processing it broadcasts the answer, sets "Ready" to 1 and waits.|
|1||1||The device waits for the response. The processor captures data broadcasted by the device, stops broadcasting data and sets "Start" to 0 terminating the connection.|
|0||1||The device stops broadcasting data, sets "Ready" to 0 and continues it's operation until another communication is requested.|
This method has many advantages: it is simple, it assumes nothing about both devices and it allows for temporary synchronisation between components that can otherwise be running on very different speeds.
Two Brainfuck Assembly Language commands are used for communication with external devices:
, for input and
. for output. They will perform a variant of the handshake described above.
For this purpose the BPU needs equivalents of "Start" and "Ready" signals that would also specify whether the processor requests an input or an output. I will implement this on three signal lines:
in for requesting input,
out for requesting output and
resume as an equivalent of the "Ready" signal.
|Handshake element||BPU equivalent|
|Data for the device||
|Data from the device||sent over the data bus|
|Handshake element||BPU equivalent|
|Data for the device||
|Data from the device||none|
With knowledge about the handshake protocol and what signals will be used to perform it I can now design a simple manual input and a simple output display. Because I'm using only a single input and output I will not be using command arguments.
Manual input is a really simple circuit. Almost nothing is automated so it is as straightforward as can be:
in signal is on, the LED lights up to notify the user and input is broadcasted to the data bus. Pressing the button will send a
resume signal and continue the program.
Output display is not as easy. It requires a register to store the output value and it should also work independently of the user. Therefore it needs to implement automatic handshaking: something that emits a "Ready" signal after receiving the
in signal and storing data, and takes it down when the
in signal ends.
Fortunately both are still quite simple to set up. The data register is just a standard register with its "enable" input connected to the
in signal so it only loads data when it's supposed to. The handshake can be performed by a one-byte register (AKA D-flip-flop): it will pass on the
in signal as a
resume signal but synchronised with the module's clock* and will be reset asynchronously when
in goes down.
Outputs are set up for connection with Logisim's hex displays, so from the outside the whole setup looks like this:
*In my final simulation everything will run on the same clock, but I want to design BPU to be able to communicate with devices with different speeds.
This week I've shown you the handshake protocol for communication between devices of different speeds. I also designed the external parts needed to operate the BPU. Next week I'll begin designing the BPU itself starting from some core registers.