← Design Verification Interviews

Interview Question · Code Writing

Writing a Register Adapter

L2 Mid-Leveluvmraladapter

The Question

The interviewer asks

Write the adapter between a register model and an APB agent. What do reg2bus, bus2reg and provides_responses do?

Reveal the Model Answer

reg2bus() turns a register operation into a bus item: kind, address and write data. bus2reg() does the reverse, filling kind, address, data and status from a completed bus item. The model calls it after each frontdoor access, and the predictor calls it for every observed transfer. Set provides_responses to 1 only if the driver returns separate responses with put_response(). Otherwise the model waits for a response that never comes.

One Frontdoor Write, Out and BackArrows are calls and items, in order, for regs.ctrl.write(status, 'h5a). The desired value changes when write() starts, the design at 25 ns, and the mirror at 30 ns.
One frontdoor write, out and backArrows are calls and items, in order, for `regs.ctrl.write(status, 'h5a)`. The desired value changes when `write()` starts, the design at 25 ns, and the mirror at 30 ns. component ral_test Callsregs.ctrl.write(status,5a) at 0 ns model regs.ctrl Desired 5a from 0 ns;mirror 01 until theaccess is predicted component default_map Address 0; fills auvm_reg_bus_op component apb_adapter reg2bus builds anapb_item; bus2regreads back data andstatus component APB sequencer +driver Setup at 10 ns, accesscompletes at 25 ns,item_done at 30 ns design incr_csr.ctrl Holds 5a after the 25ns edge write() callkind, addr 0, data 5areg2bus(rw)apb_item, started onthe sequencerAPB write at 25 nsstatus; predict 5a(auto prediction)
  1. Register to map0 ns (illustrative)

    At 0 ns write finds CTRL's address in the map and fills a uvm_reg_bus_op: kind, address 0, data 5a, size.

    Follow the calls, values and waits
    1. call write(status, 5a): ral_test → regs.ctrl
    2. data bus op: write, addr 0, data 5a: regs.ctrl → default_map
    3. Waiting: ral_test — inside write() until 30 ns
  2. Map to adapter

    reg2bus turns the operation into an apb_item, the only thing the APB driver understands. The map starts it on the sequencer.

    Follow the calls, values and waits
    1. data bus op: write, addr 0, data 5a: default_map → apb_adapter
    2. data apb_item: write 0 <- 5a: apb_adapter → APB sequencer + driver
    3. Waiting: default_map — waiting for the item to finish
  3. On the pins25 ns (illustrative)

    The driver runs the setup phase at 10 ns and the access phase; the design takes 5a at the 25 ns edge.

    Follow the calls, values and waits
    1. data apb_item: write 0 <- 5a: APB sequencer + driver → incr_csr.ctrl
  4. The item comes back30 ns (illustrative)

    At 30 ns the driver calls item_done. The map calls bus2reg on the finished item for its status.

    Follow the calls, values and waits
    1. return item_done: finished apb_item: APB sequencer + driver → apb_adapter
    2. return item_done: finished apb_item: apb_adapter → default_map
    3. Released: default_map
  5. Back to the register30 ns (illustrative)

    With auto prediction the mirror becomes 5a; the desired value already was, because write set it before the access began. write returns UVM_IS_OK at 30 ns.

    Follow the calls, values and waits
    1. data mirror = 5a: default_map → regs.ctrl
    2. return status UVM_IS_OK: regs.ctrl → ral_test
    3. Released: ral_test
Read the diagram as text
  • ral_test: Calls regs.ctrl.write(status, 5a) at 0 ns
  • regs.ctrl: Desired 5a from 0 ns; mirror 01 until the access is predicted
  • default_map: Address 0; fills a uvm_reg_bus_op
  • apb_adapter: reg2bus builds an apb_item; bus2reg reads back data and status
  • APB sequencer + driver: Setup at 10 ns, access completes at 25 ns, item_done at 30 ns
  • incr_csr.ctrl: Holds 5a after the 25 ns edge
  • ral_test → regs.ctrl: write() call
  • regs.ctrl → default_map: kind, addr 0, data 5a
  • default_map → apb_adapter: reg2bus(rw)
  • apb_adapter → APB sequencer + driver: apb_item, started on the sequencer
  • APB sequencer + driver → incr_csr.ctrl: APB write at 25 ns
  • default_map → regs.ctrl: status; predict 5a (auto prediction)

The register ledger with a bus: desired 5a at 0 ns, design 5a at 25 ns, mirror 5a at 30 ns.

An APB adapter whose driver writes read data back into the request item.
class apb_adapter extends uvm_reg_adapter;
  `uvm_object_utils(apb_adapter)
  function new(string name = "apb_adapter");
    super.new(name);
    supports_byte_enable = 0;
    provides_responses   = 0;   // the driver puts read data into the request
  endfunction
  virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
    apb_item t = apb_item::type_id::create("t");
    t.write = (rw.kind inside {UVM_WRITE, UVM_BURST_WRITE});
    t.addr  = rw.addr;
    t.data  = rw.data;
    return t;
  endfunction
  virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
    apb_item t;
    if (!$cast(t, bus_item)) `uvm_fatal("NOTAPB", "bus2reg needs an apb_item")
    rw.kind   = t.write ? UVM_WRITE : UVM_READ;
    rw.addr   = t.addr;
    rw.data   = t.data;
    rw.status = t.slverr ? UVM_NOT_OK : UVM_IS_OK;
  endfunction
endclass

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Mid-Level)

