About GBL Designer |
|
![]() |
|
| GBL Designer is a graphical environment intended to simplify creating event-drivent designs which use GBL Simulation Library . GBL Designer uses schematic approach to designing and testing of GBL modules. This approach frees a developer from the need to remember the details of GBL Simulation Library , generating the C++ library code and building binaries automatically, thus eliminating errors, saving time, and allowing a developer to focus on more creative work. Since GBL designer decouples schematic representation from the library implementation, it allows easier evolution of library code without breaking backward compatibility. GBL Designer also helps with design modifications, providing automatic changes that keep different parts of the design and imported modules in sync, making the necessary changes to the generated C++ code. All that turns a tedious error-prone work of direct coding for the simulation library into an enjoyable experience working in GBL Designer. | |
Starting a new project |
|
![]() |
|
| GBL Designer on start creates a new empty project and names it project1 . You can create a new project at any time by pressing the New button or selecting File/Start New Project command from the menu. | |
![]() |
|
|
When a new project is created, the Project Manager shows a design tree with only one subnode called project1 . You can change name, location, and other project properties by selecting the project node and modifying values in Properties Window . |
|
Project Manager |
|
![]() |
|
|
Project Manager
presents a hierarchical view of the design. It shows expandable tree nodes, corresponding to the modules, ports, wires, functions, instances, texts. Project Manager
is synchronized with the Property Manger
to allow editing properties of the selected node. It is also synchronized with Module View
, so selecting an element in the Module View automatically selects the same element in the Project Manager
tree.
There are five buttons on the Project Manager caption bar:
|
|
Properties Window |
|
![]() |
|
|
Properties Window
shows a list of properties of the selected node in the Project Manager
. Some properties are read-only, other can be modified.
GBL Designer Properties :
Project Properties:
Module Properties:
Port Properties:
Wire Properties:
Function Properties:
Text Properties:
Instance Properties:
|
|
Module View |
|
![]() |
|
| Module View window displays the graphical view of the module. On the top bar, it contains buttons that allow adding basic elements to the module: ports, connections, functions, text, module instances . Select the element and click anywhere in the window to place it. By holding Ctrl key, you can add multiple instances of the selected element. Entering connections follows somewhat different procedure. Because it's likely a connection would have more than two points, each mouse click adds a connection vertex allowing to continue defining that connection. By holding down a Ctrl key when clicking left mouse button, a connection will be closed. Alternatevely by clicking on the right mouse button, unfinished segment is deleted and connection is closed. Pressing ESC key during any operation cancells it. Click and drag left mouse button to select the elements. If you hold down Ctrl button, the new selection is added to the existing one. Otherwise the existing selection is de-selected. Selection can be moved, deleted, or duplicated. To move selection, click and drag it with the left mouse button. To delete or duplicate selection use the corresponding buttons on the toolbar. The Properties Window always displays the first element of the selection. You can change the design size of the module canvas by changing Page Height and Page Width properties of the corresponding module. | |
Code Generation |
|
![]() |
|
Open Header
and Source
tabs to see code that GBL Designer
generated for the current design. You can modify code inside the GBL User Code region:#pragma region GBL User Code #pragma endregion This region will not be modified by the Designer. Any changes outside this portion of code will be discarded by the Designer. Inline Functions property (see Module Porperties ) determines whether the code for event handlers , fibers , and threads goes to the header file or to the source file. Since most compilers at this time do not support exported templates, you will need to specify Inline Functions = yes for template modules. If you decide to explicitly specialize template modules you can select either inline or outline definitions. |
|
Building Project |
|
![]() |
|
|
Click Open Modules in IDE Build Targets Run Test Modules will run the test modules that were successfully compiled. | |
GBL Simulation Library | |
| GBL Simulation Library provides a number of classes to simplify event-driven designs. It provides virtual and real-time schedulers, events, signals, ports, fibers, threads, modules and other classes implementing all essential parts of such designs. All facilities in GBL Simulation Library are declared in GBL namespace. The GBL Simulation Library is automatically linked to the designs created in GBL Designer. If you create designs manually, you need to include gbl.h header file and link to the approprate version of gbl.lib. When building using dynamically linked library gbl.dll must be available during run time. | |
GBL Time Models |
|
There two time classes provided in sim_time.h file. One is generic class template: template<class T> class TimeT;And the other is real-time class: class RealTime : public TimeT<double>The time span is described by nested class Diff.
Header file defaults.h defines default simulator virtual time typedef:
typedef TimeT<unsigned> SimTime;and virtual and real-time constants: const SimTime::Diff Tick(1); const RealTime::Diff Day(1.); const RealTime::Diff Hour(1/24.); const RealTime::Diff Min(1/24./60.); const RealTime::Diff Sec(1/24./60./60.); const RealTime::Diff Msec(1/24./60./60./1000.);If you change the default time classes used by GBL simulator, you will need to recompile the simulation library and the projects it is linked to. |
|
GBL Data Types |
|
GBL Simulation library provides additional data types for system modeling.
enum LogicValue { logic_0 = 0, logic_1, logic_x, logic_z };
class Bit;
class Logic;
template<size_t N> class BitSet;
template<size_t N> class LogicSet;
Types Bit and Logic represent 2-bit (logic_0, logic_1) and 4-bit (logic_0, logic_1, logic_x, logic_z) logic. These types have constructors and assignment operators from char and bool.
Templates BitSet<N> and LogicSet<N> represent arbitrary sized vectors of Bit and Logic values. They have constructors and assignment operators from integral types
, from std::string and const char*, and from other bit types. Operators and functions that define interface for these types are listed below:
|
|
GBL Globals |
|
Global functions in simulator.h : Simulator& GetSimulator()-- function returns reference to the default simulator. SimTime GetSimTime();-- function returns current simulation time. RealTime GetRealTime()-- function returns current real time. Event& eReset() -- a reset event happens after calling Event& eStop() -- a stop event happens after calling Event& eIdle()-- an idle event, which occures when the event queues are empty. Event& eTick()-- a tick event, which happens when the virtual time advances. Event& eRtTick()-- a real time tick event, which happens when the real time advances. void Reset()-- cleans the event queues and issue reset event.Fibers and Threads are not affected. void Run(SimTime::Diff t, RealTime::Diff tr)-- run simulator until specified simulation or real time elapses. void Run(SimTime::Diff t)-- runs simulator t ticks only. Real-time scheduler is not run.
void* RunAsync() -- starts simulator run in a separate thread and exits immediately. Simulator can be stopped by calling Simulator::Stop() function. Returned value is Windows thread handle. It can be used in Windows API accepting thread handles. For example, you can use void Close()-- function terminates all GBL Threads. Since threads cannot becontrolled by the simulator, they may continue to modify event queues after the simulator object has been already destroyed causing unhandled exceptions on program exit. Calling Close() before the termination of the program terminates all threads while the simulator is still alive. This function call is only necessary if the application creates GBL threads.
Global functions in defaults.h: std::ostream& Log()-- returns ostream object that logs simulator messages. void SetLog(std::ostream&)-- directs simulator messages to the specified ostream. void SetLog(const std::string& file_name)-- directs simulator messages to the specified file. void LogException()-- default exception dispatcher. |
|
GBL Modules |
|
|
GBL Module class is the base class for all user-defined modules. class Module : public EventHandler
{
public:
// module constructor accepts a string argument as instance name
Module(const std::string& name = "");
// GetName returns module instance name
const std::string& GetName() const;
// MakeThread creates preemptive thread out of member function
template<class M>
void MakeThread(void (M::*f)());
// MakeFiber creates a non-preemptive fiber out of member function
template<class M>
void MakeFiber(void (M::*f)());
// Enqueue schedules function to be executed in a thread pool
// function is guaranteed to be executed in the current delta cycle
// execution of enqueued functions is neither ordered nor sequenced
template<class M>
void Enqueue(void (M::*f)());
protected:
virtual void OnException() const;
};
Override OnException() to provide specific exception handling in user-defined modules.
class Example1 : public GBL::Module
{
public:
Example1() : GBL::Module("example1")
{
MakeThread(&Example1::Print);
}
private:
void Print()
{
GBL::Wait(GBL::Sec);
std::cout << "Print() called ...\n";
}
};
GBL Module class inherits from EventHandler
class, which provides facilities for event scheduling.
In order to make an event handler out of member function use Handler() or AsyncHandler() functions. |
|
GBL Events |
|
Event classes contain ActionPair objects, which are wrapped pointers to the event handlers. class EventHandler; typedef void (EventHandler::*Action)(); typedef void (EventHandler::*ActionC)()const; typedef std::pair<EventHandler*, Action> ActionPair;Events provide facilities for binding and executing of the event handlers, according to the event type. All event classes in GBL are derived from class EventBase, which specifies the following virtual interface: void Bind(const ActionPair&)-- binding of event handlers. Event handlers are bound permanently, unless Unbind()function removes binding. void BindTemp(const ActionPair&) -- binding of temporary event handlers. Temporary binding is removed after event is raised. void BindAsync(const ActionPair&) -- binding of asynchrous event handlers. void Execute()-- executing of the bound event handlers. size_t ActionCount() const-- number of event handlers event object holds. size_t TempCount() const -- number of temporary event handlers event object holds. size_t AsyncCount() const -- number of asynchronous event handlers event object holds. ActionPair Unbind()-- unbind and return the last bound event handler. ActionPair UnbindTemp() -- unbind and return the last bound temporary event handler. ActionPair UnbindAsync() -- unbind and return the last bound asynchronous event handler. The following event classes are defined in GBL:
|
|
GBL Signals |
|
Signals just like events allow binding of the event handlers. They execute the event handlers when the value of the signal changes. Initial value for the signals can be specified in their constructors. If no initial value specified the default initialization takes place. Signals provide conversion operator T () to the signal data type, as well as Read() function for cases when implicit conversion cannot be performed. Assignment operator for writable signals is resolved to Write() function. Writable delayed signals accept optional time parameter for delayed writing, as well as operator ()(TimeT delay), e.g. the expressions (1) and (2) below perform the same delayed writing to the signal, while expressions (3) and (4) perform zero-delayed writing: GBL::Signal<bool> signal; signal.Write(true, 5 * GBL::Tick); // (1) signal(5 * GBL::Tick) = true; // (2) signal.Write(true); // (3) signal = true; // (4)The signal types defined in GBL are listed below: template<class D> class ConstSignal;-- constant signal, it never changes its value after initialization and therefore never raises events. Signal data type is D.
template<class D, class E = Event> class ReadSignal;-- a signal, which can be read, but cannot be written. In addition to data type D you can specify
event type E
template<class D, class E = Event, class Condition = std::not_equal_to-- DirectSignal is never scheduled, it triggers event handlers bound to it immediately.
In addition to data and event types, you can specify a condition type, which
triggers event handlers bound to the signal.
template<class D, class E = Event, class Condition = std::not_equal_to-- a general signal type, which can be read and written. It schedules bound handlers with a delay (zero-delay by default.) | |
GBL Ports |
|
Port classes implement generalized signal pointer types and provide means for delayed bindings of the signals. From a design point of view, ports represent public module interface, through which the signal flow occurs. Thus ports efficiently decouple module design from its environment.
The following port types are defined in GBL:
-- represents unconnect port. For unconnected ports a constantclass UnconnectedPort N_C of UnconnectedPort type can be used.
template<class S> class Port template<class D> class InPort template<class D, class E = Event> class OutPort -- output port, accepting Signal<D,E>.Ports can be bound to other ports or signals. GBL defines macros GBL_CONNECTORN(p1, p2, ... , pN) for port binding in the module. For example, an inverter
with one input and one output port would have GBL_CONNECTOR2(in, out) statement. To connect external signals to an inverter
instance, they must be listed in the same order (positional binding) using operator ()(), e.g. GBL::Signal<bool> sig_in; GBL::Signal<bool> sig_out; inverter inv; inv(sig_in, sig_out); Alternatively, if ports are made public (not recommended), a binding can be done by name (nominal binding): GBL::Signal<bool> sig_in; GBL::Signal<bool> sig_out; inverter inv; inv.in(sig_in); inv.out(sig_out);
|
|
GBL Event Handlers |
|
Event handlers are member functions of modules derived from Module
(or EventHandler
) class, that have the following signatures: void (user_defined_module_class::*)();
void (user_defined_module_class::*)()const;
Use Handler() function to specify a member functionof user module class as an event handler. To bind an event handler to the events, signals, or ports use operator << (). For example, the following code creates event handler from OnSomeEvent() function and binds it to some_event event.class MyModule : public GBL::Module
{
void OnSomeEvent() { /* do synchronous processing */ }
void OnSomeEventAsync() { /* do asynchronous processing */ }
void OnOtherEvent() { Enqueue(&MyModule::OnOtherEventAsync); }
void OnOtherEventAsync() { /* do asynchronous processing */ }
GBL::Event some_event;
GBL::Event other_event;
public:
MyModule()
{
Handle(&MyModule::OnSomeEvent) << some_event;
AsyncHandle(&MyModule::OnSomeEventAsync) << some_event;
Handle(&MyModule::OnOtherEvent) << other_event;
}
};
When Function execution in the current delta cycle is neither ordered nor sequenced.
|
|
GBL Fibers and Threads |
|
|
GBL provides two classes for building asynchronous designs: Unlike asynchronous event handlers, which are executed in thread pool, Thread
function creates an physical thread and runs in infinite loop. So the number of Thread
objects that can be created is significantly smaller than the number of asynchronous event handlers. You can also use Module
class provide two functions, Example: class MyModule: public GBL::Module
{
GBL::InPort<bool> in;
void fiber() { Wait(in); std::cout << "\nInput changed: " << in; }
void thread(){ Wait(GBL::Hour); std::cout << "\nOne hour elapsed"; }
public:
MyModule()
{
MakeFiber(&MyModule::fiber);
MakeThread(&MyModule::thread);
}
}
Since fibers and threads always run in an infinite loop, they must have template<class E> void Wait(E& e)-- waiting on event/signal/port template<class S, class BinaryPredicate> void Wait(S& s, typename RefTraits<typename S::DataType>::cref value, BinaryPredicate p)-- waiting on signal/port until p(s, value) turns to truetemplate<class S> void Wait(S& s, typename RefTraits<typename S::DataType>::cref value)-- waiting until signal/port value becomes equal to value
void Wait()-- waiting until the current cycle of zero-queue void Wait(SimTime::Diff t)-- waiting for t simulator ticks void Wait(RealTime::Diff t) -- waiting in real time Threads might also need to lock shared data to prevent collisions. GBL provides the following classes (in lock.h ) to lock shared resources:
Mutex m;
{
Lock l(m);
locked_scope;
}
Mutex m;
Lock l(m);
locked_scope;
{
Unlock u(l);
unlocked_scope;
}
locked_scope_continued;
|
|
Examples |
|
|
Examples shown in this section are created for demonstration purposes only. Download project file: examples.gbl Download invertor module file: inverter.gblmod Download And2 module file: and2.gblmod Download Selector2 module file: selector2.gblmod Download Handshake module file: handshake.gblmod Download test module file: test.gblmod |
|
Inverter |
|
![]() |
|
|
Inverter module performs boolean function
In GBL Designer create one GBL Designer generated code is shown below.
|
|
//--------------------------------------------------------------------------------
// GBL Designer generated module
// Module: inverter
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#ifndef inverter_H9727
#define inverter_H9727
#include "gbl.h"
namespace examples {
class inverter : public GBL::Module
{
GBL::InPort< bool > in;
GBL::OutPort< bool > out;
public:
GBL_CONNECTOR2(in, out)
inverter(const std::string& name = "") : GBL::Module(name)
{
Handler(&inverter::OnInput) << GBL::eReset() << in;
}
#pragma region GBL User Code
private:
//----------------------------------------
void OnInput()
{
out = !in;
}
#pragma endregion
};
} // namespace examples
#endif
|
|
And2 |
|
![]() |
|
|
And2 module performs boolean function
In GBL Designer create two Select GBL Designer generated code is shown below.
|
|
//--------------------------------------------------------------------------------
// GBL Designer generated module
// Module: And2
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#ifndef And2_H9728
#define And2_H9728
#include "gbl.h"
namespace examples {
class And2 : public GBL::Module
{
GBL::InPort< bool > in1;
GBL::InPort< bool > in2;
GBL::OutPort< bool > out;
public:
GBL_CONNECTOR3(in1, in2, out)
And2(const std::string& name = "") : GBL::Module(name)
{
Handler(&And2::OnInput) << GBL::eReset() << in1 << in2;
}
#pragma region GBL User Code
private:
//----------------------------------------
void OnInput()
{
out.Write(in1 && in2, GBL::Tick * 2);
}
#pragma endregion
};
} // namespace examples
#endif
|
|
Selector2 |
|
![]() |
|
|
Selector2 module performs selection operation:
In GBL Designer create two Add event handler Select GBL Designer generated code is shown below.
|
|
//--------------------------------------------------------------------------------
// GBL Designer generated module
// Module: Selector2
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#ifndef Selector2_H9728
#define Selector2_H9728
#include "gbl.h"
namespace examples {
export template< class T >
class Selector2 : public GBL::Module
{
GBL::InPort< T > in1;
GBL::InPort< T > in2;
GBL::InPort< bool > select;
GBL::OutPort< T > out;
public:
GBL_CONNECTOR4(in1, in2, select, out)
Selector2(const std::string& name = "") : GBL::Module(name)
{
Handler(&Selector2::OnSelect) << GBL::eReset() << select;
}
#pragma region GBL User Code
private:
//----------------------------------------
void OnSelect()
{
out = select ? in1 : in2;
}
#pragma endregion
};
} // namespace examples
#endif
|
|
Handshake |
|
![]() |
|
|
GBL Designer generated code is shown below.
|
|
//--------------------------------------------------------------------------------
// GBL Designer generated module
// Module: HandShake
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#ifndef HandShake_H9727
#define HandShake_H9727
#include "gbl.h"
#include <stdlib.h>
namespace examples {
class HandShake : public GBL::Module
{
GBL::OutPort< int > data;
GBL::Signal< bool > w_en;
GBL::Signal< bool > r_en;
public:
GBL_CONNECTOR1(data)
HandShake(const std::string& name = "") : GBL::Module(name)
{
Handler(&HandShake::OnReset) << GBL::eReset();
MakeFiber(&HandShake::writer);
MakeFiber(&HandShake::reader);
}
//<GBL_user>
private:
//----------------------------------------
void writer()
{
if(!w_en)
GBL::Wait(w_en, true);
int r = rand();
data = r;
std::cout << "\nwriter: " << r;
w_en = false;
r_en.Write(true, GBL::Tick);
}
//----------------------------------------
void reader()
{
if(!r_en)
GBL::Wait(r_en, true);
std::cout << "\nreader: " << data.Read();
r_en = false;
w_en.Write(true, GBL::Tick);
}
//----------------------------------------
void OnReset()
{
w_en = true;
}
//</GBL_user>
};
} // namespace examples
#endif
|
|
Test |
|
![]() |
|
|
GBL Designer generated code is shown below.
|
|
test.h file
//--------------------------------------------------------------------------------
// GBL Designer generated module
// Module: test
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#ifndef test_H9727
#define test_H9727
#include "gbl.h"
#include "examples.h"
#include "BasicModules.h"
namespace examples {
class test : public GBL::Module
{
BasicModules::ClockGen i1;
inverter i2;
And2 i3;
Selector2< int > i4;
HandShake i5;
And2 i6;
GBL::Signal< bool > clk;
GBL::Signal< bool > inv_out;
GBL::Signal< bool > w1;
GBL::Signal< bool > clk_;
GBL::Signal< int > selector_out;
GBL::ConstSignal< unsigned > period;
GBL::Signal< bool > enable;
GBL::ConstSignal< int > const_10;
GBL::ConstSignal< int > const_1;
GBL::Signal< bool > and2_out;
GBL::Signal< int > hs_out;
void trace() { GBL::AddTrace(GetName() + ".and2_out", and2_out);
GBL::AddTrace(GetName() + ".clk", clk);
GBL::AddTrace(GetName() + ".clk_", clk_);
GBL::AddTrace(GetName() + ".hs_out", hs_out);
GBL::AddTrace(GetName() + ".inv_out", inv_out);
GBL::AddTrace(GetName() + ".selector_out", selector_out);
GBL::AddTrace(GetName() + ".w1", w1); }
public:
test(const std::string& name = "") : GBL::Module(name)
, i1(name + ".i1"), i2(name + ".i2"), i3(name + ".i3"), i4(name + ".i4")
, i5(name + ".i5"), i6(name + ".i6")
, period(10), const_10(10), const_1(1)
{
i1 ( period, enable, clk, clk_ );
i2 ( clk, inv_out );
i3 ( w1, clk, and2_out );
i4 ( const_10, const_1, clk_, selector_out );
i5 ( hs_out );
i6 ( inv_out, inv_out, w1 );
Handler(&test::OnReset) << GBL::eReset();
Handler(&test::trace) << and2_out << clk << clk_
<< hs_out << inv_out << selector_out << w1;
}
//<GBL_user>
private:
//----------------------------------------
void OnReset()
{
enable = true;
}
//----------------------------------------
void Run()
{
GBL::Run(GBL::Tick * 1000, GBL::Sec * 10);
}
//</GBL_user>
};
} // namespace examples
#endif
|
|
test.cpp file
//--------------------------------------------------------------------------------
// GBL Designer generated module implementation
// Module: test
// 2006-2010(c) GB RESEARCH, LLC. ALL RIGHTS RESERVED
//--------------------------------------------------------------------------------
#include "test.h"
using namespace examples;
//----------------------------------------main
int main(int argc, char* argv[])
{
GBL::SetTraceFile("C:\\GBL\\Examples\\examples.trace");
examples::test("test").Run();
GBL::Close();
}
//<GBL_user>
//</GBL_user>
|
|
| After building and running test.exe , click on Tracer icon to open saved traces from this example. They should look like in the picture below. | |
![]() |
|