//----------------------------------------------------------------------------- // This confidential and proprietary software may be used only as authorized // by a licensing agreement from Synopsys Inc. In the event of publication, // the following notice is applicable: // // (C) COPYRIGHT 2003 SYNOPSYS INC. ALL RIGHTS RESERVED // // The entire notice above must be reproduced on all authorized copies. //----------------------------------------------------------------------------- // Filename : Dcr_Cpudriver.vr // // // Description : Basic DCR CPU driver // //----------------------------------------------------------------------------- #include #include typedef class Dcr_CpuDriver; class Dcr_CpuDriver_callbacks extends rvm_xactor_callbacks { //-- event to indicate that Transaction Information is driven by the Driver event trans_driven; //-- Called before a transaction is executed virtual task pre_trans_t(Dcr_CpuDriver master, Dcr_Cpu_transaction tr, var bit drop) { } //-- Called after a transaction has been executed virtual task post_trans_t(Dcr_CpuDriver master, Dcr_Cpu_transaction tr) { } } //-- Adding a definition for: //-- Dcr_CpuDriver class, derives from rvm_xactor //-- Dcr_Cpu data channel (in_chan) //-- Dcr_Cpu port (iport) class Dcr_CpuDriver extends rvm_xactor { //-- Bit to indiacte direction of transfer bit Dcr_Transfer_Direction; //-- Bit vector to sample read data from slave bit [`DCR_DBUS_WIDTH-1:0] DATA_REC; //-- integer to implement the time-out counter integer count; //-- bit to indicate whether normal/faulty test bit faulty; bit sizing; //-- Error control bits bit AddressInvalid; bit DataInvalid; bit NoWaitForNegAck; bit NoControlTransition; bit ControlSignalViolation; //-- Integer to indicate which signal is faulty integer fault_mode; //-- Input rvm_channel: this is where transactions to be sent Dcr_Cpu_transaction_channel in_chan; //-- Interface to Dcr_Cpu Bus HDL signals local Dcr_port iport; //-- RVM_Xactor Constructor and Data Members task new(string instance, integer stream_id, Dcr_port iport, Dcr_Cpu_transaction_channel in_chan = null); virtual task reset_xactor(integer rst_type = 0); protected virtual task main_t(); local virtual task process_data(Dcr_Cpu_transaction data, bit faulty, integer fault_mode); local virtual task wait_for_ack(bit RNW, bit faulty, Dcr_Cpu_transaction tr); local virtual task mtdcr(Dcr_Cpu_transaction data, bit faulty, integer fault_mode, bit sizing); local virtual task mfdcr(Dcr_Cpu_transaction data, bit faulty, integer fault_mode); local virtual task DriveTransaction (Dcr_Cpu_transaction tr); } task Dcr_CpuDriver::new(string instance, integer stream_id, Dcr_port iport, Dcr_Cpu_transaction_channel in_chan = null) { //-- Adding a call to super.new //-- Name is "Dcr_Cpu Driver" //-- Also instance and stream_id super.new("Dcr_Cpu Driver", instance, stream_id); //-- Adding the details to the new function //-- Save the iport //-- Save in_chan //-- Allocate a channel if in_chan is null //-- Drive the signals this.iport = iport; this.in_chan = in_chan; if (in_chan==null) { in_chan = new("Dcr_Cpu Driver Input Channel", instance); } this.iport.$CPU_dcrABus = 'b0; this.iport.$CPU_dcrDBusOut = 'b0; this.iport.$CPU_dcrRead = 1'b0; this.iport.$CPU_dcrWrite = 1'b0; //-- Initialize other variables this.count = 0; this.sizing = 0; this.faulty = 0; this.fault_mode = 0; this.AddressInvalid = 0; this.DataInvalid = 0; this.NoWaitForNegAck = 0; this.NoControlTransition = 0; this.ControlSignalViolation = 0; } task Dcr_CpuDriver::main_t() { Dcr_Cpu_transaction tr; fork super.main_t(); join none while(1) { // Get a transaction from the mailbox // and cast to a Dcr_Cpu_transaction cast_assign(tr, this.next_transaction_t(this.in_chan)); //-- Now it will drive the transaction if it is the first //-- one to be transmitted. Otherwise it will wait for the //-- DCR_CpuAck to be negated for the current operation prior to //-- start of a new operation //-- Note that every operation is synchronized to the posedge //-- of CPU Clock @(posedge this.iport.$CPU_clk); process_data(tr, faulty, fault_mode); } } task Dcr_CpuDriver::DriveTransaction (Dcr_Cpu_transaction tr) { //-- Discard the Transaction this.iport.$CPU_dcrWrite = tr.Cpu_Dcr_Wr; this.iport.$CPU_dcrRead = tr.Cpu_Dcr_Rd; this.iport.$CPU_dcrABus = tr.Dcr_ABus; this.iport.$CPU_dcrDBusOut = tr.Dcr_DBusOut; } task Dcr_CpuDriver::wait_for_ack(bit RNW, bit faulty, Dcr_Cpu_transaction tr) { //-- Wait for proper Acknowledgement from the slave for 16 cycles. //-- If proper response comes in-between go for the next opeartion. //-- If timeout occurs, go for the next operation while(1) { @(posedge this.iport.$CPU_clk); if(this.iport.$DCR_cpuAck == 1'b1) { this.count = 0; if(!RNW) { //-- MFDCR -> Store the data DATA_REC = this.iport.$DCR_cpuDBusIn; if(this.faulty == 1'b0) @1 this.iport.$CPU_dcrRead = 1'b0; else if(this.NoControlTransition) @1 this.iport.$CPU_dcrRead = 1'b1; } else { //-- MTDCR if(this.faulty == 1'b0) @1 this.iport.$CPU_dcrWrite = 1'b0; else if(this.NoControlTransition) @1 this.iport.$CPU_dcrWrite = 1'b1; } //-- Wait for slave Negedge Ack if(this.faulty == 1'b0) { @(negedge this.iport.$DCR_cpuAck); return; } else if(this.NoWaitForNegAck) { @(posedge this.iport.$CPU_clk); return; } } else { //-- increment the timeout counter this.count = this.count + 1; if(this.count == 16) { //-- %% Constraint %% tr.randomize () with {Cpu_Dcr_Wr == 0 && Cpu_Dcr_Rd == 0 && Dcr_ABus == 0 && Dcr_DBusOut == 0;}; DriveTransaction (tr); //-- Wait for a cycle @(posedge this.iport.$CPU_clk); this.count = 0; return; } //-- Error Injection for Control signal stability violation //-- Control signal changes during a transaction if (this.ControlSignalViolation && (random() % 8 == 0)) { if (RNW) this.iport.$CPU_dcrRead = 1'b0; else if (!RNW) this.iport.$CPU_dcrWrite = 1'b0; } } } } task Dcr_CpuDriver::process_data(Dcr_Cpu_transaction tr, bit faulty, integer fault_mode) { //-- Adding code here to process the data bit drop = 0; foreach (super.callbacks, i) { Dcr_CpuDriver_callbacks cb; if (cast_assign(cb, super.callbacks[i], CHECK)) { cb.pre_trans_t(this, tr, drop); } } if (drop) { if (this.log.start_msg(this.log.DEBUG_TYP, this.log.DEBUG_SEV)) { if (this.log.text("Dropping transaction...")) { void = this.log.text(); tr.display("Driver "); } void = this.log.text(); } return; } if (this.log.start_msg(this.log.DEBUG_TYP, this.log.TRACE_SEV)) { if (this.log.text("Starting transaction...")) { printf("\n======================================================================\n"); void = this.log.text(); tr.display("Driver "); printf("\n======================================================================\n\n"); } void = this.log.text(); } tr.notify.indicate(tr.STARTED); //-- Check for the mode of operation if(tr.Cpu_Dcr_Wr == 1'b1) { //-- mtdcr operation //-- Go for MTDCR Instruction if(this.faulty == 1'b0) mtdcr(tr, faulty, fault_mode, sizing); else mfdcr(tr, faulty, fault_mode); // Call any post-transmit callbacks foreach (this.callbacks, i) { Dcr_CpuDriver_callbacks cb; if (cast_assign(cb, this.callbacks[i], CHECK)) { cb.post_trans_t(this, tr); } } //-- Wait for SLAVE Acknowledgement wait_for_ack(1, faulty, tr); } else { //-- mfdcr operation //-- Go for MFDCR operation if(this.faulty == 1'b0) mfdcr(tr, faulty, fault_mode); else mtdcr(tr, faulty, fault_mode, sizing); // Call any post-transmit callbacks foreach (this.callbacks, i) { Dcr_CpuDriver_callbacks cb; if (cast_assign(cb, this.callbacks[i], CHECK)) { cb.post_trans_t(this, tr); } } //-- Wait for SLAVE Acknowledgement wait_for_ack(0, faulty); } } //-- Perform an MTDCR cycle task Dcr_CpuDriver::mtdcr(Dcr_Cpu_transaction data, bit faulty, integer fault_mode, bit sizing) { // %% Constraint %% if (sizing) { if (this.AddressInValid) { if (this.DataInValid) { tr.randomize () with {Cpu_Dcr_Wr == 1 && Cpu_Dcr_Rd == 0 && Dcr_ABus == 'bx && Dcr_DBusOut == 'bx;}; } else { tr.randomize () with {Cpu_Dcr_Wr == 1 && Cpu_Dcr_Rd == 0 && Dcr_ABus == 'bx; }; } } else { tr.randomize () with {Cpu_Dcr_Wr == 1 && Cpu_Dcr_Rd == 0 && (Dcr_Abus + size) >= 256 && (Dcr_Abus + size) <= 511; }; } } else { tr.randomize () with {Cpu_Dcr_Wr == 1 && Cpu_Dcr_Rd == 0;}; } DriveTransaction (tr); //-- Notify the Application Layer data.notify.indicate(data.ENDED); } //-- Perform an MFDCR cycle task Dcr_CpuDriver::mfdcr(Dcr_Cpu_transaction data, bit faulty, integer fault_mode) { // %% Constraint %% tr.randomize () with {Cpu_Dcr_Wr == 0 && Cpu_Dcr_Rd == 1;}; DriveTransaction (tr); //-- Notify the Application Layer data.notify.indicate(data.ENDED); } //-- TASK TO RESET THE TRANSACTOR task Dcr_CpuDriver::reset_xactor(integer rst_type = 0) { //-- CALL THE PARENT RESET TASK super.reset_xactor(rst_type); this.in_chan.flush(); this.iport.$CPU_dcrABus = 'b0; this.iport.$CPU_dcrDBusOut = 'b0; this.iport.$CPU_dcrRead = 1'b0; this.iport.$CPU_dcrWrite = 1'b0; }