Jump to content

David Black

Members
  • Posts

    690
  • Joined

  • Last visited

  • Days Won

    154

Everything posted by David Black

  1. SystemVerilog does not allow 'function overloading' like C++. Suppose I have a class A with a function write as follows: class MyClass function void write(input T1 value); ... endfunction function void write(input T2 value); ... endfunction // ***ERROR*** Not allowed to have two 'write' functions in same class (no overloading allowed) ... Instead you should have: class MyClass function void write_T1(input T1 value); ... endfunction function void write_T2(input T2 value); ... endfunction // OK, different name ...
  2. The simplest examples of polymorphism at work are the UVM factory when you use overrides.
  3. I've often thought of writing a delayed assignment channel for SystemC. Probably just a new signature for sc_signal::write(...). Of course that begs the question of transport vs inertial delay, which would be interesting to use. I think both are likely to have their uses. Perhaps: template<typename T> class sc_signal_delayed : public sc_core::sc_signal<T> { ... void write(const T& value, sc_time delay, bool transport=true) { ...details left to the implementor... } };
  4. You are free to use my solution. All you need is a C++ compiler that supports the new 2011 standard (i.e. C++11). There are several free solutions out there including GCC 4.7, Clang 3.4, and Microsoft Studios Visual C++ 2013 Express Edition. They all work with SystemC versions 2.3 and later. I provide the complete code including a testbench. Any practioner proficient in SystemC should be sufficiently proficient with C++ that this is not hard to do. The solution could also have been rewritten using function pointers, but the result would be less compact code. I can point you to many tutorials and documents on C++11, which has many very good features. A few of the more forward thinking EDA vendors are about to introduce C++11 support in the near future; however, I cannot reveal their names due to confidentiality.
  5. Briefly (because you can find a lot more on this topic if you browse the web, or take a class): 1. SystemC is usually focused above RTL and models typically provide much less detail. This means it can be written in less time, and makes it run much faster. 2. SystemC is a standardized (IEEE-1666-2011) modeling language with a LOT of EDA vendor tool support. 3. SystemC can be used for High Level Synthesis, which creates RTL (e.g. Verilog or VHDL). 4. SystemC can be used as a reference model for verification. 5. SystemC is very compatible with software since it is really just a C++ library, and means software folks can understand more easily. 6. SystemC can run fast enough that it is an acceptable virtual platform to develop software on before hardware is available (RTL runs much too slowly). 7. SystemC has an open-source free implementation to get you started, and only requires a good text editor and C++ compiler develop.
  6. If you don't have the linux 'patch' utility handy, you can apply a patch manually (assuming it is small, which this one is). The file is plain text and tells which files and lines to change. The lines beginning with a '-' are old lines to be replaced with the '+' lines representing replacement/new code. This particular patch says the problem is just after line 69 of the sc_cmnhdr.h file. If you look closely, you will see the fix places a #ifdef around the problematic code.
  7. Virtual platforms can be written much faster than actual hardware implementation and simulate much faster. Virtual platforms should be written in days vs months. In other words at least an order of magnitude faster to write. They should execute 100-100,000 times faster as well. This means they can be used before hardware design is completed to develop software on. Also, they can be used in a mixed-level simulation to speed up results of RTL simulations when the focus is on other parts of the system still represented in RTL. Also virtual platforms can be used to debug problems that are almost impossible to debug in hardware because you can set breakpoints and single step them. Many other good reasons and uses.
  8. Dakupoto, the question regards start_of_simulation(), which occurs before processes start, and itself is not a process. It is still true that ordering is up to the implementation of SystemC and not prescribed by the standard. Thundium, if Alan's answer doesn't work for you, you might consider writing your own mini-scheduler. It's actually rather easy if you use a std::multimap to store function pointers indexed by their priority or perhaps create a queue of function pointers (harder to manage I think). You could then register methods or lambdas to execute under control of the mini-scheduler during construction and later invoke the mini-scheduler to execute them from a single start_of_simulation (e.g. top module). I've written one of these using C++11 features (need GCC 4.7 or VS2013 to run): #ifdef __MSC_VER # if __MSC_VER < 1700 /* Microsoft Visual Studio 2012 */ # pragma message("ERROR: Requires C++11 vis avi Microsoft Visual Studio 2012 or later") # endif #else # if __cplusplus < 201103L # ifdef WIN32 # pragma message("ERROR: Requires C++11") # else # error "Requires C++11" # endif # endif #endif //////////////////////////////////////////////////////////////////////////////// // Ordered_execution allows registration of lambdas to be executed at a later // time with specified priority. #include <map> #include <utility> #include <functional> using priority_t = size_t; class Ordered_execution { using lambda_t = std::function<void(priority_t)>; std::multimap<priority_t,lambda_t> execution_queue; public: void schedule(priority_t priority, const lambda_t& lambda) { execution_queue.insert(std::make_pair(priority,lambda)); } void execute(void) { for (const auto& item : execution_queue) { (item.second)(item.first); } execution_queue.clear(); } }; // Define UNIT_TEST to run the following code #ifdef UNIT_TEST #include <systemc> #include <ostream> #include <iomanip> #include <memory> using namespace sc_core; using namespace std; namespace { Ordered_execution end_elab; Ordered_execution start_sim; const int max_modules = 8; } //------------------------------------------------------------------------------ // Simple example module registering its code struct Simple_module : sc_module { Simple_module(sc_module_name instance_name) { cout << " +- Constructing " << name() << "." << __func__ << endl; SC_HAS_PROCESS(Simple_module); SC_THREAD(main_thread); start_sim.schedule( /* Priority */ 2 , [&](priority_t p) { cout << " start_sim " << name() << " with priority " << p << endl; } ); } void start_of_simulation(void) { cout << "Running " << name() << "." << __func__ << endl; } void main_thread(void) { cout << "Running " << name() << "." << __func__ << endl; } }; //------------------------------------------------------------------------------ // This module is instantiated multiple times to illustrate the general idea struct Module : sc_module { Module(sc_module_name instance_name, priority_t priority) { cout << " +- Constructing " << name() << "." << __func__ << endl; SC_HAS_PROCESS(Module); SC_THREAD(main_thread); end_elab.schedule( priority , [&](priority_t p) { cout << " end_elab " << name() << " with priority " << p << endl; } ); start_sim.schedule( priority , [&](priority_t p) { cout << " start_sim " << name() << " with priority " << p << endl; } ); } void start_of_simulation(void) { cout << "Running " << name() << "." << __func__ << endl; } void main_thread(void) { cout << "Running " << name() << "." << __func__ << endl; } }; Module* module_ctor( const char* instance_name, size_t s ) { priority_t priority = abs(random())%max_modules + 1; cout << "- Construct module_" << s << " with priority " << priority << endl; return new Module(instance_name, priority); } //------------------------------------------------------------------------------ SC_MODULE(Top_module) { Simple_module* simple; sc_vector<Module> module_vec; SC_CTOR(Top_module) : simple(new Simple_module("simple")), module_vec("module") { cout << "Constructing " << name() << "." << __func__ << endl; module_vec.init(max_modules, module_ctor); SC_THREAD(main_thread); } void end_of_elaboration(void) { cout << "Running " << name() << "." << __func__ << endl; cout << "Ordered stuff..." << endl; end_elab.execute(); cout << "Finished " << name() << "." << __func__ << endl; } void start_of_simulation(void) { cout << "Running " << name() << "." << __func__ << endl; cout << "Ordered stuff..." << endl; start_sim.execute(); cout << "Finished " << name() << "." << __func__ << endl; } void main_thread(void) { cout << "Running " << name() << "." << __func__ << endl; wait(1,SC_NS); sc_stop(); } }; //------------------------------------------------------------------------------ namespace { // Declare string used as message identifier in SC_REPORT_* calls char const * const MSGID = "/Doulos/example/main"; } //------------------------------------------------------------------------------ int sc_main(int argc, char* argv[]) { SC_REPORT_INFO(MSGID,"Elaborating"); Top_module* top; try { top = new Top_module("top"); } catch (std::exception& e) { SC_REPORT_ERROR(MSGID,(string(e.what())+" Please fix elaboration errors and retry.").c_str()); return 1; } catch (...) { SC_REPORT_ERROR(MSGID,"Caught exception during elaboration"); return 1; }//endtry // Simulate try { SC_REPORT_INFO(MSGID,"Starting kernal"); sc_start(); SC_REPORT_INFO(MSGID,"Exited kernal"); } catch (std::exception& e) { SC_REPORT_WARNING(MSGID,(string("Caught exception ")+e.what()).c_str()); } catch (...) { SC_REPORT_ERROR(MSGID,"Caught exception during simulation."); }//endtry if (not sc_end_of_simulation_invoked()) { SC_REPORT_INFO(MSGID,"ERROR: Simulation stopped without explicit sc_stop()"); sc_stop(); }//endif size_t info_count = sc_report_handler::get_count(SC_INFO); size_t warning_count = sc_report_handler::get_count(SC_WARNING); size_t error_count = sc_report_handler::get_count(SC_ERROR); size_t fatal_count = sc_report_handler::get_count(SC_FATAL); bool success = ((fatal_count + error_count) == 0); cout << " " << setw(4) << warning_count << " warning messages" << "\n" << " " << setw(4) << error_count << " errors" << "\n" << " " << setw(4) << fatal_count << " fatalities" << "\n" ; if (success) { cout << "PASSED - No errors detected." << endl; } else { cout << "FAILED" << endl; }//endif delete top; return (success?0:1); } #endif
  9. I think deriving your own specialized signal class is the best solution. This is similar to Ralph's suggestion, but restricted to sc_logic. It will make the coding go faster. struct my_signal : sc_signal<sc_logic> { // Override appropriate methods void write(...) { } void update() { ... } private: sc_logic prev; }
  10. Perhaps the issue is focusing on the problem each tries to accomplish. All three involve 'modeling', which is 'a standard or example for imitation or comparison.' Performance modeling is used to compare or analyze performance of a proposed design. In electronic design, it is often the communications that are under scrutiny, but a processor model might look at the performance of a particular instruction set. Register modeling usually means creating simulated registers to allow examination of how well a particular design works. Sometimes register models are used to provide software designers an early look at proposed hardware. Behavioural modeling is often a way of contrasting a very open easy style of writing a model versus detail RTL modeling. RTL (register transfer language) has rules and details that make it harder to write. These terms are very fluid and may vary from one group to the next. The moment you nail one down, somebody will invent a new term for their particular flavor. When you encounter these terms, it is best to ask what they want to accomplish with them.
  11. Likely as not you will also need to reword your SystemC TB somewhat (or perhaps even remove to be replaced by SystemVerilog driven version). What I mean is that SystemVerilog/UVM probably needs to be able to control the SystemC model. At very least, there needs to be a way to halt and progress time externally. Another approach is to have the SystemVerilog issue commands to the fabric. Quite a lot of this depends on exactly what you are modeling.
  12. A module is intended to represent the design under development/test and may be synthesized (subject to appropriate coding guidelines). A program block is intended for verification only. Thus the code in a program is never intended to be synthesized. If a module were allowed to call a task or function in a program, that would imply that the code could be synthesized. The tools that synthesize would then have to be more complex and consider program blocks. This restriction removes that burden. Also, program blocks were intended to remove race conditions between verification code and design implementation. If a module could call tasks in a program, then race conditions might occur in as the rules for where things are executed would create problems. [NOTE: This is the strongest reason, but more difficult to follow.]
  13. The LD_LIBRARY_PATH issue cannot be taken care of by the installer since that would mean a very delicate modification of users' home "dot" files and is very dependent on features that are not easy to infer. As somebody observed, SystemC is a C++ library and there is a fundamental expectation that you are competent in C++. I would not suggest anybody try to learn SystemC without first mastering C++. Sort of like asking somebody to read complex novel before they even know how to read. That said, if LD_LIBRARY_PATH is the only issue, which I doubt, then it depends on: 1. Which shell you are using (probably BASH) 2. Where you installed SystemC (not where you expanded the tarball 3. The architecture of your host computer (e.g. x86 or x86_64 etc...) Assuming you installed in a directory such as $HOME/systemc-2.3, and assuming BASH, and assuming you are on x86_64, then likely you need a command like: SYSTEMC_HOME=$HOME/systemc-2.3 if [[ "$LD_LIBRARY_PATH" == "" ]]; then LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$SYSTEMC_HOME/lib-linux64 else LD_LIBRARY_PATH=$SYSTEMC_HOME/lib-linux64 fi Again, read the INSTALL file for Linux carefully.
  14. A cheap; albeit, imperfect, solution would be to put all elements except address, and burst information into the data portion (payload, checksums, and other decorations) of the generic payload (GP). Perhaps remove those elements (the ones already handled by GP), and then: // CAVEAT EMPTOR: **UNTESTED** #include <tlm> ... Your_struct data; tlm::tlm_generic_payload* gp; gp = memory_manager.allocate(); gp->set_data_ptr(reinterpret_cast<unsigned char*>(&data)); gp->set_data_len(sizeof(data)); gp->set_address(address); ... Alternately, you could use TLM 2.0 with your custom data structure, but it won't interoperate with other TLM components that don't know about your structure. If you are using TLM for a network application rather than the targeted memory mapped bus use case, then this approach might be valid. You can of course use TLM 2.0 extensions to put additional fields on the data, but this is certainly a less standard approach. The closer you come to using the GP unmodified, the more interoperable your TLM IP will be.
  15. Each of those agents should have its own interface instance. Make sure you are connecting those correctly.
  16. Simple answer: no Slightly longer: Since SystemC is really just a methodology using a standardized API to a C++ library, it would rely heavily on users creating their components to have rollback. I have heard rumor of work exploring this goal. Adding this to the standard would fundamentally affect existing implementations.
  17. If the port is not connected, it is likely declared as a wire rather than a var'iable. I would expect you would need to force (uvm_hld_force) the the port rather than just a simple write. If you are trying to do this via a register, then you will need to query the register for the path to that bit in order to use force (uvm_reg::get_full_hdl_path). You will also need to learn about uvm_hdl_path_concat. These are all documented in the class reference.
  18. Your monitor::post_shutdown_phase did not raise an objection at time zero, the default drain time is 0ns, and you waited 50ns to start. No surprise that the phase is ready to shutdown. ALL run-time phases need objections raised to keep the respective component's phase method running. This starts at time zero.
  19. Actually, Cam's code is almost correct with respect to the array if using C++11. If your version of GCC is relatively recent (e.g. 4.7) or perhaps you are using CLANG++ versions 3.4 or later, or even Visual Studio C++ 2013, then there is a new initializer syntax. That is what the error message was trying to tell you. In C++11, you can do things like: int array_2[2] = {1,2}; // creates an array of 2 elements std::vector<int> vector_1 = { 1, 2, 3, 4 }; // creates a vector of 4 elements auto array_1[] = {1U, 2U, 3U}; // creates an array of 3 unsigned int elements The following should work with GCC 4.7 if you include the -std=c++11 switch: #include <array> struct hci_top : sc_module { std::array<unsigned int,16> const_matrix_arr; ------ ------ Constructor hci_top(sc_module_name nm):sc_module(nm), host_hci_tar_socket("host_hci_tar_socket") { const_matrix_arr = {2, 3, 1, 1, 1, 2, 3, 1, 1, 1, 2, 3, 3, 1, 1, 2}; // Initialization } };
  20. If you want to guarantee the # of bits, but want speed then you should include <cstdint> or stdint.h (which has become part of the C++11 standard, but has been available for many years). You only have access to multiples of 8-bits, but at least least it's fast. Of course to grab bit ranges you will need to do the standard software masking rather than the convenience of sc_int. sc_int<W> should be used for situations where modeling the exact number of bits will make a difference in the results. For example, if the hardware implementation will have 13 bits and you do arithmetic (addition/subtraction), then sc_int<W> can catch overflow issues. Another example is synthesis of a register, where you need to control size of the hardware. The difference in performance is dramatic. Consider the following code and timing results: { using data_t = int32_t; //< replace this with sc_int<32>, sc_fixed<32,32>, float, etc... data_t result = 1; data_t A = 1103515245; data_t C = 12345; start_timer(); //< Calls a routine to get CPU time using C++11 constructs -- portable for (size_t loop=loop_count; loop!=0; --loop) { result = A * result + C; } cout << "result=" << result << endl; // Ensure compiler doesn't optimize loop out report_time(typeid(data_t).name); //< Calculates final time -- Be sure to filter with c++filt } I saw results for SystemC 2.3.0-ASI --- Jan 6 2014 07:20:27 (on 2.7GHz Intel i7) with no optimization using clang++ compiler: loop_count = 1e8 int took 0.343008s sc_dt::sc_int<32> took 2.01204s double took 0.755805s sc_dt::sc_fixed<32, 32> took 41.3482s With -O3 optimization: loop_count = 1e8 int took 0.125028s sc_dt::sc_int<32> took 0.199671s double took 0.364543s sc_dt::sc_fixed<32, 32> took 25.6714s So be careful what you select AND what compiler options you use. You can view the source code at https://github.com/dcblack/scdataperf
  21. There is no "SystemC" standard. Remember that SystemC is really just a C++ library (API). Using a common C++ coding standard of which there are several (e.g. JSF) is a good place to start. Here are a few ideas: Indentation (a hotly debated topic) - I prefer two spaces. Look for tools support to automate this aspect. Variable names should not be abbreviated, but rather use lowercase and separate words with underscore. Classes should start with Uppercase letter. Member data other than channels/sockets, should be prefixed with m_. Class static variables should be prefixed with s_. Suffixes should indicate process types (i.e. _thread, _method, _cthread), channels (_channel), events (_event), ports/sockets (_port/_socket). More importantly, if you are going to use a standard, there should be a tool that can help enforce/code. WARNING: You might want to avoid any standard suggesting leading underscores and a few other things. See the following Stack Overflow article for a discussion of this <http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier>.
  22. A basic question: Which type of mutex are you using? sc_mutex or something else?
  23. Try: 1. Installed Visual C++ 2012 Express Edition (Note - won't work on XP only Windows 7/8) 2. Download Systemc-2.3.0.tgz 3. uncompress systemc-2.3.0.tgz 4. Assuming in c:\systemc-2.3.0 5. copy msvc80 to msvc11 (optional, but helps if you attempt to run regressions) 6. Run Visual C++ 2012 EE and open msvc11\systemc\systemc.sln 7. Upgrade is offered - click OK 8. Menu Build > Build Solution Build failed due to warning 4005 Edit sc_cmnhdr.h line 75 and add a test for _MSC_VER == 1200 as follows: // MSVC6.0 for() scope bug #if defined(_MSC_VER) && (_MSC_VER == 1200) #define for if( false ); else for #endif Now it should build. 9. Add an environment variable SYSTEMC set to c:\systemc-2.3.0\ 10. Set library, src, include paths as for Visual C++ 2010 Note: to find the property pages, load in a project (e.g. ex6 from the course). Then do View > Other Windows > Property Manager Expand the project name until you find Debug | Win32 > Microsoft.CPP.Win32.user and set the include and library directories to $(SYSTEMC)\src $(SYSTEMC)\msvc11\systemc\debug
  24. What is the purpose of this encoder? Will it be used to allow software development or is it intended to model intended performance (choose one or the other)? The choice of answer will lead you to the general coding style of either loosely-timed or approximately-timed. Cycle-accurate is an extreme form of approximately-timed. SC_THREAD's tend to be easier to code IMNSHO. Which you choose should be dependent on which is easier to code for your application, and that may be tied to the project description. If a state-machine description is given, then SC_METHOD's may be more appropriate.
  25. You should include the "solution"; otherwise, this thread is useless to others. I assume the solution was to use sc_object::name() method, which returns the full hierarchical name and is accessible in a module as simply name(). It is possible you were needing basename() or kind(). See IEEE-1666-2011 for more information on sc_object.
×
×
  • Create New...