CPU 3.8 Manual
A complete guide and specifications for Colin's PowderToy CPU. Visit my website
Started 2014 May 2, updated 2015 Jan 4, and latest 2023 Jul 16
This document will tell you what kind of CPU this is and just how it operates in general.
If you want personal help, you can e-mail me at ColinL333@gmail.com
And please don't just download this file because I will be updating it as I improve the CPU itself.
Introduction
This Central Processing Unit reads everything it needs from the RAM stack. This transistor-based RAM allows full freedom over it's contents.
You can:
- store any kind of data in it
- access any address from any other address
- write code that makes changes to itself
- graphically see the contents as the state of each SWCH
Do not copy/paste portions of ram. Every 8th byte is slightly different, and won't work if this pattern is distrupted.
Typical types of data stored in RAM:
Commands
4bit codes that tell CPU what to do with the next types of data after the command. Each command has a specific number of arguments, so read the syntax details and be a pro!
Addresses (of Variables or JumpTo destinations)
Points the CPU to a number stored at that address. An address is like the name of a variable, because it can be accessed from anywhere, with its value stored at that address. Note that the value can be overwritten by certain commands, just like a variable's value can be changed. Since the ram is only 64 bytes long, (26) only 6 bits are needed to indicate any address. The other 2 more significant bits in an address byte are safely ignored (although they should be 0). The top address is 00000000 and the last bottom one is 00111111. Unfortunately, constants cannont be input DIRECTLY into commands. Instead, access a variable that never gets overwritten.
Raw Data
There is also data in the RAM that the CPU can't understand, but is still valid. This is raw data, and is specific to its purpose. Say you have a display connected to the output port, and want to show stuff on it. The CPU can read raw data from the RAM and send it directly to the device so it can use it. The display may require an input of unique patterns of signals, instead of a binary number. The CPU can output any byte pattern of data (at it's own speed) via it's 8 bit parallel port.
It is also important to remember that all of these are stored together, next to eachother, in RAM, and the only way of differentiating between anything is its address. It is VERY important to be aware of your program flow, where the switches and gotos will lead the CPU. The biggest mistake would be allowing the CPU to "wander" into an area storing variable values, interpreting them as commands. There are safegaurds to detect this and abort, but the CPU does have the ability to start destrying the RAM's own code by accident! The command to stop a program is a blank line of all 0s AND the null action must be already set to abort (the two buttons found on the "UI" beside the start/stop buttons).
In an emergency, simply SPRK the red stop button (beside the run button) to prevent any more commands from being executed. You may notice it does not stop immediately; the CPU will finish the current command so that it does not leave itself in an unstable state.
What it Does With Your Code
Execution begins at address 0; the first command should be at that address. No space/blank line is needed between last argument of last command and next command (blank lines CAN be interpreted as STOP or ignored). To change how the CPU handles nulls: SPRK the buttons on the UI.
Most significant bit is on left, least is on right. So when coding a command, the 4 command bits are the ones on the right half. Addresses are only 6 bits long (see explanation above) and again use the least significant bits on the right. This can easily increase with expansion of the device.
While programming, set the cursor to 1px, zoom in. Each byte in memory can be manually erased (set to all 0) by sparking the INST adjacent to the upper ARAY on the left end of the row of RAM bits. (There is quite a lot of ARAY around, so you may need to test until you find the right one.)
To write a 1, spark the PSCN adjacent to the SWCH. To write a 0 (erase a single bit) spark the NSCN adjacent to the SWCH. The RAM grid is very friendly- sparking any part of a bit by accident will not affect any adjacent bits. A single functional enlarged bit is provided to see how it works. A bit is simply an AND gate with a SWCH to store the value.
The Instruction Set
Most important thing to know. These are all the commands that the CPU can understand and perform. Each command requires a specific number of lines after it (sometimes none), to give the CPU more info, if needed. Details of this follow.
*STAR = DOES NOT EXIST!! You can try unavailable commands if you want, but this CPU was designed with people like you in mind. It will just turn on the error light and stop. :P
----0000 End Program (or advance to next address if disabled with buttons)
----0001 Store address counter to memory
----0010 Goto
----0011 Goto if
----0100 Copy & Overwrite variable
----0101*Save data to Hard-drive
----0110*Import code from Hard-drive
----0111 Output var to device
----1000
----1001 Add
----1010 Subtract
----1011*Multiply
----1100
----1101*Divide (how many multiples will fit)
----1110 Wait for input (press any key to continue)
----1111 Query Input Register (eg: from user keyboard, random number generator)
Instruction Set Syntax Details
How to use each command, and templates of how they should reside in RAM. The command, and any required following addresses are shown.
----0000 End program. stops execution if enabled; Reset ALU, disconnect all from bus, enables green light, clears register, BUT address counter left unchanged.
-------- (no arguments; 1-line command)
----0001 Store address counter to memory. Takes the current position of execution (as an address) and stores stores it at another address. This could be useful for remembering where something happened, and going back to it later. The address that will be saved is the exact place where the location to save it is specified. So a GOTO that address will cause an error. Therefore, it is not very useful, or encouraged. inefficient.
--@@@@@@ Address to store current address
----0010 Goto
--@@@@@@ Address of command to resume execution (destination of jump)
----0011 If A >= B, then Goto address. B is subtracted FROM A (A-B), jumps to specified address if result is 0 or >0 Otherwise, will continue execution right after address.
--@@@@@@ Address of var A
--@@@@@@ Address of var B
--@@@@@@ Address to jump to, otherwise continue to next command.
----0100 Copy & Overwrite variable.
--@@@@@@ Address of source variable
--@@@@@@ Address of destination (will overwrite)
----0101 *Save data to Hard-drive. Overwrite one byte in drive with data from address in ram.
@@@@@@@@ Sector in drive of destination (each sector = size of ram)
--@@@@@@ Address in sector of destination
--@@@@@@ Address in RAM of data to send/save
----0101 *Import code from Hard-drive. Completely overwrites all of ram, program begins execution at 0 in RAM after new data.
@@@@@@@@ Address of ram-sized block of memory to import from hard-drive
----0111 Output var to external device.
--@@@@@@ Address of var to output
----1xxx Add/Subtract/*Multiply/*Divide/*Remainder. All math operations follow this same template. See above for command code of each.
--@@@@@@ Address of var A
--@@@@@@ Address of var B
--@@@@@@ Address to store answer (will overwrite)
----1110 Wait for input. Simply pauses execution and waits for the "sent" signal from connected device (1st pin). Then continues to next command. Similar to "press any key to continue". Will activate yellow waiting light, and turn it off when finished.
-------- (no arguments; 1-line command)
----1111 Query Input Device Register.
--@@@@@@ Address to store byte received from device (will overwrite)
Future ideas:
*format memory?
*Addresses can be 8 bits, but only smallest 6 are used in addressing column. So addresses have untapped "metadata"
*reset entire system (no arguments), erase all registers, go to address 0
*Remainder (what's left over after subtracting whole increments)
Preloaded Programs
Sinewave Plotting
This is a basic program that was originally preloaded in the RAM when I released the CPU around 2014. There's something you should know:... The cos() is a lie! A computer that can only add and subtract isn't going to do trigonometry! You might not notice, but the example program's graph is actually pairs of parabolas connected together- by logic!
The default program: (the curly brackets are imaginary; there are no brackets in this CPU's low-level machine language, but they are shown here to make it eaisier to understand.
Initialize variables:
@28: Y value (starts at 128)
@29: Y displacement (starts at 1)
@30: Y "acceleration" (constant: 2)
@31: midpoint/turning point for acceleration (starts at 112)
@32: (constant: 1)
{
Goto @2
@2: Outp @28
@28 - @29 -> @28
if (@28 >= @31), then Goto @22
else {
@29 - @30 -> @29
Goto @2
}
@22:{
@29 + @30 -> @29
Goto @2
}
}
Prime Finder
A later program released 2017 October for finding primes! The first prime it will output is 5. It will check numbers for primeness upto 127.
After which, the registers will overflow and it's undefined behaviour.
This program has many high-level concepts implemented: 2's complement, integer division, while loops, and nested subroutines!
It makes use of repeated subtraction to check divisibility.
Note how -1 is the same as 255 when using 8-bit, so when the running total eventually goes negative, the negative result is actually considered as a large positive number,
and so the branch asks if it is greater than 128 to check if it's negative. Of course, with 8 bit numbers, This limits finding primes beyond 127.
The program uses only 48 bytes out of the 64 available! - You could put another tiny program in the remaining 16 bytes- the initial GOTO in the code is provisioned for jumping to an alternate program in memory. You gain at least 1 byte by removing unused constant @43.
Initialize variables:
@40: (start value 3) Constant. The first number to check if it divides evenly into the current prime candidate, @45
@41: (start value 128) Constant. For checking overflow to end repeated subtraction.
@42: (start value 0) Constant.
@43: (start value 1) Constant. Unused! Likely the old incrementor, needed for finding primes smaller than 5.
@44: (start value 2) Constant. The amount to increment @45, to skip even numbers!
@45: (start value 3) The current number to check if it's prime.
@46: (start value 0) Utility var for repeated subtraction- the number we are repeatedly subtracting (denominator)
@47: (start value 0) Utility var for repeated subtraction- the running total. Begins with the candidate prime.
{
Goto @2 // could change this address to jump to other program elsewhere in memory
@2: @45 + @44 -> @45 // increment the number (candidate prime) we will check for primeness
@40 -> @46 // load the denominator (reset back to 3, it increments by 2)
@9: @45 -> @47 // load the candidate prime
@12:@47 - @46 -> @47
if ( @47 >= @41 ), then Goto @26 // did the subtraction overflow? if yes, then this denominator is not a factor of the candidate prime.
else {
if ( @42 >= @47 ), then Goto @2 // did the running subtraction divide evenly? if remainder was 0, then divided evenly. Candidate is not prime. Go on to new candidate prime.
else {
Goto @12 // running total is not zero or negative: not done yet. Repeat subtraction.
}
@26: @46 + @44 -> @46 // increment the denominator by 2 to the next one to try.
if ( @46 >= @45 ), then Goto @36 // is the new denominator >= the candidate prime? If so, then we made it though all potential denominators!
else {
Goto @9 // haven't tried all possible denominators yet. Reload the candidate prime and begin subtracting again with new denominator.
}
@36: Outp @45 // output the prime to external port!
Goto @2 // Go on to new candidate prime.
}
}
Stuff You Will Probably Break
Don't touch these unless you are modding the CPU; just email me and I'll do it for you :D
These are the wires of the Command Bus. When you call a command like the ones above, the command performs many of these lowest-level tasks, operating the hardware. You do not need to even LOOK at these if all you want to do is write programs. The beauty of the CPU is that it does this for you.
E --- End of command, request next
A RAM Read/Write mode
B RAM Erase mode
C *RAM Reset Addressing Column
=====8bit DATA BUS=====
1 BUS Addressing Column Off
2 BUS Addressing Column On and Reset Addressing Column
3 RAM Perform current mode at current address
4 RAM Start and Stop (RAM writer) saving bus to RAM at current address
5 CNT Reset
6 CNT Query address Counter to bus
7 CNT [2 & C] & Address +1, wait for add, [6],[1]
8 BUS [5] & Address Counter On and Off
9 BUS Put input register on bus, then clear register. (TPR): Turn on and reset command interpreter
10 TPR Query and execute command, turn off interpreter
11 BUS External Device Off
12 BUS External Device On
F -ALU Overflow- the value in ALU workplace has exceeded 255 OR < 0
1 REG Output value (onto bus if connected), erasing value from it
2 REG Connect to bus for short time (for in OR out)
3 ALU Reset- clear workspace and disable LOWER inverter only.
4 ALU Disconnect inputs from bus
5 ALU Connect inputs to bus
6 ALU Output subt result to bus, AND re-enable addition mode
7 ALU Query answer (to bus if adding, to inverter if subt)
8 ALU Subtraction mode- enable I/O inverters, then pass input to adder, wait for operation complete, disable UPPER ONLY inverter
9 --- A byte from an input device has arrived and just been stored to the input register, ready for transfer along data bus.
Meta-Data For Files (Completely unused, from computer 2.x):
00 Bytes (so 4 bytes can fit into 32 bit file) This way, if first byte is empty, it will just be skipped without errors.
01
10
11 Drawing or Random data.