Jump to content

All Activity

This stream auto-updates     

  1. Yesterday
  2. 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.
  3. 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.
  4. 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)?
  5. Last week
  6. 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; }
  7. 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
  8. 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
  9. 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); } }
  10. 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
  11. 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
  12. 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.
  13. 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.
  14. 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.
  15. 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'?
  16. 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);
  17. Earlier
  18. 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?
  19. 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.
  20. From the standard: "Tagged? Incoming interface method calls are tagged with an id to indicate the socket through which they arrived."
  21. 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?
  22. Use the appropriate target convenience socket.
  23. I have two multipass through initiators bound to same target. Is there a way to know the id of calling initiator?
  24. 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...
  25. The blog post also touches my third question although not providing an answer
  26. Looking at open source UVM repositories I think it safe to say that keeping all transaction types within the same sequence item class is the most common design pattern (the only pattern I found when looking at many of these repos). Luckily, I also found an interesting blog post about type handles that address what I'm looking for. There is a way of doing what I'm looking for although standard practice seems to be something else. I guess that keeping everything in one packet is more convenient. I think this answers my first question.
  27. Well, without lnowing the implementation it is hard to tell. I suppose your initiator sockets are connected to target sockets at he bus and the initiator sockets of the bus are connected to the target sockets of your target components. All these sockets need to be bound to each other (by calling bind() or the operator() function). There is no concept of bind-by-name in SystemC. Maybe you should have a look here: https://www.doulos.com/knowhow/systemc/tlm2/tutorial__3/ Sockets need to be bound except they are declared with the appropriate binding policy (the 4th template of the sockets). If this is not the case you need to create dummy targets.
  28. I'm guessing you are trying to read the signal values immediately after calling write(). That won't return the values just written due to how update semantics work with primitive channels in SystemC. To make sure this is the cause of confusion, you can try creating a thread in your model where the signal values are written and read back after a delta-cycle wait: SC_MODULE(some_module) { sc_signal<pixel> p1; sc_signal<pixel> p2; void some_thread() { p1.write(pixel(1, 2, 3)); p2.write(pixel(4, 5, 6)); // Read and print p1 and p2 // Values won't be updated here wait(0, SC_NS); // Read and print p1 and p2 // Values will be updated here };
  1. Load more activity
×