A good mid-level answer writes both functions and sets the status in bus2reg(). It sets provides_responses to match how the driver returns read data.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

WhyWhat IfProve ItCompare

  1. Writing a Register Adapter
  2. WhyWhy the Register Layer Needs an AdapterL1 JuniorL2 Mid-Level

    Why does the register layer need an adapter at all?

    Reveal the Model Answer

    The register model knows registers, addresses and values, but nothing about APB or AXI. The adapter is the only bus-specific piece. Swap the adapter and the same model and register sequences run over another bus.

    Self-Check

    Tick each key point you covered in your answer.

  3. What IfAn Adapter That Drops the Bus ErrorL2 Mid-Level

    What if the bus can return an error, and the adapter's bus2reg ignores it?

    Reveal the Model Answer

    Then every register access reports UVM_IS_OK, even when the bus answered with an error. A test of a missing or protected register then passes. Map the bus response into the status field, for example UVM_NOT_OK on an error. Then register sequences can check the status of each access.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "The register model checks bus errors itself."

    The model knows only what the adapter returns. If bus2reg leaves the status at OK, the error is lost.

    Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, reg/uvm_reg_adapter.svh, bus2reg

  4. What IfByte Enables in the AdapterL2 Mid-Level

    What if the bus has byte strobes, and you want to write one field without touching the rest of the register?

    Reveal the Model Answer

    Set supports_byte_enable to 1 and map rw.byte_en onto the strobes in reg2bus(). Then a field write can touch only its own bytes. With it at 0, uvm-core warns that the bus has no byte enables and accesses the complete register instead.

    Self-Check

    Tick each key point you covered in your answer.

  5. CompareDirect vs Layered Register SequencingL3 Senior

    Compare running register sequences directly on the bus sequencer with layering a register sequencer on top of it.

    Reveal the Model Answer

    On the bus sequencer directly, register items compete with other bus sequences, and a test can grab the sequencer. A layered register sequencer gives central, bus-independent control. But register traffic then cannot mix with bus-specific sequences or use their grab and notification hooks. Most benches use the direct form.

    Self-Check

    Tick each key point you covered in your answer.

  6. Prove ItSolve U13.2.1: Registers That All Read ZeroSimulator-graded

    Show it, don't just say it: this Silicon Lab problem is graded by the simulator.

    Open Problem U13.2.1

What People Get Wrong

Common wrong answers and why they fail.

Missed Corner

"provides_responses = 1 is safer; it waits for the read data."

With 1, the map calls get_response() after every item. A driver that writes read data into the request and never calls put_response() leaves the register access hanging.

Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, reg/uvm_reg_map.svh (do_bus_write/do_bus_read: get_base_response when provides_responses)

Misconception

"bus2reg() is only used for reads."

The map calls it after frontdoor writes too, and the predictor calls it for every observed write and read. A bus2reg() that skips writes breaks prediction.

Source uvm-core 2020.3.1 (IEEE 1800.2 library) source, reg/uvm_reg_predictor.svh (write calls adapter.bus2reg)

Half-Truth

"Status is always UVM_IS_OK on APB."

APB has PSLVERR since APB3. If bus2reg() ignores it, every register test passes straight over a slave error.

Learn It, Then Prove It