Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


tudor.timi last won the day on July 10 2017

tudor.timi had the most liked content!

1 Follower

About tudor.timi

  • Rank

Contact Methods

  • Website URL

Profile Information

  • Gender
  • Location

Recent Profile Visitors

2,080 profile views
  1. Seems like a tool limitation. Create a variable of type event and assign the result of the function call to it. Use this variable in the @(...) statement. Note: a better place for this type of question is /https://stackoverflow.com/. Use the system-verilog tag when posting a question.
  2. 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.
  3. 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.
  4. 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.
  5. 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(
  6. 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_
  7. Hi Tudor

    Please can you help me with the RAL register read.

    I have multiple register in my design for which i have generated the RAL model  and i want to read all the register using reg_map ?

      // Get all the registers in map

      foreach(map) begin
        map.read(status, reg_rdata,.map(map), .parent(this));

    I tried doing this but i am getting following error -

    Could not find member 'read' in class 'uvm_reg_map'

    Can you suggest how to do read to all the registers in RAL model.


  8. You're using 'var' as a variable name, but this is an SV keyword. Try naming your variable something different: fork automatic int idx = i; // ! `uvm_do_on(eseq_inst[var], p_sequencer.master_sequencer[var]) join_none
  9. The philosophy behind nested classes is that they have access to private members of the parent class. If you want to do scoping, you're better off using packages (though it's not possible to define a nice hierarchical structure of packages).
  10. Are you trying to compile it on Windows? I don't think QuestaSim supports DPI under Windows (or at least not easily). At the same time, you don't really need to compile UVM itself when running QuestaSim, because the simulator comes packaged with the library and can reference that. * You can change the Makefile to not compile UVM anymore, only the testbench code for the example. * You can also disable DPI by adding the UVM_NO_DPI define (here you might also need to remove the lines from the Makefile that try to compile the C code). * Finally, what's missing there is the path to '
  11. The second argument for new(...) is the number of memory locations. You should call: new(..., 2048, 64, ...);
  12. It's not clear in this case what 'valid' means. I don't understand why in your case, when the model would generate '0100', the DUT will respond with '0101' after a '0101'.
  13. The "env.spi_m[0].reg2spi_adapter.*" won't work in there, because the adapter doesn't know under which env it was instantiated. You can check this by calling get_full_name() from the adapter. That's what you need to pass as a context.
  14. When using RAL like this, items aren't created by your agents, but by the adapters interfacing with those agents. If you set up the contexts properly when creating items inside your adapters, it's going to be possible to do instance-based overrides: class spi_adapter extends uvm_reg_adapter; function uvm_sequence_item reg2bus(...); // notice the 'get_full_name()' here spi_item bus_item = spi_item::type_id::create("bus_item", null, get_full_name()); // ... endfunction endclass The extra argument to create(...) sets the context for items create under the adapter as being "<
  • Create New...