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

  • RTL Foundations36
  • Combinational Design25
  • Sequential Design27
  • FSM & Control27
  • Timing & Clocking39
  • Reset & CDC34
  • Memory & Buses57
    • SRAM and ROM
    • Register Files
    • Valid/Ready Handshake
    • AXI-Lite
    • AXI-Stream
    • Bus Integration
    • Synchronous FIFO
    • Register-Map and CSR RTL
    • Memory Reliability
    • Peripheral RTL Integration
      • Peripheral Shell
      • Clock, Reset, and Power Contract
      • Interrupts and Events
      • FIFO and DMA Boundary
      • Errors and Integration Signoff
    • Full AXI4: RTL Roadmap
  • Advanced RTL28
  • Senior & Interview76
  • Glossary and Notation
Loading lesson

‹Peripheral RTL Integration
  1. Topics
  2. RTL Design
  3. Memory & Buses
  4. Peripheral RTL Integration
  5. Peripheral Shell

Part 7 · Memory & Buses · Intermediate

Peripheral Shell

Partition the block so bus timing, software-visible state, buffering, and pin protocol can be verified independently.

Why this matters

A peripheral whose engine sees bus signals directly is hard to test and hard to reuse. A thin shell with one accepted-request interface keeps bus timing out of the protocol engine.

After this lesson you can: partition a peripheral into transport, CSR bank, control, datapath and IO timing, and define the accepted-request interface between them.

Partition

Owns

Does not own

Bus adapter

Handshake, response, transport errors

Field side effects

CSR bank

Address decode, access types, reset values

AXI/APB timing

Control FSM

Start/stop, sequencing, timeout

Software bus state

Datapath/FIFO

Serialization, buffering, counters

Interrupt policy

IO wrapper

Synchronizers, pin enables, pad-facing timing

Register map

The bus adapter passes req_take to the CSR bank. The CSR bank sends start_pulse to the control FSM and tx_fifo_push to the TX FIFO, and pops the RX FIFO. The TX FIFO feeds the serializer datapath, which the FSM controls, which drives the IO wrapper and pushes into the RX FIFO.
The peripheral shell as five owners: only accepted operations cross each boundary, so the engine never sees a bus signal

Read the picture from the top: each arrow label is the only thing that crosses that boundary.

  • Accepted operations only. The CSR bank turns a bus request into start_pulse or tx_fifo_push after its reject checks; a rejected request crosses nothing.

  • Two sides of each FIFO. Software or DMA pushes the TX FIFO; the engine pops it. The two must never be confused.

  • Pins live at the bottom. Synchronisers and output enables sit in the IO wrapper, away from the register map.

The CSR boundary enqueues TX words; the SPI engine dequeues them when it can serialize and enqueues RX samples. engine_busy is the single busy owner (including start reservation on the acceptance edge); no separate stale busy_q gates commands. Software and DMA arbitrate for each FIFO port before acceptance. The engine never sees AXI-Lite or APB signals.

Request at internal req_take

CSR response

Side effect owner

TX write while tx_fifo_full

Error, no enqueue; software retains/retries word

CSR boundary

TX write with space and port grant

OK

One tx_fifo_push

RX read while rx_fifo_empty

Error, no dequeue

CSR boundary

START while engine_busy or invalid config

Error plus sticky illegal-command event

CSR boundary; engine unchanged

Legal START

OK

One start_pulse; engine reserves busy immediately

Use the linked CSR single-outstanding contract: acceptance is req_valid && req_ready at an edge; full/empty/busy are sampled there. csr_start_write/csr_tx_write/csr_rx_read below are decoded committed one-cycle req_take pulses, even for a request returning error. Error responses are retained until consumed, and no invalid operation is silently reported as success. RX return data additionally needs the FWFT or registered-result adapter described below.

design.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
// snippet: clean internal contracts
assign start_reject = csr_start_write && (engine_busy || !config_valid);
assign tx_reject    = csr_tx_write && tx_fifo_full;
assign rx_reject    = csr_rx_read && rx_fifo_empty;
assign csr_op_error = start_reject | tx_reject | rx_reject;
assign start_pulse = csr_start_write && !start_reject;
assign tx_fifo_push = csr_tx_write && !tx_reject;
assign rx_fifo_pop  = csr_rx_read && !rx_reject;
// TX engine dequeue is distinct from software/DMA enqueue.
assign tx_fifo_pop = engine_tx_take;
assign busy_o      = engine_busy;
assign done_event  = engine_done;
assign error_event = timeout_error | protocol_error | start_reject;

Illustrative edge

Bus/internal ownership

Result

E0

TX write accepted internally while full

Error response saved; zero pushes

E1/E2

APB ACCESS held or AXI response stalled

Same error held; no replay even if engine frees space

E3

Response consumed

One rejected operation completes

E4

Software retry accepted with space

Exactly one enqueue (not engine dequeue)

E5

START accepted while engine_busy=1

One error + illegal-command cause; zero start pulses

The internal interface names accepted FIFO operations and start events instead of leaking bus channel levels into the engine.

Check yourself Where should a write to TXDATA be rejected when the TX FIFO is full?

At the CSR/peripheral contract boundary, with a documented stall or error policy. The protocol engine should only see accepted FIFO pushes.

Remember

  • The engine sees accepted FIFO operations and start events, never bus channel levels.

  • engine_busy has a single owner, including the reservation on the accepting edge.

  • An invalid operation returns an error and is never reported as success.

Rule of thumb: decide who owns each piece of state, then draw the boundary around it.

Keep going

  • Practice: Memory-mapped register interface with read and write support

  • Interview: run a mock interview on this topic

Related topics

  • Register-map RTL

  • Clock, reset, and power contract

Previous

239 / 350

Next: Clock, Reset, and Power Contract

Up next

Up nextClock, Reset, and Power Contract

Sign in to save progress

Practice this lessonReport an error

See also

  • Interrupts and Events
  • FIFO and DMA Boundary
  • Errors and Integration Signoff