Input, output and memory for the BPU
Tags: tutorial, esoteric, hardware
Published: 2021-06-04 10:54:58

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.

### Memory
###### May contain knowledge
 
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 module diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ps7bl83hfl9oetno9pb.png)
 <figcaption>Memory module in Logisim</figcaption>
 

Memory should connect to the following lines:

| Name | Type | Description |
| --- | --- | --- |
| 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 |
| `D->RAM` | Control | Enables storing data from the data bus |
| `RAM->D` | 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 |

##### Zero flag
Note that `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.

![Zero flag diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/47mg19xlyaphpmtfzc50.png)
<figcaption>Zero flag circuit in Logisim</figcaption>
 
### Input/Output overview
###### Talking to other devices
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.

##### Handshake
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:

| Start | Ready | Description |
| --- | --- | --- |
| 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.

##### Handshaking in the BPU
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.

Input handshake:

| Handshake element | BPU equivalent |
| --- | --- |
| Start | `in` signal |
| Ready | `resume` signal |
| Data for the device | `,` command argument |
| Data from the device | sent over the data bus |

Output handshake:

| Handshake element | BPU equivalent |
| --- | --- |
| Start | `out` signal |
| Ready | `resume` signal |
| Data for the device | `.` command argument and contents of the data bus |
| Data from the device | none |

### Input/Output design
###### [Insert your implementation here]
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.

##### Input
Manual input is a really simple circuit. Almost nothing is automated so it is as straightforward as can be:

![input diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/572z0sn8ev6pml3hux1g.png)
<figcaption>Manual BPU input in Logisim</figcaption>

When the `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
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.

![output diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d6e37nnqr7bh0bnjx7gq.png)
<figcaption>Hex output circuit diagram in Logisim</figcaption>

Outputs are set up for connection with Logisim's hex displays, so from the outside the whole setup looks like this:

![output block in use](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ermsni2qyjor8ktt7456.png)
<figcaption>Hex output module in use</figcaption>

*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.

### Conclusion
###### That's all, folks!
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.