Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Paths
  • Concept Map
  • How to Read the Diagrams
  • Part 0: What Is a Protocol?10
  • Part 1: Timing and Clocking11
  • Part 2: Encoding and Framing12
  • Part 3: Handshakes13
  • Part 4: Flow Control17
  • Part 5: Transactions19
    • Reads and Writes Are Not Symmetric
    • The Request/Response Model
    • Address Maps and Decoding
    • Register Semantics
    • Combined and Split Transactions
    • Independent Channels
    • Posted and Non-Posted Writes
    • Bursts
    • Alignment, Strobes and Narrow Transfers
    • Boundary Rules
    • Width and Endianness Conversion
    • Transaction Attributes
    • Atomics
    • Sideband or In-Band
    • Interrupts and Notification
    • Descriptors, Rings and Doorbells
    • Bridges and Protocol Conversion
    • Protocols Compared: Transactions
    • Drills: Transactions
  • Part 6: Concurrency and Performance17
  • Part 7: Ordering13
  • Part 8: Sharing and Arbitration12
  • Part 9: Deadlock and Liveness13
  • Part 10: Reliability and Recovery20
  • Part 11: Bring-Up and Link Management10
  • Part 12: Power8
  • Part 13: Shared State and Coherence9
  • Part 14: Security and Isolation7
  • Part 15: Specifying and Verifying11
  • Part 16: Protocols Dissected17
  • Part 17: Capstones5
  • Part 18: Interview Preparation6
Loading lesson

‹Part 5: Transactions
  1. Topics
  2. First Principles of Hardware Protocols
  3. Part 5: Transactions
  4. Combined and Split Transactions

Part 5 · Transactions · Working (W)

Combined and Split Transactions

A combined transaction holds the bus until its answer comes back; a split transaction lets go after the request and is answered later. Why splitting helps, and what it costs: IDs, buffers and more state.

