Advanced features like "addition" and "number comparisons" make anything else seem...uncool.
The CoolCPU is a brand new CPU architecture, inspired by processors like the Zilog Z80 and the MOS Technology 6502.
The CoolCPU can access up to 256 bytes of external memory.
The first 128 bytes (
0x7F) are read-only memory, or ROM, and it's what you set in the "Try it now" box above.
Then, the memory from
0xF0 is random-access memory, or RAM.
Your code can store and load values from RAM however it wants.
0xF1 is the output register.
Anything you write to the output register will be printed to the screen.
In addition, consult the DynamicBlast! Engine section to learn about the remaining registers.
The CoolCPU has four main registers. The first is the Program Counter, or PC, which keeps track of the next instruction to run. The PC always starts at 0, and the CPU keeps track of it for you.
The remaining three are registers A, B, and C, which are general-purpose 8-bit registers. You can use them any way you want; however, note that some instructions only work on register A.
Different CoolCPU instructions take different amounts of time to run. We measure each instruction in clock cycles. The Instructions table below specifies the number of cycles each instruction requires.
The DynamicBlast! Engine lets you read data from an external hard drive connected to the CoolCPU. It works by copying data from the external hard drive to RAM. You must set the parameters for the copy (for example, the source and destination) and then start the DynamicBlast! Engine.
The hard drive is broken up into 256 different sectors, numbered from 0 to 255. Each sector is 32 bytes long. The DynamicBlast! Engine works at a sector level. It will always copy exactly one sector—no more and no less.
To perform a copy, do the following:
0xF2) to the destination address of your copy. This should be somewhere in RAM.
0xF3) to the sector you wish to copy from.
0x01. This starts the copy.
As mentioned before, poking the DynamicBlast! Engine is crucial.
To poke the DynamicBlast! Engine, write the poke index to
The poke index starts at 5 and decreases by one for each poke.
So, for the first poke you would write a 5, then the next poke a 4, the next poke a 3, and so on.
The timing of the first poke does not matter. However, for every poke after the first one, you must poke precisely 36 cycles after the previous poke—no more, no less. To be even more precise: there should be exactly 36 cycles from right before the store instruction of the first poke up to right before the store instruction of the next poke. Incorrect poke timing will destroy the attached hard drive.
You will need to poke the hard drive a total of 5 times. (so the last poke index you write to
DBEPKE will be a 1)
After the fifth poke, the data will be available in memory, and the copy will be complete.
No OperationDoes nothing.
|LDA nn||01 nn||1||
Load Register AReads the data at address nn and stores it in register A.
|LDB nn||02 nn||1||
Load Register BReads the data at address nn and stores it in register B.
|LDC nn||03 nn||1||
Load Register CReads the data at address nn and stores it in register C.
Load Register AReads the data located at the address in register A and stores it in register A.
Load Register BReads the data located at the address in register A and stores it in register B.
Load Register CReads the data located at the address in register A and stores it in register C.
|STA nn||11 nn||1||
Store Register AStores the value of register A into address nn.
|STB nn||12 nn||1||
Store Register BStores the value of register B into address nn.
|STC nn||13 nn||1||
Store Register CStores the value of register C into address nn.
Store Register AStores the value of register A into the memory address in register A.
Store Register BStores the value of register B into the memory address in register A.
Store Register CStores the value of register C into the memory address in register A.
IncrementAdd 1 to register A.
DecrementSubtract 1 from register A.
|CON nn||22 nn||1||
ConstantSets register A to the literal value nn.
|JP nn||30 nn||2||
JumpMoves the Program Counter to address nn.
|JZ nn||31 nn||3||
Jump If ZeroIf register A is 0, moves the Program Counter to address nn. Otherwise does nothing.
|JNZ nn||32 nn||3||
Jump If Not ZeroIf register A is not 0, moves the Program Counter to address nn. Otherwise does nothing.
Swap Register BSwaps the contents of registers A and B.
Swap Register CSwaps the contents of registers A and C.
Halt And Catch FireLights the CPU on fire, which terminates your program. Due to technological restrictions, the CoolCPU simulator cannot accurately simulate this instruction, and will only halt the CPU.
Let's say you want to print out "cool!". This means you'd have to write each character in that string to the output register, which we know from the "Description" section above is
By looking up the characters in an ASCII table, you can figure out what values to write. The instructions to do this might look something like:
; print out c CON 0x63 STA 0xF1 ; print out o CON 0x6F STA 0xF1 ; print out o CON 0x6F STA 0xF1 ; print out l CON 0x6C STA 0xF1 ; print out ! CON 0x21 STA 0xF1 ; stop CPU HCF
We use the
CON instruction to load a value into register A, and then use the
STA instruction to store that value into the output register.
Finally, we use
HCF to set the CPU on fire, which ends the program.
Now, using the table above, we can determine the hexadecimal values that correspond to these instructions:
22 63 11 F1 22 6F 11 F1 22 6F 11 F1 22 6C 11 F1 22 21 11 F1 FF
(they're spaced out on multiple lines for clarity—the spacing has no effect on their location)
And that's our program! You can try it in the simulator above.
Let's say you now want to repeat the earlier code five times. You could just write the whole thing out over and over; however, it's better to do this in a loop. That might look something like this:
CON 5 loop: SWB ; print out c CON 0x63 STA 0xF1 ; print out o CON 0x6F STA 0xF1 ; print out o CON 0x6F STA 0xF1 ; print out l CON 0x6C STA 0xF1 ; print out ! CON 0x21 STA 0xF1 SWB DEC JNZ loop ; stop CPU HCF
The main thing to notice here is that we're using the A register to track how many iterations are left in the loop.
At the beginning of the program, the
CON 5 sets it to 5.
Then, at the end of each loop iteration, the
DEC instruction subtracts 1, and the
JNZ continues the loop—unless A is 0, in which case
HCF is run.
However, you might have noticed an issue with this: we're using the A register for both the loop count and the character values!
That's what the
SWB instruction is for: it swaps registers A and B.
We swap at the start of the loop to save the loop count, and then do a swap at the end to restore the count so that we can check it.
Since most operations occur on register A, you'll find the swap instructions to be very helpful.
Like before, we can use the instruction table to find the hexadecimal representation of these instructions:
22 05 40 22 63 11 F1 22 6F 11 F1 22 6F 11 F1 22 6C 11 F1 22 21 11 F1 40 21 32 02 FF
Notice how we had to calculate where the
loop label is in the code.
Based on the size of the instruction before it, and knowing that the first byte is address
0x0, we can determine that
JNZ loop becomes
JNZ 0x02, which becomes