Skip to content

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 PPROT at the version level: it told you that APB4 adds two signals (PSTRB and PPROT) on top of APB3, and that PPROT is "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 PPROT against its access policy and returns PSLVERR when a request is not permitted. That chapter owns the verdict — the permit/deny logic and the error response. It (correctly) assumes the PPROT bits 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's PPROT. The slave never invents these bits; it only receives them.
  • Stable through the access, like PADDR. PPROT is 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.

A two-part diagram: on the left a table of the three PPROT bits with their polarities including the inverted security bit; on the right the provenance of each bit from the master's privilege, security, and access-kind context; and along the bottom the propagation path from master through an AXI-to-APB bridge to the slave, with PPROT held stable through SETUP and ACCESS, and the enforcement step drawn dashed and deferred to chapter 9.4.
Figure 1 — the PPROT[2:0] encoding and its lifecycle. Left: the three independent bits with their AMBA polarities — PPROT[0] privilege (1 = privileged, 0 = unprivileged), PPROT[1] security with inverted sense (0 = secure, 1 = non-secure), PPROT[2] access type (1 = instruction, 0 = data). Right: provenance — each bit is sourced from the master's execution context (privilege level → bit 0, TrustZone security state → bit 1, fetch-vs-load/store → bit 2). Bottom: the lifecycle — the master drives AxPROT, an AXI→APB bridge maps it one-to-one onto PPROT, the slave samples it, and the bits are held stable through SETUP and ACCESS exactly like PADDR. The enforcement step (permit/deny + PSLVERR) is shown dashed and deferred to chapter 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."

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ---------------------------------------------------------------------------
// (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.
endmodule

Three 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:

BitNameMeaning when 0Meaning when 1Where it comes from
PPROT[0]privilegeunprivileged / normal accessprivileged accessMaster's current privilege level (kernel vs user); via bridge from AxPROT[0]
PPROT[1]non-secure (inverted!)secure accessnon-secure accessMaster's security state (TrustZone secure/non-secure); via bridge from AxPROT[1]0 = secure
PPROT[2]instructiondata 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. Carrying PPROT end-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 PPROT to 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 real AxPROT, or, if the upstream genuinely has no notion of protection, drive a conservative constant (e.g. unprivileged + non-secure, 0b011 for data) so over-permissioning never happens silently — never the most privileged constant.
  • Decode-on-the-fly vs. register. Because PPROT is 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 PPROT at the slave and at the originating master in the same window. At the master, PPROT = 0b011 for the non-secure data access (bit 1 = 1, non-secure — correct). At the slave, PPROT = 0b000 — bit 1 reads 0 (secure) and bit 0 reads 1 (privileged). The context has changed between master and slave, and it changed at exactly one component: the AXI→APB bridge. The bridge's pprot output sits at a constant 0b000 for every access, regardless of the axprot input.

  • Root cause: the bridge hardwires PPROT to a constant privileged-secure value instead of propagating AxPROT. Someone wrote assign pprot = 3'b000; (or left it unconnected with a 0 default) 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 sees PPROT[1] = 0 (secure) and PPROT[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 Mentor
    Snippet
    // 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 semantics

    If the upstream side genuinely has no protection notion, drive the conservative constant (unprivileged + non-secure, e.g. 3'b011 for data) so accesses are never over-trusted — never 0b000.

  • 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 Mentor
    Snippet
    // 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 PPROT end-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 the PPROT it decides from; verify the input before you debug the decision.

Two stacked cases of an AXI-to-APB bridge. The top green case shows AxPROT 0b011 propagated faithfully to PPROT 0b011 so the slave sees the true non-secure unprivileged context. The bottom red case shows the same AxPROT 0b011 input ignored and PPROT hardwired to 0b000, so the slave sees a forged privileged-secure context and the protection scheme is silently defeated at the bridge.
Figure 2 — the bridge propagation bug. Top (correct, green): a non-secure unprivileged data access enters as AxPROT = 0b011, the bridge maps it one-to-one, and the slave sees PPROT = 0b011 — the true context is preserved, so the protection scheme can work. Bottom (bug, red): the same access enters as AxPROT = 0b011, but the bridge ignores its input and ties PPROT to the constant 0b000 (privileged + secure); the slave now sees a forged privileged-secure context for every access, so the entire protection scheme is silently defeated at the bridge. No error is raised because PPROT carries context, not a verdict — the bug is invisible until a low-privilege or non-secure access is wrongly accepted.

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 on pprot with 8 bins, ideally crossed with read/write direction, is the baseline.

    Azvya Education Pvt. Ltd.VLSI Mentor
    Snippet
    covergroup 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 PPROT arriving at the APB slave equals the AxPROT that 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 upstream AxPROT against the downstream PPROT per transaction ID/address, not just instantaneously.

  • Assert stability through the access. PPROT must not change once the transfer has started — it is held from SETUP through ACCESS like PADDR. A $stable assertion makes a wandering PPROT (a master that updates it mid-transfer, or a glitchy mux) loud:

    Azvya Education Pvt. Ltd.VLSI Mentor
    Snippet
    // 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 PPROT reflects the true context. The deepest property — and the one a constraint-random environment must encode — is that the driven PPROT actually corresponds to the requester's modelled execution state: a secure-world master drives PPROT[1] = 0, a privileged access drives PPROT[0] = 1, a fetch drives PPROT[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 whose PPROT contradicts 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

  1. 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.
  2. Generate from context. Given a master with cpu_privileged, cpu_secure, and access_is_fetch, write the three assign statements that produce PPROT — and explain which one needs an inversion and why.
  3. 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.
  4. 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.
  5. Write the stability check. Draw an APB4 transfer and mark where PPROT is 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 onto PPROT.
  • It is address-phase information, stable through SETUP and ACCESS like PADDR — it describes the whole access and does not change cycle-to-cycle.
  • PPROT is the context, not the verdict. It carries who-is-asking-and-in-what-mode; the permit/deny decision and the PSLVERR on a violation are enforcement, owned by chapter 9.4. Keep the two crisply separate.
  • The marquee failure is a bridge that hardwires or drops PPROT when 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 → PPROT correspondence checked, stability asserted, and PPROT proven 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) and PPROT (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.