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
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
No comments:
Post a Comment