Skip to content
varkenvarken edited this page Feb 27, 2020 · 6 revisions

The CPU is currently a simple, non-pipelined risc design.

It features 16 32-bit registers and a single ALU, although address calculations and branch target calculations are done by separate adders. Registers and opcodes are documented in this spreadsheet.

A distinctive feature is that alu operations are not implemented as separate instructions. Instead, there is a single 'alu' instruction that performs the operation stored in the lower byte of the flags register (R13). This makes it possible to keep (almost) all instructions 16-bit. Also because the move instruction move r2,r1,r0 adds the contents of the registers selected by r1 and r0 and stores it into r2, addition doesn't need the alu and incrementing a register can be done by refering to R1 which is always 1.

Because there are no dedicated call and return instructions these activities are typically performed using two or more instructions involving JAL (jump and link, i.e. jump to and address while simultaneously saving the program counter in a register). This is easy enough to deal with by defining suitable macros in the assembler but does not produce very compact code.

While working on a simple C-compiler it became quickly clear that the original decision not to include dedicated push/pop instructions made for very bloated code as each push/pop action involved two instruction, one to update the stack pointer and one to actually read or write the other register. So I added them along with seteq, setne, setpos and setmin instructions.

Future research will be focused on analyzing more coding needs as well as optimizing the complexity and performance of the cpu.

Intermediate findings are that the load/store instructions for 16bit words are not used and i am thinking to remove them to reduce cpu complexity. Also the current implementation of the (conditional) branch instruction allows for a 16bit instruction that has a single byte offset or 16+32 bit instruction with a 32 bit offset. This might be replaced with a single 16bit offset form that would specify which register to test as well, thereby obviating the need for flags as well as the setxxx instructions. The opcode format would look something like this:

[Bra][xxx][R1][Cond][16bit offset]

The condition would be 0: equal, 1: notequal, 2:positive, 3:negative and unconditional branch would be realized by testing against the r0 or r1 registers. R1 would be the register tested (which could the potentially share code with alu)

If we really need to keep the setxxx instructions we could generalize these to

[Set][R0][R1][Cond]

An even wilder idea is to combine these two: a branch would have R0 as one of the immutable registers r0,r1 while the set could have offset of zero (or not, for an atomic set-and-branch)

A variant of this last approach is now implemented an is described in this article

Clone this wiki locally