1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20// sc_vector.cpp -- test for
21//
22//  Original Author: John Aynsley, Doulos, Inc.
23//
24// MODIFICATION LOG - modifiers, enter your name, affiliation, date and
25//
26// $Log: sc_vector.cpp,v $
27// Revision 1.3  2011/07/24 16:04:12  acg
28//  Philipp A. Hartmann: remove assert() that does not test the correct thing.
29//
30// Revision 1.2  2011/05/08 19:18:46  acg
31//  Andy Goodrich: remove extraneous + prefixes from git diff.
32//
33
34// sc_vector
35
36#define SC_INCLUDE_DYNAMIC_PROCESSES
37#include <systemc>
38#include <cstring>
39
40using namespace sc_core;
41using std::cout;
42using std::endl;
43using std::string;
44
45struct Sub: sc_module
46{
47  sc_inout<int> p;
48
49  Sub(sc_module_name)
50  {
51    SC_THREAD(T);
52  }
53
54  void T()
55  {
56    for (;;)
57    {
58      wait(p.default_event());
59    }
60  }
61
62  SC_HAS_PROCESS(Sub);
63};
64
65
66struct my_module: sc_module
67{
68  my_module(sc_module_name n, string weird_arg )
69  {
70    sc_assert( weird_arg == "The Creator" || weird_arg == "WeIrD_aRg" );
71  }
72};
73
74
75struct my_object: sc_object
76{
77  my_object()              : sc_object()  {}
78  my_object(const char* c) : sc_object(c) {}
79};
80
81
82struct i_f: virtual sc_interface
83{
84  virtual void method() = 0;
85};
86
87
88struct Initiator: sc_module
89{
90  sc_vector<sc_port<i_f> > ports;
91
92  Initiator(sc_module_name)
93  : ports("ports", 4)
94  {
95    SC_THREAD(T);
96  }
97
98  void T()
99  {
100    for (unsigned int i = 0; i < ports.size(); i++)  // Use method size() with vector
101    {
102      wait(10, SC_NS);
103      ports[i]->method();  // Use operator[] with vector
104    }
105  }
106  SC_HAS_PROCESS(Initiator);
107};
108
109
110struct Initiator1: sc_module
111{
112  sc_port<i_f> port;
113
114  Initiator1(sc_module_name)
115  : port("port")
116  {
117    SC_THREAD(T);
118  }
119
120  void T()
121  {
122    wait(10, SC_NS);
123    port->method();
124  }
125  SC_HAS_PROCESS(Initiator1);
126};
127
128
129struct Target: public sc_module, private i_f
130{
131  sc_export<i_f> xp;
132
133  Target(sc_module_name)
134  : xp("xp")
135  {
136    xp.bind( *this );
137  }
138
139  virtual void method() {
140    cout << "Called method() in " << name() << " at " << sc_time_stamp() << endl;
141  }
142};
143
144
145typedef sc_vector<sc_inout<int> > port_type;
146
147struct M: sc_module
148{
149  port_type ports; // Vector-of-ports
150
151  sc_vector<Sub> kids; // Vector-of-modules, each with a port p
152  sc_vector<Sub> kids2;
153  sc_vector<sc_signal<int> > sigs2;
154  sc_vector<sc_signal<int> > sigs3;
155
156  int dim;
157
158  Initiator*        initiator;
159  sc_vector<Target> targets;
160
161  sc_vector<Initiator1> initiator_vec;
162  sc_vector<Target>     target_vec;
163
164
165  sc_vector<my_module> my_vec_of_modules;
166
167  struct my_module_creator
168  {
169    my_module_creator( string arg ) : weird_arg(arg) {}
170
171    my_module* operator() (const char* name, size_t)
172    {
173      return new my_module(name, weird_arg );
174    }
175    string weird_arg;
176  };
177
178  sc_vector<my_module> my_vec_of_modules2;
179
180  // If creator is not a function object, it could be a function
181  my_module* my_module_creator_func( const char* name, size_t i )
182  {
183    creator_func_called = true;
184    return new my_module( name, "WeIrD_aRg" );
185  }
186
187  bool creator_func_called;
188
189
190  M(sc_module_name _name, int N)
191  : ports("ports", N)
192  , kids("kids")  // Construct the vector with name seed "kids"
193  , kids2("kids2", 8)
194  , sigs2("sigs2", 4)
195  , sigs3("sigs3", 4)
196  , dim(N)
197  , targets("targets", N)
198  , initiator_vec("initiator_vec", N)
199  , target_vec("target_vec", N)
200  , my_vec_of_modules("my_vec_of_modules")
201  , creator_func_called(false)
202  {
203    //vec.init(N);  // Alternative initialization (instead of passing N to ctor)
204    kids.init(N);
205
206    sc_assert( ports.size() == static_cast<unsigned int>(N) );
207    sc_assert( kids.size()  == static_cast<unsigned int>(N) );
208
209    // Using vector view to create vector-of-ports
210    sc_assemble_vector(kids, &Sub::p).bind( ports );
211
212    for (unsigned int i = 0; i < kids.size(); i++)
213    {
214      sc_assert( kids[i].p.get_interface() == ports[i].get_interface() );
215    }
216
217    initiator = new Initiator("initiator");
218
219    // Using vector view to create vector-of-exports
220    initiator->ports.bind( sc_assemble_vector(targets, &Target::xp) );
221
222    // Double whammy
223    sc_assemble_vector(initiator_vec, &Initiator1::port).bind( sc_assemble_vector(target_vec, &Target::xp) );
224
225    // sc_vector_view has no public constructors, though it is copyable
226    sc_vector_assembly< Initiator1, sc_port<i_f> > assembly = sc_assemble_vector(initiator_vec, &Initiator1::port);
227
228    sc_assert( &*(assembly.begin()) == &(*initiator_vec.begin()).port );
229    // sc_assert( &*(assembly.end())   == &(*initiator_vec.end()).port );
230    sc_assert( assembly.size()  == initiator_vec.size() );
231    for (unsigned int i = 0; i < assembly.size(); i++)
232    {
233      sc_assert( &assembly[i]    == &initiator_vec[i].port );
234      sc_assert( &assembly.at(i) == &initiator_vec[i].port );
235    }
236
237    std::vector<sc_object*> elements;
238
239    // sc_vector_view (aka sc_vector_assembly) acts as a proxy for sc_vector
240    // It has begin() end() size() operator[] bind() etc
241
242    elements = assembly.get_elements();
243    for ( unsigned i = 0; i < elements.size(); i++ )
244      if ( elements[i] )
245        sc_assert( elements[i] == &initiator_vec[i].port );
246
247    elements = ports.get_elements();
248    for ( unsigned i = 0; i < elements.size(); i++ )
249      if ( elements[i] )
250        sc_assert( elements[i] == &ports[i] );
251
252    elements = sc_assemble_vector(initiator_vec, &Initiator1::port).get_elements();
253    for ( unsigned i = 0; i < elements.size(); i++ )
254      if ( elements[i] )
255        sc_assert( elements[i] == &initiator_vec[i].port );
256
257    // Additional method to support a vector iterator as an offset
258    sc_assemble_vector(kids2, &Sub::p).bind( sigs2.begin(), sigs2.end(), kids2.begin());
259    sc_assemble_vector(kids2, &Sub::p).bind( sigs3.begin(), sigs3.end(), kids2.begin() + 4 );
260
261    // Construct elements of sc_vector, passing through ctor arguments to user-defined sc_module
262    my_vec_of_modules.init(N, my_module_creator("The Creator"));
263
264    // Alternatively, instead of a function object pass in a function
265    my_vec_of_modules2.init(N, sc_bind( &M::my_module_creator_func, this, sc_unnamed::_1, sc_unnamed::_2 ) );
266
267    // Well-formedness check on creator function call
268    my_module_creator foo("The Creator");
269    const char* nm = "foo";
270    unsigned int idx = 0;
271    my_module* next = foo( (const char*)nm, (sc_vector<my_module>::size_type)idx );
272    char buf[80];
273    strcpy(buf, this->name());
274    strcat(buf, ".foo");
275    sc_assert( strcmp(next->name(), buf) == 0 );
276    delete next;
277
278    SC_THREAD(T);
279  }
280
281  void T()
282  {
283    int j = 0;
284    for (int i = 0; i < 10; i++)
285    {
286      wait(10, SC_NS);
287      ports[i % dim].write((j++) % 10);  // Use operator[] with vector
288    }
289  }
290
291  SC_HAS_PROCESS(M);
292};
293
294struct Top: sc_module
295{
296  sc_vector<sc_signal<int> > sigs; // Vector-of-signals
297  sc_vector<sc_signal<int> > more_sigs; // Vector-of-signals
298  sc_vector<sc_signal<int> > hi_sigs; // Vector-of-signals
299  sc_vector<sc_signal<int> > lo_sigs; // Vector-of-signals
300
301  M *m1, *m2, *m3;
302
303  Top(sc_module_name _name)
304  : sigs("sigs", 4)
305  , more_sigs("more_sigs", 4)
306  , hi_sigs("hi_sigs", 2)
307  , lo_sigs("lo_sigs", 2)
308  {
309    m1 = new M("m1", 4);
310    m2 = new M("m2", 4);
311    m3 = new M("m3", 4);
312
313    for (int i = 0; i < 4; i++)
314      m1->ports[i].bind( sigs[i] );  // Using operator[] with a vector
315
316    port_type::iterator it = m2->ports.bind( more_sigs ); // Vector-to-vector bind
317    sc_assert( (it - m2->ports.begin()) == 4 );
318
319    // Bind upper half of ports vector to hi_sigs
320    it = m3->ports.bind( hi_sigs.begin(), hi_sigs.end() );
321    sc_assert( (it - m3->ports.begin()) == 2 );
322
323    // Bind lower half of ports vector to lo_sigs
324    it = m3->ports.bind( lo_sigs.begin(), lo_sigs.end(), it);
325    sc_assert( (it - m3->ports.begin()) == 4 );
326
327    SC_THREAD(T);
328    SC_THREAD(T2);
329  }
330
331  void T()
332  {
333    sc_event_or_list list;
334    for (int i = 0; i < 4; i++)
335      list |= sigs[i].default_event();
336    for (;;)
337    {
338      wait(list);
339      cout << "Top:" << sigs[0] << sigs[1] << sigs[2] << sigs[3] << endl;
340    }
341  }
342
343
344  void T2()
345  {
346    wait(10, SC_US);
347
348    // Create sc_vector during simulation
349    sc_vector<my_object> vec_obj("vec_obj", 4);
350    sc_assert( vec_obj.size() == 4 );
351    for (unsigned int i = 0; i < vec_obj.size(); i++)
352      cout << "vec_obj[" << i << "].name() = " << vec_obj[i].name() << endl;
353
354    sc_object* proc = sc_get_current_process_handle().get_process_object();
355    std::vector<sc_object*> children = proc->get_child_objects();
356
357    sc_assert( children.size() == 5 ); // sc_vector itself + 4 X my_object
358  }
359
360  SC_HAS_PROCESS(Top);
361};
362
363
364int sc_main(int argc, char* argv[])
365{
366  Top top("top");
367
368  std::vector<sc_object*> children = top.get_child_objects();
369  sc_assert( children.size() == 21 ); // sc_vectors themselves are sc_objects
370
371  sc_start();
372
373  sc_assert( top.m1->creator_func_called );
374  sc_assert( top.m2->creator_func_called );
375  sc_assert( top.m3->creator_func_called );
376
377  cout << endl << "Success" << endl;
378  return 0;
379}
380
381