Jump to content

imajeeth

Members
  • Content Count

    6
  • Joined

  • Last visited

  • Days Won

    2
  1. Use +UVM_VERBOSITY=<your option HIGH/LOW/MEDIUM/DEBUG> on command line.
  2. Write a constraint for that. The idea is, for each element in the array, you iterate through all the elements of the array. If the index don't match, the make sure the values are not equal. This is O(n^2) complexity, there could be a better way of accomplishing the same as well. constraint c_unique_array_value { foreach(id_array) { foreach(id_array[j]) { if(i != j) id_array != id_array[j]; } } }
  3. I was under the assumption that once bins are created, the coverage would be collected only for those bins and the remaining combinations would be ignored. However, I noticed this was not the case when using intersect. Intention: Assuming there are 3 banks (0,1,2) and 3 requestors(a,b,c). I wanted to write a coverpoint that covers the case where all 3 banks are active at the same time. Example 1: No bins for coverpoints and use intersect for cross coverpoint cp_bank_0_hit: coverpoint req_a_bank_id == 0 || req_b_bank_id == 0 || req_c_bank_id == 0; cp_bank_1_hit: coverpoint req_a_bank_id == 1 || req_b_bank_id == 1 || req_c_bank_id == 1; cp_bank_2_hit: coverpoint req_a_bank_id == 2 || req_b_bank_id == 2 || req_c_bank_id == 2; //cross coverpoint when all the banks (0,1,2) are being accessed at the same time. ccp_all_banks_active: cross cp_bank_0_hit, cp_bank_1_hit, cp_bank_2_hit { bins all_hit = binsof(cp_bank_0_hit) intersect {1} && binsof(cp_bank_1_hit) intersect {1} && binsof(cp_bank_2_hit) intersect {1}; } Here I was expecting just one bin to be created for the cross coverpoint. However, I noticed other combinations(2^3=8) were generated. Example 2: Creating bins for coverpoints cp_bank_0_hit: coverpoint req_a_bank_id == 0 || req_b_bank_id == 0 || req_c_bank_id == 0 { bins hit = {1}; } cp_bank_1_hit: coverpoint req_a_bank_id == 1 || req_b_bank_id == 1 || req_c_bank_id == 1 { bins hit = {1}; } cp_bank_2_hit: coverpoint req_a_bank_id == 2 || req_b_bank_id == 2 || req_c_bank_id == 2 { bins hit = {1}; } //cross coverpoint when all the banks (0,1,2) are being accessed at the same time. ccp_all_banks_active: cross cp_bank_0_hit, cp_bank_1_hit, cp_bank_2_hit { bins all_hit = binsof(cp_bank_0_hit.hit) && binsof(cp_bank_1_hit.hit) && binsof(cp_bank_2_hit.hit) ; } The above code accomplishes the goal and only one bin was created, with other combinations not covered, as desired. Not sure why this change behavior, found it interesting nevertheless. I thought both should accomplish the same, maybe I was wrong. Feel free to comment.
  4. This is my solution. Not necessarily the best one. Suggestions for improvements are welcome. If any of you find any shortcomings with this method, please let me know. Open to constructive criticism! /* Assume there are 3 requestors namely: A,B and C with reqA, reqB and reqC being the requests and gntA, gntB and gntC being the grants. Assumes the request and grant are on the same cycle Similar sequence and assertions need to be replicated for each requestor. Can concatenate the requests and grants into a bit vector, in order to save some redundant code */ //Denotes there is request and grant for the requestor A. Does not care about other requestors logic requestorA_req_and_gnt; //Denotes there is request and grant for requestor A and there is atleast one other requestor active logic requestorA_req_and_gnt_with_other_requestors_active; //There are requests other than requestor A logic other_req_except_requestorA; //There are grants other than requestor A logic other_gnt_except_requestorA; assign other_req_except_requestorA = reqB | reqC; //High when any one of the other requestor's are active assign other_gnt_except_requestorA = gntB | gntC; assign requestorA_req_and_gnt = reqA & gntA; assign requestorA_req_and_gnt_with_other_requestors_active = reqA && other_req_except_requestorA && gntA; //----------------------------------------------------------------------------------------------------------------------------------------------- // Covers the case where there is request and grant on one cycle for requestorA, followed by no other requests. And then few cycles later there // are multiple requests(reqA and atleast one other request). In this case, requestorA should NOT be granted again //----------------------------------------------------------------------------------------------------------------------------------------------- sequence requestorA_req_and_gnt_followed_by_other_req_seq; requestorA_req_and_gnt ##0 (!other_req_except_requestorA)[*1:$] ##1 reqA && other_req_except_requestorA; endsequence //----------------------------------------------------------------------------------------------------------------------------------------------- //Covers the case where there are more than one requestor active(reqA and any one of the other requests) followed by cycles of no other request at all // and again followed by more than one requestor active. First time during multiple requests, reqA is granted, so, the second time when multiple // requests are active, gntA should not be asserted again, and one of the other requests should be granted //----------------------------------------------------------------------------------------------------------------------------------------------- sequence multiple_requests_with_requestorA_req_and_gnt_followed_by_other_req_seq; requestorA_req_and_gnt_with_other_requestors_active ##1 (!other_req_except_requestorA)[*0:$] ##1 reqA && other_req_except_requestorA; endsequence //----------------------------------------------------------------------------------------------------------------------------------------------- //Covers the case where there are multiple requestors active in one cycle and next cycle may or may not have reqA, but will have other requests. // If reqA is granted in the previous cycle, it should not be granted again in the next cycle, rather other requestor should be granted //----------------------------------------------------------------------------------------------------------------------------------------------- sequence back_to_back_multiple_requests_active_with_requestorA_gnted_followed_by_other_req_seq; requestorA_req_and_gnt_with_other_requestors_active ##1 other_req_except_requestorA; endsequence //----------------------------------------------------------------------------------------------------------------------------------------------- //Assertion to check if reqA do not hog the round robin arbiter //----------------------------------------------------------------------------------------------------------------------------------------------- assert_fairness_wrt_requestorA: assert property( @(posedge clk) disable iff(!resetn) (requestorA_req_and_gnt_followed_by_other_req_and_no_bts_seq or multiple_requests_with_requestorA_req_and_gnt_followed_by_other_req_and_no_bts_seq or back_to_back_multiple_requests_active_with_requestorA_gnted_followed_by_other_req_and_no_bts_seq ) |-> other_gnt_except_requestorA && !gntA ) `uvm_info("ARB_ASSERT",$sformatf("Requestor A was previously granted, and not granted again, round robin scheme followed!"),UVM_LOW) else `uvm_error("ARB_ASSERT_ERR",$sformatf("Requestor A was previously granted, and gets granted again, round robin scheme not followed"))
  5. Are are any standard or recommended ways of verifying the functionality of the round-robin arbiter and more specifically checking the fairness? I'm looking for something that is scalable with the number of requestors. Functionality of the arbiter is as follows: - Say there are 3 requestors, req1, req2 and req3. The pointer points to req1 initially. Consider different cases for illustration. - If all 3 requests are asserted, req1 goes through and the pointer is updated to req2. - If req2 and req3 is asserted, then req2 will go through and pointer is updated to req3. - If just req3 is asserted, then req3 will go through and pointer is updated to req1(cyclic). The pointer is always updated to the next requestor that got previously granted - if req1 granted, pointer is updated to req2 - if req2 got granted, pointer is updated to req3, - if req3 is granted, pointer is updated to req1 The pointer points to the requestor that has higher priority for the next round of requests, in order to ensure fairness in the way grants are allotted.
  6. I need to implement coverage across multiple interfaces. For example in the arbitor designs, it is of interest to see if multiple requests from different agents are driven at the same time. All the texts have only discussed coverage specific to the interface or transaction. I have an idea of implementing this, but not sure if it is the right way forward. Here is my idea: First place, instead of extending the coverage class from uvm_subscriber, I intend to extend it from uvm_scoreboard. This is because, uvm_subscriber is tied to a transaction type, whereas uvm_scoreboard is not. The code below might not be syntactically right, and I intentionally leave the factory registration, new(), build() etc. in order to be concise. `uvm_analysis_imp_decl(_transaction_A) `uvm_analysis_imp_decl(_transaction_B ) `uvm_analysis_imp_decl(_transaction_C ) class coverage_class extends uvm_scoreboard; bit req_a; //request coming from transaction A bit req_b; //request coming from transaction B bit req_c; //request coming from transaction C uvm_analysis_imp_transaction_A #(trans_a, coverage_class) trans_a_port; uvm_analysis_imp_transaction_B #(trans_b, coverage_class) trans_b_port; uvm_analysis_imp_transaction_C #(trans_c, coverage_class) trans_c_port; covergroup cg; coverpoint req_a; coverpoint req_b; coverpoint req_c; cross req_a, req_b, req_c; //Want to capture a case where all 3 requests go high at the same time from 3 different interfaces. endgroup //write function to capture trans_a virtual function void write_transaction_A(trans_a t); req_a = t.req; cg.sample(); endfunction //write function to capture trans_b virtual function void write_transaction_B(trans_b t); req_b = t.req; cg.sample(); endfunction //write function to capture trans_c virtual function void write_transaction_C(trans_c t); req_c = t.req; cg.sample(); endfunction endclass I also realize that, when 2 requests are high at the same time, there might be a delta delay between the two. Say "write_transaction_A" happens a delta before "write_transaction_B" (still the same timestamp). So when transaction_A happens, req_a is set to 1 and the covergroup is sampled. At this delta time, transaction_B has not occurred so, req_b is still 0. In the next delta cycle, write_transaction_B happens and so, req_A as well as req_B is asserted, and covergroup is sampled again. I see 2 issues here: 1. We are sampling the covergroup more than actually required. Is there a better way of sampling the covergroup? 2. Where do we clear the req_A/req_B/req_C variables in order to be sampled again. Is there a better way of accomplishing the same task? Please share your thoughts.
×