I was browsing the architecture of a simple CPU but there is one thing a cannot understand. Why is there data from the ALU going to the program counter and what is that data for?
2 Answers
Since this is a simple CPU, it's almost certainly to compute branch targets. Branch instructions typically represent the location to branch to as a small signed number to add to the program counter. The reason for this is that conditional branches almost always occur within a procedure or function, so it makes sense to encode them as an offset, which uses fewer bits.
In "real" CPUs, another common use case is to support position-independent code.
-
1$\begingroup$ In your second paragraph, you mean to provide PC-relative addressing modes and/or address-generation into registers? That's not necessary to support PIC, but it helps efficiency. e.g. 32-bit x86 can only read the program counter by running a
call
instruction (which pushes a return address), then reading that memory (e.g. withpop
into a register). This sucks a lot for PIC/PIE code: every function that accesses static data needs to find its own address and address the GOT relative to that, which is why x86-64 introduced RIP-relative addressing for data load/store, not just jumps/calls. $\endgroup$ Commented Mar 8, 2022 at 5:13 -
1$\begingroup$ Many modern RISC ISAs have an instruction like
adrp
that sets a GP-integer register = PC + something, with page granularity so it can reach far (scaling the immediate offset). See What are the semantics of ADRP and ADRL instructions in ARM assembly? for details for AArch64. So that's a specific real-world example of what I think you're talking about in that 2nd paragraph. $\endgroup$ Commented Mar 8, 2022 at 5:16
The program counter is a special processor register pointing to the next instruction to be fetched from memory and executed. When executing a non-branching instruction, the CPU increases the PC by 1 (or the size of instructions). Branching means assigning a new value to the program counter. Addresses to branch to are rarely absolute - usually they are relative to the current position, or to the beginning of a code segment. Therefore, such values need to be able to come from the ALU.
-
4$\begingroup$ Branch addresses can also come from a dedicated address generator, but an address generator and an ALU are similar enough that a simple CPU is likely to have just the ALU. $\endgroup$– MarkCommented Mar 8, 2022 at 2:36
-
1$\begingroup$ @Mark: yup, one reason for not sharing is in a pipelined design where an adder is busy computing the next PC to fetch, in parallel with executing an earlier instruction that might be ALU. e.g. a MIPS with the pipelining between stages taken out is even simpler to look at: Mips datapath procedure for executing an AND instruction? $\endgroup$ Commented Mar 8, 2022 at 5:20
-
$\begingroup$ Just as a comment about this, 8-bit micros of the 1970s and 1980s did not use the "main" ALU for incrementing the PC because data was typically 8-bit but the PC was 16-bit. The MOS 6502 had dedicated PC increment logic, the Zilog Z80 had a separate 16+8 bit adder which was also used for branch and index register calculations, and the Intel 8080 had a separate piece of logic that was used for increment and decrement operations on general registers as well as the PC. I suspect that using the "main" ALU for incrementing the PC has always been rare. $\endgroup$– Pseudonym ♦Commented Mar 8, 2022 at 23:24