OpenCores
URL https://opencores.org/ocsvn/i2c_master_slave_core/i2c_master_slave_core/trunk

Subversion Repositories i2c_master_slave_core

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /i2c_master_slave_core/trunk/i2c_master_slave_core/i2c_master_slave_core/svtb/vmm_svtb
    from Rev 4 to Rev 6
    Reverse comparison

Rev 4 → Rev 6

/vmm_i2c_stimulus_packet.sv
0,0 → 1,69
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This file defines Stimulus packet class for Scenario Generator. //
// The Packet Randomizes intr_en to enable/disable interrupt, byte_count to transfer //
// Random no. of data_bytes, register_address and data for register testcase. It also //
// randomize slave address. Other fields get assigned in Scenario generator class. //
// Constraint block called reg_add is used to contrain randomized fields. //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
 
class stimulus_packet extends vmm_data;
vmm_log log;
 
rand bit intr_en ; // 1 for Interrupt enable and 0 for disable
rand int byte_count; // no. of bytes to be transfered
rand bit [7:0] register_data; // to check register read/write
rand bit [7:0] register_addr; // to select the address of internal register
rand bit [6:0] slave_address; // slave address to be checked
bit [7:0] data_packet[]; // data packets to be transfered
bit master_slave; // 1 for master and 0 for slave
bit tr; // 1 for trasmit and 0 for receive
bit register_check; // 1 to check registers writing and 0 for not.
bit reset_check; // 1 to check reset test and 0 for not.
int temp_count;
 
