Jump to content

All Activity

This stream auto-updates     

  1. Today
  2. That's true. If I want to fully randomize I need to add some extra code in my sequence. It seems that it also causes a performance hit making that solution slower despite less randomization. However, if I want to do a write-delay-read sequence with random address and data I can express that more explicitly instead of constraining variables to be a fix value. In this case the solution with separate transactions becomes faster. In these tests I used randomize() everywhere and the differences are in the percentage range. I more concerned about the difference between randomize() and $urandom which can be a factor 100x.
  3. Yesterday
  4. Roman Popov

    write different types of data in a custom port

    But even this won't fix your error. Because compiler will still complain about assigning sc_logic to double, even if it is in always false branch. What you need is if-constexpr and std::is_same if you have C++17. Or SFINAE, if you don't. Something like this may work: if constexpr (std::is_same_v<T, sc_dt::sc_logic>) { out = SC_LOGIC_Z; } else { out = 0; }
  5. You cannot not check typeid() against a string as this is compiler dependend. What you shoudl do is void write_out{ if(typeid(T) == typeid(sc_dt::sc_logic){ out.write(SC_LOGIC_Z); }else{ out.write(0); } } } But actually this is more a C++ related question, in my experience Stackoverflow is a good source of help. Cheers
  6. Hi, i am creating a new port for a specific purpose, it works very well with the most of datatypes, but i got an error trying to support sc_logic. in this example the behavior is if my_event is detected a write is forced. but if it is an sc_logic I forced sc_logic_z but if it is other datatype I force 0. my intention is to detect if the object is sc_logic or not using typeid(T).name(), what in my operative system is "N5sc_dt8sc_logicE" , but i am getting this error: In file included from ./main.cpp:42:0: ./port_new.h: In instantiation of ‘void sc_out_new<T>::write(T) [with T = double]’: ./stage1.cpp:67:15: required from here ./port_upf.h:194:8: error: no match for ‘operator=’ (operand types are ‘sc_core::sc_out<double>’ and ‘const sc_dt::sc_logic’) out=SC_LOGIC_Z; any idea about how i can write both types using the same class ??? my module: struct numgen : sc_module { sc_out_new<double> out1; //output 1 sc_out_new<sc_logic> out2; ... } my class: Template<typename T> class sc_out_new : public sc_channel { ... SC_HAS_PROCESS(sc_out_new); sc_in_upf(const sc_module_name& nmod) : sc_channel(nmod){ SC_METHOD(write_out); sensitive << my_event } void write_out{ if(typeid(T).name() == "N5sc_dt8sc_logicE"){ out.write(SC_LOGIC_Z); }else{ out.write(0); } } } thanks for the help
  7. Last week
  8. When I failed to see examples of transaction reuse I though that maybe people put their reuse effort elsewhere, for example by moving the pin wiggling functionality (which comes in different flavors) to the transaction class so that the driver becomes more generic. I agree that transactions are data classes and I do want to reuse them so moving the pin wiggling into these classes is not something I want. The visitor pattern is also a way to create a more generic driver while not destroying the potential for transaction reuse. The visitor would remove the need for a $cast.
  9. Being able to do simple reads/writes is indeed a reusable abstraction. I've seen the TLM generic payload but that's also the only attempt for a reusable transaction I've seen. Are there others? To verify a bus interface you need to be concerned about the details but when the focus of your testbench is to verify the functionality which the bus interface is configuring you get far with the simple read/writes. A driver could support both reusable simple read/write, reset, delay and specialized transactions used when fully verifying such an interface. I like to think of the driver as a composition of supported services, some are reused, some are new.
  10. Thanks for your answers @tudor.timi Looking at the examples out there it seems like both the single and double data field approaches are popular. What people prefer depends on their main concerns. You're concerned with the number of if statements but Mentor who takes the double data field approach (https://verificationacademy.com/cookbook/sequences/items) expresses other concerns: I'm also concerned about randomization performance (http://forums.accellera.org/topic/6275-constrained-random-performance) but splitting into two data fields doesn't improve performance. You still have unnecessary randomization of write_data for read requests. All they've done is not making it worse by also randomizing read_data. The corruption risk is related to the shared memory approach of the get_next_item/item_done pattern. They avoid that risk by not sharing the data field but I feel that not sharing request and response objects and use the get/put pattern would be a better approach. UVM supports it but maybe there is a good reason why we shouldn't use it? Since one of my concerns is performance I don't like too many randomized fields that aren't applicable to all commands. The read/write example may not represent a "too many" scenario, it's just a common example where such a problem exists. This gets worse as you add more commands. The address and data fields would for example be completely irrelevant for a reset command. A reset command is also an example of a transaction that would be very reusable if available in isolation. A randomized sec_mode is a property relevant to both read and write so that would not be a reason for splitting. A delay field is also something that is relevant to both reads and writes but it's also reusable so I can see a reason to have that in a separate transaction anyway Summary: I'm not looking for the "best" solution to the read/write example. People have different concerns and I accept that. What I wanted to find out was if people are concerned about performance and reuse in such a way that they would consider alternatives to the all-in-one sequence item. If I understand you correctly you wouldn't use the all-in-one pattern for heterogeneous protocols (A "too many" scenario)?
  11. Hi @AmeyaVS I have solved this problem. This runtime error shows up when I try to trace out the wave of sc_fifo. Use the built-in trace() method of sc_fifo instate of sc_trace() solving this problem. #include "system.h" SYSTEM *top = NULL; int sc_main (int argc, char* argv[]) { top = new SYSTEM("top"); sc_trace_file *tr= sc_create_vcd_trace_file("pe"); sc_trace(tr,top->clk_sig,"clock"); top->Input.trace(tr); top->Output.trace(tr); sc_trace(tr,top->rst_sig,"rst"); sc_core::sc_report_handler::set_actions( "/IEEE_Std_1666/deprecated", sc_core::SC_DO_NOTHING ); sc_start(); sc_close_vcd_trace_file(tr); return 0; }
  12. I agree with Bas, recently integrated a model to UVM driver/component using standard TLM socket (simple_initiator_socket), tried with TLM put port first but didn't work. -RC
  13. Hello @chatbq, There is not enough context, probably the exception is being thrown from another module. Overall the code seems fine. You can try and see from where the exception is being thrown from the debugger. Regards, Ameya Vikram Singh
  14. Hi everyone, I have a runtime error when trying to simulate a sc_module An example of my code architecture is presented hereunder, do you see any problem? Here is my error: Error: (E519) wait() is only allowed in SC_THREADs and SC_CTHREADs: in SC_METHODs use next_trigger() instead In file: ../../../src/sysc/kernel/sc_wait.cpp:94 pe.h #include "systemc.h" template<typename IN_T, typename OUT_T> SC_MODULE (pe) { sc_in<bool> clk; sc_in<bool> rst; sc_fifo_in<IN_T> Input; sc_fifo_out<OUT_T> Output; void pe_proc(); SC_HAS_PROCESS(pe); pe(sc_module_name name_, int p_time_) : sc_module(name_), p_time(p_time_) { SC_CTHREAD(pe_proc, clk.pos()); reset_signal_is(rst, true); } private: int p_time; }; template<typename IN_T, typename OUT_T> void pe<IN_T, OUT_T>::pe_proc(void) { IN_T in_val; OUT_T out_val; // Reset code // Reset internal variables in_val = 0; out_val = 0; // Reset outputs wait(); while (true) { // Read inputs in_val = Input.read(); // Algorithm code for (int i = 0; i < p_time; i++) { wait(); } // write outputs out_val = (OUT_T) in_val; Output.write(out_val); } }
  15. Hello All I am trying to list out all the ports, sockets in a given SystemC platform. For that I am traversing the hierarchy using sc_get_top_level_object/get_child_object and able to list out all the ports and sockets. But for TLM 2 sockets I get two entries there for example - top_inst.init_inst.initiator_socket - top_inst.init_inst.initiator_socket_export_0 and - top_inst.memory_inst.target_socket - top_inst.memory_inst.target_socket_port_0 It is obvious because each TLM2 socket internally have one port and one sc_export. Is there a way that I get only those sockets which are visible in SystemC model header file for example I want to have only the following - top_inst.init_inst.initiator_socket - top_inst.memory_inst.target_socket Thanks Khushi
  16. Hello All I am trying to understand the hierarchical events and for this I created a SystemC class which contains a sc_event object. - How I can control an event to make it hierarchical or non-hierarchical ? -What is the example use case or hierarchical events. Can anyone help me on this ? Thanks Khushi
  17. Earlier
  18. tudor.timi

    Transaction Design Patterns

    Regarding point 4: If you want reusable abstractions, one of them is "register/memory accesses". Most hardware blocks use bus transactions to update/query special function registers or memory locations. This is also an abstraction that software/firmware engineers understand. You should look into that. There is so much variation in bus protocols that it's difficult to talk about a universal abstraction. It's also mostly pointless, as when you're talking about verifying bus level aspects, you're interested in the details of that bus protocol.
  19. tudor.timi

    Transaction Design Patterns

    The blog post you quoted w.r.t. working with types is correct regarding " The correct thing to do from an OOP perspective is to create a virtual function ", but not regarding the further points. In that case, where a protocol uses heterogeneous transaction types (i.e. different kinds have different properties), you're better off using the visitor pattern. The transactions would have a virtual function accept function.
  20. tudor.timi

    Transaction Design Patterns

    Regarding point number 3, I don't see why the coupling between transaction, driver and monitor is a bad thing. If you treat transactions as mere data classes, the behavior based on this data will have to be implemented in a different class. Should a transaction know how to drive itself and how to monitor itself? Should it also know how to cover itself? What if you have to add another operation, like tracing itself in a waveform viewer? Do you add that to the transaction class too? This violates the single responsibility principle.
  21. tudor.timi

    Transaction Design Patterns

    Regarding point number 1: Transactions aren't supposed to model traditional classes (not sure what the correct term for such classes is), which contain behavior (i.e. methods) and make use of polymorphism. Transactions are data classes, where you bundle information together to pass around, similar to plain old structs. Contrast the following examples: // Bad design // Using tag classes, where a "tag" field controls the behavior of methods is a code smell class service; direction_e dir; function void do_stuff(); if (dir == READ) do_read(); else do_write(); endfunction endclass // Better design, have two classes interface class service; pure virtual function void do_stuff(); endclass class read_service; virtual function void do_stuff(); // do read stuff endfunction endclass class write_service; // ... endclass In the case above, it makes sense to create different classes for handling reads and writes, because you have a common abstraction (doing stuff), which comes in two different flavors. How would you handle processing different kinds of transactions in a driver (for example) if you had different classes for read and for write? You'd need to cast, which is very frowned upon (at least in the software world). My point about transactions being data classes isn't strictly true w.r.t how they are currently used in the industry. Transactions are also used for randomization, which is a polymorphic operation. Even here though, assuming you want to generate a list of transactions, where some of them are reads, some of them are writes, it will be impossible to do this in a single step if you build up your class hierarchy in such a way that you have a 'read_transaction' class and a 'write_transaction' class. This is because you can't choose an object's type (and I mean from the point of view of the compiler) via randomization. Finally, why is 'direction' the field you choose to specialize on? Assuming you would also have another field in your transaction class called 'sec_mode', which could be either 'SECURE' or 'NONSECURE', would you be inclined to say that you need to create a 'secure_transaction' and a 'non_secure_transaction' because they are different things? Because you also chose to specialize based on direction, would you have 'secure_read_transaction', 'secure_write_transaction', 'nonsecure_read_transaction' and 'nonsecure_write_transaction'? What would happen if you would add another field called 'priviledge_mode', which could be 'PRIVILEGED' or 'UNPRIVILEGED'?
  22. tudor.timi

    Transaction Design Patterns

    Regarding point number 2: Having both a write_data and a read_data field in the transaction is bad design. A field called data would be sufficient and it would contain that data being transmitted in that transaction, whether it is a read or a write (i.e. regardless of what direction that data flows). The direction field tells you whether you're dealing with read_data or with write_data. Having both fields makes for a pretty difficult to use API if you want to do things irrespective of the direction: if (trans.direction == READ) do_stuff(trans.read_data); else do_stuff(trans.write_data); You'll find your code repeating these conditional statements all over. Contrast this to the case where you only have data: do_stuff(trans.data);
  23. https://matthieu-moy.fr/sc-during/doc/html/index.html I have found some library, which for the first look sound interesting and useful Is there any collective experience with it?
  24. Grisha

    Build error SystemC 2.3.3 with C++17

    +1. I tried to understand why I can't build under c++14 very long. Until I found this post. Thank you.
  25. From the standard: "Tagged? Incoming interface method calls are tagged with an id to indicate the socket through which they arrived."
  26. I have a multipass through target with nb_btransport_fw registered. init1 (target) init2 (target) Something like this target.register_nb_transport_fw( this, &top::nb_transport_fw); tlm::tlm_sync_enum nb_transport_fw(int id, tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_time& delay){ } does the id parameter identify the incoming initiators or is it the id of the target socket which means this is stuck at 0?
  27. Use the appropriate target convenience socket.
  28. I have two multipass through initiators bound to same target. Is there a way to know the id of calling initiator?
  29. The list of open source UVM repositories can also provide an answer to question 4. I couldn't find any well supported (project with many stars) library of sequence items. There are many verification components for various bus protocols but they all have a single sequence items tailored specifically for that bus. This leads me back to question 3...
  1. Load more activity