your own ISA, what do you think about having 64 registers ? - Page 1
Forum section: electronics / general

author: legacy
author_rank: Super Contributor
timestamp: October 14, 2016, 10:43:20 pm
content: currently I have 32 registers, two are special (e.g. r0,ra),16 registers are used for the context inside a function,while the rest is used to pass parameters on function call(if you don't want to use the stack because it costs moreload/store operations --> the external ram is slower)I can easily increase their number up to 64 registersis it good, bad, useful, useless ?

author: legacy
author_rank: Super Contributor
timestamp: October 14, 2016, 10:52:03 pm
content: (ops, I had forgotten to say, the size of each cpu register is 32bit)

author: Sal Ammoniac
author_rank: Super Contributor
timestamp: October 14, 2016, 11:19:56 pm
content: Too many. Task context switch times increase when you have to save/restore that many registers.

author: helius
author_rank: Super Contributor
timestamp: October 14, 2016, 11:20:47 pm
content: Having a lot of registers increases the cost of context switches, unless you have physical shadow register files for all of them. One thing that has worked well in the past is to use a base pointer into the register file, like the AMD 29000.

author: westfw
author_rank: Super Contributor
timestamp: October 14, 2016, 11:44:22 pm
content: What they said. Too much context. I've noticed this particularly on Atmel AVRs. ~37 bytes of context, 2k of memory, 16MB/s memory access - not a great combination.

author: C
author_rank: Super Contributor
timestamp: October 15, 2016, 02:46:25 am
content: My first thought is Slow stack memory, fix stack memory.Does you external memory save you time if you read/write a block of locations?Done right a cache for stack would make most cpu access very fast while doing block read/writes to external memory.Stack uses block read/writeInstruction uses block readdata uses with normal memory read/write.

author: ale500
author_rank: Frequent Contributor
timestamp: October 15, 2016, 05:54:54 am
content: There are not that many examples of working architectures with 64 registers. One of the newest is the epiphany processor found in the Parallella board. It has 2 sizes of opcodes, 16 and 32 bits. Accessing the upper 56 registers requires the use of 32 bit opcodes, the lower 8 registers can be manipulated with 16 bit opcodes. It supports C, through GCC. Each processor has a 32 kBytes pool of local memory... that much.The 4-bit Saturn processor used in the HP48 among others, has 8 64-bit registers. Memory access is slow, and math routines are realized using only registers, and reading constants from memory.One architecture I like is the SuperH: 16 bit opcodes and 16 GPRs. Small constants can be used directly, larger constants need to be read from memory.Different uses have different needs, I'd like to see what uses do you have for 64 registers.

author: richardman
author_rank: Frequent Contributor
timestamp: October 15, 2016, 07:35:54 am
content: Not only is it expensive for context switching, it also affects your ISA encoding. It takes 6 bits to encode 64 registers, and that's just too much overhead.

author: andersm
author_rank: Super Contributor
timestamp: October 15, 2016, 08:59:00 am
content: Do what real ISA designers do, and analyze real code to see how registers are actually used. There's an unprecedented amount of research material available. Port a compiler to your proposed architecture, and see how it is able to use the registers. Does your average function take fourteen parameters? If not, they're wasted, unless you're implementing some kind of register window scheme, in which case are there enough? Non-leaf functions will need to save the contents of those registers, so they will be heavily disfavoured by compilers. How it affect your code density? Latencies?AFAIK, current research shows that around 16-32 registers is optimal, depending on whether you're using two- or three-operand instructions.

author: legacy
author_rank: Super Contributor
timestamp: October 15, 2016, 09:17:20 am
content: Quote from: Sal Ammoniac on October 14, 2016, 11:19:56 pmthe context switch is performed in hardwareit costs 1 instruction, and 4 clock ticks

author: legacy
author_rank: Super Contributor
timestamp: October 15, 2016, 09:19:50 am
content: Quote from: C on October 15, 2016, 02:46:25 amthe external memory is an asynchronous static ramthe RAM controller needs to take 100 msec of timein order to propagate the addressthen it needs other time in order to address the cell,perform the IO operation, and close the bus cycleit means a delay of 100msec plus some clock ticks to do socurrently every load/store on external memory needs morethan 10 clock ticks on my spartan6e @ 33Mhz,whereas BRAM takes 1 clock tick: it's at least 10x times slowerconclusion: the less you use the stack, the faster you goUnfortunately I can't use the BRAM, it's already usedQuote from: C on October 15, 2016, 02:46:25 amah, that fixage, you mean caching … well yes,I can add a "Write-through" caches D and Iit's not tested at the moment, but I can do it

author: legacy
author_rank: Super Contributor
timestamp: October 15, 2016, 09:25:43 am
content: I said "Write through" as the preferred methodbecause it allows for fast retrieval on demandwhile the same data in main memory ensuresthat nothing will get lost if a crash, or otherdisruption occurs: data loss cannot be tolerated

author: Kleinstein
author_rank: Super Contributor
timestamp: October 15, 2016, 09:38:41 am
content: Usually one does not need that many registers in typical algorithms. So the only use would be parameter passing. Even than so many registers with a static address are not needed - you would need to move the data to free the parameter passing registers before you can do an other function call. So if at all so many registers might be more useful if they are used similar to the sparc CPU: a few fixed direct accessible register file and more that are shifted out on function calls. This is kind of in between many static registers and a hardware implemented stack.A faster (buffered) stack might be the more useful way. Stack buffering could be different (simpler) than a classic memory cache, as there is only a defined way of access, no random access.It also depends on the use of the CPU. Context switching only is an issue with a multitasking OS.

author: legacy
author_rank: Super Contributor
timestamp: October 15, 2016, 09:59:19 am
content: Quote from: andersm on October 15, 2016, 08:59:00 amI have studied something similar on register transfer languageit's internally used by C compiler before taking the choiceof the machine code generation, in this phase you can havean infinity amount of registers, which are then reducedaccording to the target capability, in this phase the optimizertakes place, the smarter it goes the less it uses the stackI am designing my own compiler, it's not so smartQuote from: andersm on October 15, 2016, 08:59:00 amlooking at my own C programming style, I never use more than 6 parametersif I need more, I usually pass a pointer to a structQuote from: andersm on October 15, 2016, 08:59:00 amin the current ISA I have 32 registers, and hardware context switch14 registers are not saved, they are used to pass parameters on function call16 registers are saved in hardware, it costs 4 clock ticks, they are usable forlocal variables, local loop-indexes, local data, etcexceptions and interrupts have their private spacewhen interrupted, the hardware switch the whole bank of registers(both parameters pool and context pool), so you can call a functionfrom the ISR and it won't waste parameters once you go backfrom the exceptionthe mechanism is very comfortable for the programer's point of viewat the price of making the pipelining (HDL implementation) more complexQuote from: andersm on October 15, 2016, 08:59:00 amcurrently both the ALU and the ISA are designed with 3 sourcesinstructions can take three registers, or 1 register and 2 immediate datathe ALU always outputs 1 register(plus an hidden register, e.g. used by multiply and division)I can have up to 15 Cop-s, Cop0 is reserved for exceptions and interruptsCop1 is used for the DSP Engine, Cop2 is used by CordicCop1 has 3 inputs and 2 outputsCop2 has 3 inputs and 3 outputsQuote from: andersm on October 15, 2016, 08:59:00 amswitching from 32 registers to 64 registersdoesn't increase the code density,without increasing the latenciesthe code density is not itself optimalthe instruction's length usually takesfrom 4 bytes to 12 bytesapplications are usually 2 times bloated

author: legacy
author_rank: Super Contributor
timestamp: October 15, 2016, 10:16:42 am
content: Quote from: ale500 on October 15, 2016, 05:54:54 amcurrently I am solving the expression evaluation through an RPN approachwhich tries to map on registers instead of doing pushs and pops on memory,even though thereverse polish notationis itself a stack approach

author: andersm
author_rank: Super Contributor
timestamp: October 15, 2016, 10:59:38 am
content: Quote from: legacy on October 15, 2016, 09:59:19 amFunctions often call other functions.EDIT: Register banking helps with interrupt latency (but you need several banks for nested interrupts), but not OS task switching.

author: Kalvin
author_rank: Super Contributor
timestamp: October 15, 2016, 11:28:45 am
content: The instruction set needs to be as orthogonal as possible so that the compiler construction is straightforward. As the register count increases the instruction word needs to have more bits to access the registers. If you implement the processor in FPGA as softcore, you could possibly create an architecture which will have a sliding register window using the FPGA's internal fast RAM memory blocks. With the sliding register window you do not have to save and restore the registers during interrupts as you just slide the register window for a new context. You should have a few dedicated registers that are hardcoded: R0 will always be read as 0, register R1 could be dedicated as the base address of the sliding register window, R2 could be used as a generic stack pointer and R3 could be used as a generic register (for example Ada is using a second stack for the string operations). Then the other N register will be accessed using the sliding register window. During the FPGA compilation time you will just determine how deep the register window should be which will determine how many nested function calls and interrupts you can have.

author: legacy
author_rank: Super Contributor
timestamp: October 15, 2016, 11:48:44 am
content: Quote from: andersm on October 15, 2016, 10:59:38 amthere is no problem with that since before calling it's all matter ofcopying the (parameter) register's content into a (context) registerwhich consumes less clock ticks than putting things on the stackthe alternative consists on special class of instructionsable to load/save things from/to the local context to/from the next one(i don't call itsliding window register, the concept is the almost same)in this case parameters are all a private matterand all the registers are saved by the hardwaretherefore, every function owns its context with parametersthe problem with this approach: it adds more complexityand it costs a whole class of special instructionswhile the limit of this approach is the size of the BRAMcurrently I can serve 1024 contexts, each of 16 registersextending to 32 registers to be savedthe hardware will be able to serve the halfI have also implemented these features in abranchof the ISA(I say "branch", because it's a git branch of vhdl files)the multi-cycle version works as expected, but I have some troubles withthe pipelined versionQuote from: andersm on October 15, 2016, 10:59:38 amcurrently I have no support for nested interruptssince the hardware, during those events, can serve only one bank per timeit means, if an interrupt happens while the CPU is already serving an interruptthe new interrupt will be added to a queue, marked as "pending"and it will be served only after the conclusion of the RTI instruction(return from interrupt)edit:thequeueuses a First In -> First Out principle of actioninterrupts are not sorted or served by their priority, the Cop0 is not smart at alland from the programming point of view: interrupts are disabled during an ISR

author: legacy
author_rank: Super Contributor
timestamp: October 15, 2016, 11:51:38 am
content: @Kalvindude, something similar is already designed and implementedI have to decide details: how many registers and which branchI'd better go on

author: Kalvin
author_rank: Super Contributor
timestamp: October 15, 2016, 12:01:09 pm
content: Quote from: legacy on October 15, 2016, 11:51:38 amYes, I know it has already implemented. I just addressed the problem of the context switching and how the register count may affect the instruction width. There are studies that have determined the optimal register count for different architectures (just google a bit). Of course, you can ignore those and do what ever you want to. The single instruction architecture (MOVE) could be very simple and flexible, too.

author: Kalvin
author_rank: Super Contributor
timestamp: October 15, 2016, 12:12:40 pm
content: I you can fit the complete application code inside the FPGA's memory, you don't have to worry about instruction width and you can use a VLIW ISA, thus you can have as many registers as you want. Pretty simple.

author: andersm
author_rank: Super Contributor
timestamp: October 15, 2016, 12:31:51 pm
content: Maybe you should rephrase the question, since you're clearly not just designing an ISA, but instead have some fixed hardware and are designing around that. Which is fine, as long as you recognize that many of your design decisions don't make sense outside of that context.

author: amyk
author_rank: Super Contributor
timestamp: October 15, 2016, 12:41:49 pm
content: I agree with everyone else here who says that's far too many... in fact you're probably going to have trouble getting a compiler to use them all effectively. x86 has only 8 (more like 7 in practice) and yet I often see compilers using only 3-4 of them at once.That is provided we are talking about addressable registers, and not physical registers if you're doing out-of-order execution.

author: legacy
author_rank: Super Contributor
timestamp: October 15, 2016, 01:54:52 pm
content: Quote from: amyk on October 15, 2016, 12:41:49 pmgood pointmmm, at the end I believe I will go back on the 32-registers branch

author: technix
author_rank: Super Contributor
timestamp: October 16, 2016, 02:22:36 pm
content: From what I have seen I think having 64 orthogonal GPRs can be a bit too much. However if some of the 64 32-bit registers serve different purposes than GPRs I would consider it a better design. For example you can have 28 orthogonal GPRs, have your program counter, stack pointer, program state word and return address register all accessible just like normal registers, and 16 128-bit float-point and SIMD registers each accessible as 4 of 32-bit registers using a different instruction (or a subset of memory access instructions.)This would be somewhere in the middle of your 32-register branch and your 64-register idea. For a processor core that is not optimized for DSP/SIMD/Multimedia purposes you can leave the FPU/SIMD registers unimplemented or limited, while if the core is DSP-oriented you can even allowing the 28 main integer registers being used as 7 FPU and SIMD registers.

author: legacy
author_rank: Super Contributor
timestamp: October 16, 2016, 02:30:43 pm
content: Quote from: evb149 on October 15, 2016, 06:42:44 pmexactly the point

author: Kalvin
author_rank: Super Contributor
timestamp: October 16, 2016, 03:27:18 pm
content: It is very difficult for a human to utilize large number of registers efficiently, and optimize the code locally and globally so that it will maximize the register usage as optimal as possible. Not to mention what kind of a nightmare it will be to maintain. In a similar way it is very difficult for a human to produce manually efficient code for the architectures having multiple parallel execution units in order to keep the pipeline and the parallel execution units as full as possible. The TI C6000 is one example of this. Therefore, I would say that the optimal register count would be around 16 registers if you produce manual asm code. An optimizing high-level language compiler could possibly benefit from a large register array, but even then the gains may be quite marginal. Of course one can point out some specific applications that can really benefit from large register array, but in general the benefits of a large register array will not be that great.