AMBA APB · Module 10
PPROT Feature Deep Dive
PPROT[2:0] as the access's identity — privileged vs unprivileged, secure vs non-secure (inverted polarity), instruction vs data — where the bits come from (the originating master's execution context), how they propagate through bridges from AXI AxPROT, and the bridge bug that defeats protection by hardwiring them. Enforcement is owned by the protection-violations chapter.
Every protection decision a system makes — may this access read that register, fetch that code, touch that secure region? — needs one thing first: a trustworthy description of who is asking and in what mode. That description is PPROT. The single idea to carry through this chapter: PPROT[2:0] is three independent attribute bits — privilege, security, and data-vs-instruction — that the originating master drives from its current execution context and the system propagates unchanged down to the slave, where they sit stable across the access like PADDR. PPROT is the access's identity. It does not decide anything; it is the input every protection decision is made from — and getting its encoding, source, and propagation exactly right is what makes the whole protection scheme trustworthy.
1. Problem statement
A modern SoC runs code at different privilege levels (kernel vs user), in different security worlds (TrustZone secure vs non-secure), and issues two fundamentally different kinds of access (instruction fetches vs data loads/stores). A peripheral — a secure key store, a privileged control register, a region that must never be executed from — frequently needs to behave differently depending on the requester. But the slave sits at the far end of a bus fabric. It has no visibility into the CPU's privilege level, no idea which security world issued the access, and no way to tell a fetch from a load. By the time the transfer reaches it, all of that context has been stripped to an address and a direction.
PPROT is the protocol's answer to "carry the requester's context all the way to the slave." It is three bits that travel with every access and encode exactly the attributes a protection-aware slave (or a downstream filter) needs:
- Privilege — is this a privileged (kernel-class) access or an unprivileged (user-class) one?
- Security — is this a secure-world access or a non-secure one?
- Access type — is this an instruction fetch or a data access?
The job of this chapter is the feature itself: the precise encoding of those three bits (including their easy-to-mistake polarities), where each bit physically comes from, how it is carried and kept faithful from the originating master through bridges down to the APB slave, and what each bit means. The job is not what the slave then does with it — that decision (permit, deny, raise PSLVERR) is a separate concern we deliberately hand off.
2. Why previous knowledge is insufficient
You have already met PPROT twice, from two different angles — and neither one is the feature deep-dive.
- Chapter 10.3 — APB4 introduction introduced
PPROTat the version level: it told you that APB4 adds two signals (PSTRBandPPROT) on top of APB3, and thatPPROTis "the protection/access-context signal." That is the right altitude for "what changed between versions," but it stops at naming. It does not tell you the bit-by-bit encoding, the inverted security polarity, where the bits originate, or how they survive a protocol down-conversion. - Module 9, Chapter 9.4 — protection violations covered enforcement: how a slave checks
PPROTagainst its access policy and returnsPSLVERRwhen a request is not permitted. That chapter owns the verdict — the permit/deny logic and the error response. It (correctly) assumes thePPROTbits arriving at the slave are meaningful, and reasons about what to do with them.
This chapter sits between those two. 9.4 owns enforcement; this chapter owns the feature definition. Here we answer the questions 10.3 was too high-level to reach and 9.4 took as a given: what does each bit mean, what polarity does it use, where does it come from, and how does it propagate faithfully from the master's context to the slave's input. We will repeatedly forward-link to 9.4 for "and then the slave decides" — because the moment you start reasoning about permit/deny and PSLVERR, you have left this chapter's scope.
There is also a structural parallel worth holding in mind. Chapter 10.6 — PSTRB deep dive dissected the other APB4 sideband signal — byte strobes — as a feature: its encoding, its source, its lifecycle. PPROT is the companion. Where PSTRB describes which bytes of a write to commit, PPROT describes who is making the access and in what mode. Both are sideband attributes that travel with the address; both are dropped harmlessly when down-converting to APB2, which has neither. The mental scaffolding from 10.6 transfers directly.
3. Mental model
The model: PPROT is the access's ID badge. When someone walks up to a secure door, the lock does not interrogate them — it reads the badge they are already wearing. The badge encodes three independent facts: their clearance level (privileged or not), their security domain (secure or non-secure), and what they came to do (fetch instructions or move data). The person (the master) is issued the badge by the system that knows their context; they cannot forge it themselves mid-transaction; and they wear it unchanged for the whole visit. The lock (the slave) reads the badge to decide — but reading and deciding are different jobs, and the badge is just the data.
Three refinements make it precise:
- Three independent bits, eight legal combinations.
PPROT[0]= privilege (1= privileged,0= unprivileged/normal).PPROT[1]= security, with inverted sense:1= non-secure,0= secure — zero, not one, is the secure value.PPROT[2]= access type (1= instruction,0= data). The bits are orthogonal: a privileged-secure data access (0b000), an unprivileged-non-secure instruction fetch (0b111), and every combination in between are all valid. - The master drives it from context, not the slave. Every bit is sourced from the originating master's current execution state — its privilege level sets bit 0, its security state sets bit 1, and whether the access is a fetch or a load/store sets bit 2. A bridge between protocols propagates the equivalent upstream signal (AXI's
AxPROT) one-to-one down to APB'sPPROT. The slave never invents these bits; it only receives them. - Stable through the access, like
PADDR.PPROTis driven in SETUP alongside the address and held constant through ACCESS until the transfer completes. It does not change cycle-to-cycle within a transfer. It is address-phase information: it describes this access and is valid for exactly as long as the access is.
The throughline: PPROT is context carried as data. It says who is asking and in what mode. What gets done with that answer — permit, deny, error — is enforcement, and that lives in 9.4.
4. Real SoC implementation
In silicon, PPROT has a clear lifecycle: a master generates it from its execution context, a bridge propagates it from the upstream protocol, and a slave samples it. Here are all three. Note carefully that the slave samples and decodes PPROT but defers the actual permit/deny + PSLVERR to the enforcement logic of chapter 9.4 — this chapter's RTL stops at "the context has arrived and been understood."
// ---------------------------------------------------------------------------
// (A) A master generating PPROT from its current execution context.
// The bits are NOT invented by the bus — they reflect the requester's state.
// ---------------------------------------------------------------------------
module apb_master_pprot_gen (
input cpu_privileged, // 1 = kernel/privileged, 0 = user
input cpu_secure, // 1 = secure world, 0 = non-secure
input access_is_fetch, // 1 = instruction fetch, 0 = data load/store
output [2:0] pprot
);
// PPROT[0] = privilege : 1 = privileged, 0 = unprivileged
// PPROT[1] = security : 1 = NON-secure, 0 = secure <-- INVERTED sense!
// PPROT[2] = access : 1 = instruction, 0 = data
assign pprot[0] = cpu_privileged; // direct
assign pprot[1] = ~cpu_secure; // INVERT: secure world drives 0
assign pprot[2] = access_is_fetch; // direct
endmodule
// ---------------------------------------------------------------------------
// (B) An AXI->APB bridge propagating AxPROT down to PPROT, one-to-one.
// AXI AxPROT uses the SAME bit semantics, so this is a faithful pass-through,
// NOT a constant. Hardwiring it would silently defeat the protection scheme.
// ---------------------------------------------------------------------------
module axi2apb_pprot_bridge (
input [2:0] axprot, // from the AXI transaction (AWPROT / ARPROT)
output [2:0] pprot // to the APB segment
);
// AxPROT[0]=privileged, AxPROT[1]=non-secure, AxPROT[2]=instruction
// map identically — the access context must survive the down-conversion.
assign pprot = axprot; // faithful 1:1 propagation
endmodule
// ---------------------------------------------------------------------------
// (C) A slave SAMPLING and decoding PPROT. It reads the context and exposes
// the decoded attributes. It does NOT permit/deny here and does NOT drive
// PSLVERR -- that enforcement decision belongs to chapter 9.4.
// ---------------------------------------------------------------------------
module apb_slave_pprot_sample (
input pclk, presetn,
input psel, penable,
input [2:0] pprot,
// decoded view of the requester's context (consumed by 9.4 enforcement)
output acc_privileged,
output acc_secure,
output acc_instruction
);
// PPROT is address-phase info: valid and stable from SETUP through ACCESS.
// Decode straight off the bus -- no need to register it for the decision.
assign acc_privileged = pprot[0]; // 1 = privileged
assign acc_secure = ~pprot[1]; // inverted: 0 on the bus = secure
assign acc_instruction = pprot[2]; // 1 = instruction fetch
// NOTE: the permit/deny comparison against this slave's access policy, and
// the resulting PSLVERR on a violation, are deliberately NOT here.
// See chapter 9.4 (protection-violations) for the enforcement mechanics.
endmoduleThree facts define PPROT design. First, the bits are generated from real context — the master in (A) maps its privilege/security/access state onto the three bits, and the inversion on bit 1 is the single most common place this goes wrong. Second, propagation must be faithful — the bridge in (B) passes AxPROT through unchanged because AXI and APB share the same bit semantics; substituting a constant there is the classic protection-defeating bug we dissect in beat 7. Third, the slave's job in this chapter ends at decode — (C) exposes the access's context but hands the permit/deny verdict to 9.4. Keeping that boundary crisp is exactly what keeps the feature (context) separable from enforcement (decision).
5. Engineering tradeoffs
There are not many knobs on PPROT — its value is fixed by the requester's context — so the "tradeoffs" here are really the encoding contract an integrator must get exactly right, plus the few real design choices around how faithfully and how far the context is carried. The encoding table is the heart of the chapter:
| Bit | Name | Meaning when 0 | Meaning when 1 | Where it comes from |
|---|---|---|---|---|
PPROT[0] | privilege | unprivileged / normal access | privileged access | Master's current privilege level (kernel vs user); via bridge from AxPROT[0] |
PPROT[1] | non-secure (inverted!) | secure access | non-secure access | Master's security state (TrustZone secure/non-secure); via bridge from AxPROT[1] — 0 = secure |
PPROT[2] | instruction | data access (load/store) | instruction access (fetch) | Whether the access is a fetch vs load/store; via bridge from AxPROT[2] |
The design choices that do exist sit around this contract:
- Carry full context vs. drop it. Down-converting to a version without
PPROT(e.g. APB2) drops the context — which is safe by omission (the slave simply enforces nothing) but means that segment has no protection capability. CarryingPPROTend-to-end is what enables protection at all; the cost is three extra wires per access path and the integration discipline to keep them faithful. - Faithful propagation vs. hardwiring. A bridge can tie
PPROTto a constant — and it is tempting when the upstream side does not expose protection. But a constant forges every access's identity (see beat 7). The honest choices are: propagate the realAxPROT, or, if the upstream genuinely has no notion of protection, drive a conservative constant (e.g. unprivileged + non-secure,0b011for data) so over-permissioning never happens silently — never the most privileged constant. - Decode-on-the-fly vs. register. Because
PPROTis stable through the access, a slave can decode it combinationally off the bus (as in beat 4) rather than registering it. Registering buys nothing for the decision and costs flops; the only reason to register is if downstream logic needs the attribute after the access completes.
The throughline: PPROT's tradeoff space is small precisely because its value is not a design choice — it is a faithful report of context. The engineering is in carrying that report intact, and the failure mode is any place the report gets corrupted, dropped, or forged.
6. Common RTL mistakes
7. Debugging scenario
-
Observed symptom: a TrustZone bring-up team finds that a non-secure bus master can successfully access a peripheral that the security architecture says is secure-only. There is no error, no
PSLVERR, no hang — the access just works when it should have been rejected. Functional traffic looks perfect; only the security test that deliberately issues a non-secure access to a secure region exposes it, and even then only because the access succeeds instead of being denied. -
Waveform clue: trace
PPROTat the slave and at the originating master in the same window. At the master,PPROT = 0b011for the non-secure data access (bit 1 =1, non-secure — correct). At the slave,PPROT = 0b000— bit 1 reads0(secure) and bit 0 reads1(privileged). The context has changed between master and slave, and it changed at exactly one component: the AXI→APB bridge. The bridge'spprotoutput sits at a constant0b000for every access, regardless of theaxprotinput. -
Root cause: the bridge hardwires
PPROTto a constant privileged-secure value instead of propagatingAxPROT. Someone wroteassign pprot = 3'b000;(or left it unconnected with a0default) when down-converting from AXI — likely because the upstream interface was stubbed during early integration and never revisited. The effect is catastrophic and silent: every downstream access is now labelled privileged-and-secure, so every secure-only slave seesPPROT[1] = 0(secure) andPPROT[0] = 1(privileged) and permits the access. The protection scheme is not bypassed — it is defeated at the source, because the very context it decides from has been forged. No enforcement logic in 9.4 can save it; that logic is making correct decisions on a lie. -
Correct RTL: propagate the real context. Replace the constant with a faithful one-to-one mapping:
Azvya Education Pvt. Ltd.VLSI MentorSnippet// WRONG: forges every access as privileged + secure // assign pprot = 3'b000; // RIGHT: propagate the originating master's true context unchanged assign pprot = axprot; // AxPROT and PPROT share identical bit semanticsIf the upstream side genuinely has no protection notion, drive the conservative constant (
unprivileged + non-secure, e.g.3'b011for data) so accesses are never over-trusted — never0b000. -
Verification assertion: bind a propagation check across the bridge that fails the instant the slave-side context diverges from the master-side context:
Azvya Education Pvt. Ltd.VLSI MentorSnippet// PPROT seen by the slave must equal the AxPROT that entered the bridge, // sampled in the access phase of the same transfer. property pprot_propagates_faithfully; @(posedge pclk) disable iff (!presetn) (psel && penable) |-> (pprot == axprot_latched); endproperty a_pprot_prop: assert property (pprot_propagates_faithfully) else $error("PPROT at slave (%b) != AxPROT at bridge in (%b) -- forged/dropped context", pprot, axprot_latched); -
Debug habit: when a protection check behaves wrongly, trace
PPROTend-to-end before you touch the enforcement logic. Compare the bits at the originating master against the bits at the slave. If they differ, the bug is generation or propagation (this chapter), not enforcement (9.4) — and the usual culprit is a bridge or adapter that dropped, defaulted, or hardwired the context. A protection scheme is only ever as trustworthy as thePPROTit decides from; verify the input before you debug the decision.
8. Verification perspective
Verifying PPROT as a feature is about proving the context is correct, complete, faithfully carried, and stable — strictly separate from verifying the slave's decision (which is 9.4's coverage). Four properties anchor a PPROT verification plan:
-
Cover all eight combinations.
PPROT[2:0]has three independent bits, so there are exactly 8 legal values. Functional coverage must hit every one — privileged/unprivileged × secure/non-secure × data/instruction — because protection bugs frequently hide in the rarely-exercised corners (e.g. a non-secure instruction fetch,0b111, that nothing in the directed suite ever generates). A coverpoint onpprotwith 8 bins, ideally crossed with read/write direction, is the baseline.Azvya Education Pvt. Ltd.VLSI MentorSnippetcovergroup cg_pprot @(posedge pclk iff (psel && penable)); cp_pprot : coverpoint pprot { bins all[] = {[0:7]}; } // all 8 contexts endgroup -
Check correspondence across propagation (AxPROT → PPROT). Where a bridge down-converts, assert that the
PPROTarriving at the APB slave equals theAxPROTthat entered the bridge for the same transaction. This is the property that catches the beat-7 forge/drop bug. Because AXI and APB share bit semantics, the check is a direct equality — any re-encoding or constant is a failure. Scoreboard the upstreamAxPROTagainst the downstreamPPROTper transaction ID/address, not just instantaneously. -
Assert stability through the access.
PPROTmust not change once the transfer has started — it is held from SETUP through ACCESS likePADDR. A$stableassertion makes a wanderingPPROT(a master that updates it mid-transfer, or a glitchy mux) loud:Azvya Education Pvt. Ltd.VLSI MentorSnippet// PPROT must be stable from the SETUP edge until the transfer completes. property pprot_stable_through_access; @(posedge pclk) disable iff (!presetn) (psel && !penable) |=> (psel && penable && $stable(pprot)); endproperty a_pprot_stable: assert property (pprot_stable_through_access); -
Prove
PPROTreflects the true context. The deepest property — and the one a constraint-random environment must encode — is that the drivenPPROTactually corresponds to the requester's modelled execution state: a secure-world master drivesPPROT[1] = 0, a privileged access drivesPPROT[0] = 1, a fetch drivesPPROT[2] = 1. In a UVM agent, the sequence's notion of "secure/privileged/fetch" must map onto the bits with the correct (inverted-for-security) polarity, and a check should flag any transaction whosePPROTcontradicts its declared context. This is what separates "the bits are legal" from "the bits are true."
The point: PPROT verification proves the context is sound — all combinations exercised, faithfully propagated, stable, and truthful — and stops at the boundary where the slave acts on it. The permit/deny + PSLVERR coverage (illegal-access detection, error response timing) belongs to 9.4; keeping the two plans separate is what keeps each one complete.
9. Interview discussion
"What is PPROT and where does it come from?" is a fast filter for whether a candidate has actually integrated a protection-aware fabric or only read the signal name. The clean answer is structured in three moves: encoding, provenance, lifecycle.
Start with the encoding, and lead with the trap: PPROT[2:0] is three independent bits — [0] privilege (1 = privileged), [1] security inverted (0 = secure, 1 = non-secure), [2] access type (1 = instruction). Naming the inverted security polarity unprompted is the single strongest signal you actually know this. Then provenance: every bit is driven by the originating master from its execution context — privilege level, TrustZone security state, fetch-vs-load/store — and propagated through bridges from AXI's AxPROT (same encoding) down to APB PPROT. The slave never invents it. Then lifecycle: it is address-phase information, stable from SETUP through ACCESS like PADDR.
The depth move is to draw the line between feature and enforcement: PPROT carries the context; the slave's permit/deny decision and the PSLVERR it raises on a violation are enforcement, a separate concern. A candidate who says "PPROT blocks the access" has conflated the two — PPROT blocks nothing; it is the input a protection check decides from. Close with the integration payoff and the war story: the most damaging PPROT bug is a bridge that hardwires or drops it when down-converting from AXI, forging every access as privileged-secure and silently defeating protection everywhere downstream — which is why, when a protection check misbehaves, you trace PPROT from master to slave before you touch the enforcement logic. That sequence — encoding (with the inverted bit), provenance, lifecycle, feature-vs-enforcement, and the propagation failure mode — is exactly the version-aware, integration-grade judgment the question is probing for.
10. Practice
- Encode three contexts. Write the
PPROT[2:0]value for: (a) a privileged secure data write; (b) an unprivileged non-secure instruction fetch; (c) a privileged non-secure data read. State each bit and watch the inverted security polarity. - Generate from context. Given a master with
cpu_privileged,cpu_secure, andaccess_is_fetch, write the threeassignstatements that producePPROT— and explain which one needs an inversion and why. - Audit a bridge. Given
assign pprot = 3'b000;in an AXI→APB bridge, state exactly what every downstream access now looks like, why no error is raised, and what test would expose it. - Place the boundary. For a secure-only register that returns an error on a non-secure access, identify which part is
PPROT(this chapter) and which part is enforcement (9.4), and name the signal each side owns. - Write the stability check. Draw an APB4 transfer and mark where
PPROTis driven and where it must be held; then write the assertion that fails if it changes between SETUP and the end of ACCESS.
11. Q&A
12. Key takeaways
PPROT[2:0]is three independent context bits:[0]privilege (1= privileged),[1]security inverted (0= secure,1= non-secure),[2]access type (1= instruction,0= data). All eight combinations are legal.- The master drives it from execution context — the slave never invents it. Privilege level, TrustZone security state, and fetch-vs-load/store set the three bits; bridges propagate AXI's
AxPROT(same encoding) one-to-one ontoPPROT. - It is address-phase information, stable through SETUP and ACCESS like
PADDR— it describes the whole access and does not change cycle-to-cycle. PPROTis the context, not the verdict. It carries who-is-asking-and-in-what-mode; the permit/deny decision and thePSLVERRon a violation are enforcement, owned by chapter 9.4. Keep the two crisply separate.- The marquee failure is a bridge that hardwires or drops
PPROTwhen down-converting from AXI — forging every access as privileged-secure and silently defeating protection everywhere downstream. Faithful one-to-one propagation, or at worst a conservative constant, is mandatory. - Verification proves the context is correct, complete, faithfully carried, and stable — all 8 combinations covered,
AxPROT → PPROTcorrespondence checked, stability asserted, andPPROTproven to reflect the true requester context. - The whole APB evolution ties together here: APB2 was context-free; APB3 added flow control and an error channel; APB4 added the two sideband attributes —
PSTRB(which bytes to write) andPPROT(who is asking and in what mode). Together they turn the minimal baseline into a fabric that can do partial writes and carry protection context — the two-phase core unchanged underneath.