Pipeline - wgrzegorz/c5xtools GitHub Wiki
Pipeline
Normative source: SPRU056D, chapter 7 (Pipeline Structure, Pipeline Operation, Pipeline Latency).
The TMS320C5x executes instructions through a four-level pipeline. At any moment up to four instructions are in flight, each occupying a different phase, so that one instruction can finish while the next three advance. The pipeline is not hardware-protected for every conflict: most interlocks are left to the programmer, who must arrange code so that two phases never fight over the same resource. This page transcribes the four phases, shows how instructions overlap cycle by cycle, walks through the conflict cases (branches, memory-mapped register loads, external-bus contention), and lists the latency a program must account for after writing certain registers.
1. Pipeline structure
The pipeline has four phases. Each instruction passes through all four in order:
| Phase | Letter | What it does |
|---|---|---|
| Fetch | F | Reads the instruction word(s) from memory and updates the program counter (PC). |
| Decode | D | Decodes the instruction word, generates the operand address, and performs ARAU updates of the auxiliary registers. |
| Read | R | Reads operands from memory when the instruction needs them. In indirect mode it reads the location pointed at by the current AR as it stood before the update made in the previous decode phase. |
| Execute | E | Carries out the operation and, when required, writes the result of an earlier operation back to memory. |
When the pipeline is fully loaded, all four phases run in parallel on four different instructions. The hardware assigns no priority among the phases, so if two phases need the same resource (a memory location or a CPU register) in the same cycle, the result is undefined. The programmer's job is to keep those collisions out of the code.
ASCII rendering of the fully loaded pipeline (after SPRU056D Figure 7-1), with instruction N entering fetch while older instructions occupy the later phases:
Each column is one CLKIN cycle. A single-word, single-cycle instruction run with no wait states overlaps perfectly: once the pipe is primed, one instruction reaches execute every cycle.
2. How instructions flow each cycle
Follow one instruction diagonally: it is fetched, then one cycle later decoded, then read, then executed - four cycles from fetch to completion. Because the four phases work on four different instructions at once, a new instruction starts and an old one finishes on every cycle of a filled pipe.
flowchart LR
F["Fetch (F)\nread word, update PC"] --> D["Decode (D)\ndecode, address gen, ARAU update"]
D --> R["Read (R)\nread operand (AR pre-update)"]
R --> E["Execute (E)\noperate, write-back"]
A two-word instruction spends two cycles in fetch (one per word). The cycle that fetches the second word produces a "dummy" operation one phase downstream, because that fetched word is an operand, not a new opcode. The reference tables show this as the word "dummy" sitting in the decode, read, or execute slot.
3. Pipeline operation
The pipeline is invisible to the programmer except in a handful of situations: auxiliary-register updates, memory-mapped accesses to CPU registers, the NORM instruction, and memory-configuration changes. In those cases the lack of full protection shows through and the code must be arranged to avoid a conflict.
3.1 Normal operation (one-word and two-word)
For a stream of one-word, single-cycle instructions the pipe stays full and the
F/D/R/E diagonal above holds. A worked one-word example from the source
(ADD *+, SAMM TREG0, MPY *+, SQRA *+,AR2) illustrates two points that
recur throughout the chapter:
- An indirect read in the R phase uses the AR value that existed before the decode-phase update two cycles earlier, not the current value.
- A memory-mapped store such as
SAMM TREG0writes in the E phase, so its effect is not visible to instructions already past their own decode phase.
3.2 Branch, call, and return
Because the pipe is four levels deep, a branch, a subroutine call, or a return normally takes 4 cycles to flush the partially fetched instructions that follow it in memory. A conditional branch (BCND) also costs 4 cycles when its condition is true; when the condition is false the BCND behaves like an ordinary two-word instruction and no flush occurs.
The decision happens in the branch's execute (E) phase. Only then is the PC updated - to the destination when the branch is taken, or to the next sequential instruction when it is not. The instructions fetched speculatively in the meantime are turned into dummy operations as they move down the pipe.
Transcribed flush sequence for a taken branch (SPRU056D Table 7-3,
ADD/BCND LBL,NEQ/.../LBL SUB *+; F/D/R/E columns, "dummy" = flushed slot):
Cycles 4 through the re-fetch of the branch target are consumed by dummy operations - the 4-cycle flush. For a call the return address is pushed onto the top of stack (TOS) during the E phase before control transfers; for a return, the address is popped from TOS back into the PC in the E phase. The dummy sequence that surrounds them is the same.
3.3 Memory-mapped loads of auxiliary registers
ARAU updates of the ARs happen in the decode (D) phase, early enough to feed the following read (R) phase. But a memory-mapped write to an AR (for example SAMM, LMMR, SACL, or SPLK targeting the AR) happens in the execute (E) phase, which is later. Consequently:
- The next two instructions after a memory-mapped load of an AR must not use that AR.
- Updates to the index register (INDX) and to the auxiliary-register compare register (ARCR) also occur in the E phase, so any AR update that relies on INDX or ARCR must come at least two cycles after the load of those registers.
Inserting one or two NOPs between the memory-mapped load and the dependent use (as the source's Example 7-7 and Example 7-8 show) resolves the hazard.
3.4 External-memory bus conflict
The C5x has a single external address/data bus pair. If both program and data memory are external, the instruction fetch (F), operand read (R), and execute (E) write phases can all demand the external bus at once. The hardware inserts a dummy operation to break the tie, delaying the losing access by a cycle. An external write takes 3 cycles, so while a store (e.g. SACL) occupies the E phase writing externally, any instruction fetch or operand read that needs the external bus is delayed for 3 cycles.
4. Pipeline latency
Memory-mapped registers are reached in the decode (D) and fetch (F) phases, but they are written in the E phase. A write therefore does not take effect until a few instruction words later; instructions in between see the old value. Table 7-10 of the source lists, for each register, how many words of latency to allow.
Direct accesses that do not use memory-mapped addressing - all the C2x-compatible instructions such as LAR and LT - are pipeline-protected (stalled) in hardware, so they introduce no programmer-visible latency. The latency below applies only to the memory-mapped write path.
| Register | Description | Words | A later instruction is affected by |
|---|---|---|---|
| ARx | Auxiliary registers 0-7 | 2 | Next word uses the previous value; a second-word update is overwritten |
| ARCR | Auxiliary register compare register | 2 | Next 2 words use the previous value |
| BMAR | Block move address register | 1 | Next 1 word uses the previous value |
| CBCR | Circular buffer control register | 2 | Next 2 words cannot be the end of a buffer |
| CBER | Circular buffer end registers 1 and 2 | 2 | Next 2 words cannot be the end of a buffer |
| CBSR | Circular buffer start registers 1 and 2 | 2 | Next 2 words use the previous value |
| CWSR | Wait-state control register | 1 | Next 1 word uses the previous modes |
| GREG | Global memory allocation register | 1 | Next 1 word uses the previous map |
| INDX | Index register | 2 | Next 2 words use the previous value |
| IOWSR | I/O port wait-state register | 1 | Next 1 word uses the previous count |
| PDWSR | Program/data wait-state register | 1 | Next 1 word uses the previous count |
| PMST | Processor mode status register | 2 | Next 2 words use the previous map |
| ST1 | Configuration control (CNF) bit in ST1 | 2 | Next 2 words use the previous map |
| TREG1 | Dynamic shift count | 1 | Next 1 word uses the old shift count |
| TREG2 | Dynamic bit address | 1 | Next 1 word uses the old bit address |
4.1 NORM and the -p assembler option
The NORM instruction changes the current AR in its execute (E) phase. The same
pipeline management applies: an AR update or an SAR store placed directly after
a NORM would use the stale AR. The assembler's -p option detects an AR update
or store immediately after NORM and inserts NOP instructions automatically, so
the code stays source-compatible with the C2x.
4.2 Memory-reconfiguration latency
The C5x reconfigures memory segments (internal versus external) during the E phase. Before an instruction can rely on the new configuration, at least two instruction words must follow the reconfiguring instruction. A long-immediate instruction counts as two words and can fill the requirement by itself:
CLRC CNF ; map RAM block B0 into data space
LACC #01234h ; 2-word instruction fills the 2-word gap; ACC = 00001234h
ADD * ; ACC = 00001235h
The same two-word rule applies to configurations controlled by the PMST. A related caveat concerns CNF and interrupts: if the main code runs in block B0 (CNF = 1) and an interrupt service routine that is not in B0 clears CNF to 0, a RETE will not restore CNF in time to fetch the next instruction from B0. The service routine must therefore set the CNF bit at least two words before the RETE.
5. Relation to the Instruction Timing page
Everything above describes the mechanism; the Instruction Timing page gives the resulting cycle counts. A one-word, single-cycle instruction in a full pipe retires every cycle - the non-delayed, fully overlapped case. Operations that break the overlap cost extra cycles that Instruction Timing accounts for: a branch, call, or return flushes the pipe for 4 cycles, external-bus contention inserts dummy cycles (and up to 3 cycles for an external write), and the memory-mapped register latencies above force spacing (one or two words) between a write and its first dependent use. Read the two pages together: this page says why a given instruction class is not single-cycle, and Instruction Timing says how many cycles it is.
License
MIT - (c) 2026 Grzegorz Worona [email protected]. See LICENSE.