| Backward | Up | Forward |
|---|
This section presents the principle functions of the SMI library; initializing the hardware simulation, test processes and model instance communications; communicating messages between hardware and software model instances; and terminating the hardware simulation and test processes.
To begin a simulation using SMI models, both the hardware simulation and the test processes need to be run. These processes are typically started from a UNIX command script which invokes the executables. The arguments provided to the executables are used to specify the method of inter-process communication and to provide any additional parameters required by that method. Once running, these processes are now ready to initialize inter-process communication and model instances. A model instance is initialized by establishing a link between the hardware model instance and the software model instance that together implement the model instance.
Each test process executes a three stage initialization procedure:
The hardware simulation contains hardware model instances that each perform a single initialization operation:
Each test process establishes a communications channel with the hardware simulation by using the SMI_Channel::initial() method. The test process's command line arguments are passed as parameters. The hardware simulation establishes a communications channel with test processes as part of the $smi_initial() task call.
Software model instances are objects constructed from classes that inherit from the SMI_Model base class. These objects can be created on the stack or on the heap. For a software model instance to be linked with the corresponding hardware model instance, each software model instance must be registered with SMI. Software model instances either register themselves in their constructors or they can be registered after they have been constructed. The method SMI_Channel::add() registers a software model instance with SMI and associates it with a pair of strings that uniquely identify the model instance. The strings must match the strings supplied to $smi_initial() in the instantiation of the model in the hardware simulation.
Prototype objects are constructed from classes that inherit from the SMI_Prototype base class which in turn inherits from the SMI_Model base class. These objects can be created on the stack or on the heap. For a prototype object to be used by SMI to create software model instances, it must be registered with SMI. Prototype objects either register themselves in their constructors or they can be registered after they have been constructed. The method SMI_Channel::add() registers a prototype object with SMI and associates it with a string the uniquely identifies the type of model instances it can generate. The string must match the model type string supplied to $smi_initial() in the instantiation of models in the hardware simulation.
Finally, after all the software model instances and prototypes supported by a test process have been created and registered with SMI, they must be advertised to the hardware simulation. The method SMI_Channel::post() sends a list of all the software model instances and prototypes to the hardware simulation where the pairs of strings that uniquely identify each model instance and single string that uniquely identify each prototype are stored in a database. After advertising it's software model instances and prototypes, the test process is ready to perform message communication with the hardware simulation by calling the SMI_Channel::wait() method.
Each hardware model instance must be initialized must be initialized using the $smi_initial() task. A pair of strings that uniquely identify the model instance are passed as arguments, the model type and an instance name (the scope is used if the instance name argument is missing). This task begins by searching the internal database of model instances and prototypes to see if it contains the software model instance associated with the pair of strings or the prototype associated with the model type. If so, the task links the hardware and software model instances, generating a new software model instance from the prototype if necessary, and the model instance is initialized. If not, the task waits for a test process to connect to the hardware simulation. Each test process connecting to the hardware simulation provides a list of software model instances and prototypes it supports which are added to the database. After each new test process has connected, the database is scanned once more to see if it contains the software model instance or a matching prototype. If so, the task links the hardware and software model instances, generating new software model instances where necessary and the model instance is initialized. If not, the task waits for a test process to connect to the hardware simulation and the loop repeats. Once the model instance has been initialized, the hardware model instance is ready to perform message communication with the software model instance.
For example, the instantiation of the following module creates a hardware model instance:
module MyModel (...)
integer id;
initial
$smi_initial(id, "MyModel", "MyInstance");
...
endmodule
that corresponds to the software model instance created by the following test
process code:
class MyModel: public SMI_Model { ... };
int
main(int argc, char** argv)
{
// INITIALIZE SMI
SMI_Channel* channel = SMI_Channel::initial(argc, argv);
// CREATE A SOFTWARE MODEL INSTANCE
MyModel my_model;
// REGISTER THE SOFTWARE MODEL INSTANCE WITH SMI
channel->add("MyInstance", "MyModel", &my_model);
// ADVERTISE MODEL TO THE HARDWARE SIMULATION
channel->post();
...
}
or using a prototype
class MyPrototype: public SMI_Prototype { ... };
int
main(int argc, char** argv)
{
// INITIALIZE SMI
SMI_Channel* channel = SMI_Channel::initial(argc, argv);
// CREATE A PROTOTYPE OBJECT
MyPrototype my_prototype;
// REGISTER THE PROTOTYPE WITH SMI
channel->add("MyModel", &my_model);
// ADVERTISE PROTOTYPE TO THE HARDWARE SIMULATION
channel->post();
...
}
A model instance is implemented in two parts, a hardware model instance and a software model instance. The two parts cooperate to produce the required functionality. However, this is not a partnership of equals. The software model instance assists the hardware model instance rather then the other way round. The hardware model instance sends messages to the software model instance which may or may not require a reply. The software model instance may only send a message to the hardware model instance in response to a message that requires a reply. The software model instance may not initiate message transfer.
The set of messages sent from the hardware model instance to the software model instance and the set of reply messages sent back form a message protocol for the model. The messages themselves are lists of simulation values, e.g. reg, wire, integer values, that can be converted into an equivalent representation in the test process.
A hardware model instance performs the following sequence of operations to send a message and receive a reply from its corresponding software model instance:
The test process performs the following sequence of operations for one of its software model instances to receive and reply to a message from its corresponding hardware model instance:
When the hardware simulation reaches a $smi_write() or a $smi_read() task, the hardware model instance sends a message to the software model instance. The message contains a representation of the simulation values passed as arguments to the $smi_write() and $smi_read() tasks. If these tasks have arguments numbered 0 through N, then argument 0 is the model instance identifier. For $smi_write(), the message contains the values of the arguments numbered 1 through N and no reply is expected. For $smi_read(), the message contains values of the arguments numbered 1 through N-1. A reply is expected where the first value in the reply will be used to set argument N of the $smi_read() task.
The message received by the software model instance is contained in an SMI_RxMessage object. The SMI_RxMessage object provides a container for the list of values transmitted by the hardware model instance to the software model instance. Messages are processed by the SMI_Model::process() method of the object implementing the software model instance. This method has a single argument, a reference to the SMI_RxMessage object containing the incoming message. The values contained in a SMI_RxMessage object may represent the following Verilog types: real, integer, string, signal (wire and reg). Methods are provided to access these values. A method returns the number of values stored in the message. It is the users responsibility to ensure that the access method used is appropriate for the type of value being read. No mechanism has been provided for determining the type of a value before it is read. It is also the users responsibility to ensure that a reply, in the form of a SMI_TxMessage object, is returned by SMI_Model::process() whenever necessary. No mechanism has been provided for determining whether a reply is required. Typically, the user sets the first value in the SMI_RxMessage message to be of a fixed type for all messages accepted by the model. Its value specifies the types of the values that follow it and, if a reply is expected, the types of values in the reply.
The SMI_TxMessage object provides a container for a list of values to be transmitted from the software model instance back to the corresponding hardware model instance. The values contained in a SMI_TxMessage object may represent the following Verilog types; real, integer and signal (reg only). Methods are provided to allow values to be stored by appending additional values to the list. A method returns the number of values currently stored in the list. From the software model instances perspective, a SMI_TxMessage object is a write only structure, so values may not be read back or deleted after they have been appended to the object (except by deleting the object). SMI will delete all the values stored within the object after they have been transmitted to the hardware simulation. The software model instance replies to the hardware model instance by returning a pointer to a SMI_TxMessage object containing the reply as the return value from the SMI_Model::process() method.
Once the hardware model instance receives the reply, it sets the last argument of the $smi_read() task to the value of the first element in the reply. The remaining list of values are saved, so that subsequent calls to the $smi_data() task can be used to set simulation values from the remaining elements in the list. It is the users responsibility to ensure that the types of the values stored in the reply match the types of simulation values assigned by $smi_read() and $smi_data() task calls. After the contents of a SMI_TxMessage object have been transmitted to the hardware simulation, the contents of the object are cleared, i.e. the length becomes zero. This SMI_TxMessage object may now be used to construct a new message.
For example, given the task call:
$smi_read(id, 3.14, "hello", 4'b01zx, 4'b0101, reply_1);
$smi_data(id, reply_2, reply_3);
$display("reply_1 = %d", reply_1);
$display("reply_2 = %b", reply_2);
$display("reply_3 = %d", reply_3);
to the software model instance coded as follows:
SMI_TxMessage*
MyModel::process(const SMI_RxMessage& rx)
{
// EXTRACT VALUES FROM INCOMING MESSAGE
double value_1(rx.real(0));
string value_2(rx.text(1));
string value_3(rx.signal(2));
unsigned int value_4(rx.integer(3));
// PRINT MESSAGE VALUES
cout << "value_1 = " << value_1 << endl;
cout << "value_2 = " << value_2 << endl;
cout << "value_3 = " << value_3 << endl;
cout << "value_4 = " << value_4 << endl;
// ALLOCATE REPLY MESSAGE STRUCTURE ONCE ONLY
static SMI_TxMessage* tx(0);
if (tx == 0)
tx = SMI_Channel::instance()->newTxMessage();
// APPEND REPLY MESSAGE VALUES
tx->append(3.14);
tx->append("0011zzxx");
tx->append(32, 42);
// RETURN REPLY MESSAGE
return tx;
}
the following output is produced by the test process:
value_1 = 3.14 value_2 = hello value_3 = 01zx value_4 = 5the following output is produced by the hardware simulation:
reply_1 = 3.14 reply_2 = 0011zzxx reply_3 = 42
At some point, the simulation will need to terminate. The simulation exit procedure shuts down the hardware simulation, test processes and their communications channels. A single instance of the simulation exit procedure must be implemented in the hardware simulation. This procedure can be triggered by a number of different causes originating in the hardware simulation or any of the test processes.
If any of these conditions occur, the simulation exit procedure is initiated by setting a global flag in the hardware simulation. This flag is either output directly as a signal in the simulation (see $smi_exiting()) or it must be polled regularly (see $smi_poll_exiting()). When the flag is set, the simulation exit procedure cleans up the simulation (e.g. closes the waveform file) before calling $smi_finish(), which terminates all the models and test processes, followed by $finish, which ends the simulation.
For example, the following code implements the simulation exit procedure:
integer is_exiting; // EXIT FLAG
initial is_exiting = 0;
always@(posedge clock)
begin
// POLL SIMULATION EXIT FLAG EACH CLOCK CYCLE
$smi_poll_exiting(is_exiting);
// IF SIMULATION EXIT REQUESTED
if (is_exiting == 1)
begin
// SIMULATION EXIT PROCEDURE
$dumpflush; // FLUSH WAVEFORM LOG
$smi_finish; // SHUTDOWN SMI MODELS/PROCESSES
$finish; // EXIT THE SIMULATION
end
end
SMI raises an exception (SMI_Shutdown) in the test process to terminate that process.
| Backward | Up | Forward |
|---|