I am building a UVC and have a question about implementation.
There is a uvm_seq_item class and I defined several fields in there. when I receive those randomized fields in the driver I have decode them and generate a frame to send to the DUT.
its a CAN frame including sof , id, data, dlc , crc … and eof
in the drive based on the value of dlc (which is rand) I have to create a frame.
means : frame.size = dlc
as the code got too long I am thinking of better solution . It gets long because dlc is in the range of 0 to 8 bytes. Besides the id can also be standard or extended i.e different frame size.
I have the code now (even too long ) but I faced a new problem: I have to calculate the crc in the driver and I can only calculate it after randomization , when dlc or id are known.
In order to do that I have to write twice the code I have currently for all possible cases and calculate crc for each separately. Is there any better solution for this problem?
I think you might be doing this the hard way. You should use a constraint block to constrain frame.size == dlc such as:
constraint c_frame_size { frame.size == dlc; }
Your code should be minimal. There is no need for large if-else or case statements. For your data, I have found it easiest to use a queue of bits so the driver can easily pop each bit off the queue. I made a copy or clone of the packet before driving it since pop is destructive. UVM components have built-in copy and clone virtual functions; make sure you override them for your packet class.
For the CRC, you can either write a constraint or use the post_randomize method. However, the Cadence simulator (irun) does not support putting functions in constraints. Therefore, I suggest using post_randomize if you are using Cadence. In my opinion, using post_randomize for calculating CRC makes more sense anyway. CRC is a function of the data packet, not some random value.
Thank you very much for your answer.
There are still some questions:
First I did the same, in the driver I defined an unpacked array and the frame size I defined like this:
for standard frames : frame.size = dlc + constant_a;
for extended frames : frame.size = dlc + constant_b;
But with this scenario the problem was with assigning packed arrays from my seq_item (like dlc or id) to the unpacked array (frame)
the frame is : frame = {sof,id,ide,rtr,r0,dlc,data,crc,ack,eof}
I need to concatinate all these fields inthe driver, how can I use your soliution here: For your data, I have found it easiest to use a queue of bits so the driver can easily pop each bit off the queue → can you explain more.
1- first problem: in the driver I have to decide which and hawmany of the frame bits are dedicated to data. ex. 8 bits of the frame or 16 bits or more(even zero)
2- second problem: id is another factor to decide which frame size(11bits id or 29 bits)
3- even if I use post randomize method crc calculation should be different for all possible cases (combination if 2 id possibilities + 8 dlc possibilities)what is difference if I implement a post_randomize method or implement the crc in the driver?
I use Questasim.
Thanks again for your support.
(1) In your driver, why don’t you also make frame a queue of bit or logic and push bits to it in the correct order. Then you won’t have to worry about keeping up with the size of the (dynamic) array. I much prefer using queues to using dynamic arrays.
(2) If id/dlc determines frame size, then you should put them in a constraint on frame.size().
(3) I don’t understand why your CRC calc is different for different cases. Usually one algorithm is used for the data, regardless of its length. You are correct, the driver could be used to calculate and set the CRC too (overriding the initial value), or you could do it in the body of your sequence. I think the earlier the CRC is corrected, the better, and post_randomize would be the earliest.