Transistories

DLC-0

The Project

Introduction

What is DLC-0?

DLC-0 is a proof-of-concept to showcase that it is possible to design and built a computer from scratch using only logic gates. From the start the design goal was to build a simple, yet capable computer that was Turing complete.

Although learning and exploring everything related to designing and building a computer took quite a bit of time, the actual computer was designed and implemented in a simulator over a weekend.

Why DLC-0?

There are multiple reasons why I wanted to do this project. The biggest reasons for me were because it presented itself as a challenge and it seemed fun (and it was a lot of fun!). On top of that, it is also a really good project if you want to learn a lot about electronics and about how computers work, on a more fundamental level.

This project will provide a lot of insight into how computers work and how programs are processed on it. By building your own computer you will get a really good understanding of how data and instructions flow through a computer.

This project is also historically relevant, as almost all the early computers were built this way; from countless IC's. In the 60s many computers were built using 74-series logic ICs (or equivalents). As time went on, components became smaller and computers became more powerful. At the same time, "older" components became cheaper, the 74-series ICs were no different. Like that computers found their way into hobby electronics. As hobbyists started experimenting more and more; the homebrew computer was born.

Key Features

  • 4-bit word size
  • Von Neumann architecture
  • Turing complete
  • Completely open-source

Schematics

DLC-0 Block Diagram

Instruction Set

Instruction table

The following table contains the entire instruction set for DLC-0. The two instructions marked with NI are not implemented in this design.

opcodehexnamedescription
00000x0NOPNo operation
00010x1JMPJump to address
00100x2JPOJump to address on overflow
00110x3OUTOutput accumulator value
01000x4LDALoad accumulator
01010x5SWPSwap the values in the accumulator and swap
01100x6INVInvert accumulator
01110x7JMZJump to address on zero (NI)
10000x8JMEJump to address if equal (NI)
10010x9NNDBitwise NAND
10100xaNORBitwise NOR
10110xbXORBitwise XOR
11000xcADDAddition
11010xdSUBSubtraction
11100xeADSAddition from swap
11110xfSBSSubtraction from swap

DLC-1 instruction set

A few remarks:

  • A load B instruction would be useful
  • RAM functionality would also be useful, however this would eliminate the SWP register and require a complete redesign of the hardware.

MicroCode Matrix

OPRFlagT0T1T2T3T4T5T6T7T9T10
NOPPC out
MAR in
ROM out
INS in
CNTMCC rst
JMPfetchPC out
MAR in
ROM out
PC in
MCC rst
JPOfetchCNTMCC rst
JPOOVFfetchPC out
MAR in
ROM out
PC in
MCC rst
OUTfetchACC out
OUT int
MCC rst
LDAfetchPC out
MAR in
ROM out
MAR in
CNTMCC rst
SWPfetchSWPMCC rst
INVfetchMOD 1001
OPR 00
ACC strMCC rst
JMZfetchNI
JMZZEROfetchNI
JMEfetchNI
JMEAisBfetchNI
NANDfetchPC out
MAR in
ROM out
MAR in
ROM out
B in
CNTMOD 0000
OPR 01
ACC strMCC rst
NORfetchLDBMOD 0000
OPR 10
ACC strMCC rst
XORfetchLDBMOD 0000
OPR 11
ACC strMCC rst
ADDfetchLDBMOD 0000
OPR 00
ACC strMCC rst
SUBfetchLDBMOD 0100
OPR 01
ACC strMCC rst
ADSfetchSWP out
B in
MOD 0000
OPR 00
ACC strMCC rst
SBSfetchSWP out
B in
MOD 0100
OPR 00
ACC strMCC rst

Microcode matrix

Schematic

There is no schematic per-se for this project. However there is a logisim simulation, which can be considered a schematic. The logisim file can be found in the repo.

Direct link: DLC-0.circ

Example Programs

Programming language

There is no specific language requirement for DLC-0, since there is no compiler available. We ourselves are acting as the compiler, and as such we transform the written code to values that have to be placed in the memory.

In order to make it easier for ourselves to compile our own code, it is easiest if the code is written is assembly or something closely resembling that. Assembly itself is already close to machine code, making the translation a lot simpler for us.

As later versions and iterations will get more and more complex, the need for a compiler will become self-evident. Not only will the programs become larger and more complex, the computer itself will become more capable. So on top of being able to write large programs, we will also have access to more complex instructions, with varying numbers of arguments... As all of us know, writing programs in higher-level languages is far easier than writing programs in assembly. However, for the time being, programs are written and programmed into the computer like in the good ol' days; with pen and paper and one bit at a time!

Assembler

To reduce the work involved in and risk for mistakes while translating our code into the bytes that the computer will understand. An assembler was written, it can output the resulting data to the screen and to a binary file that can be understood by logisim.

The source code for this assembler is written in python and can be found at: https://gitlab.com/transistories/dlc/dlc-0/-/blob/release/assembler/assembler.py

Simple Counter

This is a simple program that increments a value and outputs it each time. When an overflow occurs the program resets and starts over again. This program was written to test the basic functionality and to check if the control unit was designed without mistakes.

The program also showcases the normal jump instruction and the conditional jump instructions.

0LDA15Load the ACC with the value at address 15
1OUTOutput the value in ACC
2ADD14Add the value at address 14 to ACC
3JPOJump on overflow to instruction 0
4JMPJump to instruction 1

counter.asm

The following table show the values that have to be programmed into each address of the ROM. The cells marked with n.u. are not used, but can be programmed with 0x0 for safety reasons. This is the NOP instruction. If the computer would ever get here at least it will move along the zero's and eventually get out of the block of zero's.

adr0x00x10x20x30x40x50x60x70x80x90xa0xb0xc0xd0xe0xf
codeLDA15OUTADD14JPO0JMP2n.u.datdat
val0x40xf0x30x90xe0x20x00x10x20x00x00x00x00x00x10x0

counter memory dump

Fibonacci Sequence

This is a slightly more advanced program that calculates and outputs the numbers in the Fibonacci sequence.
It will output the numbers: 1,2,3,5,8,e(13); and then start over.

This program makes use of the SWP instruction, swapping the result in the ACC and SWP register. This was one of the original design goals!

0LDA15Load the ACC with the value at address 15
1SWPSwap the values in ACC and SWP
2LDA15Load the ACC with the value at address 15
3OUTOutput the value in ACC
4ADSAdd the value of SWP to ACC
5JPO0Jump on overflow to instruction 0
6OUTOutput the value in ACC
7SWPSwap the values in ACC and SWP
8JMP4Jump to instruction 4

fibonacci.asm

The following table shows the values that have to be programmed into each address of the ROM.

adr0x00x10x20x30x40x50x60x70x80x90xa0xb0xc0xd0xe0xf
codeLDA15SWPLDA15OUTADSJPO0OUTSWPJMP6n.u.dat
val0x40xf0x50x40xf0x30xe0x20x00x30x50x10x60x00x00x1

fibonacci memory dump

Next Steps

So what is next?

As this is a mere proof-of-concept created in a simulation, the logical continuation of this project would be a physical build, using the appropriate logic IC's and discrete components.

Beyond that, there are two paths that I would like to explore further;

  • Create an even lower-level design, consisting of discrete components only.
  • Create a more advanced design with more functionality.

Ragardless of where this road takes me; you can stay up to date by following the Transistories RSS feed: Keep up to date