0% found this document useful (0 votes)
77 views9 pages

Ral Intergration of I2c

The document outlines the integration of I2C using UVM, detailing steps for creating a register block, environment, adapter, predictor, and virtual sequences. It includes code snippets for building and configuring registers, connecting components, and implementing read/write operations. The process culminates in running the virtual sequence for I2C communication.

Uploaded by

hemaprasad512
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
77 views9 pages

Ral Intergration of I2c

The document outlines the integration of I2C using UVM, detailing steps for creating a register block, environment, adapter, predictor, and virtual sequences. It includes code snippets for building and configuring registers, connecting components, and implementing read/write operations. The process culminates in running the virtual sequence for I2C communication.

Uploaded by

hemaprasad512
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

RAL INTERGRATION OF I2C

REG BLOCK
STEP 1
NOTE: UVM provides default “uvm_reg_block”
 Take instances for the Registers
Build:
 Create map for the default maps
 Create objects for all registers
 Configure the registers
 Call the build method
 Map the register in the reg map
class i2c_reg_block extends uvm_reg_block;

`uvm_object_utils_begin(i2c_reg_block)
`uvm_object_utils_end

rand i2c_reg_0 h_i2c_reg_0;


rand i2c_reg_1 h_i2c_reg_1;

function new(string name = "i2c_reg_block");


[Link](name);
`uvm_info("I2C_REG_BLOCK","I2c_register_block build method",UVM_NONE);
endfunction

virtual function void build();


default_map =
create_map(.name("default_map"),.base_addr(8'h00),.n_bytes(1),.endian(UVM_BIG_ENDIAN),.by
te_addressing(1));
h_i2c_reg_0 = i2c_reg_0::type_id::create("h_i2c_reg_0");
h_i2c_reg_0.configure(this, null,"h_i2c_reg_0");
h_i2c_reg_0.build();
default_map.add_reg(h_i2c_reg_0, 'h3, "RW");

h_i2c_reg_1 = i2c_reg_1::type_id::create("h_i2c_reg_1");
h_i2c_reg_1.configure(this, null,"h_i2c_reg_1");
h_i2c_reg_1.build();
default_map.add_reg(h_i2c_reg_1, 'h4, "RW");

endfunction
STEP 2
 Include Reg block in the Environment
 Take handle for the Reg block
Build phase:
 Create object for the Reg block
 Call the build function in reg block
 Call the lock_model in the reg block
class i2c_env extends uvm_env;

i2c_reg_block h_i2c_reg_block;

virtual function void build_phase(uvm_phase phase);


super.build_phase(phase);
`uvm_info("TAG","INSIDE BUILD PHASE",UVM_NONE);
h_i2c_reg_block = i2c_reg_block :: type_id :: create("h_i2c_reg_block",this);
h_i2c_reg_block.build();
h_i2c_reg_block.lock_model();

endfunction : build_phase

STEP 3
Registers
 Take instances for the reg fields in the corresponding register
 Inside build function, create object for the reg fields
 Configure the reg fields
class i2c_reg_0 extends uvm_reg;

`uvm_object_utils_begin(i2c_reg_0)
`uvm_object_utils_end

rand uvm_reg_field field_0;

virtual function void build();


field_0 = uvm_reg_field::type_id::create("field_0");
field_0.configure(.parent(this),
.size(8),
.lsb_pos(0),
.access("rw"),
.volatile(0),
.reset(0),
.has_reset(1),
.is_rand(1),
.individually_accessible(0)
);
endfunction

endclass : i2c_reg_0
STEP 4
 Include the reg block in package
 Compile
 Run

ADAPTER
STEP 1
NOTE: UVM provides default class “uvm_reg_bus_op”
2 methods
Reg2bus
 Create sequence item
 Assign default values for the variables in sequence item
 Update the item according to read and write
Bus2reg
 Create sequence item
 Update the register according to read and write

class i2c_reg_adaptor extends uvm_reg_adapter;

`uvm_object_utils(i2c_reg_adaptor)

function new(string name = "i2c_reg_adaptor");


[Link](name);
`uvm_info("I2C_REG_ADAPTOR","I2c_register_adaptor build method",UVM_NONE);
endfunction

virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);


i2c_sequence_item item = i2c_sequence_item :: type_id :: create("item");
[Link] = 1;
item.start_dr_en = 1;
item.slave_id_dr_en = 1;
item.opcode_dr_en = 1;
item.reg_addr_dr_en = 1;
item.reg_data_master_dr_en = 1;
item.stop_dr_en = 1;
item.rd_ack_dr_en = 1;
if([Link] == UVM_READ) begin
[Link] = READ;
item.slave_id = 'h10;
item.reg_addr_dr_en = 0;
item.reg_data_master_dr_en = 0;
end else if([Link] == UVM_WRITE) begin
[Link] = WRITE;
item.data_q.push_back([Link]);
[Link] = [Link];
item.slave_id = 'h10;
end
return item;
endfunction : reg2bus

virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);


