The registers are a precious resource. Using the coding space for something else reduces the orthogonality and flexibility of the whole architecture.
However, including the PC as a read/write register has many benefits. AMD introduced the RIP-relative addressing mode with their AMD64, though it's not directly visible. You might still be able to do a LEA [0] to get RIP in a register.
Classic operations with the PC can emulate many special opcodes and free some space in the opcode map. Make sure though that you correctly handle the value : is PC pre- or post-incremented ?
In my design, there is often a cohabitation of PC and NPC :
- PC is the address of the current instruction. It's good to have it for when you have a trap.
- NPC is "Next PC" or "New PC", pointing to the next instruction (not the destination of a jump, yet, it's usually the output of an incrementer). It's important to have it to fetch the next instruction, sure, but also to save it during function calls or interrupts.
Now, if the PC is a user-visible and writable register, you can have some fun :
- any writes to PC will jump. You can perform conditional jumps if the opcode is predicated. For free.
- you can save PC easily along with all the register set, in a clean bundle.
- you can directly implement indirect jumps (or calls) by loading memory into PC. No funky addressing modes to take care of.
This approach uses one register in an already tight register set but the gain in opcode space and flexibility are worth it, IMHO.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.
No mention of the venerable PDP11 where the PC is R7 and SP by convention is R6? I realised how elegant this was ages ago. For example local variables in languages like C are just indexed off SP. Well maybe a better example is load constant is actually load indirect PC with auto increment.
Are you sure? yes | no