# IP-XACT register model
This example starts from a checked-in IP-XACT component rather than
SystemRDL. PeakRDL imports the standard IP-XACT memory map and the cpptb
exporter generates the same typed C++ RAL used by the other register examples.
The user does not author an intermediate `.rdl` file or check in generated C++.
The complete source is under `examples/ipxact_regfile/`:
```text
ipxact_regfile/
├── component.xml # authored IP-XACT contract
├── ipxact_regfile.sv # authored APB4 RTL
├── testbench.cpp # generated-model APB test
├── model_contract.cpp # simulator-free fake-master check
├── cpptb.toml
└── systemverilog/
└── ipxact_regfile_sv_tb.sv # matching direct-SV sequence
build/cpptb/ipxact_regfile/
├── generated/ipxact_regs.hpp # generated typed model
├── obj/ # C++ DPI simulator
└── systemverilog_obj/ # pure-SV simulator
```
## Author the contract
The checked-in `component.xml` uses IP-XACT 1685-2014. Its register address
block defines fields, an enum, and a four-element register array. A separate
native memory address block describes the scratchpad:
```xml
control
'h0
32
enable
0
1
read-write
scratchpad
'h100
'h40
32
memory
read-write
```
The example build runs the equivalent generation command:
```sh
uv run --frozen --extra peakrdl peakrdl cpptb \
examples/ipxact_regfile/component.xml \
-o build/cpptb/ipxact_regfile/generated/ipxact_regs.hpp \
--namespace ipxact_regs \
--rename peripheral
```
`--namespace` selects the C++ namespace. `--rename` selects the logical model
root used by descriptors and diagnostics, so paths read
`peripheral.registers.control` instead of inheriting the component and memory
map wrapper names. The XML filename and generated header name are independent.
## Use the generated hierarchy
The generated model preserves the IP-XACT address-block hierarchy. Ordinary
registers, register arrays, and memory all use typed handles:
```cpp
ipxact_regs::RegModel regs{test, master};
co_await regs.registers.control.write(0x5u);
regs.registers.control.enable.stage(1u);
regs.registers.control.mode.stage(
ipxact_regs::mode_enum_t::STREAM);
co_await regs.registers.control.update();
co_await regs.registers.threshold.at<2>().write(0x1234u);
constexpr std::array packet{
0x1122'3344u, 0xa5a5'5a5au, 0xcafe'babeu};
co_await regs.scratchpad.write(
4, std::span{packet});
```
The register array index is checked at compile time. The memory call writes
three words beginning at logical entry 4, which maps to absolute addresses
`0x110`, `0x114`, and `0x118`.
## Compare the executable sequence
The two benches issue the same APB4 transfers and both finish at 410 ns. The
C++ version uses the generated contract; the SV version spells out the
corresponding addresses and bus operations.
cpptb (C++ DPI)
```cpp
ipxact_regs::RegModel regs{test, master};
co_await regs.registers.control.write(0x5u);
const auto control = co_await regs.registers.control.read();
test.expect_eq("control readback", control.data, 0x5u);
regs.registers.control.mode.stage(
ipxact_regs::mode_enum_t::STREAM);
co_await regs.registers.control.update();
co_await regs.registers.threshold.at<2>().write(0x1234u);
co_await regs.scratchpad.write(4, packet);
co_await regs.scratchpad.read(4, readback);
test.expect_eq("scratchpad readback", readback, packet);
```
Pure SystemVerilog
```systemverilog
apb_write_word(9'h000, 32'h0000_0005);
apb_read_word(9'h000, data);
expect_eq("control readback", data, 32'h0000_0005);
// Combined enable/mode field update.
apb_write_word(9'h000, 32'h0000_0003);
apb_write_word(9'h028, 32'h0000_1234);
for (int unsigned index = 0; index < 3; index++)
apb_write_word(9'h110 + (index * 4), packet[index]);
for (int unsigned index = 0; index < 3; index++) begin
apb_read_word(9'h110 + (index * 4), data);
expect_eq("scratchpad readback", data, packet[index]);
end
```
Run the complete example from the repository root:
```sh
make cpptb-ipxact-regfile-model-test
make cpp-dpi-ipxact-regfile-run
make cpp-dpi-ipxact-regfile-sv-run
```
Or run `make test` inside `examples/ipxact_regfile/`.
## Compatibility boundary
cpptb accepts IP-XACT through the installed PeakRDL importer. Registers,
fields, arrays, standard access and reset properties, enumerated values, and
native memory address blocks all reach the generated model in this regression.
The checked-in example is regenerated, compiled against a fake master, and run
over APB in the normal test suite.
Vendor extensions are not automatically portable. PeakRDL must first map an
extension into SystemRDL semantics before the cpptb exporter can preserve it.
When a project depends on custom IP-XACT properties, add that mapping to the
import layer or keep a SystemRDL source contract; silently assuming an unknown
extension affected the model is not supported.
See [Register generation](../verification-components/register-generation.md)
for naming controls and [Memory and register models](../memory-register-models.md)
for the complete generated API.