Skip to content
VLSI Mentor

C Part II · Module 20 · DPI-C Type Mapping

The DPI Header: svdpi.h

The standard specifies a header that every simulator ships, and the useful question about it is not what is inside but when you need it at all. A function taking only scalar types compiles with no DPI header anywhere — measured, sanitiser-clean, with the include absent — and the moment a declaration mentions a packed vector, a four-state value or an open array, the header becomes the only place those names exist. This chapter is that line, and the hazard on the wrong side of it: a hand-written stand-in for one of those types compiles perfectly and is a guess at somebody else's layout.

Advanced20 min readCPart IIVerificationDPI-C

Part II · Module 20 · Chapter 20.2 · The DPI Header: svdpi.h

1. A Note on What This Chapter Can Check

svdpi.h does not exist on this machine. Chapter 19.1 §4 reported it and it was verified again for this chapter — nothing under /opt/homebrew, /usr/local or /usr/include. There is no copy here to read.

So everything this chapter says about the header's contents is from the LRM — the SystemVerilog standard specifies the header, its type names and its functions, and that specification is the source.

What is measurable is the thing the chapter's purpose actually asks for: "know which types and functions come from it rather than from your own code." That is a question about which names a translation unit defines, and it can be answered with a compiler and no simulator at all. §3 and §5 do exactly that.

2. What the Header Is For

From the LRM: svdpi.h is a header the standard defines and every simulator provides, and it supplies three kinds of thing.

Type names for SystemVerilog values that C has no type for. svBit and svLogic for single-bit values, svBitVecVal and svLogicVecVal for packed vectors, svScalar and svLogicVal for the four-state constants, svOpenArrayHandle for an open array, and svScope for a SystemVerilog scope.

Functions for reaching into those values. Accessors that read and write individual bits of a packed vector, functions that report an open array's dimensions and element size, and functions that convert between representations.

Functions for the simulation context. svGetScope, svSetScope and relatives — the machinery Chapter 19.5 §4 named as requiring a context import.

What it is not is a general-purpose library. It exists for the values and the context, and a DPI function that needs neither needs nothing from it.

3. When You Do Not Need It

This is the measurable half, and it is the more useful half because it covers most functions.

Chapter 19.4's complete import:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
#include <stdint.h>

uint8_t c_crc8(const uint8_t *data, int len) {
    unsigned c = 0u;
    for (int i = 0; i < len; i++) {
        c ^= (unsigned)data[i];
        for (int b = 0; b < 8; b++)
            c = (c & 0x80u) ? (((c << 1) ^ 0x07u) & 0xFFu) : ((c << 1) & 0xFFu);
    }
    return (uint8_t)c;
}

Measured: that compiles with -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion, runs clean under AddressSanitizer and UndefinedBehaviorSanitizer, produces the published check value 0xF4, and contains no DPI header. Chapter 19.2 §3 established the general property and this is it in practice.

The rule, which §4 states precisely: scalar arguments need no header. byte, shortint, int, longint, real, shortreal and chandle all map onto types C already has — Chapter 20.1 §4 measured them — so the C side is ordinary C.

That covers a large fraction of real imports: a checksum, an encoder, a decoder, a lookup, an expected-value computation. Chapter 19.1 §3 made the point and it bears repeating because it is the reason most DPI C is easy: the common case needs nothing special.

4. The Line

No header: scalar types only — byte, shortint, int, longint, real, shortreal, chandle.

Header required: anything packed, four-state, open-array, or scope-aware.

Crossing that line is what Chapters 20.5, 20.6, 20.10 and Module 21 are about. The four triggers:

A packed vector wider than the scalar types, which arrives as svBitVecVal * or svLogicVecVal * — Chapter 20.6.

Any four-state value, because the two-word representation needs names for its parts — Chapter 20.5.

An open array, whose dimensions are not known at compile time and must be queried — Module 21's subject.

Anything that needs the calling scope, which is Chapter 19.5's context and its svScope machinery.

Applying the line is a one-line check on a declaration: if every argument and the return type is a scalar, the C needs no DPI header.

5. The Hazard: Writing Your Own

Here is what makes this chapter worth more than a list of names.

Suppose a declaration needs svBitVecVal and the header is missing, or the build cannot find it, or you are writing the C before the simulator is available. The compiler says so:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
error: unknown type name 'svBitVecVal'

Measured — that is the actual diagnostic, and it is the helpful case. The unhelpful case is the fix people reach for:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
typedef uint32_t svBitVecVal;    /* "it is a 32-bit chunk, surely" */

Measured: that compiles perfectly. No warning, no error, a clean build under the full flag set.

And it is a guess at another program's layout. The typedef satisfies your compiler, which has no way to check it against the simulator — the simulator is not a translation unit your compiler can see. Chapter 19.6 §4 made the same structural point about an exported symbol: one side of the agreement is not a C translation unit, so C's usual checking does not reach it.

