blob: e697447936b73b53266df3925369f7dca19aeef8 [file] [log] [blame]
//
//------------------------------------------------------------//
// Copyright 2009-2012 Mentor Graphics Corporation //
// All Rights Reserved Worldwid //
// //
// Licensed under the Apache License, Version 2.0 (the //
// "License"); you may not use this file except in //
// compliance with the License. You may obtain a copy of //
// the License at //
// //
// http://www.apache.org/licenses/LICENSE-2.0 //
// //
// Unless required by applicable law or agreed to in //
// writing, software distributed under the License is //
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR //
// CONDITIONS OF ANY KIND, either express or implied. See //
// the License for the specific language governing //
// permissions and limitations under the License. //
//------------------------------------------------------------//
#include <systemc.h>
using namespace sc_core;
//-----------------------------------------------------------------------------
// Title: UVMC Connection Example - SC to SV, SC side
//
// This example shows a SC producer driving a SV consumer via a TLM connection
// made with UVMC, including how to derive a SC producer subtype that can
// control UVM phasing using the UVMC Command API.
// See <UVMC Connection Example - SC to SV, SV side> to see the SV portion
// of the example.
//
// (see UVMC_Connections_SC2SV.png)
//
// In a pure SC simulation, synchronization between a producer and consumer
// occurs exclusively through the protocol prescribed by the TLM standard.
// In mixed SC-SV simulation, SC usually elaborates and starts its threads
// before SV has finished elaborating. To prevent run-time errors, UVMC will
// block any cross-language access until SV is ready. This means calls to
// interface methods via SC ports or sockets connected to SV must be made
// from within SC threads (via the SC_THREAD macro or sc_spawn).
//
// Blocking until SV is ready technically violates TLM non-blocking semantics.
// It was deemed more useful to hold back activity from all cross-language
// calls rather than reject all non-blocking calls until SV was ready. Future
// releases may provide an option to return immediately with 0 status from
// non-blocking calls.
//
// When a UVM testbench is sitting on the SV side, you must also consider UVM's
// phasing semantics, which says that a phase will end if there are no objections
// raised to its ending. When, as in this example, there is a SC-side participant
// to UVM phase control, an objection will need to be raised from the SC side
// for the phase(s) in which the SC side actively participates. The producer,
// in other words, must use the UVMC Command API to raise and drop the objection
// that corresponds to the phase in which it is generating stimulus. If it does
// not, then UVM (SV) will end that phase and likely end simulation before the
// SC producer has had a chance to emit the first transaction.
//
// To preserve reuse, it is recommended that the UVM Command API usage be
// relegated to a subtype of the native SC producer. This way, you do not couple
// the producer's primary functionality (producing transactions) with
// cross-language synchronization issues and UVMC.
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Group: UVM-aware SC producer
//
// This example defines the ~producer_uvm~ class, which derives from
// our generic SC ~producer~. In it, we spawn a dynamic ~objector~ thread
// that calls ~uvmc_raise_objection~ to UVM's run phase. This keeps simulation
// alive on the SV side while the base ~producer~ in SC generates stimulus.
//
// When the base ~producer~ is finished generating stimulus, it will notify a
// ~done~ sc_event. The ~objector~ thread in this ~producer_uvm~ wakes up on
// that event notification and drops its objection using ~uvmc_drop_objection~.
// This allows UVM simulation to proceed to the next phase and eventually
// complete simulation.
//-----------------------------------------------------------------------------
// (begin inline source)
#include "uvmc.h"
using namespace uvmc;
#include "producer.h"
class producer_uvm : public producer {
public:
producer_uvm(sc_module_name nm) : producer(nm) {
SC_THREAD(objector);
}
SC_HAS_PROCESS(producer_uvm);
void objector() {
uvmc_raise_objection("run");
wait(done);
uvmc_drop_objection("run");
}
};
// (end inline source)
//-----------------------------------------------------------------------------
// Group: sc_main
//
// The ~sc_main~ function below creates and starts the SC portion of this example.
// It does the following:
//
// - Instantiates a basic ~producer~
//
// - Registers the producer's ~in~ port with UVMC using the lookup
// string "42". During elaboration, UVMC will connect this port with
// a port registered with the same lookup string. In this example, the
// match will occur with a consumer's ~in~ port on the SV side.
//
// - Calls ~sc_start~ to start SystemC
//
//-----------------------------------------------------------------------------
// (begin inline source)
int sc_main(int argc, char* argv[])
{
producer_uvm prod("producer");
uvmc_connect(prod.out,"42");
sc_start(-1);
return 0;
}
// (end inline source)