From rtl-agent-team
Enforces SystemC/TLM-2.0 coding standards for BFM and Reference Model development in C++17. Covers AT/LT patterns, AMBA-PV extensions, naming conventions, testbench integration.
npx claudepluginhub babyworm/rtl-agent-team --plugin rtl-agent-teamThis skill uses the workspace's default tool permissions.
<Purpose>
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
Target standard: C++17 (-std=c++17).
-std=c++17
<Use_When>
<Do_Not_Use_When>
systemverilog skillrtl-p5s-func-verify skill
</Do_Not_Use_When><Why_This_Exists> BFMs and Reference Models are the golden reference for RTL verification. Following consistent coding standards and TLM-2.0 patterns ensures:
<Execution_Policy>
templates/tlm2-module-template.cpp as the starting point for new modulesexamples/bfm-at-pattern.cpp for AT BFM implementation patternsexamples/bfm-pattern.cpp for LT-style BFM implementation patterns (for simple register access)
</Execution_Policy>| Type | Pattern | Example |
|---|---|---|
| Reference Model | ref_{module}.c / .h | ref_cabac.c |
| BFM | bfm_{module}.cpp / .h | bfm_axi_master.cpp |
| TLM Adapter | tlm_{module}_adapter.cpp | tlm_cabac_adapter.cpp |
| Memory Manager | memory_manager.h | memory_manager.h |
| DPI-C Interface | dpi_{module}.cpp / .h | dpi_interface.cpp |
| Testbench Top | tb_{module}_top.cpp | tb_cabac_top.cpp |
| Package (shared types) | {module}_types.h | cabac_types.h |
| Target | Rule | Example |
|---|---|---|
| SC_MODULE | snake_case | cabac_encoder_bfm |
| Reference Model class | {module}_ref_model | cabac_ref_model |
| BFM class | {module}_bfm | axi_master_bfm |
| TLM Socket | {role}_{protocol}_socket | init_axi_socket, targ_mem_socket |
| Member variables | m_ prefix | m_state, m_ctx_table |
| Constants | UPPER_SNAKE_CASE | MAX_CTX_ENTRIES |
SystemC ports use the same names as their RTL counterparts:
sc_in<sc_uint<8>> i_data{"i_data"};
sc_out<bool> o_valid{"o_valid"};
sc_in<bool> sys_clk{"sys_clk"}; // clock: no i_/o_ prefix
sc_in<bool> sys_rst_n{"sys_rst_n"}; // reset: no i_/o_ prefix
class cabac_ref_model {
public:
static uint32_t encode_bin(uint16_t ctx_addr, bool bin_val,
const ctx_table_t& ctx_table);
void process_block(const block_input_t& input, block_output_t& output);
void reset();
private:
ctx_table_t m_ctx_table;
};
int16_t, uint32_t (no int, no float)// CORRECT: bit-exact fixed-point multiply
int32_t fixed_mul(int16_t a, int16_t b) {
return static_cast<int32_t>(a) * static_cast<int32_t>(b);
}
// WRONG: implicit promotion may differ from RTL
int result = a * b; // 'int' width is platform-dependent
nb_transport_fw/bw() (LT only when explicitly requested)| Style | Interface | Use Case |
|---|---|---|
| AT (Approximately Timed) | nb_transport_fw/bw() | DEFAULT. Timing-accurate, pipelined, OoO |
| LT (Loosely Timed) | b_transport() | Fast simulation, simple register access only |
Initiator Target
|-------- BEGIN_REQ ------->|
|<------- END_REQ ----------|
|<------- BEGIN_RESP -------|
|-------- END_RESP -------->|
#include <systemc>
#include <tlm>
#include <tlm_utils/simple_initiator_socket.h>
#include <tlm_utils/simple_target_socket.h>
#include <tlm_utils/peq_with_cb_and_phase.h> // AT phase scheduling
// #include <amba_pv.h> // AMBA protocol extensions (when needed)
┌────────────┐ AT nb_transport ┌────────────┐
│ Testbench │◄──── fw/bw ─────►│ BFM │
│ (Initiator)│ │(Cycle-acc.)│
└────────────┘ └─────┬─────┘
│ Pin Adapter
┌──────▼──────┐
│ RTL Wrapper │ (optional)
│ (sc_signal) │──► DPI-C ──► SV TB
└─────────────┘
Required component for payload reuse in AT models:
class MemoryManager : public tlm::tlm_mm_interface {
public:
tlm::tlm_generic_payload* allocate() {
if (m_pool.empty()) return new tlm::tlm_generic_payload(this);
auto* p = m_pool.back(); m_pool.pop_back(); return p;
}
void free(tlm::tlm_generic_payload* p) override {
p->reset(); m_pool.push_back(p);
}
~MemoryManager() override { for (auto* p : m_pool) delete p; }
private:
std::vector<tlm::tlm_generic_payload*> m_pool;
};
Usage: m_mm.allocate() → trans->acquire() → ... → trans->release()
| Protocol | When to Use |
|---|---|
| AXI | DEFAULT. High-performance, burst, out-of-order |
| AHB | Legacy interconnect, in-order |
| APB | Low-bandwidth peripherals, register access |
| ACE | ONLY when cache coherency is explicitly required |
Default AXI extension setup:
#include <amba_pv.h>
auto* ext = new amba_pv::axi_extension();
ext->set_id(0);
ext->set_burst(amba_pv::AXI_BURST_INCR); // Incrementing (most common)
ext->set_length(burst_len); // AxLEN (beats - 1)
ext->set_size(log2(beat_size)); // AxSIZE
ext->set_cache(0xF); // Write-back, allocate
ext->set_prot(0x0); // Unprivileged, secure, data
trans.set_extension(ext);
See the
<Advanced>section for AHB/APB/ACE details and AXI attribute tables.
# Reference Model (standalone C, no SystemC)
gcc -std=c11 -O2 -Wall -Wextra -Werror -shared -fPIC -o ref_cabac.so ref_cabac.c
# BFM (SystemC required)
g++ -std=c++17 -O2 -Wall -Wextra \
-I${SYSTEMC_HOME}/include -L${SYSTEMC_HOME}/lib-linux64 -lsystemc \
-o tb_cabac tb_cabac_top.cpp bfm_cabac.cpp
# cocotb integration (shared library, C ref model)
gcc -std=c11 -shared -fPIC -o ref_cabac.so ref_cabac.c
cocotb integration:
import ctypes
lib = ctypes.CDLL("./ref_cabac.so")
lib.encode_bin.restype = ctypes.c_uint32
lib.encode_bin.argtypes = [ctypes.c_uint16, ctypes.c_bool]
expected = lib.encode_bin(ctx_addr, bin_val)
<cstdint>), RAII, const, Header guardfloat/double in bit-exact modelsmalloc/free, platform-dependent intusing namespace std; in headersb_transport in performance BFMs (use AT)<Tool_Usage> This skill is not executed directly. It is referenced by agents that generate SystemC code (e.g., bfm-dev, ref-model-dev). Agents should follow the conventions defined here. </Tool_Usage>
AT non-blocking BFM with AXI extension and memory manager: ```cpp void axi_master_bfm::run() { tlm::tlm_generic_payload* trans = m_mm.allocate(); trans->acquire(); // ... setup payload + AXI extension ... tlm::tlm_phase phase = tlm::BEGIN_REQ; sc_core::sc_time delay = sc_core::SC_ZERO_TIME; init_socket->nb_transport_fw(*trans, phase, delay); // ... handle END_REQ, BEGIN_RESP, END_RESP via PEQ ... trans->release(); } ``` Bit-exact ref model with fixed-width integers: ```cpp int32_t cabac_ref_model::encode_bin(uint16_t ctx_addr, bool bin_val) { uint16_t range = m_ctx_table[ctx_addr].range; uint16_t lps = static_cast((range >> 6) & 0x03); // ... bit-exact operations } ``` Float, platform-dependent int, LT in performance BFM: ```cpp float encode_result = ctx_range * 0.5f; // WRONG: float in bit-exact model int lps = range >> 6; // WRONG: 'int' is platform-dependent ```<Escalation_And_Stop_Conditions>
<Final_Checklist>
ref_ / bfm_ / tlm_ / dpi_ prefixint32_t etc., no int/float)i_data, o_valid, sys_clk)m_ prefix for member variables| Type | Value | Description |
|---|---|---|
AXI_BURST_FIXED | 0 | Fixed address (FIFO access) |
AXI_BURST_INCR | 1 | Incrementing address (DEFAULT) |
AXI_BURST_WRAP | 2 | Wrapping burst (cache line) |
0x0: Non-cacheable, non-bufferable (device)0x3: Cacheable, bufferable, no allocate0xF: Write-back, read/write allocate (normal memory)| Code | Description |
|---|---|
AXI_RESP_OKAY | Success |
AXI_RESP_EXOKAY | Exclusive access success |
AXI_RESP_SLVERR | Slave error |
AXI_RESP_DECERR | Decode error (no slave at address) |
auto* ahb_ext = new amba_pv::ahb_extension();
ahb_ext->set_trans(amba_pv::AHB_TRANS_NONSEQ);
ahb_ext->set_burst(amba_pv::AHB_BURST_SINGLE);
ahb_ext->set_size(2); // 4 bytes (2^2)
ahb_ext->set_prot(0x0);
ahb_ext->set_master(0);
trans.set_extension(ahb_ext);
Transfer types: AHB_TRANS_IDLE (0), AHB_TRANS_BUSY (1), AHB_TRANS_NONSEQ (2), AHB_TRANS_SEQ (3)
Burst types: SINGLE, INCR, WRAP4, INCR4, WRAP8, INCR8, WRAP16, INCR16
auto* apb_ext = new amba_pv::apb_extension();
apb_ext->set_prot(0x0);
trans.set_extension(apb_ext);
APB: Single 32-bit transfers only, in-order, 2-phase (SETUP + ACCESS).
Use ACE only when cache coherency is explicitly required:
auto* ace_ext = new amba_pv::ace_extension();
ace_ext->set_domain(amba_pv::ACE_DOMAIN_INNER_SHAREABLE);
ace_ext->set_snoop(amba_pv::ACE_SNOOP_READ_SHARED);
ace_ext->set_barrier(amba_pv::ACE_BARRIER_NORMAL);
ace_ext->set_burst(amba_pv::AXI_BURST_INCR);
ace_ext->set_cache(0xF);
trans.set_extension(ace_ext);
Domain types: NON_SHAREABLE, INNER_SHAREABLE, OUTER_SHAREABLE, SYSTEM
Use only when SystemVerilog co-simulation is needed.
// dpi_interface.h
#ifdef __cplusplus
extern "C" {
#endif
void dpi_sc_init();
void dpi_sc_run(uint64_t time_ps);
void dpi_sc_finish();
int dpi_axi_write(uint64_t addr, const unsigned char* data, unsigned int len);
int dpi_axi_read(uint64_t addr, unsigned char* data, unsigned int len);
extern void sv_notify_completion(int trans_id, int status);
#ifdef __cplusplus
}
#endif
module tb_dpi_cosim;
import "DPI-C" function void dpi_sc_init();
import "DPI-C" function void dpi_sc_run(longint unsigned time_ps);
import "DPI-C" function void dpi_sc_finish();
import "DPI-C" function int dpi_axi_write(
longint unsigned addr, input byte unsigned data[], int unsigned len);
export "DPI-C" function sv_notify_completion;
function void sv_notify_completion(int trans_id, int status);
$display("Transaction %0d completed with status %0d", trans_id, status);
endfunction
initial begin
dpi_sc_init();
dpi_sc_run(100_000); // 100ns
// ... transactions ...
dpi_sc_finish();
$finish;
end
endmodule
Use LT only for simple register access (APB/AXI-Lite) or fast SW simulation:
void my_bfm::b_transport(tlm::tlm_generic_payload& trans, sc_time& delay) {
if (trans.get_command() == tlm::TLM_WRITE_COMMAND) {
std::memcpy(&m_memory[addr], data, len);
trans.set_response_status(tlm::TLM_OK_RESPONSE);
} else if (trans.get_command() == tlm::TLM_READ_COMMAND) {
std::memcpy(data, &m_memory[addr], len);
trans.set_response_status(tlm::TLM_OK_RESPONSE);
}
delay += sc_time(m_latency_cycles * m_clk_period_ns, SC_NS);
}
# BFM with AMBA-PV headers
g++ -std=c++17 -O2 -Wall -Wextra \
-I${SYSTEMC_HOME}/include -I${AMBA_PV_HOME}/include \
-L${SYSTEMC_HOME}/lib-linux64 -lsystemc \
-o tb_axi tb_axi_top.cpp bfm_axi_master.cpp
| Category | Forbidden | Correct |
|---|---|---|
| Protocol | LT when AT is specified | Use nb_transport_fw/bw |
| Protocol | ACE when simple AXI suffices | Use AXI by default |
| Timing | Magic numbers: wait(2.0, SC_NS) | Derive from timing_constraints.json |
| Memory | No memory manager for pooled payloads | Use tlm_mm_interface + acquire/release |
| Extensions | Leaking extension memory | Call p->reset() in MemoryManager::free() |
| Phases | Missing phase transitions in AT | Implement all 4 phases with PEQ |
| Verification | Model without testbench | Every model needs sc_main testbench |
| DPI | Blocking calls that deadlock | Queue to SC_THREAD for async handling |
| Response | Missing set_response_status() | Always set before returning |