Chapter 16.8's categories apply exactly. A locally-invented svBitVecVal that happens to match is observed, not guaranteed — it works on this simulator, this version, this target, and the failure when it stops is a packed value that is wrong in a structured way rather than a build error.

6. The Misconception: If It Compiles, the Types Are Right

"The C compiles against the DPI declaration, so the types must match."

Your compiler checked your C against itself. It did not check it against the simulator, because the simulator is not part of the translation.

Three things that compile and can be wrong, all measured or established earlier in this module:

A hand-written svBitVecVal. §5 — compiles clean, and is a guess at a layout.

A signedness mismatch. Chapter 20.1 §2 measured 0x80 reading as -128 or 128 depending on the declaration. Both C functions compile; one disagrees with the SystemVerilog side.

A width that happens to match here. Chapter 20.1 §4 measured long as 8 bytes on this machine, which is why the standard maps longint to long long. Writing long compiles and is wrong on targets where it is 4.

What catches all three is not the compiler:

The declaration is the contract, and it lives in the SystemVerilog file. The C compiler cannot see it. Write the mapping down beside the C, and test at the top of each type's range.

That is Chapter 16.8 §7's habit — put the promise next to the code — and Chapter 20.1 §7's instruction, arriving here as the specific defence against a header you cannot verify locally.

7. What You Should Be Able to Say Now

  1. svdpi.h is specified by the standard and shipped by every simulator. It does not exist on this machine, so this chapter's account of its contents is from the LRM.
  2. It supplies three kinds of thing: type names for values C has no type for, accessors for those values, and the scope machinery context imports use.
  3. It is not a general-purpose library. A function needing neither special values nor the context needs nothing from it.
  4. Scalar arguments need no header. Measured: Chapter 19.4's complete import compiles and runs sanitiser-clean with the include absent.
  5. The line: no header for byte, shortint, int, longint, real, shortreal, chandle; header required for packed, four-state, open-array or scope-aware.
  6. Applying it is a one-line check on the declaration — are all the argument and return types scalar?
  7. A missing header gives a clear error — measured: unknown type name 'svBitVecVal'.
  8. The dangerous fix compiles. Measured: typedef uint32_t svBitVecVal; builds clean under the full flag set and is a guess at another program's layout — Chapter 16.8's observed, not guaranteed.
  9. Confine the header to a thin adapter and keep the model in ordinary C, so it stays standalone-testable (19.2 §5).
  10. If it compiles, that proves nothing about the other side. The contract is in the SystemVerilog file, which your compiler cannot see.

8. Exercises

  1. Compile Chapter 19.4's CRC import and confirm it needs no DPI header. Then list every argument type in it and check each against §4's line.
  2. Write a C function using svBitVecVal without the header and record the exact error. Then add the typedef from §5 and confirm it compiles — and say what you have actually established by that.
  3. Take three DPI declarations you have seen. For each, apply §4's one-line check and say whether the C needs the header.
  4. Write the adapter split from §5's callout for a function taking a packed vector: a model function in ordinary C and an adapter that would include the header.
  5. Add the #error guard from §5's callout to a file and confirm it fires. Compare the message with the unknown type name error — which would you rather receive?
  6. §6 lists three things that compile and can be wrong. For each, say what would have caught it: a compiler, a test, a review, or a document.
  7. If your machine has a simulator, find svdpi.h and read its type declarations. Compare svBitVecVal's definition with what Chapter 20.6 derives from the standard.

9. Summary

  • svdpi.h is standard-specified and simulator-shipped. It is absent here, so its contents are reported from the LRM.
  • Three kinds of content: types C lacks, accessors for them, and the scope machinery.
  • Scalar arguments need no header — measured: a complete import, sanitiser-clean, include absent.
  • The line: scalars without; packed, four-state, open-array or scope-aware with.
  • A missing header errors clearly — measured unknown type name 'svBitVecVal'.
  • The dangerous fix compiles silently — a hand-written typedef is a guess at another program's layout (16.8).
  • Confine the header to a thin adapter; keep the model standalone-testable.
  • Compiling proves nothing about the other side — the contract is in a file your compiler never sees.

The line in §4 puts the scalar types on the easy side, and Chapter 20.1 measured their sizes agreeing with the mapping. What it did not examine is the set of assumptions sitting inside each of those obvious-looking choices — one of which is already visible in the fact that the standard declined to use the most natural-looking C type for the widest of them.

Standards & specifications

Governing standard
IEEE Std 1800 (SystemVerilog)(opens IEEE in a new tab)

Defines SystemVerilog language semantics — syntax, data types, scheduling and the behaviour a conforming simulator must produce. It does not define tool-specific synthesis support or vendor methodology.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the C Programming curriculum.