Custom UART Integration with Fast Models in C++ Without sgcanvas
When designing and verifying ARM-based SoCs, engineers often need to integrate custom peripherals, such as a UART, with ARM Fast Models for simulation purposes. ARM Fast Models provide a high-performance, cycle-accurate simulation environment for ARM IP and SoCs. Typically, the sgcanvas
tool is used to create system diagrams and generate simulation executables using simgen
. However, in some cases, directly instantiating Fast Models components in C++ can be more efficient, especially when integrating custom models like a UART with Fast Models components such as TelnetTerminal
.
The challenge lies in understanding how to bypass the sgcanvas
and simgen
workflow to directly instantiate and connect Fast Models components in C++. This requires a deep understanding of the Fast Models API, the component interfaces, and the underlying mechanisms for data exchange between components. For example, integrating a custom UART model with a TelnetTerminal
component involves exposing a SerialData
port on the UART and connecting it to the corresponding port on the TelnetTerminal
. This approach avoids the overhead of creating a system diagram and allows for more flexible and dynamic simulation setups.
Fast Models API and Component Instantiation Challenges
The primary obstacle in directly using Fast Models in C++ is the complexity of the Fast Models API and the need to manually handle component instantiation, port connections, and simulation control. Fast Models components are designed to be used within the sgcanvas
environment, which automates much of the setup process. When bypassing sgcanvas
, engineers must manually replicate this setup in C++.
One of the key challenges is understanding the Fast Models API, which provides classes and methods for creating and managing components. Each Fast Models component, such as TelnetTerminal
, has a specific interface that must be instantiated and configured correctly. For example, the TelnetTerminal
component requires a SerialData
port to be connected for communication. Similarly, the custom UART model must expose a SerialData
port that matches the interface expected by the TelnetTerminal
.
Another challenge is managing the simulation lifecycle. In the sgcanvas
workflow, simgen
generates a simulation executable that handles initialization, execution, and termination of the simulation. When using Fast Models directly in C++, these steps must be implemented manually. This includes initializing the simulation environment, creating and connecting components, starting the simulation, and handling simulation events such as data transfer and synchronization.
Direct Instantiation and Simulation Control in C++
To integrate a custom UART model with Fast Models components directly in C++, engineers must follow a structured approach that includes component instantiation, port connection, and simulation control. The following steps outline the process:
Step 1: Include Fast Models Headers and Define Component Classes
The first step is to include the necessary Fast Models headers and define the component classes. For example, to use the TelnetTerminal
component, the pv::pv_TelnetTerminal
class must be included. Similarly, the custom UART model must be defined as a class that exposes a SerialData
port.
#include "pv/TelnetTerminal.h"
#include "pv/SerialData.h"
class CustomUART {
public:
pv::SerialData serialPort;
// UART implementation details
};
Step 2: Instantiate Components and Connect Ports
Next, instantiate the TelnetTerminal
and CustomUART
components and connect their SerialData
ports. This involves creating instances of the components and using the Fast Models API to bind the ports.
pv::pv_TelnetTerminal telnetTerminal("TelnetTerminal");
CustomUART customUART;
// Connect the SerialData ports
telnetTerminal.serialPort.bind(customUART.serialPort);
Step 3: Initialize and Start the Simulation
After connecting the ports, initialize the simulation environment and start the simulation. This includes setting up the simulation clock, initializing the components, and starting the simulation loop.
pv::sc_core::sc_start(0, pv::sc_core::SC_NS); // Initialize simulation time
telnetTerminal.init();
customUART.init();
pv::sc_core::sc_start(1000, pv::sc_core::SC_MS); // Run simulation for 1000 milliseconds
Step 4: Handle Simulation Events and Data Transfer
During the simulation, handle events such as data transfer between the TelnetTerminal
and CustomUART
. This may involve implementing callbacks or event handlers to process incoming and outgoing data.
void handleSerialData() {
// Process data received from TelnetTerminal
uint8_t data = customUART.serialPort.read();
// Process data and send response if necessary
customUART.serialPort.write(data);
}
Step 5: Terminate the Simulation
Finally, terminate the simulation and clean up resources. This includes stopping the simulation loop and releasing any allocated resources.
pv::sc_core::sc_stop(); // Stop the simulation
// Clean up resources
By following these steps, engineers can successfully integrate custom UART models with Fast Models components directly in C++ without relying on sgcanvas
or simgen
. This approach provides greater flexibility and control over the simulation setup, enabling more efficient development and verification of ARM-based SoCs.