APB bus interface

APB (Advance peripheral BUS)  bus Master in OVM


class apb_my_trans extends ovm_sequence_item;

  rand PADDR;
  rand PRDATA;
  rand PWDATA;
 // rand PSEL;
  rand PWRITE;
  rand PENABLE;
//  rand PREADY;

 `ovm_object_utils_begin(apb_my_trans)
      `ovm_field_int(PADDR, OVM_ALL_ON)
      `ovm_field_int(PRDATA, OVM_ALL_ON )
      `ovm_field_int(PWDATA, OVM_ALL_ON )
      //`ovm_field_int(PSEL, OVM_ALL_ON )
      `ovm_field_int(PWRITE, OVM_ALL_ON )
      `ovm_field_int(PENABLE, OVM_ALL_ON )
//`ovm_field_int(PREADY, OVM_ALL_ON )
     
    `ovm_object_utils_end
 
    function new (string name = "apb_my_trans",
                  ovm_sequencer_base sequencer = null,
                  ovm_sequence parent_seq= null) ;
      super.new(name,sequencer,parent_seq);
    endfunction: new
   
endclass: apb_my_trans


sequence :




class apb_seq_my extends ovm_sequence;

apb_my_trans  trans_o;

function new(string name="apb_seq_my",ovm_sequencer sequencer=null,
   ovm_sequence parent_seq=null);
   super.new(name,sequencer,parent_seq);
endfunction

virtual task body();

  `ovm_do_with(trans_o)

  `ovm_rand_send_with (trans_o)

endtask
 
endclass: apb_seq_my




sequesncer :


class apb_sequencer_my extends ovm_sequencer;   
                                            

  `ovm_sequencer_utils(apb_sequencer_my)
 
   function new (string name="apb_sequencer_my", ovm_component parent);
    string inst_name;
    super.new(name, parent);
    `ovm_update_sequence_lib_and_item(apb_my_trans)
   
  endfunction : new   
 
   function void build();
    string inst_name;
    super.build();
       
  endfunction  

 

endclass :apb_sequencer_my

driver :



class apb_driver_my extends ovm_driver ;

  protected virtual interface  master_if drv_if; // dut interface

  `ovm_component_utils(ex_driver_C)
 


 function new (string name = "apb_driver_my", ovm_component parent);
   
    super.new(name, parent);

  endfunction : new
 
 
 
   function void assign_vi(virtual interface master_if drv_if);
    this.drv_if = drv_if;  
  endfunction : assign_vi
 
 
  function void build();
    super.build();
  endfunction
 
 
  virtual task run();
   `message(OVM_NONE, ("EX DRIVER: run task started"))
     @(negedge drv_if.PRESET);
    `message(OVM_NONE, ("EX DRIVER: power on reset applied"))
     tDefault(); // Drive default values of the i/f signals
    `message(OVM_NONE, ("EX DRIVER: default values are driven"))
     wait (drv_if.PRESET == 1); // Wait for reset deassertion
   
    forever
    begin
      fork
      begin
        tget_and_drive();
      end
     
      begin
        wait(drv_if.PRESET == 0);
        tDefault();
        @(drv_if.drv_cb);
      end
      join_any
      disable fork; // Disable all the child threads of the previous operation

      `message(OVM_HIGH,("Ex DRIVER: Main thread disabled"))

      // If reset applied disable the threads
      if(drv_if.PRESET == 0)
      begin
        wait(drv_if.PRESET == 1); // Wait till reset is deasserted
      end
    end
   
  endtask : run
 
 
  //   default setting
   task tDefault;
   begin              
     drv_if.drv_cb.PADDR    <=  32'b0;
     drv_if.drv_cb.PSEL   <=  16'b0;
     drv_if.drv_cb.PENABLE    <=  1'b0;
   end
   endtask
  
  
  
   task tget_and_drive();
    ovm_sequence_item item;
    apb_my_trans trans_item_o;
    forever
    begin
      seq_item_prod_if.get_next_item(item);
      
       $cast(trans_item_o, item);
        psel_index = sel_lookup(trans_item_o.ADDR);
       if(psel_index >= 0)
          tdrive_transfer(trans_item_o,psel_index);
       else
          `message(OVM_HIGH,(" DRIVER: ADDR out of range"))
          
       seq_item_prod_if.item_done();
    end                               

  endtask : tget_and_drive

`ifdef NCSIM
wave.swh
`elsif Questasim
wave.wlf
`elsif VCS
wave.

 
   task tdrive_transfer (apb_my_trans trans_item_o, int index);
   if(trans_item_o.PWRITE == 1'b1)
    begin
        drv_if.drv_cb.PSEL[index] <= 1'b1;
        drv_if.drv_cb.PADDR <= trans_item_o.PADDR;
        drv_if.drv_cb.PWDATA <= trans_item_o.PWDATA;
        @(posedge drv_if.PCLK)
        drv_if.drv_cb.PENABLE <= 1'b1;
        /*while (!drv_if.PREADY)
         @(posedge drv_if.PCLK);
        drv_if.drv_cb.PENABLE <= 1'b0;*/
       
        fork
             begin
             if (drv_if.PREADY == 1'b1)
             @(posedge drv_if.PCLK);
             end
             begin
             repeat(20) @ (posedge of drv_if.PCLK)
             `message(OVM_NONE,(" DRIVER: slave time out"))
             end
        join_any
        disable fork;
    end
    
   else /*if(trans_item_o.PWRITE == 1'b0)*/
        begin
                drv_if.drv_cb.PSEL[index] <= 1'b1;
                drv_if.drv_cb.PADDR <= trans_item_o.PADDR;
                @(posedge drv_if.PCLK)
                drv_if.drv_cb.PENABLE <= 1'b1;;
               while (!drv_if.PREADY)
                @(posedge drv_if.PCLK);
                drv_if.PRDATA <= trans_item_o.PRDATA;
                @(posedge drv_if.PCLK);
                drv_if.drv_cb.PENABLE <= 1'b0;
        end
  endtask : tdrive_transfer
 
  // Looks up the address and returns PSEL line that should be activated
// If the address is invalid, a non positive integer is returned to indicate an error
function int apb_driver_my::sel_lookup(logic[31:0] address);
  for(int i = 0; i < m_cfg.no_select_lines; i++) begin
    if((address >= m_cfg.start_address[i]) && (address <= (m_cfg.start_address[i] + m_cfg.range[i]))) begin
      return i;
    end
  end
  return -1; // Error: Address not found
endfunction: sel_lookup