constraint reg_add {
register_addr inside {8'h02, 8'h04, 8'h0A, 8'h0C, 8'h0E};
byte_count inside {[2:10]};
slave_address < 7'b111_1111;
intr_en dist {0 := 1, 1 :=1};
}
function new();
super.new(this.log);
this.log = new("Stimulus Data", "class");
endfunction
 
function void display();
this.log.start_msg(vmm_log::NOTE_TYP);
void'(this.log.text($psprintf("Master/Slave mode is = %b\n", master_slave)));
void'(this.log.text($psprintf("tr = %d\n", tr)));
void'(this.log.text($psprintf("register_check = %b\n", register_check)));
void'(this.log.text($psprintf("reset_check = %b\n", reset_check)));
void'(this.log.text($psprintf("Interrupt Enable is = %b\n", intr_en)));
void'(this.log.text($psprintf("byte_count = %d\n", byte_count)));
void'(this.log.text($psprintf("register_addr = %b\n", register_addr)));
void'(this.log.text($psprintf("register_data = %b\n", register_data)));
void'(this.log.text($psprintf("slave_address = %b\n", slave_address)));
this.log.end_msg();
temp_count = byte_count;
endfunction
 
 
function vmm_data copy(vmm_data to = null);
copy = new this;
endfunction
endclass
`vmm_channel(stimulus_packet) // This macro defined in VMM Methodology creates channel named stimulus_packet_channel
 
/vmm_i2c_sb_pkt.sv
0,0 → 1,43
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code defines Scoreboard Packet. This packet will be sent to Scoreboard //
// and Coverage Module from Both W/B Driver and I2C M/S Driver through vmm_callback. //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
 
class scoreboard_pkt extends vmm_data;
 
vmm_log log;
bit master_slave; // 1 for Master; 0 for Slave;
bit tx_rx; // 1 for Tx; 0 for Rx
bit [6:0] slave_address; // 7-bit Slave Address
bit [7:0] data_byte; // 8-bit Data Byte
 
function new();
super.new(this.log);
this.log = new("Sb Data", "class");
endfunction
 
function vmm_data copy(vmm_data to = null);
copy = new this;
endfunction
 
 
function void display();
this.log.start_msg(vmm_log::NOTE_TYP);
void'(this.log.text($psprintf("master_slave is %0b", this.master_slave)));
void'(this.log.text($psprintf("tx_rx is %0b", this.tx_rx)));
void'(this.log.text($psprintf("slave_address is %b", this.slave_address)));
void'(this.log.text($psprintf("data_byte is %b", this.data_byte)));
this.log.end_msg();
endfunction
 
endclass
/vmm_i2c_scoreboard.sv
0,0 → 1,146
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code implements Scoreboard. //
// Scoreboard contains queues for data_bytes comparision and Associative Array for //
// Register values comparision for read/write test-cases. //
// Whenever any transaction starts, through pre_txn callback it gets oject and //
// save that object into queue. Once transaction is done, it get another objects //
// through post_txn call backs from dirvers. In Scoreboard it compares both object's //
// data_byte and reports MATCH or MISMATCH of data. //
// For Register testcases it saves register value whenever any data gets written //
// to DUT register into associative array with register address as an index. Now, //
// When Register-read test occurs, it compares the data read from internal register //
// with Assocative Array's dat of same index. If register was not written previously //
// it compread read data with initial value of that register. //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
 
class i2c_scoreboard extends vmm_xactor;
 
scoreboard_pkt sb_pre_txn_q[$]; // Queue of scoreboard_pkt for pre_transaction
scoreboard_pkt sb_post_txn_q[$]; // Queue of scoreboard_pkt for post_transaction
vmm_log log;
scoreboard_pkt sb_pre_obj; // Scoreoard_pkt's instance for pre_transaction
scoreboard_pkt sb_pre_obj1; // Scoreoard_pkt's instance for pre_transaction
scoreboard_pkt sb_post_obj; // Scoreoard_pkt's instance for post_transaction
scoreboard_pkt sb_post_obj1; // Scoreoard_pkt's instance for post_transaction
 
register_pkt reg_pkt; // registet_pkt's instance
register_pkt reg_pkt1; // register_pkt's instance
 
typedef bit [7:0] reg_addr;
bit [7:0] initial_reg [*]; // 8-bit wide Associative Array of to store initial_register's value
bit [7:0] wr_reg [*]; // 8-bit wide Associative Array of to store data which were written in DUT reigsters
bit [7:0] ref_reg_value; // 8-bit wide register for storing reference data to be compared.
// Constructor Class
function new (string name, string instance);
super.new("I2C_Scoreboard", "SCOREBOARD");
this.log = new("Scoreboard", "SCOREBOARD");
endfunction
 
 
// Write_reg Task. It saves the data written to internal register of DUT into Associative Array wr_reg
task write_reg(register_pkt reg_pkt);
// $display("Scoreboard: inside write_reg at %t", $time);
// if(reg_pkt.reset_bit)
// begin
// wr_reg.delete;
// for (int i = 0; i < sb_pre_txn_q.size ; i++)
// sb_pre_txn_q.delete(i);
// for (int j = 0; j < sb_post_txn_q.size ; j++)
// sb_post_txn_q.delete(j);
// end
// else
// begin
$cast(reg_pkt1,reg_pkt.copy());
wr_reg[reg_pkt1.reg_address] = reg_pkt1.data_byte;
// end
endtask
 
 
// Read_reg task. It Check whether data is previously written to internal register (Checks Whether data already exists for the given index,
// which is internal register's address in this case). If data already exists, it compare this data with the read data. If data with same index
// doesn't exists, it will compare this read data with initial data of that index.
task read_reg(register_pkt reg_pkt);
$cast(reg_pkt1,reg_pkt.copy());
if(wr_reg.exists(reg_pkt1.reg_address)) // Data Already written into internal register of given index(address)
begin
ref_reg_value = wr_reg[reg_pkt1.reg_address];
if(reg_pkt1.reg_address == 8'h0C)
if(ref_reg_value[7:1] == reg_pkt1.data_byte[7:1])
`vmm_note(log, "Scoreboard: Date written into Register MATCH with Date read from Register");
else
`vmm_error(log, "Scoreboard: Date written into Register DO NOT MATCH with Date read from Register");
else if (reg_pkt1.reg_address == 8'h04)
if(ref_reg_value[7:2] == reg_pkt1.data_byte[7:2])
`vmm_note(log, "Scoreboard: Date written into Register MATCH with Date read from Register");
else
`vmm_error(log, "Scoreboard: Date written into Register DO NOT MATCH with Date read from Register");
else
if(ref_reg_value == reg_pkt1.data_byte)
`vmm_note(log, "Scoreboard: Date written into Register MATCH with Date read from Register");
else
`vmm_error(log, "Scoreboard: Date written into Register DO NOT MATCH with Date read from Register");
end
else
begin // Data was not written before
if(reg_pkt1.data_byte == 8'h00)
`vmm_note(log, "Scoreboard: Date written into Register MATCH with Initial Valre of Register");
else
`vmm_error(log, "Scoreboard: Date written into Register DO NOT MATCH with Initial Value of Register");
end
endtask
// Pre_txn_push task. This task will push back the data packet(object) been received by callback.
task pre_txn_push(scoreboard_pkt sb_pre_obj);
$cast(sb_pre_obj1,sb_pre_obj.copy());
this.sb_pre_obj1.display();
this.sb_pre_txn_q.push_back(sb_pre_obj1);
endtask
 
// Post_txn_push Task. This task is used to compare both data_byte, the one to be transmitter before starting transmission and
// the one which was received after completion of transation. This task will check whether any object is already available
// in the queue(If size > 0). If object is alread there, It will pop_out that object and check the data_byte of both objects.
task post_txn_push(scoreboard_pkt sb_post_obj);
if(sb_pre_txn_q.size > 0)
begin
sb_post_obj1 = this.sb_pre_txn_q.pop_front();
if(sb_post_obj1.data_byte == sb_post_obj.data_byte)
`vmm_note(log, $psprintf("DATA TRANSMITED AND RECEIVED MATCH WITH EACH OTHER AT TIME %t", $time));
else
`vmm_error(log, $psprintf("DATA TRANSMITED AND RECEIVED DO NOT MATCH WITH EACH OTHER AT TIME %t", $time));
end
endtask
 
 
// This task it used to display all contents of queue.
task sb_display();
this.log.start_msg(vmm_log::NOTE_TYP);
void'(this.log.text($psprintf("****************************")));
void'(this.log.text($psprintf("*****SCOREBOARD REPORT*****")));
void'(this.log.text($psprintf("****************************")));
void'(this.log.text($psprintf("\n*****PACKETS TRANSMITTED*****")));
for (int i = 0; i < this.sb_pre_txn_q.size ; i++)
begin
void'(this.log.text($psprintf("Master/Slave = %0b Data_Transmitted = %b", sb_pre_txn_q[i].master_slave, sb_pre_txn_q[i].data_byte)));
end
void'(this.log.text($psprintf("\n*****PACKETS RECEIVED*****")));
for (int i = 0; i < this.sb_post_txn_q.size ; i++)
begin
void'(this.log.text($psprintf("Master/Slave = %0b Data_Received = %b", sb_post_txn_q[i].master_slave, sb_post_txn_q[i].data_byte)));
end
this.log.end_msg();
endtask
 
endclass
/vmm_i2c_slave_driver.sv
0,0 → 1,717
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code implements I2C M/S Driver. //
// Driver will be receiving Scenario packets from Stimulus gen and accordingly it //
// will keep on monitoring/driving interface signals. //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
 
`include "vmm.sv"
 
class i2c_slave_driver extends vmm_xactor;
 
vmm_log log = new("lOG", "SLAVE_DRIVER");
 
virtual i2c_pin_if pif; // Virtual Interface
stimulus_packet_channel s_stim_req_chan; // Scenario_gen to Driver Channel
stimulus_packet s_stim_packet; // Stimulus Packet's Instance
stimulus_packet s_temp_stim_packet; // Stimulus Packet's Temprary Instance
stimulus_packet s_response_packet;
scoreboard_pkt s_sb_pkt; // Scoreboard Packet's Instance
 
 
// Class Constructor
function new(string name, string instance, virtual i2c_pin_if pif, stimulus_packet_channel s_stim_req_chan = null);
super.new("slave_driver","i2c_slave_driver");
if(s_stim_req_chan == null) s_stim_req_chan = new("slave_stimulus_packet_channel", "s_stim_req_chan");
this.s_stim_req_chan = s_stim_req_chan;
s_stim_packet = new;
s_temp_stim_packet = new;
s_response_packet = new;
s_sb_pkt = new;
this.pif = pif;
endfunction
 
 
reg [6:0] slave_address; // Stores slave addess
reg [7:0] mem_in ; // memory reg which receives data
reg [7:0] mem_out; // memory data output
reg [2:0] bit_cnt; // 3-bit down counter
reg [2:0] state; // State when this core is in slave mode
reg [7:0] sr; // 8bit shift register
reg sta, d_sta; // Local Start and delayed Start Signal
reg sto, d_sto; // Local Stop and delayed Stop Signal
reg rw; // read/write direction
reg ld; // load downcounter
reg sda_o; // sda-drive level
reg scl_o; // sca-drive level
reg my_adr, my_adr_flag ; // address match flags
reg i2c_reset; // i2c-state machine reset
reg acc_done; // Checks whethere 8-bits transmission done
reg sda_dly; // delayed version of sda
int byte_count; // Byte count
reg core_master_slave; // Selects Master/Slave configuration of this driver
reg tr; // Selects Transmit/Receive Operation of this driver
reg [7:0] data_out; // memory data output
bit [7:0] slave_data_out[]; // memory data output
bit load_data; // Load new data into mem_out
int sent_data_count; // Count no. of bytes already been sent
int received_data_count; // Count no. of bytes already been received
int slave_bit_count; // Control Slave bit count while sending address to DUT
bit slave_start_sig; // Local Start signal for generating Start
bit slave_stop_sig; // Local Stop Signal for generating Stop
bit slave_ack; // Checks Acknowledgment from DUT
reg [2:0] slave_state; // Slave State when this core is in master mode
int i =0;
reg temp; // Temp signal to be assigned on sda_oe
reg shift_data_out; // Control Shifting of data
reg load_first_data_flag;
 
// Initialize the local variables of driver
task i2c_slave_driver_initialize;
sda_o = 1'b1;
scl_o = 1'b1;
pif.scl_oe = 1'b1;
state = 3'b000;
slave_state = 3'b000;
slave_start_sig = 1'b1;
sta = 1'b0;
sto = 1'b0;
endtask
 
// This task will invoke parallel threads which will be running continuously throughout the simulation. //
task set_always;
fork
shift_reg;
set_sda;
set_scl;
bit_count;
detect_start;
detect_stop;
set_mem_out;
delayed_start;
acc_done_check;
address_check;
generate_scl;
generate_start;
set_data_out;
set_load_first_data_flag;
join
endtask
 
// This Task will be shifting sr register. On every scl clock it will get the data from sda line and //
// that data will be copied to lsb of sr register and data will be shifted left bit by bit. //
task shift_reg;
forever @(posedge pif.scl)
begin
if (sta) sr = #1 {sr[6:0],pif.sda};
end
endtask
 
// This task will be counting no. of scl clock events. When ld (load Count) is one, it will initialize //
// the counter, otherwise it will decrement the count by one on every posedge of scl //
task bit_count;
forever @(posedge pif.scl)
begin
if(ld)
bit_cnt = #1 3'b111;
else
bit_cnt = #1 bit_cnt - 3'b001;
end
endtask
 
// This task will be comparing the slave address being received on sda line and the address assigned to //
// this transactor. It sets the flag when addresses match. //
task address_check;
forever @(posedge pif.clk)
begin
my_adr_flag = (sr[7:1] == slave_address);
if (my_adr_flag && !(my_adr))
my_adr = #1 1'b1;
end
endtask
 
// This task will set the flag load_first_data_flag
task set_load_first_data_flag;
forever @(posedge pif.scl)
begin
load_first_data_flag = my_adr;
end
endtask
 
// This task will check whether 8 bits have been transmitted or received. In other words it checks the //
// bit-Count. Sets the flag when 8 bits transaction is done. //
task acc_done_check;
forever @(posedge pif.clk)
begin
acc_done = !(|bit_cnt);
end
endtask
 
// This task will detect start signal on sda line. It sets flags when start signal is detected. //
task detect_start;
forever @(negedge pif.sda)
if(pif.scl)
begin
sta = #1 1'b1;
d_sta = #1 1'b0;
sto = #1 1'b0;
my_adr = 1'b0;
end
else sta = #1 sta;
endtask
 
// This task will detect stop signal on sda line. It sets flags when stop signal is detected. //
task detect_stop;
forever @(posedge pif.sda);
if(pif.scl)
begin
sta = #1 1'b0;
sto = #1 1'b1;
end
else sto = #1 1'b0;
endtask
 
// This task assign start signal to delayed version of start. //
task delayed_start;
forever @(posedge pif.scl)
d_sta = #1 sta;
endtask
 
// This task shifts bitwise data of mem_out. MSB of this register is transmitted when I2C M/S works as //
// a Trasnmitter. //
task set_mem_out;
forever @(posedge pif.scl)
begin
if(!acc_done && rw)
mem_out = #1 {mem_out[6:0],1'b1};
end
endtask
// This task assign sda_o (local sda_o data) to interface sda_oe. //
task set_sda;
begin
forever
begin
#5;
temp = slave_start_sig & sda_o;
if(slave_stop_sig)
begin
if(!pif.scl)
pif.sda_oe = 1'b0;
else
#100 pif.sda_oe = 1'b1;
end
else
pif.sda_oe = temp;
end
end
endtask
 
// This task assigns value of local scl_o to interface port scl_o //
task set_scl;
forever begin
#10; pif.scl_oe = scl_o;
end
endtask
 
 
// This task will generate SCL clk when I2C Master/Slave Driver (this one) is working in Master mode.
task generate_scl;
int s_clk_gen_count = 0;
forever @(posedge pif.clk)
begin
if(core_master_slave == 1'b0)
begin
if(s_clk_gen_count == 49)
begin
scl_o = ~scl_o;
s_clk_gen_count = 0;
end
else
s_clk_gen_count++;
end
end
endtask
 
// This task will generate Start Signal on sda line when This Driver is working in Master Mode.
task generate_start;
if(core_master_slave == 1'b0)
begin
#100;
forever
begin
if(sta != 1'b1 && !(core_master_slave) && !(s_temp_stim_packet.reset_check) && !(s_temp_stim_packet.reset_check))
begin
@(posedge pif.scl)
begin
if(sta != 1'b1 && !(core_master_slave))
begin
#100 slave_start_sig = 1'b0;
end
end
@(negedge pif.scl) slave_start_sig = 1'b1;
end
#100;
end
end
endtask
 
// This task will set data out on posedge of scl //
task set_data_out;
forever @(posedge pif.scl)
begin
if(!acc_done || shift_data_out)
begin
data_out = #1 {data_out[6:0],1'b1};
#2;
end
end
endtask
 
 
// process task
task process;
forever
begin
s_stim_packet = new;
s_stim_req_chan.peek(s_stim_packet);
$cast(s_temp_stim_packet,s_stim_packet.copy());
`vmm_note(log, "***********Packet Received inside I2C_SLAVE_DRIVER from GENERATOR************");
s_temp_stim_packet.display();
slave_address = s_temp_stim_packet.slave_address;
byte_count = s_temp_stim_packet.byte_count;
slave_data_out = new[byte_count];
slave_data_out = s_temp_stim_packet.data_packet;
core_master_slave = s_temp_stim_packet.master_slave;
tr = s_temp_stim_packet.tr;
#1;
// $display("begining of task process mem_out is %b and byte_count is %d and slave_address is %b", mem_out, byte_count, slave_address);
i = 0;
if(my_adr_flag && !(load_first_data_flag))
begin
mem_out = slave_data_out[0];
end
 
// If load_data is set, it will copy a new data byte from slave_data_out array to mem_out register.
// This mem_out register's data will be outputed on sda line.
if(load_data)
begin
mem_out = slave_data_out[byte_count - sent_data_count];
// `vmm_callback
if(core_master_slave == 1)
begin
s_sb_pkt.master_slave = 1'b1;
s_sb_pkt.tx_rx = 1'b0;
end
else
begin
s_sb_pkt.master_slave = 1'b0;
s_sb_pkt.tx_rx = 1'b1;
end
s_sb_pkt.slave_address = s_temp_stim_packet.slave_address;
s_sb_pkt.data_byte = mem_out;
// $display("Callback for pre_transaction in slave driver at %t", $time);
`vmm_callback(i2c_callback,pre_transaction(s_sb_pkt));
// vmm_callback
load_data = 1'b0;
end
 
// When reset_check test case is begin run on W/B driver side (DUT) this driver will not do any operation.
if(s_temp_stim_packet.reset_check)
begin
`vmm_note(log, $psprintf("SLave_Driver: Checking reset operation of DUT at %t", $time));
repeat (10) @(posedge pif.clk);
i2c_slave_driver_initialize;
s_stim_req_chan.get(s_stim_packet);
end
 
// When register_check test case is begin run on W/B driver side (DUT) this driver will not do any operation.
else if(s_temp_stim_packet.register_check)
begin
`vmm_note(log, $psprintf("SLave_Driver: Checking register test operation of DUT at %t", $time));
repeat (10) @(posedge pif.clk);
i2c_slave_driver_initialize;
s_stim_req_chan.get(s_stim_packet);
end
 
// Data-Transmisstion test-case is being run now. This Core (I2C M/S) is working as a Slave Device
else if(core_master_slave) //In slave mode
begin
@(negedge pif.scl or posedge sto)
begin
if(sto || (sta && !d_sta))
begin
sda_o = #1 1'b1;
//scl_o = #1 1'b1;
ld = #1 1'b1;
state = #1 3'b000;
end
else
begin
sda_o = #1 1'b1;
ld = #1 1'b0;
end
 
// Case 000 will be checking whether 8 bits of transaction is done, Address matches and rd/wr bit. //
// It will assign next state to state 001, which is Address Acknowledgment State. //
case (state)
3'b000:
begin
if(acc_done && my_adr)
begin
rw = #1 sr[0];
sda_o = #5 1'b0;
#2;
if(rw)
begin
sent_data_count = byte_count;
// if(sent_data_count != 0)
//s_rsp_port.put(1);
// #1;
end
else if (!rw)
begin
received_data_count = byte_count;
end
state = #1 3'b001;
end
end
 
// Case 001 is Acknowledgment state for address. It checks rd/wr bit received with slave address //
// Then for I2C M/S Core(this dirver) as a Transmitter, next state will be assigned to 010 and send //
// slave address acknowledgment signal. For I2C M/S Core (This driver) as a Receiver, next state //
// will be assigned to 011. Then it sets load_count bit. //
3'b001:
begin
if(rw)
begin
state = #1 3'b010; // read state
// `vmm_callback
s_sb_pkt.master_slave = 1'b1;
s_sb_pkt.tx_rx = 1'b0;
s_sb_pkt.slave_address = s_temp_stim_packet.slave_address;
s_sb_pkt.data_byte = mem_out;
// $display("Callback for pre_transaction in slave driver at %t", $time);
`vmm_callback(i2c_callback,pre_transaction(s_sb_pkt));
sda_o = #1 mem_out[7];
end
else
state = #1 3'b011; // write state
ld = #2 1'b1;
end
 
// When I2C M/S DUT is acting as a Master trasnmitter and access is done, it will send msb of //
// mem_out to sda_o which will get assigned to sda_oe line on interface. When Access is done, //
// next State will be assigned to 100, which is Data Acknowledgment state. It also checks //
// whether byte_count is 0. If it is not 0, load_data will be set to 1 for next byte. //
3'b010:
begin
if(rw)
#1 sda_o = mem_out[7];
if(acc_done)
begin
sda_o = #1 rw;
state = #1 3'b100; // Data Acknoledgment
if(rw)
begin
sent_data_count --;
if(sent_data_count != 0)
load_data = 1'b1;
end
end
end
 
// When I2C M/S core (this core) is acting as a receiver and access is done, it will get data_byte //
// from shift register sr and send acknowledgement signal to interface through sda_o signal. Next //
// State will be assigned to 100, which is Data Acknowledgment state. //
3'b011:
begin
if(acc_done)
begin
mem_in = #1 sr;
sda_o = #1 1'b0;
// `vmm_callback
s_sb_pkt.master_slave = 1'b1;
s_sb_pkt.tx_rx = 1'b0;
s_sb_pkt.slave_address = s_temp_stim_packet.slave_address;
s_sb_pkt.data_byte = mem_in;
// $display("Callback for post_transaction in slave driver when DUT is in master at %t", $time);
`vmm_callback(i2c_callback,post_transaction(s_sb_pkt));
// vmm_callback
state = #1 3'b100; // Data Acknoledgment
end
// #1;
end
 
// This is Data Acknowledgment State. When I2C M/S Core (this driver) is acting as a trasmitter and when after //
// sending data byte it doesn't get acknowledgment from Master DUT, next state will assigned to 000. //
// If it gets the acknoeledgment, next state will be assigned to 010. Similerly when I2C M/S core (this core) //
// as a receiver, next state will be assigned to 011. //
3'b100:
begin
ld = #1 1'b1;
if(rw)
begin
if(sr[0]) // read and master send NACK
begin
sda_o = #1 1'b1;
state = 3'b000;
end
else
begin
sda_o = mem_out[7];
//if(byte_count == 0)
if(sent_data_count == 0)
begin
state = 3'b000;
ld = 1'b0;
#5000 s_stim_req_chan.get(s_stim_packet);
i2c_slave_driver_initialize;
end
else
state = 3'b010;
end
end
else
begin
received_data_count--;
if(received_data_count != 0)
begin
state = #1 3'b011;
sda_o = #1 1'b1;
end
else
begin
#5000 s_stim_req_chan.get(s_stim_packet);
i2c_slave_driver_initialize;
end
end
end
default : $display("default case");
endcase
end // @(negedge pif.scl or posedge sto)
end // (s_stim_packet.master_slave))
 
// Data Transmission test-case and this core (I2C M/S Core) is working as a Master Device.
else if(core_master_slave == 1'b0) // This core works as in master mode (DUT core in slave mode)
begin
#100;
rw = tr;
shift_data_out = 1'b1;
@(negedge pif.scl)
begin
if(sto || (sta && !d_sta))
begin
data_out = {slave_address,!tr};
ld = 1'b1;
slave_state = #1 3'b000;
end
else
begin
ld = 1'b0;
end
 
case(slave_state)
 
// State 000 will be generating SCL and then check Ack bit and accordingly set next state. //
// For I2C M/S Core(this driver) as a Transmitter it will be setting next state to 001 and //
// for I2C M/S Core(this dirver) to be a Receiver this will be setting next state to 010. //
3'b000:
begin
if(acc_done && slave_bit_count > 7)
begin
sent_data_count = byte_count;
received_data_count = byte_count;
ld = #2 1'b1;
slave_state = 3'b001;
sda_o = 1'b1;
@(posedge pif.scl)
begin
slave_ack = pif.sda;
if(!slave_ack && tr) // This slave will be sending data to DUT core
begin
mem_out = slave_data_out[0];
end
else if (!slave_ack && !tr) // This slave will be receiving data from DUT core
begin
// $display("slave ack is 0 and tr is 1 at %t", $time);
end
end
end
else
begin
if(sta)
begin
sda_o = data_out[7];
slave_bit_count++;
end
end
end
 
// Case 001 is Acknowledgment state for address. It checks rd/wr bit received with slave address //
// Then for I2C M/S Core(this dirver) as a Transmitter, next state will be assigned to 010 and send //
// slave address acknowledgment signal. For I2C M/S Core (This driver) as a Receiver, next state //
// will be assigned to 011. Then it sets load_count bit. //
3'b001:
begin
if(rw)
begin
slave_state = #1 3'b010; // I2C M/S Core (this dirver) transmit state
// `vmm_callback
s_sb_pkt.master_slave = 1'b0;
s_sb_pkt.tx_rx = 1'b1;
s_sb_pkt.slave_address = s_temp_stim_packet.slave_address;
s_sb_pkt.data_byte = mem_out;
// $display("Callback for pre_transaction in slave driver when DUT is in slave mode at %t", $time);
`vmm_callback(i2c_callback,pre_transaction(s_sb_pkt));
// vmm_callback
sda_o = #1 mem_out[7];
end
else
slave_state = #1 3'b011; // I2C M/S Core (this dirver) receive state
 
ld = #2 1'b1;
end
// State 010 will be transmitting serial data from mem_out to sda_o. //
// If 8 bits are transmitted (acc_done set) it will decrese the sent_data_count. //
// If sent_data_count is not 0, it will set load_data to load new data into mem_out. //
3'b010:
begin
#1 sda_o = mem_out[7];
if(acc_done)
begin
slave_state = 3'b100;
sent_data_count--;
if(sent_data_count != 0)
load_data = 1'b1;
end
end
// State 011 will be receiving data from sda_in. //
// If 8 bits are received (acc_done set) it will copy sr into mem_in and //
// decrese the received_data_count. //
3'b011:
begin
if(acc_done)
begin
mem_in = #1 sr;
sda_o = #1 1'b0;
// `vmm_callback
s_sb_pkt.master_slave = 1'b0;
s_sb_pkt.tx_rx = 1'b0;
s_sb_pkt.slave_address = s_temp_stim_packet.slave_address;
s_sb_pkt.data_byte = mem_in;
// $display("Callback for post_transaction in driver when DUT is in slave mode at %t", $time);
`vmm_callback(i2c_callback,post_transaction(s_sb_pkt));
// vmm_callback
slave_state = #1 3'b100; // Data Acknoledgment
end
// #1;
end
 
 
// State 100 is for acknowledgment of data byte tx/rx //
// In transmit mode it will check ack from DUT and then if sent_data_count is not zero, //
// It will set the next state to 010. If sent_data_count is 0, it will set next state //
// to 000 and set all local variable to their initial values. //
// Similerly, In Receive mode when received_data_count is not 0, it will set next state //
// to 011. If its 0, next state will be set to 000 and set all local variable to their //
// initial values. //
3'b100:
begin
if(rw)
begin
sda_o = mem_out[7];
if(sent_data_count == 0)
begin
slave_state = 3'b000;
ld = 1'b0;
if(sto != 1'b1)
#10 slave_stop_sig = 1'b1;
else
begin
@(posedge pif.scl);
begin
#1000 slave_stop_sig = 1'b0;
end
end
#1000 slave_stop_sig = 1'b0;
slave_bit_count = 0;
sda_o =1'b1;
scl_o = 1'b1;
sta = 1'b0;
s_stim_req_chan.get(s_stim_packet);
end
else
begin
ld = #1 1'b1;
slave_state = 3'b010;
end
end
else
begin
received_data_count--;
if(received_data_count != 0)
begin
slave_state = #1 3'b011;
sda_o = #1 1'b1;
ld = 1'b1;
end
else
begin
slave_state = 3'b000;
ld = 1'b0;
if(sto != 1'b1)
#10 slave_stop_sig = 1'b1;
else
begin
@(posedge pif.scl);
begin
#1000 slave_stop_sig = 1'b0;
end
end
#1000 slave_stop_sig = 1'b0;
slave_bit_count = 0;
sda_o = 1'b1;
scl_o = 1'b1; // to check scl generation when this core's mode got changed from m to s ...
sta = 1'b0;
s_stim_req_chan.get(s_stim_packet);
end
end
end
endcase
end
end
else
begin
#10;
// $display("Slave Driver: no condition matches");
end
end
endtask
 
virtual protected task main();
super.main();
begin
fork
i2c_slave_driver_initialize;
set_always;
process;
join
end
endtask
 
endclass
 
/vmm_i2c_monitor.sv
0,0 → 1,205
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code implements I2C Master-Slave Monitor. //
// Monitor does protocol validations. It checks generation of Start, Stop, interrupt //
// request, slave and data acknowledgment for every trnasaction. It will create //
// monitor packet on every transaction and send that packet to Coverage Module. //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
 
class i2c_monitor extends vmm_xactor;
vmm_log log = new("lOG", "MONITOR");
virtual i2c_pin_if pif; // Virtual Interface
stimulus_packet mon_stim_packet; // Stimulus Packet
stimulus_packet temp_mon_stim_packet; // Stimulus Packet
monitor_pkt mon_pkt; // Monitor Packet
 
// Class Constructor
function new(string name, string instance, virtual i2c_pin_if pif);
super.new("Monitor","I2C_MONITOR");
mon_stim_packet = new;
temp_mon_stim_packet = new;
mon_pkt = new;
this.pif = pif;
endfunction
 
reg sta, d_sta; // Local Variable of start and delayed start
reg sto, d_sto; // Local variable of stop and delayed stop
reg slave_ack; // Local Variable for Slave Acknowledgment
reg data_ack; // Local variable for Data Acknowledgment
reg intr_ack; // Local variable for Genaration of Interrupt
reg first_stop_flag; // Local variable for First Stop bit
integer local_byte_count; // Track byte_count
integer ack_count; // Track Acknowledgment pulse count
integer intr_count; // Track Interrupt Count
reg [3:0] bit_count; // 3-bit Counter
reg load_counter; // load_counter flag
 
 
// This task gets packet from driver. Though this call monitor will be aware of what kind of test-case is being run.
task get_packet_from_driver(stimulus_packet mon_stim_packet);
`vmm_note(log, $psprintf("Received Packet IN MONITOR at time %t", $time));
$cast(temp_mon_stim_packet, mon_stim_packet.copy());
temp_mon_stim_packet.display();
endtask
// Initialize the local variables of Monitor
task initialize;
sta = 1'b0;
d_sta = 1'b0;
sto = 1'b0;
d_sto = 1'b0;
slave_ack = 1'b0;
data_ack = 1'b0;
intr_ack = 1'b0;
bit_count = 4'h0;
load_counter = 1'b0;
ack_count = 0;
intr_count = 0;
endtask
 
 
// This task will be counting no. of scl clock events. When load_counter is one, it will initialize //
// the counter, otherwise it will decrement the count by one on every posedge of scl //
task bit_counter;
forever @(posedge pif.scl)
begin
if(load_counter)
bit_count = 4'h8;
else
bit_count = bit_count - 4'h1;
end
endtask
// This task will detect start signal on sda line. It sets flags when start signal is detected. //
task detect_start;
forever @(negedge pif.sda)
if(pif.scl)
begin
sta = #1 1'b1;
d_sta = #1 1'b0;
sto = #1 1'b0;
load_counter = 1'b1;
end
else sta = #1 sta;
endtask
// This task will detect stop signal on sda line. It sets flags when stop signal is detected. //
task detect_stop;
forever @(posedge pif.sda)
if(pif.scl)
begin
sto = #1 1'b1;
end
else sto = #1 1'b0;
endtask
// This task assign start signal to delayed version of start. //
task delayed_start;
forever @(posedge pif.scl)
d_sta = #1 sta;
endtask
// This task assign stop signal to delayed version of start. //
task delayed_stop;
forever @(posedge pif.clk)
d_sto = #1 sto;
endtask
 
// This task will detect interrupt signal on sda line. If bit_count is 0, it will increment intr_count. //
task detect_intr;
forever @(posedge pif.irq)
begin
if(bit_count == 0)
intr_count++;
else if(bit_count != 0 && temp_mon_stim_packet.intr_en && !(temp_mon_stim_packet.register_check) && !(temp_mon_stim_packet.reset_check))
`vmm_error(log, "INTERRUPT SIGNAL NOT GENERATED ON RIGHT TIME");
end
endtask
 
// Process Task
task process;
forever @(posedge pif.scl or posedge sto)
begin
if(sta && !(d_sta) && !(sto)) // First SCL posedge after Start pulse
begin
load_counter = 1'b0;
`vmm_note(log, $psprintf("START DETECTED IN MONITOR AT %t", $time));
end
else if (sta && d_sta && !(sto))
begin
load_counter = 1'b0;
// It checks the value of sda line when bit_count is 0 for acknowledgment. First Acknowledgment pulse is Slave Acknowledgment
// and from then it will be Data acknowldgment.
if(bit_count == 4'h0 && !pif.sda)
begin
if(ack_count == 0)
`vmm_note(log,$psprintf("SLAVE ADDRESS ACKNOWLEDGMENT DETECTED AT %t", $time));
else
`vmm_note(log,$psprintf("DATA ACKNOWLEDGMENT DETECTED AT %t", $time));
ack_count++;
load_counter = 1'b1;
end
end
else if (sto && !(d_sto))
begin
if(!first_stop_flag)
first_stop_flag = 1'b1;
else
begin
// Checks whether the testcase being run is not of register_check or reset_check type.
if(!(temp_mon_stim_packet.register_check) && !(temp_mon_stim_packet.reset_check))
begin
`vmm_note(log, $psprintf("STOP DETECTED IN MONITOR AT %t", $time));
if(!(sta || d_sta))
`vmm_error(log, "START PULSE NOT DETECTED");
if(temp_mon_stim_packet.byte_count != (ack_count-1))
`vmm_error(log, "ACKNOWLEDGMENT NOT DETECTED");
if(temp_mon_stim_packet.intr_en && temp_mon_stim_packet.byte_count != (intr_count-1))
`vmm_error(log, "INTERRUPT BIT NOT CLEARED FOR ALL INTERRUPT MODE TRANSACTIONS");
if (sta)
begin
// Create a monitor pkt and sent it to and coverage module through callback
mon_pkt.start_bit = 1'b1;
mon_pkt.stop_bit = 1'b1;
mon_pkt.slave_ack = 1'b1;
mon_pkt.data_ack = 1'b1;
mon_pkt.intr_ack = 1'b1;
`vmm_callback(i2c_callback,protocol_checks_coverage(mon_pkt));
@(posedge pif.clk) initialize;
end
end
end
end
end
endtask
 
// Main Task
virtual protected task main();
super.main();
begin
first_stop_flag = 1'b0;
fork
initialize;
bit_counter;
delayed_start;
delayed_stop;
detect_start;
detect_stop;
detect_intr;
process;
join
end
endtask
 
endclass
 
 
 
/vmm_i2c_env.sv
0,0 → 1,187
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code Creates VMM Environment of the I2C M/S Core. //
// //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
`include "config.sv"
`include "vmm_i2c_interface.sv"
//`include "debug_if.sv"
`include "vmm_i2c_sb_pkt.sv"
`include "vmm_i2c_mon_pkt.sv"
`include "vmm_i2c_reg_pkt.sv"
`include "vmm_i2c_scenario_packet.sv"
`include "vmm_i2c_stimulus_packet.sv"
`include "vmm_i2c_data_packet.sv"
`include "vmm_i2c_scenario_generator.sv"
`include "sb_callback.sv"
`include "vmm_i2c_driver.sv"
`include "vmm_i2c_slave_driver.sv"
 
class i2c_env extends vmm_env;
 
vmm_log log = new("log", "ENV");
virtual i2c_pin_if pif; // Virtual Interface
i2c_scenario_generator sc_gen; // Scenario Generator
configuration cfg; // Configuration Class
stimulus_packet_channel m_stim_req_chan; // Scenarion_gen to W/B Driver Channel
stimulus_packet_channel s_stim_req_chan; // Scenarion_gen to I2C M/S Driver Channel
i2c_master_driver m_driver_xactor; // W/B Driver Xactor
i2c_slave_driver s_driver_xactor; // I2C Driver Xactor
i2c_scoreboard i2c_sb; // Scoreboard
sb_callback sb_c; // Sb_Callback
i2c_coverage i2c_cov; // Coverage_Module
i2c_monitor i2c_mon; // Monitor
 
bit rand_tran = 1'b0; // Rand_mode
integer transaction_count; // No. of Transaction
 
// Class Constructor
function new(virtual i2c_pin_if pif);
super.new("MY_ENV");
this.pif = pif;
// this.d_if = d_if;
$value$plusargs("transaction_count=%d",transaction_count);
$value$plusargs("rand_trans=%b",rand_tran);
cfg = new();
endfunction
 
 
//Gen Config Function. If rand_trans is 1 then this will randomize trasaction_count in config class
virtual function void gen_cfg();
super.gen_cfg();
`vmm_note(log, "inside gen_cfg");
if(rand_tran)
begin
if(!cfg.randomize())
`vmm_error(log,"Configuration Randomization Failed");
transaction_count = cfg.transaction_count;
end
endfunction
 
// Build function to all Connections Initializaion
virtual function void build();
super.build();
m_stim_req_chan = new("master_stimulus_packet_channel", "m_stim_req_chan");
s_stim_req_chan = new("slave_stimulus_packet_channel", "s_stim_req_chan");
sc_gen = new("scenario_generator", "generator", m_stim_req_chan, s_stim_req_chan);
m_driver_xactor = new("i2c_master_driver", "m_driver_xactor", this.pif, m_stim_req_chan);
s_driver_xactor = new("i2c_slave_driver", "s_driver_xactor", this.pif, s_stim_req_chan);
sc_gen.transaction_count = transaction_count;
i2c_sb = new("I2C_Scoreboard", "SCOREBOARD");
i2c_cov = new("I2C_Coverage", "COVERAGE");
i2c_mon = new("I2C_Monitor", "MONITOR",this.pif);
sb_c = new(i2c_sb, i2c_cov, i2c_mon);
m_driver_xactor.append_callback(sb_c);
s_driver_xactor.append_callback(sb_c);
i2c_mon.append_callback(sb_c);
endfunction
 
// Reset DUT task. It will reset dut for 5 system clk cycle
virtual task reset_dut();
super.reset_dut();
m_driver_xactor.set_enable_signals;
pif.rst = 1;
repeat(5)
begin
@(posedge pif.clk);
pif.rst = 0;
end
`vmm_note(log, "inside reset_dut");
endtask
 
// cfg dut task for configuration of DUT.
virtual task cfg_dut();
super.cfg_dut();
`vmm_note(log, "inside cfg_dut");
endtask
 
// Start Transactor task. This will start all transactor in the Environment.
virtual task start();
super.start();
sc_gen.start_xactor();
m_driver_xactor.start_xactor();
s_driver_xactor.start_xactor();
i2c_mon.start_xactor();
`vmm_note(log, "inside start");
endtask
 
// Wait for end task. It will wait for Done signal from Scenario Generartor.
virtual task wait_for_end();
super.wait_for_end();
`vmm_note(log, "inside wait_for_end");
`vmm_note(log, "inside wait_for_end: before wait for done");
this.sc_gen.notify.wait_for(this.sc_gen.DONE);
`vmm_note(log, "inside wait_for_end: Affter wait for done");
endtask
// Report Task
virtual task report();
super.report();
// i2c_sb.sb_display();
`vmm_note(log, "inside report");
endtask
 
// Clean-up task
virtual task cleanup();
super.cleanup();
`vmm_note(log, "inside cleanup");
endtask
 
endclass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/config.sv
0,0 → 1,27
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code is used to configure the test-case. //
// This class randmomize the no. of transactions. //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
 
class configuration;
 
rand int transaction_count; // No. of transaction to be done
 
function new();
endfunction
 
constraint valid {
transaction_count inside {[0:44]};
}
 
endclass
 
/vmm_program1_test.sv
0,0 → 1,134
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code is written to apply directed test-case to I2C M/S core. //
// This test-case will be written to apply write-write-read operation on register //
// test-case. //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
`include "vmm_i2c_env.sv"
`include "vmm_clkgen.sv"
 
class i2c_scenario_generator1 extends i2c_scenario_generator;
int transaction_count;
byte reg_addr[5] = {8'h02, 8'h04, 8'h0A, 8'h0C, 8'h0E};
 
function new( string name, string instance_name, stimulus_packet_channel m_req_chan = null, stimulus_packet_channel s_req_chan = null);
super.new("scenario_generator ", "scenario_generator");
if(m_req_chan == null) m_req_chan = new("master_stimulus_packet_channel", "m_req_chan");
this.m_req_chan = m_req_chan;
if(s_req_chan == null) s_req_chan = new("slave_stimulus_packet_channel", "s_req_chan");
this.s_req_chan = s_req_chan;
this.DONE = this.notify.configure(1,vmm_notify::ON_OFF);
sc_packet = new;
stim_packet = new;
d_pkt = new;
$value$plusargs("transaction_count=%d",transaction_count);
$value$plusargs("rand_gen=%b",rand_gen);
$value$plusargs("master_slave=%b",master_slave);
$value$plusargs("register_check=%b",register_check);
$value$plusargs("reset_check=%b",reset_check);
$value$plusargs("tx_rx=%b",tx_rx);
endfunction
 
 
// Main task
virtual protected task main();
begin
stim_packet.master_slave = 1'b1;
stim_packet.tr = 1'b1;
stim_packet.register_check = 1'b1;
stim_packet.reset_check = 1'b0;
// For all internal register
foreach (reg_addr[i])
begin
stim_packet.register_addr = reg_addr[i];
// Writing into registers twice
for (int j = 1; j <=2 ; j++)
begin
stim_packet.register_data = {reg_addr[i]+j};
stim_packet.intr_en = 1'b1;
this.m_req_chan.put(stim_packet); // sending packet to master driver
this.s_req_chan.put(stim_packet); // sending packet to slave driver
end
// Reading Registers
stim_packet.intr_en = 1'b0;
this.m_req_chan.put(stim_packet); // sending packet to master driver
this.s_req_chan.put(stim_packet); // sending packet to slave driver
end
notify.indicate(DONE);
end
endtask
 
endclass
 
 
//-------------------- Program Block --------------------------
program program_test(i2c_pin_if pif);
 
i2c_scenario_generator1 i2c_sc_gen1;
initial begin
i2c_env env;
env = new(pif);
env.build();
i2c_sc_gen1 = new("new_scenario_generator", "generator", env.m_stim_req_chan, env.s_stim_req_chan);
env.sc_gen = i2c_sc_gen1; // Assigning a new Scenario Generator to handle of Old Scenarion Gen in env.
env.run();
end
endprogram
//-------------------------------------------------------------
 
 
 
//---------------------- Module Top --------------------
module top;
 
i2c_pin_if pif();
clkgen c_gen(pif);
program_test p_test(pif);
 
wire dut_sda_o;
wire dut_sda_oe;
wire dut_sda_in;
wire dut_scl_o;
wire dut_scl_oe;
wire dut_scl_in;
wire temp;
wire temp_scl;
assign dut_sda_o = 1'b0;
 
assign temp = pif.sda_oe & dut_sda_oe;
assign temp_scl = pif.scl_oe & dut_scl_oe;
assign pif.sda = temp ? 1'bz : 1'b0;
assign pif.scl = temp_scl ? 1'bz : 1'b0;
pullup p1_if(pif.sda);
pullup p2_if(pif.scl);
 
block i2c_core( .scl_in(pif.scl),
.scl_o(dut_scl_o),
.scl_oe(dut_scl_oe),
.sda_in(pif.sda),
.sda_o(dut_sda_o),
.sda_oe(dut_sda_oe),
.wb_add_i(pif.addr_in),
.wb_data_i(pif.data_in),
.wb_data_o(pif.data_out),
.wb_stb_i(pif.wb_stb_i),
.wb_cyc_i(pif.wb_cyc_i),
.wb_we_i(pif.we),
.wb_ack_o(pif.ack_o),
.irq(pif.irq),
.trans_comp(pif.trans_comp),
.wb_clk_i(pif.clk),
.wb_rst_i(pif.rst)
);
 
endmodule
 
 
/vmm_i2c_scenario_packet.sv
0,0 → 1,57
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This file is the packet class for Scenario Generator. //
// The Packet Randomizes Master/Slave bit,(1 for configuring DUT as a Master and 0 for //
// Slave), tx_rx bit, which determines the direction of data to be transfered. //
// It also randomize reset_check and register_check to enable/disable reset or register//
// testcases. Transacation_count will be assigned from environment itself. //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
 
`include "vmm.sv"
 
class scenario_packet extends vmm_data;
vmm_log log;
 
randc bit master_slave ; // 1 for master and and 0 for slave
int transaction_count; // No. of transaction to be done
rand bit register_check; // to check register read/write
rand bit reset_check; // to check reset
rand bit tx_rx ; // 1 for transmit and and 0 for receive
function new();
super.new(this.log);
this.log = new("Scenario data", "class");
endfunction
 
function void display();
this.log.start_msg(vmm_log::NOTE_TYP);
void'(this.log.text($psprintf("Master/Slave mode is = %b\n", master_slave)));
void'(this.log.text($psprintf("transaction_count = %d\n", transaction_count)));
void'(this.log.text($psprintf("register_check = %b\n", register_check)));
void'(this.log.text($psprintf("reset_check = %b\n", reset_check)));
void'(this.log.text($psprintf("tx_rx = %b\n", tx_rx)));
this.log.end_msg();
endfunction
 
 
function vmm_data copy(vmm_data to = null);
copy = new this;
endfunction
constraint valid_scenario {
reset_check dist {1 := 1 , 0 := 20};
register_check dist { 1 := 1 , 0 := 20};
}
 
endclass: scenario_packet
 
 
/vmm_i2c_coverage.sv
0,0 → 1,181
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This Source Code Implements Coverage Collector. //
// This Coverage Module contains 3 Covergroups. CG1 for data transaction and modes of //
// of operation, CG2 for Register read-write testcases and CG3 for Protocol validation.//
// All Covergroups are sampled on events which are triggered in different tasks. //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
 
class i2c_coverage extends vmm_xactor;
 
scoreboard_pkt cov_pkt; // Scoreboard_pkt's instance
register_pkt reg_pkt; // register_pkt's instance
monitor_pkt mon_pkt; // Monitor_pkt's instance
event start_cov; // Event data_tye to sample cg1
event start_cov_reg; // Event data type to sample cg2
event start_protocol_checks_cov; // Event data type to sample cg3
 
// local variables which gets assigned object's data members in tasks
bit [7:0] data_byte;
bit master_slave;
bit tx_rx;
bit [6:0] slave_address;
bit start_bit;
bit stop_bit;
bit slave_ack;
bit data_ack;
bit intr_ack;
bit [7:0] reg_address;
bit wr_rd;
bit reset_bit;
bit [8:0] reg_addr_txn;
 
 
// Covergroup CG1. This Covergroup Generate Coverage for modes of operation. their cross coverpoint is defined as well.
// This covergroup will be sampled on every event of start_cov variable. This event will be triggered in task pre_txn_start_cov.
covergroup cg1 @start_cov;
data_in : coverpoint data_byte {
bins low = {[8'h00 : 8'h40]};
bins mid = {[8'h41 : 8'h80]};
bins high = {[8'h81: 8'hff]};
}
m_s : coverpoint master_slave;
tx_rx : coverpoint tx_rx;
slave_addr: coverpoint slave_address {
bins low = {[7'h00 : 7'h20]};
bins mid = {[7'h21 : 7'h40]};
bins high = {[7'h41: 7'h7f]};
}
data_mode_cross : cross data_in, m_s, tx_rx;
endgroup : cg1
 
// Covergroup CG2. This covergroup generate fucntion coverage for all register read-write operations. Cross Coverage is written
// to check both read and write operation of all reigsters. Transaction Coverage is wrritten for write-write-read operations.
// This covergroup is sampled on every event of start_cov_reg.
covergroup cg2 @start_cov_reg;
register_addr : coverpoint reg_address {
bins prescale = {8'h02};
bins control = {8'h04};
bins timeout = {8'h0A};
bins address = {8'h0C};
bins data_tx = {8'h0E};
}
write_read : coverpoint wr_rd {
bins write = {1'b1};
bins read = {1'b0};
}
cross_reg_addr_wr : cross register_addr, write_read;
reset_test: coverpoint reset_bit {
bins reset = {1'b1};
}
prescale_txn : coverpoint wr_rd iff(reg_address == 8'h02) {
bins wr_wr_rd = ( 1 => 1 => 0);
}
control_txn : coverpoint wr_rd iff(reg_address == 8'h04) {
bins wr_wr_rd = ( 1'b1 => 1'b1 => 1'b0);
}
timeout_txn : coverpoint wr_rd iff(reg_address == 8'h0A) {
bins wr_wr_rd = ( 1'b1 => 1'b1 => 1'b0);
}
address_txn : coverpoint wr_rd iff(reg_address == 8'h0C) {
bins wr_wr_rd = ( 1'b1 => 1'b1 => 1'b0);
}
data_tx_txn : coverpoint wr_rd iff(reg_address == 8'h0E) {
bins wr_wr_rd = ( 1'b1 => 1'b1 => 1'b0);
}
txn: coverpoint reg_addr_txn {
bins pre = (9'h102 => 9'h102 => 9'h002);
bins con = (9'h104 => 9'h104 => 9'h004);
bins tim = (9'h10A => 9'h10A => 9'h00A);
bins add = (9'h10C => 9'h10C => 9'h00C);
bins dat = (9'h10E=> 9'h10E => 9'h00E);
}
endgroup
 
 
// Covergroup CG3. This Covergroup is used to check fucntion coverage of all protocol validation. Cross Coverage is written to check
// all protocol checks in every possible mode of operation. This Cover Group is sampled on every even of start_protocol_checks_cov.
covergroup cg3 @start_protocol_checks_cov;
start_bit : coverpoint start_bit {
bins sta = {1'b1};
}
stop_bit : coverpoint stop_bit {
bins sto = {1'b1};
}
slave_ack : coverpoint slave_ack {
bins sl_ac = {1'b1};
}
data_ack : coverpoint data_ack {
bins da_ac = {1'b1};
}
intr_ack : coverpoint intr_ack {
bins int_ac = {1'b1};
}
start_mode_cross : cross start_bit, master_slave, tx_rx;
stop_mode_corss : cross stop_bit, master_slave, tx_rx;
sack_mode_cross : cross slave_ack, master_slave, tx_rx;
dack_mode_cross : cross data_ack, master_slave, tx_rx;
inack_mode_cross : cross intr_ack, master_slave, tx_rx;
endgroup
 
 
// Class Constructor
function new(string name, string instance);
super.new("fifo_coverage_gen","COVERAGE_GEN");
cg1 = new;
cg2 = new;
cg3 = new;
endfunction
 
 
// This task will assign values of object's(cov_pkt) fields to local variables and then trigger the event start_cov to sample Covergroup CG1.
task pre_txn_start_cov (scoreboard_pkt cov_pkt);
this.cov_pkt = cov_pkt;
data_byte = cov_pkt.data_byte;
slave_address = cov_pkt.slave_address;
master_slave = cov_pkt.master_slave;
tx_rx = cov_pkt.tx_rx;
-> start_cov;
endtask
 
// This task will assign values of object's(reg_pkt) fields to local variables and then trigger the event start_cov_reg to sample Covergroup CG2.
task write_reg_cov (register_pkt reg_pkt);
this.reg_pkt = reg_pkt;
reg_address = reg_pkt.reg_address;
wr_rd = reg_pkt.wr_rd;
reset_bit = reg_pkt.reset_bit;
reg_addr_txn = {wr_rd,reg_address};
-> start_cov_reg;
endtask
 
// This task will assign values of object's(reg_pkt) fields to local variables and then trigger the event start_cov_reg to sample Covergroup CG2.
task read_reg_cov (register_pkt reg_pkt);
this.reg_pkt = reg_pkt;
reg_address = reg_pkt.reg_address;
wr_rd = reg_pkt.wr_rd;
reg_addr_txn = {wr_rd,reg_address};
-> start_cov_reg;
endtask
// This task will assign values of object's(mon_pkt) fields to local variables and then trigger the event start_protocol_checks_cov to
// sample Covergroup CG2.
task protocol_checks_cov (monitor_pkt mon_pkt);
this.mon_pkt = mon_pkt;
start_bit = mon_pkt.start_bit;
stop_bit = mon_pkt.stop_bit;
slave_ack = mon_pkt.slave_ack;
data_ack = mon_pkt.data_ack;
intr_ack = mon_pkt.intr_ack;
-> start_protocol_checks_cov;
endtask
 
endclass
/vmm_i2c_driver.sv
0,0 → 1,734
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code implements W/B M/S Driver. //
// Driver will be receiving Scenario packets from Stimulus gen and accordingly it //
// will drive W/B ports of interface to configure DUT in different modes. //
// In every mode of operation whenever DUT is configured in interupt mode, this driver //
// waits for posedge of interrupt and then write commands/data to internal reigster of //
// DUT. In normal mode where interrupt will not be generated, it keeps on checking //
// Status register of DUT and act accordingly. //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
 
class i2c_master_driver extends vmm_xactor;
vmm_log log = new("lOG", "MASTER_DRIVER");
virtual i2c_pin_if pif; // Virtual Interface
stimulus_packet_channel m_stim_req_chan; // Scenario Generator to Diver Channel
stimulus_packet stim_packet; // Stimulus Packet's Instance
stimulus_packet temp_stim_packet; // Stimulus Packet's Instance
stimulus_packet response_packet;
scoreboard_pkt sb_pkt; // Scoreboard Packet's instance for callback
register_pkt reg_pkt; // Register Packet's instance for callback
 
 
// Class Constructor
function new(string name, string instance, virtual i2c_pin_if pif, stimulus_packet_channel m_stim_req_chan = null);
super.new("driver","i2c_master_driver");
if(m_stim_req_chan == null) m_stim_req_chan = new("master_stimulus_packet_channel", "m_stim_req_chan");
this.m_stim_req_chan = m_stim_req_chan;
stim_packet = new;
temp_stim_packet = new;
response_packet = new;
sb_pkt = new;
reg_pkt = new;
this.pif = pif;
endfunction
 
 
/* task for initial setting */
task set_enable_signals;
pif.rst = 1'b1;
pif.clk = 1'b0;
pif.wb_stb_i = 1'b0;
pif.ack_o = 1'b0;
pif.wb_cyc_i = 1'b0;
#10 pif.rst = 1'b0;
#20 write_inf(1,8'h04, 8'hD0);
#40 write_inf(1,8'h04, 8'h00);
endtask
/* task for initial setting */
 
// Task to Enable core
task enable_core;
#20 write_inf(1,8'h04, 8'h80);
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'hD0;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
#40 write_inf(1,8'h04, 8'h00);
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h00;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
endtask
// Task to reset Core. This task is called from ENV.
task set_reset;
pif.rst = 1'b1;
pif.clk = 1'b0;
pif.wb_stb_i = 1'b0;
pif.ack_o = 1'b0;
pif.wb_cyc_i = 1'b0;
repeat(2) @(posedge pif.clk);
pif.rst = 1'b0;
endtask
// Task to set TimeOut Register's Value
task set_timeout_reg;
#40 write_inf(1,8'h0A, 8'hff);
reg_pkt.reg_address = 8'h0A;
reg_pkt.data_byte = 8'hff;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
endtask
 
/* Write Task to write data and address on interface */
task write_inf;
input delay;
input [7:0] reg_addr;
input [7:0] reg_value;
integer delay;
begin
repeat(delay) @(posedge pif.clk)
#1;
pif.addr_in = reg_addr;
pif.data_in = reg_value;
pif.we = 1'b1;
pif.wb_stb_i = 1'b1;
pif.wb_cyc_i = 1'b1;
@(posedge pif.clk)
while (~pif.ack_o) @(posedge pif.clk)
#1;
pif.addr_in = {3{1'bx}};
pif.data_in = {8{1'bx}};
pif.we = 1'bx;
pif.wb_stb_i = 1'bx;
pif.wb_cyc_i = 1'b0;
end
endtask
 
// Task to Set Prescale Register's Value
task set_prescale_register;
#40 write_inf(1,8'h02, 8'h64);
reg_pkt.reg_address = 8'h02;
reg_pkt.data_byte = 8'h64;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
endtask
/* Read Task to read data from the design core through interface */
task read_inf;
input delay;
input [7:0] reg_addr;
output [7:0] reg_value;
integer delay;
repeat(delay) @(posedge pif.clk)
#1;
pif.addr_in = reg_addr;
pif.we = 1'b0;
pif.wb_stb_i = 1'b1;
pif.wb_cyc_i = 1'b1;
pif.data_in = {8{1'bx}};
 
@(posedge pif.clk)
while (~pif.ack_o) @(posedge pif.clk)
#1;
pif.wb_cyc_i = 1'b0;
pif.we = 1'bx;
pif.wb_stb_i = 1'bx;
pif.addr_in = {3{1'bx}};
pif.data_in = {8{1'bx}};
reg_value = pif.data_out;
endtask
 
 
// task process;
 
virtual protected task main();
super.main();
begin
stimulus_packet stim_packet;
int byte_count;
reg intr_check;
reg register_check;
reg register_write;
string s;
reg [7:0] status_reg;
reg [7:0] reg_data_register;
forever
begin
m_stim_req_chan.peek(stim_packet);
$cast(temp_stim_packet,stim_packet.copy());
`vmm_note(log, "***********Packet Received inside I2C_DRIVER from GENERATOR************");
temp_stim_packet.display();
byte_count = temp_stim_packet.byte_count;
register_write = temp_stim_packet.intr_en;
`vmm_callback(i2c_callback,send_pkt_to_monitor(temp_stim_packet)); // Sending packet to monitor
 
// Reset test-case. Driver will driver high on pif.rst to Reset DUT
// This will set reset_bit of reg_pkt and then invoke callback for scoreboad.
if(temp_stim_packet.reset_check) // reset check
begin
repeat (10)
begin
@(posedge pif.clk)
pif.rst = 1'b1;
end
@(posedge pif.clk)
pif.rst = 1'b0;
reg_pkt.reg_address = 8'h00;
reg_pkt.data_byte = 8'h00;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b1;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
m_stim_req_chan.get(stim_packet); // get(remove) the packet from channel
end // reset check
 
// Register Test-case. If register_write is 1, it will write internal register, set fields of reg_pkt and invoke callback.
// If register_write is 0, it will read value of internal register, set fields of reg_pkt and invoke callback for
// comparision of register datas in Scoreboard.
else if(temp_stim_packet.register_check) //Internal register read and write check
begin
if(register_write) // write
begin
write_inf(1,temp_stim_packet.register_addr,temp_stim_packet.register_data);
reg_pkt.reg_address = temp_stim_packet.register_addr;
reg_pkt.data_byte = temp_stim_packet.register_data;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
end
else //read
begin
read_inf(1,temp_stim_packet.register_addr,reg_data_register);
reg_pkt.reg_address = temp_stim_packet.register_addr;
reg_pkt.data_byte = reg_data_register;
reg_pkt.wr_rd = 1'b0;
`vmm_callback(i2c_callback,read_reg(reg_pkt));
end
m_stim_req_chan.get(stim_packet); // get (remove) packet from channel
end //Internal register read and write check
 
// Data Transfer test-case starts
else //Data Transfer check
begin
m_stim_req_chan.get(stim_packet); // get (remove) packet from channel
enable_core;
set_prescale_register;
set_timeout_reg;
 
// DUT (W/B Driver) is in Master Mode.
if(temp_stim_packet.master_slave) //Core in Master Mode
begin
// DUT (W/B Driver) in Master Mode and Transmitting data.
if(temp_stim_packet.tr == 1) // Writing data packets to slave device
begin
 
// DUT (W/B Driver) in Master/Transmiter and in Interrupt mode.
// Driver will configure DUT in given mode and then write data to Tx reg of DUT on each posedge of irq after slave acknowledgment.
// After transmission of last byte it will configure DUT to generate Stop Signal
if(temp_stim_packet.intr_en) // Interrupt Mode
begin
write_inf(1,8'h0E, {{temp_stim_packet.slave_address},{1'b0}}); // Slave Address + rd/wr bit
reg_pkt.reg_address = 8'h0E;
reg_pkt.data_byte = {{temp_stim_packet.slave_address},{1'b0}};
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
write_inf(1,8'h04, 8'h70); //Enable the core,set mode into interrupt and tx and generate Start
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h70;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
while(byte_count != 0)
begin
@(posedge pif.irq)
begin
write_inf(1,8'h0E, temp_stim_packet.data_packet[byte_count-1]);
reg_pkt.reg_address = 8'h0E;
reg_pkt.data_byte = temp_stim_packet.data_packet[byte_count-1];
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
// vmm_callback
sb_pkt.master_slave = 1'b1;
sb_pkt.tx_rx = 1'b1;
sb_pkt.slave_address = temp_stim_packet.slave_address;
sb_pkt.data_byte = temp_stim_packet.data_packet[byte_count-1];
`vmm_callback(i2c_callback,pre_transaction(sb_pkt));
// vmm_callback
write_inf(1,8'h04, 8'h73);
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h73;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
end
byte_count-- ;
end
read_inf(1,8'h08,status_reg);
while (!status_reg[7] && !status_reg[0])
begin
read_inf(1,8'h08,status_reg);
end
if(byte_count == 0 && status_reg[7])
write_inf(1,8'h04, 8'h01); // Generate Stop Command
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h01;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
#1200; response_packet.tr = 1'b1;
end // Interrupt Mode
 
// DUT (W/B Driver) in Master/Transmiter and in Non-Interrupt mode.
//Driver will configure DUT in given mode,then it will keep on checking status register and wait for bit 7 of Status Register (TIP) to be set,
// After Slave Acknowledgment detection, it will write data to Transmit Register of DUT.
// After transmission of last byte it will configure DUT to generate Stop Signal
else // Non-Interrupt Mode
begin
write_inf(1,8'h0E, {{temp_stim_packet.slave_address},{1'b0}});
reg_pkt.reg_address = 8'h0E;
reg_pkt.data_byte = {{temp_stim_packet.slave_address},{1'b0}};
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
write_inf(1,8'h04, 8'h30); //Enable the core,set mode into non-interrupt and tx and generate Start
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h30;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
while(byte_count != 0)
begin
read_inf(1,8'h08,status_reg);
while(!status_reg[7])
begin
read_inf(1,8'h08,status_reg);
end
write_inf(1,8'h0E, temp_stim_packet.data_packet[byte_count-1]);
reg_pkt.reg_address = 8'h0E;
reg_pkt.data_byte = temp_stim_packet.data_packet[byte_count-1];
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
read_inf(1,8'h08,status_reg);
while (!status_reg[7] && !status_reg[0])
begin
read_inf(1,8'h08,status_reg);
end
// vmm_callback
sb_pkt.master_slave = 1'b1;
sb_pkt.tx_rx = 1'b1;
sb_pkt.slave_address = temp_stim_packet.slave_address;
sb_pkt.data_byte = temp_stim_packet.data_packet[byte_count-1];
`vmm_callback(i2c_callback,pre_transaction(sb_pkt));
// vmm_callback
write_inf(1,8'h04, 8'h31);
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h31;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
byte_count-- ;
read_inf(1,8'h08,status_reg);
while (!status_reg[7] && !status_reg[0])
begin
read_inf(1,8'h08,status_reg);
end
if(byte_count == 0 && status_reg[7])
write_inf(1,8'h04, 8'h01); // Generate Stop Signal
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h01;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
end
#1200; response_packet.tr = 1'b1;
end // Non-Interrupt Mode
end
 
// DUT (W/B Driver) in Master/Receiver and in Interrupt mode.
// Driver will configure DUT in given mode and then After Slave Acknowledgment detection, it will read data from Receive Register on
// on every posedge of irq. After Reception of last byte it will configure DUT to generate Stop Signal
else // Reading Data Packets from Slave Address
begin
if(stim_packet.intr_en) // Interrupt Mode
begin
write_inf(1,8'h0E, {{temp_stim_packet.slave_address},{1'b1}});
reg_pkt.reg_address = 8'h0E;
reg_pkt.data_byte = {{temp_stim_packet.slave_address},{1'b1}};
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
write_inf(1,8'h04, 8'h63); //Enable the core,set mode into interrupt and tx and generate Start
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h63;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
@(posedge pif.irq)
while(byte_count != 0)
begin
write_inf(1,8'h04, 8'h63);
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h63;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
@(posedge pif.irq)
begin
read_inf(1,8'h00,status_reg);
// $display("In Driver - Received Data in interrupt mode is %b",status_reg);
// vmm_callback
sb_pkt.master_slave = 1'b1;
sb_pkt.tx_rx = 1'b1;
sb_pkt.slave_address = temp_stim_packet.slave_address;
sb_pkt.data_byte = status_reg;
`vmm_callback(i2c_callback,post_transaction(sb_pkt));
// vmm_callback
end
byte_count--;
end
read_inf(1,8'h08,status_reg);
while (!status_reg[7])
read_inf(1,8'h08,status_reg);
if(byte_count == 0)
write_inf(1,8'h04, 8'h43); //Generate Stop Signal
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h43;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
#1200; response_packet.tr = 1'b1;
end
 
// DUT (W/B Driver) in Master/Receiver and in Non-Interrupt mode.
// Driver will configure DUT in given mode,then it will keep on checking status register and wait for bit 7 of Status Register (TIP) to be set,
// After Slave Acknowledgment detection, it will read data from Receive Register everytime TIP bit is set.
// After Reception of last byte it will configure DUT to generate Stop Signal
else // non-interrupt mode
begin
write_inf(1,8'h0E, {{temp_stim_packet.slave_address},{1'b1}});
reg_pkt.reg_address = 8'h0E;
reg_pkt.data_byte = {{temp_stim_packet.slave_address},{1'b1}};
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
write_inf(1,8'h04, 8'h20); //Enable the core,set mode into interrupt and tx and generate Start
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h20;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
read_inf(1,8'h08,status_reg);
while(!status_reg[7])
read_inf(1,8'h08,status_reg);
while(byte_count != 0)
begin
write_inf(1,8'h04, 8'h21);
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h21;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
read_inf(1,8'h08,status_reg);
while(!status_reg[7])
read_inf(1,8'h08,status_reg);
read_inf(1,8'h08,status_reg);
while (!status_reg[7] && !status_reg[0])
begin
read_inf(1,8'h08,status_reg);
end
read_inf(1,8'h00,status_reg);
// $display("In Driver - Received Data in non-interrupt mode is %b",status_reg);
// vmm_callback
sb_pkt.master_slave = 1'b1;
sb_pkt.tx_rx = 1'b1;
sb_pkt.slave_address = temp_stim_packet.slave_address;
sb_pkt.data_byte = status_reg;
`vmm_callback(i2c_callback,post_transaction(sb_pkt));
// vmm_callback
byte_count--;
read_inf(1,8'h08,status_reg);
while (!status_reg[7])
read_inf(1,8'h08,status_reg);
if(byte_count == 0 && status_reg[7] )
write_inf(1,8'h04, 8'h01); // Generate Stop signal
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h01;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
end
#1200; response_packet.tr = 1'b1;
end
end
 
end
 
// DUT (W/B Driver) in Slave mode.
else // core in slave mode
begin
// DUT (W/B Driver) in Slave Mode and Transmitting data.
if(temp_stim_packet.tr == 1) // Core in Slave mode: Receiving
begin
 
// DUT (W/B Driver) in Slave/Receiver and in Interrupt mode.
// Driver will configure DUT in given mode, on posedge on irq it will again configure core to receive data and
// then it will read data from Receive Register on every posedge of irq.
if (temp_stim_packet.intr_en) // Interrupt Mode
begin
write_inf(1,8'h0C, {{temp_stim_packet.slave_address},{1'b1}}); // Slave Address + 1'b1 bit
reg_pkt.reg_address = 8'h0C;
reg_pkt.data_byte = {{temp_stim_packet.slave_address},{1'b1}};
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
write_inf(1,8'h04, 8'h40); //Enable the core,keep it in slave mode
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h40;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
@(posedge pif.irq)
while(byte_count != 0)
begin
write_inf(1,8'h04, 8'h43);
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h43;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
@(posedge pif.irq)
begin
read_inf(1,8'h00,status_reg);
// $display("In Driver - When core is in slave mode: Received Data in interrupt mode is %b",status_reg);
// vmm_callback
sb_pkt.master_slave = 1'b0;
sb_pkt.tx_rx = 1'b1;
sb_pkt.slave_address = temp_stim_packet.slave_address;
sb_pkt.data_byte = status_reg;
`vmm_callback(i2c_callback,post_transaction(sb_pkt));
// vmm_callback
end
byte_count--;
end
end
 
// DUT (W/B Driver) in Slave/Receiver and in Non-Interrupt mode.
// Driver will configure DUT in given mode, it will keep on waiting for tip bit (bit 7) of Status Register to be set.
// After first occurance of tip to be set it will again configure DUT core to receive data and then it will read data
// from Receive Register every time tip bit of Status Register is set.
else // Non-interrupt mode
begin
write_inf(1,8'h0C, {{temp_stim_packet.slave_address},{1'b1}}); // Slave Address + 1'b1 bit
reg_pkt.reg_address = 8'h0C;
reg_pkt.data_byte = {{temp_stim_packet.slave_address},{1'b1}};
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
write_inf(1,8'h04, 8'h00); //Enable the core,keep it in slave mode , non-interrupt mode
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h00;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
read_inf(1,8'h08,status_reg);
while(!status_reg[7])
read_inf(1,8'h08,status_reg);
while(byte_count != 0)
begin
write_inf(1,8'h04, 8'h01);
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h01;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
read_inf(1,8'h08,status_reg);
while(!status_reg[7])
read_inf(1,8'h08,status_reg);
read_inf(1,8'h08,status_reg);
while (!status_reg[7] && !status_reg[0])
begin
read_inf(1,8'h08,status_reg);
end
read_inf(1,8'h00,status_reg);
// $display("In Driver - When core is in slave mode: Received Data in non-interrupt mode is %b",status_reg);
// vmm_callback
sb_pkt.master_slave = 1'b0;
sb_pkt.tx_rx = 1'b1;
sb_pkt.slave_address = temp_stim_packet.slave_address;
sb_pkt.data_byte = status_reg;
`vmm_callback(i2c_callback,post_transaction(sb_pkt));
// vmm_callback
byte_count--;
read_inf(1,8'h08,status_reg);
while (!status_reg[7])
read_inf(1,8'h08,status_reg);
if(byte_count == 0 && status_reg[7] )
write_inf(1,8'h04, 8'h01);
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h01;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
end
end
end
// DUT (W/B Driver) in Slave/Transmiter Mode.
else // Core in Slave Mode: Transmitting
begin
 
// DUT (W/B Driver) in Slave/Transmiter and in Interrupt mode.
// Driver will configure DUT in given mode and then it will write data to Transmit Register of DUT on every posedge of irq.
if (temp_stim_packet.intr_en) // Interrupt Mode
begin
write_inf(1,8'h0C, {{temp_stim_packet.slave_address},{1'b1}}); // Slave Address + 1'b1 bit
reg_pkt.reg_address = 8'h0C;
reg_pkt.data_byte = {{temp_stim_packet.slave_address},{1'b1}};
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
write_inf(1,8'h04, 8'h40); //Enable the core,keep it in slave mode , non-interrupt mode
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h40;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
while(byte_count != 0)
begin
@(posedge pif.irq)
begin
write_inf(1,8'h0E, temp_stim_packet.data_packet[byte_count-1]);
reg_pkt.reg_address = 8'h0E;
reg_pkt.data_byte = temp_stim_packet.data_packet[byte_count-1];
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
write_inf(1,8'h04, 8'h43);
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h43;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
// vmm_callback
sb_pkt.master_slave = 1'b0;
sb_pkt.tx_rx = 1'b0;
sb_pkt.slave_address = temp_stim_packet.slave_address;
sb_pkt.data_byte = temp_stim_packet.data_packet[byte_count-1];
`vmm_callback(i2c_callback,pre_transaction(sb_pkt));
// vmm_callback
end
byte_count-- ;
end
read_inf(1,8'h08,status_reg);
while (!status_reg[7])
read_inf(1,8'h08,status_reg);
if(byte_count == 0 && status_reg[7] )
begin
write_inf(1,8'h0E, 8'hFF);
reg_pkt.reg_address = 8'h0E;
reg_pkt.data_byte = 8'hFF;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
end
end
 
// DUT (W/B Driver) in Slave/Transmiter and in Non-Interrupt mode.
// Driver will configure DUT in given mode it will keep on waiting for tip bit (bit 7) of Status Register to be set
// and then it will write data to transmit register of DUT.
else // Non-Interrupt Mode
begin
write_inf(1,8'h0C, {{temp_stim_packet.slave_address},{1'b1}}); // Slave Address + 1'b1 bit
reg_pkt.reg_address = 8'h0C;
reg_pkt.data_byte = {{temp_stim_packet.slave_address},{1'b1}};
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
write_inf(1,8'h04, 8'h00); //Enable the core,keep it in slave mode , non-interrupt mode
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h00;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
while(byte_count != 0)
begin
read_inf(1,8'h08,status_reg);
while(!status_reg[7])
begin
read_inf(1,8'h08,status_reg);
end
write_inf(1,8'h0E, temp_stim_packet.data_packet[byte_count-1]);
reg_pkt.reg_address = 8'h0E;
reg_pkt.data_byte = temp_stim_packet.data_packet[byte_count-1];
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
write_inf(1,8'h04, 8'h01);
reg_pkt.reg_address = 8'h04;
reg_pkt.data_byte = 8'h01;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
// vmm_callback
sb_pkt.master_slave = 1'b0;
sb_pkt.tx_rx = 1'b0;
sb_pkt.slave_address = temp_stim_packet.slave_address;
sb_pkt.data_byte = temp_stim_packet.data_packet[byte_count-1];
`vmm_callback(i2c_callback,pre_transaction(sb_pkt));
// vmm_callback
read_inf(1,8'h08,status_reg);
while (!status_reg[7] && !status_reg[0])
begin
read_inf(1,8'h08,status_reg);
end
//write_inf(1,8'h04, 8'h01);
byte_count-- ;
end
read_inf(1,8'h08,status_reg);
while (!status_reg[7] && !status_reg[0])
begin
read_inf(1,8'h08,status_reg);
end
if(byte_count == 0 && status_reg[7])
write_inf(1,8'h0E, 8'hFF);
reg_pkt.reg_address = 8'h0E;
reg_pkt.data_byte = 8'hFF;
reg_pkt.wr_rd = 1'b1;
reg_pkt.reset_bit = 1'b0;
`vmm_callback(i2c_callback,write_reg(reg_pkt));
#1200; response_packet.tr = 1'b1;
end
end
end
end
end
 
end
endtask
 
 
endclass : i2c_master_driver
 
 
/vmm_i2c_reg_pkt.sv
0,0 → 1,44
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code defines Register Packet. This packet will be used while running //
// Register Read-Write Testcases and this packet will be sent to Scoreboard from W/B //
// Master Driver to Scoreboard and Coverage Module. //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
 
class register_pkt extends vmm_data;
 
vmm_log log;
bit [7:0] reg_address;
bit [7:0] data_byte;
bit wr_rd;
bit reset_bit;
 
function new();
super.new(this.log);
this.log = new("Reg Data", "class");
endfunction
 
function vmm_data copy(vmm_data to = null);
copy = new this;
endfunction
 
 
function void display();
this.log.start_msg(vmm_log::NOTE_TYP);
void'(this.log.text($psprintf("slave_address is %b", this.reg_address)));
void'(this.log.text($psprintf("data_byte is %b", this.data_byte)));
void'(this.log.text($psprintf("write_read is %b", this.wr_rd)));
void'(this.log.text($psprintf("reset_bit is %b", this.reset_bit)));
this.log.end_msg();
endfunction
 
endclass
/vmm_i2c_callback.sv
0,0 → 1,24
`include "vmm.sv"
 
class i2c_callback extends vmm_xactor_callbacks;
 
virtual task pre_transaction(scoreboard_pkt sb_pkt);
endtask
virtual task post_transaction(scoreboard_pkt sb_pkt);
endtask
virtual task write_reg(register_pkt reg_pkt);
endtask
virtual task read_reg(register_pkt reg_pkt);
endtask
 
virtual task send_pkt_to_monitor(stimulus_packet mon_stim_pkt);
endtask
virtual task protocol_checks_coverage(monitor_pkt mon_pkt);
endtask
 
endclass
/vmm_i2c_data_packet.sv
0,0 → 1,41
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This file is the data packet class for Scenario Generator. //
// The Packet Randomizes data_pkt whose size will be assigned in Scenario Generator. //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
 
class i2c_data_packet extends vmm_data;
vmm_log log;
rand bit [7:0] data_pkt[]; // data packets to be transfered
 
function new();
super.new(this.log);
this.log = new("Data_packet", "class");
endfunction
 
function void display();
int i;
this.log.start_msg(vmm_log::NOTE_TYP);
while( i < data_pkt.size)
begin
void'(this.log.text($psprintf("Data_Byte[%0d] is %b", i, this.data_pkt[i])));
i++;
end
this.log.end_msg();
endfunction
 
 
function vmm_data copy(vmm_data to = null);
copy = new this;
endfunction
 
endclass : i2c_data_packet
 
/vmm_i2c_interface.sv
0,0 → 1,107
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code is used to declare interface. //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
 
interface i2c_pin_if();
 
reg clk; // System_clk
logic rst; // Reset
logic [7:0] addr_in; // W/B Address Input lines
logic [7:0] data_in; // W/B Data Input lines
wire [7:0] data_out; // W/B Data Output lines
logic wb_stb_i; // W/B Strobe
logic wb_cyc_i; // W/B Cycle valid
logic we; // W/B Write Enable
wire trans_comp; // Transacation Complete
logic ack_o; // W/B Acknowledgment
wire irq; // Interrupt from DUT
logic scl_o; // SCL O/P
reg scl_oe; // SCL O/P Enable
wire scl; // SCL I/P
logic sda_o; // SDL O/P
logic sda_oe; // SDA O/P Enable
wire sda; // SDA I/P
 
 
modport dut_mp (
input clk,
input rst,
input addr_in,
input data_in,
output data_out,
input wb_stb_i,
input wb_cyc_i,
input we,
output ack_o,
output trans_comp,
output irq,
output scl ,
output scl_o,
output scl_oe,
output sda_o,
output sda_oe,
output sda
);
 
 
modport driver_mp (
input clk,
input rst,
input addr_in,
input data_in,
output data_out,
input wb_stb_i,
input wb_cyc_i,
input we,
output trans_comp,
output ack_o,
output irq,
output scl ,
output scl_o,
output scl_oe,
output sda_o,
output sda_oe,
output sda
);
 
 
modport monitor_mp (
input clk,
input rst,
input addr_in,
input data_in,
input data_out,
input wb_stb_i,
input wb_cyc_i,
input we,
input ack_o,
input trans_comp,
input irq,
input scl ,
input sda ,
input scl_o,
input scl_oe,
input sda_o,
input sda_oe
);
 
modport slave_mp (
output scl ,
output sda ,
output scl_o ,
output scl_oe,
output sda_o ,
output sda_oe
);
 
endinterface : i2c_pin_if
 
/vmm_i2c_top.sv
0,0 → 1,61
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code implements I2C M/S Core's Top Module. //
// Top Module instantiates program block and DUT and connects them with each other. //
// sda and scl lines are anded with scl and sda lines from both sides (DUT as well as //
// Environment). Both sda and scl lines are pulled up by verilog pullup construct. //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm_clkgen.sv"
`include "vmm_program_test.sv"
 
 
module top;
 
i2c_pin_if pif(); // Interface
clkgen c_gen(pif); // Clock Generator
program_test p_test(pif); // Program Block
 
wire dut_sda_o;
wire dut_sda_oe;
wire dut_sda_in;
wire dut_scl_o;
wire dut_scl_oe;
wire dut_scl_in;
wire temp_sda;
wire temp_scl;
assign dut_sda_o = 1'b0;
assign temp_sda = pif.sda_oe & dut_sda_oe;
assign temp_scl = pif.scl_oe & dut_scl_oe;
assign pif.sda = temp_sda ? 1'bz : 1'b0;
assign pif.scl = temp_scl ? 1'bz : 1'b0;
pullup p1_if(pif.sda); // Pull up sda line
pullup p2_if(pif.scl); // Pull up scl line
 
// I2C Core (DUT)
block i2c_core( .scl_in(pif.scl),
.scl_o(dut_scl_o),
.scl_oe(dut_scl_oe),
.sda_in(pif.sda),
.sda_o(dut_sda_o),
.sda_oe(dut_sda_oe),
.wb_add_i(pif.addr_in),
.wb_data_i(pif.data_in),
.wb_data_o(pif.data_out),
.wb_stb_i(pif.wb_stb_i),
.wb_cyc_i(pif.wb_cyc_i),
.wb_we_i(pif.we),
.wb_ack_o(pif.ack_o),
.irq(pif.irq),
.trans_comp(pif.trans_comp),
.wb_clk_i(pif.clk),
.wb_rst_i(pif.rst)
);
 
endmodule
/sb_callback.sv
0,0 → 1,72
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code implements all callback function defined in faced class named //
// vmm_i2c_callback. All callback functions invoke another function/task in Scoreboard //
// and Coverage Collector Module. //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
 
`include "vmm.sv"
`include "vmm_i2c_scoreboard.sv"
`include "vmm_i2c_coverage.sv"
`include "vmm_i2c_callback.sv"
`include "vmm_i2c_monitor.sv"
 
class sb_callback extends i2c_callback;
 
vmm_log log = new("scorebd_cb","CALLBACK");
scoreboard_pkt sb_pkt; // Scoreboard Packet
register_pkt reg_pkt; // Register Packet
stimulus_packet mon_stim_pkt; // Stimulus Packet
monitor_pkt mon_pkt; // Monitor Packet
i2c_scoreboard i2c_sb; // Scoreboard's Instance
i2c_coverage i2c_cov; // Coverage Instance
i2c_monitor i2c_mon; // Monitor's Instance
 
function new(i2c_scoreboard i2c_sb, i2c_coverage i2c_cov, i2c_monitor i2c_mon);
this.i2c_sb = i2c_sb;
this.i2c_cov = i2c_cov;
this.i2c_mon = i2c_mon;
endfunction
 
 
// This task invoke pre_txn_push task in Scoreboard and pre_txn_start_cov task in Coverage module and send sb_pkt as a formal argument.
virtual task pre_transaction(scoreboard_pkt sb_pkt);
this.i2c_sb.pre_txn_push(sb_pkt);
this.i2c_cov.pre_txn_start_cov(sb_pkt);
endtask
// This task invoke post_txn_push task in Scoreboard and send sb_pkt as a formal argument.
virtual task post_transaction(scoreboard_pkt sb_pkt);
this.i2c_sb.post_txn_push(sb_pkt);
endtask
// This task invoke write_reg task in Scoreboard and write_reg_cov task in Coverage module and send reg_pkt as a formal argument.
virtual task write_reg(register_pkt reg_pkt);
this.i2c_sb.write_reg(reg_pkt);
this.i2c_cov.write_reg_cov(reg_pkt);
endtask
// This task invoke read_reg task in Scoreboard and read_reg_cov task in Coverage module and send reg_pkt as a formal argument.
virtual task read_reg(register_pkt reg_pkt);
this.i2c_sb.read_reg(reg_pkt);
this.i2c_cov.read_reg_cov(reg_pkt);
endtask
 
// This task invoke get_packet_from_driver task in Monitor and send mon_stim_pkt as a formal argument.
virtual task send_pkt_to_monitor(stimulus_packet mon_stim_pkt);
this.i2c_mon.get_packet_from_driver(mon_stim_pkt);
endtask
 
// This task invoke protocol_checks_cov task in Coverage Module and send mon_pkt as a formal argument.
virtual task protocol_checks_coverage(monitor_pkt mon_pkt);
this.i2c_cov.protocol_checks_cov(mon_pkt);
endtask
 
endclass
/vmm_clkgen.sv
0,0 → 1,21
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code generates clock for the interface. //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
module clkgen(i2c_pin_if i);
 
initial begin
forever begin
#5 i.clk = 1;
#5 i.clk = 0;
end
end
 
endmodule
 
/vmm_i2c_mon_pkt.sv
0,0 → 1,46
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code defines Monitor Packet. This packet will be sent to Scoreboard and //
// Coverage Module from Monitor Transactor. //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
 
class monitor_pkt extends vmm_data;
 
vmm_log log;
bit start_bit; // Start bit
bit stop_bit; // Stop bit
bit slave_ack; // Slave Acknowledgment
bit data_ack; // Data Acknowledgment
bit intr_ack; // Interrupt Generation Acknowledgment
 
// Class Constructor
function new();
super.new(this.log);
this.log = new("Monitor Data", "class");
endfunction
 
function vmm_data copy(vmm_data to = null);
copy = new this;
endfunction
 
// Display Function
function void display();
this.log.start_msg(vmm_log::NOTE_TYP);
void'(this.log.text($psprintf("start_bit is %0b", this.start_bit)));
void'(this.log.text($psprintf("stop_bit is %0b", this.stop_bit)));
void'(this.log.text($psprintf("slave_ack is %b", this.slave_ack)));
void'(this.log.text($psprintf("data_ack is %b", this.data_ack)));
void'(this.log.text($psprintf("intr_ack is %b", this.intr_ack)));
this.log.end_msg();
endfunction
 
endclass
/vmm_i2c_scenario_generator.sv
0,0 → 1,132
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code implements Scenario Generator. Please note that this Scenario //
// Generator is coded and its different than the one getting created by using macro //
// `vmm_scenario_gen(defined in VMM). //
// //
// If type of test-case to be run is given in command line(rand_gen=0) and other //
// variable are assgined then it will use those values and then randomize only stimlus //
// packet and data packet and then stimulus packet will be sent to both drivers. //
// //
// When type of test-case to be run is not given in command line (rand_gen=1) then it //
// will randomize Scenario Packet first to find out what kind of test-case it to be run//
// Accordingly it will randomized stimulus and data_pkt and then Stimulus packet will //
// be sent to both drivers. //
// //
//////////////////////////////////////////////////////////////////////////////////////////
 
`include "vmm.sv"
class i2c_scenario_generator extends vmm_xactor;
 
vmm_log log = new("lOG", "GENERATOR");
 
scenario_packet sc_packet; // Scenario Packet
stimulus_packet stim_packet; // Stimulus Packet
i2c_data_packet d_pkt; // Data Packet
stimulus_packet_channel m_req_chan; // Scenario_Gen to W/B Driver
stimulus_packet_channel s_req_chan; // Scenario_Gen to I2C Master/Slave Driver
int stop_after_n_inst;
static int DONE; // Done to check whether all scenarios have been sent
bit rand_gen = 1'b0;
integer transaction_count;
bit master_slave;
bit register_check;
bit reset_check;
bit tx_rx;
function new( string name, string instance_name, stimulus_packet_channel m_req_chan = null, stimulus_packet_channel s_req_chan = null);
super.new("scenario_generator ", "scenario_generator");
if(m_req_chan == null) m_req_chan = new("master_stimulus_packet_channel", "m_req_chan");
this.m_req_chan = m_req_chan;
if(s_req_chan == null) s_req_chan = new("slave_stimulus_packet_channel", "s_req_chan");
this.s_req_chan = s_req_chan;
this.DONE = this.notify.configure(1,vmm_notify::ON_OFF);
sc_packet = new;
stim_packet = new;
d_pkt = new;
$value$plusargs("rand_gen=%b",rand_gen); // Gets value of read_gen from Command line
$value$plusargs("master_slave=%b",master_slave); // Gets value of master_slave from Command line
$value$plusargs("register_check=%b",register_check); // Gets value of register_check bit from Command line
$value$plusargs("reset_check=%b",reset_check); // Gets vlaue of reset_check bit from Command line
$value$plusargs("tx_rx=%b",tx_rx); // Gets value of tx_rx from Command line
endfunction
 
 
 
virtual protected task main();
super.main();
begin
string str;
stimulus_packet m_response;
stimulus_packet s_response;
`vmm_note(log,"I2C Scenario from Scenario generator");
 
while (transaction_count != 0)
begin
if(!rand_gen) // If type of test-cases to run is assigned in command line
begin
sc_packet.master_slave = master_slave;
sc_packet.transaction_count = transaction_count;
sc_packet.register_check = register_check;
sc_packet.tx_rx = tx_rx;
end
else // If type of test-cases to run is to be randomized.
begin
if(sc_packet.randomize()); else `vmm_error(log, "I2C Scenario Generator : Randomization of I2C Scenario Packet Packet Failed");
master_slave = sc_packet.master_slave;
sc_packet.transaction_count = transaction_count;
register_check = sc_packet.register_check;
reset_check = sc_packet.reset_check;
tx_rx = sc_packet.tx_rx;
end
sc_packet.display();
`vmm_note(log, $psprintf("Scenario Generator: packet to Driver @ %t", $time));
 
// If register read_write testcase are to be run, it will randomize stimulus packet for register data and addres and read/write operation.
// Other fields of stimulus packet will be assigned here only.
if(register_check) // Register test-case to be run
begin
stim_packet.master_slave = master_slave;
stim_packet.tr = tx_rx;
stim_packet.register_check = register_check;
stim_packet.reset_check = reset_check;
if(stim_packet.randomize()); else `vmm_error(log, "I2C Master Stimulus: Randomization of I2C Stimulus Packet Failed");
stim_packet.display();
this.m_req_chan.put(stim_packet); // sending packet to master driver
this.s_req_chan.put(stim_packet); // sending packet to slave driver
end
 
// If data transacation test-caser are to be run, it will stimulus packet, get the size of data_bytes(no of bytes) and again randomized
// data_pkt class for data_bytes. All fields of stimulus packet wil be assigned here and then sent to both dirvers.
 
else // Data Transacation test-case to be run
begin
stim_packet.master_slave = master_slave;
stim_packet.tr = tx_rx;
stim_packet.register_check = register_check;
stim_packet.reset_check = reset_check;
if(stim_packet.randomize()); else `vmm_error(log, "I2C Master Stimulus: Randomization of I2C Stimulus Packet Failed");
d_pkt.data_pkt = new[stim_packet.byte_count];
if(d_pkt.randomize()); else `vmm_error(log, "I2C Master Stimulus: Randomization of I2C Data Packet Failed");
stim_packet.data_packet = d_pkt.data_pkt;
stim_packet.display();
d_pkt.display();
this.m_req_chan.put(stim_packet); // sending packet to master driver
this.s_req_chan.put(stim_packet); // sending packet to slave driver
end
transaction_count--;
end
notify.indicate(DONE); // Indicate Enviorment that all scenarios have been sent to drivers.
end
endtask
 
 
endclass
 
 
/vmm_program_test.sv
0,0 → 1,24
//////////////////////////////////////////////////////////////////////////////////////////
// //
// Verification Engineer: Atish Jaiswal //
// Company Name : TooMuch Semiconductor Solutions Pvt Ltd. //
// //
// Description of the Source File: //
// This source code implements I2C M/S Core's Program Block. //
// This Program Block instantiate i2c_env and run the main thread of environment. //
// //
// //
//////////////////////////////////////////////////////////////////////////////////////////
`include "vmm_i2c_env.sv"
 
program program_test(i2c_pin_if pif);
 
initial begin
i2c_env env;
env = new(pif);
env.run();
end
 
endprogram
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.