i2c_sequence_item item;
if( ! $cast(item,bus_item)) begin
`uvm_fatal("NOT_WB_TYPE","Provided bus_item is not of the correct type");
end
if([Link] == READ) begin
[Link] = UVM_READ;
[Link] = [Link];
if(item.data_q.size !=0) [Link] = item.data_q.pop_front();
end else if([Link] == WRITE) begin
[Link] = UVM_WRITE;
[Link] = [Link];
[Link] = [Link];
end
endfunction : bus2reg

endclass: i2c_reg_adaptor
STEP 2
Environment:
 Take handle for the adapter
Build phase:
 Create object for the adapter
Connect phase:
 Connect the adapter with the default map in the reg map
 Set auto predict
STEP 3
 Include the adapter in package
 Compile
 Run
class i2c_env extends uvm_env;
`uvm_component_utils(i2c_env)
i2c_reg_adaptor h_i2c_adaptor;

virtual function void build_phase(uvm_phase phase);


super.build_phase(phase);
`uvm_info("TAG","INSIDE BUILD PHASE",UVM_NONE);
h_i2c_adaptor = i2c_reg_adaptor::type_id::create("h_i2c_adaptor",this);
endfunction : build_phase

virtual function void connect_phase(uvm_phase phase);


super.connect_phase(phase);
`uvm_info("TAG","INSIDE Connect phase",UVM_NONE);

h_i2c_reg_block.default_map.set_sequencer(h_i2c_master_ag.h_master_sequencer,h_i2c_a
daptor);

h_i2c_reg_prd.adapter = h_i2c_adaptor;

h_i2c_master_ag.h_master_monitor.h_trans_item_collected_ap.connect(h_i2c_reg_prd.bus_
in);
endfunction

PREDICTOR
STEP 1
Environment:
 Take handle for the Predictor, adapter and reg block
 UVM provides uvm_reg_predictor. Using this as a type declare handle
for the predictor
Build phase:
 Create object for the Predictor
Connect phase:
 Connect the map in the Predictor with the default map in the reg block
 Connect the adapter in the predictor with the adapter
 Connect the port in the monitor with the default port(bus_in) predictor
class i2c_env extends uvm_env;
`uvm_component_utils(i2c_env)

typedef uvm_reg_predictor#(i2c_sequence_item) i2c_reg_predictor;

i2c_reg_predictor h_i2c_reg_prd;

virtual function void build_phase(uvm_phase phase);


super.build_phase(phase);
`uvm_info("TAG","INSIDE BUILD PHASE",UVM_NONE);
h_i2c_reg_prd = i2c_reg_predictor::type_id::create("h_i2c_reg_prd",this);
endfunction : build_phase

virtual function void connect_phase(uvm_phase phase);


super.connect_phase(phase);
`uvm_info("TAG","INSIDE Connect phase",UVM_NONE);
h_i2c_reg_prd.map = h_i2c_reg_block.default_map;
h_i2c_reg_prd.adapter = h_i2c_adaptor;

h_i2c_master_ag.h_master_monitor.h_trans_item_collected_ap.connect(h_i2c_reg_prd.bus_in);

endfunction

STEP 2
 Compile
 Run

VIRTUAL SEQUENCE LIB


STEP 1
 Write individual virtual task for read and write in the base virtual
sequence
virtual task write(bit7_t slave_id, bit8_t address, bit8_t w_data_q[$]);
i2c_write_sequence h_seq;
int length = w_data_q.size();
`uvm_do_on_with(h_seq, p_sequencer.h_master_sqr,{
h_seq.l_slave_id == slave_id;
h_seq.l_address == address;
h_seq.l_length == length;
foreach(w_data_q[i]) h_seq.l_data_q[i] == w_data_q[i];
});
`uvm_info(TAG,$sformatf("PKT = %0s",h_seq.sprint),UVM_NONE);
endtask : write

virtual task read(bit7_t slave_id, bit8_t address,int length, ref bit8_t r_data_q[$]);
i2c_read_sequence h_seq;
r_data_q = {};
write(slave_id,address,r_data_q);
`uvm_do_on_with(h_seq, p_sequencer.h_master_sqr,{
h_seq.l_slave_id == slave_id;
h_seq.l_length == length;
});
`uvm_info(TAG,$sformatf("PKT = %0s",h_seq.sprint),UVM_NONE);
foreach(h_seq.l_data_q[i]) r_data_q.push_back(h_seq.l_data_q[i]);
endtask : read
STEP 2
 Write multiple virtual sequences derived from the base virtual sequence
 Overwrite the seq_specific_task and call the write or read method in
base virtual sequence
 Write virtual sequence for each and every feature[single write/read ,
burst write/read, multiple write/read,etc..]
// I2C SINGLE WRITE READ VSEQ
class i2c_single_write_read_vseq extends i2c_base_vseq;

bit7_t slave_id = 'h10;


bit8_t address;
int length;
bit8_t w_data_q[$];
bit8_t r_data_q[$];

`uvm_object_utils(i2c_single_write_read_vseq)

virtual task seq_specific_task();


// slave_id = $urandom_range(16,20); // multiple slave
address = $urandom_range(1,10); // random address
w_data_q.push_back($urandom_range(1,10)); // random data
length = w_data_q.size();
write(slave_id,address,w_data_q);
read(slave_id,address,length,r_data_q);
endtask : seq_specific_task

endclass : i2c_single_write_read_vseq

STEP 3
 Run the required virtual sequence on virtual sequencer in test

You might also like