Modeling Best Practices: API Docs and Doxygen
How to comment SystemC modules, sockets, registers, CCI parameters, callbacks, and examples so generated docs help real users.
Modeling Best Practices: API Docs and Doxygen
A SystemC Virtual Platform is a software product. Like any software library, if the APIs are not documented, they are unusable. In SystemC, the "APIs" are your module constructors, TLM sockets, CCI parameters, and memory-mapped register contracts.
The industry standard for SystemC documentation is Doxygen. Doxygen comments should explain contracts and abstractions, not just repeat the C++ syntax.
What to Document
When distributing a SystemC IP block, the following elements MUST be documented:
- Module Abstraction Level: What does it model? (RTL, AT, LT/VP). What is intentionally left out?
- TLM Sockets: Which protocols do they support? Do they support DMI? What is the expected bus width?
- Registers: Base offsets, bitfields, reset values, and side-effects of reads/writes (e.g., "Reading this register clears the interrupt").
- CCI Parameters: Name, type, default value, and mutability rules.
- Report Message Types (
msg_type): The string IDs used inSC_REPORT_ERRORso the integrator knows what they can filter.
Doxygen Commenting Style
Use the standard Doxygen /** ... */ syntax.
Module and Abstraction Comment
/**
* @class Uart
* @brief Memory-mapped UART model for VP firmware bring-up.
*
* Models TX/RX FIFOs, status flags, and interrupt generation.
* @note Bit-level serial waveform timing is intentionally abstracted.
* Data is transferred instantaneously when the TX FIFO drains.
*/
class Uart : public sc_core::sc_module {TLM Socket Comment
/**
* @brief Target socket receiving memory-mapped register transactions.
*
* Supports standard TLM-2.0 b_transport. DMI is NOT supported for
* memory-mapped peripheral registers. Expected payload width is 32 bits.
*/
tlm_utils::simple_target_socket<Uart> target_socket{"target_socket"};CCI Parameter Comment
/**
* @brief Approximate per-byte transmit delay.
*
* Mutable during simulation. Changing this affects future bytes only.
* If set to SC_ZERO_TIME, the UART operates in zero-delay mode.
*/
cci::cci_param<sc_core::sc_time> tx_delay{"tx_delay", sc_core::sc_time(1, sc_core::SC_US)};Complete Example: A Fully Documented IP Block
This complete sc_main demonstrates how a professionally documented SystemC IP block should look. It includes Doxygen groupings, parameter documentation, and register definitions.
#include <systemc>
#include <iostream>
/**
* @defgroup vp_timer Timer IP Block
* @brief Abstract timer model for Loosely Timed (LT) Virtual Platforms.
* @{
*/
/**
* @class VpTimer
* @brief A 32-bit countdown timer with interrupt generation.
*
* This model uses SystemC SC_THREADs to abstract away clock cycles.
* It calculates the exact future time an interrupt should fire and waits
* for that duration, maximizing simulation speed.
*/
SC_MODULE(VpTimer) {
/**
* @brief Interrupt output signal.
* Active HIGH. Level-triggered.
*/
sc_core::sc_out<bool> irq_out{"irq_out"};
/**
* @name Register Offsets
* Memory map offsets relative to the module base address.
* @{
*/
static constexpr uint32_t REG_CTRL = 0x00; ///< Control register. Bit 0: Enable.
static constexpr uint32_t REG_LIMIT = 0x04; ///< Value to countdown from.
static constexpr uint32_t REG_ACK = 0x08; ///< Write any value to clear IRQ.
/** @} */
/**
* @brief Constructs the VpTimer.
* @param name The SystemC hierarchical name.
*/
SC_CTOR(VpTimer) {
SC_THREAD(timer_process);
}
private:
void timer_process() {
wait(10, sc_core::SC_NS); // Dummy logic for compilation
irq_out.write(true);
}
};
/** @} */ // End vp_timer group
int sc_main(int argc, char* argv[]) {
// Instantiate the documented IP block
sc_core::sc_signal<bool> irq_sig{"irq_sig"};
VpTimer timer("my_timer");
timer.irq_out(irq_sig);
std::cout << "Starting Simulation of Documented IP...\n";
sc_core::sc_start(1, sc_core::SC_US);
return 0;
}Explanation of the Execution
While running this code simply executes the dummy logic, running the doxygen tool against this source file will generate a professional HTML manual.
The generated documentation will group the VpTimer class, its irq_out port, and its register offsets into a cohesive "Timer IP Block" page. When a firmware engineer needs to write a driver for this VP, they will look at the Doxygen output to find that REG_ACK = 0x08 and that the IRQ is "Active HIGH, Level-triggered", completely eliminating guesswork.
Comments and Corrections