On this page

    Note

    Level: Working (W) · Answers: What exactly is being asked?

    Before this: The Request/Response Model

    Two processors share a bus. One reads from a slow flash controller that takes a long time to answer. While it waits, the other processor, which only wants a word from fast on-chip RAM, cannot use the bus at all. The bus is "busy", yet for most of that time no data is moving on it. Everyone is waiting for one slow target.

    Must a transaction hold the bus until it is answered, and what does letting go cost?

    The obvious answer, and why it breaks

    The obvious bus protocol keeps a transaction on the bus from request to response: the requester drives the address, the target stretches the transfer until it has the data, and then the bus is free. It is simple, because the bus itself remembers who asked what. But the bus is occupied for the target's whole latency, and a slow target turns a shared bus into a queue behind it.

    The idea: split the request from the response

    Combined (held)

    Split

    The bus is occupied

    From request until the response

    Only while a request or a response is actually moving

    During the target's latency

    Nobody else can use the bus

    Other requests and responses use it

    How the response finds its requester

    Implicit: the bus is still connected

    The response carries an ID or tag

    State needed

    None beyond the bus

    The target queues requests; the requester remembers what is outstanding

    A split transaction turns one long occupation of the bus into two short ones: a request phase and a response phase, with the target's latency between them spent off the bus. That is what lets a protocol keep many requests in flight (Part 6).

    Build it: the same two requests, both ways

    Master A reads from a slow target (4 cycles to answer) in cycle 0; master B reads from a fast target (1 cycle) in cycle 1. The testbench draws both buses side by side.

    tb.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    // Two masters, A and B, share a path to two targets: a slow one (4 cycles to answer)
    // and a fast one (1 cycle). A asks the slow target in cycle 0; B asks the fast one in
    // cycle 1. Both buses are simulated side by side.
    //   Combined: a transaction holds the bus from request until its data returns, so B
    //   waits for A. (c_a / c_b = bus held by A / B.)
    //   Split: a request takes one cycle on the request path and the bus is free again;
    //   the target answers later on the response path. (s_*_req / s_*_rsp.)
    module tb;
      logic clk = 0;
      always #5 clk = ~clk;
      initial begin $dumpfile("wave.vcd"); $dumpvars(0, tb); end
      localparam int SLOW = 4, FAST = 1;
      int cyc = -1;
      always @(posedge clk) cyc <= cyc + 1;
    
      // Combined bus: A holds it for 1 + SLOW cycles, then B for 1 + FAST
      wire c_a = (cyc >= 0) && (cyc < 1 + SLOW);
      wire c_b = (cyc >= 1 + SLOW) && (cyc < 2 + SLOW + FAST);
      // Split bus: one-cycle requests; responses come back after each target's latency
      wire s_a_req = (cyc == 0);
      wire s_b_req = (cyc == 1);
      wire s_b_rsp = (cyc == 1 + FAST + 1);
      wire s_a_rsp = (cyc == SLOW);
    
      int b_done_c = -1, b_done_s = -1, busy_c = 0, busy_s = 0;
      always @(posedge clk) begin
        if (c_b && !(cyc + 1 < 2 + SLOW + FAST) && b_done_c < 0) b_done_c <= cyc;
        if (s_b_rsp) b_done_s <= cyc;
        if (c_a || c_b) busy_c <= busy_c + 1;
        if (s_a_req || s_b_req) busy_s <= busy_s + 1;
      end
      initial begin
        #120;
        if (b_done_c == 6 && b_done_s == 3 && busy_c == 7 && busy_s == 2)
          $display("PASS: B finishes in cycle %0d split vs %0d combined; the request path is busy 2 cycles instead of 7", b_done_s, b_done_c);
        else $display("FAIL: B done %0d / %0d, busy %0d / %0d", b_done_s, b_done_c, busy_s, busy_c);
        $finish;
      end
    endmodule

    The model only draws who uses each path in each cycle; the point is when B is answered and how long the shared path is busy.

    Watch it run

    How to read it, slot by slot:

    • Combined, slots 0 to 4: c_a is high: A holds the bus for its request and the target's four cycles of latency, though data moves only at the end.

    • Combined, slots 5 and 6: only now can B use the bus (c_b); its answer arrives in slot 6.

    • Split, slots 0 and 1: A's request (s_a_req) and B's request (s_b_req) each take one cycle, back to back.

    • Split, slots 3 and 4: B's response comes back in slot 3, before A's (slot 4). B finished in slot 3 instead of 6, and the request path was busy for 2 cycles instead of 7.

    What splitting costs

    • Identifiers. With several requests outstanding, each response must say which request it answers (lesson 6.4).

    • Buffering. A target that accepts requests faster than it answers them must queue them; a requester must keep track of what it is waiting for, and have room for responses when they arrive.

    • Ordering questions. B's answer overtook A's. Whether that is allowed, and between which requests, is a protocol decision (Part 7).

    • Deadlock risk. Requests and responses now travel separately and can block each other if they share buffers (Part 9).

    How real protocols chose

    Protocol

    Choice

    APB

    Combined: one transfer at a time, stretched with wait states until PREADY.

    Original AHB (AMBA 2)

    Combined, with escape hatches: SPLIT and RETRY responses let a slow target release the bus. AHB-Lite, a single-master version, dropped them.

    AXI

    Split by construction: requests and responses travel on separate channels, matched by IDs.

    PCI Express

    Split: a non-posted request is answered later by a completion carrying the requester's tag.

    What breaks

    A system (illustrative) put a slow configuration-flash controller on the same combined bus as the processors' fast peripherals. Every boot-time flash read froze every other bus access for hundreds of cycles, and an interrupt handler missed its deadline. Moving the flash behind a split interface (accept the request, answer later) freed the bus during flash latency; the alternative, a dedicated bus for the slow target, would have worked too.

    Why this matters

    Senior lens. A combined bus is fine when every target answers within a few cycles and few requesters share it. As soon as one target is slow, or requesters need several transactions in flight, split them, and budget the IDs, queues and ordering rules that come with it. Look for the slowest target on any held bus: it sets everyone's worst-case latency.

    Interview

    Asked: "Why do split transactions improve bus utilisation?"

    Weak answer: Because they're faster.

    Strong answer: On a combined bus a transaction holds the bus for the target's whole latency, even though data only moves at the end, so one slow target blocks everyone. Splitting releases the bus after the request and brings the response back later, so other requests and responses use the bus during that latency. The cost is IDs to match responses, queues in targets and requesters, and ordering and deadlock rules, because requests and responses now travel independently.

    Follow-ups: (1) What does a split protocol need that a combined one doesn't? (2) How did AHB handle slow targets?

    Check yourself A combined bus has a target with 20 cycles of latency. While it serves one read, how many cycles is the bus unavailable to others?

    About 21: the request cycle plus all 20 cycles of latency, during which almost no data moves.

    Check yourself In the waveform, B's response arrives before A's. Why is that possible only on the split bus?

    On the split bus the paths are free during A's latency, so B's request and response pass through; on the combined bus B cannot even start until A is done.

    Key takeaways

    • A combined transaction holds the bus for the target's whole latency; a split one uses it only to move the request and the response.

    • Splitting lets other traffic use the bus during latency and allows many transactions in flight.

    • Splitting needs IDs, buffering, ordering rules and deadlock care.

    Keep going

    Next: Lesson 5.6, Independent Channels. Separate channels for addresses, data and responses: why AXI has five.

    Related topics

    • Part 5 overview: Transactions

    Previous

    72 / 234

    Next: Independent Channels

    Up next

    Up nextIndependent Channels

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Reads and Writes Are Not Symmetric
    • The Request/Response Model
    • Address Maps and Decoding
    clkc_ac_bs_a_reqs_b_reqs_b_rsps_a_rsp
    Simulation output: A asks a slow target, B a fast one. Combined, B waits for A's whole latency; split, B is answered first.