URL
https://opencores.org/ocsvn/tinycpu/tinycpu/trunk
Subversion Repositories tinycpu
[/] [tinycpu/] [trunk/] [docs/] [design.md.txt] - Rev 39
Compare with Previous | Blame | View Log
This is the design of TinyCPU. It's goals are as follows:1. 8-bit registers and operations (8 bit processor)2. 16-bit address bus3. fixed 16-bit instruction length4. use a small amount of "rich" instructions to do powerful things5. 1 instruction per clock cycleI/O:I/O has been decided to use a memory mapped approach.Howto:Basically, absolute address 0-32 is reserved for ports. Right now there is only a Port0. This port is 8-bits long.Each even address is the port address. Each odd address is the bitmap for write or read for the port below it.So to make ports 7 to 4 write and 3 to 0 read, you'd assign 0xF0 to address 0x0001BIG CHANGE:So, apparently making a single-cycle CPU is extremely hard... so instead, we'll be striving for a 2-cycle CPU.Usual cycles:1-cycle: mov, jmp, etc general data movement2-cycle: ALU operations1-cycle with memory wait(so really 2 cycle): all instructions that reference memoryRelative moves:In order to provide uesfulness to the segment-carryover feature, there are a few options for moving a "relative" amount to a register, including IP and SPA relative move differs in most of the opcodes in that the relative factor is treated as a signed value.so for instance, amov r0,50mov_relative r0, -10in the ned, r0 will end up being 40. Although this feature won't see much use in general registers, IP and SP are special because of the option of using thesegment-carryover feature. This means that SP and IP, while being 8-bit registers, can function very similar to a 16-bit register, enabling full usage of the available address space.Register list:r0-r5 general purpose registerssp stack pointer (represented as r6)ip instruction pointer register (represented as r7)cs, ds, es, ss segment registers (code segment, data segment, extra segment, stack segment)tr truth register for conditionalsgeneral opcode formatfirst byte:first 4 bits: actual instructionnext 3 bits: (target) registerlast 1 bit: conditionalsecond byte:first 1 bit: second portion of condition (if not immediate) (1 for only if false)next 1 bit: use extra segmentnext 3 bits: other register. If not 3rd registerlast 3 bits: extra opcode information or third register. such as for ADD it could be target=source+third_register...or second byte is immediate valueFor opcodes requiring 3 registers but without room, the target opcode is assume to be the second operation. Such as for AND, target=source AND targetshort list of instructions: (not final, still planning)immediates:1. move reg, immediate2. move [reg], immediate3. push and move reg, immediate (or call immediate)4. move (relative) reg, immediatemini-group 5. Root opcode is 5, register is to tell which opcode( up to 8). No register room, only immediatepush immedateXXXXXXXXXXXXXXgroups: (limited to 2 registers and no immediates. each group has 8 opcodes)group 1:move(store) [reg],regmove(load) reg,[reg]out reg1,reg2 (output to port reg1 value reg2)in reg1,reg2 (input from port reg2 and store in reg1)XXXXmove segmentreg,regmove reg,segmentreggroup 2:and reg1,reg2 (reg1=reg1 and reg2)or reg, regxor reg,regnot reg1,reg2 (reg1=not reg2)left shift reg,regright shift reg,regrotate right reg,regrotate left reg,reggroup 3: comparesis greater than reg1,reg2 (TR=reg1>reg2)is greater or equal to reg,regis less than reg,regis less than or equal to reg,regis equal to reg,regis not equal to reg,regequals 0 regnot equals 0 reggroup 4:push segmentregpop segmentregpush and move reg, reg (or call reg)exchange reg,regexchange reg,segXXXXgroup 5:XXXXfar jmp reg1, reg2 (CS=reg1 and IP=reg2)far call reg1,reg2far jmp [reg] (first byte is CS, second byte is IP)push extended segmentreg, reg (equivalent to push seg; push reg)pop extended segmentreg, reg (equivalent to pop reg; pop seg)reset processor (will completely reset the processor to starting state, but not RAM or anything else)group 6:set default register bank to 0 (can be condensed to 1 opcode)set default register bank to 1push extended reg, regpop extended reg,regenable carryover segdisable carryover segmov relative reg, regexchange reg, regsuper group: Super groups only have room for 1 register argument. Each subgroup has 8 opcodes, capable of 8 subgroups.subgroup 0:push regpop regset TRreset TRincrement regdecrement regset register bank 0set register bank 1subgroup 1:enable carryover segdisable carryover seg3 register instructions:1. add reg1, reg2, reg3 (reg1=reg2+reg3)2. sub reg1, reg2, reg3opcodes used: 14 of 16. 2 more opcodes available. Decide what to do with the room later.Possible canidates for opcode compression include* equals 0 and not equals 0 (room for 7 sub-opcodes each) (not doing that because it'd screw with the easy ALU codeconditionals0 -- always1 -- only if truefor only if false, there should basically be another compare or if applicable an always afterwardslimitations that shouldn't be passed with instructions* Doing 2 memory references* pushing a memory reference (equates to 2 memory references)Note it is possible however to read and write 16bits at one time to the memory to consecutive addresses that are 16-bit aligned.segments:DS is used in all "normal" memory referencesSS is used in all push and pop instructionsES is used when the ExtraSegment bit is set for either push/pop or normal memory referencesCS is only used for fetching instructionsSegment carryover:In order to overcome the limitations of only having a 256 byte segment, there is a workaround option to "pretend" that IP is a 16 bit register.When CS carryover is enabled, when IP rollover from 255 to 0 or whatever, CS will be incremented. This makes it so that if you start at address 0:0.you can continue as far as needed into the address space without having to do ugly far jumps at each of the borders.Carryover can only be done on CS and SS. The required circuitry is not implemented for DS or ES due to an extreme level of complexity required for it, alsoit would only lead to unncessarily complex codeAlso of note is that `move relative` implements a "carryover" component. This component will work on either IP or SP, and uses CS and SS respectively.If used on other registers, there will be no carry over functionality, though it can be used as an easy way to add or subtract an immediate from a register.States needed:0. reset1. decode current instruction (All without memory capable within 1 clock cycle)2. increment IP(and SP if needed) and fetch next instruction3. Write 1 register to memory4. Read 1 register from memory5. Write 2 registers to memory6. Read 2 registers from memory7. Write 1 register to memory and setup increment of sp8. Write 2 registers to memory and setup double increment of sp9. Read 1 register from memory and setup decrement of sp10. Read 2 registers from memory and setup double decrement of sp11.registerfile map:0000: general r00001: general r10010: general r20011: general r30100: general r40101: general r50110: SP (r6)0111: IP (r7)1000: second bank r01001: second bank r11010: second bank r21011: second bank r31100: CS1101: DS1110: ES1111: SSBanking works like if(regnumber(2) = '0') then regnumber(3)=regbank; end if;ALU operations00000 and reg1,reg2 (reg1=reg1 and reg2)00001 or reg, reg00010 xor reg,reg00011 not reg1,reg2 (reg1=not reg2)00100 left shift reg,reg (logical)00101 right shift reg,reg (logical)00110 rotate right reg,reg00111 rotate left reg,reg01000 is greater than reg1,reg2 (TR=reg1>reg2)01001 is greater or equal to reg,reg01010 is less than reg,reg01011 is less than or equal to reg,reg01100 is equal to reg,reg01101 is not equal to reg,reg01110 equals 0 reg01111 not equals 0 reg10000 Set TR10001 Reset TR10011 Increment10010 Decrement10100 Add10101 SubtractAlignment restrictions:In general, their is very few times that a full 16-bit read or 16-bit write is done. These are the times:* Extended push* Extended pop* instruction fetchBecause of this, and because I want for 2 clock cycles to be the longest instruction, I must place some alignment restrictions on the CPUSo, IP must be aligned to a 16-bit address (must be an even number). And SP must also be aligned to a 16-bit address.Though I don't plan on putting any "real" restriction to setting it to an odd address, nothing will actually work right.Stack Details:Because of the need for 16-bit writes and reads of the stack, even though we're usually only using 8-bit values, we end up pushing 2 bytes at one time always.Stack is oppositely done from the 8086. push X will move X to SS:SP and then increment SP by 2.Let's take an example program:--SS is 0mov sp, 10push 0xffafter this, 0x00FF will be moved to SS:SP (0x0010) and then sp will be incremented by 2. If we push an 8-bit value, the value is put in the least-significant byte, and the MSB is 0On Reset:On reset, all general registers are set to 0CS is set to 1, IP is set to 0. SS is set to 2 and SP is set to 0.Carryover is set on CS and not set on SS. DS and ES is 0. TR is false.Register bank 0 is selected.Electrical operation:On power-on, RESET should be high for at least 2 clock cycles. HOLD can optionally be high as well after these two clock cycles.When HOLD is no longer needed, it should just be turned low and an extra clock cycle should be waited on for it to return to RESET stateWhen RESET is held low, the processor will execute. It takes 3 clock cycles for the processor to "catch up" to actually executing instructionsRegister order:The order of registers is read from left to right with left being the most significant bit of the 16-bit opcode.So for instance,0101_*000*0_0*111*_0010 is `mov [r0], IP/r7`. The register portions of the opcode are surrounded by astericksImplemented opcode list:legend:r = register choiceR = register choice or opcode choice for sub groupsC = conditional portions = segment register choicei = immediate dataN = not usedo = opcode choice (for groups)_ = space for readability0000_rrrC_iiii_iiiimov reg, immediate0001_rrrC_iiii_iiiimov [reg], immediategroup 3 comparions0011_rrrC_Crrr_Noooopcode choices000: is greater than reg1,reg2 (TR=reg1>reg2)001: is greater or equal to reg,reg010: is less than reg,reg011: is less than or equal to reg,reg100: is equal to reg,reg101: is not equal to reg,reg110: equals 0 reg111: not equals 0 reggroup 4 bitwise0100_rrrC_Crrr_Noooopcode choices000: and reg1,reg2 (reg1=reg1 and reg2)001: or reg, reg010: xor reg,reg011: not reg1,reg2 (reg1=not reg2)100: left shift reg,reg101: right shift reg,reg110: rotate right reg,reg111: rotate left reg,reggroup 5 misc0101_rrrC_CRRR_soooopcode choices:000: subgroup 5-0RRR choices:000: push reg001: pop reg001: mov reg, reg010: mov reg, [reg]011: mov [reg], reg
