DIY - HomeWorks
everything unfinish..

CoBo-CPU : Operation and Programming

4. Dec 2021, by plexus

This is just a quick look into the way the CoBo-CPU is programmed.
I'm doing this as a primer because the programming differs quite a bit from the usual way CPUs are programmed.
There will be a complete article just about CoBo programming with way less prose, and much more details.

Limits

Since the architecture is very limited, the CPU can perform only two instructions: "Read From Memory" and "Write To Memory".

This may seem a bit lacking. But there's parameters. Something like: "Where does the memory address come from?" or "Where does the data end up after a read?"
Or you choose to perform a left shift while you're writing data.
Maybe you want to add a condition to only write when the carry flag is set.

It's the combination of parameters like these for each read and write that turn this simple data mover into a working CPU.

Each read or write has at least two parameters:

r dp dr

'r' is the instruction: "read". The first parameter tells the CPU which register is used to address the memory. In this case it's 'DP' - the Data Pointer.
The second parameter sets the destination for the data that is read from memory. In the example the data is read into the Data Register (DR).

Likewise a simple write looks like this:

w dp dr

Again, the address is taken from DP. The data that is written into the memory comes from DR.
'w' means "write", of course.

The order of the first two parameters DOES NOT denote any direction of data flow.
Hence the two registers have not changed place between the read and the write instruction.
The first parameter is always the register that provides the memory address, and the second parameter always determines where the data comes from or goes to.

Therefore, a more general format of a read instruction would be:

r <address-source> <data-destination>

or likewise, a write would be:

w <address-source> <data-source>

In total, there are six registers that can be used as address-source, data-source or data-destination: dp, dr, ic, ir, io, st.


But wait, there's more!

There is also a bunch of parameters available for logic operations and conditional execution. Also, there's a few nifty tricks that I designed into the architecture that make a programmers life a little easier.

A more complicated instruction could look like this:

w dp dr and.0 cc

This is an actual instruction I used in a program.
It does three things:

  1. check if the carry flag is clear (cc)
    if clear:
  2. do a logic AND between DR and 0x0000 (and.0)
  3. write the result of "DR AND 0x0000" into memory pointed to by DP (w dp dr)
!!! The order of operations IS NOT determined by the order of parameters in the instruction!
I just wrote them out in a way that makes sense from a logical point of view.
The actual order is determined by the hardware architecture.

Especially because the CPU has no idea how you've written the line in your code, because every line is turned into one 16 bit word.
Also, the parameters 'and.0' and 'cc' are optional parameters which can appear in any order in the instruction line.

But what does the instruction actually do?

It clears a memory location depending on the state of the carry flag.

In C you would write: if(!carry) SYSTEM_MEMORY[DP] = 0;
Or more precise: if(carry == 0) SYSTEM_MEMORY[DP] = DR & 0;

Of course, DP has to be set in advance to point to the right location, duh.
The other thing the keen eye might have spotted is the rather stupid action of ANDing DR with 0.
Because it'll always yield zero.
That's the point.
We don't actually care about the value in DR here, the only thing we want is putting out a zero. However, the output of DR is ALWAYS sent through the ALU.
So, the only way to get a zero regardless of the value of DR is: DR AND 0.

Cumbersome you might say, but look at this:

r ic dp +1          ; load pointer from a literal
#0xAB12             ; literal: address of variable
w dp dr and.0 cc    ; set variable to 0x0000 if carry is clear
w dp dr or.1 cs     ; set variable to 0xFFFF if carry is set
Looks like a pretty quick way to conditionally initialize a variable in two different ways. (The '+1' in the first line means that there's a literal following the instruction)
At 1MHz that takes just 4 microseconds. (Well - "just" - but you get the point)

Don't be confused by the '.0' and '.1'.
Those numbers aren't actual values, it's just one bit that tells the CPU to use either 0x0000 (.0) or 0xFFFF (.1) as the second operand for AND and OR.
There are no options available other than .0 or .1 !

Of course, you can also write something like: w dp dr and.1, which just writes DR to the memory unchanged, unconditionally, but it does adjust the flags, too. So, it could be used as a check if DR is zero. (there's better ways for that, though)

~ ~ ~

Just for fun, the four lines of CoBo code from above would look like this in C/C++:

if(carry)
  *variable = 0xFFFF;
else
  *variable = 0;
Assuming that 'variable' is at 0xAB12 in memory.


Leave a Comment




Message:



Comments