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 |
|
|