//
// -------------------------------------------------------------
// Copyright 2010-2011 Mentor Graphics Corporation
// All Rights Reserved Worldwide
//
// Licensed under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in
// writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See
// the License for the specific language governing
// permissions and limitations under the License.
// -------------------------------------------------------------
//
//------------------------------------------------------------------------------
// Class: uvm_reg_fifo
//
// This special register models a DUT FIFO accessed via write/read,
// where writes push to the FIFO and reads pop from it.
//
// Backdoor access is not enabled, as it is not yet possible to force
// complete FIFO state, i.e. the write and read indexes used to access
// the FIFO data.
//
//------------------------------------------------------------------------------
class [docs]uvm_reg_fifo extends uvm_reg;
local uvm_reg_field value;
local int m_set_cnt;
local int unsigned m_size;
// Variable: fifo
//
// The abstract representation of the FIFO. Constrained
// to be no larger than the size parameter. It is public
// to enable subtypes to add constraints on it and randomize.
//
rand uvm_reg_data_t fifo[$];
constraint valid_fifo_size {
fifo.size() <= m_size;
}
//----------------------
// Group: Initialization
//----------------------
// Function: new
//
// Creates an instance of a FIFO register having ~size~ elements of
// ~n_bits~ each.
//
function [docs]new(string name = "reg_fifo",
int unsigned size,
int unsigned n_bits,
int has_cover);
super.new(name,n_bits,has_cover);
m_size = size;
endfunction
// Funtion: build
//
// Builds the abstract FIFO register object. Called by
// the instantiating block, a <uvm_reg_block> subtype.
//
virtual function void [docs]build();
value = uvm_reg_field::type_id::create("value");
value.configure(this, get_n_bits(), 0, "RW", 0, 32'h0, 1, 0, 1);
endfunction
// Function: set_compare
//
// Sets the compare policy during a mirror (read) of the DUT FIFO.
// The DUT read value is checked against its mirror only when both the
// ~check~ argument in the <mirror()> call and the compare policy
// for the field is <UVM_CHECK>.
//
function void [docs]set_compare(uvm_check_e check=UVM_CHECK);
value.set_compare(check);
endfunction
//---------------------
// Group: Introspection
//---------------------
// Function: size
//
// The number of entries currently in the FIFO.
//
function int unsigned [docs]size();
return fifo.size();
endfunction
// Function: capacity
//
// The maximum number of entries, or depth, of the FIFO.
function int unsigned [docs]capacity();
return m_size;
endfunction
//--------------
// Group: Access
//--------------
// Function: write
//
// Pushes the given value to the DUT FIFO. If auto-prediction is enabled,
// the written value is also pushed to the abstract FIFO before the
// call returns. If auto-prediction is not enabled (via
// <uvm_reg_map::set_auto_predict>), the value is pushed to abstract
// FIFO only when the write operation is observed on the target bus.
// This mode requires using the <uvm_reg_predictor> class.
// If the write is via an <update()> operation, the abstract FIFO
// already contains the written value and is thus not affected by
// either prediction mode.
// Function: read
//
// Reads the next value out of the DUT FIFO. If auto-prediction is
// enabled, the frontmost value in abstract FIFO is popped.
// Function: set
//
// Pushes the given value to the abstract FIFO. You may call this
// method several times before an <update()> as a means of preloading
// the DUT FIFO. Calls to ~set()~ to a full FIFO are ignored. You
// must call <update()> to update the DUT FIFO with your set values.
//
virtual function void [docs]set(uvm_reg_data_t value,
string fname = "",
int lineno = 0);
// emulate write, with intention of update
value &= ((1 << get_n_bits())-1);
if (fifo.size() == m_size) begin
return;
end
super.set(value,fname,lineno);
m_set_cnt++;
fifo.push_back(this.value.value);
endfunction
// Function: update
//
// Pushes (writes) all values preloaded using <set()> to the DUT.
// You must ~update~ after ~set~ before any blocking statements,
// else other reads/writes to the DUT FIFO may cause the mirror to
// become out of sync with the DUT.
//
virtual task [docs]update(output uvm_status_e status,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_reg_data_t upd;
if (!m_set_cnt || fifo.size() == 0)
return;
m_update_in_progress = 1;
for (int i=fifo.size()-m_set_cnt; m_set_cnt > 0; i++, m_set_cnt--) begin
if (i >= 0) begin
//uvm_reg_data_t val = get();
//super.update(status,path,map,parent,prior,extension,fname,lineno);
write(status,fifo[i],path,map,parent,prior,extension,fname,lineno);
end
end
m_update_in_progress = 0;
endtask
// Function: mirror
//
// Reads the next value out of the DUT FIFO. If auto-prediction is
// enabled, the frontmost value in abstract FIFO is popped. If
// the ~check~ argument is set and comparison is enabled with
// <set_compare()>.
// Function: get
//
// Returns the next value from the abstract FIFO, but does not pop it.
// Used to get the expected value in a <mirror()> operation.
//
virtual function uvm_reg_data_t [docs]get(string fname="", int lineno=0);
//return fifo.pop_front();
return fifo[0];
endfunction
// Function: do_predict
//
// Updates the abstract (mirror) FIFO based on <write()> and
// <read()> operations. When auto-prediction is on, this method
// is called before each read, write, peek, or poke operation returns.
// When auto-prediction is off, this method is called by a
// <uvm_reg_predictor> upon receipt and conversion of an observed bus
// operation to this register.
//
// If a write prediction, the observed
// write value is pushed to the abstract FIFO as long as it is
// not full and the operation did not originate from an <update()>.
// If a read prediction, the observed read value is compared
// with the frontmost value in the abstract FIFO if <set_compare()>
// enabled comparison and the FIFO is not empty.
//
virtual function void [docs]do_predict(uvm_reg_item rw,
uvm_predict_e kind = UVM_PREDICT_DIRECT,
uvm_reg_byte_en_t be = -1);
super.do_predict(rw,kind,be);
if (rw.status == UVM_NOT_OK)
return;
case (kind)
UVM_PREDICT_WRITE,
UVM_PREDICT_DIRECT:
begin
if (fifo.size() != m_size && !m_update_in_progress)
fifo.push_back(this.value.value);
end
UVM_PREDICT_READ:
begin
uvm_reg_data_t value = rw.value[0] & ((1 << get_n_bits())-1);
uvm_reg_data_t mirror_val;
if (fifo.size() == 0) begin
return;
end
mirror_val = fifo.pop_front();
if (this.value.get_compare() == UVM_CHECK && mirror_val != value) begin
`uvm_warning("MIRROR_MISMATCH",
$sformatf("Observed DUT read value 'h%0h != mirror value 'h%0h",value,mirror_val))
end
end
endcase
endfunction
// Group: Special Overrides
// Task: pre_write
//
// Special pre-processing for a <write()> or <update()>.
// Called as a result of a <write()> or <update()>. It is an error to
// attempt a write to a full FIFO or a write while an update is still
// pending. An update is pending after one or more calls to <set()>.
// If in your application the DUT allows writes to a full FIFO, you
// must override ~pre_write~ as appropriate.
//
virtual task [docs]pre_write(uvm_reg_item rw);
if (m_set_cnt && !m_update_in_progress) begin
`uvm_error("Needs Update","Must call update() after set() and before write()")
rw.status = UVM_NOT_OK;
return;
end
if (fifo.size() >= m_size && !m_update_in_progress) begin
`uvm_error("FIFO Full","Write to full FIFO ignored")
rw.status = UVM_NOT_OK;
return;
end
endtask
// Task: pre_read
//
// Special post-processing for a <write()> or <update()>.
// Aborts the operation if the internal FIFO is empty. If in your application
// the DUT does not behave this way, you must override ~pre_write~ as
// appropriate.
//
//
virtual task [docs]pre_read(uvm_reg_item rw);
// abort if fifo empty
if (fifo.size() == 0) begin
rw.status = UVM_NOT_OK;
return;
end
endtask
function void post_randomize();
m_set_cnt = 0;
endfunction
endclass