Jump to content

David Black

Members
  • Posts

    690
  • Joined

  • Last visited

  • Days Won

    154

Everything posted by David Black

  1. Please provide more detail (e.g. actual code snippet) in order for a proper response. Q1: What callback? Are we talking about a true callback or an overridden method (erroneously labeled as callbacks by the documentation). Q2: Have you considered using a true UVM callback to fix the problem?
  2. You probably forgot to raise an objection in your run_phase as required by UVM. Also, I suggest you use uvm-1.1d rather than 1.0p1 (very old version and has some "issues").
  3. Timing is part of a transaction so adding delays to the driver is perfectly natural. Many agents have inter-transaction delays modified in the driver's in reaction to attributes of the transaction. Don't get stuck thinking of the transaction as purely a data related object. Transactions are communication, and events (e.g. clocks or acknowledgement signals) are definitely information to be communicated. You could also use a uvm_event triggered from the monitor. Uvm sequences should not be tied to the hardware signals in any manner. Uvm_events are ok. Finally, your delay should be a random variable and then constrained as needed.
  4. I disagree with the approach of putting code into the config object on the basis that the config object is inteded conceptually for configuration and not operation. Don't mix abstractions. In order to synchronize to a hardware signal event, I think it would be architecturally cleaner to add fields to the transaction type (or a derived type) and let the driver do the delay. Consider a transaction class: typedef enum { read_e, write_e }; class bus_trans; rand oper_t m_oper; // read_e, write_e rand addr_t m_addr; rand data_t m_data; endclass if you add an attribute m_delay, you can have the driver use this to create an arbitrary delay. class delayable_bus_trans_t extends bus_trans_t; int unsigned m_delay = 0; //< default no delay endclass The driver could do something like: seq_item_port.get_next_item(req); if (req.delay == 0) begin // Normal transaction end else begin repeat(req.delay) @(vif.cb); end Notice that the driver is not obligated to used every attribute (field) of the transaction. In my example, the driver only does the delay. Of course this depends on the requirements of the interface. You could also have driver fork off a process to wait on the delay and send a response when the delay completed. This would allow other transactions from other sequences to be intermingled while the waiting. So the sequence would be waiting on a response matching the delay request. This depends on whether the delay should be blocking or not. We describe this in the advanced sequences portion of our UVM adopters class. If unable to modify the driver, then I would suggest creating a "side" agent connected to the same interface with a sole purpose of monitoring clocks, and other synchronization. You can then have your sequence call a sub-sequence on the side-agent's sequencer with a transaction to request the delay information. This may seem a bit contrary to the usual notion of a driver, but it keeps the distinction of pin-level interface activity relegated to the driver rather than polluting configuration objects. A monitor could also provide the information, but then you would need to connect an analysis port or add a callback to the sequencer. Remember that the sequence wants to be reusable. Tying it too closely to the hardware violates the separation of concerns and makes it less reusable. This is just one of several approaches. You could also use uvm_event_pool to create a driver clock event, but I think it is less clean. Signal level tasks should be relegated to the driver (BFM) or monitor.
  5. First, ask yourself: Do we really want to be testing timing related issues using functional simulation or would we be better served using static timing analysis (STA)? If you just want to simulate what might happen for a signal arriving late/early, just drive it a clock later/earlier. If you insist on driving a signal asynchronously, I would suggest creating a task to do this... interface my_if(input clock); logic DATA; clocking cb @(posedge clock); default input #1step output #0ns; output DATA; endclocking time period=0, first=0; initial begin // observe/measure clock period for later use @(posedge clock); first = $time; @(posedge clock); period = $time - first; end task async_DATA(logic value, time offset); if (period>0 && offset>period) $warn("Offset greater than clock period."); if (offset == 0) $warn("Possible race situation with zero time offset."); fork @(posedge clock); // starting point for offset #(offset); $info("Driving DATA asynchronously"); DATA <= value; join_none endtask modport test_mp(clocking cb, import task async_DATA(logic value, time offset)); endinterface This approach has several benefits. First, it clearly marks the fact you are doing an asynchronous modification. Second, it requires effort to go beyond the normal synchronous drive. Third, you can see when it happens in the simulation so there are no surprises. In your transaction (uvm_sequence_item), you might want a async_time member that has a normal value of 0 and is set non-zero when invoking this "feature". Debugging asynchronous issues can be a bear. I do understand the occasional need to do this. I would recommend against anything that makes it too easy to generate asynchronous stimulus for something fundamentally synchronous.
  6. I typically use the following code following sc_start(): sc_start(); if (not sc_end_of_simulation_invoked()) { SC_REPORT_INFO(MSGID,"ERROR: Simulation stopped without explicit sc_stop()"); sc_stop(); }//endif That way I always know end_of_simulation() will be invoked. I also put try/catch blocks around both the design instantiation and sc_start itself to be certain I know why my simulation stopped. std::unique_ptr<Top_module> top_instance; //NOTE: Use std::auto_ptr<> for pre-C++11 try { top_instance.reset( new Top_module("top_instance") ); } 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(); // <<<<<<<<<<<<<<<<<<<<<<<<<<<< START SIMULATOR 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
  7. Depends on what you are verifying, what you already have in place, what tools you own, and your expertise... Do you have a SystemVerilog simulator available? Are you verifying SystemC or an HDL (e.g. VHDL or SystemVerilog)? Do you have knowledge of SystemVerilog OOP and/or UVM?
  8. Using unknowns is reasonable. How about driving ~DATA instead of unknown during the first cycle? That way you would see the wrong data getting sampled and you would be able to relate it to the actual data during debug. An advantage to this approach is that you could use it safely on gate-level or even with real hardware later. Unknowns are sort of hard to create in real hardware, and they often create headaches in gate-level netlists.
  9. The new thread safe mechanism added to SystemC was designed to allow interaction between SystemC and other OS threads and processes. It does nothing to improve SystemC processes (SC_THREAD, SC_METHOD, etc). There have been several presentations on the former (look on NASCUG for info). There is also going to be a very interesting talk at this years NASCUG annual DAC users meeting in San Francisco on Monday afternoon (June 2). The meeting is free for attendance. It is an opportunity to talk with SystemC experts about these topics. There is also plans for an informal meeting at DAC, but date/time is not yet confirmed.
  10. Comparing a recent PowerPoint "UVM What's New and what's Next - UVM 1.2 Introduction" to the UVM 1.2 reference manual (draft), I notice that quite a few features are not documented. Looking into the code, I see the features, but they are not advertised. If I am to use these features, I expect them to be documented; otherwise, I would simply be using internal artifacts, which is technically an incorrect approach to using the library. It is my expectation that every feature shown in an official presentation should appear in the documentation with appropriate recommendations (e.g. am I allowed to use the direct calls or am I required to use the macros?).
  11. I like your idea, and you are correct that this is more of a SystemVerilog issue (what was I thinking?).
  12. If you are interested in getting a SystemC netlist (non-graphical) with module hierarchy, then yes the Accellera PoC simulator supports that. I have written a simple netlister several times.
  13. Create an extended that (extend_if) that instantiates the original interface (apb_if). [No, I am not suggesting inheritance. Just create an interface that has an APB_if inside it.] Make sure the base driver/monitor classes have "callbacks" at strategic places in run_phase where you might add extensions. These could be actual UVM callbacks or new virtual methods with empty implementations. No you can extend the driver/monitor class and provide appropriate definitions for callbacks when needed. Of course this is problematic if the base driver/monitor classes are provided by a 3rd party unless you can convince them where to put stuff. This problem is probably not general enough to expect a UVM fix.
  14. It's because inside the braces of the constraint, using the word addr or data by itself does not bind those variables to the local context of your sequence body. The SystemVerilog standard clearly states in IEEE-1800-2012 section 18.7: You might consider using the local:: qualifier if you insist of having those names per: Try: `uvm_do_with(item, { item.addr == local::addr; data == local::data; // item. left off because it is redundant (though may help reader) } ) Your mileage may vary dependent on your simulator vendor and version. local:: was introduced in the 2009 standard.
  15. Actually, you can start a sequence in any phase. It is more important to understand the domain/scheduling relationships between the task based (i.e. runtime) phases. UVM undergoes a number of pre-simulation phases (build, connect, end_of_elaboration, start_of_simulation) that are all implemented with functions. Once those are completed, the task based phases begin. The standard includes two schedules. One is simply the run_phase, which starts executing at time zero and continues until all components have dropped their objections within the run_phase. The other schedule contains twelve phases that execute parallel to the run phase. They are: pre_reset, reset, post_reset, pre_config, config, post_config, pre_main, main, post_main, pre_shutdown, shutdown, and post_shutdown. They execute in sequence. Every component has the opportunity to define or not define tasks to execute these phases. A phase starts only when all components in the previous phase have dropped their objections. A phase continues to execute until all components have dropped their objections in the current phase. Many companies use the run_phase for everything because there are some interesting issues to consider when crossing phase boundaries. In some respects it may be easier to use uvm_barriers for synchronization. Drivers and monitors (things that touch the hardware) are usally run exclusively in the run_phase, but there is nothing to prevent them also having reset_phase, main_phase, etc...
  16. Sequences are uvm_object's; whereas, the driver is a uvm_component. The field automation macros automatic configuration fetching works due to super.build_phase automation. You will need to do two things: Add the following in your sequence: `declare_p_sequencer(SEQR_TYPE) In function pre_start add: uvm_config_db#(string)::get(p_sequencer,"","file_name",file_name); Notice that the information is tied to the sequencer that the sequence is running on.
  17. @Tudor: Many times you are correct that if one thing goes wrong there may be no point in continuing; however, there are failures that are orthogonal to one another. Consider if you add some new IP with associated VIP. The tests in the VIP may reveal some other errors that have nothing to do with your own errors. Hence by letting the simulation go further, you can get twice the opportunity to debug errors. Of course you have to carefully discern this when reading the log file. I agree that many times the simplest approach is to fix one bug at a time. This is more true early in the design cycle of the project. As a product matures, mutiple errors may be worth allowing. This would be a good reason to use set_max_quit_count(). Use a value of 1 early on and relax it later in the project.
  18. First, before I discuss the problems with SystemVerilog, I would like to point out that you are really missing a much simpler solution to your problem: module top; int farray[10]; //fixed array initial begin foreach (farray[jjj]) begin farray[jjj] = $urandom_range(121,0); end $display("******************************"); foreach (farray[jjj]) begin $display("%0d: %0d",jjj,farray[jjj]); end end endmodule : top With respect to "how many elements does my container have?", try the following. Note that you may need to comment out a few lines since the EDA vendor simulators don't all agree on whether some of these should work, and to be fair, the standard is not entirely clear... module top; byte Fixed_array[3]; byte Dynamic_array[] = {10, 20, 30}; string String = "abc"; byte Queue[$] = {40,50,60}; byte Assoc_array[string] = '{"a":70,"b":80,"c":90}; initial $display("Fixed_array size is %0d", $size(Fixed_array) ); initial $display("Dynamic_array size is %0d", Dynamic_array.size() ); initial $display("String size is %0d", String.len() ); initial $display("Queue size is %0d", Queue.size() ); initial $display("Assoc_array size is %0d", Assoc_array.num() ); // Alternate approach initial $display("$size(Fixed_array ) is %0d", $size(Fixed_array) ); initial $display("$size(Dynamic_array) is %0d", $size(Dynamic_array) ); initial $display("$size(String size ) is %0d", $size(String) ); // May not be legal initial $display("$size(Queue size ) is %0d", $size(Queue) ); initial $display("$size(Assoc_array ) is %0d", $size(Assoc_array) ); // Yet another approach initial $display("$bits(Fixed_array ) is %0d", $bits(Fixed_array) ); initial $display("$bits(Dynamic_array) is %0d", $bits(Dynamic_array) ); initial $display("$bits(String size ) is %0d", $bits(String) ); initial $display("$bits(Queue size ) is %0d", $bits(Queue) ); initial $display("$bits(Assoc_array ) is %0d", $bits(Assoc_array) ); // Strange result endmodule The standard attempts to rationalize away this inconsistency at the bottom of page 45 (85 in the PDF) in the IEEE 1800-2012 standard:[/size][/font][/color][/code] I for one don't entirely agree with this rationalization. The concepts are all closely related and should have been unified to make the coders job easier. Actually, $size() appears to work with most of them.
  19. Writing to the config_db should normally be established in the build_phase, which is executed top-down, rather than the run_phase, then I believe it should work.
  20. When considering a many to one solution, keep in mind that depending on the implementation, this could cause havoc if you care about the source of the invocation. For instance, if the imp provides a FIFO then the consumer of the information won't know where the source of the information originated unless the data itself is tagged. Also, it is possible for two accesses to be in the same delta cycle, which results in a race condition.
  21. SystemC TLM is a part of the SystemC standard (both parts TLM1 and TLM2). True, it is an newer addition, but it is never-the-less part of the standard. TLM1 was the first attempt to standardize an API, which worked, but it didn't address the needs of the SystemC community as well as had been hoped. TLM2 standardizes a methodology to model address mapped bus communications and the associated API. It allows for easier exchange of IP blocks for simulation. TLM emphasizes that "ports" are not just wiring connection points, but rather a nexus for higher levels of communication. TLM2 has "sockets", which are really just glorified SystemC port combinations (sc_port & sc_export). TLM2 also standardizes some concepts (even if not stringently) of different styles of transaction level modeling (sometimes called coding styles). For instance, "loosely-timed" (LT) represents "execute as fast as possible while maintaining register functional accuracy"; whereas, "approximately-timed" (AT) means "provide sufficient timing detail to allow bus-level timing analysis[1]". AT does not simulate as quickly as LT because it has to provide extra details and timing behavior. Note 1: Not necessarily the same as clock cycle accuracy. On the other hand, the SystemC core provides the fundamental mechanisms that allow for design encapsulation (sc_module), event-driven simulation (sc_event and wait()), processes (SC_THREAD, SC_METHOD), a notion of simulated time (sc_time) and channels (sc_interface, sc_prim_channel, sc_channel). Channels are one of the most important features and enable abstraction of safe interprocess communications. SystemC also provides the minor addition of hardware datatypes (sc_logic<>, sc_int<>, sc_fixed<>, etc). It also provides primitive communications channels such as sc_signal<> and sc_fifo<>. Thus, the SystemC core provides the foundation needed to implement TLM. Sadly in some sense, SystemC provides a number of simplifications for writing RTL even though it is fundamentally not the strong point of the simulator. To some degree these simplifications are an holdover from SystemC 1.0 for backwards compatibility. I said sad because the simplifications have encouraged many to think of SystemC as an appropriate vehicle for writing RTL code, but then get frustrated at the lack of performance (for RTL). SystemVerilog and VHDL are much better suited for that task. The RTL aspect of SystemC is good in making it easier to interface SystemC to the other languages for co-simulation.
  22. sc_in<> and sc_out<> are specialized ports that use an sc_signal<> channel. sc_signal<> is a primitive channel that makes use of delta delays and has a somewhat surprizing effect from a programmers view. Witness: SC_MODULE(Example) { sc_in<int> a, b int r1; sc_signal<int> r2; SC_CTOR(Example) { SC_METHOD(method_process); } void method_process(void) { // assume a=1, b=2, r1 = 0, r2 = 0; r1 = a + b; r2 = a + b; std::cout << "r1=" << r1 << " r2=" << r2 << std::endl; // prints "r1=3 r2=0 } }; Most programmers would be surprized if not appalled at this behavior. Using explicit write() method reminds us that something special is happening. In languages such as Verilog or VHDL, the second statement would be written: r2 <= a + b; which is less surprizing because you see this weird operator <= and are reminded of the non-blocking signal assignment behavior. Note, I don't mind too much the use of plain a and b vs. a->read() and b->read(); however, adding ->read() does remind us of the special nature of these identifiers. On a related topic, you may notice I use the dagger operator (->) rather than the dot operator (.) for port access. This is because sc_in<> and sc_out<> are specialized ports that happen to have read() and write() methods defined (for backwards compatibility with SystemC 1.0 -- does anybody use this?); however, I often encounter designs that use standard sc_port<> where all the channel method calls must use the dagger operator. So I use -> for all SystemC port accesses as a matter of consistency. Note that the specialized port versions of read() and write() simply call ->read() and ->write() anyhow.
  23. The IEEE-1666-2011 standard, which can be freely downloaded via a link on Accellera.org.
  24. Errr... SystemC is C++. No wrapper needed. SystemC is not a new computer language. It is a library of classes and a methodology for modeling hardware. Not sure what you are really asking. Give an example of your C++ class and what you want to do with it.
×
×
  • Create New...