DEV Community

Alex Esoposting
Alex Esoposting

Posted on • Updated on

Interpreting BPU commands

Last week the CPU gained its final operation-performing parts.
Today I will be looking at the Command Decoder which, in order to execute the program, governs the workflow of other components.
First, I need to introduce another external part of a brainfuck computer. If you want to follow along all examples are on the github repo.

Read Only Memory

Because RAM allows rapid reading and writing to arbitrary addresses it's perfect as a working memory, but it looses all its data when not powered. This means that it needs to be reprogrammed at every computer startup, which is tedious to do by hand. A nicer solution is Read Only Memory: it stores data without the need for being powered. The drawback is that its contents can't be easily changed with simple circuitry (if at all), hence the "Read Only" part.

Various ROMs have been used as means of permanent storage of programs, in form of console cartridges, floppy disks and CDs among others. Currently I'm focused on design, so it doesn't matter what form of ROM the final product is going to use. I will use ROM to initialise RAM with the correct program and data. The BPU will need a special signal to enable "Program Loading" mode which is set after starting operation and unset after all the memory is copied. Otherwise ROM doesn't need any new connections as it can use the Address and Data Buses for data transfer.

"Load" signal

To generate the Load signal I will use an SR flip-flop. It can hold a single bit of data and has synchronous set (S) and reset (R) inputs that change its contents when set high. I will also be using an asynchronous input that overrides the flip-flop's contents no matter the clock.

Load signal generator diagram

Load signal generator in Logisim

Data loading should be triggered every time the machine is reset, so the Reset signal works asynchronously overriding any inputs on S or R. Copying ends after everything has been copied, so the R input is connected to a NOR of all the address bits which is on only when the address is 0. To make sure everything works properly and the address gets back to 0 at the end, the SR flip-flop can't update at the same time as the the address changes. Since rising edge can't be used, the signal should be updated on the falling edge by inverting the clock. This prevents undefined behaviour that happens when the flip-flop tries to update based on inputs that change at the same time.

ROM circuitry

There isn't much to be done with the ROM itself. It's output is enabled by the Load signal, it's addressed by the Address Bus and outputs to the Data Bus. Everything just needs to be plugged in with the Load signal generator and we're good to go.

ROM connection diagram

ROM circuit in Logisim

BPU signals

Back on track

With ROM out of the way I have finally finished the list of all signals used to control the BPU.

Ecternal signals (supplied to the BPU):

  • Clock
  • Zero flag
  • Load
  • Resume (for I/O)
  • Halt

Internal signals (generated by the BPU):

  • Program Register: NEG, D->PR
  • ALU: D->ALU, ALU->D
  • Memory: D->MEM, MEM->D
  • Data Pointer: D->DP, DP->D, DP->A
  • Program Counter: D->PR, PR->D, PR->A, PR++
  • I/O: I/O

The last BPU component, the Command Decoder, is supposed to translate the 3-bit BAL commands into these signals. Next step in designing it is to determine how to execute the commands using just these signals.

Command translation

From low level to lower level

Before executing anything each command has to be loaded into the Program Register first. This step will be the same for every command: load the cell addressed by the program counter into the program register. Incrementing the program counter will occur on the next cycle.

0. PC->A; MEM->D; D->PR; PC++
Enter fullscreen mode Exit fullscreen mode

Now the execution of each command is as follows (remember that ALU output is ALU input plus/minus the command argument):

Commands + and -

  1. Pass the cell at which the Data Pointer points to the ALU
  2. Save the result of addition/subtraction back in the cell
1. DP->A; MEM->D; D->ALU; PC++;
2. DP->A; ALU->D; D->MEM;
Enter fullscreen mode Exit fullscreen mode

Commands > and <

  1. Pass the Data Pointer to the ALU
  2. Save the result of addition/subtraction back in the Data Pointer
1. DP->D; D->ALU; PC++;
2. ALU->D; D->DP;
Enter fullscreen mode Exit fullscreen mode

Commands [ and ]

  1. Pass the Program Counter to the ALU
  2. If the condition is met save the result back in the Program Counter
1. PC->D; D->ALU; PC++;
2. ALU->D; D->PC;
Enter fullscreen mode Exit fullscreen mode

Command ,

  1. Set the I/O flag. After resuming put input into the cell addressed by the Data Pointer
1. DP->A; I/O; D->MEM; PC++;
Enter fullscreen mode Exit fullscreen mode

Command .

  1. Output the cell addressed by the Data Pointer and set the I/O flag
1. DP->A; MEM->D; I/O; PC++;
Enter fullscreen mode Exit fullscreen mode

Cliffhanger

To be continued

I've shown how to execute each BAL command in at most three cycles using my hardware, but implementation details of the Command Decoder will come next week. As always please leave a comment if you have any feedback whatsoever. Have a good day!

Discussion (0)