Jan 31, 2014

Correct way of Digital design RTL Coding

  • Why Synthesis Tools Fail: A Practical Guide to Writing Efficient RTL
  • Efficient RTL Coding Guidelines - RTL Digital Design

    What is the efficient way to code the RTL ?

    Many digital designers think the code they have written will be optimized by synthesis tools (Design Compiler or RTL Compiler) and expect the tool to understand the logic and produce efficient hardware automatically.

    This may be true sometimes, but there is uncertainty about how a tool will optimize the RTL code. The tool understands the logic and tries to optimize it, but there are chances that the synthesis tool may actually screw up the design instead of improving it. Some guidelines are given below to avoid such scenarios.

    Golden Rule: RTL coding is not just about functional correctness. It is about describing the hardware you have already envisioned in your mind, in a way the synthesis tool can map cleanly to gates, flops, and muxes — without guessing your intent.

    Why "Trust the Tool Blindly" Fails

    Synthesis tools are extremely good at local optimizations — Boolean minimization, technology mapping, retiming within constraints, and resource sharing when the code clearly implies it. But they are not architects. If your RTL is ambiguous, tools will pick "a" legal interpretation — not necessarily the one you intended.

    Designer's Intent Tool's Interpretation +------------------+ +------------------------+ | "I want a | RTL | Tool sees behavioral | | 3-stage | --------> | code, picks its own | | pipeline mux" | | latch/mux structure | +------------------+ +------------------------+ | | v v Efficient, predictable Possibly bloated / mismatched hardware timing, extra muxes, glitches

    Steps to Design Micro-Architecture of Efficient Hardware

    1. Collect all requirements, IO specification and timing diagrams.
    This is your complete set of inputs. Missing even one corner-case signal behavior (like reset polarity, back-to-back transaction handling, or clock domain relationships) leads to re-spins later.
    2. Go for a top-to-down approach — start with the top level block diagram.
    +----------------------------+ | TOP MODULE | | | | +--------+ +---------+ | | | Block A|-->| Block B | | | +--------+ +---------+ | | \ | | | v v | | +--------------+ | | | Block C | | | +--------------+ | +----------------------------+
    3. Prepare the data-flow for the design block.
    Identify where data is generated, transformed, and consumed. This helps decide pipeline stages, buffering, and where flops are truly needed.
    4. Freeze the specification.
    At this point specification must be clear. If there are doubts, consult the relevant stakeholder and get it clarified. Any assumption made must be clearly documented in the design spec — undocumented assumptions are the #1 cause of verification escapes.
    5. Identify common functionality across blocks and share hardware.
    Don't duplicate arbiters, CRC generators, FIFOs, or comparators. Build one well-verified shared block and reuse it — this reduces area and verification effort.
    Block A ---\ >---- Shared Comparator Logic ----> Result Block B ---/
    6. Design a central FSM to control all the blocks.
    A single, well-documented control FSM is easier to verify, debug, and modify than scattered local state machines with implicit dependencies.
    +-------------------+ | Central FSM | +-------------------+ / | \ v v v Block A ctrl Block B ctrl Block C ctrl
    7. Flop all inputs/outputs of blocks (if latency is not a constraint).
    This isolates combinational paths inside each block, making timing closure predictable and STA analysis clean at block boundaries.
    8. In multi-clock domain designs, isolate logic per clock domain and use a single, standardized synchronizer module for all CDC signals.
    Many companies maintain their own hardened synchronizer cells in their library. Using ONE synchronizer module company-wide makes CDC signoff (via tools like Spyglass/Meridian) far easier and more consistent.
    Clock Domain A Clock Domain B +-------------+ +----------+ +-------------+ | Logic A |---->| SYNC |--->| Logic B | +-------------+ | Module | +-------------+ +----------+ (Same sync module used everywhere)
    9. Mix coding styles — don't rely purely on behavioral coding.
    Writing behavioral logic is easy — almost anyone can describe functionality using if-else or case. But truly efficient RTL uses a deliberate mix of behavioral and structural styles depending on what hardware you want.
    10. Before writing code, be clear on the logic — try to visualize it in terms of gates first.
    If you can sketch the AND-OR-MUX structure on paper, converting it to RTL becomes a translation exercise rather than a guessing game for the synthesis tool.
    11. Break the design into a mix of structural and behavioral code so that you effectively "hint" the synthesis tool about the intended hardware, instead of leaving everything to its discretion.
    12. Review synthesis attributes carefully — decide what part of the design needs dont_touch, dont_size, size_only, or specific mapping constraints.

    Behavioral vs Structural vs Mixed Coding Style

    Coding Style Description Pros Cons
    Behavioral Describes functionality using high-level constructs (if-else, case, for loops) Fast to write, easy to read/verify Tool decides hardware — may not match designer's intended structure
    Structural Explicit instantiation of gates/muxes/flops Predictable hardware, precise control over timing/area Verbose, harder to maintain, less portable
    Mixed (Recommended) Critical/timing-sensitive paths coded structurally; control and less-critical logic coded behaviorally Best of both worlds — efficient hardware + maintainability Requires experienced designer to judge where to mix

    2 comments:

    SiteMap