VR Ad Lib2.0
VR Ad Lib2.0
Memory Package
Version 2.0
Legal Notice
Copyright © 2003-2005 Verisity Design, Inc. All rights reserved.
Trademarks
Verisity, the Verisity logo, eAnalyzer, eCelerator, eRM, Invisible Specman, LicenseE, Pure
IP, Specman, Specman Elite, SpeXsim, SpeXtreme, SureCov, SureLint, SureSolve, sVM,
Verification Advisor, Verification Alliance, Verification Vault, Verification Viewport,
Visualization Toolkit, vManager, vPlan, Xbench, Xchange, Xcite, XoC, Xpert, Xsim, and
Xtreme are either trademarks or registered trademarks of Verisity Design, Inc. in the
United States and/or other jurisdictions. All other trademarks are the exclusive property of
their respective owners.
Confidentiality Notice
Verisity confidential; do not distribute. The contents of this document constitute valuable
proprietary and confidential property of Verisity Design, Inc. No part of this information
product may be reproduced, transmitted, or translated in any form or by any means,
electronic, mechanical, manual, optical, or otherwise without prior written permission
from Verisity Design, Inc.
Information in this product is subject to change without notice and does not represent a
commitment on the part of Verisity. The information contained herein is the proprietary
and confidential information of Verisity or its licensors, and is supplied subject to, and may
be used only by Verisity’s customers in accordance with, a written agreement between
Verisity and its customers. Except as may be explicitly set forth in such agreement,
Verisity does not make, and expressly disclaims, any representations or warranties as to the
completeness, accuracy, or usefulness of the information contained in this document.
Verisity does not warrant that use of such information will not infringe any third party
rights, nor does Verisity assume any liability for damages or costs of any kind that may
result from use of such information.
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Index-1
• Section 1.1, “Introduction to the Register and memory package,” on page 1-1
• Section 1.2, “Overview of the Register and Memory Package,” on page 1-3
• Section 1.3, “Architecture of the Register Model,” on page 1-7
• Section 1.4, “Integration of the Register Model,” on page 1-16
• Section 1.5, “Creating Register Sequences,” on page 1-20
• Section 1.6, “Using the Register Features,” on page 1-31
• Section 1.7, “Sparse Memory,” on page 1-48
• Section 1.8, “Register and Memory Data Structures,” on page 1-59
• Section 1.9, “Address Management (Sets),” on page 1-91
• Section 1.10, “Registers Visualization,” on page 1-98
• Section 1.11, “Register and Memory Commands,” on page 1-104
The package addresses three independent aspects: address management, register modeling, and memory
modeling.
• Section 1.1.1, “Main Features of the Register and Memory Package,” on page 1-2
• Section 1.1.2, “Naming Conventions,” on page 1-2
• Section 1.1.3, “Compilation,” on page 1-2
1.1.3 Compilation
The register and memory package (vr_ad) includes some macro definitions. Therefore, if you want to
compile the package with user code that relies on the package, you must compile the package first and
then compile the user code on top of the package.
• Register File — Represents DUT agent registers. It contains a list of consecutive registers.
• Address Map — Represents the address space. It maps the register files and the memory blocks (if
any) in the address space, and it contains references to them. In a very simple environment with only
one register file, an address map may seem redundant. Address maps gain importance in environments
with multiple register files.
• Register Sequence Driver (RSD) — A dedicated sequence driver for register operations. The
functionality of the RSD resembles that of a virtual sequence driver.
ex_c_bus env
RSD Register
Address File
Map
SD
Figure 1-2 shows the connection between the various elements of the register and memory package.
For a detailed description of the data structures, see Chapter 1 “The Register and Memory Package”.
To create and integrate the register model into your ex_c_bus environment:
For example, you could define a register file named XCORE with a size of 256 bytes and reset all
registers as follows:
extend vr_ad_reg_file_kind : [XCORE];
extend XCORE vr_ad_reg_file {
keep size == 256;
post_generate() is also {
reset();
};
};
For details on defining a register file, see “Defining a Register File” on page 1-9.
For example, you could instantiate the XCORE register file under the ex_c_bus env as follows:
extend ex_c_bus_env {
reg_file : XCORE vr_ad_reg_file;
};
For details on where and how to instantiate the register file, see “Instantiating the Register File in the
Architecture” on page 1-14.
The register sequence driver must be linked to the address map and it must have a default BFM
sequence driver.
For example, you could use the ex_c_bus env to instantiate both the address map and the register
sequence driver. You could use the BFM sequence driver of masters[0] as the default driver for the
register sequence driver (RSD).
extend ex_c_bus_env {
addr_map : vr_ad_map;
rsd: vr_ad_sequence_driver is instance;
keep rsd.addr_map == value(addr_map);
keep rsd.default_bfm_sd == masters[0].driver;
};
For details on instantiating the address map and the RSD, see “Instantiating the Address Map and
the RSD” on page 1-15.
5. Allocate an address space for the register file by adding it to the address map at the desired offset.
For example, you could allocate addresses starting from 0x0 as follows:
extend ex_c_bus_env {
post_generate() is also {
addr_map.add_with_offset(0,reg_file);
};
};
For details on adding the register file to the address map, see “Adding the Register File to the
Address Map” on page 1-15.
6. Implement the eVC BFM sequence driver’s vr_ad_execute_op() method, which takes the contents
of the register operation and executes it.
This is necessary for layering the register sequences on top of the eVC. For example, your
implementation of vr_ad_execute_op might use the read() and write() sequence methods as
follows:
extend ex_c_bus_driver {
7. Bind the eVC monitor to the address map for updating the register model and collecting coverage.
For example, you could use the transfer_end event detected by the monitor. The update() method is
called for write operations. The compare_and_update() method is called for read operations.
extend vr_xbus_bus_monitor_u {
on transfer_end {
if transfer.read_write == WRITE {
get_enclosing_unit(vr_xbus_env_u).addr_map.update(
transfer.addr,pack(packing.low,transfer.data),{});
} else {
compute get_enclosing_unit(vr_xbus_env_u).\
addr_map.compare_and_update(transfer.addr,
pack(packing.low,transfer.data));
};
};
};
For details on updating the registers from a monitor, see “Updating the Register Model Using an eVC
Monitor” on page 1-20.
You can now create register sequences and access the registers using the write_reg and read_reg
macros. For example:
extend vr_ad_sequence_kind: [MY_SEQ];
extend MY_SEQ vr_ad_sequence {
!tx_data : EX_REG_TX_DATA vr_ad_reg;
body() @driver.clock is only {
write_reg tx_data;
read_reg tx_data;
};
};
For details on accessing the registers, see “write_reg and read_reg Macros” on page 1-23.
• Typically each XCore is represented by a module eVC. The best place to instantiate the register file
is in the module eVC. If your environment does not have a module eVC, you can instantiate the
register file in the XBus env or in the PASSIVE slave agent.
• The XBus passive slave has a reference to the register file instantiated in the module eVC.
• The XBus env has the address map and the register sequence driver (RSD).
• The RSD is layered on top of the BFM sequence driver.
2. Define the register types and optionally add instances of those registers into a register file (using the
reg_def macro).
3. Instantiate the register file in the architecture (for example, in an agent) with no absolute address
assigned yet.
4. Instantiate the address map and the register sequence driver in the environment.
5. Add the register file to the address map (setting the absolute base address for the register file). This
can be done at runtime or at post-generate.
• Section 1.3.1, “Defining the Register Address and Data Width,” on page 1-8
• Section 1.3.2, “Defining a Register File,” on page 1-9
• Section 1.3.3, “Defining Registers with the reg_def Macro,” on page 1-9
• Section 1.3.4, “Instantiating the Register File in the Architecture,” on page 1-14
• Section 1.3.5, “Instantiating the Address Map and the RSD,” on page 1-15
• Section 1.3.6, “Adding the Register File to the Address Map,” on page 1-15
If your address or data width exceeds these default settings, you must change them to the highest value
to be used in your verification environment. As these statements define the actual types used in the
model, they must be set before the vr_ad package is loaded. For example, if your largest registers are 64
bits wide, you must define VR_AD_DATA_WIDTH to be 64, and your configuration file must start
with the following lines:
define VR_AD_DATA_WIDTH 64;
import vr_ad/e/vr_ad_top;
If your address space is a 64 bits wide, you must define VR_AD_ADDR_WIDTH to be 64, and your
configuration file must start with:
define VR_AD_ADDRESS_WIDTH 64;
import vr_ad/e/vr_ad_top;
Syntax
reg_def reg-name [register-file-name offset] {
reg_fld field-name : field-type : field-mask : field-reset-value [: cov];…
};
Syntax example:
reg_def EX_REGS_TX_MODE XCORE 0x100 {
reg_fld dest : uint(bits:2) : RW : 0x0 : cov;
reg_fld frame_kind : [DATA,MESSAGE,A,B](bits:2) : RW : DATA : cov;
};
Parameters
reg_name Register name — Must follow eRM naming conventions and use a
company prefix
register-file-name (Optional) Name of the register file where the register is instantiated
Notes
• The keyword reg_fld automatically defines the register field as a physical field (%).
• The reset value must be a legal value for the type of the declared field. For example, if the field is
defined as Boolean, the reset value must be either TRUE or FALSE. Fields that are structs or lists
should get a number for the entire field.
• You can specify only the field name and type. In that case, the default mask is RW, and the reset value
is 0.
Example
You could create an “EX_REGS_TX_MODE” register with several fields and instantiate a copy of it
under the XCORE register file as follows:
// NAME FILE OFFSET
reg_def EX_REGS_TX_MODE XCORE 8’h03 {
// Custom Fields
reg_fld dest : uint(bits:2) : RW : 0 : cov;
reg_fld frame_kind : [DATA,MESSAGE,A,B](bits:2) : RW : DATA : cov;
reg_fld resv : uint(bits:4) : RW : 0 ;
};
The default field order of a register is from high bit position to low bit position. For example, the field
order of the EX_REGS_TX_MODE register is:
extend EX_REGS_TX_MODE vr_ad_reg {
%dest : uint(bits:2); // Bits [7:6]
For instructions on changing the default field order, see “Changing the Register Field Order” on page
1-43.
Note The name of the register that is automatically added to the register file is the register kind
in lower case. So, with the above example, you can directly access the register
xcore_reg_file.ex_regs_tx_mode.
See Also
• “Fields and Methods of vr_ad_reg” on page 1-71
1. Create the register type using the reg_def macro, but do not specify a register file name or offset.
For example:
// NAME
reg_def EX_REGS_PORT_CONTROL {
reg_fld control : port_control_kind_t;
};
2. Extend the register file to add instances of the register type using the add_with_offset() method.
For example:
extend vr_ad_reg_file_kind : [PORTS];
extend PORTS vr_ad_reg_file {
port_regs[4] : list of EX_REGS_PORT_CONTROL vr_ad_reg;
post_generate() is also {
for each (p) in port_regs {
add_with_offset(index*4, p);
};
};
};
Note You can also use the reg_list macro here (see “reg_list Macro” on page 1-13).
Syntax
reg_list list-name[list-size] of reg-kind at offset;
Syntax example:
extend EX_FILE vr_ad_reg_file {
reg_list regs[128] of EX_REG at 0x1000;
};
Parameters
offset Starting address from which the registers are subsequently added
};
// Add Mirror address
extend XCORE vr_ad_reg_file {
post_generate() is also {
add_with_offset(0x10,ex_regs_tx_mode);
// Note: ex_regs_tx_mode is automatically defined by the
// "reg_def" macro as a field of the XCORE register file.
};
};
See Also
• add_with_offset() on page 1-75
Example
The following code would be automatically created by the register definition in the example found in
“Mirroring Registers” on page 1-13.
See Also
• Chapter 1 “The Register and Memory Package”
For example:
extend PASSIVE SLAVE vr_xbus_agent_u {
reg_file : XCORE vr_ad_reg_file;
};
If you want to use register sequences, an RSD must also be instantiated at the same place and connected
to the address map. The RSD gets the information it requires for accessing registers from the address
map. The RSD should also be connected to a default BFM SD (for example, an xbus sequence driver) so
that it can perform the register operation according to the specific bus protocol.
};
};
See Also
• add_with_offset() on page 1-79
See Also
• add_with_offset() on page 1-79
1. Connect the eVC monitor to the address map of the register model.
The monitor identifies DUT activity. For WRITE transactions, it updates the register model via the
update() method. For READ transactions it checks the received data via the
compare_and_update() method.
The vr_ad_execute_op() method lets you layer the RSD on top of the BFM SD.
Note This step is needed only when the register and memory package drives registers.
The register operation flow can be divided into two parts as follows:
Driving Registers
1. The RSD activates the appropriate BFM sequence driver by calling its vr_ad_execute_op() method.
2. The BFM sequence driver executes the operation using the associated BFM.
Monitoring
4. The monitor in the PASSIVE slave picks up transactions on the bus.
5. The monitor notifies the address map by calling the update() method.
• Section 1.4.1, “Integrating the RSD with the BFM Sequence Driver,” on page 1-18 (Steps 1-3)
• Section 1.4.2, “Updating the Register Model Using an eVC Monitor,” on page 1-20 (Steps 4-6)
The information needed for creating eVC-specific register access is available through the operation
parameter. The returned value of the method is a list of byte, used only for READ operations.
Table 1-1 describes the information that is typically required from the operation parameter.
Field/Method Description
addr_space Address space identifier (required only if you use it in the register
sequences)
byte_enable Byte enable (required only if you use it in the register sequences)
Example 1
You could implement the vr_ad_execute_op() method for the Verisity XBus eVC as follows.
extend vr_xbus_master_seq_kind : [REG_SEQ]
extend vr_xbus_master_driver_u {
// This example uses a dedicated sequence instead of MAIN for executing
Note The above implementation uses the read and write methods of the native sequence. The
implementation of these methods is recommended by eRM. They are described in the section
on “Enhancing the User Interface” of the e Reuse Methodology (eRM) Developer Manual.
The read() and write() methods of the Verisity XBus eVC sequences are implemented as follows:
extend vr_xbus_master_sequence {
!trans: MASTER vr_xbus_trans_s;
// This method performs one write transfer on the bus.
write(size : uint, addr : uint(bits:16),
data : uint(bits:64)) @driver.clock is {
assert size in [1, 2, 4, 8];
do trans keeping {
.addr == addr;
.read_write == WRITE;
.size == size;
.data == pack(packing.low, data[size*8-1:0]);
};
};
// This method performs one read transfer on the bus.
read(size : uint, addr : uint(bits:16)) :
uint(bits:64) @driver.clock is {
assert size in [1, 2, 4, 8];
do trans keeping {
.addr == addr;
.read_write == READ;
.size == size };
if trans != NULL {
result = pack(packing.low, trans.data);
} else {
out("trans is NULL");
};
};
};
See Also
• Verisity XBus documentation
Notes
• Typically monitors contain an event (for example, transaction_end) that can be used for updating.
• Monitors should have access to a register file or address map. In the above example, access is achieved
through a reference to the address map in the env. If the register file is local to the agent enclosing
the monitor, the monitor can access it directly.
As this syntax tends to get complicated when many constraints are needed or when indirect accessing is
required, Verisity recommends using the macros described in “write_reg and read_reg Macros” on page
1-23. The macros provide a more efficient implementation than the preceding example.
Table 1-2 and Table 1-3 list all controllable fields in vr_ad_operation and vr_ad_sequence. The rest of
this section provides more details on how and when to constrain these fields.
byte_enable: vr_ad_data_t Can be used for specifying byte enables. vr_ad does
not use this value but just passes it on to the
vr_ad_execute_op() method. The implementation of
vr_ad_execute_op() must take care of the
byte_enable
prevent_test_done: bool TRUE to prevent the test from finishing as long as the
sequence is running
Note Fields that appears both in vr_ad_operation and in vr_ad_sequence, by default, inherit
their values from their patent sequence.
Syntax
write_reg [{op-block-constraints}]
register-field [{register-block-constraints}]|[val[ue] register-value-exp]
Parameters
Usage
For an example of using op-block-constraints, see “Writing to a Specific Instance of a Register Type” on
page 1-26.
2. Create a copy of the register using the copy() method and cast it to the exact register subtype.
4. Write the copy of the register back using the write_reg macro.
Example
extend MAIN vr_ad_sequence {
!xmode : EX_REGS_TX_MODE vr_ad_reg;
body() @driver.clock is only {
xmode = driver.addr_map.get_reg_by_kind(EX_REGS_TX_MODE).copy()\
.as_a(EX_REGS_TX_MODE vr_ad_reg);
xmode.dest = 2; // Modify field value
write_reg xmode {it == xmode}; // Write back the modified register.
};
};
Example 1
In the following example, there are two instances of the XCORE register file, located at address 0x100
and 0x200. The static_item field is constrained to a specific instance of the register file. Inside the
register file, the registers can be located uniquely by their type.
extend MAIN vr_ad_sequence {
!tx_data : EX_REGS_TX_DATA vr_ad_reg;
body() @driver.clock is only {
var reg_file1 : XCORE vr_ad_reg_file =
driver.addr_map.get_reg_file_by_address(0x100);
var reg_file2 : XCORE vr_ad_reg_file =
driver.addr_map.get_reg_file_by_address(0x200);
// Access tx_data of reg_file1
write_reg {.static_item == reg_file1} tx_data {.data == 0xaa};
// Access tx_data of reg_file2
write_reg {.static_item == reg_file2} tx_data {.data == 0xbb};
read_reg {.static_item == reg_file1} tx_data;
read_reg {.static_item == reg_file2} tx_data;
};
};
Example 2
In the following example, the register file contains a list of registers of the same type. The register type
is not unique inside the register file. Therefore, you must constrain the address of the operation to the
right register address. Alternatively, you can constrain the static_item field to the specific register
instance.
// Define EX_PORT_CTL register type.
reg_def EX_PORT_CTL {
reg_fld enable : bool;
reg_fld cmd : uint(bits:31);
};
// Add multiple instances of EX_PORT_CTL to the register file
extend PORTS vr_ad_reg_file {
port_regs[4] : list of EX_PORT_CTL vr_ad_reg;
post_generate() is also {
for each (p) in port_regs {
add_with_offset(index*4, p);
};
};
};
// Write to specific instances in the register list. When the PORTS
// register file is located at address 0x100, the first register in the
// register file is located at address 0x100, the second register is
// located at address 0x104...
Note If more than one instance exists and no static_item or address is specified, an error
message is issued.
See Also
• “write_reg and read_reg Macros” on page 1-23
• add_with_offset() on page 1-75
Field Description
reg_addr : vr_ad_addr_t Register address (not to be used with reg_kind at the same time)
Field Description
Example 1
Reading a random register out of the address map registers:
extend MAIN vr_ad_sequence {
!simple : SIMPLE vr_ad_sequence;
body() @driver.clock is only {
do simple keeping {
.direction == READ;
};
};
};
Example 2
Writing 0xaaaa to EX_REGS_TX_MODE register:
extend MAIN vr_ad_sequence {
!simple : SIMPLE vr_ad_sequence;
body() @driver.clock is only {
do simple keeping {
.reg_kind == EX_REGS_TX_MODE;
.direction == WRITE;
.reg_data == 0xaaaa;
};
};
};
Field Description
Example
You could write an entire register file using the ALL_REGS_IN_FILE sequence as follows.
2. Write the content of the file image to the DUT according to your preferred order.
// Write the register file in an ASCENDING order
do rgf_seq keeping {
.reg_file == xcore;
.order == ASCENDING;
.direction == WRITE
};
};
};
ALL_REGS_IN_FILE accesses each register in the register file. Following is a partial example of the
sequence body. For the full implementation, see the vr_ad_reg_file_random_access.e example.
extend ALL_REGS_IN_FILE vr_ad_sequence {
order : vr_ad_access_order;
direction : vr_ad_rw_t;
reg_file_kind : vr_ad_reg_file_kind;
keep soft reg_file_kind in
driver.addr_map.get_all_reg_files().kind;
reg_file : vr_ad_reg_file;
keep soft reg_file == NULL;
!all_reg_nodes : list of vr_ad_node;
body() @driver.clock is {
..............
if order == RANDOM {
// Gen a permutation of the registers
gen all_reg_nodes keeping {
it.is_a_permutation(reg_file.get_all_nodes());
};
} else if order == ASCENDING {
all_reg_nodes = reg_file.get_all_nodes();
} else {
all_reg_nodes = reg_file.get_all_nodes().reverse();
};
// Go over all registers
for each (node) in all_reg_nodes {
do op keeping {
.address == reg_file_offset + node.offset;
.reg == node.ad_item.as_a(vr_ad_reg);
.direction == direction;
};
};
};
};
The post_access() hook method can be used for checking the legality of the register values. For
example, you could verify that a reserved field (resv) of EX_REGS_TX_MODE is always zero as
follows:
extend EX_REGS_TX_MODE vr_ad_reg {
post_access(direction : vr_ad_rw_t) is only {
check that resv == 0 else
dut_error("resv value must be 0 in ", me);
};
};
You can also use the post_access() hook to implement side effects such as “clear on read”:
extend EX_REGS_TX_MODE vr_ad_reg {
// Clear on Read
post_access(direction : vr_ad_rw_t) is {
if direction == READ {
write_reg_val(0x0);
};
};
};
The pre_access() hook method provides similar capabilities for actions needed just before the register is
accessed.
The static_info struct of the register contains information related to the last executed operation:
For a full list of the fields of static_info, see vr_ad_reg_static_info on page 1-73.
These values can be used to update the corresponding value in the agent. For example you could update
the value of “cur_reg_value” in the agent based on the previous value and the value written into
EX_REGS_TX_MODE as follows:
extend EX_REGS_TX_MODE vr_ad_reg {
post_access(direction : vr_ad_rw_t) is only {
if static_info.written_data ==
0x1 and static_info.prev_value == 0x3 {
get_enclosing_unit(vr_abus_agent).cur_reg_value =
static_info.cur_value;
};
};
};
See Also
• “Fields and Methods of vr_ad_reg” on page 1-71
• write_reg_val() on page 1-62
1.6.2 Reset
Each register has a reset value specified in the reg_def macro. This value is restored automatically
whenever the reset() method is called for any register. Typically, reset() is called for register files or
address maps. In that case, the appropriate reset value is assigned to each contained register instance. For
example:
extend XCORE vr_ad_reg_file {
post_generate() is also {
reset();
};
};
1.6.3 Coverage
Coverage information is collected on each register access, that is, each time the update(), fetch(), or
compare_and_update() method is called.
See Also
• “reg_def Macro” on page 1-10
Sometimes you might want to ignore some of the predefined coverage values, for example, when a status
register can only be read and should never be written.
See Also
• vr_ad_reg_static_info on page 1-73
If you constrain a sequence to run entirely in backdoor mode, there is no need to specify backdoor mode
for each do inside the sequence.
See Also
• “write_reg and read_reg Macros” on page 1-23
You might require a non-standard implementation, for example, when your register has fields with a
different backdoor_path.
See Also
• “Fields and Methods of vr_ad_reg” on page 1-71
• vr_ad_reg_static_info on page 1-73
To change read access results to be taken directly from the address map:
• Constrain vr_ad_sequence_driver.bd_read_from_addr_map to be TRUE.
For example:
extend my_env {
rsd : vr_ad_sequence_driver;
keep rsd.bd_read_from_addr_map == TRUE;
};
Unmapped registers must reside in an unmapped register file. If a register file is to be used for indirect
access:
• Do not assign an address to the unmapped register file (in other words, do not use
vr_ad_map.add_with_offset()).
• Add the unmapped register file to the addr_map.reg_file_list by calling
vr_ad_map.add_unmapped_item().
• Driving a register indirectly must be translated into a sequence of accesses to the corresponding
address and data registers (see Section 1.6.5.1, “Driving Indirect Registers,” on page 1-40).
• Any access to the data register must be passed to the unmapped register file (see Section 1.6.5.2,
“Identifying and Handling Indirect Access,” on page 1-42).
See Also
• vr_ad_map on page 1-78
Note Indirect access cannot be accomplished with the do operation. You must use the
write_reg macro.
1. Implement a dedicated sequence of INDIRECT sequence mode to carry out all necessary operations
required for accessing the indirect register.
Note INDIRECT is another subtype and not the sequence name. The INDIRECT sequence
subtype contains several fields to be used in the sequence implementation. See “Fields of INDIRECT
vr_ad_sequence” on page 41.
2. Use set_indirect_seq_name() to inform the unmapped register file which sequence to execute upon
driving its registers.
Each time you access an unmapped register, the access is automatically translated to the appropriate
sequence of mapped register accesses.
3. Add the unmapped register file to the address map using add_unmapped_item() (instead of
add_with_offset()).
reg: vr_ad_reg INDIRECT Content of the unmapped register. For WRITE access, it
contains the data for the register access. For READ
access, you must update the register value
Unmapped registers have no absolute addresses but only offsets in the unmapped register file where they
reside. The vr_ad_reg.get_indirect_addr() method can be used to obtain the offset of the register in the
unmapped register file.
Example 1
This example contains an indirect sequence, ACTIVE_XCORE. It is extended with the subtype,
ACTIVE_XCORE INDIRECT.
extend vr_ad_sequence_kind : [ACTIVE_XCORE];
extend ACTIVE_XCORE INDIRECT vr_ad_sequence {
!ind_addr : EX_REGS_IND_ADDR vr_ad_reg;
!ind_data : EX_REGS_IND_DATA vr_ad_reg;
body() @driver.clock is only {
if direction == WRITE {
write_reg ind_data {.data == reg.read_reg_val()};
write_reg ind_addr {.addr==
reg.get_indirect_addr(driver.addr_map)};
} else {
write_reg ind_addr {.addr ==
reg.get_indirect_addr(driver.addr_map)};
read_reg ind_data;
// Update the returned register
reg.write_reg_val(ind_data.read_reg_val());
};
};
};
Example 2
This example shows how to use the vr_ad_reg_file.set_ indirect_seq_name() method to apply the
indirect register sequence (ACTIVE_XCORE) to the unmapped register file.
extend ex_c_bus_env {
indirect_reg_file : XCORE vr_ad_reg_file;
post_generate() is also {
indirect_reg_file.set_indirect_seq_name(ACTIVE_XCORE);
addr_map.add_unmapped_item(indirect_reg_file);
};
};
See Also
• “write_reg and read_reg Macros” on page 1-23
• vr_ad_reg_file on page 1-74
1. Connect the unmapped register file to the appropriate mapped register by calling vr_ad_reg.attach()
with the register file as a parameter.
The mapped register notifies the unmapped register file when any access occurs.
2. Implement the vr_ad_reg_file.indirect_access() method to define the behavior of the register file
upon notification.
Example 1
You could connect the unmapped register file to the mapped data register as follows.
extend ex_c_bus_env {
indirect_reg_file : XCORE vr_ad_reg_file
mapped_reg_file : MAP_REGS vr_ad_reg_file;
post_generate() is also {
// Set the unmapped reg file for notification
mapped_reg_file.ind_data.attach(indirect_reg_file);
};
};
Example 2
You could implement notification handling for the unmapped register file via
vr_ad_reg_file.indirect_access() as follows.
extend XCORE vr_ad_reg_file {
!ind_addr : VR_AD_IND_ADDR vr_ad_reg; // Reference to the addr register
!ind_data : VR_AD_IND_DATA vr_ad_reg; // Reference to the data register
// indirect_access()
// On WRITE operation - update the relevant unmapped register.
// On READ operation - update the (mapped) VR_AD_IND_DATA register.
indirect_access( direction : vr_ad_rw_t, ad_item : vr_ad_base) is {
if ad_item is a VR_AD_IND_DATA vr_ad_reg {
if direction == WRITE {
// Update The unmapped register-file
update(ind_addr.addr,
pack(packing.high,ind_data.data), {});
} else { // READ
// Update the mapped data register with data from the
// unmapped reg-file
ind_data.data = fetch(ind_addr.addr,1)[:];
};
};
};
};
Some specs use the opposite field order (packing.low). They interpret the same register definitions as:
// NAME FILE OFFSET
reg_def EX_REGS_RX_MODE XCORE 32'h00000003 {
reg_fld dest : uint(bits:2); // Bits [1:0]
reg_fld frame_kind : uint(bits:2); // Bits [3:2]
You can change the register packing option for a register file from packing.high to packing.low. The
change affects the packing option for all registers in the file. You cannot change the order for only some
of the registers in a register file.
To change the default packing option of a register file from packing.high to packing.low:
• Constrain vr_ad_reg_file.packing_mode to packing.low.
For example:
extend YCORE vr_ad_reg_file {
keep packing_mode == packing.low;
};
See Also
• vr_ad_reg_file on page 1-74
Sometimes the required address width is Halfword or Word. In that case, each address entry will contain
two or four bytes instead of one byte as follows:
word1 0x0
word2 0x1
word3 0x2
See Also
• “Basic Register Operations” on page 1-21
To turn on all messages coming from the register and memory package:
• Use the set message command.
For example:
set message @vr_ad_*
Or:
To filter out all messages coming from the register and memory package:
• Use the set message command with the -remove option.
For example:
set message -remove @vr_ad_*
Or:
The preceding examples assume that the messages are handled by sys.logger. For more information, see
the section on messaging in the e Reuse Methodology (eRM) Developer Manual.
1. Label each address map with a different enumerated value, and use
vr_ad_sequence_driver.add_space() to add each address map with its label to the RSD map list.
For example:
extend vr_ad_space_kind : [EX_IO, EX_CONFIG1];
extend ex_c_bus_env {
addr_map1 : vr_ad_map;
addr_map2 : vr_ad_map;
rsd : vr_ad_sequence_driver;
post_generate() is also {
// Two address spaces can be accessed through the bus
rsd.add_space(addr_map1, EX_CONFIG1);
rsd.add_space(addr_map2, EX_IO);
};
};
2. Use the label in the sequence to specify which address map to access.
For example:
extend MAIN vr_ad_sequence {
!r2 : EX_R2 vr_ad_reg;
// By default, register accesses use the IO space
keep soft addr_space == EX_IO;
body() @driver.clock is only {
...
// Use the CONFIG1 space for this access
write_reg {.addr_space == EX_CONFIG1 } r2 keeping {.data1 == 3};
};
};
Note The sparse memory feature is still at an alpha level of development. For more
information, see the sVM release notes.
1. Extend vr_ad_mem_kind, and add a new kind (according to eRM naming conventions).
2. Extend the relevant unit by adding a field of the specific vr_ad_mem subtype, and constrain the
memory to the appropriate size.
3. Add the memory to the address space using add_with_offset() (same as adding a register file)
For example, assuming that the memories of the slaves are mapped in consecutive addresses, you
could map all active XBus slaves as follows:
extend vr_xbus_env {
post_generate() is also {
for each (slave) in active_slaves {
addr_map.add_with_offset(index*1000,slave.mem);
};
};
};
To access a memory:
• Use the predefined field mem_op as a sequence item and constrain its address, data, and direction.
For example:
extend MAIN vr_ad_sequence {
body() @driver.clock is only {
do mem_op keeping {
.direction == WRITE;
.address == 0x10;
.data == {1;2;3;4;5;6;7;8};
};
};
};
Note The above code has an abbreviated form using the write_mem and read_mem macros.
See “write_mem and read_mem Macros” on page 1-49.
Syntax
write_mem [{op-block-constraints}] address write-data-exp [mask]
Parameters
Syntax Example
var data : list of byte;
read_mem 0x100 data 4;
write_mem 0x110 data;
Example
Writing and reading from a memory.
extend vr_ad_sequence_kind : [EX_SEQ1];
For example:
extend vr_xbus_bus_monitor_u {
on transfer_end {
if transfer.read_write == WRITE {
env.address_map.update(transfer.addr,%{transfer.data},{});
} else {
env.address_map.compare_and_update(
transfer.addr,%{transfer.data});
};
};
};
See Also
• “Updating the Register Model Using an eVC Monitor” on page 1-20.
For example:
extend vr_ad_mem_kind : [EX_MEM];
extend ACTIVE SLAVE vr_xbus_agent {
mem : EX_MEM vr_ad_mem;
};
extend EX_MEM vr_ad_mem {
get_data(addr : vr_ad_addr_t, size : uint) : list of byte is only {
if address < 0x100 {
// Set the size of the list and fill it with 0xbb
result.resize(size,TRUE,0xbb,TRUE);
} else {
// Set the size of the list and fill it with 0xaa
result.resize(size,TRUE,0xaa,TRUE);
};
};
};
See Also
• “Implementing Side Effects” on page 1-32
For example:
extend ACTIVE SLAVE vr_xbus_agent {
mem : EX_MEM vr_ad_mem;
keep mem.size == 0x1024;
keep mem.backdoor_path == "~/top/sram";
};
For example:
verilog variable ’~/top/sram[99:0][7:0]’;
See Also
• “Backdoor Operation” on page 1-36
See Also
• “Accessing Objects in Memory” on page 1-57
Syntax
mem_obj_def obj-name {
mem_fld field-name : field-type [: cov];…
};
Syntax Example
mem_obj_def EX_DESC {
mem_fld kind : uint(bits:2) : cov;
mem_fld data[16] : list of byte : cov;
};
Parameters
obj_name Memory object name. Must follow eRM naming conventions and use a
company prefix
• The memory content can be updated using object methods (see “Methods for Accessing Objects in
Memory” on page 1-58).
• The object will be updated automatically on any change in the corresponding memory area.
Table 1-7 vr_ad_mem Memory Object Allocation Methods
Method Description
alloc_obj(addr : vr_ad_addr_t, Allocates address space for a memory object using the
mem_obj : vr_ad_mem_obj) : bool default memory set
is_valid(addr : vr_ad_addr_t) : bool Returns whether the address contains valid data
Example
You could allocate address space for a list of descriptors as follows:
extend ex_c_bus_env {
mem : vr_ad_mem;
keep mem.mem_size == 1000;
post_generate() is also {
addr_map.add_with_offset(0x100,mem);
};
};
Syntax
write_mem_obj [{op-block-constraints}] object
Parameters
Syntax Example
read_mem_obj desc;
write_mem_obj desc;
Example
You could read a descriptor from the memory, modify it, and write it back to the memory as follows:
extend vr_ad_sequence_kind : [EX_SEQ1];
Table 1-8 describes the methods that let you access the e model or HDL memory after connecting the
memory object to the memory.
Method Description
update_model() Writes the current content of the object into the e model
Method Description
write_obj_val_backdoor() Write the current content of the object into the HDL
memory using backdoor access
read_obj_val_backdoor() Reads the current content of the object from the memory
using backdoor access
Address maps and register files contain a list of addressable items (of type vr_ad_base). Therefore, they
can hierarchically contain other address maps, register files, and registers. The following methods are
common to all addressable items:
For example, an attribute like the write mask is relevant only when you update the e reference model and
should be generated only once, at the beginning of the test. Therefore, it is located in the
vr_ad_reg_static_info struct, which is generated only once.
An attribute like direction (read or write) describes an operation done on a register. It is not an integral
part of a register. Therefore, it is best to locate it in the vr_ad_operation struct.
Table 1-10 describes the structs used to implement the various aspects of registers.
Struct Description
Figure 1-1 shows how the register attributes are divided. (Only the most important fields are listed.)
See Also
• vr_ad_operation on page 1-61
• vr_ad_reg on page 1-61
• vr_ad_reg_static_info on page 1-73
1.8.4 vr_ad_operation
vr_ad_operation is the data item (sequence item) for register and memory accesses. It encapsulates all
attributes that describe the operation to be done on the register (like direction). For more information,
see “Basic Register Operations” on page 1-21.
1.8.5 vr_ad_reg
The different register types are modeled using when inheritance. For each register type, a new subtype
of vr_ad_reg_kind is created and the physical fields are added to the specific subtype of vr_ad_reg.
Typically, the definition of a new register is done with the reg_def macro described in “Defining
Registers with the reg_def Macro” on page 1-9.
Method Operation
write_reg_val() Write a value into an e model register, applying the write mask
Method Operation
set_read_mask() Set a read mask (mainly for registers with multiple read masks)
compare_and_update() Read from the e model and compare with a given list of byte
For a list of all fields and methods of vr_ad_reg, see “Fields and Methods of vr_ad_reg” on page 1-71.
1.8.5.1 write_reg_val()
Syntax
write_reg_val(data : vr_ad_data_t)
Parameters
Description
This method updates register content. The parameter for this method is the vr_ad_data_t type value to be
updated (as opposed to a list of bytes in the update() method). The data in this method is anded with the
write mask before it is written to the register. When using this method, the post_access() hook for side
effect is not called, and no coverage is collected.
Example
extend EX_TX_MODE vr_ad_reg {
post_access(direction : vr_ad_rw_t) is {
write_reg_val(0xffffffff);
};
};
1.8.5.2 read_reg_val()
Syntax
read_reg_val(): vr_ad_data_t
Description
This method returns the current value of the register. The returned value is of type vr_ad_data_t. When
using this method, the post_access() hook for side effect is not called, and no coverage is collected.
Example
extend ex_c_bus_driver {
reg_seq : REG_SEQ ex_c_bus_sequence;
keep reg_seq.driver == me;
vr_ad_execute_op(op_item : vr_ad_operation) : list of byte @clock is {
if op_item is a REG vr_ad_operation (reg_op) {
if op_item.direction == WRITE {
reg_seq.write(op_item.address,
reg_op.reg.read_reg_val());
}
};
};
};
1.8.5.3 write_reg_raw()
Syntax
write_reg_raw(offset : vr_ad_addr_t, data : vr_ad_data_t, mask : vr_ad_data_t)
Parameters
Description
This method updates register content. The data is shifted with the offset before being written. The
method does not consider the static_info write mask, but it is masked with the mask parameter. If no
mask is needed use 0xffffffff (or ~0). When using this method, the post_access() hook for side effect is
not called, and no coverage is collected.
Example
This example shows how to clear register VR_AD_R2 when the clear_r2 field of register VR_AD_R1 is
set to 1.
extend VR_AD_R1 vr_ad_reg {
post_access(direction : vr_ad_rw_t) is {
if clear_r2 == 0x1 {
// Locate target register
var my_reg_file : SIDE_EFFECT_FILE vr_ad_reg_file =
get_parents()[0].as_a(SIDE_EFFECT_FILE vr_ad_reg_file);
// Set the value of the target register
my_reg_file.vr_ad_r2.write_reg_raw(0,0x0,0xffffffff);
};
};
};
1.8.5.4 write_reg_rawval()
Syntax
write_reg_rawval(data : vr_ad_data_t)
Parameters
Description
This method updates register content with the specified data. It does not consider any mask — the data
is written as is.When using this method, the post_access() hook for side effect is not called, and no
coverage is collected.
Example
This example shows how to clear register VR_AD_R2 when the clear_r2 field of register VR_AD_R1 is
set to 1.
extend VR_AD_R1 vr_ad_reg {
post_access(direction : vr_ad_rw_t) is {
if clear_r2 == 0x1 {
// Locate target register
var my_reg_file : SIDE_EFFECT_FILE vr_ad_reg_file =
get_parents()[0].as_a(SIDE_EFFECT_FILE vr_ad_reg_file);
// Set the value of the target register
my_reg_file.vr_ad_r2.write_reg_rawval(0x0);
};
};
};
1.8.5.5 set_static_info()
Syntax
set_static_info()
Description
The reg_def macro sets only the write mask and reset value. Other optional static information like
backdoor path and description must be set by the set_static_info() method.
Example
reg_def R1 {
reg_fld data : uint(bits:32) : RW : 0;
set_static_info() is {
set_backdoor_path("r1");
};
};
1.8.5.6 set_write_mask()
Syntax
set_write_mask(wmask : vr_ad_data_t, file_or_map : vr_ad_group)
Parameters
Description
This method sets the write mask of a register. Sometimes the write-mask value of a register depends on
the address space where the register is accessed. It could be R (read only) when accessing from one
address space or RW (read-write) when accessing from another address space. The set_write_mask()
method lets you specify a write-mask value for a specific address map. If no map is specified, then the
write-mask value is fixed and does not depend on the address map from which it is accessed.
Example
reg_def EX_R1 EX_FILE 0x0 {
reg_fld data2 : uint(bits:8) : RW : 0; // [23:16]
reg_fld data1 : uint(bits:8) : RW : 0; // [15: 8]
reg_fld data0 : uint(bits:8) : RW : 0; // [ 7: 0]
};
extend ex_c_bus_env {
addr_map1 : vr_ad_map;
addr_map2 : vr_ad_map;
ex_file : EX_FILE vr_ad_reg_file;
post_generate() is also {
// EX_FILE register file is mapped on both address maps with
// different offsets.
addr_map1.add_with_offset(0x00000, ex_file);
addr_map2.add_with_offset(0x01000, ex_file);
// EX_R1 has 2 masks:
// RW - when accessed from addr_map1 (as specified by the macro).
// RO - when accessed from addr_map2.
ex_file.ex_r1.set_write_mask(0x0,addr_map2);
};
};
1.8.5.7 set_read_mask()
Syntax
set_read_mask(rmask : vr_ad_data_t, file_or_map : vr_ad_group)
Parameters
Description
This method sets the register’s read mask. If the read-mask value is applicable only when accessing the
register through a specific address map (or register file), you must use the address map (or register file)
for the file_or_map parameter. Otherwise, use NULL.
Example
reg_def EX_R1 EX_FILE 0x0 {
reg_fld data2 : uint(bits:8) : RW : 0; // [23:16]
reg_fld data1 : uint(bits:8) : RW : 0; // [15: 8]
reg_fld data0 : uint(bits:8) : RW : 0; // [ 7: 0]
set_static_info() is also {
set_read_mask(0xff00ff,NULL);
// Note that the above setting is equivalent to writing:
// reg_fld data1 : uint(bits:8) : W : 0;
// in the reg_def macro.
};
};
1.8.5.8 set_compare_mask()
Syntax
set_compare_mask(compare_mask : vr_ad_data_t)
Parameters
Description
Excludes some fields from comparison.
Example
reg_def R1 {
reg_fld status : uint(bits:32) : R : 0;
set_static_info() is {
set_compare_mask(0);
};
};
1.8.5.9 set_backdoor_path()
Syntax
set_backdoor_path(path : string)
Parameters
Description
Sets the backdoor path of a register. The register backdoor mechanism uses this string to write
(write_reg_val_backdoor()) or to read (read_reg_val_backdoor()).
Example
reg_def R1 {
reg_fld status : uint(bits:32) : RW : 0;
set_static_info() is {
set_backdoor_path(“r1”);
};
};
1.8.5.10 set_field_backdoor_path()
Syntax
set_field_backdoor_path(field_name : string, path : string)
Parameters
Description
Sets the backdoor path of a single register field. To be used when each register field has a different HDL
path.
Example
reg_def R1 {
reg_fld ctrl1 : uint(bits:8) : RW : 0;
reg_fld ctrl2 : uint(bits:8) : RW : 0;
set_static_info() is {
set_backdoor_path("ctrl1","~/top/ctrl1");
set_backdoor_path("ctrl2","~/top/ctrl2");
};
};
1.8.5.11 update()
Syntax
update(addr : vr_ad_addr_t, data : list of byte, mask : list of byte)
Parameters
mask List of byte to be used as masks. Each element in the list masks the
equivalent element in the data list. 0x0 masks out a byte, and 0xff writes
the data as is. An empty list “{}” indicates that no masking is applied
Description
Use this method when you need to update a specific e model register. Usually, you use the address 0,
meaning write from the beginning of the register. You can also use non-zero offsets if the register is in a
register file. If you update a register and you specify a mask, the mask will be anded with the wmask of
the register. Whenever this method is called, the pre_access() and post_access() hooks are activated,
and coverage of the register is collected with direction WRITE.
Example
extend vr_xbus_bus_monitor_u {
on transfer_end {
if transfer.read_write == WRITE {
reg_file.tx_data.update(0,%{transfer.data},{});
};
};
};
1.8.5.12 compare_and_update()
Syntax
compare_and_update(addr : vr_ad_addr_t, expected_data : list of byte): bool
Parameters
Description
Use this method to compare a specific register with given data. Typically, you use the address 0, meaning
comparing from the beginning of the register. You can also use non-zero offsets if the register is in a
register file. Comparison is done only for the number of bytes given as the expected data. An error is
issued only for a mismatch in a register whose compare_mask bits are set. Whenever this method is
called, the pre_access() and post_access() hooks are activated, and coverage of registers is collected
with direction READ.
Example
extend vr_xbus_bus_monitor_u {
on transfer_end {
if transfer.read_write == READ {
compute p_xbus_env.addr_map.compare_and_update(transfer.addr,
%{transfer.data});
};
};
};
1.8.5.13 post_access()
Syntax
post_access()
Description
This method is a user hook for implementing features like “clear on read” and “clear on write”.
Example
extend EX_REGS_TX_MODE vr_ad_reg {
// Clear on Write
post_access(direction : vr_ad_rw_t) is {
if direction == write{
write_reg_raw(0x0,0x0,0xffffffff);
};
};
};
See Also
• “Implementing Side Effects” on page 1-32
Field Description
Method Description
compare_and_update(addr : Read from the e model and compare it with a given list of
vr_ad_addr_t, data : list of byte): bool byte
get_packing_option(): pack_options Packing option of the register, taken from the register file
Method Description
write_reg_raw(offset : uint, data : Write a uint into a register without applying the wmask
vr_ad_data_t, mask : vr_ad_data_t)
1.8.6 vr_ad_reg_static_info
The vr_ad_reg_static_info struct contains register attributes that should not be generated on the fly when
doing register operations. The static information struct is created only when you add a register to a
register file or to an address map (by add_with_offset()). You can set some fields using
set_static_info() or the reg_def macro. Other fields are automatically updated by the e model.
Field Description
Field Description
1.8.7 vr_ad_reg_file
The register file contains a list of registers (or register files) referenced by vr_ad_node. The
implementation assumes that a register can be accessed through several addresses, and therefore the
address is stored in address nodes rather than the register itself.
Register File
ad_nodes : list of vr_ad_node
Each vr_ad_node contains an address and a reference to a register, a register file, or a memory block.
Field Description
All offsets are relative to the base address of the containing object. The absolute address is calculated by
totaling all offsets from the addressable item to the top address map.
Method Operation
For a list of all fields and methods of vr_ad_reg_file, see “Fields and Methods of vr_ad_reg_file” on page
1-76.
1.8.7.1 add_with_offset()
Syntax
add_with_offset(offset : vr_ad_addr_t, ad_item : vr_ad_base)
Parameters
Description
This method creates an address node with a reference to the register and holds the address of the item.
The parameters for this method are the offset of the register and the register to be added. The reg_def
macro uses this method to automatically add a register to a register file. Explicitly use this method when
a register file contains multiple instances of a register type.
Example
extend XCORE vr_ad_reg_file {
%tx_mode_regs[4] : list of EX_REGS_TX_MODE vr_ad_reg;
post_generate() is also {
for each (reg) in tx_mode_regs {
add_with_offset(index*4,reg);
};
};
};
Field Description
ad_nodes: list (key: offset) of List of all addressable items mapped inside the object
vr_ad_node
Method Description
compare_and_update(addr : Compares the given data read on the bus with the e model.
vr_ad_addr_t, data : list of byte): bool Updates the e model if needed
get_all_nodes(): list of vr_ad_node Returns the address node list of all addressable items
get_all_reg_files(): list of Returns all register files, including unmapped register files
vr_ad_reg_file
Method Description
1.8.8 vr_ad_map
The address map has all of the functionality of a register file (see “vr_ad_reg_file” on page 1-74). In
addition, it has address management capabilities (allocation and release of address ranges). The address
management capabilities are discussed in Chapter 1 “The Register and Memory Package”.
The address map contains a list of register files and memory banks with their absolute addresses. The
address map also manages the unmapped (indirect) register maps, even though they are not mapped in
the address space.
Method Operation
Method Operation
compare_and_update() Read a list of bytes from the e model, and compare it with an
expected list of bytes.
For a full list of all register-related fields and methods of vr_ad_map, see “Fields and Methods of
vr_ad_map” on page 1-84.
1.8.8.1 add_with_offset()
Syntax
add_with_offset(offset : vr_ad_addr_t, ad_item : vr_ad_base)
Parameters
Description
This method adds an addressable item to the address map at the specified offset. It allocates the required
address space from the free_addrs set and creates an address node with the specified address and a
reference to the addressable item. If the method fails to add the addressable item, an error message is
issued.
Example
extend ex_c_bus_env {
xcore_reg_file : XCORE vr_ad_reg_file;
post_generate() is also {
// Add a reg-file to the address map
addr_map.add_with_offset(0x0,xcore_reg_file);
};
};
1.8.8.2 add_to_addr_map()
Syntax
add_to_addr_map(min_addr : vr_ad_addr_t, max_addr : vr_ad_addr_t,
ad_item : vr_ad_base, alignment : uint): vr_ad_addr_t
Parameters
Description
This method adds an addressable item to the address map (similar to add_with_offset()). It lets you
specify the alignment and a range from which to allocate the addresses for the addressable item. The
allocated size will be the size of the addressable item. It creates an address node with the allocated base
address and a reference to the addressable item. The returned value is the allocated base address. If
allocation fails, the returned value is UNDEF.
Example
extend ex_c_bus_env {
xcore_reg_file : XCORE vr_ad_reg_file;
!xcore_base_address : vr_ad_addr_t;
post_generate() is also {
// Add a reg-file to the address map
xcore_base_address=
addr_map.add_to_addr_map(0x0,0x1000,xcore_reg_file,4);
};
};
1.8.8.3 add_unmapped_item()
Syntax
add_unmapped_item(reg_file : vr_ad_reg_file)
Parameters
Description
This method adds the reg_file and its registers into the reg_list and reg_file_list of the address map lists.
All unmapped register files must be registered in the address map by using this method.
Example
extend ex_c_bus_env {
ycore_reg_file : YCORE vr_ad_reg_file;
post_generate() is also {
// Add the unmapped reg file to the address map
addr_map.add_unmapped_item(ycore_reg_file);
};
};
1.8.8.4 update()
Syntax
update(addr : vr_ad_addr_t, data : list of byte, mask : list of byte)
Parameters
mask List of byte to be used as masks. Each element in the list masks the
equivalent element in the data list. 0x0 masks out a byte, and 0xff writes
the data as is. An empty list “{}” indicates that no masking is applied
Description
This method updates the e model. For example, it can update on the basis of information gathered by the
monitor. If you update a register and you specify a mask, the mask will be anded with the wmask of the
register. Whenever this method is called, the pre_access() and post_access() hooks are activated, and
coverage of registers is collected with direction WRITE.
Example
extend vr_xbus_bus_monitor_u {
on transfer_end {
if transfer.read_write == WRITE {
reg_file.update(transfer.addr,%{transfer.data},
{0x0;0xff;0xff;0xff});
// The update() mask is: 0xffffff00
// Wmask can be, for example: 0x00ffffff
// The actual mask that will be used is: 0x00ffff00
};
};
};
1.8.8.5 fetch()
Syntax
fetch(addr :vr_ad_addr_t, size : vr_ad_addr_t): list of byte
Parameters
Description
This method reads the specified number of bytes from the e model starting from the specified address.
The address does not have to be aligned to the register boundaries. So, for example, it is legal to start
reading from a second byte of a register. The method recursively calls the fetch methods of the
addressable items inside the address map until it gets to a register that returns its packed value. If there
is a gap between two registers, the gap will be padded with 0s. Whenever this method is called, the
pre_access() and post_access() hooks are activated, and coverage of registers is collected with direction
READ.
Example
extend vr_xbus_bus_monitor_u {
on transfer_end {
if transfer.read_write == READ{
read_data = p_xbus_env.addr_map.fetch(transfer.addr,4);
};
};
};
1.8.8.6 compare_and_update()
Syntax
compare_and_update(addr : vr_ad_addr_t, expected_data : list of byte): bool
Parameters
Description
This method can be used to automatically compare the data captured on the bus with the data that is
stored in the e reference model. The comparison is done only for the number of bytes given as the
expected data. It does not have to be aligned to the register boundaries. An error is issued only for a
mismatch in a register whose compare_mask bits are set. Whenever this method is called, the
pre_access() and post_access() hooks are activated, and coverage of registers is collected with direction
READ.
Example
extend vr_xbus_bus_monitor_u {
on transfer_end {
if transfer.read_write == READ {
compute p_xbus_env.addr_map.compare_and_update(transfer.addr,
%{transfer.data});
};
};
};
Field Description
reg_file_list: list of vr_ad_reg_file All register files related to the address map
reg_list: list (key: it) of All registers related to the address map
vr_ad_reg_base
Method Description
compare_and_update(addr : Compares the given data read on the bus with the
vr_ad_addr_t, data : list of byte): bool e model. Updates the e model if needed
Method Description
get_all_nodes(): list of vr_ad_node Returns the address node list of all addressable items
get_all_reg_files(): list of vr_ad_reg_file Gets all address nodes in the specified range
Method Description
See Also
• “Address Management (Sets)” on page 1-91
1.8.9 vr_ad_mem
The vr_ad_mem struct provides sparse memory functionality.
Method Operation
1.8.9.1 readmemh()
Syntax
readmemh(file_name : string, start_addr : vr_ad_addr_t, end_addr : vr_ad_addr_t,
file_start_addr : vr_ad_addr_t, file_end_addr : vr_ad_addr_t)
Parameters
start_addr Data read from file will be written to memory starting from this address.
Typically, the start address is 0.
Description
This method loads values from a file into the memory. It is equivalent to the readmemh Verilog task or
VHDL procedure. The format of the file must be according to the standard supported by Verilog or
VHDL. In general, it will have the following structure:
@00 00 01 02 03 04 05 06 07
@08 08 09 0a 0b 0c 0d 0e 0f
Example
extend ex_c_bus_env {
run() is also {
mem.readmemh("data_file.txt",0,1000,0,1000);
};
};
1.8.9.2 dumpmemh()
Syntax
dumpmemh(file_name : string, start_addr : vr_ad_addr_t, end_addr : vr_ad_addr_t)
Parameters
start_addr Data will be written to file starting from this memory address.
Description
This method dumps the memory content to file. It is equivalent to the dumpmemh Verilog task or VHDL
procedure. The format of the file must be according to the standard supported by Verilog or VHDL (see
readmemh() on page 1-86).
Example
extend ex_c_bus_env {
finalize() is also {
mem.dumpmemh("data_file.txt",0,100);
};
};
1.8.9.3 get_data()
Syntax
get_data(addr :vr_ad_addr_t, size : vr_ad_addr_t): list of byte
Parameters
Description
This method is called each time an uninitialized area is read in the memory. By default, the returned data
is determined according to the policy in read_default_value. The size of the returned data is according
to the parameter size. If you need a different behavior, you can override this method and implement your
own logic. If you override this method, you must do it only under a specific memory subtype.
Example
extend EX_MEM vr_ad_mem {
get_data(addr : vr_ad_addr_t, size : uint) : list of byte is only {
result.resize(size,TRUE,0,TRUE);
for each (b) in result {
b = addr + index;
};
};
};
Field Description
Method Description
get_data(addr : vr_ad_addr_t, size : Hook method, called whenever an uninitialized area is read
uint) so that you can provide data
Method Description
readmemh(file_name : string, Read the content of a hex-format file into the memory
file_type : string,
start_addr : vr_ad_addr_t,
end_addr : vr_ad_addr_t,
file_start_addr : vr_ad_addr_t,
file_end_addr : vr_ad_addr_t)
readmemb(file_name : string, Read the content of a binary-format file into the memory
file_type : string,
start_addr : vr_ad_addr_t,
end_addr : vr_ad_addr_t,
file_start_addr : vr_ad_addr_t,
file_end_addr : vr_ad_addr_t)
1.8.10 vr_ad_sequence_driver
The RSD is a dedicated sequence driver for register and memory operations.
Field Description
bd_write_to_addr_map : bool Controls whether the RSD updates the e model upon
backdoor access
bd_read_from_addr_map : bool Controls whether RSD reads from the e model on backdoor
access
Method Description
add_space(space : vr_ad_group, Adds an address space to the RSD. To be used when you
name : vr_ad_space_kind) have multiple address spaces (MEMORY, IO, CONFIG) on
the bus
For example, assume that you have a slave DUT that responds to several inconsecutive addresses as
follows [0x0..0x500, 0x2000..0x3000, 0x3500..0x7000]. To randomly access the slave DUT, you would
want to generate random areas of various sizes inside the slave DUT address space. A possible request
might be to generate a 50 byte area but not beyond address 0x6000. The address map lets you define a
set of slave DUT addresses and then allocate random regions in it.
0xffff 0x0
2. Use the add_segment() method to initialize the new field with the desired regions.
For example, you could add the field slave0_set to your address map and then initialize it with addresses
[0x0..0x500, 0x2000..0x3000, 0x3500..0x7000] as follows:
extend MY_MAP vr_ad_map { // Add slave0_set to the address map
slave0_set : vr_ad_set;
Once you define your set, you can allocate random regions in it.
Allocation removes the allocated region from the set, making it unavailable for subsequent allocations.
If, for example, alloc_from_set() allocated a 40 byte region [0x52..0x91], then:
slave0_set before allocation: [0 .. 0x500, 0x2000..0x3000,
0x3500..0x7000]
slave0_set after allocation : [0..0x51, 0x92..0x500, 0x2000..0x3000,
0x3500..0x7000]
Note Address maps use predefined sets to allocate addresses for the addressable items. Each
time you add a register file to an address map (with add_with_offset() or
add_to_addr_map()), the address map allocates a region from the free_addrs set and adds a
region to the occupied_addrs set:
extend vr_ad_map {
free_addrs : vr_ad_set;
occupied_addrs : vr_ad_set;
};
Method Operation
For a full list of the memory-management methods, see “Memory-Management Methods” on page 1-97.
1.9.1 add_segment()
Syntax
add_segment(set: vr_ad_set, min_addr: vr_ad_addr_t, max_addr: vr_ad_addr_t)
Parameters
Description
This method initializes a set and adds the specified region to it. You can add several segments to a set. If
you add contiguous segments, they are automatically combined into one segment in the set.
Example
extend EX_MAP vr_ad_map {
slave0_set : vr_ad_set;
post_generate() is also {
add_segment(slave0_set,0x0,0x150);
add_segment(slave0_set,0x220,0x350);
};
};
1.9.2 alloc_from_set()
Syntax
alloc_from_set(set: vr_ad_set, min_addr: vr_ad_addr_t, max_addr: vr_ad_addr_t, min_size:
vr_ad_addr_t, max_size: vr_ad_addr_t, alignment: uint): vr_ad_set
Parameters
Description
This method allocates a region in a set. The allocation is done randomly between the specified range of
min_addr and max_addr. The size of the region is also randomly generated between min_size and
max_size. The returned value is a new set created from the allocated region. You can get the region base
address and size by the methods vr_ad_set.get_address() and vr_ad_set.get_size(). To allocate the
whole address space (the range 0x0 to 0xffffffff, by default definitions), set min_size and max_size to
zero.
Example
extend MAIN vr_ad_sequence {
1.9.3 dealloc_to_set()
Syntax
dealloc_to_set(dest_set: vr_ad_set, alloc_set: vr_ad_set)
Parameters
Description
This method deallocates a set that was previously allocated by the method alloc_from_set().
Example
extend MAIN vr_ad_sequence {
body() @driver.clock is only {
var allocated_set :=
map.alloc_from_set(map.slave0_set,0,0x1000,10,50,2);
// Do something
map.deallocate_to_set(map.slave0_set, allocated_set);
};
};
1.9.4 lock_item()
Syntax
lock_item(ad_item: vr_ad_base): bool
Parameters
Description
When you have a sequence that needs exclusive access to a register or a register file, you do not want
other sequences to interfere as long as the sequence is not finished. The address map contains a
predefined set for that purpose. The method lock_item() removes the relevant addresses from that
predefined set, preventing other sequences from locking the same addresses.
Example
extend MAIN vr_ad_sequence {
body() @driver.clock is only {
var my_reg = driver.addr_map.get_reg_by_address(0x100);
var item_is_locked = lock_item(my_reg);
if item_is_locked {
// Do something
};
};
};
1.9.5 release_item()
Syntax
release_item(ad_item: vr_ad_base)
Parameters
Description
This method releases an addressable item that was previously locked by lock_item().
Example
extend MAIN vr_ad_sequence {
body() @driver.clock is only {
Method Description
is_in_set(set: vr_ad_set, addr: vr_ad_addr_t): bool Returns whether the address is in the set
Method Description
Method Description
For an example of AHB eVC sequences that use sets, see vr_ad/examples/vr_ad_ahb_sets.e.
• “All Address Maps Page” on page 1-99 Table with all of the address maps
• “Top-Level Address Map Page” on page 1-99 Top-level content of the address map
• “Detailed Address Map Page” on page 1-100 Table with the full content of the address map
• “Register Files Page” on page 1-101 All register files related to the address map
• “Address Sets Page” on page 1-102 All memory sets related to the address map
• “Register File Page” on page 1-102 Content of the register file in stripes
• “Stripe Chart Page” on page 1-103 Stripe chart of the RSD sequences
In case of hierarchical addressable items (for example, a register file containing a register or another
register file), all items are displayed.
• show map Displays the address map, register files and registers
• trace ad alloc Initiates tracing of memory allocation operations
Syntax
Usage
Syntax
trace ad al[loc]
Usage
The following vr_ad_map methods produce trace messages after the trace command is issued:
• alloc_from_set()
• dealloc_to_set()
• dealloc_addr_to_set()
E L
end of test 1-45 layering, register sequence drivers 1-16
eRM architecture 1-7
ex_c_bus environment 1-3 M
macros
F def_reg
features, main, package 1-2 defining registers with 1-9
fetch() 1-82 read_reg 1-23, 1-49
fetch_and_compare() 1-83 reg_def 1-10
fields reg_list 1-13
coverage, defining 1-14 write_reg 1-23, 1-49
order, registers 1-11, 1-43 main features, package 1-2
order, registers, changing 1-43 map, address 1-78
register instantiating 1-15
modifying 1-26 register files, adding 1-15
vr_ad_map 1-84 updating 1-39
vr_ad_node 1-75 mem_def 1-55
vr_ad_operation 1-22 memory 1-48
vr_ad_reg 1-72 addresses, uninitialized 1-52
vr_ad_reg_file 1-76 backdoor access 1-53
vr_ad_reg_static_info 1-73 instantiating 1-48
vr_ad_sequence 1-23, 1-41 objects 1-54
accessing in memory 1-57
G connecting to memory 1-55
creating 1-55
get_data 1-88 objects, accessing in memory
methods 1-58
H reading from file 1-51
hierarchy, types 1-60 returned data of uninitialized addresses,
controlling 1-52
side effects 1-53
I sparse memory 1-48
indirect registers updating 1-50
access handling 1-42 writing to file 1-51
addressing 1-39 memory model 1-1
addressing model 1-39 message verbosity, controlling 1-45
driving 1-40 methods
identifying 1-42 add_to_addr_map() 1-80
instances, register, defining 1-11 add_unmapped_item() 1-81
add_with_offset() 1-75, 1-79
compare_and_update() 1-70
fetch() 1-82
W
width, addressing, customizing 1-44
write_mem_obj 1-57
write_reg macro 1-23, 1-49
write_reg_rawval() 1-64
write_reg_val() 1-62
writing to specific instance of register type 1-26