Introduction
This project will aid new FPGA designers to tackle a real project using VHDL and Verilog and later Matlab HDL generator. The idea is to develop a full 16 bit SOC (System on a chip) system that will be used in or Hexapod project. Also we're going improve our HDL coding design. This project will be largelly based on xsoc xr16 project and my magic-1 fpga port aka as "fpga-magic-1". This processor should be very simple and easy to read, so I will supress MMU, Instruction set, addressing modes, etc.. to keep it simple.
Processor main characteristics
This processor will be a RISC non pipeline 16 bit big endian processor (By means of non pipeline we mean that our processor will execute one instruction at a time). As xr16 this processor will be designed to run integer-only C programs. After we develop our processor we will also develop a simple assembly compiler and retarget lcc to generate code to our processor.
Other important characteristic of our architecture is that our processor is Von Neumann. Wich means that our program and the data will be placed in the same memory storage.
Data Format
With this 16 bit processor we're going to define our data types like this:
typedef unsigned char Byte; // 8 bits
typedef unsigned Word; // 16 bits
typedef unsigned long Long; // 32 bits
Program Counter and addressing modes
Our PC register will have 16 bits wich means that we're going to address 65K of memory, on reset PC will be set to address 0, and each normal instruction it will be added by 2. The branch instructions may add different values in the case of displacements, the jump instructions will directly load a value.
Other point... Each instruction is 16-bit wide, so, we will encode our opcodes in 16-bits...
Register file
We're going to have 16 registers each one with the following meaning:
Register |
Use |
|---|---|
| r0 | General register |
| r1=RAcc | Reserved for assembler (Accumulator) |
| r2 | General register |
| r3-r5 | Routine parameters (Fast mode) |
| r6-r9 | General register |
| r10-r12 | Register variables (Fast mode) |
| r13 | Stack pointer |
System Flags
Some instructions will set some hardware flags, used to check conditions and stuff, in our processor we will be using these.
| Flag | Description |
|---|---|
| Zero | Result of ALU operation is Zero |
| Sign | Flag set when we have negative result |
| Carry | Indicate an arithmetic carry or borrow has been generated out of the most significant ALU bit (Unsigned overflow) |
| Overflow | Indicate when an arithmetic overflow has occurred in an operation. 127+127=-2 (Overflow) |
Instruction set and description
Now one of the most important part of a CPU design, the instruction set ... our CPU will have 32 instructions so they can be encoded with 5 bits. The table bellow show this encoding format.
| 15-11 | 10-7 | 6-3 | 2-0 |
|---|---|---|---|
| opcode | 0000 | 0000 | 000 |
| opcode | r(destiny) | 0000 | 000 |
| opcode | imm10-7 | imm6-3 | imm2-0 |
| opcode | r(destiny) | r(source) | 000 |
| Instruction | Encoding | Operation | Desctiption | Sample |
|---|---|---|---|---|
| mov | 00001 rrrr rrrr 000 | r(1) = r(2) | Move the content of some register to another | mov r1,r2 |
| movi | 00010 imm11 000 | RAcc = imm11 | Move the imediate 11 bit value to Accumulator | mov r1,0xFF |
| ldm | 00011 rrrr rrrr 000 | r(1) = mem(r(2)) | Load some value from memory pointed by r(1) and place in some register | ldm r1,r2 |
| stm | 00100 rrrr rrrr 000 | mem(r(1)) = r(2) | Place in memory pointed by r(1) the value in r(2) | stm r1,r2 |
| Instruction | Encoding | Operation | Desctiption | Sample |
|---|---|---|---|---|
| and | 00101 rrrr rrrr 000 | RAcc = r(1) and r(2) | Move the content of some register to another | mov r1,r2 |
| or | 00110 rrrr rrrr 000 | RAcc = r(1) or r(2) | Move the imediate 8 bit value to some register | mov r1,0xFF |
| not | 00111 rrrr 0000000 | RAcc = NOT r(1) | Invert all values of r(1) register | not r2 |
| inc | 01000 rrrr 0000000 | r(1) = r(1) + 1 | Increment register content | inc r3 |
| dec | 01001 rrrr 0000000 | r(1) = r(1) - 1 | Decrement register content | dec r2 |
| add | 01010 rrrr rrrr 000 | RAcc = r(1) + r(2) | Add r(1) and r(2) and place result in R accumulator | add r4,r5 |
| sub | 01011 rrrr rrrr 000 | RAcc = r(1) - r(2) | Subtract r(1) and r(2) and place result in R accumulator | sub r4,r5 |
| shfl | 01100 rrrr 0000000 | r(1) = r(1) << 1 | Shift left | shfl r5 |
| shfr | 01101 rrrr 0000000 | r(1) = r(1) >> 1 | Shift right | shfr r5 |
| rotr | 01110 rrrr rrrr 000 | r(1) = r(1) ror 1 | Rotate right | rotr r5 |
| Instruction | Encoding | Operation | Desctiption | Sample |
|---|---|---|---|---|
| jmp | 01111 rrrr 0000000 | PC = r(1) | Jump absolute to some position pointed by some register | jmp r4 |
| jmpr | 10000 s imm10 | if (s imm10 != 0) then if s = 0 then PC = PC + imm10 else PC = PC - imm10 |
Jump relative if s=0 increment PC by imm10 if s=1 decrement PC by imm10 | jmpr 3 |
| jz | 10001 rrrr 0000000 | if (ZeroFlag) then PC = r(1) |
Jump if zero absolute | jz r1 |
| jzr | 10010 s imm10 | if (ZeroFlag) then if s = 0 then PC = PC + imm10 else PC = PC - imm10 |
Jump if zero relative if s=0 increment PC by imm10 if s=1 decrement PC by imm10 | jzr 3 |
| jnz | 10011 rrrr 0000000 | if (!ZeroFlag) then PC = r(1) | Jump if not zero absolute | jnz r4 |
| jnzr | 10100 s imm10 | if (!ZeroFlag) then if s = 0 then PC = PC + imm10 else PC = PC - imm10 |
Jump if not zero relative (Comes back in | jnzr 10 |
| jp | 10101 rrrr 0000000 | if (SignFlag) then PC = r(1) | Jump absolute if positive | jp r3 |
| jpr | 10110 s imm10 | if (SignFlag) then if s = 0 then PC = PC + imm10 else PC = PC - imm10 |
Jump if positive relative if s=0 increment PC by imm10 if s=1 decrement PC by imm10 | jpr 3 |
| call | 10111 rrrr 0000000 | PC = r(1) , r2 = PC (current) | Go to routine in adress pointed by r(1) | call r1 |
| ret | 11000 00000000000 | PC = r2 | Return from routine to the point of calling | ret |
| Instruction | Encoding | Operation | Desctiption | Sample |
|---|---|---|---|---|
| in | 11001 rrrr 0000000 | r(1) = External | Receive something from external 16 bits port | in r1 |
| out | 11010 rrrr 0000000 | External = r(1) | Send something to external 16 bits port | out r1 |
| halt | 11011 00000000000 | HALT | Halt the system | halt |
| nop | 11100 00000000000 | no operation | Does nothing just increment PC | nop |
| Instruction | Encoding | Operation | Desctiption | Sample |
|---|---|---|---|---|
| push | 11101 rrrr 0000000 | mem(r13)=r(1) r13 = r13 + 1 |
Push a value from r(1) in memory at address in r13 | push r2 |
| pop | 11110 rrrr 0000000 | r(1) = mem(r13) r13 = r13 - 1 |
Get a value from memory at r13 and put in r(1) | pop r2 |
One point to observe... the RAcc (the accumulator registe) is just the r1 register. By sacrificing one register we can simplify a little bit the instruction opcode size.
Project source code and instructions definitions
Next topic:
Now that we defined all the important aspects of our CPU we're going to define it's datapath that will be controled by the control unit.