Creating protocol transfers

Hi,

I am trying to build an AHB vip, just to get hold of the basics of UVM.
I am finding difficulty in randomizing the various AHB protocol signals. For e.g, I can randomize HBURST type , HSIZE type and the starting address. But how do i randomize or create the HTRANS, HADDR for the same burst type (number of HADDR, HTRANS is going to chnage based on the randomized HBURST type). Also, my HADDR values will change, either incremented by 4 or 8 or etc, base on burst type and HSIZE; similarly the HTRANS values can be BUSY and SEQ for burst transfers whereas NSEQ and IDLE for single transfers.

I am presently handling such things in the driver by generating a loop for the number of beat transfer as dictated by HBURST, HSIZE type. But i am not sure whether that is the right way. What will be the best way to handle this?

A sample code will be very helpful.

Thanks.

Hi, Debjit

Here is an example below. You can see how parity is generated in the post_randomize function. Your concerns on HADDR in your situation is the same, I think.

// Parity Type Control knob
typedef enum bit {GOOD_PARITY, BAD_PARITY} parity_e;

class uart_frame extends uvm_sequence_item; //lab1_note1
// UART Frame
rand bit start_bit;
rand bit [7:0] payload;
bit parity;
rand bit [1:0] stop_bits;
rand bit [3:0] error_bits;

// Control Knobs
rand parity_e parity_type;
rand int transmit_delay;

// Default constraints //lab1_note2
constraint default_txmit_delay {transmit_delay >= 0; transmit_delay < 20;}
constraint default_start_bit { start_bit == 1’b0;}
constraint default_stop_bits { stop_bits == 2’b11;}
constraint default_parity_type { parity_type==GOOD_PARITY;}
constraint default_error_bits { error_bits == 4’b0000;}

// This method calculates the parity
function bit calc_parity(int unsigned num_of_data_bits=8,
bit[1:0] ParityMode=0);
bit temp_parity;

if (num_of_data_bits == 6)
  temp_parity = ^payload[5:0];  
else if (num_of_data_bits == 7)
  temp_parity = ^payload[6:0];  
else
  temp_parity = ^payload;  

case(ParityMode[0])
  0: temp_parity = ~temp_parity;
  1: temp_parity = temp_parity;
endcase
case(ParityMode[1])
  0: temp_parity = temp_parity;
  1: temp_parity = ~ParityMode[0];
endcase
if (parity_type == BAD_PARITY)
  calc_parity = ~temp_parity;
else 
  calc_parity = temp_parity;

endfunction

// Parity is calculated in the post_randomize() method //lab1_note5
function void post_randomize();
parity = calc_parity();
endfunction : post_randomize


Regards,
Yao he

In reply to yaohe:

Hi,
Thanks for sharing the code. I understand the code and how parity is calculated based on the randomized payload.
But my question is different. Let me give you a snippet of my code that i have written so far for the AHB master:

class driver extends uvm_driver…

task run_phase();

while(1) begin
seq_item_port.get_next_item(req);
req.print();
if($cast(pkt,req)) begin
for(i=0;i<pkt.beats;) begin
if(ahb_if.cb_master.HREADY) begin
ahb_if.HWRITE = pkt.HWRITE;
ahb_if.HBURST = pkt.HBURST;
ahb_if.HSIZE = pkt.HSIZE;
ahb_if.HPROT = pkt.HPROT;
ahb_if.HTRANS = pkt.HTRANS[i];
ahb_if.HWDATA = $random;
i=i+1;
end
@(posedge ahb_if.HCLKM);
end
end
else begin
`uvm_fatal(“CASTERR”, $sformatf(“AHB packet couldn’t be cast”));
end
seq_item_port.item_done();
end

endtask
endclass

class ahb_sequence extends uvm_sequence…
rand logic [31:0] HADDR;
logic [ 1:0] HTRANS ;
rand logic HWRITE;
rand logic [ 2:0] HSIZE;
rand logic [ 2:0] HBURST;
rand logic [ 2:0] HPROT;
//logic [31:0] HWDATA [$];
int beats, addr_incr;
logic [31:0] beat_addr;

function void post_randomize();
beats = 0;
case(HBURST)
3’b000 : beats = 1;
3’b011 : beats = 4;
3’b101 : beats = 8;
3’b111 : beats = 16;
endcase
case(HSIZE)
3’b000 : addr_incr = 1;
3’b001 : addr_incr = 2;
3’b010 : addr_incr = 4;
3’b011 : addr_incr = 8;
endcase
beat_addr = new[beats];
HTRANS = new[beats];
HTRANS[0] = 2’b10;
beat_addr[0] = HADDR;
foreach(beat_addr[i]) begin
if(i>0) begin
HTRANS[i] = 2’b11;
beat_addr[i] = beat_addr[i-1] + addr_incr;
end
end
endfunction
endclass

In the above example, i cannot directly randomize my HTRANS because set of values and the number of values is completely dependent on HBURST. Example, if HBURST = INCR4, HTRANS should have values (NSEQ, SEQ,BUSY) and the number of such values should be 4. For HBURST = INCR8, HTRANS set should have 8 values. If HBURST=SINGLE, HTRANS can be {IDLE, NSEQ} and number of values in the set is 1. What i am trying to say is the number of values to be gathered for a particular variable is not fixed, hence i cannot randomize. Similar is the case for HWDATA (hence i am handling that in the driver). I can still handle HADDR by randomizing the starting address and using addr_incr to increment the address based on the HSIZE.

My question is what is the best way to do that. Also, how to handle weights while randomizing? Like I want HBURST tobe 40% of type INCR4 and remaining 60% of type INCR8.

Thanks.

In reply to Debjit:

Hi, Debjit

  1. Please ignore my answer. I read the AHB protol just now. I see that HTRANS[1:0] and HWDATA[31:0] are tightly related to the timing of operation. I will put them in driver like the way you did. Expecting another solution.

  2. The way to handle weights while randomizing I see in book ‘systemverilog for verification’. Is this what your need?

constraint c_dist {
src dist {0:=40, [1:3]:=60 };
// src = 0, weight = 40/220
// src = 1, weight = 60/220
// src = 2, weight = 60/220
// src = 3, weight = 60/220
dst dist {0:/40, [1:3]:/60};
// dst = 0, weight = 40/100
// dst = 1, weight = 20/100
// dst = 2, weight = 20/100
// dst = 3, weight = 20/100
}