Layered sequencers - any possible way to pass dynamic constraints between the running sequences?

Ok, so typical layered sequencer would have the “lower” sequencer’s sequences getting it’s items from the “upper” sequencer via a port like this:

 p_sequencer.upper_seq_item_port.get_next_item(temp);

Does anyone know of a way that the lower sequencer could dynamically pass a constraint to be used by the upper sequencer in it’s randomization of it’s delivered item? For example, something akin to the following?

 p_sequencer.upper_seq_item_port.get_next_item(temp) with (someconstraint);

I’ve not been able to find something like this anywhere so wondering if it’s even possible.

Maybe the easiest thing it to just re-randomize the upper item once it’s received (temp in this case) with the new constraint?

In reply to russ.petersen@broadcom.com:

What you normally want to do when layering is to convert from one higher level protocol to another lower level protocol. There might not be a 1-to-1 mapping between the higher level item and the lower level item, so you’d let constrained randomization fill in the gaps in those cases. The flow of information is in any case top → down.

What you want means going against the flow. Normally when you want to send information like this you use the response path for the sequencer/driver communication. I wouldn’t re-randomize the item in the lower layer, because that would mean you’d have a mismatch between what your high level sequence thinks it’s doing and what your lower level sequence is actually sending to the driver.

Maybe if you describe your use case more specifically you can get some better suggestions.

In reply to Tudor Timi:

Hmmm… Turns out the re-randomizing is not working anyways as the new item is screwy (ie: invalid results being created). I’ll have to debug that further to understand why.

Anyways,

Here is an example where you might use a layered approach and want to apply a constraint:

First sequencer: creates ethernet frames
Second sequencer: creates ipv4 frames which go into the ethernet frames

ipv4 frames creation will need some input from the ethernet frame sequence since the size of the embedded ipv4 frame is going to be constrained by the randomized values of the eth_frame (such as total length, mtu size, whatever…). Hence, the generation of ipv4 frames is linked to the randomization of the eth frame. Of course you could just do all of this in a single sequencer and not two layered ones but this represents the kind of dilemma I’ve having in my own situation…

In reply to russ.petersen@broadcom.com:

You mean something along the lines: “I can offer you this Ethernet frame to transport your IPv4 frame in, make it fit in here”? I don’t work with these protocols, but my limited understanding would be that if you get an IP frame that’s too big, you split it into more Ethernet frames.

In reply to Tudor Timi:

Yep, that’s right but I assume you are saying to pass the eth_frame to the ipv4_frame sequence? That works in simple cases but ethernet frames can get complex and even if, for example, you set the total mtu at the eth level other things may randomize in the lower levels that make it impossible for that length to be exactly obeyed. In other words, strict top-down build of the ethernet frame would get pretty complex and unwieldy for some cases.

Probably the answer is don’t use layered sequencers in this way but rather combine the two classes (ie: eth_frame and ipv4_frame in this case) into a single sequence generator.

Another options would be to parameterize the constraints of an extension of the ipv4_class and then use that class in the ipv4_sequencer and adjust the values of these parameters via a response to the ipv4 sequencer. Not really a great way though and pretty limiting but it would work.

I think I have my answer in that it’s just not possible or mabye even really “uvm’ish” to be passing an item constraint from one sequence to another. I can see the logic of that but also see it as limiting too. Believe ‘e’ would have the same problem but not sure…

In reply to russ.petersen@broadcom.com:

Hi Russ,

I Tudor introduced me to layered sequencing earlier this year, and I have adopted the technique since. It sounds like you have run into some of the same things I have. I am using to apply TCP/IP on the LocalLink physical interface. My interpretation of the technique is that I create “high level” transactions, for example, an ARP, UDP, IP, etc, and pass that into, say, the IP_2_Eth agent (to it’s sequencer). The next sequencer immediately sees this, and pulls in the IP transaction, and stuffs it into the payload of an ethernet transaction. Next, my physical interface agent (LocalLink in this case), snags the Ethernet transaction, and builds low level LocalLink transactions. Point being, I rarely create Ethernet packets. I start out with the higher level protocols, and stick those into the pipe. Then each section (an agent) of the larger “layering agent” can build the next level of the protocol (and randomizing the new layer). It sounds a little like you are first making an Ethernet transaction, and then trying to stick the IP transaction into that (which is the opposite direction).

About the constraints; if you have constraints that aren’t changing, you can place them in-line in the translation sequences. Some of my translation sequences don’t even randomize the new transaction type. For example, when I create an Ethernet packet after an ARP packet appears in the downstream sequencer,

right_txn.payload=left_txn.pack8(); // assign ARP packet -> Ethernet payload

// configure the Ethernet packet (nothing to randomize)
right_txn.EthType=ARP;
right_txn.sMAC=left_txn.sMAC;
right_txn.dMAC=left_txn.dMAC;

But, going from IGMP to IP (in-line constraint):


      array=left_txn.pack8();  // pack transaction
      array_len=$size(array); // record the length

      // construct a new IP packet
      right_txn=ip_transaction::type_id::create("right_txn");
      right_txn.payload=array; // assign to payload

      right_txn.payload.rand_mode(0); // lock existing payload values
      if(!right_txn.randomize() with {
        payload.size==array_len; // lock payload array size
        IpProt==IGMP;
        left_txn.igmp_type==IGMP_QUERY   -> dIP==IGMP_MULTICAST_ALL_HOST_IP;
        left_txn.igmp_type==IGMP_REPORT  -> dIP==left_txn.grp_addr;
        left_txn.igmp_type==IGMP_INVALID -> dIP==left_txn.grp_addr;
      }) `uvm_fatal(report_id,"right_txn randomize() failed!")

For any constraints that may change, or are not appropriate all the time; in my case, I want to set the destination MAC address of my ethernet packet, I simply extended the Ethernet transaction class, set the constraint, and used the factory to substitute it.

In reply to bmorris:

Yeah, I want to go top-down. Created this structure before for Cisco but in that case we just put all classes together into a single generator, ie: ipv4, ipv6,eth_frame etc… all were part of the same generator item package. Might be the best way to go to drive things top-down like I want. I was just experimenting with the concept of breaking it into separate sequencers. Additionally I have another case (not Ethernet) where the separate sequencers would make more sense but again, might have to modify my plans. Thks for the replies.