Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by tudor.timi

  1. They don't go to X. That's just to show you that the positions where you put UVM_NO_CHECK (regardless of what access policy they have) are treated as "don't care". Your problem there is that there are some checked bits that don't match. I see an 8 and a 1e in the value read from the DUT, but I see a 0 and an fe in the mirrored value.
  2. You're on the right track with get_full_name(), but you should do one small change: this.cd = command_descriptor::type_id::create("cd", null, get_full_name()); This way you pass a short name ("cd") as an object name and no one can complain. You don't have any component to pass in as a parent if you're starting the item in a sequence (as sequences are also objects), which is why we pass null. Instead of getting the context from a component, you can just pass it in directly with the third argument. In order for this to work, the sequence also has to have been created with a context.
  3. I'd be careful when comparing frontdoor with backdoor, seeing as how frontdoor accesses will take simulation cycles to complete (backdoor is done in 0 time). That extra time that needs to be simulated will also affect the total job length. The frontdoor also has the extra overhead of triggering your bus UVC(s) and the sequencers/drivers/etc. will also slow down your simulation. A fair comparison in terms of simulation length would be with "RAL and frontdoor" against "no RAL and native bus sequences" that do exactly the same thing. It's probably going to run faster without the RAL, but "how
  4. I'm trying to declare a memory like this: class some_mem extends uvm_mem; function new(string name = "some_mem"); super.new(name, 2 ** 24, 8, "RO"); endfunction endfunction Later on, I'm trying to add this memory to an address map that was created like this: default_map = create_map("some_map", 0, 4, UVM_NO_ENDIAN); By using the default value for the byte_addressing argument I want each address to represent a one byte location. The problem I'm seeing is that the uvm_reg_map_info associated with this memory shows an end address of 32'03ff_ffff and a stride of 4, instead of 32'00ff
  5. I don't see why doing a read would be bad form, seeing as how this is most probably how the real software would work. The fact that you have the state of a register stored and can rely on it is a "nice-to-have". If you want to do RMW, what you want to ensure is that this is treated as an atomic operation, i.e. there are no other accesses in between. To do this you can grab your register sequencer before doing the read and ungrab it after doing the write.
  6. I'm not sure how arbitration works at the register read/write level, but if you have 2 writes scheduled because the bus sequencer is busy with some other transaction, I could imagine that you can run into some "unexpected" behavior. I could see a scenario where the following happens: - bus sequencer is busy doing some item - thread 1 does field1.set() and starts waiting - thread 2 does field2.set() and starts waiting - item finishes on bus sequencer - thread 1 gets the sequencer, writes the val (reg with both fields set) - thread 2 gets the sequencer, writes the same val as thread1 wr
  7. True. Objections are used as an end-of-test mechanism, to make sure that the simulation doesn't stop prematurely. The flow of execution in a UVM simulation goes through all of the phases anyway, so objections are only useful to make sure that the run_phase (or its sub-phases) don't end too early.
  8. If you're a Cadence user you get HAL (HDL Advanced Linter I guess it's called, but don't let the name fool you, it can do HVLs too) included with Incisive.
  9. Using the UVM pools is a shortcut you can take, but it might hurt you further down the line. Consider the case where you wouldn't pass the monitor handle to your sequence and use the uvm_event_pool instead. You wouldn't be able to tell by just looking at the class declaration that it has an external dependency. You'd have to read the body() method to see that at some point it's waiting on event from outside. Even in your current setup, it might be cleaner to get a uvm_event handle from the monitor and not the monitor itself, as that would show that you only need the event and nothing more.
  10. What I ended up doing was creating my own subclass of uvm_reg_predictor that handles UVM_NOT_OK. I don't have access to the code right now, but it should be pretty easy for you to do by just having a quick look at that class.
  11. You might get a faster answer if you shortly explain what this wait_if_stopped(...) method should do.
  12. Now that Robert mentioned it, I also remember seeing VIP from one vendor that did such a separation of concerns. An active agent would be used to drive stimulus on an interface with a handshake mechanism. A passive agent hooked onto the same interface would monitor the DUT's handshakes and check that everything is in order. You could tap any of the monitors to feed the scoreboard, since they both collect the same thing.
  13. Regardless of what you do, you can't do randomization in one pass (because of the limitations discussed above). I'd probably also go with the latter because it's the same thing you did with the other layers and it's nice to be consistent.
  14. It's unclear to me what you mean. Do you have a device with two (almost) identical interfaces, where traffic flow only in one direction? _______ IF1 | | IF2 ---->| DUT |----> |_______| In this case it makes sense to instantiate 2 agents, because you have 2 different wire bundles. If not, do you have only one bidirectional interface? _______ IF1 | | <--->| DUT | |_______| In this other case you only need one agent. You can have one monitor feed the scoreboard through an analysis port and the scoreboard itself would figure out what
  15. It would be nice to get a Mantis item filed from it then and get it fixed in a future version of the standard.
  16. I was just reading the 1800-2012 standard and I've come across something that strikes me as a possible contradiction. In section 18.8 Disabling random variables with rand_mode() it states that Later on, when an example is presented, I see the following code snipped: The comment states that packet_a.rand_mode(0) disables randomization for all variables inside the object, which is against the statement from above. Could anyone who's part of the SV committee shed some light on the issue?
  17. I don't really get why you would like to statically set the IP address in one run, but of course you could do that. You can just use inheritance and the factory to set an override to a type that does your desired functionality. For example, I'd do something like this: class transport_to_ip_sequence extends uvm_sequence; // ... body method and other stuff // the body method calls this function to get an IP packet from a // TCP/UDP packet function ip_packet convert_transport(transport_packet packet); if (packet.protocol == TCP) return convert_tcp(packet); else
  18. We're also comparing apples with oranges here in this thread. A reference in C++ is a different concept from a reference (to an object) in SystemVerilog (which is more like a reference in Java). SystemVerilog decided to take elements from both languages (the pass by whatever semantics of Java when passing objects together with allowing pass by value and by reference as in C++) and mix them into a nice soup of confusion. Java doesn't allow immutable arguments (because there "the general ideology is that access policy to the state of an object is controlled by the class" - according to this
  19. @puneet You're half right with your hierarchical immutability statement. The C++ compiler doesn't follow through pointers and references, but if I have a data member defined that is an object, then I can't change any of its fields. Here's a snippet of C++ code I've tried this out with: #include <iostream> struct some_inner_struct { int some_inner_field; some_inner_struct() { some_inner_field = 0; } void print() { std::cout<<"some_inner_field = "<<some_inner_field<<std::endl; } }; struct some_struct { int some_field; some_inner_struct some_o
  20. Oh, now I get what you meant. Yes, you just randomize your UDP packets and start them on the 'A' sequencer. From that sequencer it's going to be picked up by the translation sequence running on the 'B' sequencer. In your translation sequence you'd have something like: forever begin // get a UDP/TCP item from the 'A' sequencer up_sequencer.get_next_item(t_layer_item); ip_packet = my_ip_packet::type_id::create(); start_item(ip_packet); // convert from UDP/TCP to IP if (t_layer_item.protocol == UDP) begin // set IP address of 'ip_packet' // set contents, etc. end
  21. Let's start with question 2 first since it's easier to answer. As you correctly pointed out, you can start items on any of the A/B/C sequencers, allowing you to work at the level of abstraction you need. For example, you might figure out that you need to write some raw Ethernet traffic where you send some corrupted frames to check the DUT's error handling. Same for IP, etc. This also allows you to run other protocol over Ethernet that aren't as abstract as TCP/UDP (as you mentioned, ARP). Regarding question 1, I don't really know all of the details. I don't work with networking chips and t
  22. Normally, an Ethernet frame doesn't care what it's transporting (i.e. what's in its payload). The moment you start saying that you want an Ethernet frame that contains an IP packet with a certain IP address and so on it's clear that you're thinking at a higher level of abstraction. What you're interested more is in the IP fields and it makes sense to separate these from the Ethernet fields. In your context, layering would mean having individual items for each layer. At the top you'd have TCP and UDP items. The middle layer would consist of IP (v4 and/or v6) item(s), ARP, etc. At the very b
  23. It's a well known limitation of SystemVerilog that you can't do any kind of casting inside constraints, which means that it won't suffice to just have a handle for all payloads. You'd need one handle to each type of payload to be able to reference the fields defined under each specific payload type: class ethernet_frame; // ... rand ip_payload ip_pload; rand arp_payload arp_pload; endclass Afterwards, we hit the next limitation, due to which we're not allowed to create objects during randomization. I wouldn't do this in post_randomize() as this would hurt us later: class ethernet_f
  24. Oops, I opened my mouth too soon and I didn't notice we were talking about constructors. Here's what the standard states here: This means you can't pass the length to the constructor. I see to ways around it: 1. Use the same `define you're using in the top level TB in the constructor call: super.new(name, `NUM_TIMERS, UVM_NO_COVERAGE); 2. Use a type override. Define a generic regs_counter_e_reg and override it with a specific version where the length is set by a parameter: class regs_counter_e_reg #(int length) extends abstract_regs_counter_e_reg; // ... registration ...
  25. The call to super.new(...) doesn't have to come first. You can call it any time you want (in your case after getting the config).
  • Create New...