0% found this document useful (0 votes)
50 views1,269 pages

SN e Reference PDF

Uploaded by

PM
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
50 views1,269 pages

SN e Reference PDF

Uploaded by

PM
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1269

e Language

Reference
Specman 4.3.4
Legal Notice
Copyright © 1998-2004 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.

Restricted Rights Legend


Use, duplication, or disclosure by the Government is subject to restrictions as set forth in
subparagraphs (c)(1)(ii) of the Rights in Technical Data and Computer Software clause at
DFARS 252.227-7013.

Destination Control Statement


All technical data contained in this product is subject to the export control laws of the
United States of America. Disclosure to nationals of other countries contrary to United
States law is prohibited. It is the reader’s responsibility to determine the applicable
regulations and to comply with them.
Contents

1 About This Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1-1


1.1 Conventions in This Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-1
1.2 Syntax Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2

2 e Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2-1
2.1 Lexical Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-2
2.1.1 File Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-2
2.1.2 Code Segments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-2
2.1.3 Comments and White Space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-3
2.1.4 Literals and Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-3
2.1.4.1 Unsized Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-4
2.1.4.2 Sized Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-5
2.1.4.3 MVL Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-5
2.1.4.4 Predefined Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-8
2.1.4.5 Literal String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-8
2.1.4.6 Literal Character . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-9
2.1.5 Names, Keywords, and Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-10
2.1.5.1 Legal e Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-10
2.1.5.2 Reserved Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-10
2.1.5.3 Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-12
2.2 Syntactic Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-12
2.2.1 Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-13
2.2.2 Struct Members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-15
2.2.3 Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-16
2.2.3.1 Creating or Modifying Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-17
2.2.3.2 Executing Actions Conditionally . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-18
2.2.3.3 Executing Actions Iteratively . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-18

e Language Reference iii


Contents

2.2.3.4 Controlling Program Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-19


2.2.3.5 Invoking Methods and Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-20
2.2.3.6 Performing Time-Consuming Actions . . . . . . . . . . . . . . . . . . . . . . . 2-20
2.2.3.7 Generating Data Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-21
2.2.3.8 Detecting and Handling Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-22
2.2.3.9 Printing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-22
2.2.4 Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-23
2.3 Struct Hierarchy and Name Resolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-23
2.3.1 Struct Hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-24
2.3.1.1 Global Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-24
2.3.1.2 Sys Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-24
2.3.1.3 Packing Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-25
2.3.1.4 Files Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-25
2.3.1.5 Scheduler Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-25
2.3.1.6 Simulator Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-25
2.3.1.7 Session Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-25
2.3.2 Referencing e Entities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-26
2.3.2.1 Structs and Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-27
2.3.2.2 Method and Routine Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-28
2.3.2.3 Enumerated Type Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-29
2.3.3 Implicit Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-30
2.3.3.1 it . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-30
2.3.3.2 me . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-31
2.3.3.3 result . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-32
2.3.3.4 index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-32
2.3.4 Name Resolution Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-33
2.3.4.1 Names that Include a Path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-33
2.3.4.2 Names that Do Not Include a Path . . . . . . . . . . . . . . . . . . . . . . . . . . 2-34
2.4 Operator Precedence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-35
2.5 Evaluation Order of Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-37
2.6 Bitwise Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-38
2.6.1 ~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-38
2.6.2 & | ^ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-40
2.6.3 >> << . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-42
2.7 Boolean Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-44
2.7.1 ! (not) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-44
2.7.2 && (and) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-45
2.7.3 || (or) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-46
2.7.4 => . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-48

iv e Language Reference
Contents

2.7.5 now . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-49


2.8 Arithmetic Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-50
2.8.1 Unary + - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-51
2.8.2 + - * / % . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-52
2.9 Comparison Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-54
2.9.1 < <= > >= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-54
2.9.2 == != . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-56
2.9.3 === !== . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-58
2.9.4 ~ !~ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-60
2.9.5 in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-62
2.10 String Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-65
2.10.1 Native Specman String Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-65
2.10.2 AWK-Style String Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-67
2.11 Extraction and Concatenation Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-69
2.11.1 [ ] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-69
2.11.2 [ : ] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-70
2.11.3 [ .. ] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-75
2.11.4 {… ; …} . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-77
2.11.5 %{… , …} . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-79
2.12 Scalar Modifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-83
2.12.1 [ range,...] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-83
2.12.2 (bits | bytes : width-exp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-84
2.13 Parentheses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-85
2.13.1 list-method() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-86
2.14 Special-Purpose Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-88
2.14.1 is [not] a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-88
2.14.2 new . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-90
2.14.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-93
2.14.4 ' . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-95
2.14.5 ? : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-96

3 Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-1


3.1 e Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-1
3.1.1 Scalar Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2
3.1.2 Scalar Subtypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-3
3.1.2.1 Scalar Modifiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-3

e Language Reference v
Contents

3.1.2.2 Named Scalar Subtypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-4


3.1.2.3 Infinite (Unbounded) Integers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-4
3.1.3 Enumerated Scalar Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-5
3.1.3.1 Casting of Enumerated Types in Comparisons . . . . . . . . . . . . . . . . . 3-6
3.1.4 Struct Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-8
3.1.5 Struct Subtypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-8
3.1.5.1 Referring to a Struct Subtype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-9
3.1.5.2 Using extend, when, and like with Struct Subtypes . . . . . . . . . . . . 3-10
3.1.5.3 Referring To Conditional Fields in when Constructs . . . . . . . . . . . 3-11
3.1.6 List Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-13
3.1.6.1 Regular Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-14
3.1.6.2 Keyed Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-14
3.1.7 The string Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-15
3.1.8 The external_pointer Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-16
3.2 Memory Requirements for Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-16
3.3 Untyped Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-17
3.4 Assignment Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-19
3.4.1 What Is an Assignment? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-19
3.4.2 Assignments Create Identical References . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-20
3.4.3 Assignment to Different but Compatible Types . . . . . . . . . . . . . . . . . . . . . . 3-21
3.4.3.1 Assignment of Numeric Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-21
3.4.3.2 Assignment of Boolean Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-22
3.4.3.3 Assignment of Enumerated Types . . . . . . . . . . . . . . . . . . . . . . . . . . 3-22
3.4.3.4 Assignment of Structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-22
3.4.3.5 Assignment of Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-23
3.4.3.6 Assignment of Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-24
3.5 Precision Rules for Numeric Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-24
3.5.1 Determining the Context of an Expression . . . . . . . . . . . . . . . . . . . . . . . . . . 3-25
3.5.2 Deciding Precision and Performing Data Conversion and Sign Extension . . 3-27
3.5.3 Example Application of Precision Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-27
3.6 Automatic Type Casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-28
3.7 Constructs for Defining and Extending Scalar Types . . . . . . . . . . . . . . . . . . . . . . . . . 3-31
3.7.1 type enumerated scalar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-31
3.7.2 type scalar subtype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-34
3.7.3 type sized scalar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-35
3.7.4 extend type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-37
3.8 Additional Type-Related Constructs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-39
3.8.1 Type Conversion Between Scalars and Strings . . . . . . . . . . . . . . . . . . . . . . . 3-39

vi e Language Reference
Contents

3.8.2 as_a() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-39


3.8.3 all_values() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-52

4 Structs, Fields, and Subtypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4-1


4.1 Structs Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
4.2 Defining Structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
4.2.1 struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
4.3 Extending Structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-6
4.3.1 extend type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-6
4.4 Extending Subtypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-9
4.5 Defining Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-11
4.5.1 field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-11
4.6 Defining List Fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-14
4.6.1 list of . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-14
4.6.2 list(key) of . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-17
4.7 Creating Subtypes with When . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-21
4.7.1 when . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-22
4.8 Extending When Subtypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-25
4.8.1 Coverage and When Subtypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-25
4.8.2 Extending Methods in When Subtypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-26
4.9 Defining Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-28
4.9.1 attribute field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-28
4.10 Comparison of When and Like Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-33
4.10.1 Summary of When versus Like . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-33
4.10.2 A Simple Example of When Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-33
4.10.3 A Simple Example of Like Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-35
4.10.4 Advantages of Using When Inheritance for Modeling . . . . . . . . . . . . . . . . . 4-36
4.10.5 Advantages of Using Like Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-40
4.10.6 Restrictions on Like Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-41
4.10.6.1 Restrictions Due to Inherent Differences . . . . . . . . . . . . . . . . . . . . . 4-41
4.10.6.2 Restrictions Due to Implementation . . . . . . . . . . . . . . . . . . . . . . . . 4-42
4.10.6.3 Generation Restrictions on Like Inheritance . . . . . . . . . . . . . . . . . . 4-42
4.10.6.4 Examples of Like Inheritance Restrictions . . . . . . . . . . . . . . . . . . . 4-44
4.10.7 A When Inheritance Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-47

e Language Reference vii


Contents

5 Units . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-1
5.1 Units Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-1
5.1.1 Units vs. Structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-3
5.1.2 HDL Paths and Units . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-4
5.1.3 Methodology Recommendations and Limitations . . . . . . . . . . . . . . . . . . . . . . 5-5
5.2 Defining Units and Fields of Type Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-6
5.2.1 unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-6
5.2.2 field: unit-type is instance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-11
5.2.3 field: unit-type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-13
5.2.4 field: list of unit instances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-15
5.2.5 field: list of unit-type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-16
5.3 Predefined Methods for Any Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-18
5.3.1 hdl_path() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-19
5.3.2 full_hdl_path() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-22
5.3.3 e_path() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-23
5.3.4 agent() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-25
5.3.5 get_parent_unit() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-27
5.4 Unit-Related Predefined Methods for Any Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-28
5.4.1 get_unit() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-29
5.4.2 get_enclosing_unit() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-32
5.4.3 try_enclosing_unit() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-35
5.4.4 set_unit() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-36
5.5 Unit-Related Predefined Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-37
5.5.1 set_config_max() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-37
5.5.2 get_all_units() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-39

6 e Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6-1
6.1 Introduction to e Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-2
6.1.1 Advantages of Using Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-2
6.1.1.1 Current Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-2
6.1.2 Creating Port Instances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-3
6.1.3 Using Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-4
6.1.4 Ports Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-5
6.2 Using Simple Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-6
6.2.1 Accessing Simple Ports and Their Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-7
6.2.2 Multi-Value Logic (MVL) on Simple Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-9

viii e Language Reference


Contents

6.2.3 @sim Temporal Expressions with External Simple Ports . . . . . . . . . . . . . . . 6-11


6.2.4 An Internal Simple Ports Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-12
6.2.5 An External Simple Ports Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-13
6.3 Using Buffer Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-15
6.3.1 Rendezvous-Zero Size Buffer Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-16
6.3.2 An Internal Buffer Ports Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-16
6.4 Using Event Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-17
6.4.1 Accessing Event Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-17
6.5 Defining and Referencing Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-18
6.5.1 simple_port . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-19
6.5.2 buffer_port . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-21
6.5.3 event_port . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-23
6.5.4 any_simple_port, any_buffer_port, any_event_port . . . . . . . . . . . . . . . . . . . 6-26
6.5.5 port$ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-28
6.5.6 port$[ : ] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-29
6.5.7 force port$ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-34
6.5.8 release port . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-35
6.5.9 force port$[ : ] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-36
6.6 Port Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-38
6.6.1 Generic Port Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-38
6.6.2 Port Attributes for HDL Simulators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-40
6.6.3 bind() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-43
6.6.4 buffer_size() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-47
6.6.5 declared_range() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-48
6.6.6 delayed() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-49
6.6.7 driver() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-50
6.6.8 driver_delay() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-51
6.6.9 driver_initial_value() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-52
6.6.10 edge() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-53
6.6.11 hdl_path() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-54
6.6.12 pack_options() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-56
6.6.13 pass_by_pointer() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-57
6.6.14 verilog_drive() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-58
6.6.15 verilog_drive_hold() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-59
6.6.16 verilog_forcible() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-59
6.6.17 verilog_strobe() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-60

e Language Reference ix
Contents

6.6.18 verilog_wire() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-61


6.6.19 vhdl_delay_mode() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-62
6.6.20 vhdl_disconnect_value() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-63
6.7 Using Port Values and Attributes in Constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-64
6.8 Buffer Port Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-65
6.8.1 get() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-65
6.8.2 put() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-67
6.8.3 is_empty() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-68
6.8.4 is_full() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-69
6.9 Multi-Value Logic (MVL) Methods for Simple Ports . . . . . . . . . . . . . . . . . . . . . . . . . 6-70
6.9.1 put_mvl() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-71
6.9.2 get_mvl() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-72
6.9.3 put_mvl_list() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-74
6.9.4 get_mvl_list() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-75
6.9.5 put_mvl_string() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-76
6.9.6 get_mvl_string() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-77
6.9.7 get_mvl4() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-79
6.9.8 get_mvl4_list() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-80
6.9.9 get_mvl4_string() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-81
6.9.10 put_mvl_to_bit_slice() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-83
6.9.11 force_mvl_to_bit_slice() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-84
6.10 Methods for Simple Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-86
6.10.1 has_x() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-86
6.10.2 has_z() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-87
6.10.3 has_unknown() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-88
6.11 Global MVL Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-89
6.11.1 string_to_mvl() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-90
6.11.2 mvl_to_string() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-91
6.11.3 mvl_to_int() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-92
6.11.4 int_to_mvl() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-94
6.11.5 mvl_to_bits() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-95
6.11.6 bits_to_mvl() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-96
6.11.7 mvl_to_mvl4() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-97
6.11.8 mvl_list_to_mvl4_list() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-98
6.11.9 string_to_mvl4() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-99
6.12 Port-Related Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-100

x e Language Reference
Contents

6.12.1 show ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-100


6.12.2 trace ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-102

7 Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7-1
7.1 Rules for Defining and Extending Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-2
7.1.1 method is [inline] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-5
7.1.2 method @event is . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-8
7.1.3 method [@event] is also | first | only | inline only . . . . . . . . . . . . . . . . . . . . . 7-12
7.1.4 method [@event] is undefined | empty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-19
7.2 Invoking Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-22
7.2.1 tcm() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-23
7.2.2 start tcm() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-25
7.2.3 method() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-27
7.2.4 compute method() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-29
7.2.5 return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-30
7.3 Parameter Passing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-34
7.3.1 Scalar Parameter Passing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-34
7.3.2 Compound Parameter Passing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-35
7.3.3 Notes on Passing by Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7-36

8 Creating and Modifying e Variables . . . . . . . . . . . . . . . . . . . . . . . . .8-1


8.1 About e Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-1
8.2 var . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-2
8.3 = . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-4
8.4 op= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-6
8.5 <= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-9

9 Control Flow Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .9-1


9.1 Conditional Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-1
9.1.1 if then else . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-1
9.1.2 case labeled-case-item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-3
9.1.3 case bool-case-item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-5
9.2 Iterative Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-7
9.2.1 while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-7
9.2.2 repeat until . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-9

e Language Reference xi
Contents

9.2.3 for each in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-11


9.2.4 for from to . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-14
9.2.5 for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-15
9.3 File Iteration Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-17
9.3.1 for each line in file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-17
9.3.2 for each file matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-19
9.4 Actions for Controlling the Program Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-20
9.4.1 break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-20
9.4.2 continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-21

10 Checks and Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .10-1


10.1 Handling DUT Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-1
10.1.1 check that . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-1
10.1.2 dut_error() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-4
10.1.3 dut_error_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-5
10.1.4 set_check() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-11
10.2 Handling User Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-13
10.2.1 warning() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-14
10.2.2 error() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-15
10.2.3 fatal() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-17
10.2.4 try . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-19
10.3 Handling Programming Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-21
10.3.1 assert . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-21

11 Generation Constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11-1


11.1 Basic Concepts of Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-2
11.1.1 Generation Order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-2
11.1.1.1 Subtype Generation Optimization Constraints . . . . . . . . . . . . . . . . 11-3
11.1.2 Unidirectional Constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-4
11.1.3 Enforceable Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-7
11.1.4 Order of Evaluation of Soft Value Constraints . . . . . . . . . . . . . . . . . . . . . . . 11-9
11.1.5 Constraining Struct Instances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-10
11.1.6 Constraining Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-11
11.1.6.1 Constraining List Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-12
11.1.6.2 Constraining a List Item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-12
11.1.6.3 Constraining a List To Keep a Specific Item . . . . . . . . . . . . . . . . . 11-14

xii e Language Reference


Contents

11.1.6.4 Constraining One List to Another List . . . . . . . . . . . . . . . . . . . . . 11-14


11.1.6.5 Constraining Multiple List Items . . . . . . . . . . . . . . . . . . . . . . . . . . 11-15
11.1.6.6 Constraining a List of Structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-15
11.1.6.7 Constraining Multiple Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-15
11.1.7 Constraining Bit Slices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-15
11.1.7.1 Bit Slice Constraints and Generation Order . . . . . . . . . . . . . . . . . 11-16
11.1.7.2 Bit Slice Constraints and Signed Entities . . . . . . . . . . . . . . . . . . . 11-18
11.1.7.3 Bit Slice Constraints and Soft Constraints . . . . . . . . . . . . . . . . . . . 11-19
11.1.7.4 Limitations of Bit Slice Constraints . . . . . . . . . . . . . . . . . . . . . . . . 11-19
11.1.7.5 Debugging Bit Slice Constraints . . . . . . . . . . . . . . . . . . . . . . . . . . 11-19
11.2 Defining Constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-20
11.2.1 keep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-21
11.2.2 keep all of {…} . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-24
11.2.3 keep struct-list.is_all_iterations() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-25
11.2.4 keep for each . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-27
11.2.5 keep soft . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-31
11.2.6 keep soft… select . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-33
11.2.7 keep gen-item.reset_soft() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-37
11.2.8 keep gen… before . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-39
11.2.9 keep soft gen … before . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-41
11.2.10 keep gen_before_subtypes() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-43
11.2.11 keep reset_gen_before_subtypes() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-46
11.2.12 value() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-48
11.2.13 constraint-bool-exp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-50
11.2.14 gen-item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-53
11.3 Invoking Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-55
11.3.1 gen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-56
11.3.2 pre_generate() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-59
11.3.3 post_generate() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-61

12 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-1
12.1 Events Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-1
12.1.1 Causes of Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-3
12.1.2 Scope of Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-3
12.2 Defining and Emitting Named Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-4
12.2.1 event . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-4
12.2.2 emit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-6

e Language Reference xiii


Contents

12.3 Sampling Events Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-8


12.4 Predefined Events Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-10
12.4.1 General Predefined Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-10
12.4.2 Events for Aiding Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-13
12.4.3 Simulation Time and Specman Ticks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-14

13 Temporal Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13-1


13.1 Temporal Expressions Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-1
13.1.1 Evaluating Temporal Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-2
13.1.2 Using HDL Objects in Temporal Expressions . . . . . . . . . . . . . . . . . . . . . . . . 13-5
13.1.3 Selected Applications of Temporal Expressions . . . . . . . . . . . . . . . . . . . . . . 13-6
13.1.3.1 Handling Overlapping Transactions . . . . . . . . . . . . . . . . . . . . . . . . 13-6
13.1.3.2 Restricting TE Matches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-7
13.1.4 Forms for Common Temporal Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . 13-7
13.1.4.1 Examples of Sequence Expressions . . . . . . . . . . . . . . . . . . . . . . . . . 13-8
13.1.4.2 Examples of Behavioral Rule Checks . . . . . . . . . . . . . . . . . . . . . . . 13-9
13.1.5 Translation of Temporal Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-10
13.2 Temporal Operators and Constructs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-11
13.2.1 Precedence of Temporal Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-12
13.2.2 not . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-13
13.2.3 fail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-14
13.2.4 and . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-16
13.2.5 or . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-19
13.2.6 { exp ; exp } . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-21
13.2.7 eventually . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-23
13.2.8 [ exp ] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-24
13.2.9 [ exp..exp ] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-26
13.2.10 ~[ exp..exp ] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-28
13.2.11 => . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-30
13.2.12 detach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-31
13.2.13 delay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-34
13.2.14 @ unary event operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-35
13.2.15 @ sampling operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-37
13.2.16 cycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-38
13.2.17 true(exp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-40
13.2.18 change(exp), fall(exp), rise(exp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-41

xiv e Language Reference


Contents

13.2.19 consume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-45


13.2.20 exec . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13-48

14 Temporal Struct Members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14-1


14.1 on . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-1
14.2 expect | assume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-3

15 Time-Consuming Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .15-1


15.1 Synchronization Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15-1
15.1.1 sync . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15-1
15.1.2 wait . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15-4
15.2 Concurrency Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15-6
15.2.1 all of . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15-6
15.2.2 first of . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15-8

16 Coverage Constructs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16-1


16.1 Defining Coverage Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-1
16.1.1 cover . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-1
16.2 Defining Basic Coverage Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-8
16.2.1 item . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-8
16.3 Defining Cross Coverage Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-31
16.3.1 cross . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-31
16.4 Defining Transition Coverage Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-42
16.4.1 transition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-42
16.5 Defining External Coverage Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-48
16.5.1 cover … using external=surecov . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-49
16.6 Extending Coverage Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-53
16.6.1 cover ... using also ... is also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-53
16.7 Extending Coverage Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-58
16.7.1 item ... using also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-58
16.8 Coverage API Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-64
16.8.1 scan_cover() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-64
16.8.2 start_group() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-66
16.8.3 start_instance() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-67
16.8.4 start_item() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-68

e Language Reference xv
Contents

16.8.5 scan_bucket() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-70


16.8.6 end_item() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-71
16.8.7 end_instance() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-72
16.8.8 end_group() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16-73

17 Simulation-Related Constructs . . . . . . . . . . . . . . . . . . . . . . . . . . . .17-1


17.1 Verilog Statements or Unit Members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-1
17.1.1 verilog code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-2
17.1.2 verilog function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-5
17.1.3 verilog import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-7
17.1.4 verilog task . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-11
17.1.5 verilog time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-14
17.1.6 verilog variable reg | wire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-16
17.1.7 verilog variable memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-24
17.2 VHDL Statements and Unit Members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-27
17.2.1 vhdl code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-27
17.2.2 vhdl driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-30
17.2.3 vhdl function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-35
17.2.4 vhdl procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-39
17.2.5 vhdl time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-48
17.3 Simulation-Related Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-49
17.3.1 force . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-50
17.3.2 release . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-55
17.4 Simulation-Related Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-61
17.4.1 'HDL-pathname' . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-61
17.4.2 specman deferred . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-62
17.5 Simulation-Related Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-64
17.5.1 simulator_command() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-64
17.5.2 stop_run() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17-65

18 Packing and Unpacking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .18-1


18.1 Basic Packing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-2
18.1.1 A Simple Example of Packing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-2
18.1.2 A Simple Example of Unpacking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-4
18.1.3 Packing and Unpacking Scalar Expressions . . . . . . . . . . . . . . . . . . . . . . . . . 18-6

xvi e Language Reference


Contents

18.1.4 Packing and Unpacking Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-7


18.1.5 Packing and Unpacking Structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-8
18.1.6 Packing and Unpacking Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-9
18.2 Advanced Packing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-12
18.2.1 Using the Predefined pack_options Instances . . . . . . . . . . . . . . . . . . . . . . . 18-12
18.2.1.1 packing.low . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-13
18.2.1.2 packing.low_big_endian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-14
18.2.1.3 packing.high . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-15
18.2.1.4 packing.high_big_endian . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-16
18.2.1.5 packing.network . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-17
18.2.1.6 packing.global_default . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-18
18.2.2 Customizing Pack Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-18
18.2.2.1 reverse_fields . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-19
18.2.2.2 reverse_list_items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-20
18.2.2.3 scalar_reorder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-20
18.2.2.4 final_reorder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-22
18.2.3 Customizing Packing for a Particular Struct . . . . . . . . . . . . . . . . . . . . . . . . 18-23
18.2.4 Bit Slice Operator and Packing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-24
18.2.5 Implicit Packing and Unpacking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-25
18.3 How to Debug Packing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-25
18.4 Constructs for Packing and Unpacking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-26
18.4.1 pack() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-27
18.4.2 unpack() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-31
18.4.3 swap() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-36
18.4.4 do_pack() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-38
18.4.5 do_unpack() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18-42

19 Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19-1
19.1 define as . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19-1
19.2 define as computed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19-10
19.3 Debugging e Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19-15

20 Preprocessor Directives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .20-1


20.1 #ifdef, #ifndef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-1
20.2 #define . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-5
20.3 #undef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-8
20.4 Predefined Macros for Specman Version Number . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-10

e Language Reference xvii


Contents

20.4.1 SPECMAN_VERSION_n_n_n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20-10


20.4.2 SPECMAN_VERSION_n_n_n_OR_LATER . . . . . . . . . . . . . . . . . . . . . . . 20-11

21 Importing e Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .21-1


21.1 import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21-1

22 Predefined Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .22-1


22.1 Global Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-2
22.1.1 Test Phase Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-2
22.1.2 Global Method setup_test() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-4
22.1.3 Global Method generate_test() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-5
22.1.4 Global Method start_test() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-5
22.1.5 Global Method run_test() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-6
22.1.6 Global Method extract_test() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-6
22.1.7 Global Method check_test() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-7
22.1.8 Global Method finalize_test() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-8
22.2 Methods of sys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-8
22.2.1 The init() Method of sys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-9
22.2.2 The wave_setup() Method of sys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-11
22.2.3 The setup() Method of sys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-12
22.2.4 The run() Method of sys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-13
22.2.5 The extract() Method of sys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-15
22.2.6 The check() Method of sys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-16
22.2.7 The finalize() Method of sys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-17
22.3 Methods of Any Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-18
22.3.1 The check() Method of any_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-19
22.3.2 The copy() Method of any_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-20
22.3.3 The do_print() Method of any_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-22
22.3.4 The extract() Method of any_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-24
22.3.5 The finalize() Method of any_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-26
22.3.6 The init() Method of any_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-27
22.3.7 The print_line() Method of any_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-30
22.3.8 The visualize() Method of any_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-32
22.3.9 The quit() Method of any_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-36
22.3.10 The run() Method of any_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-39

xviii e Language Reference


Contents

22.3.11 The rerun() Method of any_struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-40


22.4 Pseudo-Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-44
22.4.1 declared_type() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-45
22.4.2 type() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-45
22.4.3 field() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-46
22.4.4 unsafe() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-47
22.4.5 source_location() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-47
22.4.6 source_method() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-49
22.4.7 writef() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-50
22.5 Simulation-Related Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-52
22.5.1 get_define() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-52
22.6 Semaphore Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-54
22.6.1 Lockers Versus Semaphores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-56
22.6.2 How to Use the Semaphore Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-56
22.6.3 up() and down() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-57
22.6.4 try_up() and try_down() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-61
22.6.5 set_value() and get_value() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-62
22.6.6 set_max_value() and get_max_value() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-64
22.6.7 lock() and free() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-65
22.7 TCM Related Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-69
22.7.1 get_current_handle() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-70
22.7.2 get_handles_by_name() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-72
22.7.3 get_handles_by_type() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-74
22.7.4 kill() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-76
22.7.5 terminate_branch() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-78
22.7.6 terminate_thread() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-80
22.8 Coverage Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-81
22.8.1 include_tests() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-82
22.8.2 set_weight() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-83
22.8.3 set_at_least() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-85
22.8.4 set_cover() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-86
22.8.5 get_contributing_runs() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-89
22.8.6 get_unique_buckets() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-90
22.8.7 set_external_cover() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-92
22.8.8 write_cover_file() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-93
22.8.9 get_overall_grade() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-94

e Language Reference xix


Contents

22.8.10 get_ecov_name() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-96


22.8.11 get_test_name() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-97
22.8.12 get_seed() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-98
22.9 Time Conversion Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-99
22.9.1 from_specman_scale() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-99
22.9.2 to_specman_scale() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22-101

23 List Pseudo-Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23-1


23.1 Pseudo-Methods Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-1
23.2 Using List Pseudo-Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-2
23.3 Pseudo-Methods to Modify Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-3
23.3.1 add(item) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-3
23.3.2 add(list) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-5
23.3.3 add0(item) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-7
23.3.4 add0(list) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-9
23.3.5 clear() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-10
23.3.6 delete() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-11
23.3.7 fast_delete() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-13
23.3.8 insert(index, item) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-15
23.3.9 insert(index, list) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-16
23.3.10 pop() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-18
23.3.11 pop0() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-19
23.3.12 push() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-20
23.3.13 push0() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-21
23.3.14 resize() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-23
23.4 General List Pseudo-Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-27
23.4.1 apply() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-29
23.4.2 copy() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-31
23.4.3 count() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-32
23.4.4 exists() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-33
23.4.5 field . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-35
23.4.6 first() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-36
23.4.7 first_index() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-37
23.4.8 get_indices() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-39
23.4.9 has() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-40
23.4.10 is_a_permutation() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-42

xx e Language Reference
Contents

23.4.11 is_empty() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-44


23.4.12 last() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-45
23.4.13 last_index() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-47
23.4.14 max() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-48
23.4.15 max_index() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-50
23.4.16 max_value() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-51
23.4.17 min() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-53
23.4.18 min_index() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-55
23.4.19 min_value() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-56
23.4.20 reverse() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-58
23.4.21 size() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-59
23.4.22 sort() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-61
23.4.23 sort_by_field() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-62
23.4.24 split() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-64
23.4.25 top() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-67
23.4.26 top0() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-68
23.4.27 unique() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-69
23.5 Sublist Pseudo-Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-71
23.5.1 all() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-72
23.5.2 all_indices() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-74
23.6 Math and Logic Pseudo-Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-77
23.6.1 and_all() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-78
23.6.2 average() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-79
23.6.3 or_all() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-81
23.6.4 product() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-82
23.6.5 sum() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-84
23.7 List CRC Pseudo-Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-85
23.7.1 crc_8() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-85
23.7.2 crc_32() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-87
23.7.3 crc_32_flip() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-90
23.8 Keyed List Pseudo-Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-91
23.8.1 key() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-92
23.8.2 key_index() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-95
23.8.3 key_exists() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-97
23.9 Restrictions on Keyed Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23-98

e Language Reference xxi


Contents

24 Predefined Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24-1


24.1 Deep Copy and Compare Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-2
24.1.1 deep_copy() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-2
24.1.2 deep_compare() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-5
24.1.3 deep_compare_physical() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-11
24.2 Arithmetic Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-13
24.2.1 min() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-13
24.2.2 max() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-15
24.2.3 abs() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-16
24.2.4 odd() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-17
24.2.5 even() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-18
24.2.6 ilog2() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-19
24.2.7 ilog10() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-20
24.2.8 ipow() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-21
24.2.9 isqrt() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-22
24.2.10 div_round_up() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-23
24.3 Bitwise Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-25
24.3.1 bitwise_op() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-25
24.4 String Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-28
24.4.1 append() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-29
24.4.2 appendf() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-31
24.4.3 bin() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-32
24.4.4 dec() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-34
24.4.5 hex() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-35
24.4.6 quote() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-36
24.4.7 str_chop() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-38
24.4.8 str_empty() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-39
24.4.9 str_exactly() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-40
24.4.10 str_expand_dots() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-41
24.4.11 str_insensitive() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-43
24.4.12 str_join() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-44
24.4.13 str_len() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-45
24.4.14 str_lower() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-46
24.4.15 str_match() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-47
24.4.16 str_pad() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-50

xxii e Language Reference


Contents

24.4.17 str_replace() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-51


24.4.18 str_split() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-54
24.4.19 str_split_all() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-56
24.4.20 str_sub() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-57
24.4.21 str_upper() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-58
24.4.22 to_string() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-59
24.5 Output Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-61
24.5.1 out() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-62
24.5.2 outf() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-63
24.5.3 Format String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-65
24.6 Configuration Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-66
24.6.1 set_config() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-67
24.6.2 get_config() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-72
24.6.3 write_config() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-74
24.6.4 read_config() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-76
24.6.5 set_retain_state() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-78
24.6.6 get_retain_state() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-79
24.7 Specman Command Routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-80
24.7.1 specman() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-80
24.8 OS Interface Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-82
24.8.1 spawn() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-82
24.8.2 spawn_check() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-83
24.8.3 system() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-84
24.8.4 output_from() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-86
24.8.5 output_from_check() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-87
24.8.6 get_symbol() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-88
24.8.7 date_time() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-89
24.8.8 getpid() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-90
24.9 File Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-91
24.9.1 File Names and Search Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-91
24.9.2 File Descriptors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-92
24.9.3 Low-Level File Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-92
24.9.4 add_file_type() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-93
24.9.5 close() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-95
24.9.6 flush() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-97
24.9.7 open() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-98

e Language Reference xxiii


Contents

24.9.8 read() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-100


24.9.9 read_lob() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-102
24.9.10 write() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-103
24.9.11 write_lob() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-105
24.9.12 General File Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-107
24.9.13 file_age() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-107
24.9.14 file_append() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-109
24.9.15 file_copy() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-110
24.9.16 file_delete() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-112
24.9.17 file_exists() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-113
24.9.18 file_extension() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-114
24.9.19 file_is_dir() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-116
24.9.20 file_is_link() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-117
24.9.21 file_is_readable() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-118
24.9.22 file_is_regular() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-120
24.9.23 file_is_temp() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-121
24.9.24 file_is_text() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-123
24.9.25 file_rename() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-124
24.9.26 file_size() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-125
24.9.27 new_temp_file() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-127
24.9.28 write_string_list() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-128
24.9.29 Reading and Writing Structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-130
24.9.30 read_ascii_struct() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-130
24.9.31 read_binary_struct() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-132
24.9.32 write_ascii_struct() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-134
24.9.33 write_binary_struct() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-137
24.10 On-the-Fly Garbage Collection Routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-139
24.10.1 do_otf_gc() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-139
24.11 Calling Predefined Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-140
24.11.1 routine() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24-140

25 Modeling State Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25-1


25.1 State Machine Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-1
25.2 State Machine Constructs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-2
25.2.1 state machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-2
25.2.2 state => state . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-5

xxiv e Language Reference


Contents

25.2.3 * => state . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-6


25.2.4 state action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-7
25.3 Sample State Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-9
25.4 Using State Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-10
25.4.1 Initializing a State Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-10
25.4.2 Terminating a State Machine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-11
25.4.3 Rules for State Transitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-12
25.4.4 Nested State Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-13
25.4.5 Parallel State Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25-13

26 Encapsulation Constructs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .26-1


26.1 package package-name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26-1
26.2 package type-declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26-2
26.3 package | protected | private struct-member . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26-4

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Index-1

e Language Reference xxv


Contents

xxvi e Language Reference


1 About This Book
This manual provides detailed information on the e programming language that you use to model parts
of the test environment and to create tests.

1.1 Conventions in This Book


This manual uses visual cues to help you locate and interpret information easily. These cues are
explained in Table 1-1.

Table 1-1 Document Conventions

Visual Cue Represents


courier The Courier font indicates e or HDL code. For example, the following line
indicates e code:
keep opcode in [ADD, ADDI];

courier bold In examples that show commands and their results, Courier bold indicates the
commands. For example, the following line shows the usage of the load
command:
vrst-tool> load test1

bold The bold font indicates keywords in descriptive text. For example, the following
sentence contains the keyword “commands”:

You can enter multiple -commands arguments. Specman executes the


commands in their usage order.

e Language Reference 1-1


About This Book
Syntax Notation

Table 1-1 Document Conventions (continued)

Visual Cue Represents

italic The italic font represents user-defined variables that you must provide. For
example, the following line instructs you to type the “write cover” as it appears,
and then the actual name of a file:

write cover filename

[ ] square Square brackets indicate optional parameters. For example, in the following
brackets construct the keywords “list of” are optional:

var name: [list of] type

[ ] bold brackets Bold square brackets are required. For example, in the following construct you
must type the bold square brackets as they appear:

extend enum-type-name: [name,…]

construct, … An item, followed by a separator (usually a comma or a semicolon) and an


ellipsis is an abbreviation for a list of elements of the specified type. For
example, the following line means you can type a list of zero or more names
separated by commas.

extend enum-type-name: [name,…]

| The | character indicates alternative syntax or parameters. For example, the


following line indicates that either the bits or bytes keyword should be used:

type scalar-type (bits | bytes: num)

% Denotes the UNIX prompt.

C1>, C2>, … Denotes the SpeXsim prompt (VHDL, Verilog, or mixed -HDL designs).

> Denotes a third-party VHDL simulator prompt.

vrst-tool> Denotes the prompt for the Verisity tool you are running, including
Specman Elite, vManager, SpeXsim, or SpeXtreme.

1.2 Syntax Notation


Each construct section starts with the syntax for the construct. The syntax shows the construct, any
arguments it accepts with their types, and the construct’s return type if it has one.

1-2 e Language Reference


About This Book
Syntax Notation

When using the construct, terms in bold in the syntax are to be entered exactly as shown. Terms in italics
are to be replaced by terms of your own. The argument types and the construct return type are for
information only and are not entered.

For example, the syntax notation for the predefined pseudo-method named first() on page 23-36 is

list.first(exp: bool): list-type

This is what the notation means:

• The bold “.first” and the parentheses must be entered exactly.


• The parts in italics, “list” and “exp”, must be replaced by a list name and an expression.
• “: bool” indicates that the expression must be a Boolean expression.
• “: list-type” means that the pseudo-method returns an item of the list element type.
An example of a call to the list.first() pseudo-method is shown below, where “numbers” is a list of
integer items and “my_number” is an integer. The pseudo-method returns the first integer in the list
greater than 5:
my_number = numbers.first(it > 5)

e Language Reference 1-3


About This Book
Syntax Notation

1-4 e Language Reference


2 e Basics
This chapter describes the structure of an e program, starting with the organization of e code into one or
more files and the four categories of e constructs, and ending with a description of the struct hierarchy.
This chapter also describes the e operators. It contains the following sections:

• “Lexical Conventions” on page 2-2


• “Syntactic Elements” on page 2-12
• “Struct Hierarchy and Name Resolution” on page 2-23
• “Operator Precedence” on page 2-35
• “Evaluation Order of Expressions” on page 2-37
• “Bitwise Operators” on page 2-38
• “Boolean Operators” on page 2-44
• “Arithmetic Operators” on page 2-50
• “Comparison Operators” on page 2-54
• “Extraction and Concatenation Operators” on page 2-69
• “Scalar Modifiers” on page 2-83
• “Parentheses” on page 2-85
• “Special-Purpose Operators” on page 2-88

See Also
• Chapter 13 “Temporal Expressions”
• Chapter 3 “Data Types”

e Language Reference 2-1


e Basics
Lexical Conventions

• Chapter 24 “Predefined Routines”

2.1 Lexical Conventions


The following sections describe the lexical conventions of e:

• “File Structure” on page 2-2


• “Code Segments” on page 2-2
• “Comments and White Space” on page 2-3
• “Literals and Constants” on page 2-3
• “Names, Keywords, and Macros” on page 2-10

2.1.1 File Structure


e code can be organized in multiple files. File names must be legal e names. The default file extension is
“.e”. e code files are sometimes referred to as “modules”. Each module contains at least one code
segment and can also contain comments.

See Also
• “Names, Keywords, and Macros” on page 2-10
• “Code Segments” on page 2-2
• “Comments and White Space” on page 2-3

2.1.2 Code Segments


A code segment is enclosed with a begin-code marker <' and an end-code marker '>. Both the
begin-code and the end-code markers must be placed at the beginning of a line (left most), with no other
text on that same line (no code and no comments). For example, the following three lines of code form a
code segment:
<'
import cpu_test_env;
'>

Several code segments can appear in one file. Each code segment consists of one or more statements.

2-2 e Language Reference


e Basics
Comments and White Space

See Also
• “Comments and White Space” on page 2-3
• “Statements” on page 2-13

2.1.3 Comments and White Space


e files begin as a comment which ends when the first begin-code marker <' is encountered.

Comments within code segments can be marked with double dashes (--) or double slashes (//):
a = 5; -- This is an inline comment
b = 7; // This is also an inline comment

The end-code '> and the begin-code <' markers can be used in the middle of code sections, to write
several consecutive lines of comment:
Import the basic test environment for the CPU...

<'
import cpu_test_env;
'>

This particular test requires the code that bypasses bug#72 as


well as the constraints that focus on the immediate instructions.

<'
import bypass_bug72;
import cpu_test0012;
'>

See Also
• “Code Segments” on page 2-2

2.1.4 Literals and Constants


Literals are numeric, character and string values specified literally in e. Operators can be applied to
literals to create compound expressions. The following categories of literals and constants are supported
in e:

• “Unsized Numbers” on page 2-4


• “Sized Numbers” on page 2-5

e Language Reference 2-3


e Basics
Literals and Constants

• “MVL Literals” on page 2-5


• “Predefined Constants” on page 2-8
• “Literal String” on page 2-8
• “Literal Character” on page 2-9

2.1.4.1 Unsized Numbers


Unsized numbers are always positive and zero-extended unless preceded by a hyphen. Decimal
constants are treated as signed integers and have a default size of 32 bits. Binary, hex, and octal constants
are treated as unsigned integers, unless preceded by a hyphen to indicate a negative number, and have a
default size of 32 bits. If the number cannot be represented in 32 bits then it is represented as an
unbounded integer. See “Infinite (Unbounded) Integers” on page 3-4 for more information.

The notations shown in Table 2-1 can be used to represent unsized numbers.

Table 2-1 Representing Unsized Numbers in Expressions

Notation Legal Characters Examples

Decimal integer Any combination of 0-9 possibly 12, 55_32, -764


preceded by a hyphen - for negative
numbers. An underscore (_) can be added
anywhere in the number for readability.

Binary integer Any combination of 0-1 preceded by 0b. 0b100111,


An underscore (_) can be added anywhere 0b1100_0101
in the number for readability.

Hexadecimal integer Any combination of 0-9 and a-f preceded 0xff,


by 0x. An underscore (_) can be added 0x99_aa_bb_cc
anywhere in the number for readability.

Octal integer Any combination of 0-7 preceded by 0o. 0o66_123


An underscore (_) can be added anywhere
in the number for readability.

K (kilo: multiply by A decimal integer followed by a K or k. 32K, 32k, 128k


1024) For example, 32K = 32768.

M (mega: multiply by A decimal integer followed by an M or m. 1m, 4m, 4M


1024*1024) For example, 2m = 2097152.

2-4 e Language Reference


e Basics
Literals and Constants

See Also
• “Literals and Constants” on page 2-3

2.1.4.2 Sized Numbers


A sized number is a notation that defines a literal with a specific size in bits. The syntax is as follows:

width-number ' (b|o|d|h|x) value-number

The width number is a decimal integer specifying the width of the literal in bits. The value number is the
value of the literal and can be specified in one of four radixes, as shown in Table 2-2.

Note If the value number is more than the specified size in bits, its most significant bits are ignored. If
the value number is less that the specified size, it is padded by zeros.

Table 2-2 Radix Specification Characters

Radix Represented By Example

Binary A leading 'b or 'B 8'b11001010

Octal A leading 'o or 'O 6'o45

Decimal A leading 'd or 'D 16'd63453

Hexadecimal A leading 'h or 'H or 'x or 'X 32'h12ffab04

See Also
• “Literals and Constants” on page 2-3

2.1.4.3 MVL Literals


An MVL literal is based on the mvl type, which is a predefined enumerated scalar type in Specman. The
mvl type is defined as follows:

type mvl: [MVL_U,MVL_X,MVL_0,MVL_1,MVL_Z,MVL_W,MVL_L,MVL_H,MVL_N];

Note MVL_N represents “don’t care”.

The mvl type is a superset of the capabilities provided by the @x and @z syntax allowed in HDL tick
notation. For example, if a port is defined as type list of mvl, you can assign values with the $ access
operator:
sig$ = {MVL_X;MVL_X;MVL_X} ; -- HDL tick notation is 'sig@x' = 0x3

e Language Reference 2-5


e Basics
Literals and Constants

If the port is a numeric type (uint, int, and so on), you can assign mvl values using the predefined MVL
methods for ports. For example:
sig.put_mvl_list({MVL_X;MVL_X;MVL_X});

An MVL literal, which is a literal of type list of mvl, provides a more convenient syntax for assigning
MVL values. The syntax of an MVL literal is as follows:

width-number ' (b|o|h) value-number

The width number is an unsigned decimal integer specifying the size of the list. The value number is any
sequence of digits that are legal for the base, plus x, z, u, l, h, w, n.

Syntax rules:

• A single digit represents 4 bits in hexadecimal base, 3 bits in octal base and 1 bit in binary base.
Similarly, the letters x, z, u, l, h, w, n represent 4 identical bits (for hexadecimal), 3 identical bits (for
octal), or 1 bit (for binary). For example, 8’h1x is equivalent to 8’b0001xxxx.
• If the size of the value is smaller than the width, the value is padded to the left. A most significant
bit (MSB) of 0 or 1 causes zero padding. If the MSB of the literal is x, z, u, l, h, w or n, then that mvl
value is used for padding.
• If the size of the value is larger than the size specified for the list, the value is truncated leaving the
LSB of the literal.
• An underscore can be used for breaking up long numbers to enhance readability. It is legal inside the
size and inside the value. It is illegal at the beginning of the literal, between the base and the value,
and between the single quote (') and the base.

Examples
32'hffffxxxx
32'HFFFFXXXX
//16'_b1100uuuuu --illegal because (_) is between (‘) and base
19'oL0001
14'D123
64'bz_1111_0000_1111_0000

Notes
• Decimal literals are not supported.
• White space is not allowed as a separator between the width number and base or between the base
and the value.
• The base and the value are not case sensitive.
• Size and base have to be specified.

2-6 e Language Reference


e Basics
Literals and Constants

• In the context of a Verilog comparison operator (!== or ===) or HDL tick access ('data' = 32'bx),
only the 4-value subset is supported (0, 1, u, x).
• Verilog simulators support only the 4-value logic subset.
• An MVL literal of size 1 is of type list of mvl that has one element. It is not of type mvl. Thus, you
cannot assign an MVL literal to a variable or field of type mvl:
var m: mvl = 1'bz; -- illegal; MVL_Z must be assigned

Syntactically, the same expression may be of a numeric type or MVL literal. For example, 1’b1 may
represent either the number 1 or a list of MVL with the value {MVL_1}. Specman extracts the type of a
given literal from the context. A literal is considered to be an MVL literal when:

• The literal is assigned to a list of mvl, for example:


var v2: list of mvl = 16'b1;

• When the literal is passed to a method that receives a list of mvl


• When the literal is assigned to a port of type list of mvl using the $ operator
• When the literal is compared to list of mvl, for example:
check that v == 4'buuuu;

• When the literal is compared using the === and !== operators, for example:
check that 's' === 4'bz; -- limited to the 4-value subset

• When the literal is used in an HDL tick access assignment, for example:
's' = 8'bx1z; -- limited to the 4-value subset

• When the literal is an argument for a Verilog task, for example:


'task1'(8'h1x);)

• When the literal is used in a list operation, for example


l.add(32'b0)

If the type of the expression, according to the context, is numeric, or if the type cannot be extracted from
the context, the default type remains uint, for example:
print 2'b11; -- prints unsigned integer value 3
print 2'bxx; -- syntax error
pack(NULL, 32'z) -- error
Note The type-casting operations as_a() and is a do not propagate the context.

e Language Reference 2-7


e Basics
Literals and Constants

See Also
• “Scalar Types” on page 3-2

2.1.4.4 Predefined Constants


A set of constants is predefined in e, as shown in Table 2-3.

Table 2-3 Predefined Constants

Constant Description

TRUE For Boolean variables and expressions.

FALSE For Boolean variables and expressions.

NULL For structs, specifies a NULL pointer. For character strings, specifies
an empty string.

UNDEF UNDEF indicates NONE where an index is expected.

MAX_INT Represents the largest 32-bit int (231 -1)

MIN_INT Represents the smallest 32-bit int (-231).

MAX_UINT Represents the largest 32-bit uint (232-1).

See Also
• “Literals and Constants” on page 2-3

2.1.4.5 Literal String


A literal string is a sequence of zero or more ASCII characters enclosed by double quotes (“”).

The special escape sequences shown in Table 2-4 are allowed.

Table 2-4 Escape Sequences in Strings

Escape Sequence Meaning

\n New-line

\t Tab

\f Form-feed

2-8 e Language Reference


e Basics
Literals and Constants

Table 2-4 Escape Sequences in Strings (continued)

Escape Sequence Meaning

\” Quote

\\ Backslash

\r Carriage-return

Example
This example shows escape sequences used in strings.
extend sys {

m() is {
var header: string =
"Name\tSize in Bytes\n----\t-------------\n";
var p: packet = new;
var pn: string = p.type().name;
var ps: uint = p.type().size_in_bytes;
outf("%s%s\t%d", header, pn, ps);
};
};

Result
vrst-tool> sys.m()
Name Size in Bytes
---- -------------
packet 20

See Also
• “Literals and Constants” on page 2-3

2.1.4.6 Literal Character


A literal character is a single ASCII character, enclosed in quotation marks and preceded by 0c. This
expression evaluates to the integer value that represents this character. For example, the literal character
shown below is the single ASCII character “a” and evaluates to 0x0061.
var u: uint(bytes:2) = 0c"a"
Note Literal characters can only be assigned to integers or unsigned integers without explicit casting.

e Language Reference 2-9


e Basics
Names, Keywords, and Macros

See Also
• “Literals and Constants” on page 2-3

2.1.5 Names, Keywords, and Macros


The following sections describe the legal syntax for names and macros:

• “Legal e Names” on page 2-10


• “Reserved Keywords” on page 2-10
• “Macros” on page 2-12
• “HDL Object Names” on page 8-12 in the Specman Elite Integrator’s Guide

2.1.5.1 Legal e Names


User-defined names in e code consist of a case-sensitive combination of any length of the characters
A-Z, a-z, 0-9, and underscore. They must begin with a letter. Names beginning with an underscore have
a special meaning in e and are not recommended for general use. Names beginning with a number are
not allowed. Names that are identical with a reserved keyword are not allowed. See “Reserved
Keywords” on page 2-10 for a complete list.

The syntax of an e module name (a file name) is the same as the syntax of UNIX file names, with the
following exceptions:

• ‘@’ and ‘~’ are not allowed as the first character of a file name.
• ‘[‘, ‘]’, ‘{‘, ‘}’ are not allowed in file names.
• Only one ‘.’ is allowed in a file name.
Note Many ASCII characters are not handled correctly by some UNIX commands when used in file
names. These characters include control characters, spaces, and characters reserved for command line
parsing, such as ‘-’, ‘|’, and ‘<‘.

Note Naming an e module “patch.e” or “test.e” can cause problems when you try to load the compiled
file. If the module is to be compiled, do not name it patch.e or test.e.

2.1.5.2 Reserved Keywords


The reserved keywords listed below are components of the e language. Do not use these reserved
keywords as identifiers or names for user-defined entities.

2-10 e Language Reference


e Basics
Names, Keywords, and Macros

Table 2-5 Reserved Keywords


a new all of and= and
assert assume async attribute
before bind bits break
buffer_port of bytes c export C export
case change check check that
compute computed consume continue
cover cross cycle cvl call
cvl callback cvl method def-err default
define delay detach do
down to else emit event
event_port eventually exec expect
extend external fail fall
first of for for each force
from gen if ignore
illegal import in in range
in reverse in_sequence in_unit index
inout is is a is an
is also is c routine is C routine is empty
is first is inline is inline only is instance
is not a is not empty is only is undefined
item keep keeping like
line list matching me
method_port of nand new no_collect
nor not nxor of
on or or= package
prev print private protected
range ranges reference repeat
return rise routine sequence
select simple_port of soft start
state machine step struct sync
that then time to
transition true try unit

e Language Reference 2-11


e Basics
Syntactic Elements

until using using also var


verilog code verilog function verilog import verilog simulator
verilog task verilog time verilog trace verilog variable
vhdl code vhdl driver vhdl function vhdl object
vhdl procedure vhdl simulator vhdl time wait
when while with within
FALSE MAX_INT MIN_INT NULL
UNDEF TRUE

2.1.5.3 Macros
e macros (created with the define statement) can be defined with or without an initial ` character. There
are two important characteristics of e macros defined with an initial ` character:

• They share the same name space as Verilog macros.


• You must always include the ` character when you reference the name.
Thus, if you import a file of Verilog macros containing the following macro:
'define WORD_WIDTH 8

defining the following e macro results in a name conflict:


define `WORD_WIDTH 16;

With either macro defined, the correct way to reference it is as follows:


struct t {
f: uint (bits: `WORD_WIDTH);
};

See Also
• Chapter 20 “Preprocessor Directives”
• “HDL Object Names” on page 8-12 in the Specman Elite Integrator’s Guide

2.2 Syntactic Elements


Every e construct belongs to a construct category that determines how the construct can be used. There
are four categories of e constructs:

2-12 e Language Reference


e Basics
Statements

Statements Statements are top-level constructs and are valid within the begin-code <'
and end-code '> markers. See “Statements” on page 2-13 for a list and
brief description of e statements.
Struct members Struct members are second-level constructs and are valid only within a
struct definition. See “Struct Members” on page 2-15 for a list and brief
description of e struct members.
Actions Actions are third-level constructs and are valid only when associated with
a struct member, such as a method or an event. See “Actions” on page 2-16
for a list and brief description of e actions.
Expressions Expressions are lower-level constructs that can be used only within
another e construct. See “Expressions” on page 2-23 for a list and brief
description of e expressions.

The syntax hierarchy roughly corresponds to the level of indentation shown below:
statements
struct members
actions
expressions

See Also
• “Statements” on page 2-13
• “Struct Members” on page 2-15
• “Actions” on page 2-16
• “Expressions” on page 2-23

2.2.1 Statements
Statements are the top-level syntactic constructs of the e language and perform the functions related to
extending the e language and interface with the simulator.

Statements are valid within the begin-code <' and end-code '> markers. They can extend over several
lines and are separated by semicolons. For example, the following code segment has two statements:
<'
import bypass_bug72;
import cpu_test0012;
'>

e Language Reference 2-13


e Basics
Statements

In general, within a given e module, statements can appear in any order except that import statements
must appear before any other statements. No statements other than verilog import, preprocessor
directives or defines (#ifdef, #ifndef, define, define as, define as computed) can precede import
statements. See import on page 21-1 for an example of a special case where this restriction also applies
to import statements in different e modules.

Here is the complete list of e statements:

struct on page 4-2 Defines a new data structure.


type Defines an enumerated data type or scalar subtype.
See type enumerated scalar on page 3-31, type
scalar subtype on page 3-34, or type sized scalar
on page 3-36
extend Modifies a previously defined struct or type. See
extend type on page 4-6 or extend type on page
3-37
define Extends the e language by defining new commands,
actions, expressions, or any other syntactic element.
See Chapter 19 “Macros”, define as on page 19-1, or
define as computed on page 19-10.
#ifdef, #ifndef on page 20-1 Used together with define statements to place
conditions on the e parser.
routine … is C routine on page 11-21 in the Declares a user-defined C routine that you want to
Usage and Concepts Guide for e call from e.
Testbenches
C export on page 11-48 in the Usage and Exports an e declared type or method to C.
Concepts Guide for e Testbenches
import on page 21-1 Reads in an e file.
verilog import on page 17-7 Reads in Verilog macro definitions from a file.
verilog code on page 17-2 Writes Verilog code to the stubs file, which is used to
interface e programs with a Verilog simulator.
verilog time on page 17-14 Specifies Verilog simulator time resolution.
verilog variable reg | wire on page 17-16 Specifies a Verilog register or wire that you want to
drive from e.
verilog variable memory on page 17-24 Specifies a Verilog memory that you want to access
from e.
verilog function on page 17-5 Specifies a Verilog function that you want to call
from e.
verilog task on page 17-12 Specifies a Verilog task that you want to call from e.

2-14 e Language Reference


e Basics
Struct Members

vhdl code on page 17-28 Writes VHDL code to the stubs file, which is used to
interface e programs with a VHDL simulator.
vhdl driver on page 17-31 Used to drive a VHDL signal continuously via the
resolution function.
vhdl function on page 17-38 Declares a VHDL function defined in a VHDL
package.
vhdl procedure on page 17-43 Declares a VHDL procedure defined in a VHDL
package.
vhdl time on page 17-51 Specifies VHDL simulator time resolution.

See Also
• “Struct Members” on page 2-15
• “Actions” on page 2-16
• “Expressions” on page 2-23

2.2.2 Struct Members


Struct member declarations are second-level syntactic constructs of the e language that associate the
entities of various kinds with the enclosing struct.

Struct members can only appear inside a struct type definition statement (see struct on page 4-2). They
can extend over several lines and are separated by semicolons. For example, the following struct
“packet” has two struct members, len and data:
<'
struct packet{
%len: int;
%data[len]: list of byte;
};
'>

A struct can contain multiple struct members of any type in any order. Here is a brief description of e
struct members:

e Language Reference 2-15


e Basics
Actions

field declaration Defines a data entity that is a member of the enclosing struct
and has an explicit data type.
method declaration Defines an operational procedure that can manipulate the
fields of the enclosing struct and access runtime values in
the DUT.
subtype declaration Defines an instance of the parent struct in which specific
struct members have particular values or behavior.
constraint declaration Influences the distribution of values generated for data
entities and the order in which values are generated.
coverage declaration Defines functional test goals and collects data on how well
the testing is meeting those goals.
temporal declaration Defines e events and their associated actions.

See Also
• “Defining Fields” on page 4-11
• “Rules for Defining and Extending Methods” on page 7-2
• “Creating Subtypes with When” on page 4-21
• “Defining Constraints” on page 11-19
• “Defining Coverage Groups” on page 16-1
• Chapter 14 “Temporal Struct Members”

2.2.3 Actions
e actions are lower-level procedural constructs that can be used in combination to manipulate the fields
of a struct or exchange data with the DUT.

Actions can extend over several lines and are separated by semicolons. An action block is a list of
actions separated by semicolons and enclosed in curly brackets, { }.

Actions must be associated with a struct member, specifically a method or an event, or issued
interactively as commands at the command line. Here is an example of an action (an invocation of a
method, “transmit()”) associated with an event, xmit_ready. Another action, out() is associated with the
transmit() method.
<'
struct packet{
event xmit_ready is rise('top.ready');
on xmit_ready {transmit();};

2-16 e Language Reference


e Basics
Actions

transmit() is {
out("transmitting packet...");
};
};
'>

The following sections describe the e actions:

• “Creating or Modifying Variables” on page 2-17


• “Executing Actions Conditionally” on page 2-18
• “Executing Actions Iteratively” on page 2-18
• “Controlling Program Flow” on page 2-19
• “Invoking Methods and Routines” on page 2-20
• “Performing Time-Consuming Actions” on page 2-20
• “Generating Data Items” on page 2-21
• “Detecting and Handling Errors” on page 2-22
• “Printing” on page 2-22

2.2.3.1 Creating or Modifying Variables


var on page 8-2 Defines a local variable.
= on page 8-4 Assigns or samples values of fields, local variables, or HDL objects.
op= on page 8-7 Performs a complex assignment (such as add and assign, or shift and
assign) of a field, local variable, or HDL object.
force on page 17-53 Forces a Verilog net or wire to a specified value, over-riding the value
from driven from the DUT.
release on page 17-59 Releases the Verilog net or wire that was previously forced.

See Also
• “Executing Actions Conditionally” on page 2-18
• “Executing Actions Iteratively” on page 2-18
• “Controlling Program Flow” on page 2-19
• “Invoking Methods and Routines” on page 2-20
• “Performing Time-Consuming Actions” on page 2-20

e Language Reference 2-17


e Basics
Actions

• “Generating Data Items” on page 2-21


• “Detecting and Handling Errors” on page 2-22
• “Printing” on page 2-22

2.2.3.2 Executing Actions Conditionally


if then else on page 9-1 Executes an action block if a condition is met and a different action
block if it is not.
case labeled-case-item on Executes one action block out of multiple action blocks depending on
page 9-3 the value of a single expression.
case bool-case-item on Evaluates a list of Boolean expressions and executes the action block
page 9-5 associated with the first expression that is true.

See Also
• “Creating or Modifying Variables” on page 2-17
• “Executing Actions Iteratively” on page 2-18
• “Controlling Program Flow” on page 2-19
• “Invoking Methods and Routines” on page 2-20
• “Performing Time-Consuming Actions” on page 2-20
• “Generating Data Items” on page 2-21
• “Detecting and Handling Errors” on page 2-22
• “Printing” on page 2-22

2.2.3.3 Executing Actions Iteratively


while on page 9-7 Executes an action block repeatedly until a Boolean expression
becomes FALSE.
repeat until on page 9-9 Executes an action block repeatedly until a Boolean expression
becomes TRUE.
for each in on page 9-11 For each item in a list that is a specified type, executes an action
block.
for from to on page 9-14 Executes an action block for a specified number of times.

2-18 e Language Reference


e Basics
Actions

for on page 9-15 Executes an action block for a specified number of times.
for each line in file on page Executes an action block for each line in a file.
9-17
for each file matching on Executes an action block for each file in the search path.
page 9-19

See Also
• “Creating or Modifying Variables” on page 2-17
• “Executing Actions Conditionally” on page 2-18
• “Controlling Program Flow” on page 2-19
• “Invoking Methods and Routines” on page 2-20
• “Performing Time-Consuming Actions” on page 2-20
• “Generating Data Items” on page 2-21
• “Detecting and Handling Errors” on page 2-22
• “Printing” on page 2-22

2.2.3.4 Controlling Program Flow


break on page 9-20 Breaks the execution of the enclosing loop.
continue on page 9-21 Stops execution of the enclosing loop and continues with the next
iteration of the same loop.

See Also
• “Creating or Modifying Variables” on page 2-17
• “Executing Actions Conditionally” on page 2-18
• “Executing Actions Iteratively” on page 2-18
• “Invoking Methods and Routines” on page 2-20
• “Performing Time-Consuming Actions” on page 2-20
• “Generating Data Items” on page 2-21
• “Detecting and Handling Errors” on page 2-22
• “Printing” on page 2-22

e Language Reference 2-19


e Basics
Actions

2.2.3.5 Invoking Methods and Routines


method() on page 7-27 Calls a regular method.
tcm() on page 7-23 Calls a TCM.
start tcm() on page 7-25 Launches a TCM as a new thread (a parallel process).
routine() on page 24-140 Calls an e predefined routine.
“Calling C Routines from e” on page Describes how to call user-defined C routines.
11-19 in the Usage and Concepts Guide
for e Testbenches
compute method() on page 7-29 Calls a value-returning method without using the value
returned.
return on page 7-30 Returns immediately from the current method to the
method that called it.

See Also
• “Creating or Modifying Variables” on page 2-17
• “Executing Actions Conditionally” on page 2-18
• “Executing Actions Iteratively” on page 2-18
• “Controlling Program Flow” on page 2-19
• “Performing Time-Consuming Actions” on page 2-20
• “Generating Data Items” on page 2-21
• “Detecting and Handling Errors” on page 2-22
• “Printing” on page 2-22

2.2.3.6 Performing Time-Consuming Actions


emit on page 12-6 Causes a named event to occur.
sync on page 15-1 Suspends execution of the current TCM until the temporal expression
succeeds.
wait on page 15-4 Suspends execution of the current time-consuming method until a given
temporal expression succeeds.

2-20 e Language Reference


e Basics
Actions

all of on page 15-6 Executes multiple action blocks concurrently, as separate branches of a
fork. The action following the all of action is reached only when all
branches of the all of have been fully executed.
first of on page 15-8 Executes multiple action blocks concurrently, as separate branches of a
fork. The action following the first of action is reached when any of the
branches in the first of has been fully executed.
state machine on page Defines a state machine.
25-2

See Also
• “Creating or Modifying Variables” on page 2-17
• “Executing Actions Conditionally” on page 2-18
• “Executing Actions Iteratively” on page 2-18
• “Controlling Program Flow” on page 2-19
• “Invoking Methods and Routines” on page 2-20
• “Generating Data Items” on page 2-21
• “Detecting and Handling Errors” on page 2-22
• “Printing” on page 2-22

2.2.3.7 Generating Data Items


gen on page 11-55 Generates a value for an item, while considering all relevant constraints.

See Also
• “Creating or Modifying Variables” on page 2-17
• “Executing Actions Conditionally” on page 2-18
• “Executing Actions Iteratively” on page 2-18
• “Controlling Program Flow” on page 2-19
• “Invoking Methods and Routines” on page 2-20
• “Performing Time-Consuming Actions” on page 2-20
• “Detecting and Handling Errors” on page 2-22

e Language Reference 2-21


e Basics
Actions

• “Printing” on page 2-22

2.2.3.8 Detecting and Handling Errors


check that on page 10-2 Checks the DUT for correct data values.
dut_error() on page 10-4 Defines a DUT error message string.
assert on page 10-21 Issues an error message if a specified Boolean expression is not true.
warning() on page 10-14 Issues a warning message.
error() on page 10-16 Issues an error message when a user error is detected.
fatal() on page 10-17 Issues an error message, halts all activities, and exits immediately.
try on page 10-19 Catches errors and exceptions.

See Also
• “Creating or Modifying Variables” on page 2-17
• “Executing Actions Conditionally” on page 2-18
• “Executing Actions Iteratively” on page 2-18
• “Controlling Program Flow” on page 2-19
• “Invoking Methods and Routines” on page 2-20
• “Performing Time-Consuming Actions” on page 2-20
• “Generating Data Items” on page 2-21
• “Printing” on page 2-22

2.2.3.9 Printing
print on page 9-2 in the Specman Prints a list of expressions.
Command Reference
set_config() on page 24-67 Sets options for various categories, including printing.

See Also
• “Creating or Modifying Variables” on page 2-17
• “Executing Actions Conditionally” on page 2-18
• “Executing Actions Iteratively” on page 2-18

2-22 e Language Reference


e Basics
Expressions

• “Controlling Program Flow” on page 2-19


• “Invoking Methods and Routines” on page 2-20
• “Performing Time-Consuming Actions” on page 2-20
• “Generating Data Items” on page 2-21
• “Detecting and Handling Errors” on page 2-22

2.2.4 Expressions
Expressions are constructs that combine operands and operators to represent a value. The resulting value
is a function of the values of the operands and the semantic meaning of the operators.

A few e expressions, such as expressions that restrict the range of valid values of a variable, must
evaluate to constants at compile time. More typically, expressions are evaluated at run time, resolved to
a value of some type, and assigned to a variable or field of that type. Strict type checking in e is enforced.

Each expression must contain at least one operand, which can be:

• A literal value
• A constant
• An e entity, such as a method, field, list, or struct
• An HDL entity, such as a signal
A compound expression applies one or more operators to one or more operands.

See Also
• Chapter 3 “Data Types”

2.3 Struct Hierarchy and Name Resolution


The following sections explain the struct hierarchy of an e program and how to reference entities within
the program:

• “Struct Hierarchy” on page 2-24


• “Referencing e Entities” on page 2-26
• “Implicit Variables” on page 2-30
• “Name Resolution Rules” on page 2-33

e Language Reference 2-23


e Basics
Struct Hierarchy

2.3.1 Struct Hierarchy


Because structs can be instantiated as the fields of other structs, a typical e program has many levels of
hierarchy. Every e program contains several predefined structs as well as user-defined structs. Figure 2-1
shows the partial hierarchy of a typical e program. The predefined structs are shown in bold.

Figure 2-1 Diagram of Struct Hierarchy

global

files packing sys scheduler simulator session

switch

ctrl_stub port_stub1 port_stub2 port_stub3 port_stub4

sender listener

2.3.1.1 Global Struct


The predefined struct global is the root of all e structs. All predefined structs and most predefined
methods are part of the global struct.

It is highly recommended that you do not extend the global struct.

2.3.1.2 Sys Struct


The system struct is instantiated under global as sys.

All fields and structs in sys not marked by an exclamation point (!) are generated automatically during
the generate_test phase. Any structs or fields outside of sys that need generation must be generated
explicitly.

Specman time is stored in a 64-bit integer field named sys.time. In standalone mode, time is measured
in Specman ticks. When Specman is linked with an event-driven simulator (such as SpeXsim), sys.time
shows the current simulator time. When Specman is linked with a cycle-based simulator, sys.time shows
the current simulator cycle. sys.time is influenced by the current timescale. See verilog time on page
17-14 and vhdl time on page 17-51 for information on how Specman determines the timescale.

2-24 e Language Reference


e Basics
Struct Hierarchy

2.3.1.3 Packing Struct


Packing and unpacking are controlled by a predefined struct under global named packing. Packing and
unpacking prepare e data sent to or received from the DUT. Under the packing struct are five predefined
structs. You can create your own packing order by copying one of these structs and modifying one or
more of its parameters.

2.3.1.4 Files Struct


The files struct provides predefined methods for manipulating files.

2.3.1.5 Scheduler Struct


The scheduler struct contains predefined methods that allow you to access active TCMs and terminate
them.

2.3.1.6 Simulator Struct


The simulator struct controls the HDL simulator and has a predefined method that allows access to
Verilog macros at run time.

2.3.1.7 Session Struct


The session struct holds the status of the current simulator session, related information, and events. You
can print the session struct to see the types of information that are stored in this struct by typing the
following at the Specman prompt:
print session

Fields available in the session struct that are of general interest include:

• session.user_time
• session.system_time
• session.specman_memory
• session.check_ok
• session.events
The first three fields listed above help you determine the time and memory used in a particular session.
The following sections describe the check_ok field and the events field.

e Language Reference 2-25


e Basics
Referencing e Entities

session.check_ok
This field is of Boolean type, and is set TRUE after every check, if the check succeeds. Otherwise, it is
set to FALSE. This field allows you to extend checking of a behavior without the need to duplicate the if
clause.

The following example show how this is accomplished.


post_generate() is also {
check that mlist.size() > 0 else dut_error("Empty list");
if session.check_ok then {
check that mlist[0] == 0xa else dut_error("Error at index 0");
};
};

session.events
This field contains the names of all user-defined events that occurred during the test, and how many
times each user-defined event occurred. The name of the event is preceded by the struct type and a
double underscore:

struct_type__event_name

You can view the events coverage by selecting the session.events group in the coverage GUI, or by
entering the command:
show cover session.events

If an event is defined in a when subtype, the name of the event in the session.events field is prefixed by
the subtype and a double underscore:

subtype__struct_type__event_name

2.3.2 Referencing e Entities


The following sections describe how to reference e entities:

• “Structs and Fields” on page 2-27


• “Method and Routine Names” on page 2-28
• “Enumerated Type Values” on page 2-29

2-26 e Language Reference


e Basics
Referencing e Entities

2.3.2.1 Structs and Fields


Any user-defined struct can be instantiated as a field of the sys struct or of another struct. Thus every
instantiated struct and its fields have a place in the struct hierarchy and their names include a path
reflecting that place.

The keep constraints in the following example show the use of paths to identify the fields u and kind:
<'
struct switch {
ctrl: ctrl_stub;
port: port_stub;

keep soft port.sender.cell.u == 0xff;


keep ctrl.init_command.kind == RD;
};
struct ctrl_stub {
init_command: ctrl_cmd;
};
struct simplex {
kind: [TX, RX];
cell: cell;
};
struct port_stub {
sender: TX simplex;
listener: RX simplex;
};
struct cell {
u: uint;
};
struct ctrl_cmd {
kind: [RD, WR];
addr: int;
};
extend sys {
switch : switch;
};
'>

Notes
• The name of the global struct can be omitted from the path to a field or a struct.
• The name of the enclosing struct is not included in the path if the current struct is the enclosing struct.
For example, prefixing the name port.sender.cell.u in the example above with the name of the
enclosing struct, switch, is an error.

e Language Reference 2-27


e Basics
Referencing e Entities

• In certain contexts, you can use the implicit variables me or it in the path to refer to the enclosing
struct. For example, prefixing the name port.sender.cell.u in the example above with me is legal. See
“Implicit Variables” on page 2-30 for more information.

• A special syntax is required to reference struct subtypes and fields under struct subtypes. This syntax
is described in “Struct Subtypes” on page 3-8.

See Also
• “Struct Subtypes” on page 3-8
• “Implicit Variables” on page 2-30
• . on page 2-93

2.3.2.2 Method and Routine Names


The names of all methods and routines must be followed immediately by parentheses, both when you
define the method and when you call it.

The predefined methods of any struct, such as pre_generate() or init(), and all user-defined methods,
are associated with a particular struct. Thus, like structs and fields, every user-defined method has a
place in the struct hierarchy and its name includes a path reflecting that place.

The example below illustrates the names used to call user-defined and predefined methods.
<'
struct meth {
%size: int;
%taken: int;

get_free(size: int, taken: int): int is inline {


result = size - taken;};
};
extend sys {
!area: int;
mi: meth;

post_generate() is also {
sys.area = sys.mi.get_free(sys.mi.size, sys.mi.taken);
print sys.area;
};
};
'>

2-28 e Language Reference


e Basics
Referencing e Entities

Some predefined methods, such as the methods used to manipulate lists, are pseudo-methods. They are
not associated with a particular struct. These methods are called by appending their name to the
expression that you want to manipulate. Here is an example of how to call the list pseudo-method .size():
<'
struct meth {
%data: list of int;

keep data.size() <= 10;


};
'>

User-defined routines, like predefined routines, are associated with the global struct. You can omit
global from the path when the context is unambiguous. See “Name Resolution Rules” on page 2-33 for
more information.

See Also
• “Invoking Methods and Routines” on page 2-20

2.3.2.3 Enumerated Type Values


Names for enumerated type values must be unique within each type. For example, defining a type as
“my_type: [a, a, b]” results in an error because the name “a” is not unique.

However, the same name can be used in more than one enumerated type. For example, the following two
enumerated types define the same value names:
type destination: [a, b, c, d];
type source: [a, b, c, d];

To refer to an enumerated type value in a struct where no values are shared between the enumerated
types, you can use just the value name. In structs where more than one enumerated field can have the
same value, you must use the following syntax to refer to the value when the type is not clear from the
context:
type_name'value

In the following keep constraint, it is clear that the type of “dest” is “destination”, so you can use just the
value name “b”:
type destination: [a, b, c, d];
type source: [a, b, c, d];
struct packet {
dest: destination;
keep me.dest == b;

e Language Reference 2-29


e Basics
Implicit Variables

However, because the type of the variable “tmp” below is not specified, it is necessary to use the full
name for the enumerated type value “destination'b”:
m() is {
var tmp := destination'b;
};

See Also
• “Enumerated Scalar Types” on page 3-5

2.3.3 Implicit Variables


Many e constructs create implicit variables. The scope of these implicit variables is the construct that
creates them. Two of these implicit variables, me and it, are used in pathnames when referencing e
entities.

This section describes the implicit variables:

• it on page 2-30
• me on page 2-31
• result on page 2-32
• index on page 2-32
Note With the exception of result, you cannot assign values to implicit variables. An assignment such
as “me = packet” generates an error.

2.3.3.1 it
The constructs that create the implicit variable it are:

• list pseudo-methods
• for each
• gen...keeping
• keep for each
• keep .is_all_iterations()
• new with
• list with key declaration

2-30 e Language Reference


e Basics
Implicit Variables

The implicit variable it always refers to the current item.

Wherever it.field can be used, the shorthand notation .field can be used in its place. For example, it.len
can be abbreviated to .len, with a leading dot. A typical use of it is to refer to each item in a list within a
loop.
for each in sys.packets{
it.len = 5;
.good = TRUE;
};

In the code above, .good is shorthand for it.good. The scope of the it variable is restricted to the for loop.

In many places it is legal to designate and use a name other than the implicit it. In the following example,
it is replaced with a variable name, “p”, that is declared in the iterating action.
for each (p) in sys.packets do {
print p.len;
};

See Also
• “Implicit Variables” on page 2-30

2.3.3.2 me
The implicit variable me refers to the current struct and can be used anywhere in the struct. In the
following example, me refers to the current instance of the packet struct, and it refers to the current
value of tmp.
struct packet {
data: uint;
stm() is {
var tmp: uint;
gen tmp keeping {it < me.data};
print data, tmp using hex;
};
};

When referring to a field from another member of the same struct, the me. can be omitted. In the keep
constraint shown below, the name “me.header.dest” is equivalent to the name “header.dest”.
struct packet {
%header : header;

keep header.dest == 0x55;


};

e Language Reference 2-31


e Basics
Implicit Variables

struct header {
%dest : int (bits : 8);
};

See Also
• “Implicit Variables” on page 2-30

2.3.3.3 result
The result variable returns a value of the method’s return type. If no return action is encountered, result
is returned by default. The default for the result variable is the default value for the method’s return type.
The following method returns the sum of “a” and “b”:
sum(a: int, b: int): int is {
result = a + b;
};

The default result variable values for several method return types are shown below:

Method return type Default result value


scalar types 0
boolean FALSE
struct NULL
list empty

See Also
• “Implicit Variables” on page 2-30

2.3.3.4 index
The constructs that create the implicit variable index are:

• list pseudo-methods
• for each
• keep for each
The index variable is a non-negative integer (int) that holds the current index of the item referred to by
it. The scope of the index variable is limited to the action block.

The following loop assigns 5 to the len field of every item in the packets list and also assigns the index
value of each item to its id field.

2-32 e Language Reference


e Basics
Name Resolution Rules

for each in packets do {


packets[index].len = 5;
.id = index;
};

See Also
• “Implicit Variables” on page 2-30

2.3.4 Name Resolution Rules


The following sections describe how Specman resolves names, depending on whether the names include
a path or not.

• “Names that Include a Path” on page 2-33


• “Names that Do Not Include a Path” on page 2-34

2.3.4.1 Names that Include a Path


To resolve names that include a path, Specman looks for an entity of that name at the specified scope and
issues an error message if it does not find it. In the following example, Specman is not able to resolve the
names “sys.b.u” or “.u” in the keep constraints, and issues an error if these are not commented out. It
successfully resolves all other names.
<'
struct b {
u:uint;

m() is {
print u;
};
};
struct c {
u:uint;

keep u > sys.bi.u;


keep me.u > 5;
-- keep u < sys.b.u; // 'sys' does not have a field 'b'
-- keep .u < sys.bi.u; // no such variable 'it'

m() is {
print u;
};
};

e Language Reference 2-33


e Basics
Name Resolution Rules

extend sys {
bi: b;
ci: c;

post_generate() is also {
sys.bi.m();
ci.m();
};
};
'>

Note If the path begins with a period (.), Specman assumes the path begins with the implicit variable it.

See Also
• “Names that Do Not Include a Path” on page 2-34

2.3.4.2 Names that Do Not Include a Path


To resolve names that do not include a path, Specman performs the following checks, in order. Specman
stops after the first check that identifies the named object.

1. Check whether the name is a macro. If there are two macro definitions, choose the most recent one.

2. Check whether the name is one of the predefined constants. There cannot be two identical predefined
constants.

3. Check whether the name is an enumerated type. There cannot be two identical enumerated types.

4. Check whether the name identifies a variable used in the current action block. If not, and if the action
is nested, check whether the name identifies a variable in the enclosing action block. If not, this
search continues from the immediately enclosing action block outwards to the boundary of the
method.

5. Check whether the name identifies a member of the current struct:

• If the expression is inside a struct definition, the current struct is the enclosing struct.
• If the expression is inside a method, the current struct is the struct to which the method belongs.
6. Check whether the name identifies a member of the global struct.

7. If the name is still unresolved, Specman issues an error message.

2-34 e Language Reference


e Basics
Operator Precedence

Example
The following example illustrates how variables in the inner scopes hide those in the outer scopes:
m() is {
var x: int = 6;
if x > 4 then {
var x: bool = TRUE;
print x;
};
print x;
};

Result
vrst-tool> sys.ti.m()
x = TRUE
x = 6
Note Macros, predefined constants, and enumerated types have “global scope”, which means they can
be seen from anywhere within an e program. For that reason, their names must be unique:

• No two name macros can have the same name, and no two replacement macros can have the same
macro-name’nonterminal-type (Chapter 19 “Macros”).

• No user-defined constant can have the same name as a predefined Specman constant (“Predefined
Constants” on page 2-8).

• No two enumerated types can have the same enum-type-name (“Constructs for Defining and Extending
Scalar Types” on page 3-31).

See Also
• “Names that Include a Path” on page 2-33

2.4 Operator Precedence


The following table summarizes all e operators in order of precedence. The precedence is the same as in
the C language, with the exception of operators that do not exist in C. To change the order of
computation, place parentheses around the expression that should be computed first.

Table 2-6 Operators in Order of Precedence

Operator Operation Type

[ ] on page 2-69 List indexing (subscripting)

e Language Reference 2-35


e Basics
Operator Precedence

Table 2-6 Operators in Order of Precedence (continued)

Operator Operation Type

[ .. ] on page 2-75 List slicing

[ : ] on page 2-70 Bit slicing (selection)

f(…) Method and routine calls (see “Invoking Methods and Routines” on
page 2-20)

. on page 2-93 Field selection

~ on page 2-38, Bitwise not, Boolean not


! (not) on page 2-44

{… ; …} on page 2-77 List concatenation

%{… , …} on page 2-79 Bit concatenation

Unary + - on page 2-51 Unary plus, minus

*, /, % Binary multiply, divide, modulus (see + - * / % on page 2-52)

+, - Binary add and subtract (see + - * / % on page 2-52)

>> << on page 2-42 Shift right, shift left

< <= > >= on page 2-54 Comparison

is [not] a on page 2-88 Subtype identification

== != on page 2-56 Equality, inequality

=== !== on page 2-58 Verilog four-state comparison

~ !~ on page 2-60 String matching

in on page 2-62 Range list operator

& Bitwise and (see & | ^ on page 2-40)

| Bitwise or (see & | ^ on page 2-40)

^ Bitwise xor (see & | ^ on page 2-40)

&& (and) on page 2-45 Boolean and

|| (or) on page 2-46 Boolean or

=> on page 2-48 Boolean implication

2-36 e Language Reference


e Basics
Evaluation Order of Expressions

Table 2-6 Operators in Order of Precedence (continued)

Operator Operation Type

? : on page 2-96 Conditional operator (“a ? b : c” means “if a then b else c”)

Note Every operation in e is performed within the context of types and is carried out either with 32-bit
precision or unbounded precision.

See Also
• Chapter 3 “Data Types” for information on the precision of operations and assignment rules
• “Evaluation Order of Expressions” on page 2-37

2.5 Evaluation Order of Expressions


In e it is defined that “and” (&&) and “or” (||) use left-to-right lazy evaluation. Consider the following
statement:
bool_1 = foo(x) && bar(x)

If foo(x) returns TRUE, then bar(x) will be evaluated as well, to determine whether bool_1 gets TRUE.
If, however, foo(x) returns FALSE, then bool_1 gets FALSE immediately, and bar(x) is not executed.
The argument to bar(x) is not even evaluated.

Expressions containing || are likewise evaluated in a lazy fashion: If the subexpression on the left of the
“or” operator is TRUE, then the subexpression on the right is ignored.

Although e was implemented to use left-to-right evaluation for both compiled e code and interpreted e
code, that evaluation order is not required by the language definition for operators other than && or ||.

Take for example the following statement:


bool_2 = foo(x) + bar(x)

If foo(x) or bar(x) has side effects (that is, if foo(x) changes the value of x or bar(x) changes the value of
x), then the results of foo(x) + bar(x) might depend on which of the two subexpressions, foo(x) or bar(x),
is evaluated first, so the results are not predictable according to the e language definition. Practically, the
left-to-right evaluation implemented in e assures predictable results, but that order is not guaranteed for
other compilers. Writing code that depends on evaluation order should be avoided.

See Also
• “Operator Precedence” on page 2-35

e Language Reference 2-37


e Basics
Bitwise Operators

2.6 Bitwise Operators


The following sections describe the e bitwise operators:

~ on page 2-38 The bitwise unary negation operator changes each 0 bit to 1 and each 1 bit
to 0 in a single expression.
& | ^ on page 2-40 The binary bitwise AND, OR, and XOR operators compare each bit in
one expression with the corresponding bit in a second expression to
calculate the result.
>> << on page 2-42 The shift-right and shift-left operators shift the bits in an expression to the
left or right a specified number of bits.

See Also
• bitwise_op() on page 24-25

2.6.1 ~

Purpose
Unary bitwise negation

Category
Expression

Syntax
~exp

Syntax Example
print ~x using hex;

Parameter

exp A numeric expression or an HDL pathname.

2-38 e Language Reference


e Basics
~

Description
Sets each 1 bit of an expression to 0 and each 0 bits to 1. Each bit of the result expression is the opposite
of the same bit in the original expression.

Example 1
This example shows the effect of the ~ operator on a 32-bit integer.
m() is {
var x : int = 0xff;
print ~x using hex;
};

Result
~x = 0xffffff00

Example 2
This example shows the effect of the ~ operator on a 2-bit integer.
m() is {
var x : uint (bits:2) = 2;
print ~x using bin;
};

Result
~x = 0b01

Example 3
This example shows the effect of the ~ operator on an untyped expression.

When Specman cannot determine the type and bit size of an HDL signal from the context, it
automatically casts the expression as an unsigned 32-bit integer.
m() is {
print 'top.clk';
print ~'top.clk';
print (~'top.clk')[0:0];
};

e Language Reference 2-39


e Basics
&|^

Result
'top.clk' = 0x0
~'top.clk' = 0xffffffff
(~'top.clk')[0:0] = 0x1

See Also
• “'HDL-pathname'” on page 17-65
• “Scalar Types” on page 3-2
• “Untyped Expressions” on page 3-17

2.6.2 &|^

Purpose
Binary bitwise operations

Category
Expression

Syntax
exp1 operator exp2

Syntax Example
print (x & y);

Parameters

exp1, exp2 A numeric expression or an HDL pathname.

operator is one of the following:

& Performs an AND operation.

| Performs an OR operation.

^ Performs an XOR operation.

2-40 e Language Reference


e Basics
&|^

Description
Performs an AND, OR, or XOR of both operands, bit by bit.

Example 1
m() is {
var x: uint = 0xff03;
var y: uint = 0x70f6;
print (x & y);
};

Result
vrst-tool> sys.m()
(x & y) = 0x7002

Example 2
m() is {
var x: uint = 0xff03;
'top.a' = 0x70f6;
print (x | 'top.a');
};

Result
vrst-tool> sys.m()
(x | 'top.a') = 0xfff7

Example 3
extend sys {
m() is {
var x: uint = 0xff03;
var y: uint = 0x70f6;
print (x ^ y);
};
};

Result
vrst-tool> sys.m()
(x ^ y) = 0x8ff5

e Language Reference 2-41


e Basics
>> <<

See Also
• “'HDL-pathname'” on page 17-65
• “Scalar Types” on page 3-2

2.6.3 >> <<

Purpose
Shift bits left or right

Category
Expression

Syntax
exp1 operator exp2

Syntax Example
outf("%x\n", x >> 4);

Parameters

exp1 A numeric expression or an HDL pathname.

operator is one of the following:

<< Performs a shift-left operation.

>> Performs a shift-right operation.

exp2 A numeric expression.

Description
Shifts each bit of the first expression to the right or to the left the number of bits specified by the second
expression.

In a shift-right operation, the shifted bits on the right are lost, while on the left they are filled with 1, if
the first expression is a negative integer, or 0, in all other cases.

2-42 e Language Reference


e Basics
>> <<

In a shift-left operation, the shifted bits on the left are lost, while on the right they are filled with 0.

If the second expression is greater than 31 (more than 5 bits), it is first truncated to 5 bits, and then the
shift is performed. Truncation removes the most significant bits. For example, a shift-left, where the
second expression is 32 or 64, is equivalent to a shift 0.

Note
The result of a shift by more than 31 bits is undefined.

Example 4
m() is {
var x: int = 0x8fff0011;
outf("%x\n", x >> 4);
var y: uint = 0x8fff0011;
outf("%b\n", y >> 4);
};

Result
vrst-tool> sys.m()
f8fff001
1000111111111111000000000001

Example 5
m() is {
'top.a' = 0x8fff0011;
outf("%x\n", 'top.a' << 4);
};

Result
vrst-tool> sys.m()
fff00110

See Also
• “'HDL-pathname'” on page 17-65
• “Scalar Types” on page 3-2

e Language Reference 2-43


e Basics
Boolean Operators

2.7 Boolean Operators


The following sections describe the e Boolean operators:

! (not) on page 2-44 Returns TRUE when an expression evaluates to


FALSE, and vice versa.
&& (and) on page 2-45 Returns TRUE if two expressions are both TRUE.
|| (or) on page 2-46 Returns TRUE if one of two expressions is TRUE.
=> on page 2-48 Returns TRUE when the first expression of two
expressions is FALSE, or when both expressions are
TRUE.
now on page 2-49 Returns TRUE if an event has occurred in the current
cycle.

2.7.1 ! (not)

Purpose
Boolean not operation

Category
Expression

Syntax
!exp

not exp

Syntax Example
out(!(3 > 2));

Parameters

exp A Boolean expression or an HDL pathname.

2-44 e Language Reference


e Basics
&& (and)

Description
Returns FALSE when the expression evaluates to TRUE and returns TRUE when the expression
evaluates to FALSE.

Example
m() is {
'top.a' = 3;
out(!('top.a' > 2));
out(not FALSE);
};

Result
vrst-tool> sys.m()
FALSE
TRUE

See Also
• “'HDL-pathname'” on page 17-65
• “Scalar Types” on page 3-2

2.7.2 && (and)

Purpose
Boolean and

Category
Expression

Syntax
exp1 && exp2

exp1 and exp2

Syntax Example
if (2 > 1) and (3 > 2) then {

e Language Reference 2-45


e Basics
|| (or)

out("3 > 2 > 1");


};

Parameters

exp1, exp2 A Boolean expression or an HDL pathname.

Description
Returns TRUE if both expressions evaluate to TRUE; otherwise, returns FALSE.

Example
m() is {
'top.a' = 3;
'top.b' = 2;
if ('top.b' > 1) and ('top.a' > 2) then {
out("'top.a' > 'top.b' > 1");
};
};

Result
vrst-tool> sys.m()
'top.a' > 'top.b' > 1

See Also
• “'HDL-pathname'” on page 17-65
• “Scalar Types” on page 3-2

2.7.3 || (or)

Purpose
Boolean or

Category
Expression

2-46 e Language Reference


e Basics
|| (or)

Syntax
exp1 || exp2

exp1 or exp2

Syntax Example
if FALSE || ('top.a' > 1) then {
out("'top.a' > 1");
};

Parameters

exp1, exp2 A Boolean expression or an HDL pathname.

Description
Returns TRUE if one or both expressions evaluate to TRUE; otherwise, returns FALSE.

Example
m() is {
'top.a' = 3;
if FALSE || ('top.a' > 1) then {
out("'top.a' > 1");
};
};

Result
vrst-tool> sys.m()
'top.a' > 1

See Also
• “'HDL-pathname'” on page 17-65
• “Scalar Types” on page 3-2

e Language Reference 2-47


e Basics
=>

2.7.4 =>

Purpose
Boolean implication

Category
Expression

Syntax
exp1 => exp2

Syntax Example
out((2 > 1) => (3 > 2));

Parameters

exp1, exp2 A Boolean expression.

Description
The expression returns TRUE when the first expression is FALSE, or when the second expression is
TRUE. This construct is the same as:
(not exp1) or (exp2)

Example
m() is {
out((2 > 1) => (3 > 2));
out((1 > 2) => (3 > 2));
out((2 > 1) => (2 > 3));
};

Result
vrst-tool> sys.m()
TRUE
TRUE
FALSE

2-48 e Language Reference


e Basics
now

See Also
• constraint-bool-exp on page 11-50
• “Scalar Types” on page 3-2

2.7.5 now

Purpose
Boolean event check

Category
Boolean expression

Syntax
now @event-name

Syntax Example
if now @sys.tx_set then {out("sys.tx_set occurred");};

Parameter

event-name The event to be checked.

Description
Evaluates to TRUE if the event occurs before the now expression is encountered, in the same cycle in
which the now expression is encountered.

However, if the event is consumed later during the same cycle, the now expression changes to FALSE.
This means that the event can be missed, if it succeeds after the expression is encountered.

Example 1
In the following, the sys.tx_set event is checked when the if action is encountered. If the sys.tx_set event
has already occurred, in the same sys.clk cycle, the out() routine is called.
struct pkt {
event clk is @sys.any;

e Language Reference 2-49


e Basics
Arithmetic Operators

tcm_exa()@clk is {
if now @sys.tx_set then {out("sys.tx_set occurred");};
};
run() is also {
start tcm_exa();
};
};

Example 2
In this example, the now expression is FALSE until the tx_set event is emitted, which changes the
expression to TRUE. When the event is consumed by “sync consume (@tx_set)”, the now expression
changes back to FALSE.
struct pkt {
event tx_set;
tcm_exa()@sys.any is {
print now @tx_set;
emit tx_set;
print now @tx_set;
sync consume (@tx_set);
print now @tx_set;
};
run() is also {
start tcm_exa();
};
};
extend sys {
p_i: pkt;
};

See Also
• Chapter 12 “Events”
• “Scalar Types” on page 3-2

2.8 Arithmetic Operators


The following sections describe the e arithmetic operators:

Unary + - on page 2-51 Perform arithmetic operations on a single operand.


+ - * / % on page 2-52 Perform arithmetic operations on two operands.

2-50 e Language Reference


e Basics
Unary + -

2.8.1 Unary + -

Purpose
Unary plus and minus

Category
Expression

Syntax
-exp

+exp

Syntax Example
out(5," == ", +5);

Parameter

exp A numeric expression or an HDL pathname.

Description
Performs a unary plus or minus of the expression. The minus operation changes a positive integer to a
negative one, and a negative integer to a positive one. The plus operation leaves the expression
unchanged.

Example 1
m() is {
out(5," == ", +5);
};

Result
vrst-tool> sys.m()
0x5 == 0x5

e Language Reference 2-51


e Basics
+-*/%

Example 2
m() is {
var x: int = 3;
print -x;
print -(-x);
};

Result
vrst-tool> sys.m()
-x = -3
-(-x) = 3

See Also
• “'HDL-pathname'” on page 17-65
• “Scalar Types” on page 3-2

2.8.2 +-*/%

Purpose
Binary arithmetic

Category
Expression

Syntax
exp1 operator exp2

Syntax Example
out(10 + 5);

Parameters

exp1, exp2 A numeric expression or an HDL pathname.

operator is one of the following:

2-52 e Language Reference


e Basics
+-*/%

+ Performs addition.

- Performs subtraction.

* Performs multiplication.

/ Performs division and returns the quotient, rounded down.

% Performs division and returns the remainder.

Description
Performs binary arithmetic operations.

Example 1
m() is {
out(4 * -5);
};

Result
vrst-tool> sys.m()
0xffffffec

Example 2
m() is {
out(21 / 7);
out(27 / 7);
};

Result
vrst-tool> sys.m()
0x3
0x3

Example 3
m() is {
out(23 % 7);
};

e Language Reference 2-53


e Basics
Comparison Operators

Result
vrst-tool> sys.m()
0x2

See Also
• “'HDL-pathname'” on page 17-65
• “Scalar Types” on page 3-2
• “Arithmetic Routines” on page 24-13

2.9 Comparison Operators


The following sections describe the e comparison operators:

< <= > >= on page 2-54 Compares two numeric expressions or HDL pathnames.
== != on page 2-56 Determines whether two expressions are equal or not.
=== !== on page 2-58 Performs a 4-state, Verilog-style comparison of HDL objects.
~ !~ on page 2-60 Determines whether two string expressions are equal or not.
in on page 2-62 Determines whether an expression is in a list or a range.

2.9.1 < <= > >=

Purpose
Comparison of values

Category
Expression

Syntax
exp1 operator exp2

Syntax Example
print 'top.a' >= 2;

2-54 e Language Reference


e Basics
< <= > >=

Parameters

exp1, exp2 A numeric expression, or an HDL pathname.

operator is one of the following:

< Returns TRUE if the first expression is smaller than the second
expression.

<= Returns TRUE if the first expression is not larger than the second
expression.

> Returns TRUE if the first expression is larger than the second
expression.

>= Returns TRUE if the first expression is not smaller than the second
expression.

Description
Compares two expressions.

Example
m() is {
'top.a' = 3;
print 'top.a' >= 2;
};

Result
vrst-tool> sys.m()
'top.a' >= 2 = TRUE

See Also
• “'HDL-pathname'” on page 17-65
• “Scalar Types” on page 3-2

e Language Reference 2-55


e Basics
== !=

2.9.2 == !=

Purpose
Equality of values

Category
Expression

Syntax
exp1 operator exp2

Syntax Example
print lob1 == lob2;
print p1 != p2;

Parameters

exp1, exp2 A numeric, Boolean, string, list, or struct expression.

operator is one of the following

== Returns TRUE if the first expression evaluates to the same value as the
second expression.

!= Returns TRUE if the first expression does not evaluate to the same
value as the second expression.

Description
The equality operators compare the items and return a Boolean result. All types of items are compared
by value, except for structs which are compared by address. Comparison methods for the various data
types are listed in Table 2-7.

Table 2-7 Equality Comparisons for Various Data Types

Type Comparison Method

integers, unsigned integers, Values are compared.


Boolean values, HDL pathnames

2-56 e Language Reference


e Basics
== !=

Table 2-7 Equality Comparisons for Various Data Types

Type Comparison Method

strings The strings are compared character by character.

lists The lists are compared item by item.

structs The structs addresses are compared

Notes
• Enumerated type values can be compared as long as they are of the same type.
• Do not use these operators to compare a string to a regular expression. Use the ~ or the !~ operator
instead.
• See === !== on page 2-58 for a description of using this operator with HDL pathnames.

Example
extend sys {
p1: packet;
p2: packet;

m() is {
var s: string = "/rtests/tmp";
var b: bool = TRUE;
var lob1: list of byte = {0xaa; 0xbb; 0xcc; 0xdd};
var lob2: list of byte = lob1;

print s == "/rtests/tmp";
print b != FALSE;
print lob1 == lob2;
print p1 != p2;
};
};

Result
vrst-tool> sys.m()
s == "/rtests/tmp" = TRUE
b != FALSE = TRUE
lob1 == lob2 = TRUE
p1 != p2 = TRUE

e Language Reference 2-57


e Basics
=== !==

See Also
• === !== on page 2-58
• ~ !~ on page 2-60
• “'HDL-pathname'” on page 17-65
• “Scalar Types” on page 3-2

2.9.3 === !==

Purpose
Verilog-style four-state comparison operators

Category
Expression

Syntax
'HDL-pathname' [!== | ===] exp

exp [!== | ===] 'HDL-pathname'

Syntax Example
print 'TOP.reg_a' === 4'b1100;

Parameters

HDL-pathname The full path name of an HDL object, optionally including expressions and
composite data. See “'HDL-pathname'” on page 17-65 for more information.

=== Determines identity, as in Verilog. Returns TRUE if the left and right operands
have identical values, considering also the x and z values.

!== Determines non-identity, as in Verilog. TRUE if the left and right operands
differ in at least 1 bit, considering also the x and z values.

== Returns TRUE if after translating all x values to 0 and all z values to 1, the left
and right operands are equal.

2-58 e Language Reference


e Basics
=== !==

!= Returns TRUE if after translating all x values to 0 and all z values to 1, the left
and right operands are non-equal.

exp Either a literal with four-state values, a numeric expression, or another HDL
pathname.

Description
Compares four-state values (0, 1, x and z) with the identity and non-identity operators (Verilog style
operators). Alternatively, you can use the regular equal and non-equal operators. (A description of the
regular identity and non-identity operators is included in “Parameters” on page 2-58, for clarity.)

There are three ways to use the identity (===) and non-identity (!==) operators:

• 'HDL-pathname' = = = literal-number-with-x-and-z values


This expression compares a HDL object to a literal number (for example 'top.reg' === 4'b11z0). It
checks that the bits of the HDL object match the literal number, bit by bit (considering all four
values 0, 1, x, z).
• 'HDL-pathname' = = = number-exp
This expression evaluates to TRUE if the HDL object is identical in each bit value to the integer
expression number-exp. Integer expressions in e cannot hold x and z values; thus the whole
expression can be true only if the HDL object has no x or z bits and is otherwise equal to the integer
expression.
• 'HDL-pathname' = = = 'second-HDL-pathname'
This expression evaluates to TRUE if the two HDL objects are identical in all their bits (considering
all four values 0, 1, x, z).

Example 1
In Specman as in Verilog, if the radix is not binary, the z and x values in a literal number are interpreted
as more than one bit wide and are left-extended when they are the left-most literal. The width they
assume depends on the radix. For example, in hexadecimal radix, each literal z counts as four z bits.

Thus the value assigned in the following statement is 20'bxxxx_xxxx_zzzz_0000_0001.


'x.signal[19:0]' = 20'hxz01;

Because z is evaluated as 1 and x as 0 in ordinary expressions, the value printed by the following
statement is 0000_0000_1111_0000_0001.
print 'x.signal';

e Language Reference 2-59


e Basics
~ !~

Because x is evaluated as 1 and other values as 0 in expressions with @x, the value printed by the
following statement is 1111_1111_0000_0000_0000.
print 'x.signal@x';

Because z is evaluated as 1 and other values as 0 in expressions with @z, the value printed by the
following statement is 0000_0000_1111_0000_0000.
print 'x.signal@z';

Example 2
In the following example, both comparisons evaluate to TRUE.
'TOP.reg_a' = 4'b1100;
wait cycle;
print 'TOP.reg_a' === 4'b1100;
print 'TOP.reg_a' === 0xC;

Example 3
This example shows how to test a single bit to determine its current state.
case {
'TOP.write_en' === 1'b0: {out("write_en is 0");};
'TOP.write_en' === 1'b1: {out("write_en is 1");};
'TOP.write_en' === 1'bx: {out("write_en is x");};
'TOP.write_en' === 1'bz: {out("write_en is z");};
};

See Also
• “'HDL-pathname'” on page 17-65
• “Scalar Types” on page 3-2

2.9.4 ~ !~

Purpose
String matching

Category
Expression

2-60 e Language Reference


e Basics
~ !~

Syntax
“string” operator “pattern-string”

Syntax Example
print s ~ "blue*";
print s !~ "/^Bl.*d$/";

Parameters

string A legal e string.

operator is one of the following:

~ Returns TRUE if the pattern string can be matched to the whole string.

!~ Returns TRUE if the pattern string cannot be matched to the whole string.

pattern-string Either an AWK-style regular expression or a native Specman regular expression.


If the pattern string starts and ends with slashes, then everything inside the slashes
is treated as an AWK-style regular expression. See “String Matching” on page
2-65 for more information.

Description
Matches a string against a pattern. There are two styles of string matching: native Specman style, which
is the default, and AWK-style.

After a match using either of the two styles, a local pseudo-variable $0 holds the whole matched string,
and the pseudo-variables $1, $2,…$27 hold the sub strings matched. The pseudo-variables are set only
by the ~ operator and are local to the function that does the string match. If the ~ operator produces
fewer than 28 substrings, then the unneeded variables are left empty.

Example 1
The first two patterns use Specman style; the next two use AWK.
m() is {
var s: string = "BlueBird";

print s ~ "Blue*";
print s ~ "blue*";
print s ~ "/^Bl.*d$/";
print s ~ "/^bl.*d$/";
};

e Language Reference 2-61


e Basics
in

Result
vrst-tool> sys.m()
s ~ "Blue*" = TRUE
s ~ "blue*" = TRUE
s ~ "/^Bl.*d$/" = TRUE
s ~ "/^bl.*d$/" = FALSE

Example 2
The first pattern uses Specman style; the next uses AWK.
m() is {
var s: string = "BlueBird";

print s !~ "blue*";
print s !~ "/^Bl.*d$/";
};

Result
vrst-tool> sys.m()
s !~ "blue*" = FALSE
s !~ "/^Bl.*d$/" = FALSE

See Also
• “The string Type” on page 3-15

2.9.5 in

Purpose
Check for value in a list or specify a range for a constraint.

Category
Expression

Syntax
exp1 in list

2-62 e Language Reference


e Basics
in

exp1 in range_list

Syntax Example
keep x in [1..5];
check that x in {1;2;3;4;5};

Parameters

exp1 When used with a list, in a check, for example, then the exp1 type can be one of the
following:
• A type that is comparable to the element type of the list.
• A list of type that is comparable to the element type of the list.
When used with a range list, in a keep constraint, for example, then the exp1 type must be
of a type comparable to the type of the range list.

list A list. For a list, curly braces are used.

range_list A range list is a list of constants or expressions that evaluate to constants. Expressions that
use variables or struct fields cannot appear in range lists. For a range list, square brackets
are used.

Description
• For a check, evaluates TRUE if the first expression is included or contained in the list or range list.
• For a constraint, designates the range for the first expression.

Example 1
This example checks to make sure that a variable is generated correctly by confirming that its value is in
a list of values.
extend sys {
x: int (bits: 64);
keep x in [1..5];

run() is also {
check that x in {1;2;3;4;5};
};
};

e Language Reference 2-63


e Basics
in

Example 2
This example illustrates the use of in with square brackets, [], to designate a range of values for a
constraint.
type pm_type: [PC_A, PC_B, PC_C, MM_A, MM_B];
extend sys {
pm: pm_type;
keep pm in [PC_A, PC_B, PC_C];
};

Example 3
When two lists are compared and the first one has more than one repetition of the same value (for
example, in {1;2;1}, 1 is repeated twice), then at least the same number of repetitions has to exist in the
second list for the operator to succeed.

In this example, the list y is constrained to have 0 or 2 elements. The first check makes sure that y
contains 0 to 2 instances of the numbers 0, 1, 2, and 3. An error is issued for the second check.
<'
extend sys {
y: list of uint (bits: 2);
keep y.size() in {0;2};

run() is also {
check that y in {0;0;1;1;2;2;3;3};
check that {1;1;2} in {1;2;3;4};
};
};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
*** Error: Dut error at time 0
Checked at line 12 in basics66.e (sys.run):
check that {1;1;2} in {1;2;3;4}

2-64 e Language Reference


e Basics
String Matching

Example 4
This example illustrates that the order of the list items does not influence the result of the comparison.
No error is issued.
<'
extend sys {
run() is also {
check that {1;2;3} in {3;2;1};
check that {1;1;2} in {1;2;1;2};
};
};
'>

See Also
• “List Types” on page 3-13
• [ range,...] on page 2-83

2.10 String Matching


There are two styles of string matching: native Specman style, which is the default, and an AWK-like
style. If the pattern starts and ends with slashes, then everything inside the slashes is treated as an
AWK-style regular expression.

The following sections describe these two styles of string matching:

• “Native Specman String Matching” on page 2-65


• “AWK-Style String Matching” on page 2-67

See Also
• “List Types” on page 3-13
• “String Routines” on page 24-28

2.10.1 Native Specman String Matching


Specman string matching is attempted on all patterns that are not enclosed in slashes. Specman style is
similar to UNIX filename matching.

Native string matching uses the meta-characters shown in the following table.

e Language Reference 2-65


e Basics
Native Specman String Matching

Table 2-8 Meta-Characters in Native String Matching

Character String Meaning

" " (blank) Any sequence of white space (blanks and tabs)

* Any sequence of non-white space characters, possibly empty


(""). "a*" matches "a", "ab", and "abc", but not "ab c".

… Any sequence of characters

Native style string matching always matches the full string to the pattern. For example: r does not match
Bluebird, but *r* does.

A successful match results in assigning the local pseudo-variables $1 to $27 with the substrings
corresponding to the non-blank meta-characters present in the pattern.

Native style string matching is case-insensitive.

Example
m() is {
var x := "pp kkk";
print x ~ "* *";
print $1; print $2;
print x ~ "…";
print $1;
};

Result
vrst-tool> sys.m()
x ~ "* *" = TRUE
$1 = "pp"
$2 = "kkk"
x ~ "..." = TRUE
$1 = "pp kkk"

See Also
• “AWK-Style String Matching” on page 2-67
• “The string Type” on page 3-15
• “String Routines” on page 24-28

2-66 e Language Reference


e Basics
AWK-Style String Matching

2.10.2 AWK-Style String Matching


In an AWK-style string matching you can use the standard AWK regular expression notation to write
complex patterns. This notation uses the “/…/” format for the pattern to specify AWK-style regular
expression syntax.

AWK style supports special characters such as . * [ \ ^ $ +? <>, when those characters are used in the
same ways as in UNIX regular expressions (regexp).

The + and ? characters can be used in the same ways as in UNIX extended regular expression (egrep).

In AWK-style regular expressions, you can also use the following Perl shorthand notations, each
representing a single character.

Table 2-9 Perl-Style Regular Expressions Supported

Shorthand Notation Meaning

` A shortest match operator: ` (back tick).

\d Digit: [0-9]

\D Non-digit

\s Any white-space single char

\S Any non-white-space single

\w Word char: [a-zA-Z0-9_]

\W Non-word char

After doing a match, you can use the local pseudo-variables $1, $2…$27, which correspond to the
parenthesized pieces of the match. $0 stores the whole matched piece of the string.

Example 1
m() is {
var x := "pp--kkk";
print (x ~ "/--/");
print (x ~ "/^pp--kkk$/");
};

Result
vrst-tool> sys.m()
x ~ "/--/" = TRUE

e Language Reference 2-67


e Basics
AWK-Style String Matching

x ~ "/^pp--kkk$/" = TRUE

Example 2
AWK-style matching is longest match. Specman supports also a shortest match operator: ` (back tick).
The pattern “/x.`y/” matches the minimal such substring.
m() is {
var s := "x x y y";
print s ~ "/x(.‘)y/"; // Prints TRUE
print $1; // Prints " x " Matches x x y
print s ~ "/x(.*)y/"; // Prints TRUE
print $1; // Prints " x y "Matches x x y y
};

Result
vrst-tool> sys.m()
s ~ "/x(.‘)y/" = TRUE
$1 = " x "
s ~ "/x(.*)y/" = TRUE
$1 = " x y "

Example 3
After doing a match, you can use the local pseudo-variables $1, $2…$27, which correspond to the
parenthesized pieces of the match. For instance:
m() is {
var x := "pp--kkk";
if x ~ "/^(p*)--(k*)$/" then {print $1, $2;};
};

Result
vrst-tool> sys.m()
$1 = "pp"
$2 = "kkk"

See Also
• “Native Specman String Matching” on page 2-65
• “The string Type” on page 3-15
• “String Routines” on page 24-28

2-68 e Language Reference


e Basics
Extraction and Concatenation Operators

2.11 Extraction and Concatenation Operators


The following sections describe the e extraction and concatenation operators:

[ ] on page 2-69 Extracts or sets a single item from a list.


[ : ] on page 2-70 Extracts or sets consecutive bits or slices of a scalar, a list of bits, or
a list of bytes.
[ .. ] on page 2-75 List slicing operator
[ range,...] on page 2-83 Range list operator
{… ; …} on page 2-77 List concatenation
%{… , …} on page 2-79 Bit concatenation

2.11.1 []

Purpose
List index operator

Category
Expression

Syntax
list-exp[exp]

Syntax Example
ints[size] = 8;

Parameters

list-exp An expression that returns a list.

exp A numeric expression.

Description
Extracts or sets a single item from a list.

e Language Reference 2-69


e Basics
[:]

Notes
• Indexing is only allowed for lists. To get a single bit from a scalar, use bit extraction. See [ : ] on page
2-70.

• Checking list boundaries to see if the specified element exists is done only in interpretive mode.

Example
<'
extend sys {
packets[7]: list of packet;
ints[15]: list of int;
size: int [0..15];
m() is {
print packets[5];
ints[size] = 8;
print ints[size];
};
};
'>

Result
vrst-tool> sys.m()
packets[5] = packet-@0: packet
---------------------------------------------- @basics69
0 protocol: atm
1 len: 1
2 data: (1 items)
ints[size] = 8

See Also
• “List Types” on page 3-13
• Chapter 23 “List Pseudo-Methods”

2.11.2 [:]

Purpose
Select bits or bit slices of an expression

2-70 e Language Reference


e Basics
[:]

Category
Expression

Syntax
exp[[high-exp]:[low-exp][:slice]]

Syntax Example
print u[15:0] using hex;

Parameters

exp A numeric expression, an HDL pathname, or an expression returning a list of bit or a


list of byte.

high-exp A non-negative numeric expression. The high expression has to be greater than or
equal to the low expression. To extract a single slice, use the same expression for both
the high expression and the low expression.

low-exp A non-negative numeric expression, less than or equal to the high expression.

slice A numeric expression. The default is bit.

Description
Extracts or sets consecutive bits or slices of a scalar, a list of bits, or a list of bytes.

When used on the left-hand-side of an assignment operator, the bit extract operator sets the specified bits
of a scalar, a list of bits, or a list of bytes to the value on the right-hand-side (RHS) of the operator. The
RHS value is chopped or zero/sign extended, if needed.

When used in any context except the left-hand-side of an assignment operator, the bit extract operator
extracts the specified bits of a scalar, a list of bits, or a list of bytes.

Slice and Size of the Result


The slice parameter affects the size of the slice that is set or extracted. With the default slice (bit), the bit
extract operator always operates on a 1-bit slice of the expression. When extracting from a scalar
expression, by default the bit extract operator returns an expression that is the same type and size as the
scalar expression. When extracting from a list of bit or a list of byte, by default the result is a positive
unbounded integer.

e Language Reference 2-71


e Basics
[:]

By specifying a different slice (byte, int, or uint), you can cause the bit operator to operate on a larger
number of bits.

For example, the first print statement displays the lower two bytes of big_i, 4096. The second print
statement displays the higher 32-bit slice of big_i, -61440.
var big_i: int (bits: 64) = 0xffff1000ffff1000;
print big_i[1:0:byte];
print big_i[1:1:int];

Result
big_i[1:0:byte] = 0x0000000000001000
big_i[1:1:int] = 0xffffffffffff1000

Accessing Nonexistent Bits


If the expression is a numeric expression or an HDL pathname, any reference to a non-existent bit is an
error. However, for unbounded integers, all bits logically exist and will be 0 for positive numbers, 1 for
negative numbers. It is an error to extract nonexisting bits from list items. When setting non-existing bits
in list items, new zero items are added.

Notes
• The [high : low] order of the bit extract operator is the opposite of [low.. high] order of the list extract
operator.
• The bit extract operator has a special behavior in packing. Packing the result of a bit extraction uses
the exact size in bits (high - low + 1). The size of this pack expression is (5 - 3 + 1) + (i - 3 + 1).
pack(packing.low, A[5:3], B[i:3]);

Example 1
This is a simple example showing how to extract and set the bits in an unsigned integer.
var x : uint = 0x8000_0a60;
print x[11:4];
print x[31:31];
x[3:0] = 0x7;
print x;
x[2:1:byte] = 0x1234;
print x;

2-72 e Language Reference


e Basics
[:]

Result
x[11:4] = 0xa6
x[31:31] = 0x1
x = 0x80000a67
x = 0x80123467

Example 2
This example shows how to extract and set the bits in a list of bit.
var y : list of bit = {0;1;0;1;1;0;1;0;0;0;0};
print y using bin;
print y[6:1] using bin;
y[6:1] = 0xff;
print y using bin;
var x : uint = y[:];
print x using hex;

Result
y = (11 items, bin):
0 0 0 0 1 0 1 1 0 1 0 .0

y[6:1] = 0b101101
y = (11 items, bin):
0 0 0 0 1 1 1 1 1 1 0 .0

x = 0x7e

Example 3
This example shows how to extract and set the bits in a list of byte.
var z : list of byte = {0x12;0x34;0x56};
print z;
print z[1:0];
print z[1:0:byte];
z[2:2:byte] = 0x48;
print z;

Result
z = (3 items, hex):
56 34 12 .0

z[1:0] = 0x2

e Language Reference 2-73


e Basics
[:]

z[1:0:byte] = 0x3412
z = (3 items, hex):
48 34 12 .0

Example 4
This example shows how to use variables in the bit extract operator.
var x : uint = 0x80065000;
var i : uint = 16;
var j : uint = 4;
print x[i+j:i-j] using hex;

Result
x[i+j:i-j] = 0x65

Example 5
This example shows how to use variables in the bit extract operator. “r” will be an unbounded integer
containing 32 bits, extracted starting from byte 1 of the list of bit.
var lob : list of bit;
gen lob keeping {.size() < 128};
print lob;
var i : uint = 1;
var r:= lob[i+3:i:byte];
print r using bin;

Result
lob = (40 items, hex):
1 0 1 1 1 0 0 1 0 1 1 1 1 0 1 1 1 0 0 0 0 0 0 1 .0
1 0 1 0 0 1 0 1 1 0 0 1 1 1 0 0 .24

r = 0b0000000010100101100111001011100101111011

See Also
• “Bit Slice Operator and Packing” on page 18-24
• “'HDL-pathname'” on page 17-65
• “List Types” on page 3-13
• “Scalar Types” on page 3-2

2-74 e Language Reference


e Basics
[ .. ]

2.11.3 [ .. ]

Purpose
List slicing operator

Category
Expression

Syntax
exp[[low-exp]..[high-exp]]

Syntax Example
size: int [0..14];

Parameters

exp An expression returning a list or a scalar.

low-exp An expression evaluating to a positive integer. The default is 0.

high-exp An expression evaluating to a positive integer. The default is the expression size on
bits - 1.

Description
Accesses the specified list items and returns a list of the same type as the expression. If the expression is
a list of bit it returns a list of bit. If the expression is a scalar, it is implicitly converted to a list of bit.

The rules for the list slicing operator are as follows:

• A list slice of the form a[m..n] requires that n>=m>=0 and n<a.size(). The size of the slice in this
case is always n-m+1.
• A list slice of the form a[m..] requires that m>=0 and m<=a.size(). The size of the slice in this case
is always a.size()-m.
• When assigning to a slice the size of the rhs must be the same as the size of the slice, specifically
when the slice is of form a[m..] and m==a.size() then the rhs must be an empty list.

These rules are also true for the case of list slicing a numeric value, for example

e Language Reference 2-75


e Basics
[ .. ]

var i:int;
print i[m..n];
print i[m..];

This operator interprets the numeric value as a list of bits and returns the slice of that list. In the above
example, the first print is legal if n>=m>=0 and n<32 and the second is legal if m>=0 and m<=32.

Note
• This operator is not supported for unbounded integers.
• The only case where a list slice operation returns an empty list is in the case of a[m..] where
m==a.size().

Example 1
This example shows the use of the list slicing operator on a list of integers and a list of structs.
<'
struct packet {
protocol:[atm, eth];
len : int [0..10];
data[len]: list of byte;
};
extend sys {
packets[7]: list of packet;
ints[15]: list of int;
size: int [0..15];
m() is {
print packets[5..];
print ints[0..size];
};
};
'>

Result
packets[5..] =
item type protocol len data
---------------------------------------------------------------
0. packet atm 1 (1 items)
1. packet eth 5 (5 items)
ints[0..size] =
0. 2030699911
1. -419930323
2. -1597130501
3. -494877665

2-76 e Language Reference


e Basics
{… ; …}

4. -17370926
5. -1450077749
6. 1428017017
7. 2036356410
8. -1952412155
9. -259249691

Example 2
This example shows the use of the list slicing operator on a scalar expression and an HDL pathname.
<'
extend sys {
m() is {
var u : uint = 0xffffaaaa;
print u[..15];
'top.a' = 0xbbbbcccc;
print 'top.a'[..15];
};
};
'>

Result
u[..15] = (16 items, hex):
a a a a .0
'top.a'[..15] = (16 items, hex):
c c c c .0

See Also
• “'HDL-pathname'” on page 17-65
• “List Types” on page 3-13
• “Scalar Types” on page 3-2

2.11.4 {… ; …}

Purpose
List concatenation

e Language Reference 2-77


e Basics
{… ; …}

Syntax
{exp; ...}

Syntax Example
var x: list of uint = {1;2;3};

Category
Expression

Parameters

exp Any legal e expression, including a list. All expressions need to be


compatible with the result type.

Description
Returns a list built out of one or more elements or other lists. The result type is determined by the
following rules:

• The type is derived from the context. In the following example, the result type is a list of uint:
var x: list of uint = {1;2;3};

• The type is derived from the first element type of the list. In the following example, the result type
is a list of int 50 bits wide:
var y := {50'1; 2; 3};

Example
<'
type color:[red, orange, yellow, green, blue, purple];
extend sys {
m() is {
var los: list of string = {"abc";"def"};
var loc1: list of color = {red;green;blue};
var loc2:={color'purple;loc1};
print los;
print loc1;
print loc2;
};
};
'>

2-78 e Language Reference


e Basics
%{… , …}

Result
los =
0. "abc"
1. "def"
loc1 =
0. red
1. green
2. blue
loc2 =
0. purple
1. red
2. green
3. blue

See Also
• “List Types” on page 3-13

2.11.5 %{… , …}

Purpose
Bit concatenation operator

Category
Expression

Syntax
%{expr, …}

Syntax Example
num1 = %{num2, num3};
%{num2, num3} = num1;
%{int_list} = num4;

Parameters

expr Expression that resolves to an integer type or a list of integer types. You can enter one
or more expressions with the bit concatenation operator.

e Language Reference 2-79


e Basics
%{… , …}

Description
This description is presented in three parts:

• “When Used on the Righthand Side of an Assignment”


• “When Used on the Lefthand Side of an Assignment”
• “Return Value Type”
When Used on the Righthand Side of an Assignment

When used on the righthand side of an assignment, the bit concatenation operator creates a list from the
expression(s) entered by concatenating the expression values. This form is the same as
pack(packing_high,..): the most significant bit of the first physical field or lowest list item is placed at
the highest index in the resulting list of bit. In other words:

• value-exp = %{exp1, exp2,…} is equivalent to value-exp = pack(packing.high, exp1, exp2, ...).


For instance, as illustrated in the “Example” below, the following code:

num2 = 0x1234;
num3 = 0xabcd;
num1 = %{num2, num3};
print num1;

Results in:

num1 = 0x1234abcd

When Used on the Lefthand Side of an Assignment

When used on the lefthand side of an assignment, the bit concatenation operator unpacks the value of the
righthand side of the assignment into the expression(s) entered. This form is the same as
unpack(packing_high,..). In other words:

• %{exp1, exp2,…} = value-exp is equivalent to unpack(packing.high, value-exp, exp1, exp2, ...).


For instance, as illustrated in the “Example” below, the following code:

num1 = 0x98765432;
%{num2, num3} = num1;
print num2, num3;

Results in:

2-80 e Language Reference


e Basics
%{… , …}


num2 = 0x9876
num3 = 0x5432

The “Example” below also illustrates the use of the bit concatenation operator on one argument only:

num4 = 0x5432;
%{intlist} = num4;
print intlist;

Results in:
intlist = (4 items, hex):
2 3 4 5 .0

Return Value Type

The return value is implicitly cast to match the type of the variable or field that receives it. If there is no
receiving variable or field, the return value is a list of bit.

Note that bit concatenations are untyped expressions. See “Untyped Expressions” on page 3-17 for more
information.

Example
This example shows several uses of the bit concatenation operator.
extend sys {
post_generate() is also {
var num1 : uint (bits : 32);
var num2 : uint (bits : 16);
var num3 : uint (bits : 16);
var bilist : list of bit;
var bylist : list of byte;
var num4: int(bits: 16);
var intlist: list of int(bits: 4);

num2 = 0x1234;
num3 = 0xabcd;
num1 = %{num2, num3};
print num1;

num1 = 0x98765432;
%{num2, num3} = num1;
print num2, num3;
print %{num2, num3};

e Language Reference 2-81


e Basics
%{… , …}

bilist = %{num2, num3};


print bilist;
bylist = %{num2, num3};
print bylist;

num4 = 0x5432;
%{intlist} = num4;
print intlist;

};
};

Result
test
Doing setup ...
Generating the test using seed 0x1...
num1 = 0x1234abcd
num2 = 0x9876
num3 = 0x5432
% {num2, num3} = (32 items, hex):
9 8 7 6 5 4 3 2 .0
bilist = (32 items, hex):
9 8 7 6 5 4 3 2 .0
bylist = (4 items, hex):
98 76 54 32 .0
intlist = (4 items, hex):
2 3 4 5 .0

See Also
• “A Simple Example of Packing” on page 18-2
• “A Simple Example of Unpacking” on page 18-4
• pack() on page 18-27
• unpack() on page 18-31
• swap() on page 18-36
• do_pack() on page 18-38
• do_unpack() on page 18-42

2-82 e Language Reference


e Basics
Scalar Modifiers

2.12 Scalar Modifiers


You can create a scalar subtype by using a scalar modifier to specify the range or bit width of a scalar
type. The following sections describe the scalar modifiers:

• [ range,...] on page 2-83


• (bits | bytes : width-exp) on page 2-84

See Also
• “Scalar Types” on page 3-2
• type sized scalar on page 3-36
• type scalar subtype on page 3-34

2.12.1 [ range,...]

Purpose
Range modifier

Category
Range

Syntax
[range, ...]

Syntax Example
u: uint[5..7, 15];

Parameter

range Either a constant expression, or a range of constant expressions in the form


low-value..high-value
If the scalar type is an enumerated type, it is ordered by the value associated
with the integer value of each type item.

e Language Reference 2-83


e Basics
(bits | bytes : width-exp)

Description
Creates a scalar subtype by restricting the range of valid values.

Example 1
The following example shows how to limit the values of an enumerated type and a numeric type.
<'
type color:[red, orange, yellow, green, blue, purple];
extend sys {
bright: color[red..yellow];
u: uint[5..7, 15];
};
'>

Example 2
The following example shows how to specify a list of possible values in a keep constraint.
<'
type color:[red, orange, yellow, green, blue, purple];
extend sys {
bright: color;
keep bright in [red, orange, yellow];
};
'>

See Also
• “Scalar Subtypes” on page 3-3
• type scalar subtype on page 3-34

2.12.2 (bits | bytes : width-exp)

Purpose
Define a sized scalar

Category
Expression

2-84 e Language Reference


e Basics
Parentheses

Syntax
(bits|bytes: width-exp)

Syntax Example
type word :uint(bits:16);
type address :uint(bytes:2);

Parameter

width-exp A positive constant expression. The valid range of values for sized scalars is limited
to the range 1 to 2n - 1, where n is the number of bits or bytes.

Description
Defines a bit width for a scalar type. The actual bit width is exp * 1 for bits and exp * 8 for bytes. In the
syntax example shown above, both types “word” and “address” have a bit width of 16.

Example
type word :uint(bits:16);
type address :uint(bytes:2);

See Also
• “Scalar Types” on page 3-2
• type sized scalar on page 3-36

2.13 Parentheses
You can use parentheses freely to group terms in expressions, to improve the readability of the code.
Parentheses are used in this way in some examples in this manual, although they are not syntactically
required.

Parentheses are required in a few places in e code, such as at the end of the method or routine name in
all method definitions, method calls, or routine calls. Required parentheses are shown in boldface in the
syntax listings in this manual.

The following sections describe the contexts in which the parentheses are required to invoke a method,
pseudo-method, or routine:

• list-method() on page 2-86

e Language Reference 2-85


e Basics
list-method()

• “Calling C Routines from e” on page 11-19 in the Usage and Concepts Guide for e Testbenches
• “Calling Predefined Routines” on page 24-140
• “Invoking Methods” on page 7-22

2.13.1 list-method()

Purpose
Execute list pseudo-method

Category
Expression

Syntax
list-exp. list-method([param,]…)[.list-method([param,]…). ...]

Syntax Example
print me.my_list.is_empty();

Parameters

list-exp An expression that returns a list.

list-method One of the list pseudo-methods described in Chapter 23 “List Pseudo-Methods”

Description
Executes a list pseudo-method on the specified list expression, item by item. When an item is evaluated,
it stands for the item and index stands for its index in the list.

When a parameter is passed, that expression is evaluated for each item in the list.

Example 1
This example shows how to call two simple list pseudo-methods. The is_empty() list method returns a
Boolean, while size() returns an int.
<'

2-86 e Language Reference


e Basics
list-method()

extend sys {
my_list: list of int;

post_generate() is also {
print me.my_list.is_empty();
check that (me.my_list.size() > 5)
};
};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
me.my_list.is_empty() = FALSE
Starting the test ...
Running the test ...
No actual running requested.
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

Example 2
List method calls can be nested within any expression as long as the returned type matches the context.
The following example filters the list my_packets to include only the ethernet kind, sorts the result in
ascending order, and prints.
<'
struct packet {
kind: [ethernet, atm, other];
size: uint;
};

extend sys {
packets[10]: list of packet;

post_generate() is also {
print packets.all(.kind==ethernet).sort(.size);
};
};
'>

Result
vrst-tool> test

e Language Reference 2-87


e Basics
Special-Purpose Operators

Doing setup ...


Generating the test using seed 1...
packets.all(.kind==ethernet).sort(.size) =
item type kind size
---------------------------------------------------------------
0. packet ethernet 895996206
1. packet ethernet 960947360
2. packet ethernet 3889995846
Starting the test ...
Running the test ...
No actual running requested.
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

See Also
• Chapter 23 “List Pseudo-Methods”
• “Implicit Variables” on page 2-30

2.14 Special-Purpose Operators


Specman supports the following special purpose operators:

is [not] a on page 2-88 Identify the subtype of a struct instance


new on page 2-90 Allocate a new struct
. on page 2-93 Refer to fields in structs
' on page 2-95 Used in names of e entities
? : on page 2-96 Conditional operator

2.14.1 is [not] a

Purpose
Identify the subtype of a struct instance

Category
Boolean expression

2-88 e Language Reference


e Basics
is [not] a

Syntax
struct-exp is a subtype [(name)]

struct-exp is not a subtype

Syntax Example
if me is a long packet (l) {
print l;
};
if me is not a long packet {
print kind;
};

Parameters

struct-exp An expression that returns a struct.

subtype A subtype of the specified struct type.

name The name of the local variable you want to create. This parameter cannot be used
with is not a expressions.

Description
Identifies whether a struct instance is a particular subtype or not at run time.

If a name is specified, then a local temporary variable of that name is created in the scope of the action
containing the is a expression. This local variable contains the result of struct-exp.as_a(type) when the
is a expression returns TRUE.

Notes
• A compile time error results if there is no chance that the struct instance is of the specified type.
• Unlike other constructs with optional name variables, the implicit it variable is not created when the
optional name is not used in the is a expression.
• The name parameter cannot be used with is not a expressions.

Example
<'
type pack_kind :[long, short];
struct packet {

e Language Reference 2-89


e Basics
new

kind: pack_kind;
when long packet {
a: int;
};
check_my_type() is {
if me is a long packet (l) {
print l;
};
if me is not a long packet {
print kind;
};
};
};

extend sys {
p:packet;
};
'>

Result
vrst-tool> sys.p.check_my_type()
l = packet-@0: packet
---------------------------------------------- @expressions67
0 kind: long
1 long'a: -1786485835

See Also
• as_a() on page 3-40

2.14.2 new

Purpose
Allocate a new initialized struct

Category
Expression

2-90 e Language Reference


e Basics
new

Syntax
[a] new [struct-type [[(name)] with {action;...}]]

Syntax Example
var q : packet = new good large packet;

Parameters

struct-type Either a struct type or a struct subtype.

name An optional name, valid within the action block, for the new struct. If no name is
specified, you can use the implicit variable it to refer to the new struct.

action A list of one or more actions.

Description
Creates a new struct:

1. Allocates space for the struct.

2. Assigns default values to struct fields.

3. Invokes the init() method for the struct, which by default initializes all fields of scalar type, including
enumerated scalar type, to zero. The initial value of a struct or list is NULL, unless the list is a sized
list of scalars, in which case it is initialized to the proper size with each item set to the default value.

4. Invokes the run() method for the struct, unless the new expression is in a construct that is executed
before the run phase. For example, if you use new in an extension to sys.init(), then the run() method
is not invoked.

5. Executes the action-block, if one is specified.

If no subtype is specified, the type is derived from the context. For example, if the new struct is assigned
to a variable of type packet, the new struct will be of type packet.

If the optional with clause is used, you can refer to the newly created struct either with the implicit
variable it, or with an optional name.

Note
The new struct is a shallow struct. The fields of the struct that are of type struct are not allocated.

e Language Reference 2-91


e Basics
new

Example
<'
struct packet {
good : bool;
size : [small, medium, large];
length : int;
};
extend sys {
post_generate() is also {
var p : packet = new;
print p;
var q : packet = new good large packet;
print q;
var x := new packet (p) with {
p.length = 5;
print p;
};
};
};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
p = packet-@0: packet
---------------------------------------------- @expressions69
0 good: FALSE
1 size: small
2 length: 0
q = good large packet-@1: good large packet
---------------------------------------------- @expressions69
0 good: TRUE
1 size: large
2 length: 0
p = packet-@2: packet
---------------------------------------------- @expressions69
0 good: FALSE
1 size: small
2 length: 5
Starting the test ...
Running the test ...
No actual running requested.
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

2-92 e Language Reference


e Basics
.

See Also
• The init() Method of any_struct on page 22-27
• The run() Method of any_struct on page 22-39
• “Struct Subtypes” on page 3-8

2.14.3 .

Purpose
Refer to fields in structs

Category
Expression

Syntax
[[struct-exp].] field-name

Syntax Example
keep soft port.sender.cell.u == 0xff;

Parameters

struct-exp An expression that returns a struct.

field-name The name of the scalar field or list field to reference.

Description
Refers to a field in the specified struct. If the struct expression is missing, but the period exists, the
implicit variable it is assumed. If both the struct expression and the period (.) are missing, the field name
is resolved according to the name resolution rules.

Notes
• When the struct expression is a list of structs, the expression cannot appear on the left-hand side of
an assignment operator.

e Language Reference 2-93


e Basics
.

• When the field name is a list item, the expression returns a concatenation of the lists in the field.

Example 1
The following example shows the use of the “.” to identify the fields u and kind in the keep constraints:
<'
struct switch {
ctrl: ctrl_stub;
port: port_stub;

keep soft port.sender.cell.u == 0xff;


keep ctrl.init_command.kind == RD;
};
struct ctrl_stub {
init_command: ctrl_cmd;
};
struct simplex {
kind: [TX, RX];
cell: cell;
};
struct port_stub {
sender: TX simplex;
listener: RX simplex;
};
struct cell {
u: uint;
};
struct ctrl_cmd {
kind: [RD, WR];
addr: int;
};
extend sys {
switch : switch;
};
'>

Example 2
This example shows the effect of using the “.” to access the fields in a list (switch.port) and to access a
field that is a list (switch.port.data):
<'
struct switch {
port: list of port_stub;

keep soft port.size() == 4;

2-94 e Language Reference


e Basics
'

};

struct port_stub {
data[5]: list of byte;
};

extend sys {
switch : switch;

post_generate() is also {
print switch.port;
print switch.port.data;
};
};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
switch.port =
item type data
---------------------------------------------------------------
0. port_stub (5 items)
1. port_stub (5 items)
2. port_stub (5 items)
3. port_stub (5 items)
switch.port.data = (20 items, dec):
185 24 137 186 202 3 186 107 108 119 84 212 .0
129 224 56 145 3 252 61 58 .12

See Also
• “Struct Hierarchy and Name Resolution” on page 2-23

2.14.4 '

Apostrophes
The apostrophe (') is an important syntax element used in multiple ways in e source code. The actual
context of where it is used in the syntax defines its purpose. A single apostrophe is used in the following
places:

e Language Reference 2-95


e Basics
?:

• When accessing HDL objects (for example: 'top.a')


• When defining the name of a syntactic construct in a macro definition (for example:
show_time'command)
• When referring to struct subtypes (for example: b'dest Ethernet packet)
• When referring to an enumerated value not in context of an enumerated variable (for example:
color'green)
• In the begin-code marker <' and in the end-code marker '>

See Also
• “Reading and Writing HDL Objects” on page 8-21 in the Specman Elite Integrator’s Guide
• Chapter 19 “Macros”
• “Struct Subtypes” on page 3-8
• “Enumerated Type Values” on page 2-29
• “Code Segments” on page 2-2

2.14.5 ?:

Purpose
Conditional operator

Category
Expression

Syntax
bool-exp ? exp1 : exp2

Syntax Example
z = (flag ? 7 : 15);

2-96 e Language Reference


e Basics
?:

Parameters

bool-exp A legal e expression that evaluates to TRUE or FALSE.

exp1, exp2 A legal e expression.

Description
Evaluates one of two possible expressions, depending on whether a Boolean expression evaluates to
TRUE or FALSE. If the Boolean expression is TRUE, then the first expression is evaluated. If it is
FALSE, then the second expression is evaluated.

Example
<'
extend sys {
m() is {
var z: int;
var flag: bool;

z = (flag ? 7 : 15);
print flag, z;
};
};
'>

Result
flag = FALSE
z = 15

See Also
• “Conditional Actions” on page 9-1

e Language Reference 2-97


e Basics
?:

2-98 e Language Reference


3 Data Types
The e language has a number of predefined data types including the integer and Boolean scalar types
common to most programming languages. In addition, you can create new scalar data types (enumerated
types) that are appropriate for programming, modeling hardware, and interfacing with hardware
simulators. The e language also provides a powerful mechanism for defining object-oriented
hierarchical data structures (structs) and ordered collections of elements of the same type (lists).

This chapter contains the following topics:

• “e Data Types” on page 3-1


• “Memory Requirements for Data Types” on page 3-16
• “Untyped Expressions” on page 3-17
• “Assignment Rules” on page 3-19
• “Precision Rules for Numeric Operations” on page 3-24
• “Automatic Type Casting” on page 3-29
• “Constructs for Defining and Extending Scalar Types”
• “Additional Type-Related Constructs”

See Also
• Chapter 4 “Structs, Fields, and Subtypes”
• Chapter 2 “e Basics”

3.1 e Data Types


Most e expressions have an explicit data type. These data types are described in the following sections:

e Language Reference 3-1


Data Types
Scalar Types

• “Scalar Types” on page 3-2


• “Scalar Subtypes” on page 3-3
• “Enumerated Scalar Types” on page 3-5
• “Struct Types” on page 3-8
• “Struct Subtypes” on page 3-8
• “List Types” on page 3-13
• “The string Type” on page 3-15
• “The external_pointer Type” on page 3-16
Certain expressions, such as HDL objects, have no explicit data type. See “Untyped Expressions” on
page 3-17 for information on how Specman handles these expressions.

3.1.1 Scalar Types


Scalar types in e are one of the following:

• Numeric
• Boolean
• Enumerated
Table 3-1 on page 3-2 shows Specman predefined numeric and Boolean types. See the notes below the
table for important information about these predefined types.

Table 3-1 Specman Predefined Scalar Types

Default Size
Type Name Function for Packing Default Value

int Represents numeric data, both negative 32 bits 0


and non-negative integers.

uint Represents unsigned numeric data, 32 bits 0


non-negative integers only.

bit An unsigned integer in the range 0–1. 1 bit 0

nibble An unsigned integer in the range 0-15 4 0

byte An unsigned integer in the range 0–255. 8 bits 0

time An integer in the range 0–263-1. 64 bits 0

3-2 e Language Reference


Data Types
Scalar Subtypes

Table 3-1 Specman Predefined Scalar Types

Default Size
Type Name Function for Packing Default Value

bool Represents truth (logical) values, 1 bit FALSE (0)


TRUE(1) and FALSE (0).

Note Both signed and unsigned integers can be of any size and, thus, of any range. See “Scalar
Subtypes” on page 3-3 for information on how to specify the size and range of a scalar field or variable
explicitly.

See Also
• Predefined constants, described in Chapter 2 “e Basics”
• Constraint Boolean expressions, described in Chapter 2 “e Basics”

3.1.2 Scalar Subtypes


You can create a scalar subtype by using a scalar modifier to specify the range or bit width of a scalar
type. You can also specify a name for the scalar subtype if you plan to use it repeatedly in your program.
Infinite (unbounded) integers are a predefined scalar subtype.

This section contains the following:

• “Scalar Modifiers” on page 3-3


• “Named Scalar Subtypes” on page 3-4
• “Infinite (Unbounded) Integers” on page 3-4

3.1.2.1 Scalar Modifiers


There are two types of scalar modifiers that you can use together or separately to modify predefined
scalar types:

1. Range modifiers

2. Width modifiers

Range modifiers define the range of values that are valid. For example, the range modifier in the
expression below restricts valid values to those between zero and 100 inclusive.
int [0..100]

e Language Reference 3-3


Data Types
Scalar Subtypes

Width modifiers define the width in bits or bytes. The width modifiers in the expressions below restrict
the bit width to 8.
int (bits: 8)
int (bytes: 1)

You can use width and range modifiers in combination.


int [0..100] (bits: 7)

3.1.2.2 Named Scalar Subtypes


When you use a scalar modifier to limit the range or bit width of a scalar type, you can also specify a
name.

Named scalar subtypes are useful in a context where, for example, you need to declare a counter variable
like the variable “count” several places in the program.
var count : int [0..100] (bits:7);

By creating a named scalar type, you can use the type name when introducing new variables with this
type.
type int_count : int [0..99] (bits:7);
var count : int_count;

See type enumerated scalar on page 3-31 for more information on named scalar subtypes.

3.1.2.3 Infinite (Unbounded) Integers


Infinite integers represent arbitrarily large positive or negative numbers. Infinite integers are specified
as:
int (bits: *)

You can use an infinite integer variable when you do not know the exact size of the data. You can use
infinite integers in expressions just as you use signed or unsigned integers.

Notes
• Fields or variables declared as infinite integers cannot be generated, packed, or unpacked.
• Infinite unsigned integers are not allowed, so a declaration of a type such as “uint (bits:*)” generates
a compile-time error.

3-4 e Language Reference


Data Types
Enumerated Scalar Types

See Also
• type scalar subtype on page 3-34
• type sized scalar on page 3-36
• extend type on page 3-37

3.1.3 Enumerated Scalar Types


You can define the valid values for a variable or field as a list of symbolic constants. For example, the
following declaration defines the variable “kind” as having two legal values.
var kind: [immediate, register];

These symbolic constants have associated unsigned integer values. By default, the first name in the list
is assigned the value zero. Subsequent names are assigned values based upon the maximum value of the
previously defined enumerated items + 1. You can also assign explicit unsigned integer values to the
symbolic constants.
var kind: [immediate = 1, register = 2];

The associated unsigned integer value of a symbolic constant in an enumerated type can be obtained
using the .as_a() type casting operator. Similarly, an unsigned integer value that is within the range of
the values of the symbolic constants can be cast as the corresponding symbolic constant.

Casting an unsigned integer to a symbolic constant:


type signal_number: [signal_0, signal_1, signal_2, signal_3];
struct signal {
cast_1() is {
var temp_val: uint = 2;
var signal_name: signal_number = temp_val.as_a(signal_number);
print signal_name;
};
};

Casting a symbolic constant to an unsigned integer:


type signal_number: [signal_0, signal_1, signal_2, signal_3];
struct signal {
cast_2() is {
var temp_enum: signal_number = signal_3;
var signal_value: uint = temp_enum.as_a(uint);
print signal_value;
};
};

e Language Reference 3-5


Data Types
Enumerated Scalar Types

You can explicitly assign values to some symbolic constants and allow others to be automatically
assigned. The following declaration assigns the value 3 to “immediate”; Specman assigns the value 4 to
“register” automatically.
var kind: [immediate = 3, register];

You can name an enumerated type to facilitate its reuse throughout your program. For example, the first
statement below defines a new enumerated type named “instr_kind”. The variable “i_kind” has the two
legal values defined by the “instr_kind” type.
type instr_kind: [immediate, register];
var i_kind: instr_kind;

It is sometimes convenient to introduce a named enumerated type as an empty type.


type packet_protocol: [];

Once the protocols that are meaningful in the program are identified you can extend the definition of the
type with a statement like:
extend packet_protocol : [Ethernet, IEEE, foreign];

Enumerated types can be sized.


type instr_kind: [immediate, register] (bits: 2);

Variables or fields with an enumerated type can also be restricted to a range. This variable declaration
excludes “foreign” from its legal values:
var p :packet_protocol [Ethernet..IEEE];

The default value for an enumerated type is zero, even if zero is not a legal value for that type. For
example, the variable “i_kind” has the value zero until it is explicitly initialized or generated.
type instr_kind: [immediate = 1, register = 2];
var i_kind: instr_kind;

3.1.3.1 Casting of Enumerated Types in Comparisons


Enumerated scalar types, like Boolean types, are not automatically converted to or from integers or
unsigned integers in comparison operations (that is, comparisons using <, <=, >, >=, ==, or !=
operators). This is consistent with the strong typing in e, and helps avoid introduction of bugs if the
order of symbolic names in an enumerated type declaration is changed, for example, while operations
which are affected by the order of those names in the declaration remain unchanged (because they are in
a different part of the code and therefore go unnoticed, perhaps).

3-6 e Language Reference


Data Types
Enumerated Scalar Types

Assume that I is an int, B is a bool, and E is an enumerated type. Since enumerated and boolean types
are not automatically converted to or from integers or unsigned integers, you cannot use syntax such as
“if (I) {...}”, or “if (B==1) {...}”, or “if (E<6) {...}”. In order to perform such comparisons, you must use
explicit casting, or tick notation to specify the type. Examples of correct and incorrect syntax are shown
in the sample code below.
type my_enum: [A, B, C];
struct etypes {
x: my_enum;
my_method() is {

if (A.as_a(int) < B.as_a(int)) then { // Load-time error:


out("A is less than B"); // No such variable 'A'
};

if (A.as_a(int) == B.as_a(int)) then { // Load-time error:


out("A equals B"); // No such variable 'B'
};

if (my_enum'A.as_a(int) < my_enum'B.as_a(int)) then { // No error


out ("A less than B");
};

if (my_enum'A < my_enum'B) then { // Load-time error:


out ("A less than B"); // The type of 'x' is 'my_enum'
}; // while expecting a numeric type

if (x < A) then { // Load-time error:


out("x less than A"); // The type of 'x' is 'my_enum'
}; // while expecting a numeric type

if (x == A) then { // No error
out ("x equals A");
};
};
};

The first two if statements above cause load errors because it is possible for A or B or both to be used in
more than one enumerated type declaration, and it is not possible to tell from the context which type they
are, or their values. In the third if statement, the enumerated type is specified using the tick notation, so
that statement is legal. Note that it is still necessary to cast A and B as ints in order to do the comparison,
A < B, otherwise the error in the fourth case, my_enum’A < my_enum’B, occurs.

In the fifth case, x < A, the context of A is not clear at load time, so a loading error occurs. The context
of A is clear in the last case, x == A, however, so this code loads with no problem.

e Language Reference 3-7


Data Types
Struct Types

See Also
• type enumerated scalar on page 3-31
• extend type on page 3-37

3.1.4 Struct Types


Structs are the basis for constructing compound data structures.

The following statement creates a struct type called “packet” with a field “protocol” of type
“packet_protocol”.
struct packet {
protocol: packet_protocol;
};

You can then use the struct type “packet” in any context where a type is required. For example in this
statement, “packet” defines the type of a field in another struct.
struct port {
data_in : packet;
};

You can also define a variable using a struct type.


var data_in : packet;

The default value for a struct is NULL.

See Also
• Chapter 4 “Structs, Fields, and Subtypes”
• var on page 8-2

3.1.5 Struct Subtypes


When a struct field has a Boolean type or an enumerated type, you can define a struct subtype for one or
more of the possible values for that field. For example, the struct “packet” defined below has three
possible subtypes based on its “protocol” field. The “gen_eth_packet” method below generates an
instance of the “legal Ethernet packet” subtype, where legal == TRUE and protocol == Ethernet.
type packet_protocol: [Ethernet, IEEE, foreign];

struct packet {
protocol: packet_protocol;

3-8 e Language Reference


Data Types
Struct Subtypes

size: int [0..1k];


data[size]: list of byte;
legal: bool;
};
extend sys {
gen_eth_packet () is {
var packet: legal Ethernet packet;
gen packet keeping {it.size < 10;};
print packet;
};
};

This section contains the following:

• “Referring to a Struct Subtype” on page 3-9


• “Using extend, when, and like with Struct Subtypes” on page 3-11
• “Referring To Conditional Fields in when Constructs” on page 3-12

3.1.5.1 Referring to a Struct Subtype


To refer to a Boolean struct subtype, for example “legal packet”, use this syntax:
field_name struct_type

To refer to an enumerated struct subtype in a struct where no values are shared between the enumerated
types, you can use this syntax:
value_name struct_type

In structs where more than one enumerated field can have the same value, you must use “tick notation”
syntax as in the following to refer to the struct subtype:
value'field_name struct_type

For example, if we define two enumerated types:


type destination: [a, b, c, d];
type source: [a, b, c, d];

And add two fields to the “packet” struct:


dest: destination;
src: source;

The syntax for referring to the type of an Ethernet packet with the destination “b” is:
b'dest Ethernet packet

e Language Reference 3-9


Data Types
Struct Subtypes

because the name “b Ethernet packet” is ambiguous.


type packet_protocol: [Ethernet, IEEE, foreign];
type destination: [a, b, c, d];
type source: [a, b, c, d];

struct packet {
protocol: packet_protocol;
size: int [0..1k];
data[size]: list of byte;
legal: bool;
dest: destination;
src: source;
};
extend sys {
gen_eth_packet () is {
var packet: b'dest Ethernet packet;
gen packet keeping {it.size > 511 and it.size < 1k};
print packet;
};
};

The example below shows another context where a struct subtype can be used.
type packet_protocol: [Ethernet, IEEE, foreign];
type destination: [a, b, c, d];
type source: [a, b, c, d];

struct packet {
protocol: packet_protocol;
size: int [0..1k];
data[size]: list of byte;
legal: bool;
dest: destination;
src: source;
};
extend sys {
plist: list of packet;
print_Epackets() is {
for each Ethernet packet (ep) in plist {
print ep;
};
};
};

3-10 e Language Reference


Data Types
Struct Subtypes

3.1.5.2 Using extend, when, and like with Struct Subtypes


You can also use the extend, when, or like constructs to add fields, methods, or method extensions that
are required for a particular subtype.

For example, the extend construct shown below adds a field and a method to the “Ethernet packet”
subtype. The “Ethernet packet” subtype also inherits all the characteristics of the struct “packet”.
type packet_protocol: [Ethernet, IEEE, foreign];

struct packet {
protocol: packet_protocol;
size: int [0..1k];
data[size]: list of byte;

};

extend Ethernet packet {


e_field: int;

show() is {out("I am an Ethernet packet")};


};

The “Ethernet packet” subtype could also be defined with the when construct. The following “Ethernet
packet” subtype is exactly equivalent to the Ethernet packet subtype defined by extend.
type packet_protocol: [Ethernet, IEEE, foreign];

struct packet {
protocol: packet_protocol;
size: int [0..1k];
data[size]: list of byte;

when Ethernet packet {


e_field: int;

show() is {out("I am an Ethernet packet")};


};
};

You can use either the when or the extend construct to define struct subtypes with very similar results.
These constructs are appropriate for most modeling purposes. Under certain circumstances, you may
prefer to use the like construct to create struct subtypes. See Chapter 4 “Structs, Fields, and Subtypes”
for a detailed discussion of the use of these constructs to create struct subtypes.

e Language Reference 3-11


Data Types
Struct Subtypes

3.1.5.3 Referring To Conditional Fields in when Constructs


The example below shows how to refer to a field of a struct subtype outside of a when, like, or extend
construct by assigning a temporary name to the struct subtype.
type packet_protocol: [Ethernet, IEEE, foreign];

struct packet {
protocol: packet_protocol;
size: int [0..1k];
data[size]: list of byte;

keep me is a Ethernet packet (ep) => ep.e_field == 1;

when Ethernet packet {


e_field: int;

show() is {out("I am an Ethernet packet")};


};
};

In order to reference a field in a when construct, you must specify the appropriate value for the when
determinant. For example, consider the following struct and subtype:
type packet_protocol: [Ethernet, IEEE, foreign];
struct packet {
protocol: packet_protocol;
when IEEE packet {
i_val: int;
};
};

For any instance “pk_inst” of the packet struct, references to the “i_val” field are only valid if the when
determinant is “IEEE”. The following are three ways to ensure that “pk_inst” is in fact an “IEEE packet”
before referencing “i_val”.

• Test “pk_inst” to see if it is “IEEE packet”:


if pk_inst is a IEEE packet (ip) {ip.i_val = 1; };
or
pk_list.first(it is a IEEE packet (ip) and ip.i_val == 1);
Use this method if “pk_inst” is a packet that may or may not be “IEEE”. For example, “pk_inst”
may be an element of a list of packets or may be a generated packet with no constraint on
“protocol”.
• Define “pk_inst” as an “IEEE packet”:

3-12 e Language Reference


Data Types
List Types

var pk_inst: IEEE packet;


pk_inst.i_val = 1;
or
var pk_inst: IEEE packet;
gen pk_inst keeping {
it is a IEEE packet (ip) and ip.i_val == 1
};
Use this method if you want “pk_inst” to always be “IEEE”. Note that you must either declare the
variable or field to be type “IEEE packet” or use the is a syntax. It is not sufficient to say gen
pk_inst keeping (.kind == IEEE; .i_val == 1}.
• Cast “pk_inst” as “IEEE packet”:
pk_inst.as_a(IEEE packet).i_val = 1;
This is shorthand for method 1 above. You can do it this way if you know that “pk_inst” is an “IEEE
packet” but for some reason it is defined just as a packet. For example:
var pk_inst: packet;
gen pk_inst keeping {it is a IEEE packet};
pk_inst.as_a(IEEE packet).i_val = 1;
Note that if “pk_inst” is not an “IEEE packet” you will get an error stating that “struct is NULL”.

See Also
• Chapter 4 “Structs, Fields, and Subtypes”
• var on page 8-2
• “Struct Hierarchy and Name Resolution” on page 2-23
• “Comparison of When and Like Inheritance” on page 4-33
• when on page 4-22
• extend type on page 4-6
• is [not] a on page 2-88

3.1.6 List Types


List types hold ordered collections of data elements where each data element conforms to the same type.
Items in a list can be indexed with the subscript operator [ ], by placing a non-negative integer
expression in the brackets. List indexes start at zero. You can select an item from a list by specifying its
index. For example, my_list[0] refers to the first item in the list named my_list.

e Language Reference 3-13


Data Types
List Types

Lists are defined by using the list of keyword in a variable or a field definition. The example below
defines a list of bytes named “lob” and explicitly assigns five literal values to it. The print statement
displays the first three elements of “lob”, 15, 31, and 63.
var lob: list of byte = {15;31;63;127;255};
print lob[0..2];

Note Specman does not support multi-dimensional lists (lists of lists). To create a list with sublists in
it, you can create a struct to contain the sublists, and then create a list of such structs as the main list.

The default value of a list is an empty list.

This section contains:

• “Regular Lists” on page 3-14


• “Keyed Lists” on page 3-15

3.1.6.1 Regular Lists


The following example shows two lists, “packets” and “all_lengths”.
type packet_protocol : [Ethernet, IEEE, foreign];
type length: int [0..10];
struct packet {
protocol: packet_protocol;
len: length;
};
extend sys {
packets[10] : list of packet;
do_print() is {
var all_lengths: list of length;
all_lengths = packets.len;
print packets;
print all_lengths;
};
};

Each element of “packets” is a struct of type “packet”. Each element of “all_lengths” is a scalar value of
type “length”.

Both “packets” and “all_lengths” have 10 elements because of the explicit size “[10]” specified in the
“packets” declaration. You can only specify a list size in this manner for fields. To size lists that are
variables, you have to use a keep constraint.

3-14 e Language Reference


Data Types
The string Type

3.1.6.2 Keyed Lists


A keyed list data type is similar to hash tables or association lists found in other programming
languages. The declaration below specifies that “packets” is a list of packets, and that the “protocol”
field in the packet type is used as the hash key.
type packet_protocol : [Ethernet, IEEE, foreign];
struct packet {
protocol: packet_protocol;
};
var packets : list (key: protocol) of packet;

If the element type of the list is a scalar type or a string type, then the hash key must be the predefined
implicit variable it.
struct person {
name: string;
id: int;
};
struct city {
!persons: list(key: name) of person;
!street_names: list(key: it) of string;
};

Notes
• Keyed lists cannot be generated. Trying to generate a keyed list results in an error. Therefore, keyed
lists must be defined with the do-not-generate sign (an exclamation mark), as in the above example.
• The only restriction on the type of the list elements is that they cannot themselves be lists. However,
they can be struct types containing fields that are lists.

See Also
• Chapter 4 “Structs, Fields, and Subtypes”
• var on page 8-2
• “Packing and Unpacking Lists” on page 18-9
• Chapter 23 “List Pseudo-Methods”

3.1.7 The string Type


The Specman predefined type string is the same as the C NULL terminated (zero terminated) string
type. You can assign a series of ASCII characters enclosed by quotes (“ ”) to a variable or field of type
string, for example:

e Language Reference 3-15


Data Types
The external_pointer Type

var message: string;


message = "Beginning initialization sequence…";

You cannot access bits or bit ranges of a string, but you can convert a string to a list of bytes and then
access a portion of the string. The print statement shown below displays “/test1”.
var dir: string = "/tmp/test1";
var tmp := dir.as_a(list of byte);
tmp = tmp[4..9];
print tmp.as_a(string);

The default value of a variable of type string is NULL, which is equivalent to an empty string (that is,
“”).

To continue a string over multiple lines, put the line continuation character “\” at the end of each line
except the last.

See Also
• Chapter 24 “Predefined Routines”
• “Packing and Unpacking Strings” on page 18-7

3.1.8 The external_pointer Type


The external_pointer type is used to hold a pointer into an external (non-Specman) entity, such as a C
struct. Unlike pointers to structs in e, external pointers are not changed during garbage collection.

See Also
• routine … is C routine on page 11-21 in Usage and Concepts Guide for e Testbenches

3.2 Memory Requirements for Data Types


The amount of memory needed to store Specman data types is listed in Table 3-2.

Table 3-2 Storage Sizes of Specman Data Types

Type Size in Memory

All scalars up to 32 bits 4 bytes

Scalars larger than 32 Same as a list of bit of the appropriate size


bits

3-16 e Language Reference


Data Types
Untyped Expressions

Table 3-2 Storage Sizes of Specman Data Types

Type Size in Memory

String 4 bytes (the pointer) + the size of the string + 1 byte (the NULL byte)
A NULL string is just the pointer.

Struct pointer 4 bytes

Struct 8 bytes + the sum of the field sizes


A NULL struct is just the pointer (4 bytes)

List 4 bytes (a pointer to the list) + approximately 16 bytes (header) + the sum
of the sizes of the elements
Lists of scalars of size up to 16 bits are packed to the nearest power of 2
(in bits). This is often the most efficient representation.

3.3 Untyped Expressions


All e expressions have an explicit type, except for the following types of expressions:

• HDL objects, such as 'top.w_en'


• pack() expressions, such as “pack(packing.low, 5)”
• bit concatenations, such as “%{slb1, slb2};”
The default type of HDL objects is 32-bit uint, while pack() expressions and bit concatenations have a
default type of list of bit. However, because of implicit packing and unpacking, Specman can convert
these expressions to the required data type and bit size in certain contexts.

• When an untyped expression is assigned to a scalar or list of scalars, it is implicitly unpacked and
converted to the same type and bit size as the expression on the left-hand side.
The pack expression shown below, for example, is evaluated as 0x04, taking the type and bit size of
“j”.
var j:int(bits:8);
j = pack(packing.low, 4);
Note Implicit unpacking is not supported for strings, structs, or lists of non-scalar types. As a
result, the following causes a load-time error if “i” is a string, a struct, or a list of a non-scalar type:
i = pack(packing.low, 5);

• When a scalar or list of scalars is assigned to an untyped expression, it is implicitly packed before it
is assigned.

e Language Reference 3-17


Data Types
Untyped Expressions

In the following example, the value of “j”, 0x4, is implicitly packed and converted to the size of
'top.a' before the value is driven:
'top.a' = j;
Note Implicit packing is not supported for strings, structs, or lists of non-scalar types. As a result,
the assignment above would cause a load-time error if “j” were a string, a struct, or a list of a
non-scalar type.

• When the untyped expression is the operand of any binary operator (+, -, *, /,%), the expression is
assumed to be a numeric type. Specman determines the precision of the operation based on the
expected type and the type of the operands. See “Precision Rules for Numeric Operations” on page
3-24 for more information.

Both 'top.a' and “pack(packing.low, -4)” are handled as numeric types.


print ('top.a' + pack(packing.low, 4) == 0);

• When a pack() expression includes the parameter or the return value of a method call, the expression
takes the type and size as specified in the method declaration.
The pack() expression “pack(packing.low, data)” generates a list of bit that is implicitly unpacked
into the required type list of byte as defined in the declaration of the send_data() method.
extend sys {
data[10]:list of byte;
send_data(d: list of byte) is {
...
};
run() is also {
send_data(pack(packing.low, data));
};
};
Note The method parameter or return value in the pack expression must be a scalar type or a list
of scalar type. For example, the following results in a load-time error:
struct instruction {
%opcode : uint (bits : 3);
%operand : uint (bits : 5);
%address : uint (bits : 8);
};
extend sys {
instr: instruction;
send_instr(i: instruction) is {
...
};
run() is also {;
send_instr(pack(packing.low, 5)); --load-time error
};

3-18 e Language Reference


Data Types
Assignment Rules

};

• When an untyped expression appears in one of the following contexts, it is treated as a Boolean
expression:
if (untyped_exp) then {..}
while (untyped_exp) do {..}
check that (untyped_exp)
not untyped_exp
rise(untyped_exp), fall(untyped_exp), true(untyped_exp)

When Specman cannot determine the type and bit size from the context, it automatically casts the
expression according to the following rules.

• The default type of an HDL signal is an unsigned integer.


• The default type of a pack expression and a bit concatenation expression is a list of bit.
• If no bit width specification is detected, the default width is 32 bits.
One common context where Specman cannot determine the type of an expression is a print statement.
In the following example, the value displayed by the first print statement is “0xaaaaffff”. The value
displayed by the second print statement is “0xffffaaaaffff”.
'top.a' = 48'0xffffaaaaffff;
print 'top.a';
var tmp: uint(bits: 48) = 'top.a';
print tmp;

When expressions are untyped, an implicit pack/unpack is performed according to the expected type.

See Also
• “Implicit Packing and Unpacking” on page 18-25

3.4 Assignment Rules


Assignment rules define what is a legal assignment and how values are assigned to entities. The
following sections describe various aspects of assignments:

• “What Is an Assignment?” on page 3-20


• “Assignments Create Identical References” on page 3-21
• “Assignment to Different but Compatible Types” on page 3-21

e Language Reference 3-19


Data Types
What Is an Assignment?

3.4.1 What Is an Assignment?


There are several legal ways to assign values:

• Assignment actions
• Return actions
• Parameter passing
• Variable declaration

Here is an example of an assignment action, where a value is explicitly assigned to a variable “x” and to
a field “sys.x”.
extend sys{
x: int;
m() is {
sys.x = '~/top/address';
var x: int;
x = sys.x + 1;
};
};

Here’s an example of a return action, which implicitly assigns a value to the result variable:
extend sys {
n(): int (bits: 64) is {
return 1;
};
};

Here’s an example of assigning a value (6) to a method parameter (“i”):


extend sys {
k(i: int) @sys.any is {
wait [i] * cycle;
};

run() is also {
start k(6);
};
};

Here’s an example of how variables are assigned during declaration:


extend sys {
b() is {
var x: int = 5;
var y:= "ABC";
};

3-20 e Language Reference


Data Types
Assignments Create Identical References

};
Note You cannot assign values to fields during declaration in this same manner.

3.4.2 Assignments Create Identical References


Assigning one struct, list, or value to another object of the same type results in two references pointing
to the same memory location, so that changes to one of the objects also occur in the other object
immediately.
data1: list of byte;
data2: list of byte;
run() is also {
data2 = data1;
data1[0] = 0;
};

After generation, the two lists data1 and data2 are different lists. However, after the data2=data1
assignment, both lists refer to the same memory location, therefore changing the data1[0] value also
changes the data2[0] value immediately.

3.4.3 Assignment to Different but Compatible Types


This section contains the following:

• “Assignment of Numeric Types” on page 3-21


• “Assignment of Boolean Types” on page 3-22
• “Assignment of Enumerated Types” on page 3-22
• “Assignment of Structs” on page 3-23
• “Assignment of Strings” on page 3-24
• “Assignment of Lists” on page 3-24

3.4.3.1 Assignment of Numeric Types


Any numeric type (for example, uint, int, or one of their subtypes) can be assigned with any other
numeric type. Untyped expressions, such as HDL objects, can also appear in assignments of numeric
types. See “Untyped Expressions” on page 3-17 for more information.
extend sys {
!x1: int;
x2: uint (bits: 3);
!x3: int [10..100];

e Language Reference 3-21


Data Types
Assignment to Different but Compatible Types

post_generate() is also{
x1 = x2;
x3 = x1;
var x: int (bits: 48) = x3;
};
};

Automatic casting is performed when a numeric type is assigned to a different numeric type, and
automatic extension or truncation is performed if the types have different bit size. See “Automatic Type
Casting” on page 3-29 for more information. See “Precision Rules for Numeric Operations” on page 3-24
for information on how Specman determines precision for operations involving numeric types.

3.4.3.2 Assignment of Boolean Types


A Boolean type can only be assigned with another Boolean type.
var x: bool;
x = 'top.a' >= 16;

3.4.3.3 Assignment of Enumerated Types


An enumerated type can be assigned with that same type, or with its scalar subtype. (The scalar subtype
differs only in range or bit size from the base type.)

The example below shows:

• An assignment of the same type:


var x: color = blue;

• An assignment of a scalar subtype:


var y: color2 = x;

Example
type color: [red,green,blue];
type color2: color (bits: 2);

extend sys {
m() is {
var x: color = blue;
var y: color2 = x;
};
};

3-22 e Language Reference


Data Types
Assignment to Different but Compatible Types

To assign any scalar type (numeric, enumerated, or Boolean type) to any different scalar type, you must
use the .as_a() operator.

3.4.3.4 Assignment of Structs


An entity of type struct can be assigned with a struct of that same type or with one of its subtypes. The
following example shows:

• A same type assignment:


p2 = p1;

• An assignment of a subtype (Ether_8023 packet):


set_cell(p);

• An assignment of a derived struct (cell_8023):


p.cell = new cell_8023;

Example
type packet_kind: [Ether, Ether_8023];
struct cell {};

struct cell_8023 like cell {};


struct packet {
packet_kind;
!cell: cell;
};

extend sys {
p1: packet;
!p2: packet;
!p3: packet;
post_generate() is also {
p2 = p1;
var p: Ether_8023 packet;
gen p;
set_cell(p);
};

set_cell(p: packet) is {
p.cell = new cell_8023;
};
};

e Language Reference 3-23


Data Types
Precision Rules for Numeric Operations

Although you can assign a subtype to its parent struct without any explicit casting as shown above, to
perform the reverse assignment (assign a parent struct to one of its subtypes), you must use the .as_a()
method. See “as_a()” on page 3-40 for an example of how to do this.

3.4.3.5 Assignment of Strings


A string can be assigned only with strings, as shown below.
extend sys {
m(): string is {
return "aaa"; // assignment of a string
};
};

3.4.3.6 Assignment of Lists


An entity of type list can be assigned only with a list of the same type. In the following example, the
assignment of “list1” to “x” is legal because both lists are lists of integers.
extend sys {
list1: list of int;
m() is {
var x: list of int = list1;
};
};

However, an assignment such as “var y: list of int (bits: 16) = list1;” would be an error, because “list1”
not the same list type as “y”. “y” has a size modifier, so it is a subtype of “list1”. You can use the .as_a()
method to cast between lists and their subtypes.

See Also
• “Untyped Expressions” on page 3-17
• “Precision Rules for Numeric Operations” on page 3-24
• “Automatic Type Casting” on page 3-29

3.5 Precision Rules for Numeric Operations


For precision rules, there are two types of numeric expressions in e:

• Context-independent expressions, where the precision of the operation (bit width) and numeric type
(signed or unsigned) depend only on the types of the operands

3-24 e Language Reference


Data Types
Determining the Context of an Expression

• Context-dependent expressions, where the precision of the operation and the numeric type depend
on the precision and numeric type of other expressions involved in the operation (the context), as
well as the types of the operands

A numeric operation in e is performed in one of three possible combinations of precision and numeric
type:

• Unsigned 32-bit integer (uint)


• Signed 32-bit integer (int)
• Infinite signed integer (int (bits: *))
The e language has rules for:

• Determining the context of an expression


• Deciding precision, and performing data conversion and sign extension
The following sections describe these rules and give an example of how these rules are applied:

• “Determining the Context of an Expression” on page 3-25


• “Deciding Precision and Performing Data Conversion and Sign Extension” on page 3-27
• “Example Application of Precision Rules” on page 3-28

See Also
• “Operator Precedence” on page 2-35

3.5.1 Determining the Context of an Expression


The rules for defining the context of an expression are applied in the following order:

1. In an assignment (lhs = rhs), the right-hand side (rhs) expression inherits the context of the left-hand
side (lhs) expression.

2. A sub-expression inherits the context of its enclosing expression.

3. In a binary-operator expression (lho OP rho), the right-hand operand (rho) inherits context from the
left-hand operand (lho), as well as from the enclosing expression.

Table 3-3 summarizes context inheritance for each type of operator that can be used in numeric
expressions.

e Language Reference 3-25


Data Types
Determining the Context of an Expression

Table 3-3 Summary of Context Inheritance in Numeric Operations

Operator Function Context

*/%+- Arithmetic, comparison, The right-hand operand inherits context from the
< <= > >= equality, and bit-wise left-hand operand (lho), as well as from the
== != Boolean enclosing expression. lho inherits only from the
=== !== enclosing expression.
&|^

~! Bitwise not, Boolean not, The operand inherits context from the enclosing
unary + - unary plus, minus expression.

[ ] List indexing The list index is context independent.

[ .. ] List slicing The indices of the slice are context independent.

[:] Bit slicing The indices of the slice are context independent.

f(…) Method or routine call The context of a parameter to a method is the


type and bit width of the formal parameter.

{…; …} List concatenation Context is passed from the lhs of the assignment,
but not from left to right between the list
members.

%{…, …} Bit concatenation The elements of the concatenation are context


independent.

>>, << Shift Context is passed from the enclosing expression


to the left operand. The context of the right
operand is always 32-bit uint.

lho in [i..j] Range list operator All three operands are context independent. (The
range specifiers i and j must be constant.)

&&, || Boolean All operands are context independent.

a?b:c Conditional operator a is context independent, b inherits the context


from the enclosing expression, c inherits context
from b as well as from the enclosing expression

.as_a() Casting The operand is context independent.

abs(), odd() Arithmetic routine The parameter is context independent.


even()

3-26 e Language Reference


Data Types
Deciding Precision and Performing Data Conversion and Sign Extension

Table 3-3 Summary of Context Inheritance in Numeric Operations

Operator Function Context

min(), max() Arithmetic routine The right parameter inherits context from the left
parameter (lp), as well as from the enclosing
expression. lp inherits only from the enclosing
expression.

ilog2(), Arithmetic routine The context of the parameter is always 32-bit


ilog10(), uint.
isqrt()

ipow() Arithmetic routine Both parameters inherit the context of the


enclosing expression, but the right parameter
does not inherit context from the left.

3.5.2 Deciding Precision and Performing Data Conversion


and Sign Extension
The rules for deciding precision, performing data conversion and sign extension are as follows:

• Determine the context of the expression. The context may be comprised of up to two types.
• If all types involved in an expression and its context are 32 bits in width or less:
• The operation is performed in 32 bits.
• If any of the types is unsigned, the operation is performed with unsigned integers.
Note Decimal constants are treated as signed integers, whether they are negative or not. All
other constants are treated as unsigned integers unless preceded by a hyphen.

• Each operand is automatically cast, if necessary, to the required type.


Note Casting of small negative numbers (signed integers) to unsigned integers produces large
positive numbers.

• If any of the types is greater than 32 bits:


• The operation is performed in infinite precision (int (bits:*))
• Each operand is zero-extended, if it is unsigned, or sign-extended, if it is signed, to infinite
precision.

e Language Reference 3-27


Data Types
Example Application of Precision Rules

3.5.3 Example Application of Precision Rules


Given the following assignment:
sum: int;
exp1: int (bytes:2);
exp2: uint (bits:4);
exp3: int (bits:4);

sum = exp1 + exp2 * exp3;

1. The precision of the multiplication operation (exp2 * exp3) is based on the four types involved here:

• The inherited context of the lhs expression (int)


• The inherited context of the lho (int (bytes:2))
• The type of exp2 (4-bit uint)
• The type of exp3 (4-bit int)
Because one of these four types is unsigned, the multiplication is done in 32-bit unsigned integer.
Both exp2 and exp3 are converted to 32-bit uint and the multiplication operation is performed.

2. The precision of the addition operation is based on the three types involved here:

• The inherited context of the lhs expression (int)


• The type of exp1 (int (bytes:2))
• The type of (exp2 * exp3) (uint)
Because one of these types is unsigned, the addition is done in 32-bit unsigned integer. exp1 is
converted to 32-bit uint and the addition operation is performed.

3. For the assignment operation, the result of the addition operation is converted to 32-bit int and
assigned to sum.

See Also
• “Untyped Expressions” on page 3-17
• “Assignment Rules” on page 3-19
• “Automatic Type Casting” on page 3-29

3-28 e Language Reference


Data Types
Automatic Type Casting

3.6 Automatic Type Casting


During assignment of a type to a different but compatible type, automatic type casting is performed in
the following contexts:

• Numeric expressions (unsigned and signed integers) of any size are automatically type cast upon
assignment to different numeric types. For example:
var x: uint;
var y: int;
x = y;

• Untyped expressions are automatically cast on assignment. See “Untyped Expressions” on page 3-17
for more information.
var j: uint = 0xff;
'top.a' = j;

• Sized scalars are automatically type cast to differently sized scalars of the same type.
type color: [red,green,blue];
type color2: color (bits: 2);

var x: color = blue;


var y: color2 = x;

• Specman automatically casts struct subtypes to their base struct type.


type packet_protocol: [Ethernet, IEEE, foreign];
struct packet {
protocol: packet_protocol;
size: int [0..1k];
data[size]: list of byte;
show() is undefined; // To be defined by children
};
extend Ethernet packet {
e_field: int;
show() is {out("I am an Ethernet packet")};
};
extend sys {
m() is {
var epkt: Ethernet packet = new;
var pkt: packet = epkt;
};
};

e Language Reference 3-29


Data Types
Automatic Type Casting

There are three important ramifications to automatic type casting:

1. If the two types differ in bit size, then the assigned value is extended or truncated to the required bit
size. See “Example 1” on page 3-30.

2. Casting of small negative numbers (signed integers) to unsigned integers produces large positive
numbers. See “Example 2” on page 3-30.

3. There is no automatic casting to a reference parameter. See “Parameter Passing” on page 7-34 for
more information.

Example 1
In the following example, “x” is a 32-bit signed integer, “y” is a 48-bit unsigned integer, and “z” is a
3-bit signed integer. Assigning “x” to “y” extends “x” to 48 bits. Assigning “x” to “z” chops “x” to 3
bits.
extend sys {
m() is {
var x: int = -1;
var y: int (bits: 48) = x;
var z: int (bits: 3) = x;
print y,z;
};
};

Result
Calling “sys.m()” results in:
y = 0xffffffffffff
z = 0x7

Example 2
m() is {
var x: int = -1;
var y: uint = MAX_UINT;
var z: uint = 1;
print x == y;
print x > z;
};

3-30 e Language Reference


Data Types
Constructs for Defining and Extending Scalar Types

Result
The int value “x” (0xffffffff) is automatically cast to uint and becomes MAX_UINT. As a result, the
print statements display the following:
x == y = TRUE
x > z = TRUE

See Also
• as_a() on page 3-40
• “Untyped Expressions” on page 3-17
• “Assignment Rules” on page 3-19
• “Precision Rules for Numeric Operations” on page 3-24

3.7 Constructs for Defining and Extending Scalar


Types
You can use the following constructs to define and extend scalar types:

• type enumerated scalar on page 3-31


• type scalar subtype on page 3-34
• type sized scalar on page 3-36
• extend type on page 3-37

3.7.1 type enumerated scalar

Purpose
Define an enumerated scalar type

Category
Statement

Syntax
type enum-type-name: [[name[=exp], …]] [(bits | bytes: width-exp)]

e Language Reference 3-31


Data Types
type enumerated scalar

Syntax Example
type PacketType :[ rx = 1, tx, ctrl ];

Parameters

enum-type-name A legal e name. The name must be different from any other predefined or
enumerated type name because the name space for types is global.

name A legal e name. Each name must be unique within the type.

exp A unique 32-bit constant expression. Names or name-value pairs can appear
in any order. By default, the first name in the list is assigned the integer
value zero. Subsequent names are assigned values based upon the maximum
value of the previously defined enumerated items + 1.

width-exp A positive constant expression. The valid range of values for sized
enumerated scalar types is limited to the range 1 to 2**n - 1, where n is the
number of bits.

Description
Defines an enumerated scalar type having the name you specify and consisting of a set of names or
name-value pairs. If no values are specified, the names get corresponding numerical values starting with
0 for the first name, and casting can be done between the names and the numerical values.

Example 1
This is a simple example of the basic syntax.
type PacketType :[ rx, tx, ctrl ];

struct packet {
kind :PacketType;

do_print() is {
if kind == ctrl {
out("This is a control packet.");
};
};
};

Example 2
This example shows how HDL variables are automatically cast to the required scalar type.

3-32 e Language Reference


Data Types
type enumerated scalar

type PacketType :[ rx, tx, ctrl ];

struct packet {
kind :PacketType;

set() is {
kind = 'top.pkt_type';
};
};

Example 3
This example shows an enumerated type with a bit width:
type NetworkType :[ IP=0x0800, ARP=0x8060 ](bits:16);

struct header {
dest_address :uint(bits:48);
src_address :uint(bits:48);
type :NetworkType;

do_print() is {
if type == IP {
out("This is an IP packet.");
};
};
};

Example 4
This example shows how to type cast between an enumerated type and an unsigned integer.
type signal_number: [signal_0, signal_1, signal_2, signal_3];
struct signal {
cast_1() is {
var temp_val: uint = 3;
var signal_name: signal_number = temp_val.as_a(signal_number);
print signal_name;
};

cast_2() is {
var temp_enum: signal_number = signal_0;
var signal_value: uint = temp_enum.as_a(uint);
print signal_value;
};

e Language Reference 3-33


Data Types
type scalar subtype

};

See Also
• type scalar subtype on page 3-34
• type sized scalar on page 3-36
• extend type on page 3-37
• as_a() on page 3-40
• “Enumerated Scalar Types” on page 3-5

3.7.2 type scalar subtype

Purpose
Define a scalar subtype

Category
Statement

Syntax
type scalar-subtype-name: scalar-type [range, …]

Syntax Example
type size: int [8, 16];

Parameters

scalar-subtype-name A unique e name.

scalar-type Any previously defined enumerated scalar type, any of the predefined
scalar types, including int, uint, bool, bit, byte, or time, or any previously
defined scalar subtype.

range A constant expression or two constant expressions separated by two dots.


All constant expressions must resolve to legal values of the named type.

3-34 e Language Reference


Data Types
type scalar subtype

Description
Defines a subtype of a scalar type by restricting the legal values that can be generated for this subtype to
the specified range.

Note
The default value for variables or fields of this type “size” is zero, the default for all integers; the range
affects only the generated values.

Example 1
The integer subtype defined below includes all non-negative integers except 4,5, and 7.
type medium: uint [0..3,6,8..MAX_INT];

Example 2
The following example defines the “inst” type, which has five legal instruction values, and the subtype
“mem_inst”, which has only the values related to memory.
type inst: [add, sub, mul, div, load, store];
type mem_inst: inst [load..store];

Example 3
You can omit the range list, thus renaming the full range. The first example below gives the name
“my_int” to the full range of integers. The second example gives the name “true_or_false” to the full
range of the Boolean type.
type my_int: int;
type true_or_false: bool;

See Also
• type enumerated scalar on page 3-31
• type sized scalar on page 3-36
• extend type on page 3-37
• “Scalar Subtypes” on page 3-3

e Language Reference 3-35


Data Types
type sized scalar

3.7.3 type sized scalar

Purpose
Define a sized scalar

Category
Statement

Syntax
type sized-scalar-name: type (bits | bytes: exp)

Syntax Example
type word :uint(bits:16);
type address :uint(bytes:2);

Parameters

sized-scalar-name A unique e name.

type Any previously defined enumerated type or any of the predefined scalar
types, including int, uint, bool, or time.

exp A positive constant expression. The valid range of values for sized scalars is
limited to the range 1 to 2n - 1, where n is the number of bits.

Description
Defines a scalar type with a specified bit width. The actual bit width is exp * 1 for bits and exp * 8 for
bytes. In the example shown below, both types “word” and “address” have a bit width of 16.
type word :uint(bits:16);
type address :uint(bytes:2);

3-36 e Language Reference


Data Types
extend type

Example
When assigning any expression into a sized scalar variable or field, the expression's value is truncated or
extended automatically to fit into the variable. An expression with more bits than the variable is chopped
down to the size of the variable. An expression with fewer bits is extended to the length of the variable.
The added upper bits are filled with zero if the expression is unsigned, or with the sign bit (zero or one)
if it is a signed expression.

Here is an example of assigning an expression where the expression's value is truncated:


type SmallAddressType :uint(bits:2);

extend sys {
chop_expression() is {
var small_address :SmallAddressType;

small_address = 0x2 * 8;
out("small_address: ", small_address);
};

run() is also {
chop_expression();
};
};

See Also
• type enumerated scalar on page 3-31
• type scalar subtype on page 3-34
• extend type on page 3-37
• “Assignment Rules” on page 3-19
• “Precision Rules for Numeric Operations” on page 3-24

3.7.4 extend type

Purpose
Extend an enumerated scalar type

e Language Reference 3-37


Data Types
extend type

Category
Statement

Syntax
extend enum-type: [name[= exp], …]

Syntax Example
type PacketType :[ rx, tx, ctrl ];
extend PacketType :[ status ];

Parameters

enum-type Any previously defined enumerated type.

name A legal e name. Each name must be unique within the type.

exp A unique 32-bit constant expression. Names or name-value pairs can appear in
any order. By default, the first name in the list is assigned the integer value
zero. Subsequent names are assigned values based upon the maximum value of
the previously defined enumerated items + 1.

Description
Extends the specified enumerated scalar type to include the names or name-value pairs you specify.

Example 1
This is an example of the basic syntax.
type command :[ ADD=0x00, SUB=0x02, AND=0x04,
XOR=0x06, UDEF=0xFF ] (bits: 8);

extend command :[ ADDI=0x01, SUBI=0x03,


ANDI=0x05, XORI=0x07 ];

Example 2
A common use of type extension is defining a protocol type and extending it as new protocols are added
to the test environment. For example, you can define a packet header without having to know what
specific network protocols are supported by the packet:
type NetworkType :[ ](bits:16);

3-38 e Language Reference


Data Types
Additional Type-Related Constructs

struct header {
dest_address :uint(bits:48);
src_address :uint(bits:48);
type :NetworkType;
};

As protocols are gradually added to the test environment, the new protocol type can be added without
changes to the original code:
extend NetworkType :[ ARP=0x8060 ];

Then again for more protocols:


extend NetworkType :[ IP=0x0800 ];

See Also
• type enumerated scalar on page 3-31
• type scalar subtype on page 3-34
• type sized scalar on page 3-36
• “e Data Types” on page 3-1

3.8 Additional Type-Related Constructs


This section contains:

• Type Conversion Between Scalars and Strings on page 3-39


• as_a() on page 3-40
• all_values() on page 3-52

3.8.1 Type Conversion Between Scalars and Strings


The as_a() expression is used to convert an expression from one data type to another. Information about
how different types are converted, such as strings to scalars or lists of scalars, is contained in Table 3-4
on page 3-41 and Table 3-5 on page 3-43.

e Language Reference 3-39


Data Types
as_a()

3.8.2 as_a()

Purpose
Casting operator

Category
Expression

Syntax
exp.as_a(type: type name): type

Syntax Example
print (b).as_a(uint);

Parameters

exp Any e expression.

type Any legal e type.

Description
Returns the expression, converted into the specified type. Although Specman performs some casting
automatically (see “Automatic Type Casting” on page 3-29), explicit casting is required in some cases
when making assignments between different but compatible types.

Type Conversion Between Scalars and Lists of Scalars


Numeric expressions (unsigned and signed integers) of any size are automatically type cast upon
assignment to different numeric types.

For other scalars and lists of scalars, there are a number of ways to perform type conversion, including
the as_a() method, the pack() method, the %{} bit concatenation operator and various string routines.
Table 3-4 on page 3-41 shows the recommended methods for converting between scalars and lists of
scalars.

In Table 3-4 on page 3-41, int represents int/uint of any size, including bit, byte, and any user-created
size. If a solution is specific to bit or byte, then bit or byte is explicitly stated.

3-40 e Language Reference


Data Types
as_a()

int(bits:x) means x as any constant; variables cannot be used as the integer width.

The solutions assume that there is a variables declared as


var int : int ;
var bool : bool ;
var enum : enum ;
var list_of_bit : list of bit ;
var list_of_byte : list of byte ;
var list_of_int : list of int ;

Any conversions not explicitly shown may have to be accomplished in two stages.

Table 3-4 Type Conversion Between Scalars and Lists of Scalars

From To Solutions

int list of bit list_of_bit = int[..]

int list of list_of_int = %{int}


int(bits:x) list_of_int = pack(packing.low, int)
(LSB of int goes to list[0] for either choice)

list of bit int int = list_of_bit[:]


list of byte

list of int int = pack(packing.low, list_of_int)


int(bits:x) (Use packing.high for list in other order.)

int(bits:x) int(bits:y) intx = inty


(Truncation or extension is automatic.)
intx.as_a(int(bits:y))

bool int int = bool.as_a(int)


(TRUE becomes 1, FALSE becomes 0.)

int bool bool = int.as_a(bool)


(0 becomes FALSE, non-0 becomes TRUE.)

int enum enum = int.as_a(enum)


(No checking is performed to make sure the int value is valid for the
range of the enum.)

e Language Reference 3-41


Data Types
as_a()

Table 3-4 Type Conversion Between Scalars and Lists of Scalars

From To Solutions

enum int int = enum.as_a(int)


(Truncation is automatic.)

enum bool enum.as_a(bool)


(Enumerated types with an associated unsigned integer value of 0
become FALSE; those with an associated non-0 values become
TRUE. See “Enumerated Scalar Types” on page 3-5 for more
information on values associated with enumerated types.)

bool enum bool.as_a(enum)


(Boolean types with a value of FALSE are converted to the
enumerated type value that is associated with the unsigned integer
value of 0; those with a value of TRUE are converted to the
enumerated type value that is associated with the unsigned integer
value of 1. No checking is performed to make sure the Boolean value
is valid for the range of the enum.)

enum enum enum1 = enum2.as_a(enum1)


(no checking is performed to make sure the int value is valid for the
range of the enum)

list of list of listx.as_a(list of int(bits:y))


int(bits:x) int(bits:y) (same number of items, each padded or truncated)
listy = pack(packing.low, listx)
(concatenated data, different number of items)

Type Conversion Between Strings and Scalars or Lists of Scalars


There are a number of ways to perform type conversion between strings and scalars or lists of scalars,
including the as_a() method, the pack() method, the %{} bit concatenation operator and various string
routines. Table 3-5 on page 3-43 shows how to convert between strings and scalars or lists of scalars.

In Table 3-5 on page 3-43, int represents int/uint of any size, including bit, byte, and any user-created
size. If a solution is specific to bit or byte, then bit or byte is explicitly stated.

int(bits:x) means x as any constant; variables cannot be used as the integer width.

The solutions assume that there is a variables declared as


var int : int ;

3-42 e Language Reference


Data Types
as_a()

var list_of_byte : list of byte ;


var list_of_int : list of int ;
var bool : bool ;
var enum : enum ;
var string : string ;

Any conversions not explicitly shown may have to be accomplished in two stages.

Table 3-5 Type Conversion Between Strings and Scalars or Lists of Scalars

ASCII
From To Convert? Solutions

list of int string yes list_of_int.as_a(string)


list of byte (Each list item is converted to its ASCII character and
the characters are concatenated into a single string.
int[0] represents left-most character. Depending on
the value of a given list item, its corresponding ASCII
character might be printable or non-printable. If a list
item’s value is a non-printable ASCII character, you
will get spurious results if you try to print it.)

string list of int yes string.as_a(list of int)


list of byte (Each character in the string is converted to its
numeric value and assigned to a separate element in
the list. The left-most character becomes int[0])

string list of int yes list_of_int = pack(packing.low, string)


list_of_int = %{string}
(The numeric values of the characters are
concatenated before assigning them to the list. Any
pack option gives same result; null byte, 00, will be
last item in list.)

string int yes int = %{string}


int = pack(packing.low, string)
(Any pack option gives same result.)

int string yes unpack(packing.low, %{8’b0, int}, string)


(Any pack option with scalar_reorder={} gives same
result.)

e Language Reference 3-43


Data Types
as_a()

Table 3-5 Type Conversion Between Strings and Scalars or Lists of Scalars

ASCII
From To Convert? Solutions

string int no string.as_a(int)


(Converts to decimal.)
append(“0b”, string).as_a(int)
(Converts to binary.)
append(“0x”, string).as_a(int)
(Converts to hexadecimal.)

int string no int.as_a(string)


(Uses the current print radix.)
append(int)
(Converts int according to current print radix.)
dec(int), hex(int), bin(int)
(Converts int according to specific radix.)

string bool no bool = string.as_a(bool)


(Only “TRUE” and “FALSE” can be converted to
Boolean; all other strings return an error.)

bool string no string = bool.as_a(string)

string enum no enum = string.as_a(enum)

enum string no string = enum.as_a(string)

Type Conversion Between Structs, Struct Subtypes, and Lists of Structs


Specman automatically casts struct subtypes to their base struct type, so, for example, you can assign a
variable of type “Ethernet packet” to a variable of type “packet” without using as_a().

You can use as_a() to cast a base struct type to one of its subtypes; if a mismatch occurs, then NULL is
assigned. For example, the “print pkt.as_a(foreign packet)” action results in “pkt.as_a(foreign packet)
= NULL” if pkt is not a foreign packet.

When the expression to be converted is a list of structs, as_a() returns a new list of items whose type
matches the specified type parameter. If no items match the type parameter, an empty list is returned.

The list can contain items of various subtypes, but all items must have a common parent type. That is,
the specified type parameter must be a subtype of the type of the list.

3-44 e Language Reference


Data Types
as_a()

Assigning a struct subtype to a base struct type does not change the declared type. Thus, you have to use
as_a() to cast the base struct type as the subtype in order to access any of the subtype-specific struct
members. See “Example 6” on page 3-48.

Subtypes created through like inheritance exhibit the same behavior as subtypes created through when
inheritance.

Type Conversion Between Simple Lists and Keyed Lists


You can convert simple lists to keyed lists and keyed lists to simple lists. When you convert a keyed list
to a simple list, the hash key is dropped. When you convert a simple list to a keyed list, you must specify
the key.

For example, if “sys.packets” is a simple list of packets and you want to convert it to a keyed list where
the “len” field of the packet struct is the key, you can do so like this:
Specman > var pkts: list (key: len) of packet
Specman > pkts = sys.packets.as_a(list (key: len) of packet)

The as_a() method returns a copy of sys.packets, so the original sys.packets is still a simple list, not a
keyed list. Thus “print pkts.key_index(130)” returns the index of the item that has a “len” field of 130,
while “print sys.packets.key_index(130)” returns an error.

If a conversion between a simple list and a keyed list also involves a conversion of the type of each item,
that conversion of each item follows the standard rules. For example, it is a rule that if you use as_a() to
convert an integer to a string, no ASCII conversion is performed. Similarly, if you use as_a() to convert
a simple list of integers to a keyed list of strings, no ASCII conversion is performed:
Specman > var lk: list (key:it) of string
Specman > var l: list of int = {1;2;3;4;6;9}
Specman > lk = l.as_a(list (key:it) of string)
Specman > print lk.key_index("9")
lk.key_index("9") = 5

Notes
• No checking is performed to make sure the value is valid when casting from a numeric or Boolean
type to an enumerated type or when casting between enumerated types.

Example 1
In this example, the most significant bits of the 32-bit variable “i” are truncated when “i” is printed as a
16-bit variable. When “i” is printed as a 64-bit variable, it is sign-extended to fit.
extend sys {
m() is {

e Language Reference 3-45


Data Types
as_a()

var i : int = 0xffff000f;


print (i).as_a(int(bits:16)) using radix=HEX;
print (i).as_a(int(bits:64)) using radix=HEX;
};
};

Result
vrst-tool> sys.m()
(i).as_a(int(bits:16)) = 0x000f
(i).as_a(int(bits:64)) = 0xffffffffffff000f

Example 2
No checking is performed when “c”, a variable of type color, is assigned a value outside its range.
However, a message is issued when the “c” is accessed by the print statement.
type color: [red=2, blue=0, yellow=1];
extend sys{
m() is {
var c : color = blue;
var i : int = 2;
var u : uint = 0x74786574;
print (i).as_a(color);
print (c).as_a(int);
c = u.as_a(color); --no checking
print c; --message issued
};
};

Result
vrst-tool> sys.m()
(i).as_a(color) = red
(c).as_a(int) = 0x0
c = (Bad enum value for 'color': 1954047348)

Example 3
You can use the as_a() method to convert a Boolean type to a numeric or an enumerated type or from
one of those types to a Boolean.
type color: [red=2, blue=0, yellow=1];
extend sys{
m() is {
var c : color = blue;

3-46 e Language Reference


Data Types
as_a()

var i : int = 2;
var s : string = "hello";
print (i).as_a(bool);
print (c).as_a(bool);
};
};

Result
vrst-tool> sys.m()
(i).as_a(bool) = TRUE
(c).as_a(bool) = FALSE

Example 4
You can cast between numeric types and strings with as_a(), but no ASCII conversion is performed.
This example shows how to get ASCII conversion using unpack() and the bit concatenation
operator %{}.
extend sys{
m() is {
var i : int = 65;
var s1 : string;
var s2 : string = "B";
print (i).as_a(string);
unpack(packing.low, %{8'b0,i}, s1);
print s1;
--print (s2).as_a(int); --run-time error;
--”B” is not a valid integer
i = %{s2};
print i;
};
};

Result
vrst-tool> sys.m()
(i).as_a(string) = "65"
s1 = "A"
i = 66

e Language Reference 3-47


Data Types
as_a()

Example 5
You can cast between lists of numerics and strings with as_a(). As shown in the first print statement,
each character in the string is converted to its numeric value and assigned to a separate element in the
list. As shown in the second to last print statement, using pack() to convert a string concatenates the
numeric values of the characters before assigning them to the list.
extend sys {
m() is {
var s: string;
s = "hello";
var lint: list of int;
lint = s.as_a(list of int);
print lint;
print lint.as_a(string);
var lint2: list of int;
lint2 = pack(packing.low, s);
print lint2 using bin;
print lint using bin;
};
};

Result
vrst-tool> sys.m()
lint =
0. 104
1. 101
2. 108
3. 108
4. 111
lint.as_a(string) = "hello"
lint2 =
0. 0b1101100011011000110010101101000
1. 0b1101111
lint =
0. 0b1101000
1. 0b1100101
2. 0b1101100
3. 0b1101100
4. 0b1101111

Example 6
The “print pkt.as_a(foreign packet)” action below results in “pkt.as_a(foreign packet) = NULL”
because “pkt” is of type “Ethernet packet”.

3-48 e Language Reference


Data Types
as_a()

The “print pkt.e_field” action in this example results in a compile-time error because the declared type
of “pkt” does not have a field “e_field”. However, the “print pkt.as_a(Ethernet packet).e_field” action
prints the value of the field.
type packet_protocol: [Ethernet, IEEE, foreign];
struct packet {
protocol: packet_protocol;
size: int [0..1k];
data[size]: list of byte;
show() is undefined; // To be defined by children
};
extend Ethernet packet {
e_field: int;
show() is {out("I am an Ethernet packet")};
};
extend sys {
m() is {
var epkt: Ethernet packet = new;
var pkt: packet = epkt;
print pkt.type().name;
print pkt.declared_type().name;
print pkt.as_a(foreign packet);
-- print pkt.e_field; //compile-time error
print pkt.as_a(Ethernet packet).e_field;
print pkt.size;
};
};

Result
vrst-tool> sys.m()
pkt.type().name = "Ethernet packet"
pkt.declared_type().name = "packet"
pkt.as_a(foreign packet) = (NULL)
pkt.as_a(Ethernet packet).e_field = 0
pkt.size = 0

Example 7
The as_a() pseudo-method, when applied to a scalar list, creates a new list whose size is the same as the
original size and then casts each element separately.

To pass a list of integer(bits: 4) as a parameter to a method that requires a list of integers, you can use
explicit casting, as follows:
struct dtypes {
increment_list (cnt: list of int) is {

e Language Reference 3-49


Data Types
as_a()

for each in cnt {


cnt[index] = cnt[index] + 1;
};
};
};

extend sys {
di:dtypes;
m() is {
var small_list: list of int (bits: 5) = {3;5;7;9};
var big_list: list of int = {0;0;0;0;};
big_list = small_list.as_a(list of int);
di.increment_list(big_list);
print big_list;
};
};

Result
The print statement gives the following results:
big_list =
0. 4
1. 6
2. 8
3. 10

Example 8
When the as_a() operator is applied to a list of structs, the list items for which the casting failed are
omitted from the list.
type packet_protocol: [Ethernet, IEEE, foreign];
struct packet {
protocol: packet_protocol;
size: int [0..1k];
data[size]: list of byte;
show() is undefined; // To be defined by children
};
extend Ethernet packet {
e_field: int;
show() is {out("I am an Ethernet packet")};
};
extend sys {
packets[5]: list of packet;
post_generate() is also {
print packets;

3-50 e Language Reference


Data Types
as_a()

print packets.as_a(list of IEEE packet);


};
};

Result
vrst-tool> gen
Doing setup ...
Generating the test using seed 1...
packets =
item type protocol size data Ethernet'*

0. packet Ethernet 872 (872 item* -21166003*


1. packet Ethernet 830 (830 item* -21443627*
2. packet Ethernet 834 (834 item* 1684201428
3. packet Ethernet 663 (663 item* -15262725*
4. packet IEEE 213 (213 item*
packets.as_a(list of IEEE packet) =
item type protocol size data Ethernet'*

0. packet IEEE 213 (213 item*

Example 9
You can use as_a() to convert a string to an enumerated type. The string has to match letter by letter one
of the possible values of that type or a runtime error is issued.

This example sets a list of items of an enumerated type to the values read from a file.
type reg_address: [UARTCTL1, UARTDATA1, UARTCTL2, UARTDATA2];
extend sys {
ctl_regs: list of reg_address;

keep ctl_regs == (each line in file


"~/data/enum_items.txt").apply(it.as_a(reg_address));
run() is also {
print sys.ctl_regs;
};
};

enum_items.txt
UARTCTL1
UARTDATA1
UARTCTL2
UARTDATA2

e Language Reference 3-51


Data Types
all_values()

UARTDATA1
UARTCTL2
UARTCTL2
UARTCTL1
UARTDATA1

Result
sys.ctl_regs =
0. UARTCTL1
1. UARTDATA1
2. UARTCTL2
3. UARTDATA2
4. UARTDATA1
5. UARTCTL2
6. UARTCTL2
7. UARTCTL1
8. UARTDATA1
Note If the file is not accessible, you will see a runtime error with the name of the missing file. If there
is a typo in the file, you will see a runtime error message like the following:
*** Error: Enum type 'reg_address' has no item called 'UARTCTL'

See Also
• “Automatic Type Casting” on page 3-29
• “e Data Types” on page 3-1
• is [not] a on page 2-88

3.8.3 all_values()

Purpose
Access all values of a scalar type

Category
Pseudo routine

3-52 e Language Reference


Data Types
all_values()

Syntax
all_values(scalar-type: type name): list of scalar type

Syntax Example
print all_values(reg_address);

Parameters

scalar-type Any legal e scalar type.

Description
Returns a list that contains all the legal values of the specified scalar type. When that type is an
enumerated type, the order of the items is the same as the order in which they were defined. When the
type is a numeric type, the order of the items is from the smallest to the largest.

Note
When the specified type has more than 1million legal values, this routine gives a compile time error to
alert you to possible memory abuse.

Example
type reg_address: [UARTCTL1, UARTDATA1, UARTCTL2, UARTDATA2];
extend sys {
ctl_regs: list of reg_address;

keep ctl_regs ==
all_values(reg_address).all(it.as_a(string) ~"*CTL*");
run() is also {
print sys.ctl_regs;
};
};

Result
Running the test ...
sys.ctl_regs =
0. UARTCTL1
1. UARTCTL2

e Language Reference 3-53


Data Types
all_values()

3-54 e Language Reference


4 Structs, Fields, and Subtypes
The basic organization of an e program is a tree of structs. A struct is a compound type that contains data
fields, procedural methods, and other members. It is the e equivalent of a class in other object-oriented
languages. A base struct type can be extended by adding members. Subtypes can be created from a base
struct type which inherit the base type’s members, and contain additional members.

This chapter contains the following sections:

• “Structs Overview” on page 4-2


• “Defining Structs” on page 4-2
• “Extending Structs” on page 4-6
• “Extending Subtypes” on page 4-9
• “Defining Fields” on page 4-11
• “Defining List Fields” on page 4-14
• “Creating Subtypes with When” on page 4-21
• “Extending When Subtypes” on page 4-25
• “Defining Attributes” on page 4-28
• “Comparison of When and Like Inheritance” on page 4-33

See Also
• “Syntactic Elements” on page 2-12
• “Struct Hierarchy and Name Resolution” on page 2-23
• “e Data Types” on page 3-1

e Language Reference 4-1


Structs, Fields, and Subtypes
Structs Overview

• “Constructs for Defining and Extending Scalar Types” on page 3-31


• Chapter 11 “Generation Constraints”
• Chapter 7 “Methods”
• Chapter 23 “List Pseudo-Methods”
• Chapter 12 “Events”
• Chapter 14 “Temporal Struct Members”
• Chapter 16 “Coverage Constructs”

4.1 Structs Overview


Structs are used to define data elements and behavior of components of a test environment. A struct can
hold all types of data and methods.

All user-defined structs inherit from the Specman predefined base struct type, any_struct.

For reusability of e code, you can add struct members or change the behavior of a previously defined
struct with extend.

Inheritance is implemented in e by either of two of aspects of a struct definition:

• “when” inheritance is specified by defining subtypes with when struct members


• “like” inheritance is specified with the like clause in new struct definitions
The best inheritance methodology for most applications is “when” inheritance. See “Comparison of
When and Like Inheritance” on page 4-33 for more information.

4.2 Defining Structs

4.2.1 struct

Purpose
Define a data struct

Category
Statement

4-2 e Language Reference


Structs, Fields, and Subtypes
Defining Structs

Syntax
struct struct-type [like base-struct-type] {
[struct-member; …]}

Syntax Example
type packet_kind: [atm, eth];
struct packet {
len: int;
keep len < 256;
kind: packet_kind;
};

Parameters

struct-type The name of the new struct type.

base-struct-type The type of the struct from which the new struct inherits its
members.

struct-member; … The contents of the struct. The following are types of struct
members:

• data fields for storing data


• methods for procedures
• events for defining temporal triggers
• coverage groups for defining coverage points
• when, for specifying inheritance subtypes
• declarative constraints for describing relations between data
fields
• on, for specifying actions to perform upon event occurrences
• expect, for specifying temporal behavior rules
The definition of a struct can be empty, containing no members.

Description
Structs are used to define the data elements and behavior of components and the test environment.
Structs contain struct members of the types listed in the Parameters table. Struct members can be
conditionally defined (see “Creating Subtypes with When” on page 4-21).

e Language Reference 4-3


Structs, Fields, and Subtypes
Defining Structs

The optional like clause is an inheritance directive. All struct members defined in base-struct-type are
implicitly defined in the new struct subtype, struct-type. New struct members can also be added to the
inheriting struct subtype, and methods of the base struct type can be extended in the inheriting struct
subtype.

Example 1
A struct type named “transaction” is defined in this example.
struct transaction {
address: uint;
data: list of uint;
transform(multiple:uint) is empty;
};

The “transaction” struct contains three members:

• “address” field
• “data” field
• “transform()” empty method definition

Example 2
In this example, a “pci_transaction” struct is derived from the “transaction” struct in the previous
example, using like inheritance. The following struct members are added in this inherited struct:

• Fields named “command”, “dual_address”, and “bus_id”


(a type statement is included, to enumerate values for the “command” field)
• A keep constraint
• A when conditional subtype
• An event definition
• An on member
• A cover group definition
The “transform()” method, defined as empty in the “transaction” base type, is given a method body
using the is only method extension syntax.
type PCICommandType: [ IO_READ=0x2, IO_WRITE=0x3,
MEM_READ=0x6, MEM_WRITE=0x7 ];
struct pci_transaction like transaction {
command : PCICommandType;
keep soft data.size() in [0..7];

4-4 e Language Reference


Structs, Fields, and Subtypes
Defining Structs

dual_address: bool;
when dual_address pci_transaction {
address2: uint;
};
bus_id: uint;
event initiate;
on initiate {
out("An event has been initiated on bus ", bus_id);
};
cover initiate is {
item command;
};
transform(multiple:uint) is only {
address = address * multiple;
};
};

Example 3
Additional subtypes can, in turn, be derived from a subtype. In the following example, an
“agp_transaction” subtype is derived from the “pci_transaction” subtype of the previous example. Each
subtype can add fields to its base type, and place its own constraints on fields of its base type.
type AGPModeType: [AGP_2X, AGP_4X];
struct agp_transaction like pci_transaction {
block_size: uint;
mode: AGPModeType;
when AGP_2X agp_transaction {
keep block_size == 32;
};
when AGP_4X agp_transaction {
keep block_size == 64;
};
};

See Also
• “Struct Members” on page 2-15
• “Extending Structs” on page 4-6
• “Extending Subtypes” on page 4-9
• “Creating Subtypes with When” on page 4-21
• “Comparison of When and Like Inheritance” on page 4-33

e Language Reference 4-5


Structs, Fields, and Subtypes
Extending Structs

• Chapter 3 “Data Types”


• Chapter 7 “Methods”
• Chapter 11 “Generation Constraints”
• Chapter 12 “Events”
• Chapter 14 “Temporal Struct Members”
• Chapter 16 “Coverage Constructs”

4.3 Extending Structs

4.3.1 extend type

Purpose
Extend an existing data struct

Category
Statement

Syntax
extend [struct-subtype] base-struct-type {
[struct-member; …]}

Syntax Example
type packet_kind: [atm, eth];
struct packet {
len: int;
kind: packet_kind;
};
extend packet {
keep len < 256;
};

4-6 e Language Reference


Structs, Fields, and Subtypes
Extending Structs

Parameters

struct-subtype Adds struct members to the specified subtype of the base struct type only. The
added struct members are known only in that subtype, not in other subtypes.

base-struct-type The base struct type to extend.

member; … The contents of the struct. A struct member is one of the following types:

• data fields for storing data


• methods for procedures
• events for defining temporal triggers
• coverage groups for defining coverage points
• when, for specifying inheritance subtypes
• declarative constraints for describing relations between data fields
• on, for specifying actions to perform upon event occurrences
• expect, for specifying temporal behavior rules

The extension of a struct can be empty, containing no members.

Description
Adds struct members to a previously defined struct or struct subtype.

Members added to the base struct type in extensions apply to all other extensions of the same struct.
Thus, for example, if you extend a method in a base struct with is only, it overrides that method in every
one of the like children.

Notes
If like inheritance has been used on a struct type, there are limitations on how the original base struct
type definition can be further extended with extend. See “Restrictions on Like Inheritance” on page 4-41.

Example 1
In the following example, a struct type named “pci_transaction” is defined in one module, which is then
imported into another module where a field named “data_phases” and two constraints are added in an
extension to the struct.
<'
// module pci_transaction_definition.e
type PCICommandType: [ IO_READ=0x2, IO_WRITE=0x3,
MEM_READ=0x6, MEM_WRITE=0x7 ];
struct pci_transaction {

e Language Reference 4-7


Structs, Fields, and Subtypes
Extending Structs

address: uint;
data: list of uint;
command : PCICommandType;
bus_id: uint;
event initiate;
on initiate {
out("An event has been initiated on bus ", bus_id);
};
cover initiate is {
item command;
};
};
'>

<'
// module pci_transaction_extension.e
import pci_transaction_definition;
extend pci_transaction {
data_phases: uint;
keep data_phases in [0..7];
keep data.size() == data_phases;
};
'>

Example 2
In the following, the “tx_packet” struct inherits its kind field from the “packet” struct definition, from
which it is derived using like inheritance. The “keep kind == atm” constraint in the packet struct
extension applies to both packet instances and tx_packet instances. The “keep len > 10” constraint in the
tx_packet subtype applies only to tx_packet instances, reducing the range of len in tx_packet instances
to [11..40]:
type packet_kind: [atm, eth];
struct packet {
len: int;
keep soft len <= 40;
kind: packet_kind;
};
struct tx_packet like packet {
send_delay: int [0..100];
keep len > 10;
};
extend packet {
keep kind == atm;
};

4-8 e Language Reference


Structs, Fields, and Subtypes
Extending Subtypes

See Also
• “Defining Structs” on page 4-2
• “Extending Subtypes” on page 4-9
• “Creating Subtypes with When” on page 4-21
• “Comparison of When and Like Inheritance” on page 4-33
• Chapter 3 “Data Types”
• Chapter 7 “Methods”
• Chapter 11 “Generation Constraints”
• Chapter 12 “Events”
• Chapter 14 “Temporal Struct Members”
• Chapter 16 “Coverage Constructs”

4.4 Extending Subtypes


A struct subtype is an instance of the struct in which one of its fields has a particular value. For example,
the “packet” struct defined in the following example has “atm packet” and “eth packet” subtypes,
depending on whether the “kind” field is “atm” or “eth”.
type packet_kind: [atm, eth];
struct packet {
len: int;
kind: packet_kind;
};
extend packet {
keep len < 256;
};

A struct subtype can optionally be specified with extend, so that the extension only applies to that
subtype.

Example 1
The following shows a definition of a struct type named “packet”, an extension that adds a field named
“len” to the struct definition, and a second extension that adds a field named “transmit_size” only to
packets whose “kind” is “transmit”.
type packet_kind: [transmit, receive];
struct packet {
kind: packet_kind;

e Language Reference 4-9


Structs, Fields, and Subtypes
Extending Subtypes

};
extend packet {
len: int;
};
extend transmit packet {
transmit_size: int;
};

The “extend transmit packet” syntax above is equivalent to:


extend packet {
when transmit packet {
transmit_size: int;
};
};

Example 2
The “packet” struct definition below is extended with a Boolean field named “legal”. Two additional
extensions add a field named “header” to the packet struct: for packets whose “legal” value is TRUE, the
“header” field gets a “legal_header” struct instance. For packets whose “legal” values is FALSE, the
“header” field gets a “bad_header” struct instance.
type packet_kind: [atm, eth];
struct packet {
len: int;
keep soft len == 40;
kind: packet_kind;
};

extend packet{
legal: bool;
};

struct legal_header {
legal_ck: byte;
};

struct bad_header {
bad_ck: byte;
};

extend legal packet {


header: legal_header;
};
extend FALSE'legal packet {

4-10 e Language Reference


Structs, Fields, and Subtypes
Defining Fields

header: bad_header;
};

See Also
• “Defining Structs” on page 4-2
• “Extending Structs” on page 4-6
• “Creating Subtypes with When” on page 4-21
• “Extending When Subtypes” on page 4-25

4.5 Defining Fields

4.5.1 field

Purpose
Define a struct field

Category
Struct member

Syntax
[!][%] field-name[: type] [[min-val .. max-val]] [((bits | bytes):num)]

Syntax Example
type NetworkType: [IP=0x0800, ARP=0x8060] (bits: 16);
struct header {
address: uint (bits: 48);
hdr_type: NetworkType;
!counter: int;
};

Parameters

! Denotes an ungenerated field. The “!” and “%” options can be used together,
in either order.

e Language Reference 4-11


Structs, Fields, and Subtypes
Defining Fields

% Denotes a physical field. The “!” and “%” options can be used together, in
either order.

field-name The name of the field being defined.

type The type for the field. This can be any scalar type, string, struct, or list.
If the field name is the same as an existing type, you can omit the “: type” part
of the field definition. Otherwise, the type specification is required.

min-val..max-val An optional range of values for the field, in the form. If no range is specified,
the range is the default range for the field’s type.

(bits | bytes: num) The width of the field in bits or bytes. This syntax allows you to specify a
width for the field other than the default width.
This syntax can be used for any scalar field, even if the field has a type with a
known width.

Description
Defines a field to hold data of a specific type. You can specify whether it is a physical field or a virtual
field, and whether the field is to be automatically generated. For scalar data types, you can also specify
the size of the field in bits or bytes.

Note You can reference a field before it is declared as long as the declaration of the field is in the same
file. In the case of cyclic import, the field may be declared in one of the current set of imported files.

Physical Fields
A field defined as a physical field (with the “%” option) is packed when the struct is packed. Fields that
represent data that is to be sent to the HDL device in the simulator or that are to be used for memories in
the simulator or in Specman, need to be physical fields. Nonphysical fields are called virtual fields and
are not packed automatically when the struct is packed, although they can be packed individually.

If no range is specified, the width of the field is determined by the field’s type. For a physical field, if the
field’s type does not have a known width, you must use the (bits | bytes : num) syntax to specify the
width.

Ungenerated Fields
A field defined as ungenerated (with the “!” option) is not generated automatically. This is useful for
fields that are to be explicitly assigned during the test, or whose values involve computations that cannot
be expressed in constraints.

4-12 e Language Reference


Structs, Fields, and Subtypes
Defining Fields

Ungenerated fields get default initial values (0 for scalars, NULL for structs, empty list for lists). An
ungenerated field whose value is a range (such as [0..100]) gets the first value in the range. If the field is
a struct, it will not be allocated and none of the fields in it will be generated.

Assigning Values to Fields


Unless you define a field as ungenerated, Specman will generate a value for it when the struct is
generated, subject to any constraints that exist for the field. However, even for generated fields, you can
always assign values in user-defined methods or predefined methods such as init(), pre_generate(), or
post_generate(). The ability to assign a value to a field is not affected by either the “!” option or
generation constraints.

Example
The struct definitions below contain several types of fields.
type NetworkType: [IP=0x0800, ARP=0x8060] (bits: 16);
struct header {
%address: uint (bits: 48);
%length: uint [0 .. 32];
};
struct packet {
hdr_type: NetworkType;
%hdr: header;
is_legal: bool;
!counter: uint;
};
extend sys {
packet;
};

The “header” struct contains two physical fields:

• A field named “address” which is a 48-bit field of data type uint


• A field named “length” of data type uint
The “packet” struct contains:

• An enumerated “hdr_type” field that can be either “IP” or “ARP”


• A physical field named “hdr” of type “header”, which will hold an instance of the “header” struct
• A Boolean “is_legal” field
• An ungenerated uint field named “counter”

e Language Reference 4-13


Structs, Fields, and Subtypes
Defining List Fields

The sys struct extension contains a field for an instance of a “packet” struct. No type declaration is
required for the “packet” field in the sys extension, since the field name is the same as the name of a type
that was already defined.

See Also
• Chapter 3 “Data Types”
• Chapter 11 “Generation Constraints”
• Chapter 18 “Packing and Unpacking”
• list of on page 4-14

4.6 Defining List Fields


This section shows the syntax and examples of lists in general, and of keyed lists. It contains these
topics:

• list of on page 4-14


• list(key) of on page 4-17

4.6.1 list of

Purpose
Define a list field

Category
Struct member

Syntax
[!][%]list-name[[length-exp]]: list of type

Syntax Example
packets: list of packet;

4-14 e Language Reference


Structs, Fields, and Subtypes
list of

Parameters

! Do not generate this list. The “!” and “%” options can be used together, in either
order.

% Denotes a physical list. The “!” and “%” options can be used together, in either
order.

list-name The name of the list being defined.

length-exp An expression that gives the initial size for the list. The expression must evaluate to
a non-negative integer.

type The type of items in the list. This can be any scalar type, string, or struct. It cannot
be a list.

Description
Defines a list of items of a specified type.

An initial size can be specified for the list. The list initially contains that number of items. The size
conforms to the initialization rules, the generation rules and the packing rules. Even if an initial size is
specified, the list size can change during the test if the list is operated on by a list method that changes
the number of items.

All list items are initialized to their default values when the list is created. For a generated list, the initial
default values are replaced by generated values.

For information about initializing list items to particular values, see “Assignment of Lists” on page 3-24
and “Constraining Lists” on page 11-11.

Example 1
Three list fields are defined in the struct definitions below. The “cell” struct contains a list of bytes, the
“packet” struct contains a list of “cell” struct instances, and the sys struct extension contains a list of 16
“packet” struct instances.
struct cell {
%data: list of byte;
%length: uint;
};
struct packet {
%is_legal: bool;
cells: list of cell;
};
extend sys {

e Language Reference 4-15


Structs, Fields, and Subtypes
list of

packets[16]: list of packet;


};

Example 2
Two lists of cells are defined in this following example, both with initial sizes specified using the
[length] syntax. For the cells_1 list, the length expression is a value generated from within the 16 to 32
range specified for the num_cells field. For the cells_2 list, the length expression is the integer value of
an item from the enumerated list named l_sel (sm has value 0, med has value 1, lge has value 3 due to
their positions in the enumerated list).
struct cell {
%data: list of byte;
%length: uint;
};
struct packet {
%is_legal: bool;

num_cells: int;
keep num_cells in [16..32];
cells_1[num_cells]: list of cell;

l_sel: [sm, med, lge];


cells_2[l_sel.as_a(int)]: list of cell;
};

See Also
• field on page 4-11
• “Expressions” on page 2-23
• Chapter 3 “Data Types”
• Chapter 11 “Generation Constraints”
• Chapter 18 “Packing and Unpacking”
• Chapter 23 “List Pseudo-Methods”

4-16 e Language Reference


Structs, Fields, and Subtypes
list(key) of

4.6.2 list(key) of

Purpose
Define a keyed list field

Category
Struct member

Syntax
![%]list-name: list(key: key-field) of type

Syntax Example
!locations: list(key: address) of location;

Parameters

! Do not generate this list. For a keyed list, the “!” is required, not optional.

% Denotes a physical list. The “%” option may precede or follow the “!”.

list-name The name of the list being defined.

key-field The key of the list. For a list of structs, it is the name of a field of the struct. For a list
of scalar or string items, it is the item itself, represented by the it variable.
This is the field or value which the keyed list pseudo-methods will check when they
operate on the list.

type The type of items in the list. This can be any scalar type, string, or struct. It cannot
be a list.

Description
Keyed lists are used to enable faster searching of lists by designating a particular field or value which is
to be searched for. A keyed list can be used, for example, in the following ways:

• As a hash table, in which searching only for a key avoids the overhead of reading the entire contents
of each item in the list.

e Language Reference 4-17


Structs, Fields, and Subtypes
list(key) of

• For a list that has the capacity to hold many items, but which in fact contains only a small percentage
of its capacity, randomly spread across the range of possible items. An example is a sparse memory
implementation.

Although all of the operations that can be done using a keyed list can also be done using a regular list,
using a keyed list provides an advantage in the greater speed of searching a keyed list.

Besides the key parameter, the keyed list syntax differs from regular list syntax in the following ways:

• The list must be declared with the “!” do-not-generate operator. This means that you must build a
keyed list item by item, since you cannot generate it.
• The “[exp]” list size initialization syntax is not allowed for keyed lists. That is, “list[exp]: list(key:
key) of type” is not legal. Similarly, you cannot use a keep constraint to constrain the size of a keyed
list.

The keyed list pseudo-methods (see “Keyed List Pseudo-Methods” on page 23-91) only work on lists that
were defined and created as keyed lists. Conversely, restrictions apply when using regular list
pseudo-methods or other operations on keyed lists. See “Restrictions on Keyed Lists” on page 23-98.

A keyed list is a distinct type, different from a regular list. This means that you cannot assign a keyed list
to a regular list, nor assign a regular list to a keyed list: if list_a is a keyed list and list_b is a regular list,
list_a = list_b is a syntax error.

If the same key value exists in more than one item in a keyed list, the behavior of the keyed list
pseudo-methods is undefined.

Example 1
In the following example, the list named cl is declared to be a keyed list of four-bit uints, with the key
being the list item itself. That is, the key is the value of a four-bit uint. A list of 10 items is built up by
generating items and adding them to the keyed list in the for loop.

In the if action, the list.key_exists() and list.key_index() keyed list pseudo-methods are used to check
for the existence of an item with the value of 8, and to print the list and the key value’s index if it exists.
<'
extend sys {
!cl: list(key: it) of uint(bits: 4);
run() is also {
var ch: uint(bits: 4);
for i from 0 to 10 {
gen ch;
cl.add(ch);
};
if cl.key_exists(8) then {
print cl;

4-18 e Language Reference


Structs, Fields, and Subtypes
list(key) of

print cl.key_index(8);
};
};
};
'>

Results
cl = (10 items, dec):
13 5 4 11 9 14 3 8 5 4 .0

cl.key_index(8) = 2

Example 2
In the following example, the struct type named s has fields a and b. A keyed list of s structs, with the n
field as the key, is declared in the sys extension, and the list is built by the bl() method.

In the run() method, the list.key_exists() keyed list pseudo-method is used to check whether the value
98 occurs in the n field in any of the structs in the keyed list. It so happens that the n value in the fourth
struct in the list (index 3) is 98. Other keyed list pseudo-methods are then used to print the struct instance
and the list index number of the struct that has n equal to 98.

Note that two list instances, index 12 and index 15, have the value 95 for n. If 95 was entered as the key
value for the list.key_exists() and list.key_index() pseudo-methods, those methods would use the last
instance, that is index number 15, and ignore the instance with index 12.
<'
struct s {
n: byte;
b: bit;
};

extend sys {
!sl: list(key: n) of s;
bl() is {
for i from 0 to 15 {
var t: s;
gen t;
sl.add(t);
};
};
run() is also {
bl();
print sl;
var b: bool;

e Language Reference 4-19


Structs, Fields, and Subtypes
list(key) of

b = sl.key_exists(98);
print b;
if b {
print sl.key(98);
print sl.key_index(98);
};
};
};
'>

Results
sl =
item type n b

0. s 109 0
1. s 122 0
2. s 133 1
3. s 98 0
4. s 163 0
5. s 196 0
6. s 159 0
7. s 223 1
8. s 118 1
9. s 192 1
10. s 22 1
11. s 170 1
12. s 95 0
13. s 153 1
14. s 169 0
15. s 95 0
b = TRUE
sl.key(98) = s-@0: s
@tmp
0 n: 98
1 b: 0
sl.key_index(98) = 3

Example 3
In the following example, a keyed list is used to model sparse memory. A struct type named location has
address and value fields. A keyed list named locations, with address as the key, is used to hold instances
of location structs generated in the while loop. For each new location struct generated, the
list.key_exists() pseudo-method checks to see if the list already contains an instance with that address
value. If it is not already in the list, the new instance is added to the list.This ensures that the keyed list
will contain exactly LLEN (50) items, all with different address values.

4-20 e Language Reference


Structs, Fields, and Subtypes
Creating Subtypes with When

<'
define LLEN 50;

struct location {
address: uint(bits: 8);
value: int;
};

extend sys {
!locations: list(key: address) of location;
post_generate() is also {
var loc: location = new;
while locations.size() < LLEN do {
gen loc;
if locations.key_exists(loc.address) == FALSE then {
locations.add(loc);
};
};
};
};
'>

See Also
• “Keyed Lists” on page 3-15
• “Keyed List Pseudo-Methods” on page 23-91

4.7 Creating Subtypes with When


The when struct member creates a conditional subtype of the current struct type, if a particular field of
the struct has a given value. This is called “when” inheritance, and is one of two techniques Specman
provides for implementing inheritance. The other is called “like” inheritance. When inheritance is
described in this section. Like inheritance is described in “struct” on page 4-2.

When inheritance is the recommended technique for modeling in Specman. Like inheritance is more
appropriate for procedural testbench programming. When and like inheritance are compared in
“Comparison of When and Like Inheritance” on page 4-33.

e Language Reference 4-21


Structs, Fields, and Subtypes
Creating Subtypes with When

4.7.1 when

Purpose
Create a subtype

Category
Struct member

Syntax
when struct-subtype base-struct-type
{struct-member; …}

Syntax Example
struct packet {
len: uint;
good: bool;
when FALSE'good packet {
pkt_msg() is {
out("bad packet");
};
};
};

Parameters

struct-subtype A subtype declaration in the form type-qualifier'field-name.


The type-qualifier is one of the legal values for the field named by field-name.
If the field-name is a Boolean field, and its value is TRUE for the subtype, you
can omit type-qualifier. That is, if “big” is a Boolean field, “big” is the same
as “TRUE'big”.
The field-name is the name of a field in the base struct type. Only Boolean or
enumerated fields can be used. If the field type is Boolean, the type qualifier
must be TRUE or FALSE. If the field type is enumerated, the qualifier must
be a value of the enumerated type. If the type qualifier can apply to only one
field in the struct, you can omit 'field-name.
More than one type-qualifier'field-name combination can be stated, to create
a subtype based on more than one field of the base struct type.

4-22 e Language Reference


Structs, Fields, and Subtypes
Creating Subtypes with When

base-struct-type The struct type of the current struct (in which the subtype is being created).

struct-member Definition of a struct member for the struct subtype. One or more new struct
members can be defined for the subtype.

Description
You can use the when construct to create families of objects, in which multiple subtypes are derived
from a common base struct type.

A subtype is a struct type in which specific fields of the base struct have particular values. For example:

• If a struct type named “packet” has a field named “kind” that can have a value of “eth” or “atm”, then
two subtypes of “packet” are “eth packet” and “atm packet”.
• If the “packet” struct has a Boolean field named “good”, two subtypes are “FALSE’good packet”
and “TRUE’good packet”.

Subtypes can also be combinations of fields, such as “eth TRUE’good packet” and
“eth FALSE’good packet”.

Struct members you define in a when construct can be accessed only in the subtype, not in the base
struct. This provides a way to define a subtype that has some struct members in common with the base
type and all of its other subtypes, but has other struct members that belong only to the current subtype.

Note
Once you have used like inheritance to create a subtype of a base struct type, you cannot extend the base
type using when.

Example 1
An instance of the “packet” struct below can have a “kind” of either “transmit” or “receive”. The when
construct creates a “transmit packet” subtype. The “length” field and the print() method apply only to
packet instances that have “kind” values of “transmit”.
type packet_kind: [transmit, receive];
struct packet {
kind: packet_kind;
when transmit packet {
length: int;
print() is {
out("packet length is: ", length);
};
};

e Language Reference 4-23


Structs, Fields, and Subtypes
Creating Subtypes with When

};

Example 2
The “op1” field in the struct definition below can have one of the enumerated “reg_n” type values
(REG0, REG1, REG2, or REG3). The “kind” field can have a value of “imm” or “reg”, and the “dest”
field can have a value of “mm_1” or “reg”.

The “REG0'op1” subtype specification in the first when construct creates a subtype of instances in
which the “op1” value is “REG0”. This subtype has all the “instr” struct fields plus a “print_op1()”
method.

The “reg'kind” subtype specification in the second when construct creates a subtype of instances in
which the “kind” value is “reg”. This subtype also has all the “instr” struct fields plus a “print_kind()”
method.

It is necessary to add the “'kind” expression in the second when construct because the “dest” field can
also have a value of reg, which means that “reg” is ambiguous without the further specification of the
field name.
type reg_n : [REG0, REG1, REG2, REG3];
struct instr {
%op1: reg_n;
kind: [imm, reg];
dest: [mm_1, reg];
};
extend instr {
when REG0'op1 instr {
print_op1() is {
out("instr op1 is REG0");
};
};
when reg'kind instr {
print_kind() is {
out("instr kind is reg");
};
};
};

See Also
• “Defining Structs” on page 4-2
• “Comparison of When and Like Inheritance” on page 4-33
• is [not] a on page 2-88

4-24 e Language Reference


Structs, Fields, and Subtypes
Extending When Subtypes

4.8 Extending When Subtypes


There are two general rules governing the extensions of when subtypes:

• If a struct member is declared in the base struct, it cannot be re-declared in any when subtype, but it
can be extended.
• With the exception of coverage groups and the events associated with them, any struct member defined
in a when subtype does not apply or is unknown in other subtypes, including:
• fields
• constraints
• events
• methods
• on
• expect
• assume

4.8.1 Coverage and When Subtypes


All coverage events must be defined in the base struct. Defining the ready3 event within the ADD
subtype, for example, results in a load time error. Coverage groups can be defined in the base struct or in
the subtype.
struct operation {
opcode: [ADD, SUB];
op1: uint;
op2: uint;
op3: uint;

event ready is rise('top.ready');


event ready3 is rise('top.op3ready'); // Must define here

cover ready is {
item op1;
item op2;
cross op1, op2;
};
};
extend operation {
when ADD operation {
// event ready3 is rise('top.op3ready'); // Can't define here

cover ready3 is {
item op1;

e Language Reference 4-25


Structs, Fields, and Subtypes
Extending Methods in When Subtypes

item op2;
item op3;
cross op1, op2, op3;
};
};

};

4.8.2 Extending Methods in When Subtypes


A method defined or extended within a when construct is executed in the context of the subtype and can
freely access the unique struct members of the subtype with no need for any casting.

When a method is declared in a base type, each extension of the method in a subtype must have the same
parameters and return type as the original declaration. For example, because do_op() is defined with two
parameters in the base type, extending do_op() in the ADD subtype to have three parameters results in a
load time error.
struct operation {
opcode: [ADD, ADD3];
op1: uint;
op2: uint;

do_op(op1: uint, op2: uint): uint is {


return op1 + op2;
};
};

extend operation {
when ADD3 operation {
op3: uint;
// do_op(op1:uint,op2:uint,op3:uint): uint is { // Load time error
// return op1 + op2 +op3;
// };
};
};

However, if a method is not declared in the base type, each definition of the method in a subtype can
have different parameters and return type. The following variation of the example above loads without
error.
struct operation {
opcode: [ADD, ADD3];
op1: uint;
op2: uint;
};

4-26 e Language Reference


Structs, Fields, and Subtypes
Extending Methods in When Subtypes

extend operation {
when ADD operation {
do_op(op1: uint, op2: uint): uint is {
return op1 + op2;
};
};
when ADD3 operation {
op3: uint;
do_op(op1:uint,op2:uint,op3:uint): uint is {
return op1 + op2 +op3;
};
};
};

If more than one method of the same name is known in a when subtype, any reference to that method is
ambiguous and results in a load-time error. In the following example, the legal ethernet packet subtype
inherits two definitions of the method show(). The error is not reported when the ambiguity becomes
possible (when the legal ethernet packet subtype is extended) but when the reference to the show()
method is made.
type protocol: [ethernet, ieee, foreign];
struct packet {
legal: bool;
protocol;

when legal packet {


show() is {out("it is a legal packet")};
};

when ethernet packet {


show() is {out("it is a ethernet packet")};
};

when legal ethernet packet{


le:uint;
};
};

extend sys {
packets: list of packet;
post_generate() is {
// for each legal ethernet packet (p) in packets {
// p.show(); // Load-time error
// };
};
};

e Language Reference 4-27


Structs, Fields, and Subtypes
Defining Attributes

To remove the ambiguity from such a reference, use the as_a() type casting operator or the when
subtype qualifier syntax:
p.as_a(legal packet).show();
break on call legal packet.show()
Note Method calls are checked when the e code is parsed. If there is no ambiguity, the method to be
called is selected and all similar references are resolved in the same manner. In the example above, the
extension to ethernet packet could be placed in a separate file like this:
extend packet {
when ethernet packet {
show() is {out("it is a ethernet packet")};
};
};

If this file is loaded after the rest of the e code has been loaded, no error is issued because the method call
to p.show() was resolved when the first file was loaded. Any call to p.show() always prints:
it is a legal packet

See Also
• “Defining Structs” on page 4-2
• “Extending Structs” on page 4-6
• “Extending Subtypes” on page 4-9
• “Creating Subtypes with When” on page 4-21
• “Rules for Defining and Extending Methods” on page 7-2

4.9 Defining Attributes


You can define attributes that control how a field behaves when it is copied or compared. These attributes
are used by deep_copy(), deep_compare(), and deep_compare_physical().

4.9.1 attribute field

Purpose
Define the behavior of a field when copied or compared

4-28 e Language Reference


Structs, Fields, and Subtypes
Defining Attributes

Category
Struct member

Syntax
attribute field-name attribute-name = exp

Syntax Example
attribute channel deep_copy = reference;

Parameters

field-name The name of a field in the current struct.

attribute-name is one of the following:

deep_copy Controls how the field is copied by the deep_copy() routine.

deep_compare Controls how the field is compared by the deep_compare() routine.

deep_compare_physical Controls how the field is compared by the


deep_compare_physical() routine.

deep_all Controls how the field is copied by the deep_copy() routine or


compared by the deep_compare() or deep_compare_physical()
routines.

exp is one of the following:

normal Perform a deep (recursive) copy or comparison.

reference Perform a shallow (non-recursive) copy or comparison.

ignore Do not copy or compare.

Description
Defines how a field behaves when copied or compared. For a full description of the behavior specified by
each expression, see the description of the deep_copy() on page 24-2, deep_compare() on page 24-5,
or deep_compare_physical() on page 24-11 routine.

The attribute construct can appear anywhere, including inside a when construct or an extend construct.

e Language Reference 4-29


Structs, Fields, and Subtypes
Defining Attributes

To determine which attributes of a field are valid, Specman scans all extensions to a unit or a struct in the
order they were loaded. If several values are specified for the same attribute of the same field, the last
attribute specification loaded is the one that is used.

Example
This example shows the effects of field attributes on the deep_copy() and deep_compare() routines. An
instance of “packet”, which contains three fields of type “port” (also a struct type), is deep copied and
then deep compared. Because each of the three “port” fields has a different attribute, the way each field
is copied and compared is also different.
<'
struct port {
%counter: int;
};

struct packet {
%parent: port;
attribute parent deep_all = reference;

%origin: port;
attribute origin deep_copy = ignore;

%dest: port;
attribute dest deep_copy = normal;
attribute dest deep_compare = ignore;
attribute dest deep_compare_physical = ignore;

%length: int;
};

extend sys {
run() is also {
var port1: port = new port;
var port2: port = new port;
var port3: port = new port;

var packet1: packet = new packet with {


.parent = port1;
.origin = port2;
.dest = port3;
};

var packet2: packet = deep_copy(packet1);

out("");

4-30 e Language Reference


Structs, Fields, and Subtypes
Defining Attributes

out("parent of packet1 is : ", packet1.parent);


out("parent of packet1 should be: ",
port1, " original copy");
out("");

out("parent of packet2 is : ", packet2.parent);


out("parent of packet2 should be: ", port1,
" shallow copy");
out("");

out("origin of packet1 is : ", packet1.origin);


out("origin of packet1 should be: ", port2,
" original copy");
out("");

out("origin of packet2 is : ", packet2.origin);


out("origin of packet2 should be: \
a NULL port, attribute: copy: ignore");
out("");

out("dest of packet1 is : ", packet1.dest);


out("dest of packet1 should be: ", port3);
out("");

out("dest of packet2 is : ", packet2.dest);


out("dest of packet2 should be: a different \
port, attribute: copy: normal (deep)");
out("");

packet2.dest = new port; // force different field value

var ldiff: list of string =


deep_compare(packet1, packet2, UNDEF);
out(ldiff, "\n");
out("Notice a diff in the origin field, \
attribute is normal for deep_compare");
out("Notice no diff for the dest field, \
attribute is ignore for deep_compare");
out("");
};
};

'>

Results
Here are the results of running the packet example:

e Language Reference 4-31


Structs, Fields, and Subtypes
Defining Attributes

1 Specman > run


2 Running the test ...
3
4 parent of packet1 is : port-@0
5 parent of packet1 should be: port-@0 original copy
6
7 parent of packet2 is : port-@0
8 parent of packet2 should be: port-@0 shallow copy
9
10 origin of packet1 is : port-@1
11 origin of packet1 should be: port-@1 original copy
12
13 origin of packet2 is : (a NULL port)
14 origin of packet2 should be: a NULL port,
15 attribute: copy: ignore
16
17 dest of packet1 is : port-@2
18 dest of packet1 should be: port-@2
19
20 dest of packet2 is : port-@3
21 dest of packet2 should be: a different port,
22 attribute: copy: normal (deep)
23
24 Differences between packet-@4 and packet-@5
25 --------------------------------------------------
26 origin: port-@1 != (a NULL port)
27
28 Notice a diff in the origin field,
29 attribute is normal for deep_compare
30 Notice no diff for the dest field,
31 attribute is ignore for deep_compare

Lines 4-8 Because the parent field has the deep_all attribute reference, the parent field of the packet2
instance contains a pointer to the parent field of packet1 (port-@0).

Lines 10-15 Because the origin field has the deep_copy attribute ignore, the origin field of the packet2
instance contains a NULL instance of type port.

Lines 17-22 Because the dest field has the deep_copy attribute normal, the dest field of the packet2
instance contains a new instance of type port (port-@3).

Lines 24-26 These lines show the results of a deep_compare() of packet1 and packet2. Note that just
prior to this comparison, a new instance of type port was assigned to the dest field of packet2. However,
no difference is reported for the dest fields of the two packet instances, because the deep_compare
attribute of the dest field is ignore. A difference is reported for the origin field because the
deep_compare attribute is normal and the fields are not the equal.

4-32 e Language Reference


Structs, Fields, and Subtypes
Comparison of When and Like Inheritance

See Also
• deep_copy() on page 24-2
• deep_compare() on page 24-5
• deep_compare_physical() on page 24-11

4.10 Comparison of When and Like Inheritance


There are two ways to implement object-oriented inheritance in e:

• Like inheritance is the classical, single inheritance familiar to users of all object-oriented languages.
• When inheritance is a concept introduced by e. It is less familiar initially, but lends itself more easily
to the kind of modeling that people do in e.

This section discusses the pros and cons of both these types of inheritance and recommends when to use
each of them.

4.10.1 Summary of When versus Like


In general, “when” inheritance should be used for modeling all DUT-related data structures. It is
superior from a knowledge representation point of view and from an extensibility point of view. When
inheritance lets you:

• Explicitly reference a field that determines the when subtype


• Create multiple, orthogonal subtypes
• Use random generation to generate lists of objects with varying subtypes
• Easily extend the struct later
Although like inheritance has more restrictions than when inheritance, it is recommended in some
special cases because:

• Like inheritance is somewhat more efficient than when inheritance.


• Generation of objects that use like inheritance can also be more efficient.

4.10.2 A Simple Example of When Inheritance


You can create a when subtype of a generic struct using any field in the struct that is a Boolean or
enumerated type. This field, which determines the when subtype of a particular struct instance, is called
the when determinant. In the following example, the when determinant is “legal”.

e Language Reference 4-33


Structs, Fields, and Subtypes
A Simple Example of When Inheritance

struct packet {
legal: bool;

when legal packet {


pkt_msg() is {
out("good packet");
};
};
};
Note The following syntax is used in this document because it looks closer to the “like” version:
extend legal packet {…}

This syntax is exactly equivalent to the when construct:


extend packet {when legal packet {…}}

The following example shows a generic packet struct with 3 fields, protocol, size and data, and an
abstract method show(). In this example, the “protocol” field is the determinant of the when version of
the packet. That is, this field determines whether the packet instance has a subtype of “IEEE”,
“Ethernet”, or “foreign”. In this example. the Ethernet packet subtype is extended by adding a field and
extending the show() method.
type packet_protocol: [Ethernet, IEEE, foreign];
struct packet {
protocol: packet_protocol;
size: int [0..1k];
data[size]: list of byte;
show() is undefined; // To be defined by children
};
extend Ethernet packet {
e_field: int;
show() is {out("I am an Ethernet packet")};
};

Of course, it is possible for a struct to have more than one when determinant. In the following example,
the Ethernet packet subtype is extended with a field of a new enumerated type, Ethernet_op.
type Ethernet_op: [e1, e2, e3];
extend Ethernet packet { op: Ethernet_op; };
extend e1 Ethernet packet {
e1_foo: int;
show() is {out("I am an e1 Ethernet packet")};
};

4-34 e Language Reference


Structs, Fields, and Subtypes
A Simple Example of Like Inheritance

Because it is possible for a struct to have more than one when determinant, the inheritance tree for a
struct using when inheritance consists of any number of orthogonal trees, each rooted at a separate
enumerated or Boolean field in the struct. Figure 4-1 shows a when inheritance tree consisting of 3
orthogonal trees rooted in the legal, protocol, and op fields. Note that the when subtypes that have not
been explicitly defined, such as IEEE packet, exist implicitly.

Figure 4-1 When Inheritance Tree for Packet Struct Subtypes

packet
TRUE
legal
FALSE
protocol

IEEE Ethernet foreign

op

e1 e2 e3

4.10.3 A Simple Example of Like Inheritance


You can create a like child of a generic struct using the like construct. In this example, a child
Ethernet_packet is created from the generic struct packet and is extended by adding a field and extending
the show() method.
struct packet {
size: int [0..1k];
data[size]: list of byte;
show() is undefined; // To be defined by children
};
struct Ethernet_packet like packet {
e_field: int;
show() is {out("I am an Ethernet packet")};
};
...

e Language Reference 4-35


Structs, Fields, and Subtypes
Advantages of Using When Inheritance for Modeling

In the same way, you can create an IEEE_packet from packet using like:
struct IEEE_packet like packet {
i_field: int;
show() is {out("I am an IEEE packet")};
};

You can also easily create an e1_Ethernet_packet from Ethernet_packet using like inheritance.
struct e1_Ethernet_packet like Ethernet_packet {
e1_foo: int;
show() is {out("I am an e1 Ethernet packet")};
};

In contrast to the when inheritance tree, the like inheritance tree for the packet type is a single tree where
each subtype must be defined explicitly, as shown in Figure 4-2. This difference between the like and
when inheritance trees is the essential difference between like and when inheritance.

Figure 4-2 Like Inheritance Tree for Packet Struct Subtypes

packet

Ethernet_packet IEEE_packet

e1_Ethernet_packet

4.10.4 Advantages of Using When Inheritance for Modeling


While the like version and the when version look similar, and the “like” version may seem more natural
to people familiar with other object-oriented languages, the “when” version is much better for the kind
of modeling people do in Specman. There are several reasons for this, which are explained in more detail
below:

• “You can refer explicitly to the determinant fields”


• “You can create multiple orthogonal subtypes”
• “You can use random generation to create lists of objects with varying subtypes”
• “You can easily extend the struct later”

4-36 e Language Reference


Structs, Fields, and Subtypes
Advantages of Using When Inheritance for Modeling

• “You can create a new type by simple extension”

You can refer explicitly to the determinant fields


In the when version, the determinant of the when is an explicit field. In the like version, there is no
explicit field that determines whether a packet instance is an Ethernet packet, an IEEE packet, or a
foreign packet. The explicit determinant fields provide several advantages:

• Explicit determinant fields are more intuitive.


Fields are more tangible than types and correspond better to the way hardware engineers perceive
architectures. Having a field whose value determines what fields exist under it is familiar to
engineers. (It is similar to C unions, for example.)
• You can specify the attributes of determinants that are physical fields.
If the determinant is a physical field, you probably want to specify its size in bits, the mapping of
enumerated items to values, where it is in the order of fields, and so on. These things are done very
naturally with when inheritance, because the determinant is just another field. For example:
%protocol: packet_protocol (bits: 2);

• With like inheritance, you can define the same field as the when determinant, but you also have to
tie it to the type with code equivalent to the following:
var pkt: packet;
case protocol {
Ethernet {var epkt: Ethernet packet; gen epkt; pkt = epkt;};
IEEE {var ipkt: IEEE packet; gen ipkt; pkt = ipkt;};
};
There is an added inconvenience of having to generate or calculate protocol separately from the rest
of the packet.
• You can constrain the when determinant.
Using when inheritance, it is very natural to write constraints like these in a test:
keep protocol in [Ethernet, IEEE];
keep protocol != IEEE;
keep soft protocol == select { 20: IEEE; 80: foreign; };
keep packets.is_all_iterations(.protocol, ...);

Constraining the value of fields in various ways is a main feature of Specman generation. Doing the
same with like inheritance is more complicated. For example, the first constraint above might be
stated something like this:
keep me is an Ethernet_packet or me is an IEEE_packet;
// This pseudocode is not a legal constraint specification

e Language Reference 4-37


Structs, Fields, and Subtypes
Advantages of Using When Inheritance for Modeling

However, constraints like this can become quite complex in like inheritance. Furthermore, there is
no way to write the last two constraints.

You can create multiple orthogonal subtypes


Suppose each packet (of any protocol) can be either a normal (data) packet, an ack packet or a nack
packet, except that foreign packets are always normal:
type packet_kind: [normal, ack, nack];
extend packet {
kind: packet_kind;
keep protocol == foreign => kind == normal;
};
extend normal packet { n1: int; };
...

How do you do this in like inheritance? Disregard for now the issue of extending the packet struct later.
Assume that you know the requirement stated above in advance, and you want to model it using like
inheritance in the best possible way.

Here is one way:


struct normal_Ethernet_packet like Ethernet_packet {
n1: int;
};
struct ack_Ethernet_packet like Ethernet_packet { ... };
struct nack_Ethernet_packet like Ethernet_packet { ... };
struct normal_IEEE_packet like IEEE_packet { ... };
// ...

This requires eight declarations.

Then, the Ethernet_op possibilities must be taken into account:


struct ack_e1_Ethernet_packet like e1_Ethernet_packet { ... }
// ...

This works, but requires ((N1 * N2 * … * Nd) - IMP) declarations, where d is the number of orthogonal
dimensions, Ni is the number of possibilities in dimension i, and IMP is the number of impossible cases.

Another issue is how to represent the impossible cases.

Multiple inheritance would solve some of these problems, but would introduce new complications.

With when inheritance all the possible combinations exist implicitly, but you do not have to enumerate
them all. It is only when you want to say something about a particular one that you mention it, as in the
following examples:

4-38 e Language Reference


Structs, Fields, and Subtypes
Advantages of Using When Inheritance for Modeling

extend normal IEEE packet { ni_field: int; }; // Adds a field


extend ack e1 Ethernet packet { keep size == 0; };
// Adds a constraint

All in all, the when version is more natural from a knowledge representation point of view, because:

• It is immediately clear from the description what goes with what


• You only need to mention types if you have something to say about them

You can use random generation to create lists of objects with varying subtypes
The job of the generator is to create (in this example) packet instances. By default, all possible packets
should be generated. In both versions, you would create a list of packets. For example:
extend sys { packets: list of packet; };

However, the generator should only generate fully instantiated packets. In the when version, that
happens automatically—there is no other way.

With like inheritance, if you generate a parent struct, only that parent struct is created; none of the like
children are created. For example, the following gen action always creates a generic packet, never an
Ethernet packet or an IEEE packet:
pkt: packet;
gen pkt;

Thus, in practice you should only generate fields whose type is a leaf in the like inheritance tree. For
example, you normally write:
p: e1_Ethernet_packet;
gen p;

You can easily extend the struct later


There are some restrictions on extending structs that have like children. Details are in “Restrictions on
Like Inheritance” on page 4-41.

You can create a new type by simple extension


You can extend the packet_protocol type and add new members to the packet subtype, for example:
extend packet_protocol: [brand_new];
extend brand_new packet {
…new struct members…
};

e Language Reference 4-39


Structs, Fields, and Subtypes
Advantages of Using Like Inheritance

Automatically your old environment is able to generate brand_new packets. With like inheritance, you
have to find all instances of the procedural generation code and add the new case to the case statement.

4.10.5 Advantages of Using Like Inheritance


Like inheritance is a shorthand notation for a subset of when inheritance. It is restricted but more
efficient.

Like inheritance often has better performance than when inheritance for the following reasons:

• Method calling is faster for like inheritance.


• When generation is slower then like generation. This can be important if a large part of the total run
time is attributable to generation.
• When inheritance uses more memory because all of the fields of all of the when subtypes consume
space all the time.
Note If this becomes a problem in a particular design, there is a workaround. Rather than having
many separate fields under the when, put all the fields into a separate struct and put a single field for
that struct under the when. For example, the following coding style may use a lot of memory if there
are many fields declared under the Ethernet packet subtype.
type packet_protocol: [Ethernet, IEEE, foreign];
struct packet {
protocol: packet_protocol;
when Ethernet packet {
e_field0: int;
e_field1: int;
e_field2: int;
e_field3: int;
// ...
};
};
A more efficient coding style is shown below, where a single field is declared under the Ethernet
packet subtype.
type packet_protocol: [Ethernet, IEEE, foreign];
struct Ethernet_packet {
e_field0: int;
e_field1: int;
e_field2: int;
e_field3: int;
// ...
};
struct packet {
protocol: packet_protocol;

4-40 e Language Reference


Structs, Fields, and Subtypes
Restrictions on Like Inheritance

when Ethernet packet {


e_packet: Ethernet_packet;
};
};

When to Use Like Inheritance


Like inheritance should be used for modeling only when the performance win is big enough to offset the
restrictions, for example:

• Objects that use a lot of memory, such as a register file, where the number of distinct registers is very
large, and for each such register a field of the register type must be generated, for example,
“pc: pc_reg”, “psr: psr_reg” and so on.
• Objects that do not require randomization, such as a scoreboard or a memory.
Like inheritance should also be used for non-modeling, programming-like activities, such as
implementing a generic package for a queue.

4.10.6 Restrictions on Like Inheritance


There are four types of restrictions on like inheritance:

• “Restrictions Due to Inherent Differences” on page 4-41


• “Restrictions Due to Implementation” on page 4-42
• “Generation Restrictions on Like Inheritance” on page 4-42
• “Examples of Like Inheritance Restrictions” on page 4-44

4.10.6.1 Restrictions Due to Inherent Differences


Some of the restrictions on like inheritance derive from the inherent differences between when and like
inheritance:

• You cannot explicitly reference the determinant fields.


• Creating multiple, orthogonal subtypes can be difficult with like inheritance.
• Generation of parent does not create like children.
• You cannot add when subtypes to a struct with like children. Similarly, you cannot create a like child
from a struct that has when subtypes. See “Example 1” on page 4-44 for more information.

For more information on the first 3 items in this list, see “Advantages of Using When Inheritance for
Modeling” on page 4-36.

e Language Reference 4-41


Structs, Fields, and Subtypes
Restrictions on Like Inheritance

4.10.6.2 Restrictions Due to Implementation


In addition, the following restrictions are implementation-based and may be removed in future releases:

• You cannot extend a struct with like children by:


• Extending or overriding a TCM, if the TCM has been modified by one of the like children.
• Adding fields, unless none of the like children have added fields either explicitly or implicitly.
(Adding an event or a dynamic C routine might implicitly add a field, for example.)
• Adding an event, unless none of the like children have added fields either explicitly or implicitly.
• Adding or modifying an expect or assume, unless none of the like children have added fields
either explicitly or implicitly.
• Adding a dynamic C routine, unless none of the like children have added fields either explicitly
or implicitly.
• You cannot modify in a like child a cover group whose event is defined in the parent.
For more information see See “Examples of Like Inheritance Restrictions” on page 4-44.

4.10.6.3 Generation Restrictions on Like Inheritance


This section describes restrictions on generation when like inheritance is used. For details about
generation, see the Generation Guide.

• Temporary fields in the parent cause problems.


Constraints that have expressions on one side of an equality or inequality create temporary fields.
For example:
keep a > b * c;
gets translated internally into:
keep tmp == b * c; keep a > tmp;
If such constraints are specified in a parent, this may cause a crash during run time. (Note that there
is no problem with constraints in a leaf child.)
<'
struct x {
a:uint;
b:uint;
c:uint;

keep a > b * c;
};

4-42 e Language Reference


Structs, Fields, and Subtypes
Restrictions on Like Inheritance

struct y like x {
d:uint;
};

extend sys {
x_list: list of x;
y_list: list of y;
};
'>
A possible workaround is to use explicit temporary variables. That is, replace:
keep a > b * c;
with:
tmp: int;
keep tmp == b * c;
keep a > tmp;

• Unidirectional constraints in the parent do not induce generation order.


Unidirectional constraints in the parent struct do not induce the expected generation order in the
child.
For example, suppose that the following constraint appears in packet:
keep size == f(b);
During generation of a like-inherited packet struct, such as Ethernet_packet, the constraint above
does not cause b to be generated before size. This often leads to a contradiction.
<'
struct x {
size:uint;
b:uint;

keep size == f(b);

f(z:uint): uint is {
return z * 5;
};
};

struct y like x {
c: uint;
};

extend sys {
y_list: list of y;

e Language Reference 4-43


Structs, Fields, and Subtypes
Restrictions on Like Inheritance

};
'>

4.10.6.4 Examples of Like Inheritance Restrictions


Restrictions on like inheritance are demonstrated in the following sample e code.

Example 1
You cannot add when subtypes to a struct with like children. Similarly, you cannot create a like child
from a struct that has when subtypes.
<'
type protocol: [Ethernet, IEEE, foreign];
struct packet {
p: protocol;
data:list of byte;
};
struct tx_packet like packet {
t:uint
};
extend packet {
// Load-time error
// when Ethernet packet {
// e:uint;
// };
};
'>

Example 2
You cannot extend or override a TCM in a struct that has like children, if the TCM has been modified by
one of the like children.
<'
struct packet {

event clk is rise ('~/top.clk');


zip()@clk is {wait [4]};
};

struct tx_packet like packet {


t:uint;
zip()@clk is also {wait [2]};
};

4-44 e Language Reference


Structs, Fields, and Subtypes
Restrictions on Like Inheritance

extend packet {
// Load-time error
// zip()@clk is also {wait [5]};
};
'>

Example 3
You cannot add fields to a struct that has like children if those children have added fields, either
implicitly or explicitly.
<'
struct packet {

event clk is rise ('~/top.clk');


zip()@clk is {wait [4]};

};

struct tx_packet like packet {


t:uint;
};

extend packet {
// Load-time error
// u:uint;
};
'>

Example 4
You cannot add an event to a struct that has like children if those children have added fields, either
implicitly or explicitly. It is OK to extend a parent to modify an event.
<'
struct packet {

event clk is rise ('~/top.clk')@sim;


zip()@clk is {wait [4]};
};

struct tx_packet like packet {


t:uint;
};

extend packet {

e Language Reference 4-45


Structs, Fields, and Subtypes
Restrictions on Like Inheritance

event clk is only fall ('~/top.clk')@sim; // No load-time error


// event ready is rise ('~/top.ready'); // Load-time error
};
'>

Example 5
You cannot add or modify an expect or assume to a struct that has like children if those children have
added fields, either implicitly or explicitly.
<'
struct packet {

event clk is rise ('~/top.clk')@sim;


event ready is rise ('~/top.ready');
event start_count;
event stop_count;

expect rule1 is @start_count => {[1..5];@ready}@clk;


};

struct tx_packet like packet {


t:uint;
};

extend packet {
// Load-time error for either of the following 2 lines
// expect rule1 is only @start_count => {[2..6];@ready}@clk;
// expect rule2 is @start_count => (eventually @stop_count);
};
'>

Example 6
You cannot modify in a like child a cover group whose event is defined in the parent. It may load without
error, but it will fail in unpredictable ways when run.
<'
struct packet {
len: uint;
addr:uint;

event clk is rise ('~/top.clk')@sim;


event packet_sent;

cover packet_sent is {
item len;

4-46 e Language Reference


Structs, Fields, and Subtypes
A When Inheritance Example

item addr;
};
};
struct tx_packet like packet {
t:uint;

// cover packet_sent is { // Error


// item len;
// item addr;
// item t;
// };
};

'>

4.10.7 A When Inheritance Example


The following example contains the e code fragments in the section titled “A Simple Example of When
Inheritance” on page 4-33.

<'
type packet_protocol: [Ethernet, IEEE, foreign];
struct packet {
protocol: packet_protocol;
size: int [0..1k];
data[size]: list of byte;
show() is undefined;
};
extend Ethernet packet {
e_field: int;
show() is {out("I am an Ethernet packet")};
};
extend IEEE packet {
i_field: int;
show() is {out("I am an IEEE packet")};
};
extend foreign packet {
f_field: int;
show() is {out("I am a foreign packet")};
};
type Ethernet_op: [e1, e2, e3];
extend Ethernet packet { op: Ethernet_op; };
extend e1 Ethernet packet {
e1_foo: int;
show() is {out("I am an e1 Ethernet packet")};
};

e Language Reference 4-47


Structs, Fields, and Subtypes
A When Inheritance Example

extend e2 Ethernet packet {


e2_foo: int;
show() is {out("I am an e2 Ethernet packet")};
};
extend e3 Ethernet packet {
e3_foo: int;
show() is {out("I am an e3 Ethernet packet")};
};
extend sys {
packets: list of packet;
post_generate() is also { for each in packets {.show()}; };
};
'>

4-48 e Language Reference


5 Units
This chapter describes the constructs used to define units and explains how you can use units to
implement a modular verification methodology. This chapter contains the following sections:

• “Units Overview” on page 5-1


• “Defining Units and Fields of Type Unit” on page 5-6
• “Predefined Methods for Any Unit” on page 5-18
• “Unit-Related Predefined Methods for Any Struct” on page 5-28
• “Unit-Related Predefined Routines” on page 5-37

See Also
• Chapter 4 “Structs, Fields, and Subtypes”

5.1 Units Overview


Units are the basic structural blocks for creating verification modules (verification cores) that can easily
be integrated together to test larger and larger portions of an HDL design as it develops. Units, like
structs, are compound data types that contain data fields, procedural methods, and other members.
Unlike structs, however, a unit instance is bound to a particular component in the DUT (an HDL path).
Furthermore, each unit instance has a unique and constant place (an e path) in the runtime data structure
of an e program. Both the e path and the complete HDL path associated with a unit instance are
determined during pre-run generation.

The basic runtime data structure of an e program is a tree of unit instances whose root is sys, the only
predefined unit in Specman. Additionally there are structs that are dynamically bound to unit instances.
The runtime data structure of a typical e program is similar to that of the XYZ_router program shown in
Figure 5-1.

e Language Reference 5-1


Units
Units Overview

Figure 5-1 Run-Time Data Structure of the XYZ_Router

key

sys unit instance

struct instance

XYZ_router field

chan0 chan1 chan2 current_packet

kind addr len data parity

Each unit instance in the unit instance tree of the XYZ_router matches a module instance in the Verilog
DUT, as shown in Figure 5-2. The one-to-one correspondence in this particular design between e unit
instances and DUT module instances is not required for all designs. In more complex designs, there may
be several levels of DUT hierarchy corresponding to a single level of hierarchy in the tree of e unit
instances.

Figure 5-2 DUT Router Hierarchy

top

router_i

chan0 chan1 chan2

Binding an e unit instance to a particular component in the DUT hierarchy allows you to reference
signals within that DUT component using relative HDL path names. When the units are integrated into
a unit instance tree during pre-run generation, Specman determines the complete path name for each
referenced HDL object by concatenating the complete HDL path of the parent unit to the path of the unit
containing the referenced object. Specman is thus able to check the validity of the HDL references
before starting a simulation run.

5-2 e Language Reference


Units
Units vs. Structs

This ability to use relative path names to reference HDL objects allows you to freely change the
combination of verification cores as the HDL design and the verification environment evolve.
Regardless of where the DUT component is instantiated in the final integration, the HDL path names in
the verification environment remain valid.

See Also
• “Units vs. Structs” on page 5-3
• “HDL Paths and Units” on page 5-4
• “Methodology Recommendations and Limitations” on page 5-5
• SpeXsim users: “Generating SpeXsim Stubs Files in theSpeXsim User Guide
• Third-party simulator users: “HDL Stubs Files and Units” on page 8-9 in the Specman Elite Integrator’s
Guide
• “Relative Paths, Absolute Paths, and Units” on page 8-16 in the Specman Elite Integrator’s Guide

5.1.1 Units vs. Structs


The decision of whether to model a DUT component with a unit or a struct often depends on your
verification strategy. Compelling reasons for using a unit instead of a struct include:

• You intend to test the DUT component both standalone and integrated into a larger system.
Modeling the DUT component with a unit instead of a struct allows you to use relative path names
when referencing HDL objects. When you integrate the component with the rest of the design, you
simply change the HDL path associated with the unit instance and all the HDL references it contains
are updated to reflect the component’s new position in the design hierarchy.
This methodology eliminates the need for computed HDL names (for example, ‘(path_str).sig’),
which impact runtime performance.
• Your e program has methods that access many signals at runtime.
The correctness of all signal references within units are determined and checked during pre-run
generation.
If your e program does not contain user units, the absolute HDL references within structs are also
checked during pre-run generation. However, if your e program does contain user units, the relative
HDL references within structs are checked at run time. In this case, using units rather than structs
can enhance runtime performance.

On the other hand, using a struct to model abstract collections of data, like packets, allows you more
flexibility as to when you generate the data. With structs, you can generate the data either during pre-run
generation, at runtime, or on the fly, possibly in response to conditions in the DUT. Unit instances,

e Language Reference 5-3


Units
HDL Paths and Units

however, can only be generated during pre-run generation, because each unit instance has a unique and
constant place (an e path) in the runtime data structure of an e program, just as an HDL component
instance has a constant place in the DUT hierarchical tree.Thus you cannot modify the unit tree by
generating unit instances on the fly.

Any allocated struct instance automatically establishes a reference to its parent unit. If this struct is a
generated during pre-run generation it inherits the parent unit of its parent struct. If the struct is
dynamically allocated by the new or gen action, then the parent unit is inherited from the struct
belonging to the enclosing method.

See Also
• “HDL Paths and Units” on page 5-4
• SpeXsim users: “Generating SpeXsim Stubs Files in theSpeXsim User Guide
• Third-party simulator users: “HDL Stubs Files and Units” on page 8-9 in the Specman Elite Integrator’s
Guide
• “Relative Paths, Absolute Paths, and Units” on page 8-16 in the Specman Elite Integrator’s Guide
• “Methodology Recommendations and Limitations” on page 5-5

5.1.2 HDL Paths and Units


Relative HDL paths are essential in creating a verification module that can be used to test a DUT
component either standalone or integrated into different or larger systems. Binding an e unit instance to
a particular component in the DUT hierarchy allows you to reference signals within that DUT
component using relative HDL path names. Regardless of where the DUT component is instantiated in
the final integration, the HDL path names are still valid. To illustrate this, let’s look at how the
XYZ_router (shown in Figure 5-1 on page 5-2) is bound to the DUT router (shown in Figure 5-2 on page
5-2).

To associate a unit or unit instance with a DUT component, you use the hdl_path() method within a
keep constraint. For example, the following code extends sys by creating an instance of the XYZ_router
unit and binds the unit instance to the “router_i” instance in the DUT.
extend sys {
unit_core: XYZ_router is instance;
keep unit_core.hdl_path() =="top.router_i";
};

Similarly, the following code creates three instances of XYZ_channel in XYZ_router and constrains the
HDL path of the instances to be “chan0”, “chan1”, “chan2”. These are the names of the channel
instances in the DUT relative to the “router_i” instance.

5-4 e Language Reference


Units
Methodology Recommendations and Limitations

unit XYZ_router {
channels: list of XYZ_channel is instance;
keep channels.size() == 3;
keep for each in channels {.hdl_path() ==
append("chan", index); };
};

Specman determines the full HDL path of each unit instance during pre-run generation, by appending
the HDL path of the child unit instance to the full path of its parent, starting with sys. sys has the empty
full path “”. Thus the full path for the XYZ_router instance is “top.router_i” and that for the first channel
instance is “top.router_i.chan0”.

The full path for a unit instance is used to resolve any internal HDL object references that contain
relative HDL paths. See “Relative Paths, Absolute Paths, and Units” on page 8-16 in the Specman Elite
Integrator’s Guide.

By default, the do_print() method of any unit prints two predefined lines as well as the user-defined
fields. The predefined lines display the e path and the full HDL path for that unit. The e path line
contains a hyperlink to the parent unit.

5.1.3 Methodology Recommendations and Limitations


Each unit instance has a unique and constant place (an e path) in the runtime data structure of an e
program that is determined during pre-run generation. Thus you cannot modify the unit tree created
during pre-run generation by generating unit instances on the fly or making assignments of new values
to existing unit instances. You can generate fields of unit type dynamically. However, when you generate
a field of type unit, either on-the-fly or during pre-run generation, you must constrain the field to refer to
an existing unit instance.

The following limitations are implied by the nature of unit instances and fields of unit type:

• Unit instances cannot be the object of a new or gen action or a call to copy().
• Unit instances cannot be placed on the left-hand-side of the assignment operator.
• List methods which alter the original list, like list.add() or list.pop() cannot be applied to lists of unit
instances.
• Units are intended to be used as structural components and not as data carriers. Therefore, using
physical fields in unit instances, as well as packing or unpacking into unit instances is not
recommended. Unpacking into a field of type unit when the field is NULL causes a runtime error.
• All instances of the same unit type must be bound to the same kind of HDL component.
If you intend to create a modular verification environment, the following recommendations are also
important:

e Language Reference 5-5


Units
Defining Units and Fields of Type Unit

• Avoid setting global configuration options with set_config(). Instead, for numeric settings, use
set_config_max().
• Avoid global changes to the default packing options. Instead, define unit-specific options in the
top-level unit and access them from lower-level units with get_enclosing_unit().
• References to HDL objects should be placed in unit methods. If you need to access HDL objects
from struct methods, you may declare additional methods in a unit. Because these access methods
will probably be one line of e code, you can declare them as inline methods for maximum efficiency.
For example, to access the following inline method declared in a struct,
get_reset_value() is inline { return 'reset'; };
you would use
get_enclosing_unit(CONTROLLER).get_reset_value();

• In structs that may be dynamically associated with more than one unit, it is recommended to use
computed path names.
• Pre-run generation is performed before creating the stubs file. To minimize the time required to create
a stubs file, you can move any pre-run generation that is not related to building the tree of unit
instances into the procedural code, preferably as an extension of the run() method of the appropriate
structs. For example, you probably want to avoid generating thousands of packets in order to create
a stubs file.

5.2 Defining Units and Fields of Type Unit


The following sections describe the constructs for defining units and fields of type unit:

• unit on page 5-6


• field: unit-type is instance on page 5-11
• field: unit-type on page 5-13
• field: list of unit instances on page 5-15
• field: list of unit-type on page 5-16

5.2.1 unit

Purpose
Define a data struct associated with an HDL component or block

5-6 e Language Reference


Units
unit

Category
Statement

Syntax
unit unit-type [like base-unit-type] {
[unit-member; …]}

Syntax Example
unit XYZ_channel {
event external_clock;
event packet_start is rise('valid_out')@sim;
event data_passed;

verilog variable 'valid_out' using wire;

data_checker() @external_clock is {
while 'valid_out' == 1 {
wait cycle;
check that 'data_out' == 'data_in';
};
emit data_passed;
};

on packet_start {
start data_checker();
};
};

Parameters

unit-type The type of the new unit.

base-unit-type The type of the unit from which the new unit inherits its members.

e Language Reference 5-7


Units
unit

unit-member; … The contents of the unit. Like structs, units can have the following types of
members:
• data fields for storing data
• methods for procedures
• events for defining temporal triggers
• coverage groups for defining coverage points
• when, for specifying inheritance subtypes
• declarative constraints for describing relations between data fields
• on, for specifying actions to perform upon event occurrences
• expect, for specifying temporal behavior rules
Unlike structs, units can also have verilog members. This capability lets you
create Verilog stub files for modular designs. See the following for information
on which verilog members are recommended.
• SpeXsim users: “Generating SpeXsim Stubs Files in theSpeXsim User
Guide
• Third-party simulator users: “HDL Stubs Files and Units” on page 8-9
in the Specman Elite Integrator’s Guide
The definition of a unit can be empty, containing no members.

Description
Units are the basic structural blocks for creating verification modules (verification cores) that can easily
be integrated together to test larger designs. Units are a special kind of struct, with two important
properties:

• Units or unit instances can be bound to a particular component in the DUT (an HDL path).
• Each unit instance has a unique and constant parent unit (an e path). Unit instances create a static
tree, determined during pre-run generation, in the runtime data structure of an e program.

Because the base unit type (any_unit) is derived from the base struct type (any_struct), user-defined
units have the same predefined methods. In addition, units can have verilog members and have several
specialized predefined methods.

A unit type can be extended or used as the basis for creating unit subtypes. Extended unit types or unit
subtypes inherit the base type’s members and contain additional members.

See “Units vs. Structs” on page 5-3 for a discussion of when to use units instead of structs.

Example
This example defines a unit type XYZ_router.

5-8 e Language Reference


Units
unit

<'
unit XYZ_router {

debug_mode: bool;

channels: list of XYZ_channel is instance;

keep channels.size() == 3;

keep for each in channels {


.hdl_path() == append("chan", index);
.router == me };

event pclk is rise('clock')@sim;

mutex_checker() @pclk is {
while ('packet_valid') {
var active_channel: int = UNDEF;
for each in channels {
if '(it).valid_out' {
check that active_channel == UNDEF else
dut_error ("Violation of the mutual \
exclusion by channels ",
active_channel, " and ", index);
active_channel = index;
check that active_channel == 'addr' else
dut_error ("Violation of the \
correspondence between active \
channel and selected address");
};
};
wait cycle;
};
};

// transaction-level checking and coverage

!current_packet: XYZ_packet;

event packet_in is rise('packet_valid')@pclk;


on packet_in {
current_packet = new XYZ_packet;
current_packet.addr = 'addr';
current_packet.len = 'len';
out(current_packet.get_unit());
start sample_data();
start mutex_checker();

e Language Reference 5-9


Units
unit

};

sample_data() @pclk is {
if (debug_mode) {
out("Start of sampling");
};
for j from 1 to current_packet.len {
wait cycle;
current_packet.data.add('data');
};
if (debug_mode) {
out("End of sampling: packet data ",
current_packet.data);
};
// Don't read parity yet
};

event packet_out is fall('packet_valid')@pclk;

expect (@packet_in => { [current_packet.len];


cycle @packet_out}) @pclk
else dut_error ("Violation of expected packet duration");

event log is @packet_out;

on packet_out {
current_packet.parity = 'parity';

// Check the last byte of the data


current_packet.kind =
('data' == current_packet.parity_calc()) ? good : bad;

if (debug_mode) {
print current_packet;
};

if (current_packet.kind == good) then {


check that 'err' == 0 else dut_error ("Err != 0 \
for good pkt");
}
else {
check that 'err' == 1 else dut_error ("Err != 1 \
for bad pkt");
};
};

event channel_data_passed;

5-10 e Language Reference


Units
field: unit-type is instance

expect (@packet_out => [1] @channel_data_passed) @pclk


else dut_error("Channel data pass and packet out \
aren't synchronous");

cover log using text = "End of package transaction" is {


item addr : uint (bits : 2) = current_packet.addr
using illegal = (addr == 3);
item len : uint (bits : 6) = current_packet.len
using ranges={
range([0..3],"short");
range([4..15],"medium");
range([16..63],"long");
};
item kind : XYZ_kind_type = current_packet.kind ;
item err : bool = 'err' ;
};
};
'>

See Also
• “Units Overview” on page 5-1
• Chapter 4 “Structs, Fields, and Subtypes”

5.2.2 field: unit-type is instance

Purpose
Define a unit instance field

Category
Unit member

Syntax
field-name[: unit-type] is instance

Syntax Example
cpu: XYZ_cpu is instance;

e Language Reference 5-11


Units
field: unit-type is instance

Parameters

field-name The name of the unit instance being defined.

unit-type The name of a unit type.


If the field name is the same as an existing type, you can omit the
“: unit-type” part of the field definition. Otherwise, the type
specification is required.

Description
Defines a field of a unit to be an instance of a unit type. Units can be instantiated within other units, thus
creating a unit tree. The root of the unit tree is sys, the only predefined unit in Specman.

A unit instance has to be bound to a particular component in the DUT (an HDL path). Each unit instance
also has a unique and constant place (an e path) in the runtime data structure of an e program that is
determined during pre-run generation.

Notes
• Instantiating a unit in a struct causes a compile-time error; units can only be instantiated within
another unit.
• The do-not-generate operator (!) is not allowed with fields of type unit instance. Unit instances can
be created only during pre-run generation.
• It is not recommended to use the physical field operator (%) with fields of type unit instance.

Example
This example creates an instance of the XYZ_router unit type in sys.
<'
extend sys {
mntr: monitor;
unit_core: XYZ_router is instance;
keep unit_core.hdl_path() =="top.router_i";
keep unit_core.debug_mode == TRUE;

setup() is also {
set_check("...", WARNING);
set_config(cover, mode, on);
};
};
'>

5-12 e Language Reference


Units
field: unit-type

See Also
• “Units Overview” on page 5-1
• field: unit-type on page 5-13
• field: list of unit-type on page 5-16
• Chapter 4 “Structs, Fields, and Subtypes”

5.2.3 field: unit-type

Purpose
Define a field of type unit

Category
Struct or unit member

Syntax
[!] field-name[: unit-type]

Syntax Example
extend XYZ_router{
!current_chan: XYZ_channel;
};

Parameters

! Denotes an ungenerated field. If you generate this field on the fly, you
must constrain it to an existing unit instance or a runtime error is issued.

field-name The name of the field being defined.

unit-type The name of a unit type.

If the field name is the same as an existing type, you can omit the
“: unit-type” part of the field definition. Otherwise, the type
specification is required.

e Language Reference 5-13


Units
field: unit-type

Description
Defines a field of unit type. A field of unit type is always either NULL or a reference to a unit instance
of a specified unit type.

Notes
• It is not recommended to use the physical field operator (%) with fields of type unit.
• If a field of type unit is generated it must be constrained to an existing unit instance.

Example
In the example below, the XYZ_router is extended with an ungenerated field of type XYZ_channel, a
unit type. It remains NULL until the “mutex_checker()” method is called. In this method the
“current_chan” field is used as a pointer to each of the unit instances of type XYZ_channel in the
channels list.
extend XYZ_router {
!current_chan: XYZ_channel;
mutex_checker() @pclk is {
while ('packet_valid') {
var active_channel: int = UNDEF;
for each in channels {
current_chan = it;
if '(current_chan).valid_out' {
check that active_channel == UNDEF else
dut_error ("Violation of the mutual exclusion by \
channels ", active_channel, " and ", index);
active_channel = index;
check that active_channel == 'addr' else
dut_error ("Violation of the correspondence \
between active channel and selected address");
};
};
wait cycle;
};
};
};

See Also
• field: unit-type is instance on page 5-11
• field: list of unit-type on page 5-16

5-14 e Language Reference


Units
field: list of unit instances

• Chapter 4 “Structs, Fields, and Subtypes”

5.2.4 field: list of unit instances

Purpose
Define a list field of unit instances

Category
Struct or unit member

Syntax
name:[[length-exp]]: list of unit-type is instance

Syntax Example
channels: list of XYZ_channel is instance;

Parameters

name The name of the list being defined.

length-exp An expression that gives the initial size for the list.

unit-type A unit type.

is instance Creates a list of unit instances.

Description
Defines a list field of unit instances. A list of unit instances can only be created during pre-run
generation and cannot be modified after it is generated.

Notes
• List operations, such as list.add() or list.pop(), that alter the list created during pre-run generation
are not allowed for lists of unit instances.
• It is not recommended to use the physical field operator (%) with lists of unit instances.

e Language Reference 5-15


Units
field: list of unit-type

Example
This example creates a list of unit instances of type XYZ_channel in XYZ_router.
<'
unit XYZ_channel {
event external_clock;
event packet_start is rise('valid_out')@sim;
event data_passed;

verilog variable 'valid_out' using wire;

data_checker() @external_clock is {
while 'valid_out' == 1 {
wait cycle;
check that 'data_out' == 'data_in';
};
emit data_passed;
};

on packet_start {
start data_checker();
};
};

unit XYZ_router {
channels: list of XYZ_channel is instance;
keep channels.size() == 3;
};
'>

See Also
• field: unit-type on page 5-13
• field: unit-type is instance on page 5-11
• Chapter 4 “Structs, Fields, and Subtypes”

5.2.5 field: list of unit-type

Purpose
Define a list field of type unit

5-16 e Language Reference


Units
field: list of unit-type

Category
Struct or unit member

Syntax
[!]name[[length-exp]]: list of unit-type

Syntax Example
var currently_valid_channels: list of XYZ_channel;

Parameters

! Do not generate this list.

name The name of the list being defined.

length-exp An expression that gives the initial size for the list.

unit-type A unit type.

Description
Defines a list field of type unit.

Note
It is not recommended to use the physical field operator (%) with lists of unit type.

Example
This example creates a list of unit type XYZ_channel, which is used to create a list of currently valid
channels.
<'
unit XYZ_channel {
router: XYZ_router;
};
unit XYZ_router {
channels: list of XYZ_channel is instance;
keep channels.size() == 3;

validity_checker() is {
var currently_valid_channels: list of XYZ_channel;

e Language Reference 5-17


Units
Predefined Methods for Any Unit

for each in channels {


if '(it).valid_in' {
currently_valid_channels.add(it);
};
};
print currently_valid_channels;
};
};
'>

See Also
• field: unit-type on page 5-13
• field: unit-type is instance on page 5-11
• Chapter 4 “Structs, Fields, and Subtypes”

5.3 Predefined Methods for Any Unit


There is a predefined generic type any_unit, which is derived from any_struct. any_unit is the base
type implicitly used in user-defined unit types, so all predefined methods for any_unit are available for
any user-defined unit. The predefined methods for any_struct are also available for any user-defined
unit.

The predefined methods for any unit include:

• hdl_path() on page 5-19


• full_hdl_path() on page 5-22
• e_path() on page 5-23
• agent() on page 5-25
• get_parent_unit() on page 5-27

See Also
• “Unit-Related Predefined Methods for Any Struct” on page 5-28
• “Unit-Related Predefined Routines” on page 5-37

5-18 e Language Reference


Units
hdl_path()

5.3.1 hdl_path()

Purpose
Return a relative HDL path for a unit instance

Category
Predefined pseudo-method for any unit

Syntax
[unit-exp.]hdl_path(): string

Syntax Example
extend dut_error_struct {
write() is first {
var channel: XYZ_channel =
source_struct().try_enclosing_unit(XYZ_channel);
if (channel != NULL) {
out("Error in XYZ channel: instance ",
channel.hdl_path());
};
};
};

Parameters

unit-exp An expression that returns a unit instance. If no expression is specified, the current
unit instance is assumed.

Description
Returns the HDL path of a unit instance. The most important role of this method is to bind a unit
instance to a particular component in the DUT hierarchy. Binding an e unit or unit instance to a DUT
component allows you to reference signals within that component using relative HDL path names.
Regardless of where the DUT component is instantiated in the final integration, the HDL path names are
still valid. The binding of unit instances to HDL components is a part of the pre-run generation process
and must be done in keep constraints.

Although absolute HDL paths are allowed, relative HDL paths are recommended if you intend to follow
a modular verification strategy.

e Language Reference 5-19


Units
hdl_path()

This method always returns an HDL path exactly as it was specified in constraints. If, for example, you
use a macro in a constraint string, then hdl_path() returns the original and not substituted string.

Notes
• All instances of the same unit should be bound to the same kind of HDL components.
Note You can bind different instances of the same unit to different DUT components if the
components have the same functional signals. The DUT components can be written in different
languages, such as Verilog, VHDL, SystemC, and so on.

• You cannot constrain the HDL path for sys.


• To prevent Specman from concatenating the path of the parent unit to the child unit, use
keep unit.hdl_path() == "~/";
For example:

<'
unit memory{
p: simple_port of int is instance;
keep bind(p,external);
keep p.hdl_path() == "/memory/sig"; // the path is /memory/sig
// not /top/memory/sig
};

unit my_cpu {

p: simple_port of int is instance;


keep bind(p,external);
keep p.hdl_path() == "sig"; // the path is /top/sig

memory is instance;
keep memory.hdl_path() == "~/"; // prevents concatenation of the
// hdl path

};

extend sys {
my_cpu is instance;
keep my_cpu.hdl_path() == "~/top";
};

5-20 e Language Reference


Units
hdl_path()

Example 1
This example shows how you can use relative paths in lower-level instances in the unit instance tree. To
create the full HDL path of each unit instance, its HDL path is prefixed with the HDL path of its parent
instance. In this example, because the HDL path of sys is “”, the full HDL path of “unit_core” is
“top.router_i”. The full HDL path of “extra_channel” is “top.router_i.chan3”.
extend sys {
unit_core: XYZ_router is instance;
keep unit_core.hdl_path() == "top.router_i";
};

extend XYZ_router {
extra_channel: XYZ_channel is instance;
keep extra_channel.hdl_path() == "chan3";
};

Example 2
This example shows how hdl_path() returns the HDL path exactly as specified in the constraint. Thus
the first print action prints “`TOP.router_i”. The second print action, in contrast, accesses
“top.router_i.clk”.
verilog import macros.v;
extend sys {
unit_core: XYZ_router is instance;
keep unit_core.hdl_path() == "‘TOP.router_i";
run() is also {
print unit_core.hdl_path();
print '(unit_core).clk';
};
};

Result
vrst-tool> test
...
Starting the test ...
Running the test ...
unit_core.hdl_path() = "‘TOP.router_i"
'top.router_i.clk' = 0

See Also
• “HDL Paths and Units” on page 5-4

e Language Reference 5-21


Units
full_hdl_path()

• full_hdl_path() on page 5-22


• e_path() on page 5-23
• hdl_path() on page 6-71

5.3.2 full_hdl_path()

Purpose
Return an absolute HDL path for a unit instance

Category
Predefined method for any unit

Syntax
[unit-exp.]full_hdl_path(): string

Syntax Example
out ("Mutex violation in ", get_unit().full_hdl_path());};

Parameters

unit-exp An expression that returns a unit instance. If no expression is specified, the current
unit instance is assumed.

Description
Returns the absolute HDL path for the specified unit instance. This method is used mainly in
informational messages. Like the hdl_path() method, this method returns the path as originally
specified in the keep constraint, without making any macro substitutions.

Example
This example uses full_hdl_path() to display information about where a mutex violation has occurred.
extend XYZ_router {
!current_chan: XYZ_channel;
mutex_checker() @pclk is {
while ('packet_valid') {

5-22 e Language Reference


Units
e_path()

var active_channel: int = UNDEF;


for each XYZ_channel(current_chan) in channels {
if '(current_chan).valid_out' {
if active_channel != UNDEF then {
out ("Mutex violation in ",
get_unit().full_hdl_path());};
active_channel = index;
};
};
wait cycle;
};
};
};

Result
Mutual exclusion violation in top.router_i

See Also
• hdl_path() on page 5-19
• e_path() on page 5-23

5.3.3 e_path()

Purpose
Returns the location of a unit instance in the unit tree

Category
Predefined method for any unit

Syntax
[unit-exp.]e_path(): string

Syntax Example
out("Started checking ", get_unit().e_path());

e Language Reference 5-23


Units
e_path()

Parameters

unit-exp An expression that returns a unit instance. If no expression is specified, the current unit
instance is assumed.

Description
Returns the location of a unit instance in the unit tree. This method is used mainly in informational
messages.

Example
<'
unit ex_u {
run() is also {
inst = get_unit().e_path();
var inst: string;
inst = get_unit().e_path();
out("ex instance: ", inst);
};
};

unit top_u {
exlist[10]: list of ex_u is instance;
};

extend sys {
top: top_u is instance;
};
'>

Result
ex instance: sys.top.exlist[0]
ex instance: sys.top.exlist[1]
ex instance: sys.top.exlist[2]
ex instance: sys.top.exlist[3]
ex instance: sys.top.exlist[4]
ex instance: sys.top.exlist[5]
ex instance: sys.top.exlist[6]
ex instance: sys.top.exlist[7]
ex instance: sys.top.exlist[8]
ex instance: sys.top.exlist[9]

5-24 e Language Reference


Units
agent()

See Also
• full_hdl_path() on page 5-22
• hdl_path() on page 5-19

5.3.4 agent()

Purpose
Maps the DUT’s HDL partitions into e code

Category
Predefined pseudo-method for any unit

Syntax
keep [unit-exp.]agent() == string;

Syntax Example
router: XYZ_router is instance;
keep router.agent() == "Verilog";

Parameters

unit-exp An expression that returns a unit instance. If no expression is specified,


the current unit instance is assumed.

string One of the following predefined agent names: verilog, vhdl, mti_vlog,
mti_vhdl, ncvlog and ncvhdl. Specifying the agent name as verilog or
vhdl is preferred because it makes the e code portable between
simulators. In contrast, if a unit is bound to a specific agent, for example
to mti_vhdl, an error is issued if it is ported to NC Simulator. The
predefined names are case-insensitive; in other words, verilog is the
same as Verilog.

Use verilog or vhdl as agent names when using SpeXsim.

e Language Reference 5-25


Units
agent()

Description
Specifying an agent identifies the simulator that is used to simulate the corresponding DUT component.
Once a unit instance has an explicitly specified agent name then all other unit instances instantiated
within it are implicitly bound to the same agent name, unless another agent is explicitly specified.

An agent name may be omitted in a single-HDL environment but it must be defined implicitly or
explicitly in a mixed HDL environment for each unit instance that is associated with a non-empty
hdl_path(). If an agent name is not defined for a unit instance with a non-empty hdl_path() in a mixed
HDL environment, Specman issues an error message.

Given the hdl_path() and agent() constraints, Specman establishes a correspondence map between the
unit instance HDL path and its agent name. Any HDL path below the path in the map is associated with
the same agent unless otherwise specified. This map is further used internally to pick the right adapter
for each accessed HDL object.

It is possible to access Verilog signals from a VHDL unit instance code and vice-versa. Every signal is
mapped to its HDL domain according to its full path, regardless of the specified agent of the unit that the
signal is accessed from.

When the agent() method is called procedurally, it returns the agent of the unit. The spelling of the agent
string is exactly as specified in the corresponding constraint.

Notes
• Agents are bound to unit instances during the generation phase. Consequently, there is no way to
map between HDL objects and agents before generation. As a result of this limitation, HDL objects
in a mixed Verilog/VHDL environment cannot be accessed before generation from sys.setup() or
from the command line.
• An unsupported agent name causes an error message during the test phase.
• For SpeXsim users: each type of agent name used requires a corresponding stubs file to be created.
For a vhdl agent create a VHDL stubs file; for a verilog agent, create a Verilog stubs file. For both
agents, both stubs files are needed.

Example 1
In the following example, the driver instance inherits an agent name implicitly from the enclosing router
unit instance.
extend sys {
router: XYZ_router is instance;
keep router.agent() == "Verilog";
keep router.hdl_path() == "top.rout";
};

5-26 e Language Reference


Units
get_parent_unit()

extend XYZ_router {
driver: XYZ_router_driver is instance;

};

Example 2
In this example, the signal ‘top.rout.packet_valid’ is sampled using the Verilog PLI because the path
“top.rout” is specified as a Verilog path. In contrast, the signal ‘top.rout.chan.mux.data_out’ is sampled
using a VHDL foreign interface because the closest mapped path is “top.rout.chan” and it is mapped as
a VHDL path.
extend sys {
router: XYZ_router is instance;
keep router.agent() == "Verilog";
keep router.hdl_path() == "top.rout";
};
unit XYZ_router {
channel: XYZ_channel is instance;
keep channel.agent() == "VHDL";
keep channel.hdl_path() == "chan";

run() is also {
print 'packet_valid';
};
};
unit XYZ_channel {
run() is also {
print 'mux.data_out';
};
};

5.3.5 get_parent_unit()

Purpose
Return a reference to the unit containing the current unit instance

Category
Predefined method for any unit

e Language Reference 5-27


Units
Unit-Related Predefined Methods for Any Struct

Syntax
[unit-exp.]get_parent_unit(): unit type

Syntax Example
out(sys.unit_core.channels[0].get_parent_unit());

Parameters

unit-exp An expression that returns a unit instance. If no expression is specified, the current
unit instance is assumed.

Description
Returns a reference to the unit containing the current unit instance.

Example
vrst-tool> out(sys.unit_core.channels[0].get_parent_unit())
XYZ_router-@2

See Also
• get_unit() on page 5-29
• get_enclosing_unit() on page 5-32
• try_enclosing_unit() on page 5-35

5.4 Unit-Related Predefined Methods for Any Struct


The predefined methods for any struct include:

• get_unit() on page 5-29


• get_enclosing_unit() on page 5-32
• try_enclosing_unit() on page 5-35
• set_unit() on page 5-36

See Also
• “Predefined Methods for Any Unit” on page 5-18

5-28 e Language Reference


Units
get_unit()

• “Unit-Related Predefined Routines” on page 5-37

5.4.1 get_unit()

Purpose
Return a reference to a unit

Category
Predefined method of any struct

Syntax
[exp.]get_unit(): unit type

Syntax Example
out ("Mutex violation in ", get_unit().full_hdl_path());};

Parameters

exp An expression that returns a unit or a struct. If no expression is specified, the current struct
or unit is assumed.

Description
When applied to an allocated struct instance, this method returns a reference to the parent unit—the unit
to which the struct is bound. When applied to a unit, it returns the unit itself.

Any allocated struct instance automatically establishes a reference to its parent unit. If this struct is
generated during pre-run generation it inherits the parent unit of its parent struct. If the struct is
dynamically allocated by the new or gen action, then the parent unit is inherited from the struct the
enclosing method belongs to. See “Example 3” on page 5-31 for an illustration of this point.

This method is useful when you want to determine the parent unit instance of a struct or a unit. You can
also use this method to access predefined unit members, such as hdl_path() or full_hdl_path(). To
access user-defined unit members, use get_enclosing_unit(). See “Example 1” on page 5-30 for an
illustration of this point.

e Language Reference 5-29


Units
get_unit()

Example 1
This example shows that get_unit() can access predefined unit members, while get_enclosing_unit()
must be used to access user-defined unit members.
struct instr {
%opcode : cpu_opcode ;
%op1 : reg ;
kind : [imm, reg];

post_generate() is also {
-- get_unit().print_msg() ; -- COMPILE-TIME ERROR
get_enclosing_unit(XYZ_cpu).print_msg();
out("Destination for this instruction is ",
get_unit().hdl_path()) ;
};
};

unit XYZ_cpu {
instrs[3] : list of instr;
print_msg() is {out("Generating instruction for \
XYZ_cpu...");};
};

extend sys {
cpu1: XYZ_cpu is instance;
keep cpu1.hdl_path()=="‘TOP/CPU1";
};
'>

Result
vrst-tool> gen
Doing setup ...
Generating the test using seed 1...
Generating instruction for XYZ_cpu...
Destination for this instruction is ‘TOP/CPU1
Generating instruction for XYZ_cpu...
Destination for this instruction is ‘TOP/CPU1
Generating instruction for XYZ_cpu...
Destination for this instruction is ‘TOP/CPU1
vrst-tool>

Example 2
The first call to get_unit() below shows that the parent unit of the struct instance “p” is sys. The second
call shows that the parent unit has been changed to “XYZ_router”.

5-30 e Language Reference


Units
get_unit()

vrst-tool> var p: XYZ_packet = new


vrst-tool> out(p.get_unit())
sys-@0
vrst-tool> p.set_unit(sys.unit_core)
vrst-tool> out(p.get_unit())
XYZ_router-@1

Example 3
In this example, the trace_inject() method displays the full HDL path of the “XYZ_dlx” unit (not the
“XYZ_tb” unit) because “instr_list” is generated by the run method of “XYZ_dlx”.
extend sys {
tb: XYZ_tb is instance;
keep tb.hdl_path()=="‘TOP/tb";
};
unit XYZ_tb {
dlx: XYZ_dlx is instance;
keep dlx.hdl_path()=="dlx_cpu";
!instr_list: list of instruction;
debug_mode: bool;
};
unit XYZ_dlx {
run() is also {
gen sys.tb.instr_list keeping { .size() < 30;};
};
};
extend instruction {
trace_inject() is {
if get_enclosing_unit(XYZ_tb).debug_mode == TRUE {
out("Injecting next instruction to ",
get_unit().full_hdl_path());
};
};
};

Result
vrst-tool> sys.tb.instr_list[0].trace_inject()
Injecting next instruction to ‘TOP/tb.dlx_cpu

See Also
• get_parent_unit() on page 5-27
• get_enclosing_unit() on page 5-32

e Language Reference 5-31


Units
get_enclosing_unit()

• try_enclosing_unit() on page 5-35

5.4.2 get_enclosing_unit()

Purpose
Return a reference to nearest unit of specified type

Category
Predefined pseudo-method of any struct

Syntax
[exp.]get_enclosing_unit(unit-type: exp): unit instance

Syntax Example
unpack(p.get_enclosing_unit(XYZ_router).pack_config,
'data', current_packet);

Parameters

exp An expression that returns a unit or a struct. If no expression is specified, the current
struct or unit is assumed.
Note If get_enclosing_unit() is called from within a unit of the same type as exp, it
returns the present unit instance and not the parent unit instance.

unit-type The name of a unit type or unit subtype.

Description
Returns a reference to the nearest higher-level unit instance of the specified type, allowing you to access
fields of the parent unit in a typed manner.

You can use the parent unit to store shared data or options such as packing options that are valid for all
its associated subunits or structs. Then you can access this shared data or options with the
get_enclosing_unit() method.

5-32 e Language Reference


Units
get_enclosing_unit()

Notes
• The unit type is recognized according to the same rules used for the is a operator. This means, for
example, that if you specify a base unit type and there is an instance of a unit subtype, the unit subtype
is found.
• If a unit instance of the specified type is not found, a runtime error is issued.

Example 1
In the following example, get_enclosing_unit() is used to print fields of the nearest enclosing unit
instances of type “XYZ_cpu” and “tbench”. Unlike get_unit(), which returns a reference only to its
immediate parent unit, get_enclosing_unit() searches up the unit instance tree for a unit instance of the
type you specify. A runtime error is issued unless an instance of type “XYZ_cpu” and an instance of
type “tbench” are found in the enclosing unit hierarchy.
struct instr {
%opcode : cpu_opcode ;
%op1 : reg ;
kind : [imm, reg];

post_generate() is also {
out("Debug mode for CPU is ",
get_enclosing_unit(XYZ_cpu).debug_mode);
out("Memory model is ",
get_enclosing_unit(tbench).mem_model);
};
};
unit XYZ_cpu {
instr: instr;
debug_mode: bool;
};
unit tbench {
cpu: XYZ_cpu is instance;
mem_model: [small, big];
};

extend sys {
tb: tbench is instance;
};

Result
vrst-tool> gen
Doing setup ...
Generating the test using seed 1...
Debug mode for CPU is FALSE

e Language Reference 5-33


Units
get_enclosing_unit()

Memory model is small


vrst-tool>

Example 2
extend XYZ_router {
pack_config:pack_options;

keep pack_config == packing.low_big_endian;


};

Result
vrst-tool> var p: XYZ_packet = new
vrst-tool> print p.data
p.data = (empty)
vrst-tool> out(p.get_unit())
sys-@0
vrst-tool> p.set_unit(sys.unit_core)
vrst-tool> out(p.get_unit())
XYZ_router-@1
vrst-tool> show unpack(
p.get_enclosing_unit(XYZ_router).pack_config, data, p)
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0| +0
|
0 0 0 0 1 1 0 1 0 0 0 0 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 1 0 1 0|
|
data |

|5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0| +32
+ |
|0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 0
+ |
| |

See Also
• get_unit() on page 5-29
• set_unit() on page 5-36
• try_enclosing_unit() on page 5-35
• get_parent_unit() on page 5-27

5-34 e Language Reference


Units
try_enclosing_unit()

5.4.3 try_enclosing_unit()

Purpose
Return a reference to nearest unit instance of specified type or NULL

Category
Predefined method of any struct

Syntax
[exp.]try_enclosing_unit(unit-type: exp): unit instance

Syntax Example
var MIPS := source_struct().try_enclosing_unit(MIPS);

Parameters

exp An expression that returns a unit or a struct. If no expression is specified, the current
struct or unit is assumed.
Note If try_enclosing_unit() is called from within a unit of the same type as exp, it
returns the present unit instance and not the parent unit instance.

unit-type The name of a unit type or unit subtype.

Description
Like get_enclosing_unit(), this method returns a reference to the nearest higher-level unit instance of
the specified type, allowing you to access fields of the parent unit in a typed manner.

Unlike get_enclosing_unit(), this method does not issue a runtime error if no unit instance of the
specified type is found. Instead, it returns NULL. This feature makes the method suitable for use in
extensions to global methods such as dut_error_struct.write(), which may be used with more than one
unit type.

Example
<'
extend dut_error_struct {
write() is also {

e Language Reference 5-35


Units
set_unit()

var MIPS := source_struct().try_enclosing_unit(MIPS);


if MIPS != NULL then {
out("Status of ", MIPS.e_path(),
" at time of error:");
MIPS.show_status();
};
};
};
'>

See Also
• get_unit() on page 5-29
• get_enclosing_unit() on page 5-32
• get_parent_unit() on page 5-27

5.4.4 set_unit()

Purpose
Change the parent unit of a struct

Category
Predefined method of any struct

Syntax
[struct-exp.]set_unit(parent: exp)

Syntax Example
p.set_unit(sys.unit_core)

Parameters

struct-exp An expression that returns a struct. If no expression is specified, the current struct is
assumed.

parent An expression that returns a unit instance.

5-36 e Language Reference


Units
Unit-Related Predefined Routines

Description
Changes the parent unit of a struct to the specified unit instance.

Note
This method does not exist for units because the unit tree cannot be modified.

Example
vrst-tool> var p: XYZ_packet = new
vrst-tool> out(p.get_unit())
sys-@0
vrst-tool> p.set_unit(sys.unit_core)
vrst-tool> out(p.get_unit())
XYZ_router-@1

5.5 Unit-Related Predefined Routines


The predefined routines that are useful for units include:

• “set_config_max()” on page 5-37


• “get_all_units()” on page 5-39

5.5.1 set_config_max()

Purpose
Increase values of numeric global configuration parameters

Category
Predefined routine

Syntax
set_config_max(category: keyword, option: keyword, value: exp [, option: keyword, value: exp…])

Syntax Example
set_config_max(memory, gc_threshold, 100m);

e Language Reference 5-37


Units
set_config_max()

Parameters

category Is one of the following: cover, gen, memory, and run.

option The valid cover options are:


• absolute_max_buckets, described in configure cover on page 6-3 in
the Specman Command Reference.
The valid gen options are:
• absolute_max_list_size
• max_depth
• max_structs
These options are described in configure gen on page 6-17 in the
Specman Command Reference.
The valid memory options are:

gc_threshold

gc_increment

max_size

absolute_max_size
These options are described in configure memory on page 6-26 in the
Specman Command Reference.
The valid run options are:
• tick_max, described in configure run on page 6-51 in the Specman
Command Reference.

value The valid values are different for each option and are described in the
Specman Command Reference.

Description
Sets the numeric options of a particular category to the specified maximum values.

If you are creating a modular verification environment, it is recommended to use set_config_max()


instead of set_config() in order to avoid possible conflicts that may happen in an integrated
environment. For example, if two units are instantiated and both of them attempt to enlarge Specman
configuration value of absolute_max_size then the recommended way to it is via set_config_max, so
that no unit decrements the value set by another one.

Example
<'
extend sys {

5-38 e Language Reference


Units
get_all_units()

setup() is also {
set_config_max(memory, gc_threshold, 100m);
};
};
'>

See Also
• “Predefined Methods for Any Unit” on page 5-18
• “Unit-Related Predefined Methods for Any Struct” on page 5-28
• The setup() Method of sys on page 22-12

5.5.2 get_all_units()

Purpose
Return a list of instances of a specified unit type

Category
Routine

Syntax
get_all_units(unit-type: exp): list of unit instances

Syntax Example
print get_all_units(XYZ_channel);

Parameter

unit-type The name of a unit type. The type must be defined or an error occurs.

Description
This routine receives a unit type as a parameter and returns a list of instances of this unit type as well as
any unit instances contained within each instance.

e Language Reference 5-39


Units
get_all_units()

Example
This example uses get_all_units() to print a list of the instances of XYZ_router. Note that the display
also shows that this instance of XYZ_router contains “channels”, which is a list of three unit instances.
<'
unit XYZ_router {
channels: list of XYZ_channel is instance;

keep channels.size() == 3;
keep for each in channels {
.hdl_path() == append("chan", index);
.router == me
};

};

unit XYZ_channel {
router:XYZ_router;
};

extend sys {
router:XYZ_router is instance;

run() is also {
print get_all_units(XYZ_router);
};
};
'>

Result
Specman > test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
get_all_units(XYZ_router) =
item type channels
---------------------------------------------------------------
0. XYZ_router (3 items)

See Also
• “Predefined Methods for Any Unit” on page 5-18
• “Unit-Related Predefined Methods for Any Struct” on page 5-28

5-40 e Language Reference


6 e Ports
This document describes ports, an e unit member that enhances the portability and inter-operability of
verification environments by making separation between an e unit and its interface possible.

This document discusses the following topics:

• “Introduction to e Ports” on page 6-2


• “Using Simple Ports” on page 6-6
• “Using Buffer Ports” on page 6-15
• “Using Event Ports” on page 6-17
• “Using Method Ports” on page 6-19
• “Defining and Referencing Ports” on page 6-29
• “Port Attributes” on page 6-52
• “Using Port Values and Attributes in Constraints” on page 6-81
• “Buffer Port Methods” on page 6-82
• “Multi-Value Logic (MVL) Methods for Simple Ports” on page 6-87
• “Methods for Simple Ports” on page 6-103
• “Global MVL Routines” on page 6-106
• “Port-Related Commands” on page 6-117
For information on the current limitations on ports, see “Verisity Adapters Known Limitations” on page
9-38 in About This Specman Elite Release.

e Language Reference 6-1


e Ports
Introduction to e Ports

6.1 Introduction to e Ports


A port is an e unit member that makes a connection between an e unit and its interface to another internal
or external entity. There are two ways to use ports:

• Internal ports (e2e ports) connect an e unit to another e unit.


• External ports connect an e unit to a simulated object.
External ports are a generic way to access simulated objects of various kinds. An external port is bound
to a simulated object, for example an HDL signal in the DUT. Then all access to that signal is made via
the port. The port can be used to access a different signal simply by changing the binding; all the code
that reads or writes to the port remains the same. Similarly, port semantics remain the same, regardless
of what simulator is used.

Note In this document, “simulator” means any hardware or software agent that runs in parallel with
Specman, and models the behavior of any part of the design under test (DUT) or its environment. When
using SpeXsim, “simulator” refers to the XSIM component integrated with Specman. When using
SpeXtreme, “simulator” means the RCC hardware component integrated with Specman.

6.1.1 Advantages of Using Ports


Although previous HDL access mechanisms are still supported, ports have the following advantages
over the old access mechanisms:

• Ports support modularity and encapsulation by explicitly declaring interfaces to e units.


• They are typed.
• They improve performance of accessing DUT objects with configurable names.
• They can pass not only single values but also other kinds of information, such as events and queues.
• They can be accompanied in e with generic or simulator-specific attributes that let you specify
information needed for enhanced access to DUT objects.
• They are suitable for use with a publicly available procedural External Simulator Interface (ESI).
• Some new simulator interfaces, such as SystemC, require the use of ports.

6.1.1.1 Current Limitations


For a complete list of the current limitations on ports, see “Verisity Adapters Known Limitations” on page
9-38 in About This Specman Elite Release.

6-2 e Language Reference


e Ports
Creating Port Instances

6.1.2 Creating Port Instances


Port type is defined by three aspects:

• The kind of port, either simple port, buffer port, or event port:
• Simple ports access data directly.
• Buffer ports implement an abstraction of queues with blocking get and put.
• Event ports transfer events between e units or between an e unit and a simulator.
• Method ports call regular or time-consuming methods defined in other e units or written in
foreign programming languages. They also allow calling of time-consuming e methods from
foreign programming languages.
• Direction, either input or output (or inout for simple and event ports)
• Data element, the e type that can be passed through this port
You can instantiate ports only within units. Like units, port instances are generated during prerun
generation and cannot be created, modified or removed during a run. When you instantiate a port, you
must specify:

• A unique instance name


• The port type (direction, port kind, and a kind-specific type specifier)
The generic syntax for ports is as follows:

port-instance-name: [direction] port-kind of [type-specifier] is instance;

Note Event ports do not allow a type specifier.

For example, the following unit member creates a port instance:


data_in: in buffer_port of packet is instance;

where:

• The port instance name is data_in.


• The port kind is a buffer port.
• The port direction is input.
• The data element the port accepts is “packet”.
As another example, the following line creates a list of simple ports which each pass data of type bit:
ports: list of simple_port of bit is instance;

e Language Reference 6-3


e Ports
Using Ports

6.1.3 Using Ports


A port’s behavior is influenced by port attributes, such as hdl_path() or bind(), which are applied to
port instances using pre-run generation keep constraints. For example, the following lines of code create
a port named “data” and connect (bind) it to an external simulator-related object whose HDL pathname
is “data”.
data: inout simple_port of list of bit is instance;
keep bind(data, external);
keep data.hdl_path() == "data";

The port kinds have predefined methods that you use to access the port values. For example, buffer ports
have a predefined method put(), which writes a value onto an output port:
data_out: out buffer_port of cell is instance;
drive_all() @sys.any is {
var stimuli: cell;
var counter: int=0;
while counter < cells {
wait [1]*cycle;
gen stimuli;
data_out.put(stimuli);
counter+=1;
};
};

Also, Specman has two commands, show ports and trace ports, which display port characteristics and
activity on the ports during a run.

Sample Output of show ports -full


Ports =
0. sys.ver.dut_inp - out simple_port of int (bits: 2)
e_path: sys.ver.dut_inp
agent: osci
hdl_path: sn_xor->/inp
1. sys.ver.dut_out - in simple_port of uint
e_path: sys.ver.dut_out
agent: osci
hdl_path: sn_xor->/out
2. sys.ver.clk - in event_port
e_path: sys.ver.clk
agent: osci
hdl_path: sn_xor->/clk

6-4 e Language Reference


e Ports
Ports Example

6.1.4 Ports Example


The e code in this section shows examples of instantiating and using buffer ports. An output buffer port
and an input buffer port are created, the ports are connected together, and data elements of type “cell” are
generated and transmitted from the output buffer port to the input buffer port.
1 struct cell {
2 header[2] : list of byte;
3 data[50] : list of byte;
4 };
5
6 unit trans {
7 data_out: out buffer_port of cell is instance;
8 !cells : int;
9 keep cells == 100;
10 drive_all() @sys.any is {
11 var stimuli: cell;
12 var counter: int=0;
13 while counter < cells {
14 wait [1]*cycle;
15 gen stimuli;
16 data_out.put(stimuli);
17 counter+=1;
18 };
19 };
20 };
21
22 unit rec {
23 data_in: in buffer_port of cell is instance;
24 keep data_in.buffer_size() == 20;
25 get_all() @sys.any is {
26 while TRUE {
27 print data_in.get();
28 };
29 };
30 };
31
32 extend sys{
33 transmitter: trans is instance;
34 receiver: rec is instance;
35 keep bind(transmitter.data_out, receiver.data_in);
36 run() is also {
37 start transmitter.drive_all();
38 start receiver.get_all();
39 };
40 };

e Language Reference 6-5


e Ports
Using Simple Ports

Lines 1-4 define “cell”, the data element that is passed by the output buffer port.

Line 7 creates a port instance named “data_out”, whose type is “out buffer_port of cell”.

Lines 10-19 define a TCM that generates a variable named “stimuli” of type “cell” every cycle until 100
have been generated. This variable is written to the output buffer port by a predefined buffer port TCM,
put(), in Line 16.

Line 23 creates a port instance named “data_in” of type “in buffer_port of cell”. This port complements
the “data_out” port created in the trans unit, and is used to receive cell data written to the data_out port.

Line 24 constrains the maximum number of cells that can be held in the port queue to 20.

Lines 25-29 define a TCM that retrieves and prints, one by one, the cells that have been placed on the
port queue by the drive_all() TCM. Another predefined buffer port method, get(), is used to do this.

Lines 33-35 create instances of the “rec” and “trans” units and connect the data_out port with the data_in
port.

6.2 Using Simple Ports


You can use simple ports to transfer one data element at a time to or from either an external simulated
object, such as a Verilog register, a VHDL signal or a SystemC method, or an internal object (another e
unit). A simple port’s direction can be either input, output or inout.

Internal simple ports can transfer data elements of any type. External ports can transfer scalar types and
lists of scalar types, including MVL data elements. Currently there is no support for passing structs or
lists of struct through external simple ports.

You can read or write port values using the $ port access operator. To access multi-value logic (MVL) on
simple ports, you can either declare a port’s data element to be mvl or list of mvl, or you can use the
MVL methods. See “Accessing Simple Ports and Their Values” on page 6-7 and “Multi-Value Logic (MVL)
on Simple Ports” on page 6-9 for more information.

Internal and external ports must have a bind() attribute that defines how they are connected. In addition,
you can use the delayed() attribute to control whether new values are propagated immediately or at the
next Specman tick.

An external simple port must have an hdl_path() attribute to specify the name of the object that it is
connected to. In addition, an external simple port can have several additional attributes that enable
continuous driving of external signals.

See “Port Attributes” on page 6-52 for more information on attributes for simple ports.

6-6 e Language Reference


e Ports
Accessing Simple Ports and Their Values

See Also
• “@sim Temporal Expressions with External Simple Ports” on page 6-11
• “An Internal Simple Ports Example” on page 6-12
• “An External Simple Ports Example” on page 6-13
• simple_port on page 6-30
• any_simple_port, any_buffer_port, any_event_port, any_method_port on page 6-39

6.2.1 Accessing Simple Ports and Their Values


Ports are containers, and the values they hold are separate entities from the port itself. The $ access
operator distinguishes port value expressions from port reference expressions.

The $ access operator, for example p$, is used to access or update the value held in a simple port p.
When used on the right-hand side, p$ refers to the port’s value. On the left-hand side of an assignment,
p$ refers to the value’s location, so an assignment to p$ changes the value held in the port.

Without the $ operator an expression of any type port refers to the port itself, not to its value. In
particular, an expression without the $ operator can be used for operations involving port references.

Note You cannot apply the $ access operator to an item of abstract type, such as any_simple_port.
This type does not have any access methods. The expression “port_arg$ == 0” in the following code
causes a syntax error.
foo_tcm ( port_arg : any_simple_port )@clk is {
if ( port_arg$ == 0) then { -- syntax error
out (sys.time, " Testing port logic comparison.");
};
};

Examples of Accessing Port Values


print p$; Prints the value of a simple port, p.

Note Compare with “print p”, which prints information about port p.
p$ = 0; Assigns the value 0 to a simple port, p.

Note Compare with “pref = NULL”, which modifies a port


reference so that it does not point to any port instance.
force p$ = 0; Forces a simple external port to 0.
print q$[1:0]; Prints the two least-significant bits of the value of q.

e Language Reference 6-7


e Ports
Accessing Simple Ports and Their Values

print q$[2:2]; Prints the third least-significant bit of the value of q.


print sys.pp$; Prints the value of port sys.pp.
print sys.plist[0]$; Prints the value of port plist[0] from a list of ports, plist.
print blist$[0..1]; Prints the first two elements of a list value. blist is defined as:
blist: in simple_port of list of bit is instance;
print listbl[0]$[1]; Prints the second bit in a list value of the first element in a list of ports.
Could be written (listbl[0])$[1]. listbl is defined as:
listbl: list of in simple_port of list of bit is
instance;

Note The list slicing operator [..], the list indexing operator [], and the field access operator are not
supported for ports in LHS expressions. In other words, p$[l..h], p$[i], and my_unit.p$ are not supported
on the LHS of an assignment operator.

Examples of Accessing a Port


print p; Prints the information about port p. Port p is defined as:
p: simple_port of int (bits:8) is instance;
// p = 5; An error, as it is an attempt to assign incompatible types.
keep q == p; q refers to the port instance p. Port reference q is defined as:
!q: simple_port of int (bits:8);
r = q; Port reference r refers to the port instance p too. It is defined
as:
var r: any_simple_port;
keep plist.size() == 3; plist is defined as:
plist: list of in simple_port of int
(bits:8) is instance;
keep plist[0] == p; plist[0] refers to the port instance p.
keep plist[1] == p2; plist[1] refers to the port instance p2. p2 is defined as:
p2: simple_port of int (bits:8) is
instance;
keep plist[2] == q; plist[2] refers to the port instance p (because of q).

6-8 e Language Reference


e Ports
Multi-Value Logic (MVL) on Simple Ports

See Also
• “Multi-Value Logic (MVL) on Simple Ports” on page 6-9
• simple_port on page 6-30

6.2.2 Multi-Value Logic (MVL) on Simple Ports


There are two ways to read and write multi-value logic on simple ports:

• Define numeric ports (uint, int, and so on) and use the predefined MVL methods described in
“Multi-Value Logic (MVL) Methods for Simple Ports” on page 6-87 to read and write values to the port.

• Define ports of type mvl or list of mvl and use the $ access operator to read and write values to the port.
Ports of type mvl or list of mvl (MVL ports) allow easy transformation between exact e values and
multi-value logic, which is useful for communicating with objects that sometimes model bit values other
than 0 or 1 during a test. Otherwise, using numeric ports is preferable, since numeric ports allow keeping
the port values in a bit-by-bit representation, while MVL ports require having an e list for a multi-value
logic vector.

The enumerated type mvl is defined as:

type mvl: [MVL_U, MVL_X, MVL_0, MVL_1, MVL_Z, MVL_W, MVL_L, MVL_H, MVL_N]

Notes
• You will get a syntax error if you use the Verilog comparison operators (=== or !==) with either
numeric ports or MVL ports. These operators can be used only with the tick access syntax.
• Not all supported simulators need all the potential MVL values. All nine values are supported only
for VHDL simulations. For Verilog simulations, only four values (MVL_U, MVL_X, MVL_0,
MVL_1) are supported.

Example 1 Numeric Port


This example shows how tick access notation translates to MVL methods, assuming the following
numeric port declaration:
data: inout simple_port of int is instance;
keep bind (data, external);
keep data.hdl_path() == "data";
d: int;

e Language Reference 6-9


e Ports
Multi-Value Logic (MVL) on Simple Ports

d = 'data'; d = data$;
'data' = 32'bz; data.put_mvl_list(32'bz);
check that 'data@x' == check that data.get_mvl_list().has(it == MVL_X) ==
0; FALSE;
check that data.has_x() == FALSE;
d = 'data[31:10]@z'; d = mvl_to_int(data.get_mvl_list(),
{MVL_Z})[31:0];

Example 2 MVL Port


This example shows how tick access notation translates to use of an MVL port, assuming the following
MVL port declaration:
data: inout simple_port of list of mvl is instance;
keep bind (data, external);
keep data.hdl_path() == "data";

check that 'data@x' == 0; check that data$.has(it == MVL_X} == FALSE;


check that data.has_x() == FALSE;
'data' = 32'bz; data$ = 32'bz;

Example 3 Checking Numeric Ports for MVL Values


If you have several ports that pass numeric data elements of different sizes, you might want to create a
generic method that checks these ports for MVL values such as MVL_X or MVL_Z. For example, you
can create a generic method for the following ports:
byte_port: in simple_port of byte is instance;
uint_port: in simple_port of uint is instance;

The correct way to create a generic method is to pass the port value, not the port itself, to the method.
You must convert the port value to the desired type before passing it. For example:
x_chk(m: list of mvl) is inline {
check that m.has(it == MVL_X) == FALSE else
dut_error("Bus has value of X!");
};
run() is also {
x_chk(byte_port.get_mvl_list());
x_chk(uint_port.get_mvl_list());
};

6-10 e Language Reference


e Ports
@sim Temporal Expressions with External Simple Ports

See Also
• “Multi-Value Logic (MVL) Methods for Simple Ports” on page 6-87
• “Methods for Simple Ports” on page 6-103
• “Global MVL Routines” on page 6-106

6.2.3 @sim Temporal Expressions with External Simple


Ports
When you specify an event port, you cause Specman to be sensitive to the corresponding HDL signal
during the entire simulation session. This might result in some unnecessary runtime performance cost if
you need Specman to be sensitive only in certain scenarios. In such cases you can use an external simple
port in temporal expressions with @sim, using the following syntax:

[change|rise|fall](simple-port$)@sim;

Normally you use this syntax in wait actions. For example:


transaction_complete: in simple_port of bit is instance;
keep bind(transaction_complete, external);

write_transaction(data: list of byte) @clk$ is {


...
data_port$ = data;
wait rise(transaction_complete$)@sim;
};

This syntax might be also useful if you are interested in accessing a value of a signal, in addition to
knowing if it changed. For example:
counter: in simple_port of uint is instance;
keep bind(counter, external);

event counter_change is change(counter$)@sim;


on counter_change {
if (counter$ >= 255) {out("Counter is full")};
};

Example
unit collector {
pclk1: in simple_port of bit is instance;
dataport: in simple_port of byte is instance;

read_packet(pclk: in simple_port of bit) @sys.any is {

e Language Reference 6-11


e Ports
An Internal Simple Ports Example

var p: packet = new;


var len := dataport$;
for j from 0 to len - 1 {
wait fall(pclk$)@sim;
p.data.add(dataport$);
};
sys.packets.add(p);
};
run() is also {
start read_packet(pclk1);
};
};

Trying to apply the @sim operator to a bound internal port causes an error when the corresponding
temporal expression is evaluated, which occurs at runtime.

See Also
• simple_port on page 6-30

6.2.4 An Internal Simple Ports Example


This example shows two units communicating through simple ports, with no external ports.
unit u1 {
p1: in simple_port of int(bits:64) is instance;
// Define a simple port
doit()@sys.any is {
for i from 1 to 10 do {
wait cycle;
print p1$; // Do a get from the port
wait cycle;
};
stop_run();
};
run() is also {
start doit();
};
};
unit u2 {
p2: out simple_port of int(bits:64) is instance;
// Define another simple port
doit()@sys.any is {
var v: int(bits:64);
while TRUE {
gen v;

6-12 e Language Reference


e Ports
An External Simple Ports Example

p2$ = v;
wait cycle;
wait cycle;
};
};
run() is also {
start doit();
};
};
extend sys {
u1: u1 is instance;
u2: u2 is instance;
keep bind(u1.p1, u2.p2); // Bind the two ports
};

6.2.5 An External Simple Ports Example


The following e code describes a testbench component that drives data into an encoder and checks the
output of the encoder for errors.

In this example the clk, data_length, data, address and rq ports are external ports associated with various
Verilog signals. The name of the simulator is established by the pre-run generation constraint on Line 67
(keep e.agent() == “verilog”). You can re-direct the access to another simulator (and possibly, to another
modeling language) by changing this constraint.

Verilog objects associated with the external ports are registers (clk, temp_address, data_width) and nets
(data). On the Specman side, each port’s behavior corresponds to its specified type—event port, simple
port, or buffer port. The event port clk, in Line 3, is used to synchronize Specman with the simulator. Port
rq, in Line 21, illustrates the declaration of a buffer port. The other ports read and write the specified
Verilog objects directly.

The postfix $ access operator, for example clk$ or data$ in Line 29 and Line 32, is used to access the
event associated with an event port or to read or write to a simple port. Access to a buffer port, on the
other hand, is performed using the predefined methods for buffer ports, get() and put(), as shown in Line
42.

1 unit encoder {
2
3 clk: in event_port is instance;
4 keep bind(clk, external);
5 keep clk.hdl_path() == "clk";
6
7 data_length: in simple_port of uint is instance;
8 keep bind(data_length, external);
9 keep data_length.hdl_path() == "data_width";
10

e Language Reference 6-13


e Ports
An External Simple Ports Example

11 data: inout simple_port of list of bit is instance;


12 keep bind(data, external);
13 keep data.hdl_path() == "data";
14 keep data.verilog_wire() == TRUE; -- simple port attribute
15 keep data.declared_range() == "[31:0]"; -- simple port attribute
16
17 address: in simple_port of uint is instance;
18 keep bind(address, external);
19 keep address.hdl_path() == "PRIO/temp_address";
20
21 rq: in buffer_port of bool is instance;
22 keep bind(rq, external);
23 keep rq.buffer_size() == 8; -- buffer port attribute
24 keep rq.hdl_path() == "rq";
25
26 data_list: list of bit;
27 keep data_list.size() < 32;
28
29 inject()@clk$ is {
30 for j from 0 to 15 {
31 gen data_list;
32 data$ = data_list;
33 wait cycle;
34 };
35 stop_run();
36 };
37
38 checker() @clk$ is {
39 while TRUE {
40 wait cycle;
41
42 if not rq.get() {
43 check that address$ == 0;
44 check that data$.has(it != 0)== FALSE;
45 } else {
46 check that address$ != 0;
47 var mask: uint = 0x10000000;
48 for {var i: byte = data_length$ - 1; i>0; i -= 1} {
49 if (data$[31:0] & mask) != 0 {
50 check that address$ == i;
51 break;
52 };
53 mask >>= 1;
54 };
55 };
56 };
57 };

6-14 e Language Reference


e Ports
Using Buffer Ports

58 run() is also {
59 start inject();
60 start checker();
61 };
62 };
63
64 extend sys {
65 e: encoder is instance;
66 keep e.hdl_path() == "~/priority_encoder";
67 keep e.agent() == "verilog";
68
69 };

6.3 Using Buffer Ports


You can use buffer ports to insert data elements into a queue or extract elements from a queue. Data is
inserted and extracted from the queue in FIFO order. When the queue is full, write access to the port is
blocked. When the queue is empty, read access to the port is blocked.

The queue size is fixed during generation by the buffer_size() attribute and cannot be changed at
runtime. The queue size may be set to 0 for rendezvous ports. See buffer_size() on page 6-64 and
“Rendezvous-Zero Size Buffer Queue” on page 6-16 for more information.

A buffer port’s direction can be either input or output. Inout is not supported. Internal buffer ports can
transfer data elements of any type. Currently the Verisity adapters do not support external buffer ports.

You can read or write port values using the buffer port’s predefined get() and put() methods. These
methods are time-consuming methods (TCMs). Use of the $ port access operator with buffer ports is not
supported.

Buffer ports must have a bind() attribute that defines how they are connected. In addition, you can use
the delayed() attribute to control whether new values are propagated immediately or at the next Specman
tick. The pass_by_pointer() attribute controls how data elements of composite type are passed. See “Port
Attributes” on page 6-52 for more information on these attributes.

See Also
• “An Internal Buffer Ports Example” on page 6-16
• “buffer_port” on page 6-32
• “any_simple_port, any_buffer_port, any_event_port, any_method_port” on page 6-39
• “Methods for Simple Ports” on page 6-103

e Language Reference 6-15


e Ports
Rendezvous-Zero Size Buffer Queue

6.3.1 Rendezvous-Zero Size Buffer Queue


In rendezvous-style handshaking protocol, access to a port is blocked after each put() until a subsequent
get() is performed, and access is blocked after each get() until a subsequent put() is performed.

This style of communication is easily achieved by using buffer ports with a data queue size of 0. The
following example shows how this is done.

Example
unit consumer {
in_p: in buffer_port of atm_cell is instance;
};

unit producer {
out_p: out buffer_port of atm_cell is instance;
};

extend sys {
consumer: consumer is instance;
producer: producer is instance;
keep bind(producer.out_p, consumer.in_p);
keep producer.out_p.buffer_size() == 0;
};

See Also
• buffer_port on page 6-32

6.3.2 An Internal Buffer Ports Example


This example shows two units communicating through buffer ports, with no external ports.
unit producer {
p: out buffer_port of atm_cell is instance;
producer()@sys.any is {
var cell: atm_cell;
for i from 1 to 100 do {
gen cell;
p.put(cell) // Waits if the buffer is full
};
stop_run();
};
};
unit consumer {
p: in buffer_port of atm_cell is instance;

6-16 e Language Reference


e Ports
Using Event Ports

consumer()@sys.any is {
while (TRUE) do {
var cell: atm_cell;
cell = p.get(); // Waits if the buffer is empty
// Inject the cell into the DUT
};
};
};
extend sys {
consumer: consumer is instance;
producer: producer is instance;
keep bind(producer.p, consumer.p);
keep producer.p.buffer_size() == 10;
};

6.4 Using Event Ports


You can use event ports to transfer events between two e units or between an e unit and an external
object. An internal event port’s direction can be either input, output or inout. Currently external out and
inout event ports are supported only by Verisity’s SystemC adapter.

You can read or write port values using the $ port access operator. See “Accessing Event Ports” on page
6-17 for more information.

Internal and external ports must have a bind() attribute that defines how they are connected.

An external port must have an hdl_path() attribute to specify the name of the object that it is connected
to. The edge() attribute for an external input event port specifies the edge on which an event is
generated.

See “Port Attributes” on page 6-52 for more information on these attributes.

See Also
• event_port on page 6-34
• any_simple_port, any_buffer_port, any_event_port, any_method_port on page 6-39

6.4.1 Accessing Event Ports


The $ access operator is used to access the event associated with an event port. An expression of type
event_port without the ‘$’ operator refers to the port itself and not to its event.

e Language Reference 6-17


e Ports
Accessing Event Ports

Example 1
emit me.ep$;
monitor()@ep$ is { ... };
wait @lep[0]$;
event ep1 is @ep$;
wait cycle @ep$;
expect @a => { ... }@ep$;

Example 2
This example shows how to connect event ports, using a bind() constraint, and how to use the $ operator
to access event ports in event contexts.
unit u1 {
in_ep: in event_port is instance;
tcm1()@in_ep$ is {
// ...
};
};

unit u2 {
out_ep: out event_port is instance;
event clk is @sys.any;
counter: uint;
on clk {
counter = counter + 1;
if counter %10 == 0 {
emit out_ep$
};
};
};

extend sys {
u1: u1 is instance;
u2: u2 is instance;
keep bind(u1.in_ep,u2.out_ep);
};

See Also
• “Methods for Simple Ports” on page 6-103

6-18 e Language Reference


e Ports
Using Method Ports

6.5 Using Method Ports


Method ports let you call regular or time-consuming methods defined in other e units or written in
foreign programming languages. The advantages of method ports are:

• You can implement a transaction-level interface between Specman and a high-level model described
in a foreign language.
• You can postpone the decision about which method to call (an e method or a foreign function, for
example) from compile time to pre-run generation.
Note Currently, Method ports can only be used with internal (e2e) ports or with SystemC. They cannot
be used with HDL simulators.

Figure 6-1 shows an e Bus Functional Model (BFM) that calls a write method in the e client, passing to
that method some generated input data. The client manipulates the data and then passes back the
modified data by calling a check method in the BFM.

Figure 6-1 Internal Method Port Interface

e e
BFM write$(burst) Client

check$(burst)

Figure 6-2 shows an e BFM that calls a write function in a foreign agent, passing to that method some
generated input data. The foreign agent manipulates the data and then passes back the modified data by
calling a read method in the BFM.

Figure 6-2 External Transaction Level Interface

e Foreign
write$(burst)
BFM Agent

check$(burst)

e Language Reference 6-19


e Ports
Using Method Ports Overview

Figure 6-3 shows a variation of the above example, where the foreign agent emits an event, in this case
an event port called “notify”. This causes the e BFM to call a read function in the foreign agent, which
returns the manipulated data.

Figure 6-3 External Transaction Level Interface Using an Event Port

write$(burst)
e Foreign
BFM emit notify$ Agent

read$():burst

6.5.1 Using Method Ports Overview


To implement an internal method port interface:

1. Define a method type that matches the prototype of the associated method.

The method type specifies the semantics of the method port, for example:
method_type burst_method_t (b: burst)@sys.any;

2. Specify an output method port instance in the e unit that makes the call, for example:
write: out method_port of burst_method_t is instance;

write$(burst)
e e
BFM Client

write: out method_port of


burst_method_t is
instance;

3. Specify an input method port instance in the enclosing unit of the method to be called, for example:
write_scoreboard: in method_port of burst_method_t is instance;
Because the input port instance is associated with the actual method by name, the names must
match exactly.

6-20 e Language Reference


e Ports
Using Method Ports Overview

e e
BFM write$(burst) Client

write: out method_port of write_scoreboard: in


burst_method_t is method_port of
instance; burst_method_t is instance;
write_scoreboard(data:burst)
@clk is {…};

4. Bind the method ports, for example:


keep bind(e_bfm.write, e_client.write_scoreboard);

5. Invoke the method by applying the $ operator to the output method port, for example;
write$(b);

Notes
• You can call only the output port, not the input port.
• You can bind internal ports only if they are the same method type.

To call a function in a foreign agent from e:

1. Define a method type that matches the foreign function prototype.

The method type specifies the semantics of the method port, for example:
method_type burst_method_t (b: burst)@sys.any;

2. Create an output method port instance in the e unit that makes the call, for example:
write: out method_port of burst_method_t is instance;

write$(burst)
e Foreign
BFM Agent

write: out method_port of


burst_method_t is
instance;

e Language Reference 6-21


e Ports
Using Method Ports Overview

3. Bind the method port, for example:


keep bind(e_bfm.write, external);

4. Specify the corresponding path in the foreign model (hdl_path()) and other language-specific
attributes such as hdl_convertor().

See “Generic Port Attributes” on page 6-53 for more information.

5. Invoke the method by applying the $ operator to the output method port, for example;
write$(b);

To call an e method from a foreign agent:

1. Define a method type that matches the e method prototype.

The method type specifies the semantics of the method port, for example:
method_type burst_method_t (b: burst)@sys.any;

2. Specify an input method port instance in the e unit that contains the method to be called, for example:
read: in method_port of burst_method_t is instance;
Because the input port instance is associated with the actual method by name, the names must
match exactly.

e Foreign
BFM Agent

read: in method_port of
burst_method_t is instance; read$(burst)

read(data:burst)@clk is {…};

3. Bind the method ports, for example:


keep bind(e_bfm.read, external);

4. Specify the corresponding path in the foreign model (hdl_path()) and other language-specific
attributes such as hdl_convertor() and sync_mode().

See “Generic Port Attributes” on page 6-53 for more information.

6-22 e Language Reference


e Ports
Method Ports Examples

6.5.2 Method Ports Examples


This section contains the following examples:

• “Internal Method Ports Example” on page 6-23


• “Example Use of List of Method Ports” on page 6-24

6.5.2.1 Internal Method Ports Example


This example shows how an e unit activates another unit’s methods using a method port.
-- define a method type
method_type write_packet_method_t (p : packet)@sys.any;
unit verifier {
packet_senders: list of out method_port of
write_packet_method_t is instance;
p : packet;
verify() @sys.any is {
-- iterate over the method ports
for each in packet_senders {
gen p;
-- invoke the actual method by applying the
-- $ operator to the out method port
it$(p);
};
};
};
unit client {
event clk;
scoreboard: list of packet;
-- instantiate an input port for method write_scoreboard
write_scoreboard : list of in method_port of
write_packet_method_t is instance;

write_scoreboard(p : packet )@clk is {


out ("Writing packet to scoreboard");
print p;
scoreboard.add(p);
};
};
extend sys {
client : client is instance;
keep client.write_scoreboard.size() == 3;
ver : verifier is instance;
keep ver.packet_senders.size() == 3;
-- bind the method ports

e Language Reference 6-23


e Ports
Method Ports Examples

keep for each in ver.packet_senders {


bind(it, client.write_scoreboard[index]);
};
};

6.5.2.2 Example Use of List of Method Ports

--------------------------------
-- Define the publisher
--------------------------------
method_type deliver_method_t (msg_id : string);

unit publisher {

-- Define a distribution list to hold the subscribers


------------------------------
!distribution_list : list of out method_port of deliver_method_t;

-- Define a simple publish routine


------------------------------
publish(msg : string) is {
for each in distribution_list {
it$(msg);
};
};

-- On run, publish the local unique struct ID


------------------------------
run() is also {
publish(me.to_string());
};

};

--------------------------------
-- Define the subscriber
--------------------------------
unit subscriber {

-- Define an inbox method


------------------------------
inbox_int(msg_id : string) is {
outf("%s is subscribed to = %s\n",me.to_string(),msg_id);
};

6-24 e Language Reference


e Ports
Method Ports Examples

-- Define the ports that allow the


-- inbox to be treated as a field
------------------------------
inbox : out method_port of deliver_method_t is instance;
inbox_int : in method_port of deliver_method_t is instance;
keep bind(inbox,inbox_int);

};

-------------------------------
-- Add some publishers and subscribers to Sys
-------------------------------
extend sys {

p1 : publisher is instance;
p2 : publisher is instance;
p3 : publisher is instance;

s1 : subscriber is instance;
s2 : subscriber is instance;
s3 : subscriber is instance;
s4 : subscriber is instance;
s5 : subscriber is instance;
s6 : subscriber is instance;
s7 : subscriber is instance;
s8 : subscriber is instance;

-- Add subscribers to publishers' distribution lists


-- (more or less at random)
----------------------------
post_generate() is also {
p1.distribution_list.add({s1.inbox;
s2.inbox;
s3.inbox;
s4.inbox;
s5.inbox;
s6.inbox;
s7.inbox;
s8.inbox});

p2.distribution_list.add({s2.inbox;
s3.inbox;
s5.inbox;
s8.inbox});

p3.distribution_list.add({s1.inbox;

e Language Reference 6-25


e Ports
Method Types

s5.inbox;
s6.inbox});
};

};

6.5.3 Method Types


A method port must be parameterized by a type of a special kind—a method type. The method type
specifies the prototype (signature) of the method. For example, the following declares a method type for
a method that accepts two integer arguments and returns an integer:
method_type adder_method_t (arg1: int, arg2: int): int;

A method type that is associated with a TCM must be defined with the @sys.any sampling event, for
example:
method_type send_packet_method_t (p : packet)@sys.any;

Method types must be defined with a unique name, and this name must be explicitly specified in the
instance declaration of the method port. For example, the following associates the “add” method port
with the “adder_method_t” method type:
add: out method_port of adder_method_t is instance;

Parameter mapping in e is positional, so the names of the formal parameters do not have to match the
actual parameter list. However, it is recommended to use meaningful formal parameter names to
improve the readability of the code.

Note The method type has semantic implications for the port beyond the simple matching of
parameters and result types. The method type is also used to clarify runtime messages related to a
particular method port. Thus, you cannot bind two method ports just because they have the same
signature; they must also be associated with the same method type.

Example
method_type adder_method_t (arg1: int, arg2: int): int;
method_type subtractor_method_t (arg1: int, arg2: int): int;
unit calculator {
add(arg1: int, arg2: int): int is { result = arg1 + arg2; };
add: in method_port of adder_method_t is instance;
};
extend sys {
calculator1: calculator is instance;
calculator2: calculator is instance;
op1: out method_port of adder_method_t is instance;
op2: out method_port of subtractor_method_t is instance;

6-26 e Language Reference


e Ports
Input Method Ports

keep bind(op1, calculator1.add); -- OK


keep bind(op2, calculator2.add); -- ERROR: method types are different
};

The method port “op2”, which is associated with the “subtractor_method_t” method type, cannot be
bound to port “calculator.add”, even though both methods receive two integer parameters and return an
integer result. This similarity is not enough to make them compatible; they must have the same method
type.

See Also
• method_type method-type-name on page 6-37

6.5.4 Input Method Ports


An input method port declares an e method as callable from another e unit or from a foreign agent. The
method port instance:

• Must reside in the same unit as its associated method


• Must have an instance name that matches the name of the associated method
• Must have a method type that matches the prototype of the associated method
The method prototype and the method type match if:
• They have the same number of parameters.
• Parameter types, if any, are literally equivalent.
• Return value, if any, is of the same type.
• For TCMs, the method type declaration must include the @sys.any sampling event.
Notes
• Inline methods cannot be associated with method ports.
• Input method ports can be externally bound. The only Verisity adapters that support external input
method ports currently are the SystemC adapters (OSCI and NC SystemC).

Example
method_type write_transaction_method_t (t: xyz_transaction): bool;
method_type report_transaction_method_t (t: xyz_transaction);
unit xyz_server {
scoreboard(t: xyz_transaction) is {
...

e Language Reference 6-27


e Ports
Output Method Ports

};
};
...
extend xyz_server {
scoreboard: in method_port of report_transaction_method_t is instance;
};

See Also
• method_port on page 6-38

6.5.5 Output Method Ports


Output method ports let you call regular or time-consuming methods defined in other e units or written
in foreign programming languages.

Example
unit xyz_client {
write: out method_port of write_transaction_method_t is instance;
keep bind(write, external); -- external binding
keep write.hdl_path() == "transactor";
keep write.hdl_convertor() == "(transaction: TRCONV)";
mark: out method_port of report_transaction_method_t is instance;
};
extend sys {
client: xyz_client is instance;
keep client.write.hdl_path() == "~/ip";
keep client.agent() == "systemc";
server: xyz_server is instance;
keep bind(client.mark, server.scoreboard); -- internal binding
};

See Also
• method_port on page 6-38

6.5.6 Invoking Method Ports


You must use the ‘$’ operator in order to call the method port.

The rules for parameter type checking, time-consuming method call requirements, and so on are the
same as those for invoking an e method directly. In particular, TCM method ports can only be called
from inside a TCM scope.

6-28 e Language Reference


e Ports
Defining and Referencing Ports

For input TCM method ports, you cannot activate the same instance of a port multiple times in parallel.
The same restriction applies for output TCM method ports. A runtime error is issued if your code
attempts to invoke an input TCM method port before the previous call has completed. (If the input TCM
method port is an external port, then the error message is issued by the simulator adapter.)

The parameter passing semantics are the same as in direct calls to e methods. Scalar parameters are
passed by value, while composite parameters (struct or list types) are passed by pointer.

Notes
• Do not rely on the ability to modify separate fields or list elements of the incoming parameter in the
actual method. In particular, this ability cannot be supported for external method ports. The return
value (or explicit passing of parameters by reference) must be used instead.
• All ports are elaborated after the end of post_generate(). Thus, you cannot invoke method ports either
before generation or from constraints.
• Calling an empty-bound method port is equivalent to calling an empty e method.

Example
extend xyz_client {
clock: in event_port is instance;
keep bind(clock, external);
keep clock.hdl_path() == "clock";
tr_list[17]: list of xyz_transaction;
verify() @clock$ is {
for each in tr_list {
if write$(it) == TRUE {
mark$(it);
};
};
};
};

See Also
• method_port$() on page 6-51

6.6 Defining and Referencing Ports


This section covers the following topics:

• simple_port on page 6-30


• buffer_port on page 6-32

e Language Reference 6-29


e Ports
simple_port

• event_port on page 6-34


• method_type method-type-name on page 6-37
• method_port on page 6-38
• any_simple_port, any_buffer_port, any_event_port, any_method_port on page 6-39
• port$ on page 6-41
• port$[ : ] on page 6-43
• force port$ on page 6-47
• release port on page 6-49
• force port$[ : ] on page 6-50
• method_port$() on page 6-51

6.6.1 simple_port

Purpose
Access other port instances or external simulated objects directly

Category
Unit member

Syntax
port-instance-name: [list of] [direction] simple_port of element-type is instance;

Syntax Example
data: in simple_port of byte is instance;

Parameters

port-instance-name A unique identifier you can use to refer to the port or access its value.

6-30 e Language Reference


e Ports
simple_port

direction One of in, out, or inout. The default is inout, which means that you
can read values from and write values to this port. For an in port, you
can only read values from the port, and for an out port you can only
write values to the port.

element-type Any predefined or user-defined e type except a port type or a unit


type.

Description
You can use simple ports to transfer one data element at a time to or from either an external simulated
object or an internal object (another e unit).

Internal simple ports can transfer data elements of any type. External ports can transfer scalar types and
lists of scalar types, including MVL data elements. Currently there is no support for passing structs or
lists of struct through external simple ports.

The port can be configured to access a different signal simply by changing the binding; all the code that
reads or writes to the port remains the same. Similarly, port semantics remain the same, regardless of
what simulator is used. Binding is fixed during generation.

A simple port’s direction can be either input, output, or inout. The direction specifier in a simple port is
not a when subtype determinant. This means, for example, that the following type:
data: simple_port of byte is instance;

is not the base type of:


data: out simple_port of byte is instance;

Furthermore, the following types are fully equivalent:


data: simple_port of byte is instance;
data: inout simple_port of byte is instance;

Thus, the following constraint is an error because the two types are not equivalent:
data: out simple_port of byte is instance;
!data_ref: simple_port of byte; // means inout simple_port of byte
keep data_ref == data; // error

Notes
• Simple ports of int(bits: *) are not supported by any simulator adapter provided by Verisity.
• Passing structs of lists of structs through external simple ports is not supported by any simulator
adapter provided by Verisity.

e Language Reference 6-31


e Ports
buffer_port

Example
<'
unit encoder {

data: out simple_port of int(bits:64) is instance;


keep bind(data, external);
keep data.hdl_path() == "data";

drive()@sys.any is {
var v: int(bits:64);
while TRUE {
gen v;
data$ = v;
wait cycle;
wait cycle;
};
};
run() is also {
start drive();
};
};
'>

See Also
• “Using Simple Ports” on page 6-6
• “any_simple_port, any_buffer_port, any_event_port, any_method_port” on page 6-39
• “Multi-Value Logic (MVL) Methods for Simple Ports” on page 6-87
• “Global MVL Routines” on page 6-106
• “Methods for Simple Ports” on page 6-103

6.6.2 buffer_port

Purpose
Implement an abstraction of queues with blocking get and put

Category
Unit member

6-32 e Language Reference


e Ports
buffer_port

Syntax
port-instance-name: [list of] direction buffer_port of element-type is instance;

Syntax Example
rq: in buffer_port of bool is instance;

Parameters

port-instance-name A unique identifier you can use to refer to the port or access its value.

direction One of in or out. There is no default. For an in port, you can only read
values from the port, and for an out port you can only write values to
the port. See “Buffer Port Methods” on page 6-82 for information on
how to read and write buffer ports.

element-type Any predefined or user-defined e type except a unit or a port type.

Description
You can use buffer ports to insert data elements into a queue or extract elements from a queue. Data is
inserted and extracted from the queue in FIFO order. When the queue is full, write access to the port is
blocked. When the queue is empty, read access to the port is blocked.

The queue size is fixed during generation by the buffer_size() attribute and cannot be changed at
runtime. The queue size may be set to 0 for rendezvous ports.

You can read or write port values using the buffer port’s predefined get() and put() methods. These
methods are time-consuming methods (TCMs). Use of the $ port access operator with buffer ports is not
supported.

A typical usage of a buffer port is in a producer and consumer protocol, where one object puts data on
an output port at possibly irregular intervals, and another object with the corresponding input port reads
the data at its own rate.

Notes
• Exernal buffer ports are not supported by any simulator adapter provided by Verisity.

Example
unit encoder {

rq: in buffer_port of bool is instance;


keep rq.buffer_size() == 8; -- buffer port attribute

e Language Reference 6-33


e Ports
event_port

};

See Also
• “Using Buffer Ports” on page 6-15
• “Buffer Port Methods” on page 6-82
• “Methods for Simple Ports” on page 6-103

6.6.3 event_port

Purpose
Transfer events between units or between simulators and units

Category
Unit member

Syntax
event-port-field-name: [list of] [direction] event_port is instance;

Syntax Example
clk: in event_port is instance;

Parameters

event-port-field-name A unique identifier you can use to refer to the port or access its value.

direction One of in, out, or inout. The default is inout, which means that events
can be both emitted and sampled on the port. For a port with direction
in, events can only be sampled. For a port with direction out, events
can only be emitted.

Description
You can use event ports to transfer events between two e units or between an e unit and an external
object.

6-34 e Language Reference


e Ports
event_port

You can read or write port values using the $ port access operator. See “Accessing Event Ports” on page
6-17 for more information.

An internal event port’s direction specifier can be either input, output or inout. The direction specifier is
not a when subtype determinant. This means, for example, that the following type
clk: event_port is instance;

is not the base type of


clk: out event_port is instance;

Furthermore, the following types are fully equivalent:


clk: event_port is instance;
clk: inout event_port is instance;

Notes
• Currently, external out and inout event ports are not supported.
• The on struct member for event ports is not supported.
• Coverage on event ports is currently not supported.
• The echo event command is not supported for event ports.
• It is impossible to specify a temporal formula (like “event_port is …”) for definition of an out event
port.

In order to use any of the above unsupported capabilities (except the first in the list) it is possible to
define an additional event and connect it to the event port as follows:
ep: in event_port is instance;
keep bind(ep,external);
event e is @ep$;

Example 1
References to event ports are supported. In the following example, current_clk is an event port
reference.
unit u {
clks: list of in event_port is instance;
events: list of out event_port is instance;
};

extend u {
!current_clk: in event_port;

e Language Reference 6-35


e Ports
event_port

keep current_clk == clks[0];


};

Example 2
You can pass an event port as a parameter to a TCM. In this example, each event in a list of events is
passed as a parameter to the drive() method.
extend u {
drive(ep: out event_port) @current_clk$ is {
emit ep$;
};

run() is also {
for each in events do {
start drive(it);
};
};
};

Example 3
The attribute hdl_path() must be specified for external event ports. In the following example, only a
“cti” simulator can emit ext_ep. Presumably there is some DUT event related to a simulated item
“~/top_s/transaction_done”.
unit u {
ext_ep: in event_port is instance;
keep bind(ext_ep,external);
keep ext_ep.hdl_path() == "transaction_done";
};
extend sys {
u: u is instance;
keep u.hdl_path() == "top_s";
};

Example 4

This example shows how to configure an event port to emit based either on an HDL signal change or on
sys.any (if no simulator is attached).
<'
extend sys {
e_clock_port : out event_port is instance;
on any {

6-36 e Language Reference


e Ports
method_type method-type-name

emit e_clock_port$;
};

my_event_port: in event_port is instance;


keep my_event_port.hdl_path() == "~/top/clk";

dut_connected: bool;
keep dut_connected == FALSE => bind(my_event_port,e_clock_port);
keep dut_connected == TRUE => bind(my_event_port,external);
};

'>

See Also
• “Using Event Ports” on page 6-17
• “Methods for Simple Ports” on page 6-103

6.6.4 method_type method-type-name

Purpose
Define method port semantics and enable notification

Category
Statement

Syntax
method_type method-type-name ([param-list]) [:return-type] [@sys.any];

Syntax example:
method_type str2uint_method_t (s: string):uint;

Parameters

method-type-name A legal e name. The name must be different from any other predefined
type name or user type name.

e Language Reference 6-37


e Ports
method_port

param-list The parameter list must match the parameter list of the e method or
external function.

return-type The type of the returned value must match the return type of the e
method or external function.

@sys.any If the method type declaration includes the @sys.any sampling event,
this type can only be used for method ports associated with a TCM.

Description
A method port must be parameterized by a method type, which specifies the prototype (signature) of the
method. The method type name may also be included in runtime messages related to a specific method
port.

See Also
• “Using Method Ports Overview” on page 6-20

6.6.5 method_port

Purpose
Enable invocation of abstract functions

Category
Unit member

Syntax
port-instance-name: [list of] direction method_port of method-type is instance;

Syntax example:
convert_string: out method_port of str2uint_method_t is instance;

6-38 e Language Reference


e Ports
any_simple_port, any_buffer_port, any_event_port, any_method_port

Parameters

port-instance-name A unique identifier you can use to refer to the port or to invoke the
actual method.

Note For input method ports, this name must match the actual name
of the associated method.

direction One of in or out. There is no default. For an output port, you can
invoke the method. For an input port you can only specify the actual
method to be activated.

method-type A method_type that specifies the port semantics.

Description
Implements an abstraction of calling methods (time-consuming or not) in other units or in external
agents, while delaying the binding from compile time to pre-run generation time.

See Also
• “Using Method Ports Overview” on page 6-20

6.6.6 any_simple_port, any_buffer_port, any_event_port,


any_method_port

Purpose
Reference a port instance

Category
Unit field, variable or method parameter, port type

Syntax
[! | var] port-reference-name: [direction] port-kind [of element-type]

[! | var] port-reference-name: any-port-kind

Syntax Example
!last_printed_port: any_buffer_port;

e Language Reference 6-39


e Ports
any_simple_port, any_buffer_port, any_event_port, any_method_port

!in_int_buffer_port_ref: in buffer_port of int;

!in_method_port_ref: in method_port of burst_method_t;


!last_called_port: any_method_port;

Parameters

port-reference-name A unique identifier.

direction One of in, out, or, for simple ports and event ports, inout

port-kind One of simple_port, buffer_port, any_event_port, or any_method_port

any-port-kind One of any_simple_port, any_buffer_port, any_event_port, or


any_method_port

element-type Required if port-kind is simple_port, buffer_port, or any_method_port

Description
Port instances may be referenced by a field, a variable, or a method parameter of the same port type or
of an abstract type:

• any_simple_port
• any_buffer_port
• any_event_port
• any_method_port
Abstract port types reference only the port kind, not the port direction or data element. Thus, a method
parameter of type any_simple_port accepts all simple ports, including, for example:
data_length: in simple_port of uint is instance;
data: inout simple_port of list of bit is instance;

If a port reference is a field, then it must be marked as non-generated or it must be constrained to an


existing port instance. Otherwise, a generation error results.

Port binding is allowed only for port instance fields, not for port reference fields. Trying to apply a keep
bind() constraint to a port reference results in an error.

6-40 e Language Reference


e Ports
port$

Notes
• You cannot apply the $ access operator to an item of type any_simple_port, any_event_port, or
any_method_port, any_event_port. Abstract types do not have any access methods. For example,
the expression “port_arg$ == 0” in the following code causes a syntax error.
foo_tcm ( port_arg : any_simple_port )@clk is {
if ( port_arg$ == 0) then { -- syntax error
out (sys.time, " Testing port logic comparison.");
};
};

• You cannot use an abstract type in a port instance; you must specify the element type.

Example
The print_port() method in the following example can be called with any buffer port. The iterate()
method shows an alternative way to print a list of ports.
unit u {
plist: list of in buffer_port of int is instance;
!last_printed_port: any_buffer_port; // A field, so must be
// non-generated

print_port(p: any_buffer_port) is { // A method parameter


print p; // Prints the port's e path, agent name, and so on
last_printed_port = p;
};

iterate() is {
for each in plist {
in_int_buffer_port_ref = it;
print_port(in_int_buffer_port_ref);
};
};

};

6.6.7 port$

Purpose
Read or write a value to a simple port, or emit or be sensitive to event port or call an out method port

e Language Reference 6-41


e Ports
port$

Category
Operator

Syntax
exp$

Syntax Example
p$ = 32'bz; // Assigns an mvl literal to the port 'p'

Parameters

exp An expression that returns a simple port, method port, or event port instance.

Description
The $ access operator is used to access or update the value held in a simple port, or emit or be sensitive
to event port or call an out method port. When used with a simple port, on the right-hand side, p$ refers
to the port’s value. On the left-hand side of an assignment, p$ refers to the value’s location, so an
assignment to p$ changes the value held in the port.

Without the $ operator an expression of any type port refers to the port itself, not to its value. In
particular, an expression without the $ operator can be used for operations involving port references.

Note You cannot apply the $ access operator to an item of type any_simple_port, any_method_port,
or any_event_port. Abstract types do not have any access methods. For example, the expression
“port_arg$ == 0” in the following code causes a syntax error.
foo_tcm ( port_arg : any_simple_port )@clk is {
if ( port_arg$ == 0) then { -- syntax error
out (sys.time, " Testing port logic comparison.");
};
};

Example
<'
unit u {
free_port(p: inout simple_port of list of mvl) is {
p$ = 32'bz; // Assigns an mvl literal to the port
};
};
'>

6-42 e Language Reference


e Ports
port$[ : ]

See Also
• “Accessing Simple Ports and Their Values” on page 6-7
• “Accessing Event Ports” on page 6-17
• “Multi-Value Logic (MVL) on Simple Ports” on page 6-9
• “Methods for Simple Ports” on page 6-103

6.6.8 port$[ : ]

Purpose
Read or write a value to a bit or a bit slice of a simple port

Category
Operator

Syntax
simple-port-exp$[[high-exp]:[low-exp][: slice]] = rhs-exp

lhs-exp = simple-port-exp$[[high-exp]:[low-exp][: slice]]

Syntax Example
p$[10:3] = 123;
p$[:] = 0x17;

Parameters

simple-port-exp An expression that returns a simple port instance. The element type has to be scalar,
list of bit or list of byte.

high-exp A non-negative numeric expression, greater than or equal to the low expression. To
extract a single bit, use the same expression for both the high and the low
expression.

low-exp A non-negative numeric expression, less than or equal to the high expression.
Default is zero.

e Language Reference 6-43


e Ports
port$[ : ]

slice One of bit, byte, int, or uint. The default is bit.

rhs-exp A numeric expression.

lhs-exp A expression that returns an e variable or field.

Description
The bit slicing operator can be used in a left-hand side (LHS) or right-hand side (RHS) port access
expression. The syntax of the bit slicing expression is described in [ : ] on page 2-70.

When the expression appears on the left-hand side of an assignment, the specified bits in the location
that the port refers to are set to the value of the RHS expression. The RHS value is chopped or zero/sign
extended, if necessary.

When the expression appears on the right-hand side of an assignment, the specified bits in the location
that the port refers to are written to the LHS expression.

Access to non-existing bits

Any access to non-existing bits of e2e ports causes an error, unless the port is of type unbounded
integer. This is the same behavior of the bit slicing operator.

For external ports, it the element type is list of bit or list of byte, then the list is resized by adding enough
zero bits to make the high expression index valid. On all other port types, any access to non-existing bits
causes an error.

Note External ports of type infinite integer are not supported.

For external ports, in all cases, the result of the assignment is passed to the adapter, which may modify
the value according to the actual entity accessed on the simulator side. This modification is adapter
dependent. For Verisity adapters, if the passed value is longer than the value holder on the simulator
side, a warning is issued about the loss of information.

Omitting the high expression index

When the high expression index is not given, if the port is of a bound type (in other words, it is not a port
of type infinite integer or list), then the high expression is taken to be the size of the port expression - 1.
If the port is of unbound type, then

• For e2e ports, the size of the port expression is the size of the last assigned value.
• For external ports, if there was any assignment during the current tick, it determines the size of the
assigned value. Otherwise, the size of the port expression is the size of the value that the port referred
to, as returned by the adapter.

6-44 e Language Reference


e Ports
port$[ : ]

The effect of an assignment

All the assignments in one Specman tick are executed in the end of the tick. Assignments to different
bits are accumulated. If several assignments were done to the same bit, then the last assignment wins.

That means that if a value is assigned to an input port, then any output port that connected to this port
returns this value only on the next tick.

For example:
<'
unit u {
p1 : out simple_port of int is instance;
p2 : in simple_port of int is instance;
keep bind(p1,p2);
//...
rw()@sys.any is {
p1$ = 0xffffffff;
wait[1];
p1$[7:0] = 0;
print p2$ using hex; -- will print 0xffffffff
wait[1];
print p2$ using hex; -- will print 0xffffff00
//...
};
};
'>

In cases where the non_delayed attribute of the port is set to TRUE, then the effect of the assignment is
immediate.

Note The list slicing operator [..] and the list indexing operator [] are not supported for ports in LHS
expressions. In other words, p$[l..h] and p$[i] are not supported on the LHS of an assignment operator.

Example
top.e
<'

unit verifier {
p : inout simple_port of int is instance;
keep bind(p,external);
keep p.hdl_path() == "sig";

clk : in simple_port of bit is instance;


keep bind(clk,external);
keep clk.hdl_path() == "clk";

e Language Reference 6-45


e Ports
port$[ : ]

event clk_rise is rise(clk$)@sim;

run() is also {
start do_the_test();
};

do_the_test()@clk_rise is {
p$ = 0xffffffff;
wait [1];
p.put_mvl_list(32'hxxxxzzzz);
wait [1];
p$[15:12] = 0xa;
p.put_mvl_to_bit_slice(11,8,4'hx);
p$[7:4] = 0xb;
p.put_mvl_to_bit_slice(3,0,4'hx);
check that p.get_mvl_list() == 32'hxxxxzzzz; -- assignments are
-- reflected only in the
-- next tick
wait[1];
force p$ = 0x123;
check that p$ == 0x123; -- value is reflected immediately
wait[1];
p$ = 100; -- is ignored
check that p$ == 0x123;
p.put_mvl_list(32'hzzzzzzzz); -- is ignored
check that p$ == 0x123;
wait[1];
p.force_mvl_to_bit_slice(31,24,8'hzx); -- force the most significant
-- byte
wait[1];
release p;
wait[1];
p$ = 0xabcd;
wait[1];
stop_run();
};
};

extend sys {
v : verifier is instance;
keep v.hdl_path() == "~/top";
};

'>

6-46 e Language Reference


e Ports
force port$

top.v
module top();

reg clk;
reg[31:0] sig;

initial clk <= 0;


always #50 clk <= ~clk;

always @(sig) $display($time, " : sig = %x",sig);

endmodule

See Also
• force port$[ : ] on page 6-50
• put_mvl_to_bit_slice() on page 6-100
• force_mvl_to_bit_slice() on page 6-101

6.6.9 force port$

Purpose
Force a value to a simple port

Category
Action

Syntax
force simple-port-exp$= rhs-exp

Syntax Example
force p1$ = 123;

Parameters

simple-port-exp An expression that returns a simple port instance.

e Language Reference 6-47


e Ports
force port$

rhs-exp An expression of the same type as the port’s type.

Description
Forces a value to the simple port. For both e2e and external ports, updates the value held inside the port.
Until the port is released, any other non-force assignment to the port will be ignored. Any subsequent
force assignment overrides the last one.

In addition, for external ports, the result of the force assignment is passed to the adapter.

Effect of force assignment

Force assignments are not delayed. Any forced value is immediately seen by any port that is bound to
the assigned port.

Example
<'
unit u {
p1 : out simple_port of int is instance;
p2 : in simple_port of int is instance;
keep bind(p1,p2);
//...
rw()@sys.any is {
p1$ = 0xffffffff;
wait[1];
force p1$ = 0xabc;
print p2$ using hex; -- will print 0xabc
//...
};
};
'>

See Also
• port$[ : ] on page 6-43
• put_mvl_to_bit_slice() on page 6-100
• force_mvl_to_bit_slice() on page 6-101

6-48 e Language Reference


e Ports
release port

6.6.10 release port

Purpose
Remove a force action from a port

Category
Action

Syntax
release simple-port-exp

Syntax Example
release p1;

Parameters

simple-port-exp An expression that returns a simple port instance.

Description
Releases a simple port that you previously forced. For e2e ports, the value held in the port is that last
forced value. For external ports, a release request is passed to the adaptor.

See Also
• port$[ : ] on page 6-43
• force port$ on page 6-47
• force port$[ : ] on page 6-50
• put_mvl_to_bit_slice() on page 6-100
• force_mvl_to_bit_slice() on page 6-101

e Language Reference 6-49


e Ports
force port$[ : ]

6.6.11 force port$[ : ]

Purpose
Force a value to a bit or a bit slice of a simple port

Category
Action

Syntax
force simple-port-exp$[[high-exp]:[low-exp][: slice]] = rhs-exp

Syntax Example
force p1$[10:3] = 123;
force p2$[:] = 0x17;

Parameters

simple-port-exp An expression that returns a simple port instance. The


element type has to be scalar, list of bit or list of byte.

high-exp A non-negative numeric expression, greater than or equal


to the low expression. To extract a single bit, use the same
expression for both the high and the low expression.

low-exp A non-negative numeric expression, less than or equal to


the high expression. Default is zero.

slice One of bit, byte, int, or uint. The default is bit.

rhs A numeric expression.

Description
For e2e ports, forcing a slice of a port is the same as forcing the entire port, except that values are
written only to the specified slice. That is, until the next release action, any subsequent non-force
assignment is ignored. Any subsequent force assignment overrides the last one.

For external ports, in addition to the behavior specified for e2e ports, the result of the force assignment
is passed to the adapter.

6-50 e Language Reference


e Ports
method_port$()

Effect of force assignment

Force assignments are not delayed. Any forced value is immediately seen by any port that is bound to
the assigned port.

Example
<'
unit u {
p1 : out simple_port of int is instance;
p2 : in simple_port of int is instance;
keep bind(p1,p2);
//...
rw()@sys.any is {
p1$ = 0xffffffff;
wait[1];
force p1$[7:0] = 0;
print p2$ using hex; -- will print 0xfffff00
//...
};
};
'>

See Also
• port$[ : ] on page 6-43
• put_mvl_to_bit_slice() on page 6-100
• force_mvl_to_bit_slice() on page 6-101

6.6.12 method_port$()

Purpose
Invoke an actual method via an output port

Category
Action or expression

e Language Reference 6-51


e Ports
Port Attributes

Syntax
exp$[(param-list)]

Syntax example:
u = convert_string$("32");

Parameters

exp An expression that returns a output method port instance.

param-list A list of actual parameters. The number and type of the parameters, if
any, must match the method_type.

Description
The $ access operator is used to invoke an actual method via an output port.

Without the $ operation, an expression that returns a method port instance refers to the method port
itself, not to the associated method. An attempt to call the method via the port without the $ operator
causes a syntax error.

See Also
• “Using Method Ports Overview” on page 6-20

6.7 Port Attributes


Ports have attributes that affect their behavior and how they can be used. You assign port attributes using
the attribute() syntax in pre-generation constraints, as follows:

keep [soft] port_instance.attribute() == value;

You can use soft constraints for attributes that you might want to override later.

Most port attributes are ignored unless the port is an external port, but it does no harm to specify
attributes for ports that are not external ports. Attributes intended for external ports may or may not be
supported for a particular simulator. A particular adapter can also define additional port attributes that
are required to enhance access to simulated objects.

This section contains the following:

• “Generic Port Attributes” on page 6-53

6-52 e Language Reference


e Ports
Generic Port Attributes

• “Port Attributes for HDL Simulators” on page 6-56


• “Port Attributes for SystemC Integration” on page 6-58
• bind() on page 6-60
• buffer_size() on page 6-64
• declared_range() on page 6-65
• delayed() on page 6-66
• driver() on page 6-67
• driver_delay() on page 6-68
• driver_initial_value() on page 6-69
• edge() on page 6-70
• hdl_path() on page 6-71
• pack_options() on page 6-73
• pass_by_pointer() on page 6-74
• verilog_drive() on page 6-75
• verilog_drive_hold() on page 6-76
• verilog_forcible() on page 6-76
• verilog_strobe() on page 6-77
• verilog_wire() on page 6-78
• vhdl_delay_mode() on page 6-79
• vhdl_disconnect_value() on page 6-80

6.7.1 Generic Port Attributes


Port attributes that are potentially valid for all simulators are described in Table 6-1. However, a
particular simulator adapter might not implement some of these attributes. If you are using an adapter
that is not provided by Verisity, refer to the documentation for that adapter for the list of supported
attributes.

Note Depending on the simulator adapter you are using, port attributes might cause additional code to
be written to the stubs file. In that case, if you add or change an attribute, you must rewrite the stubs file.

e Language Reference 6-53


e Ports
Generic Port Attributes

Table 6-1 Generic Port Attributes

Attribute Description Applies to

bind() Connects two internal ports or connect a port to an All kinds of internal and
external object external ports

Type: bool

Default: none

See also bind() on page 6-60.

buffer_size() Specifies the maximum number of elements for a Buffer ports


buffer port queue.

Type: uint

Default: none

See also buffer_size() on page 6-64.

declared_range() Specifies the bit width of an external multi-bit External output simple
object. ports that are bound to
some kinds of multi-bit
Type: string objects
Default: none

See also declared_range() on page 6-65.

delayed() Specifies whether propagation of a new port value Internal and external
assignment occurs immediately or is delayed to simple ports
the Specman tick boundary.

Type: bool

Default: TRUE

See also delayed() on page 6-66.

driver() When TRUE, an additional resolved HDL driver External output simple
is created for the corresponding simulator item, ports
and that driver is written to instead of the port.

Type: bool

Default: FALSE

See also driver() on page 6-67.

6-54 e Language Reference


e Ports
Generic Port Attributes

Table 6-1 Generic Port Attributes

Attribute Description Applies to

driver_delay() Specifies the delay time for all assignments from External output simple
Specman to the port. ports

Type: time

Default: 0

See also driver_delay() on page 6-68.

edge() Specifies the edge on which an event is generated. External input event
ports
Type: event_port_edge

Default: change

See also edge() on page 6-70.

hdl_path() Specifies a relative path of the corresponding External ports


simulated item as a string.

Type: string

Default: none

See also hdl_path() on page 6-71.

pack_options() Specifies how the port’s data element is implicitly External simple ports
packed and unpacked. whose data element is a
composite type (lists and
Type: pack_options structs)
Default: global.packing.adapter

See also pack_options() on page 6-73.

pass_by_pointer() When TRUE, composite data (structs or lists) are Internal simple or buffer
transferred by reference. ports whose data element
is a composite type (lists
Type: bool and structs)
Default: FALSE (pass by value)

See also pass_by_pointer() on page 6-74.

e Language Reference 6-55


e Ports
Port Attributes for HDL Simulators

6.7.2 Port Attributes for HDL Simulators


Port attributes that are potentially valid for all HDL simulators are described in Table 6-3. However, a
particular simulator adapter might not implement some of these attributes. If you are using an adapter
that is not provided by Verisity, refer to the documentation for that adapter for the list of supported
attributes.

For Verisity adapters, the port attributes in Table 6-3 enable extended functionality. They cause
additional information to be written into the HDL stubs file to enhance user control over the driving of
HDL signals. For this reason, if you add or change any attribute shown in Table 6-3, you must rewrite the
stubs file.

Some of these attributes are similar to Verilog or VHDL unit members, such as verilog variable or vhdl
driver.

Example
The following verilog variable declaration
verilog variable 'sig[7:0]' using strobe="#1", drive="#5" ;

is equivalent to the following port attributes:


data : inout simple_port of uint(bits: 8) is instance;
keep bind(data, external);
keep data.hdl_path()=="sig";
keep data.declared_range() == "[7:0]";
keep data.verilog_strobe() == "#1";
keep data.verilog_drive() == "#5";

Table 6-2 Port Attributes for Verilog or VHDL Agents

Attribute Description Applies to

driver_initial_value() Applies an initial mvl value to the port. External output


simple ports
Type: list of mvl

Default: {} (empty list)

See also driver_initial_value() on page 6-69.

6-56 e Language Reference


e Ports
Port Attributes for HDL Simulators

Table 6-2 Port Attributes for Verilog or VHDL Agents

Attribute Description Applies to

verilog_drive() Specifies the event on which the data is driven to External output
the Verilog object. simple ports

Type: string

Default: none

See also verilog_drive() on page 6-75.

verilog_drive_hold() Specifies an event after which the port data is set External output
to Z. simple ports

Type: string

Default: none

See also verilog_drive_hold() on page 6-76.

verilog_forcible() Allows forcing of Verilog wires. External output


simple ports
Type: bool

Default: FALSE

See also verilog_forcible() on page 6-76.

verilog_strobe() Specifies the sampling event for the Verilog External input
signal that is bound to the port. simple ports

Type: string

Default: none

See also verilog_strobe() on page 6-77.

verilog_wire() Binds an external out port to a Verilog wire. External output


simple ports
Type: bool

Default: FALSE

See also verilog_wire() on page 6-78.

e Language Reference 6-57


e Ports
Port Attributes for SystemC Integration

Table 6-2 Port Attributes for Verilog or VHDL Agents

Attribute Description Applies to

vhdl_delay_mode() Specifies whether pulses whose period is shorter External output


than the delay are propagated through the driver. simple ports

Type: sn_vhdl_delay_mode

Default: TRANSPORT (all pulses, regardless of


length, are propagated)

See also vhdl_delay_mode() on page 6-79.

vhdl_disconnect_value() Applies an mvl value to the port when you External output
restore Specman after issuing a test command simple ports
but do not restart the simulator.

Type: list of mvl

Default: {} (empty list)

See also vhdl_disconnect_value() on page


6-80.

vhdl_driver() This is an alias for the driver() attribute. External output


simple ports
Type: bool

Default: FALSE

See also driver() on page 6-67.

6.7.3 Port Attributes for SystemC Integration


Port attributes that are used with method ports for SystemC integration are described in Table 6-3

See Also
• Chapter 12 “SystemC Specman Elite Integration” in the Specman Elite Integrator’s Guide
• “e Port Attributes” on page 12-34 in the Specman Elite Integrator’s Guide

6-58 e Language Reference


e Ports
Port Attributes for SystemC Integration

Table 6-3 Port Attributes for SystemC Integration

Attribute Description Applies to

hdl_convertor() Specifies type or size casting operations for External method


method parameters. This attribute is currently ports
used only by Verisity’s SystemC adapters.

Type: string

Default: none

See also“e Port Attributes” on page 12-34 and


“Using the hdl_convertor() Attribute” on page
12-24 in Specman Elite Integrator’s Guide

static_sensitivity() Specifies the global path to a SystemC event that External output
triggers a time-consuming SystemC function. method ports

Type: string

Default: none

See also“e Port Attributes” on page 12-34 and


“Using Static Sensitivity Events” on page 12-30 in
Specman Elite Integrator’s Guide

sync_mode() Specifies the synchronization of a call to input External input


method port from an external agent. This method ports
attribute has three values: sync_call, async_call
and async_tick_call.

Type: sync_mode_t string

Default: sync_call

See also also“e Port Attributes” on page 12-34


and “Synchronization of Input Method Ports with
Specman Tick” on page 12-29 in Specman Elite
Integrator’s Guide

e Language Reference 6-59


e Ports
bind()

6.7.4 bind()

Purpose
Connect two internal ports or connect a port to an external object

Category
Generic port attribute

Syntax
bind(exp1, exp2);

bind(exp1, external);

bind(exp1, empty | undefined);

Syntax Example
buf_in1: in buffer_port of int(bits:16) is instance;
buf_out1: out buffer_port of int(bits:16) is instance;
keep bind(buf_in1, buf_out1); // Valid

Parameters

exp1, exp2 One or more expressions of port type. If two expressions are given and
the port types are compatible, the two port instances are connected.

external Defines a port as connected to a simulated object, such as a Verilog


register, a VHDL signal, or a SystemC object, such as a method.

empty Defines a disconnected port. Runtime accessing of a port with an empty


binding is allowed.

undefined Defines a disconnected port. Runtime accessing of a port with an


undefined binding causes an error

Description
Ports are connected to other e ports or to external simulated objects such as Verilog registers, VHDL
signals, or SystemC methods using a pre-run generation constraint on the bind() attribute. Ports can also
be left explicitly disconnected with empty or undefined.

6-60 e Language Reference


e Ports
bind()

Rules
• All ports must be bound in one of the following ways:
• Bound in pairs, that is, one input or inout port bound to one output or inout port. It is illegal to
bind together two input ports or two output ports.
• Only ports of the same kind may be bound together. A simple port cannot be bound to a buffer
port or to an event port and a buffer port cannot be bound to an event port.
• Bound to an external simulated item.
• Explicitly disconnected (empty or undefined).
• Ports connected in a pair must have exactly the same element type.
Note Dangling ports (ports without bind() attributes) cause an error during elaboration. See
“Checking of Ports” on page 6-61 for more information.

• For simulator adapters provided by Verisity:


• No port may be connected to more than one other port. In other words, you can connect port A
to port B or to port C but not to both.You can explicitly disconnect a port and then over-ride that
disconnect with a binding to an internal or external object. No other multiple bindings are
allowed. In other words, you cannot bind a port to an internal object and also bind it to an external
object. Similarly, you cannot define a port’s binding as both empty and undefined.
• You cannot bind a port to a part select of an external signal. It must be bound to the entire signal.
The declared_range() must also match the actual range of the signal. However, assignments to
a part select of a simple external port are allowed, for example:
outp$[31:16] = data;

• You cannot bind an external port to a Verilog memory or a VHDL multi-dimensional array. Use
the tick access syntax to read and write these objects.
• If you add or change the bind attribute for an external port, you must rewrite the stubs file.

Checking of Ports
Binding and checking of ports takes place automatically at the end of the predefined generate_test() test
method. This process, called elaboration of ports, includes checking for dangling ports and binding
consistency (directions, buffer sizes, and so on).

A port that has no bind() constraint is a dangling port. Since all ports must be bound, a dangling port
causes an elaboration-time error.

e Language Reference 6-61


e Ports
bind()

Disconnected Ports
A port that is bound using the empty or undefined keyword is called a disconnected port.

The empty or undefined keyword can only appear as the second argument of the bind() constraint, in
place of a second port instance name.

The same port cannot be both empty and undefined. Attempting to apply such contradicting constraints
to one port causes an elaboration-time error.

Empty binding allows you to define a port that is connected to nothing. Runtime accessing of an
empty-bound port is allowed. Its effect depends on the operation and type of the port:

• Reading from an empty-bound simple port returns the last written value or the default of the port
element type, if no value has been written so far.
• Writing to an empty-bound out or inout simple port stores the new value internally.
• Reading from an empty-bound buffer port causes the thread to halt.
• Writing to an empty-bound buffer port causes the thread to halt if the buffer is full.
• Waiting for an empty-bound event port causes the thread to halt. If the port direction is inout then
emitting the port resumes the thread.
• An empty-bound event port can be emitted.
A subsequent constraint can be used to overwrite the empty binding constraint.

Like empty binding, undefined binding lets you define a port that is connected to nothing. The
difference is that runtime accessing of a port with an undefined binding causes an error.

A subsequent constraint can be used to overwrite the undefined binding constraint.

Example 1 Valid Binding Examples for Simple Ports and Buffer Ports
buf_in1: in buffer_port of int(bits:16) is instance;
buf_out1: out buffer_port of int(bits:16) is instance;
keep bind(buf_in1, buf_out1); // Valid

buf_in4: in buffer_port of int(bits:16) is instance;


buf_out4: out buffer_port of int(bits:16) is instance;
keep bind(buf_in4, empty);
keep bind(buf_in4, buf_out4); // Valid; buf_in4 will be bound to buf_out4

simple_in1: in simple_port of int(bits:16) is instance;


keep bind(simple_in1, empty);
keep bind(simple_in1, external);
keep simple_in1.hdl_path() == "foo"; // Valid; buf_in5 will be bound to foo

6-62 e Language Reference


e Ports
bind()

Example 2 Valid Binding Example for Method Ports


unit xyz_client {
write: out method_port of write_transaction_method_t is instance;
keep bind(write, external); // external binding
keep write.hdl_path() == "transactor";
keep write.hdl_convertor() == "(transaction: TRCONV)";
mark: out method_port of report_transaction_method_t is instance;
};
extend sys {
client: xyz_client is instance;
keep client.write.hdl_path() == "~/ip";
keep client.agent() == "systemc";
server: xyz_server is instance;
keep bind(client.mark, server.scoreboard); // internal binding
};

Example 3 Invalid Bindings


buf_in2: in buffer_port of int(bits:32) is instance;
buf_out2: out buffer_port of int(bits:16) is instance;
keep bind(buf_in2, buf_out2); // Invalid; different bit size

buf_in3: in buffer_port of packet is instance;


buf_out3: out buffer_port of small packet is instance;
keep bind(buf_in3, buf_out3); // Invalid; different subtypes

simple_in2: in simple_port of int(bits:16) is instance;


simple_out2: out simple_port of int(bits:16) is instance;
keep bind(simple_in2, simple_out2);
keep bind(simple_in2, external); // Invalid; multiple binding

Example 4
The bind() method can also be used in procedural code. It returns TRUE if the port in its argument is
bound as specified. For example:

print bind(p, q);

e Language Reference 6-63


e Ports
buffer_size()

6.7.5 buffer_size()

Purpose
Specify the size of a buffer port queue

Category
Buffer port attribute

Syntax
exp.buffer_size() == num

Syntax Example
keep u.p.buffer_size() == 20;

Parameters

exp An expression of type [in | out] buffer_port of type.

num An integer specifying the maximum number of elements for the queue.

Description
This attribute determines the number of put() actions that can be performed before a get(). A get()
action is required to remove data and make more room in the queue. Specifying a buffer size of 0 means
rendezvous-style synchronization.

No default buffer size is provided. If a buffer size is not specified in a constraint, an error occurs. It is
only necessary to specify a buffer size for one of the two ports in a pair of connected ports. That size
applies to both ports. If the two ports have different buffer sizes specified, then both of them get the
larger of the two sizes.

Example
Like all port attributes, the buffer size can also be used as an expression.
unit consumer {
in_p: in buffer_port of atm_cell is instance;
};

6-64 e Language Reference


e Ports
declared_range()

unit producer {
out_p: out buffer_port of atm_cell is instance;
};

extend sys {
consumer: consumer is instance;
producer: producer is instance;
keep bind(producer.out_p, consumer.in_p);
keep producer.out_p.buffer_size() == 500;

run() is also {
// Print the size of the queue
outf("Size of the queue is set to %u\n",
consumer.in_p.buffer_size());
};
};

See Also
• buffer_port on page 6-32

6.7.6 declared_range()

Purpose
Specify the bit width of a multi-bit external object

Category
External port attribute

Syntax
exp.declared_range() == string

Syntax Example
keep u.p.declared_range() == "[31:0]";

Parameters

exp An expression of a simple port type.

e Language Reference 6-65


e Ports
delayed()

string An expression in the form:


"[msb:lsb]"

Description
This string attribute is meaningful for external simple ports that are bound to multi-bit objects. Because
it is legal to bind a port to an HDL object with a different size, Specman does not extract the range
information from the port declaration. In order to implement access to multi-bit signals correctly in the
stubs file, this attribute is required by Verisity adapters when using the verilog_wire(), verilog_drive(),
verilog_strobe() or driver() attributes.

The interpretation of the string is adapter-specific. For Verisity adapters, the declared range must match
the actual range of the signal; it cannot be a part select.

Example
unit u {
p: simple_port of int is instance;
};
extend sys {
u: u is instance;
keep u.hdl_path() == "top";
keep u.agent() == "Verilog";
keep bind(u.p, external);
keep u.p.hdl_path() == "shr";
keep u.p.verilog_wire() == TRUE;
keep u.p.declared_range() == "[31:0]";
};

6.7.7 delayed()

Purpose
Specify immediate or delayed propagation of new values

Category
Simple port attribute

6-66 e Language Reference


e Ports
driver()

Syntax
exp.delayed() == bool

Syntax Example
keep u.p.delayed() == FALSE;

Parameters

exp An expression of a simple port type.

bool Either TRUE or FALSE. The default is TRUE.

Description
This Boolean attribute specifies whether propagation of a new port value assignment occurs
immediately or is delayed.

When the delayed() attribute is TRUE (the default), propagation of external ports is delayed until the
next Specman tick. Propagation of internal ports is delayed until the next Specman tick at which the
sys.time value changes. This behavior is consistent with the definition of delayed assignments in e and
matches temporal e semantics with regard to the multiple Specman ticks occurring at the same simulator
time.

To make assigned values on ports visible immediately, constrain this attribute to be FALSE, for
example:
keep u.p.delayed() == FALSE;

6.7.8 driver()

Purpose
Create a resolved driver for an external object

Category
External out simple port attribute

Syntax
exp.driver() == bool

e Language Reference 6-67


e Ports
driver_delay()

Syntax Example
keep u.p.driver() == TRUE;

Parameters

exp An expression of a simple port type.

bool Either TRUE or FALSE. The default is FALSE.

Description
This Boolean attribute is meaningful only for external out ports. When this attribute is set to TRUE, an
additional resolved HDL driver is created for the corresponding simulator item, and that driver is written
to instead of the port.

Every port instance associated with the same simulator may create a separate driver, thus allowing HDL
resolution to be applied for multiple Specman resources.

Notes
• For Verisity adapters, if you add or change this attribute, you must rewrite the stubs file.
• Verisity adapters require that you also use declared_range() if the object that is driven is multi-bit.
• Verisity Verilog adapters make use of this attribute only if it is applied to an external signal that can
be driven contiguously and allows multiple drivers, such as Verilog wires (not registers or memories).
• Verisity VHDL adapters make use of this attribute only for MTI ModelSim and only if the VHDL
signals are of a resolved type (not VHDL variables or signals of unresolved type).
• The Verisity OSCI (SystemC) adapter requires this attribute to be specified in order to drive SystemC
ports.

6.7.9 driver_delay()

Purpose
Specify the delay for assignments to a port

Category
External out simple port attribute

6-68 e Language Reference


e Ports
driver_initial_value()

Syntax
exp.driver_delay() == time

Syntax Example
keep u.p.driver_delay() == 2;

Parameters

exp An expression of a simple port type.

time A value of type time (64 bits). The default is 0.

Description
This attribute of type time is meaningful only for external out ports. It specifies the delay time for all
assignments from Specman to the port. This attribute is silently ignored unless the driver() attribute or
the vhdl_driver() attribute is set to TRUE.

Note For Verisity adapters, if you add or change this attribute, you must rewrite the stubs file.

6.7.10 driver_initial_value()

Purpose
Specify an initial value for an HDL object

Category
HDL port attribute

Syntax
exp.driver_initial_value() == mvl-list

Syntax Example
keep u.p.driver_initial_value() == {MVL_X;MVL_X;MVL_1;MVL_1};

e Language Reference 6-69


e Ports
edge()

Parameters

exp An expression that returns a port instance.

mvl-list A lists of mvl values. Possible values are MVL_U,


MVL_X, MVL_0, MVL_1, MVL_Z, MVL_W, MVL_L,
MVL_H, MVL_N. The default is {} (an empty list).

Description
This mvl list type attribute applies an initial mvl value to an external Verilog or VHDL object. This
attribute is silently ignored unless the driver() attribute or the vhdl_driver() attribute is set to TRUE.

When Specman is driving a std_logic signal that is also driven from VHDL, unless an initial value is
specified, the adapter creates a VHDL driver that is initialized by MVL_X.

6.7.11 edge()

Purpose
Specify the edge on which an event is generated

Category
Event port attribute

Syntax
exp.edge() == edge-option

Syntax Example
keep e.edge() == any_change;

Parameters

exp An expression of an event port type.

6-70 e Language Reference


e Ports
hdl_path()

edge-option Possible values are of type event_port_edge:

• change, rise, fall — equivalent to the behavior of @sim temporal


expressions. This means that transitions between x and 0, z and 1
are not detected, x to 1 is considered a rise, z to 0 a fall, and so on.
• any_change — any change within the supported MVL values is
detected, including transitions from x to 0 and 1 to z.
• MVL_0_to_1 — transitions from 0 to 1 only.
• MVL_1_to_0 — transitions from 1 to 0 only.
• MVL_X_to_0 — transitions from X to 0 only.
• MVL_0_to_X — transitions from 0 to X only.
• MVL_Z_to_1 — transitions from Z to 1 only.
• MVL_1_to_Z — transitions from 1 to Z only.

The default is change.

Description
This attribute of type event_port_edge for an external event port specifies the edge on which an event
is generated.

Note Currently all Verisity adapters support edge attribute only for event ports that are bound to a
single-bit DUT signal.

Example
e: in event_port is instance;
keep bind(e,external);
keep e.hdl_path() == "clk";
keep e.edge() == any_change;

6.7.12 hdl_path()

Purpose
Map port instance to an external object

Category
Generic port attribute

e Language Reference 6-71


e Ports
hdl_path()

Syntax
exp.hdl_path() == string

Syntax Example
clk: in event_port is instance;
keep clk.hdl_path() == "clk";

Parameters

exp An expression of a port type.

string The path to the external object, enclosed in double quotes.


The default is an empty string.

Description
To access an external, simulated object, you must provide a path to the object with the hdl_path()
attribute. This path is a concatenation of the partial paths you provide for the port itself and for its
enclosing units. The partial paths can contain any separator that is supported by the adapter for the
simulator you are using.

To allow portability between simulators, you can use e’s canonical path notation. (See the
documentation for the adapter for a description of supported separators.)

Note For Verisity adapters, if you add or change this attribute, you must rewrite the stubs file.

Example
In this example, all ports inherit the Verilog simulator specified as the agent for the encoder instance.
The clk, data_width, data and rq ports access Verilog signals of the same name in the top-level module
“priority_encoder”. The address port accesses a signal with the path
priority_encoder.PRIO.temp_address.
unit encoder {

clk: in event_port is instance;


keep bind(clk, external);
keep clk.hdl_path() == "clk";

data_length: in simple_port of uint is instance;


keep bind(data_length, external);
keep data_length.hdl_path() == "data_width";

data: inout simple_port of list of bit is instance;

6-72 e Language Reference


e Ports
pack_options()

keep bind(data, external);


keep data.hdl_path() == "data";
keep data.verilog_wire() == TRUE; -- simple port attribute
keep data.declared_range() == "[31:0]"; -- simple port attribute

address: in simple_port of uint is instance;


keep bind(address, external);
keep address.hdl_path() == "PRIO/temp_address";

rq: in buffer_port of bool is instance;


keep bind(rq, external);
keep rq.buffer_size() == 8; -- buffer port attribute
keep rq.hdl_path() == "rq";

extend sys {
e: encoder is instance;
keep e.hdl_path() == "~/priority_encoder";
};

See Also
• hdl_path() on page 5-19

6.7.13 pack_options()

Purpose
Specify how an external port’s data element is implicitly packed and unpacked

Category
External simple port attribute

Syntax
exp.pack_options() == pack-option

Syntax Example
keep u.p.pack_options() == packing.low_big_endian;

e Language Reference 6-73


e Ports
pass_by_pointer()

Parameters

exp An expression of a simple or buffer port type.

pack-option A predefined or user-defined pack option. The default is


global.packing.adapter.

Description
This attribute of type pack_options is meaningful only for external ports whose data element is a
composite type (lists and structs). It affects the way a port’s data element is implicitly packed and
unpacked. This attribute exists both for units and ports and may be propagated downwards from an
enclosing unit instance to its ports and other unit instances.

Note None of the existing simulator adapters supports external simple port of structs.

6.7.14 pass_by_pointer()

Purpose
Specify how composite data is transferred by internal ports

Category
Internal port attribute

Syntax
exp.pass_by_pointer() == bool

Syntax Example
keep u.p.pass_by_pointer() == TRUE;

Parameters

exp An expression of a simple or buffer port type.

bool Either TRUE or FALSE. The default is FALSE.

6-74 e Language Reference


e Ports
verilog_drive()

Description
This Boolean attribute specifies how composite data (structs or lists) are transferred by internal simple
ports or buffer ports.

By default, this attribute is FALSE and complex objects are deep-copied upon an internal port access
operation. To pass data by reference and speed up the test, you can set this attribute to TRUE. If you do
so, you must write your code such that it does not result in test correctness violations.

There is also a global config misc option, ports_data_pass_by_pointer. Setting this option influences
all internal ports.

6.7.15 verilog_drive()

Purpose
Specify timing control for data driven to the Verilog object

Category
Verilog port attribute

Syntax
exp.verilog_drive() == timing-control

Syntax Example
keep u.p.verilog_drive() == "@posedge clk2";

Parameters

exp An expression of a simple port type.

timing-control A string specifying any legal Verilog timing control (event


or delay).

Description
This string attribute tells an external output port to drive its data to the Verilog signal when the specified
timing occurs. It can be either a Verilog temporal expression such as “@(posedge top.clk)” or a simple
delay of kind “#1”. This attribute is functionally equivalent to a verilog variable using drive
declaration.

e Language Reference 6-75


e Ports
verilog_drive_hold()

Notes
• For Verisity adapters, if you add or change this attribute, you must rewrite the stubs file.
• Verisity adapters require that you also use declared_range() if the object that is driven is multi-bit.

6.7.16 verilog_drive_hold()

Purpose
Specify when to set the port to Z

Category
Verilog port attribute

Syntax
exp.verilog_drive_hold() == event

Syntax Example
keep u.p.verilog_drive_hold() == "@negedge clk2";

Parameters

exp An expression of a simple port type.

event A string specifying any legal Verilog timing control.

Description
On the first occurrence of the specified event after Specman drive the port data, the value of the
corresponding Verilog signal is set to Z. The event is a string specifying any legal Verilog timing control.
This attribute requires that you also specify the verilog_drive() attribute.

6.7.17 verilog_forcible()

Purpose
Specifies that a Verilog object can be forced

6-76 e Language Reference


e Ports
verilog_strobe()

Category
Verilog port attribute

Syntax
exp.verilog_forcible() == bool

Syntax Example
keep u.p.verilog_forcible() == TRUE;

Parameters

exp An expression of a simple port type.

bool Either TRUE or FALSE. The default is FALSE.

Description
This Boolean attribute allows forcing of Verilog wires. By default Verilog wires are not forcible. This
attribute requires that you also specify the verilog_wire() attribute.

6.7.18 verilog_strobe()

Purpose
Specify the sampling event for a Verilog object

Category
Verilog port attribute

Syntax
exp.verilog_strobe() == event

Syntax Example
keep u.p.verilog_strobe() == "@posedge clk1";

e Language Reference 6-77


e Ports
verilog_wire()

Parameters

exp An expression of a simple port type.

event A string specifying any legal Verilog timing control.

Description
This string attribute specifies the sampling event for the Verilog signal that is bound to an external input
port. This attribute is equivalent to the verilog variable…using strobe declaration.

Notes
• For Verisity adapters, if you add or change this attribute, you must rewrite the stubs file.
• Verisity adapters require that you also use declared_range() if the object that is driven is multi-bit.

6.7.19 verilog_wire()

Purpose
Create a single driver for a port (or multiple ports)

Category
Verilog port attribute

Syntax
exp.verilog_wire() == bool

Syntax Example
keep u.p.verilog_wire() == TRUE;

Parameters

exp An expression of a simple port type.

bool Either TRUE or FALSE. The default is FALSE.

6-78 e Language Reference


e Ports
vhdl_delay_mode()

Description
This Boolean attribute allows an external out port to be bound to a Verilog wire, in a manner similar to a
verilog variable using wire declaration.

The main difference between this attribute and the driver() attribute is that, being backward compatible,
the verilog_wire() attribute merges all of the ports that have this attribute into a single Verilog driver,
while the driver() attribute creates a separate driver for each port.

Notes
• For Verisity adapters, if you add or change this attribute, you must rewrite the stubs file.
• Verisity adapters require that you also use declared_range() if the object that is driven is multi-bit.

6.7.20 vhdl_delay_mode()

Purpose
Specify whether short pulses are propagated through driver

Category
HDL port attribute

Syntax
exp.vhdl_delay_mode() == mode-option

Syntax Example
keep u.p.vhdl_delay_mode() == INERTIAL;

Parameters

exp An expression of a simple port type.

mode-option Either TRANSPORT (the default) or INERTIAL.

e Language Reference 6-79


e Ports
vhdl_disconnect_value()

Description
This sn_vhdl_delay_mode type attribute applies a VHDL delay mode value to an external out port.
This attribute specifies whether pulses whose period is shorter than the delay specified by the
driver_delay() attribute are propagated through the driver. INERTIAL specifies that such pulses are not
propagated. TRANSPORT specifies that all pulses, regardless of length, are propagated.

This attribute also influences what happens if another driver (either VHDL or another unit) schedules a
signal change and before that change occurs, this driver schedules a different change. With INERTIAL,
the first change never occurs.

This attribute is silently ignored unless the driver_delay() attribute is also specified.

6.7.21 vhdl_disconnect_value()

Purpose
Specify value to apply on Specman restore

Category
HDL port attribute

Syntax
exp.vhdl_disconnect_value() == mvl-value-list

Syntax Example
keep u.p.vhdl_disconnect_value() == {MVL_Z};

Parameters

exp An expression that returns a port instance.

mvl-value-list A list of one or more of the following: MVL_U, MVL_X,


MVL_0, MVL_1, MVL_Z, MVL_W, MVL_L, MVL_H,
MVL_N.

6-80 e Language Reference


e Ports
Using Port Values and Attributes in Constraints

Description
This mvl type attribute applies an mvl value to an external output port when you restore Specman after
issuing a test command but do not restart the simulator. This value should be set to a value that does not
affect the overall value of the resolved signal. In Verisity’s ModelSim VHDL adapter the default value
for std_logic signals is MVL_Z.

This attribute is silently ignored unless the driver() attribute or the vhdl_driver() attribute is set to
TRUE.

6.8 Using Port Values and Attributes in Constraints


Like units, port instances can be created only during pre-run generation. They cannot be created with
new, nor generated at runtime. Consequently, a port value cannot be initialized or sampled in pre-run
generation constraints. Port values can be used in on-the-fly generation constraints in accordance with
the basic constraint principles, such as the bidirectional nature of constraints. See “Example 1” on
page 6-81.

Another methodological requirement is that you must explicitly specify attribute values in hard
constraints if the attributes are used anywhere in bidirectional constraints, including implication
constraints. See “Example 2” on page 6-82.

Example 1
This example shows the correct way to initialize an out port.
<'
extend sys {
inport: in simple_port of int is instance;
keep bind(inport, external);
outport: inout simple_port of int is instance;
keep bind(outport, external);
!startval: int;

run() is also {
gen startval;
outport$ = startval; // Use port$ to set a value
};
};
'>

Trying to constrain the generation of startval to equal the value of the out port does not work because
outport$ in this context samples the port value, but does not affect it:
gen startval keeping { outport$ == startval}; // does not work

e Language Reference 6-81


e Ports
Buffer Port Methods

Example 2
This example shows how using port attribute values in bidirectional constraints can have undesired
effects.
<'
extend sys {
pclk: buffer_port of packet is instance;
keep synthesized() == FALSE => pclk.pass_by_pointer() == TRUE;
};
'>

The implication constraint above requires the following constraint to be set in every specific
non-synthesized test, instead of relying on the default value:
extend sys {
keep synthesized() == FALSE;
};

Adding a constraint such as


keep pclk.pass_by_pointer()==FALSE

silently sets synthesized() to TRUE.

6.9 Buffer Port Methods


The methods in this section are used to read from or write to buffer ports and to check whether a buffer
port queue is empty or full. The methods are:

• get() on page 6-82


• put() on page 6-84
• is_empty() on page 6-85
• is_full() on page 6-86

6.9.1 get()

Purpose
Read and remove data from an input buffer port queue

6-82 e Language Reference


e Ports
get()

Category
Predefined TCM for buffer ports

Syntax
in-port-instance-name.get(): port element type

Syntax Example
rec_cell = in_port.get();

Description
Reads a data item from the buffer port queue and removes the item from the queue.

Since buffer ports use a FIFO queue, get() returns the first item that was written to the port.

The thread blocks upon get() when there are no more items in the queue.

If the queue is empty, or if it has a buffer size of 0 and no put() has been done on the port since the last
get(), then the get() is blocked until a put() is done on the port.

The number of consecutive get() actions that is possible is limited to the number of items inserted by
put().

Example
unit consumer {
cell_in: in buffer_port of atm_cell is instance;
current_cell: atm_cell;
update_cell() @clk$ is {
current_cell = cell_in.get();
};
};

See Also
• put() on page 6-84
• is_empty() on page 6-85
• is_full() on page 6-86

e Language Reference 6-83


e Ports
put()

6.9.2 put()

Purpose
Write data to an output buffer port queue

Category
Predefined TCM for buffer ports

Syntax
out-port-instance-name.put(data: port-element-type)

Syntax Example
out_port.put(trans_cell);

Parameters

data A data item of the port element type.

Description
Writes a data item to the output buffer port queue. The sampling event of this TCM is sys.any.

The new data item is placed in a FIFO queue in the output buffer port.

If the queue is full, or if it has a buffer size of 0 and no get() has been done on the port since the last
put(), then the put() is blocked until a get() is done on the port.

The number of consecutive put() actions that is possible is limited to the buffer size.

The thread blocks upon put() when there is no more room in the queue, that is, when the number of
consequent put() operations exceeds the buffer_size() of the port instance.

Example
unit producer {
clk: in event_port is instance;
cell_out: out buffer_port of atm_cell is instance;
write_cell_list(atm_cells: list of atm_cell) @clk$ is {
for each in atm_cells do {
cell_out.put(it);

6-84 e Language Reference


e Ports
is_empty()

};
};
};

See Also
• get() on page 6-82
• is_empty() on page 6-85
• is_full() on page 6-86

6.9.3 is_empty()

Purpose
Check if an input buffer port queue is empty

Category
Pseudo-method for buffer ports

Syntax
in-port-instance-name.is_empty(): bool

Syntax Example
var readable: bool;
readable = not cell_in.is_empty();

Description
Returns TRUE if the input port queue is empty.

Returns FALSE if the input port queue is not empty.

Example
unit consumer {
cell_in: in buffer_port of atm_cell is instance;
clk: in event_port is instance;
check_and_read(atm_cell): atm_cell @clk$ is {
if cell_in.is_empty() {

e Language Reference 6-85


e Ports
is_full()

// No data is available - avoid blocking:


dut_error("No atm cell is available");
}
else {
// Read data from the port:
return cell_in.get();
};
};
};

See Also
• get() on page 6-82
• put() on page 6-84
• is_full() on page 6-86

6.9.4 is_full()

Purpose
Check if an output buffer port queue is full

Category
Pseudo-method for buffer ports

Syntax
out-port-instance-name.is_full(): bool

Syntax Example
var overflow: bool;
overflow = cell_out.is_full();

Description
Returns TRUE if the output port queue is full.

Returns FALSE if the output port queue is not full.

6-86 e Language Reference


e Ports
Multi-Value Logic (MVL) Methods for Simple Ports

Example
unit producer {
cell_out: out buffer_port of atm_cell is instance;
clk: in event_port is instance;
check_and_write(cell: atm_cell)@clk$ is {
if cell_out.is_full() {
// Cannot write to the port without being blocked
dut_error("Overflow in atm cells queue");
}
else {
// Write data to the port
cell_out.put(cell);
};
};
};

See Also
• get() on page 6-82
• put() on page 6-84
• is_empty() on page 6-85

6.10 Multi-Value Logic (MVL) Methods for Simple


Ports
The predefined port methods in this section are for reading and writing MVL data between ports, to
facilitate communication with objects where MVL values occur.

These methods operate on data of type mvl, which is defined as follows:

type mvl: [MVL_U, MVL_X, MVL_0, MVL_1, MVL_Z, MVL_W, MVL_L, MVL_H, MVL_N]

The enumeration literals are the same as those of VHDL, except for MVL_N, which corresponds to the
VHDL ‘-’ (“don’t care”) literal.

Note Mixed access—accessing a port with MVL methods and accessing it through the $ operator—is
allowed.

The MVL methods are applicable in accordance to the port direction. Methods that write a value to a
port are accessible for out and inout simple ports, while methods that read a value from a port are
accessible for in and inout simple ports.

The predefined methods for simple ports are:

e Language Reference 6-87


e Ports
put_mvl()

• put_mvl() on page 6-88


• get_mvl() on page 6-89
• put_mvl_list() on page 6-91
• get_mvl_list() on page 6-92
• put_mvl_string() on page 6-93
• get_mvl_string() on page 6-94
• get_mvl4() on page 6-96
• get_mvl4_list() on page 6-97
• get_mvl4_string() on page 6-98
• put_mvl_to_bit_slice() on page 6-100
• force_mvl_to_bit_slice() on page 6-101

6.10.1 put_mvl()

Purpose
Put an mvl data on a port of a non-mvl type

Category
Predefined method for simple ports

Syntax
exp.put_mvl(value: mvl)

Syntax Example
p.put_mvl(MVL_Z)

Parameters

exp An expression that returns a simple port instance.

value A multi-value logic value.

6-88 e Language Reference


e Ports
get_mvl()

Description
Place an mvl value on an output or inout simple port, to initialize an object to a “disconnected” value,
for example.

Placing an mvl value on a port whose element type is list places the value in the LSB of the list.

Example
unit uo {
pbo: out simple_port of bit is instance;
keep bind(pbo, external);
disconnect_pbo() is {
pbo.put_mvl(MVL_Z);
};
};

See Also
• get_mvl() on page 6-89
• put_mvl_list() on page 6-91
• put_mvl_string() on page 6-93
• string_to_mvl() on page 6-107
• int_to_mvl() on page 6-111
• bits_to_mvl() on page 6-113
• mvl_to_mvl4() on page 6-114

6.10.2 get_mvl()

Purpose
Read mvl data from a port of a non-mvl type

Category
Predefined method for simple ports

e Language Reference 6-89


e Ports
get_mvl()

Syntax
exp.get_mvl(): mvl

Syntax Example
check that pbi.get_mvl() != MVL_X else dut_error("Bad value");

Parameters

exp An expression that returns a simple port instance.

Description
Reads an mvl value from an input or inout simple port, to check that there are no undefined “x” bits, for
example.

Getting an mvl value from a port whose element type is list reads the LSB of the list.

Example
unit ui {
pbi: in simple_port of bit is instance;
keep bind(pbi, external);
chk_pbi() is {
check that pbi.get_mvl() != MVL_X else
dut_error("Bad value");
};
};

See Also
• put_mvl() on page 6-88
• get_mvl_list() on page 6-92
• get_mvl_string() on page 6-94
• get_mvl4() on page 6-96
• mvl_to_string() on page 6-108
• mvl_to_int() on page 6-109
• mvl_to_bits() on page 6-112
• mvl_to_mvl4() on page 6-114

6-90 e Language Reference


e Ports
put_mvl_list()

6.10.3 put_mvl_list()

Purpose
Put a list of mvl values on a port of a non-mvl type

Category
Predefined method for simple ports

Syntax
exp.put_mvl_list(values: list of mvl)

Syntax Example
pbo.put_mvl_list({MVL_H; MVL_0; MVL_L; MVL_0});

Parameters

exp An expression that returns a simple port instance.

values A list of mvl values

Description
Writes a list of mvl values to an output or inout simple port.

Putting a list of mvl values on a port whose element type is a single bit writes only the LSB of the list.

Example
unit ui {
pbi: in simple_port of uint(bits:4) is instance;
};

unit uo {
uin: ui is instance;
pbo: out simple_port of uint(bits:4) is instance;
keep bind(pbo, uin.pbi);
wr_pbo() is {
pbo.put_mvl_list({MVL_H; MVL_0; MVL_L; MVL_0});
};

e Language Reference 6-91


e Ports
get_mvl_list()

};

See Also
• put_mvl() on page 6-88
• get_mvl() on page 6-89
• get_mvl_list() on page 6-92

6.10.4 get_mvl_list()

Purpose
Get a list of mvl values from a port of a non-mvl type

Category
Predefined method for simple ports

Syntax
exp.get_mvl_list(): list of mvl

Syntax Example
check that pbil.get_mvl_list().has(it == MVL_U) == FALSE else
dut_error("Bad list");

Parameters

exp An expression that returns a simple port instance.

Description
Reads a list of mvl values from an input or inout simple port.

Example
unit uo {
pbol: out simple_port of list of bit is instance;
};

6-92 e Language Reference


e Ports
put_mvl_string()

unit ui {
uout: uo is instance;
pbil: in simple_port of list of bit is instance;
keep bind(uout.pbol, pbil);
chk_pbil() is {
check that pbil.get_mvl_list().has(it == MVL_U) == FALSE else
dut_error("Bad list");
};
};

See Also
• put_mvl() on page 6-88
• get_mvl() on page 6-89
• put_mvl_list() on page 6-91
• get_mvl4_list() on page 6-97

6.10.5 put_mvl_string()

Purpose
Put an mvl value on a port of a non-mvl type when a value is represented as a string

Category
Predefined method for simple ports

Syntax
exp.put_mvl_string(value: string)

Syntax Example
pbol.put_mvl_string("32'hxxxxllll");

Parameters

exp An expression that returns a simple port instance.

e Language Reference 6-93


e Ports
get_mvl_string()

value An mvl value in the form of a base and one or more characters,
entered as a string. The mvl values in the string must be lowercase.
Use 1 for MVL_1, 0 for MVL_0, z for MVL_Z, and so on.

Description
Writes a string representing a list of mvl values to a simple output or inout port. The mvl value consists
of any legal Specman base, for example, 32'b, followed by one or more characters, for example
xxxxzzzz. The string representation follows the same rules as Verilog literals. The difference is that
Verilog literals support only 4-value logic digits (1,0,x and z) while Specman allows also the characters
u, l, h, w and n.

Example
unit uo {
pbol: out simple_port of uint(bits:4) is instance;
keep bind(pbol, external);
wr_pbol() is {
pbol.put_mvl_string("32'hxxxxllll");
};
};

See Also
• put_mvl() on page 6-88
• get_mvl() on page 6-89
• get_mvl_string() on page 6-94

6.10.6 get_mvl_string()

Purpose
Get a value in form of a string from a port of a non-mvl type

Category
Predefined method for simple ports

6-94 e Language Reference


e Ports
get_mvl_string()

Syntax
exp.get_mvl_string(radix: radix): string

Syntax Example
print pbis.get_mvl_string(BIN);

Parameters

exp An expression that returns a simple port instance.

radix One of BIN, OCT, or HEX.

Description
Returns a string in which each character represents an mvl value. The characters are lowercase. HDL
value ‘1’ is represented by the character 1, ‘Z’ by z, ‘-’ by character n. The returned string always
includes all the bits, with no implicit extensions. For example, a port of type uint returns a string of 32
characters, since an int is a 32-bit data type.

Example
unit ui {
pbis: in simple_port of uint(bits:4) is instance;
keep bind(pbis,external);
chk_pbis() is {
print pbis.get_mvl_string(BIN);
};
};

See Also
• put_mvl() on page 6-88
• get_mvl() on page 6-89
• put_mvl_string() on page 6-93
• get_mvl4_string() on page 6-98

e Language Reference 6-95


e Ports
get_mvl4()

6.10.7 get_mvl4()

Purpose
Get an mvl value from a port, converting 9-value logic to 4-value logic

Category
Predefined method for simple ports

Syntax
exp.get_mvl4(): mvl

Syntax Example
check that pbi.get_mvl4() != MVL_Z else dut_error("Bad value");

Parameters

exp An expression that returns a simple port instance.

Description
Reads a 9-value mvl value from an input simple port and converts it to 4-value subset mvl.

The predefined mapping from 9-value logic to 4-value logic is:


MVL_U, MVL_W, MVL_X, MVL_N -> MVL_X
MVL_L, MVL_0 -> 0
MVL_H, MVL_1 -> 1
MVL_Z -> MVL_Z

Example
unit ui {
pbi: in simple_port of bit is instance;
keep bind(pbi, external);
chk_pbi() is {
check that pbi.get_mvl4() != MVL_X else
dut_error("Bad value");
};
};

6-96 e Language Reference


e Ports
get_mvl4_list()

See Also
• put_mvl() on page 6-88
• get_mvl() on page 6-89
• get_mvl4_list() on page 6-97
• get_mvl4_string() on page 6-98
• mvl_to_mvl4() on page 6-114

6.10.8 get_mvl4_list()

Purpose
Get a list of mvl values from a port, converting from 9-value logic to 4-value logic

Category
Predefined method for simple ports

Syntax
exp.get_mvl4_list(): list of mvl

Syntax Example
check that pbi4l.get_mvl4_list().has(it == MVL_X) == FALSE else
dut_error("Bad list");

Parameters

exp An expression that returns a simple port instance.

Description
Reads a list of 9-value mvl values from an input simple port and converts them to 4-value MVL.

The predefined mapping from 9-value logic to 4-value logic is:


MVL_U, MVL_W, MVL_X, MVL_N -> MVL_X
MVL_L, MVL_0 -> 0
MVL_H, MVL_1 -> 1

e Language Reference 6-97


e Ports
get_mvl4_string()

MVL_Z -> MVL_Z

Example
unit ui {
pbi4l: in simple_port of list of bit is instance;
keep bind(pbi4l, external);
chk_pbi4l() is {
check that pbi4l.get_mvl4_list().has(it == MVL_X) == FALSE else
dut_error("Bad list");
};
};

See Also
• put_mvl() on page 6-88
• get_mvl() on page 6-89
• get_mvl4() on page 6-96
• mvl_list_to_mvl4_list() on page 6-115

6.10.9 get_mvl4_string()

Purpose
Get a 4-state value in form of a string from a port of a non-mvl type

Category
Predefined method for simple ports

Syntax
exp.get_mvl4_string(radix): string

Syntax Example
print pbi4s.get_mvl4_string(BIN);

6-98 e Language Reference


e Ports
get_mvl4_string()

Parameters

exp An expression that returns a simple port instance.

radix One of BIN, OCT, or HEX.

Description
Reads a string in which each character represents a 4-value logic digit from a subset of mvl, converted
from 9-value logic. The characters are lowercase.

The predefined mapping from 9-value logic to 4-value logic is the same as it is commonly used when
converting from VHDL std_logic to Verilog:
U, W, X, N -> x
L, 0 -> 0
H, 1 -> 1
Z -> z

The returned string always includes all the bits, with no implicit extensions. For example, a port of type
int returns a string of 32 characters, since an int is a 32-bit data type.

Example
unit ui {
pbi4s: in simple_port of list of int(bits:4) is instance;
keep bind(pbi4s,external);
chk_pbi4s() is {
print pbi4s.get_mvl4_string(HEX);
};
};

See Also
• put_mvl() on page 6-88
• get_mvl() on page 6-89
• get_mvl4() on page 6-96
• string_to_mvl4() on page 6-116

e Language Reference 6-99


e Ports
put_mvl_to_bit_slice()

6.10.10 put_mvl_to_bit_slice()

Purpose
Write mvl data to a bit slice of a port

Category
Predefined method for simple out and inout ports

Syntax
exp.put_mvl_to_bit_slice(high: int, low: int, value: list of mvl)

Syntax Example
p1.put_mvl_to_bit_slice(7, 4, 4'hx);
p2.put_mvl_to_bit_slice(12, 7, {MVL_X;MVL_X;MVL_H;MVL_H;MVL_U});

Parameters

exp An expression that returns a simple out or inout port instance. The
supported element types are scalar, list of bit or list of byte.

high An integer that specifies the high index of the bit slice.

low An integer that specifies the low index of the bit slice.

value A list of mvl.

Description
Writes an mvl list to a specified slice of bit. Like the LHS bit slice operator, you can call this method port
of type scalar, list of bit or list of byte.

If the size of the value is smaller than the slice size (1 + high - low), the value is padded with MVL_Us.
If the size of the value is larger than the slice size, then the MSBs of value are truncated.

Access to non-existing bits

For e2e ports, any access to non-existing bits causes an error, unless the port is of type unbounded
integer.

6-100 e Language Reference


e Ports
force_mvl_to_bit_slice()

For external ports, if the port type is list of bit or list of byte, then the port's mvl list is resized by adding
enough MVL_U-s, to make the high index valid. On all other port types, the behavior is as on e2e ports.

Note External ports of type infinite integer are not supported.

In all cases, the result of the assignment is passed to the adapter, which may modify it according to the
entity on the simulator side. This modification is adapter dependent. For Verisity adapters, if the passed
value is longer than the value holder on the simulator side, a warning is issued regarding the loss of
information.

Effect of the function call

Like the bit slice operator, the effect of the assignment is delayed to the next tick. Thus, if the function
put_mvl_to_bit_slice() is called for a port, the consequence of this call is not seen until the next tick by
any other port that is bound to it.

For example:
unit u{
p1: out simple_port of int is instance;
p2: in simple_port of int is instance;
keep bind(p1,p2);
rw() @sys.any is {
p1.put_mvl_list(32'hzzzzzzzz);
wait[1];
p1.put_mvl_to_bit_slice(7,0,8'hxx);
print p2.get_mvl_string(HEX); --will print "32'hzzzzzzzz"
wait[1];
print p2.get_mvl_string(HEX); --will print "32'hzzzzzzxx"
};
};

See Also
• port$[ : ] on page 6-43
• force port$[ : ] on page 6-50
• force_mvl_to_bit_slice() on page 6-101

6.10.11 force_mvl_to_bit_slice()

Purpose
Force mvl data to a bit slice of a port

e Language Reference 6-101


e Ports
force_mvl_to_bit_slice()

Category
Predefined method for simple out and inout ports

Syntax
exp.force_mvl_to_bit_slice(high: int, low: int, value: list of mvl,)

Syntax Example
p1.force_mvl_to_bit_slice(7, 4, 4'hx);
p2.force_mvl_to_bit_slice(12, 7, {MVL_X;MVL_X;MVL_H;MVL_H;MVL_U});

Parameters

exp An expression that returns a simple out or inout port instance. The
supported element types are scalar, list of bit or list of byte.

high An integer that specifies the high index of the bit slice.

low An integer that specifies the low index of the bit slice.

value A list of mvl.

Description
For e2e ports, forcing a slice of a port is the same as forcing the entire port, except that values are
written only to the specified slice. That is, until the next release action, any subsequent non-force
assignment is ignored. Any subsequent force assignment overrides the last one.

For external ports, in addition to the behavior specified for e2e ports, the result of the force assignment
is passed to the adapter.

Effect of the function call

Force assignments are not delayed. The effect of the function call is immediately seen by any port that is
bound to the assigned port.

Example
<'
unit u {
p1 : out simple_port of int is instance;
p2 : in simple_port of int is instance;
keep bind(p1,p2);
//...

6-102 e Language Reference


e Ports
Methods for Simple Ports

rw()@sys.any is {
p1.put_mvl_list(32'hzzzzzzzz);
wait[1];
p1.force_mvl_to_bit_slice(7,0,8'xx);
print p2.get_mvl_string(HEX); --will print "32'hzzzzzzxx"
};
};
'>
};

See Also
• port$[ : ] on page 6-43
• force port$[ : ] on page 6-50
• put_mvl_to_bit_slice() on page 6-100

6.11 Methods for Simple Ports


These methods are defined for all simple ports, regardless of the type of data element:

• has_x() on page 6-103


• has_z() on page 6-104
• has_unknown() on page 6-105

6.11.1 has_x()

Purpose
Determine if port has X

Category
Predefined method for simple ports

Syntax
exp.has_x(): bool

e Language Reference 6-103


e Ports
has_z()

Syntax Example
print pbi4s.has_x();

Parameters

exp An expression of a simple port type.

Description
Returns TRUE if at least one bit of the port is MVL_X.

Example
unit ui {
pbi4s: in simple_port of uint(bits:4) is instance;
keep bind(pbi4s,external);
chk_pbi4s() is {
print pbi4s.has_x();
};
};

See Also
• has_z() on page 6-104
• has_unknown() on page 6-105

6.11.2 has_z()

Purpose
Determine if port has Z

Category
Predefined method for simple ports

Syntax
exp.has_z(): bool

6-104 e Language Reference


e Ports
has_unknown()

Syntax Example
print pbi4s.has_z();

Parameters

exp An expression of a simple port type.

Description
Returns TRUE if at least one bit of the port is MVL_Z.

Example
unit ui {
pbi4s: in simple_port of uint(bits:4) is instance;
keep bind(pbi4s,external);
chk_pbi4s() is {
print pbi4s.has_z();
};
};

See Also
• has_x() on page 6-103
• has_unknown() on page 6-105

6.11.3 has_unknown()

Purpose
Determine if port has U

Category
Predefined method for simple ports

Syntax
exp.has_unknown(): bool

e Language Reference 6-105


e Ports
Global MVL Routines

Syntax Example
print pbi4s.has_unknown();

Parameters

exp An expression of a simple port type.

Description
Returns TRUE if at least one bit of the port is one of the following:

• MVL_U
• MVL_X
• MVL_Z
• MVL_W
• MVL_N

Example
unit ui {
pbi4s: in simple_port of uint(bits:4) is instance;
keep bind(pbi4s,external);
chk_pbi4s() is {
print pbi4s.has_unknown();
};
};

See Also
• has_x() on page 6-103
• has_z() on page 6-104

6.12 Global MVL Routines


The global routines for manipulating MVL values are:

• string_to_mvl() on page 6-107


• mvl_to_string() on page 6-108
• mvl_to_int() on page 6-109
• int_to_mvl() on page 6-111

6-106 e Language Reference


e Ports
string_to_mvl()

• mvl_to_bits() on page 6-112


• bits_to_mvl() on page 6-113
• mvl_to_mvl4() on page 6-114
• mvl_list_to_mvl4_list() on page 6-115
• string_to_mvl4() on page 6-116

6.12.1 string_to_mvl()

Purpose
Convert a string to a list of mvl values

Category
Predefined routine

Syntax
string_to_mvl(value-string: string): list of mvl

Syntax Example
mlist = string_to_mvl("8'bxz1");

Parameters

value-string A string representing mvl values, consisting of a width and base


followed by a series of characters corresponding to mvl values.
Format of the input string is the same as in Verilog literals, except
there are additional 9-value logic digits: u, l, h, w and n.

Description
Converts each character in the input string to an mvl value.

Example
var mlist: list of mvl;
mlist = string_to_mvl("8'bz");

e Language Reference 6-107


e Ports
mvl_to_string()

// returns {MVL_Z; MVL_Z; MVL_Z; MVL_Z; MVL_Z; MVL_Z; MVL_Z; MVL_Z};


mlist = string_to_mvl("8'bxz1");
// returns {MVL_1; MVL_Z; MVL_X; MVL_X; MVL_X; MVL_X; MVL_X; MVL_X};

See Also
• mvl_to_string() on page 6-108

6.12.2 mvl_to_string()

Purpose
Convert a list of mvl values to a string

Category
Predefined routine

Syntax
mvl_to_string(mvl-list: list of mvl, radix: radix): string

Syntax Example
mstring = mvl_to_string({MVL_Z; MVL_Z; MVL_Z; MVL_Z; MVL_X; MVL_X; MVL_X;
MVL_X}, BIN);

Parameters

mvl-list A list of mvl values.

radix One of BIN, OCT, or HEX.

Description
Converts a list of mvl values to a string. The mapping is done in the following way:
MVL_U is converted to character "u" (lowercase)
MVL_X - "x"
MVL_0 - "0"
MVL_1 - "1"
MVL_Z - "z"
MVL_W - "w";

6-108 e Language Reference


e Ports
mvl_to_int()

MVL_L - "l"
MVL_H - "h"
MVL_N - "n"
Note This routine always returns a sized number as a string.

Example 1
var mstring: string;
mstring = mvl_to_string({MVL_Z; MVL_Z; MVL_Z; MVL_Z; MVL_X; MVL_X; MVL_X;
MVL_X}, BIN);
// returns "8b'zzzzxxxx"

Example 2
var l: list of mvl = {MVL_1;MVL_0};
print mvl_to_string(l, BIN); --prints 2'b10
print mvl_to_string(l, HEX); --prints 2'h2

See Also
• string_to_mvl() on page 6-107
• mvl_to_int() on page 6-109
• mvl_to_bits() on page 6-112
• mvl_to_mvl4() on page 6-114
• mvl_list_to_mvl4_list() on page 6-115

6.12.3 mvl_to_int()

Purpose
Convert an mvl value to an integer

Category
Predefined routine

e Language Reference 6-109


e Ports
mvl_to_int()

Syntax
mvl_to_int(mvl-list: list of mvl, mask: list of mvl): uint

Syntax Example
var ma: uint = mvl_to_int(l, {MVL_X});

Parameters

mvl-list A list of mvl values to convert to an integer value.

mask A list of mvl values that are to be converted to 1.

Description
Converts each value in a list of mvl values into a binary integer (1 or 0), using a list of mvl mask values
to determine which mvl values are converted to 1.

When the list is less than 32 bits, it is padded with 0. When it is greater than 32 bits, it is truncated,
leaving the 32 least significant bits.

Example
var l: list of mvl = {MVL_X; MVL_X; MVL_0; MVL_1};
var ma: uint = mvl_to_int(l,{MVL_X});
// returns 12 (0b1100)
var mb: uint = mvl_to_int(l, {MVL_Z})
// returns 0

See Also
• int_to_mvl() on page 6-111
• mvl_to_bits() on page 6-112
• mvl_to_mvl4() on page 6-114
• mvl_list_to_mvl4_list() on page 6-115

6-110 e Language Reference


e Ports
int_to_mvl()

6.12.4 int_to_mvl()

Purpose
Convert an integer value to a list of mvl values

Category
Predefined routine

Syntax
int_to_mvl(value: uint, mask: mvl): list of mvl

Syntax Example
var mlist: list of mvl = int_to_mvl(12, MVL_X)

Parameters

value An integer value to convert to a list of mvl values.

mask An mvl value that replaces each bit in the integer that has the value 1.

Description
Maps each bit that has the value 1 to the mask mvl value, retains the 0 bits as MVL_0, and returns a list
of 32 mvl values. The returned list always has a size of 32.

Example
var mlist: list of mvl = int_to_mvl(12, MVL_X)
// returns MVL_0;..........MVL_X;MVL_X;MVL_0;MVL_0

See Also
• mvl_to_int() on page 6-109

e Language Reference 6-111


e Ports
mvl_to_bits()

6.12.5 mvl_to_bits()

Purpose
Convert a list of mvl values to a list of bits

Category
Predefined routine

Syntax
mvl_to_bits(mvl-list: list of mvl, mask: list of mvl): list of bit

Syntax Example
var bl: list of bit = mvl_to_bits({MVL_Z; MVL_Z; MVL_X; MVL_L}, {MVL_Z;
MVL_X})

Parameters

mvl-list A list of mvl values to convert to bits.

mask A list of mvl values that specifies which mvl values are to be
converted to 1.

Description
Converts a list of mvl values to a list of bits, using a mask of mvl values to indicate which mvl values
are converted to 1 in the list of bits.

Example
var bl: list of bit = mvl_to_bits({MVL_Z; MVL_Z; MVL_X; MVL_L}, {MVL_Z;
MVL_X})
// returns {1; 1; 1; 0}

See Also
• mvl_to_string() on page 6-108
• mvl_to_int() on page 6-109

6-112 e Language Reference


e Ports
bits_to_mvl()

• mvl_to_mvl4() on page 6-114

6.12.6 bits_to_mvl()

Purpose
Convert a list of bits to a list of mvl values

Category
Predefined routine

Syntax
bits_to_mvl(bit-list: list of bit, mask: mvl): list of mvl

Syntax Example
var ml: list of mvl = bits_to_mvl({1; 0; 1; 0}, MVL_Z)

Parameters

bit-list A list of bits to convert to mvl values.

mask An mvl value that replaces each bit in the list that has the value 1.

Description
Maps each bit with the value 1 to the mask mvl value, retains the 0 bits as MVL_0, and returns an mvl
list that is bit-list size.

Example
var ml: list of mvl = bits_to_mvl({1; 0; 1; 0}, MVL_Z)
// returns {MVL_Z;MVL_0;MVL_Z;MVL_0}

See Also
• mvl_to_bits() on page 6-112

e Language Reference 6-113


e Ports
mvl_to_mvl4()

6.12.7 mvl_to_mvl4()

Purpose
Convert an mvl value to a 4-value logic value

Category
Predefined routine

Syntax
mvl_to_mvl4(value: mvl): mvl

Syntax Example
var m4: mvl = mvl_to_mvl4(MVL_U)

Parameters

value An mvl value to convert to a 4-value logic value

Description
Converts an mvl value to the appropriate 4-value logic subset value.

The predefined mapping from 9-value logic to 4-value logic is:


MVL_U, MVL_W, MVL_X, MVL_N -> MVL_X
MVL_L ,MVL_0 -> 0
MVL_H, MVL_1 -> 1
MVL_Z -> MVL_Z

Example
var m4: mvl = mvl_to_mvl4(MVL_U)
// returns MVL_X

See Also
• mvl_to_string() on page 6-108
• mvl_to_int() on page 6-109

6-114 e Language Reference


e Ports
mvl_list_to_mvl4_list()

• mvl_to_bits() on page 6-112


• mvl_list_to_mvl4_list() on page 6-115

6.12.8 mvl_list_to_mvl4_list()

Purpose
Convert a list of mvl values to a list of 4-value logic subset values

Category
Predefined routine

Syntax
mvl_list_to_mvl4_list(mvl-list: list of mvl): list of mvl

Syntax Example
var m4l: list of mvl = mvl_list_to_mvl4_list({MVL_N; MVL_L; MVL_H; MVL_1})

Parameters

mvl-list A list of mvl values to convert to a list of 4-value logic subset values

Description
Converts each value in a list of mvl values to the corresponding 4-value logic value.

The predefined mapping from 9-value logic to 4-value logic is:


MVL_U, MVL_W, MVL_X, MVL_N -> MVL_X
MVL_L, MVL_0 -> MVL_0
MVL_H, MVL_1 -> MVL_1
MVL_Z -> MVL_Z

Example
var m4l: list of mvl = mvl_list_to_mvl4_list({MVL_N; MVL_L; MVL_H; MVL_1})
// returns {MVL_X; MVL_0; MVL_1; MVL_1;}

e Language Reference 6-115


e Ports
string_to_mvl4()

See Also
• mvl_to_string() on page 6-108
• mvl_to_int() on page 6-109
• mvl_to_bits() on page 6-112
• mvl_to_mvl4() on page 6-114

6.12.9 string_to_mvl4()

Purpose
Convert a string to a list of 4-value logic mvl subset values

Category
Predefined routine

Syntax
string_to_mvl4(value-string: string): list of mvl

Syntax Example
mlist = string_to_mvl("8'bxz");

Parameters

value-string A string representing MVL values, consisting of a width and base


followed by a series of characters corresponding to 9-value logic
values.

Description
Converts each character in the string to the corresponding 4-value logic value. If the string contains
characters other than ‘0’, ‘1’, ‘x’, ‘z’, ‘h’, ‘l’, ‘u’, ‘w’ or ‘n’ a runtime error is issued.

Example
var mlist: list of mvl;
mlist = string_to_mvl4("8'bz");

6-116 e Language Reference


e Ports
Port-Related Commands

// returns {MVL_Z; MVL_Z; MVL_Z; MVL_Z; MVL_Z; MVL_Z; MVL_Z; MVL_Z};


mlist = string_to_mvl("8'bxz");
// returns {MVL_Z; MVL_X; MVL_X; MVL_X; MVL_X; MVL_X; MVL_X; MVL_X};

See Also
• string_to_mvl() on page 6-107
• mvl_to_string() on page 6-108
• mvl_to_mvl4() on page 6-114
• mvl_list_to_mvl4_list() on page 6-115

6.13 Port-Related Commands


Specman commands related to ports are described in this section. The commands are:

• show ports on page 6-117


• trace ports on page 6-119

6.13.1 show ports

Purpose
Lists ports with basic information

Category
Command

Syntax
show ports [-full] [exp]

Syntax Example
show ports -full rx.trans;

e Language Reference 6-117


e Ports
show ports

Parameters

full Show additional information about the listed ports, such as


connectivity and agent.

exp A port, unit, list of ports or list of units expression. A unit or a list of
units expression lists all the ports of the unit(s).
The default is all ports.

Description
Unless a specific expression is given, this command lists all ports.

Without the -full option, only the e path and the port declaration are displayed.With the -full option, the
following information is also displayed:

• The agent attached to the port


• The hdl_path() attribute of the port (if set)
• The ports bound to that port (if any)

Example 1
show ports

Results
Ports =
0. sys.ver.dut_inp - OSCI out simple_port of int (bits: 2)
1. sys.ver.dut_out - OSCI in simple_port of uint

Example 2
show ports -full

Results
Ports =
0. sys.ver.dut_inp - out simple_port of int (bits: 2)
e_path: sys.ver.dut_inp
agent: osci
hdl_path: sn_xor->/inp
1. sys.ver.dut_out - in simple_port of uint
e_path: sys.ver.dut_out
agent: osci

6-118 e Language Reference


e Ports
trace ports

hdl_path: sn_xor->/out
2. sys.ver.clk - in event_port
e_path: sys.ver.clk
agent: osci
hdl_path: sn_xor->/clk

See Also
• trace ports on page 6-119

6.13.2 trace ports

Purpose
Trace activity on ports

Category
Command

Syntax
tra[ce] port-activity [[unit-wildcard.]port-wildcard][off]

Parameters

port-activity The type of activity to be traced. This may be one of the following:

ports Trace all ports and all activities

simple_ports Trace all activities of simple ports

event_ports Trace all activities of event ports

buffer_ports Trace all activities of buffer ports

write_simple_port, Trace write or read activities of simple ports


read_simple_port

emit_event_port, Trace event emitting and event occurrence of an event port


occur_event_port

e Language Reference 6-119


e Ports
trace ports

write_buffer_port, Trace write or read activities of buffer ports


read_buffer_port

external port-kind Trace only the external activities of the specified port kind.

unit-wildcard The name of the unit type in which the port is defined. Wildcards are allowed.

port-wildcard The name of a field of type port. Wild cards are allowed.

off If the field is a port reference, then Specman traces the port instance referred to by
the reference field. If the reference is changed later, it does not influence which port
is traced.
If port tracing has previously turned on, then turn it off.

Description
This command enables tracing of activity on a port or all ports that match the specified expression.

Example 1
The following example turns on tracing of all port activities for all u1 ports, where u1 is the unit type
name.
vrst-tool> trace ports u1.*

Example 2
The following example turns on tracing of all external simple port activities for all existing ports
vrst-tool> trace external simple_ports

See Also
• show ports on page 6-117

6-120 e Language Reference


7 Methods
e methods are similar to C functions, Verilog tasks, and VHDL processes. An e method is an operational
procedure containing actions that define its behavior. A method can have parameters, local variables,
and a return value. You can define a method only within a struct and you must create an instance of the
struct before you can execute the method. When a method is executed, it can manipulate the fields of that
struct instance.

You can define methods that execute within a single point of simulation time (within zero time) or
methods that execute over multiple cycles. The first type of method is referred to as a regular method.
The second type is called a time consuming method or TCM. TCMs are used to synchronize processes
in an e program with processes or events in the DUT. Within a single e program, multiple TCMs can
execute either in sequence or concurrently, along parallel but separate threads. A TCM can also have
internal branches, which are multiple action blocks executing concurrently.

Methods defined in one module can later be overwritten, modified or enhanced in subsequent modules
using the extend mechanism. See “Rules for Defining and Extending Methods” on page 7-2 for
information on how to define and extend methods.

Implementing an e method is usually done in e. However, you might want to write a C routine and
convert it into an e method. You can do this by declaring an e method that is implemented in C.

See Also
• “Rules for Defining and Extending Methods” on page 7-2
• “Invoking Methods” on page 7-22
• “Parameter Passing” on page 7-34
• “Calling e Methods from C” on page 11-44 in the Usage and Concepts Guide for e Testbenches

e Language Reference 7-1


Methods
Rules for Defining and Extending Methods

7.1 Rules for Defining and Extending Methods


There are two phases in the declaration of regular methods and time-consuming methods (TCMs):

• Introduction
• Extension
You must introduce a method before you extend it. The introduction can be in the same struct as the
extension or in any struct that this struct inherits from, but it must precede the extension during file
loading.

To introduce a method, you can use:

• is [ C routine ]
• is undefined | empty
To extend a method, you can use:

• is also | first | only


• is only C routine
You can also use is to extend a method in the following cases:

• The method was previously introduced with is undefined or is empty and has not been previously
extended in this struct or in any struct that inherits from this struct.
• The method was previously introduced (and perhaps extended) in a struct that this struct inherits
from, as long as the method has not already been extended in this struct or in any struct that inherits
from this struct using like.

In these cases, using is after is or after is also | first | only in a when or like child is similar to using is
only in this context except that an error message is generated if child is extended more than once or if a
child is extended after any of its like grandchild are extended. The advantage of using is instead of is
only is that you will see an error if the method extensions do not occur in the order you expect.

Note As you might expect, if you use is after is or after is also | first | only in a when or like child or
in one of their descendents, you cannot subsequently use is to redefine the method in the parent.

Table 7-1 summarizes the rules for introducing and extending methods. Please keep in mind the
following:

• The “none” heading in the table indicates that the method has not been introduced yet.
• The only heading represents is also, is first, and is only.
• The “+” character indicates “is allowed”.

7-2 e Language Reference


Methods
Rules for Defining and Extending Methods

• The “-” character indicates “is not allowed”.


• The “C” character indicates “is allowed” only in a like child, a when child, or one of its descendents.

Table 7-1 Rules for Method Extension

Previous Declaration

none undefined empty is only

Extending by

undefined + - - - -

empty + - - - -

is + + + C C

only - + + + +

Notes

The following restrictions apply to all methods:

• The maximum number of parameters you can declare for a method is 14.
You can work around this restriction by passing a compound parameter such as a struct or a list.
• You cannot define methods with variable argument lists.
You can work around this restriction by passing a list, which can have variable lengths, or a struct,
which can have conditional fields. For example, the following method accepts a list of structs, and
performs appropriate operations on each struct in the list, depending on its type:
m(l: list of any_struct) is {
for each (s) in l do {
if s is a packet (p) then {};
if s is a cell (c) then {};
};
};
This method can then be called as follows:
m({my_cell; my_packet});

e Language Reference 7-3


Methods
Rules for Defining and Extending Methods

Example 1
The following example shows that you can use is to extend a method in a child after the method has been
introduced with is in the parent. However, extending a child more than once with is generates an error.
Extending a child (B) with is after extending its descendant (C) also generates an error.
struct A {my_type() is {out("I am type A")}};

struct B like A {};

struct C like B {my_type() is {out("I am type C, grandchild of A")}};

--extending a child more than once with 'is' gives an error


--extend C {my_type() is {out("This extension is not allowed!")}};

--extending a child with 'is' after extending a descendant gives an error


--extend B {my_type() is {out("I am type B, child of A")}};

Example 2
This example shows that extending a method in a child (FALSE'bye A) is allowed, even though the
method has been extended in a sibling’s descendant (stop bye A).
struct A {
bye:bool;
greetings() is empty;
};

extend bye A {
stop:bool;

when stop bye A{


greetings() is {out("when bye and stop are TRUE, A says bye")};
};
};

--this extension of a method in a child is allowed, even


--though the method has been extended in a sibling
extend FALSE'bye A {greetings() is {out("when bye is FALSE, A says hi")}};

Example 3
This example shows that if you use is after is or after is also | first | only in a when or like child or in one
of their descendents, you cannot subsequently use is to redefine the method in the parent. The last line in
the following example generates an error:

7-4 e Language Reference


Methods
method is [inline]

struct A {
bye:bool;
greetings() is empty;
};

extend bye A {
stop:bool;

when stop bye A{


greetings() is {out("when bye and stop are TRUE, A says bye")};
};
};

--this extension of a method in the parent generates an error


--extend A {greetings() is {out("A says hello")}};

Changing the last line to


extend A {greetings() is only {out("A says hello")}};

removes the error, but overrides the method definition in all A’s subtypes as well.

The following sections describe the syntax for defining and extending methods:

• method is [inline] on page 7-5


• method @event is on page 7-8
• method [@event] is also | first | only | inline only on page 7-12
• method [@event] is undefined | empty on page 7-19
• method … is C routine on page 11-25 in the Usage and Concepts Guide for e Testbenches

See Also
• “Extending Methods in When Subtypes” on page 4-26
• “Restrictions on Like Inheritance” on page 4-41

7.1.1 method is [inline]

Purpose
Declare a regular method

e Language Reference 7-5


Methods
method is [inline]

Category
Struct member

Syntax
method-name ([parameter-list]) [: return-type] is [inline] {action;…}

Syntax Example
struct print {
print_length() is { out("The length is: ", length); };
};

Parameters

method-name A legal e name. See Chapter 2 “e Basics” for more information on names.

parameter-list A list composed of zero or more parameter declarations of the form


param-name: [*]param-type separated by commas. The parentheses around the
parameter list are required even if the parameter list is empty.

param-name A legal e name. See Chapter 2 “e Basics” for more


information on names.

* When an asterisk is prefixed to a scalar parameter type, the


location of the parameter, not its value, is passed. When an
asterisk is prefixed to a list or struct type, the method can
completely replace the struct or list. See “Parameter Passing”
on page 7-34 for more information.

param-type Specifies the parameter type.

return-type For methods that return values, specifies the data type of the return value. See
Chapter 3 “Data Types” for more information.

inline Defines a new inline method and allows the compiler to optimize the inline
method code for the best performance.

action;… A list of zero or more actions. Actions that consume time are illegal in the
action block of a regular method. For information on actions, see “Actions” on
page 2-16.

7-6 e Language Reference


Methods
method is [inline]

Description
An e method is an operational procedure containing actions that define its behavior. A method can have
parameters, local variables, and a return value. You can define a method only within a struct, and you
must create an instance of the struct before you can execute the method. When a method is executed, it
can manipulate the fields of that struct instance.

Defining a method as inline requires Specman to generate code that enables the C compiler to inline the
method. The C compiler to place all the code for the method at each point in the code where the method
is called. This inline expansion allows the compiler to optimize the inline method code for the best
performance. Methods that are frequently called and involve computation, such as the one shown below,
are good candidates for inline definition. This method takes two integers as arguments and returns an
integer:
struct meth {
get_free_area_size(size: int, taken: int): int is inline {
result = size - taken;
};
};

Notes
In addition to the restrictions on all regular methods (see “Notes” in “Rules for Defining and Extending
Methods” on page 7-2), the following restrictions apply to inline methods:

• The Gnu C compiler can inline most methods declared as inline without any additional flags. For the
Sun native C compiler, you might need to use the -xO4 flag; for the HP native compiler, the +O3 flag.
• A method originally defined as inline cannot be redefined using is only, is first, or is also.
• Methods defined in when conditional struct members cannot be inline.
• Time-consuming methods (TCMs) cannot be inline.
• You cannot set a breakpoint on an inline method when there are compiled files that call the method.

Example
This example shows a method that adds two parameters and returns the result. result is an implicit
variable of the declared return type int.
sum(a: int, b: int): int is {
result = a + b;
};

It is legal to assign to the result variable implicitly by using the following alternate syntax:

e Language Reference 7-7


Methods
method @event is

sum(a: int, b: int): int is {


return a + b;
};

See Also
• method @event is on page 7-8
• method [@event] is also | first | only | inline only on page 7-12
• method [@event] is undefined | empty on page 7-19
• “Rules for Defining and Extending Methods” on page 7-2
• “Invoking Methods” on page 7-22
• “Parameter Passing” on page 7-34
• Chapter 22 “Predefined Methods”
• Chapter 2 “e Basics” (in particular, “Actions” on page 2-16)

7.1.2 method @event is

Purpose
Declare a time-consuming method

Category
Struct member

Syntax
method-name ([parameter-list]) [: return-type]@event is {action;…}

Syntax Example
struct meth {
main() @pclk is {
wait @ready;
wait [2];
init_dut();
emit init_complete;
};
};

7-8 e Language Reference


Methods
method @event is

Parameters

method-name A legal e name. See “Chapter 2 “e Basics” for more information on names.

parameter-list A list composed of zero or more parameter declarations of the form


param-name: [*]param-type separated by commas. The parentheses around the
parameter list are required even if the parameter list is empty.

param-name A legal e name. See “Chapter 2 “e Basics” for more information


on names.

* When an asterisk is prefixed to a scalar parameter type, the


location of the parameter, not its value, is passed. When an
asterisk is prefixed to a list or struct type, the method can
completely replace the struct or list. See “Parameter Passing” on
page 7-34 for more information.

param-type Specifies the parameter type.

return-type For methods that return values, specifies the data type of the return value. See
Chapter 3 “Data Types” for more information.

@event Specifies a default sampling event that determines the sampling points of the
TCM. This event must be a defined event in e and serves as the default
sampling event for the time consuming method itself as well as for time
consuming actions, such as wait, within the TCM body. Other sampling points
can also be added within the TCM. See Chapter 13 “Temporal Expressions” for
information on defining default sampling events.

action;… A list of zero or more actions, either time-consuming actions or regular actions.
For information on actions, see “Actions” on page 2-16.

Description
Defines a new time consuming method (TCM). e methods are similar to C functions, Verilog tasks, and
VHDL processes. An e method is an operational procedure containing actions that define its behavior. A
method can have parameters, local variables, and a return value. You can define a method only within a
struct and you must create an instance of the struct before you can execute the method. When a method
is executed, it can manipulate the fields of that struct instance.

TCMs can execute over multiple cycles and are used to synchronize processes in an e program with
processes or events in the DUT. TCMs can contain actions that consume time, such as wait, sync, and
state machine, and can call other TCMs. Within a single e program, multiple TCMs can execute either
in sequence or in parallel, along separate threads. A TCM can also have internal branches, which are
multiple action blocks executing concurrently.

e Language Reference 7-9


Methods
method @event is

The “main()” TCM shown here waits two “pclk” cycles after the event “ready” occurs. It calls a method
to initialize the DUT and emits an event when the initialization is complete.
struct meth {
event pclk is rise('top.pclk')@sim;
event ready is rise('top.ready')@sim;
event init_complete;
init_dut() is empty;
main() @pclk is {
wait @ready;
wait [2];
init_dut();
emit init_complete;
};
};

A TCM can specify events other than the default event as sampling points for actions. For example,
adding the “@ready” sampling event to the “wait [2]” causes the TCM to wait two “ready” cycles rather
than two pclk cycles:
main() @pclk is {
wait @ready;
wait [2] @ready;
init_dut();
emit init_complete;
};

For more information on sampling events, see Chapter 12 “Events”. For more information on temporal
expressions, see Chapter 13 “Temporal Expressions”.

Notes
The following restrictions apply to all TCMs:

• The maximum number of parameters you can declare for a TCM is 14.
You can work around this restriction by passing a compound parameter such as a struct or a list.
• You cannot define methods with variable argument lists.
You can work around this restriction by passing a list, which can have variable lengths, or a struct,
which can have conditional fields. For example, the following TCM accepts a list of structs, and
performs appropriate operations on each struct in the list, depending on its type:
m(l: list of any_struct)@send_data is {
for each (s) in l do {
if s is a packet (p) then {};
if s is a cell (c) then {};

7-10 e Language Reference


Methods
method @event is

};
};
This method can then be called as follows:
start m({my_cell; my_packet});

Example
The “init_dut” TCM shown has two branches running in parallel. The first branch is waiting for a “reset”
event. The second branch waits for two cycles of “cclk” and then launches three methods that check the
state of the DUT. If all three checking methods complete before a reset occurs, then the “Checking is
complete…” message is displayed, and the branch that is waiting for the reset event terminates. If the
reset occurs before the checking methods have completed, they are terminated and the message “A reset
has happened…” is displayed. The “cclk” event and the “reset” event are defined as events in the DUT.
event mready;
event reset is rise('top.reset')@sim;
event cclk is rise('top.cclk')@sim;

init_dut() @cclk is {
first of {
{
wait @reset;
out("A reset has happened…");
};
{
wait [2];
all of {
{check_bus_controller()};
{check_memory_controller()};
{check_alu()};
};
out("Checking is complete...");
emit mready;
};
};
};

See Also
• method is [inline] on page 7-5
• method [@event] is also | first | only | inline only on page 7-12
• method [@event] is undefined | empty on page 7-19

e Language Reference 7-11


Methods
method [@event] is also | first | only | inline only

• “Rules for Defining and Extending Methods” on page 7-2


• “Invoking Methods” on page 7-22
• “Parameter Passing” on page 7-34
• Chapter 13 “Temporal Expressions”
• Chapter 14 “Temporal Struct Members”
• Chapter 15 “Time-Consuming Actions”
• start tcm() on page 7-25
• Chapter 20 “Thread Commands” in the Specman Command Reference
• “Semaphore Methods” on page 22-54
• “event” on page 12-4

7.1.3 method [@event] is also | first | only | inline only

Purpose
Extend a regular method or a TCM

Category
Struct member

Syntax
method-name ([parameter-list]) [: return-type] [@event-type] is
[also|first|only|inline only] {action;…}

Syntax Example
struct meth {
run() is also {
out("Starting main…");
start main();
};
};

7-12 e Language Reference


Methods
method [@event] is also | first | only | inline only

Parameters

method-name The name of the original method.

parameter-list Specifies the same parameter list as defined in the original method, or a
compile-time error is issued.

return-type Specifies the same return value as defined in the original method, or a
compile-time error is issued.

@event-type Specifies the same sampling event as defined in the original method or a
compile-time error is issued.

also The new action block is appended to the end of the original action block.

first The new action block is inserted before the original action block.

only The new action block overrides the original action block.

inline only Replaces the original method definition with an inline definition. The original
method must be a regular method, not a TCM.

action;… A list of zero or more actions. Actions that consume time are illegal in the
action block of a regular method. For information on actions, see “Actions” on
page 2-16.

Description
Replaces or extends the action block in the original method declaration with the specified action block.
The following example extends the struct’s predefined method “run()” to start a user-defined TCM. (A
TCM is a time-consuming method that is distinguished from a regular method by the presence of
@event and can use time-consuming actions such as sync and wait.)
run() is also {
out("Starting main…");
start main();
};

This example extends the “init_dut()” TCM to start another user-defined TCM, “load_mem”. This TCM
is called after all the checking methods in the original method have completed successfully.
extend check_all {
load_mem() @cclk is {out("Loading memory…");};

init_dut() @cclk is also {


wait @mready;
start load_mem();

e Language Reference 7-13


Methods
method [@event] is also | first | only | inline only

};
};

Notes
• Methods that were originally defined as inline cannot be extended or redefined.
• The original method and its extensions share the me and result variables. No other local variables
can be shared across extensions.
• The following rules apply for return actions in extended methods, as illustrated in Figure 7-1 on
page 7-15, Figure 7-2 on page 7-16 and Figure 7-3 on page 7-17:

• When an extension issues a return, any actions following that return within the extension itself are
not executed.
• When a method is extended with is also, the extension starts executing right after the older version
of the method completes execution.
• is also extensions are executed regardless of whether the older version of the method issues a return
or not.
• When a method is extended with is first, the older version of the method is never executed if the
extension issues a return.
• When a method is extended with is only, the older version of the method is never executed, whether
the extension issues a return or not.

Figure 7-1 on page 7-15 shows how a method with an is also extension is executed. The older version
executes first and then the is also extension. Notice that the “This is also2…” statement is not executed
because it follows a return.

7-14 e Language Reference


Methods
method [@event] is also | first | only | inline only

Figure 7-1 Execution of is also Method Extension

module methods1.e
<'
older struct meth {
version of m() is {
method out("This is…");
};
};

is also extend sys {


mi:meth;
};

extend meth {
m() is also {
out("This is also…");
return;
out("This is also2…");
};
};
'>

Result
This is…
This is also…

Figure 7-2 on page 7-16 shows the same method extended again, this time with is first. If a return
statement is included in the is first extension, the older version of the method (the original method
definition and the is also extension) do not execute. If the return statement is deleted, the is first
extension executes and then the older version of the method executes.

e Language Reference 7-15


Methods
method [@event] is also | first | only | inline only

Figure 7-2 Execution of is first Method Extension

module methods2.e
is first <'
import methods1.e;
extend meth {
yes m() is first {
return? out("This is first…");
return;
no };
};
older '>
version of Result with a return in is first
method This is first…

Result with no return in is first


This is first…
This is...
This is also…

Figure 7-3 on page 7-17 shows another extension with is also. Notice that this new extension executes,
regardless of whether there is a return in the older version of the method or not.

7-16 e Language Reference


Methods
method [@event] is also | first | only | inline only

Figure 7-3 Execution of is first Method Extension

module methods3.e
<'
older import methods2.e;
version of extend meth {
method m() is also {
out("This is also3…");
};
};
is also '>

Result with a return in is first


This is first…
This is also3…

Result with no return in is first


This is first…
This is…
This is also…
This is also3…

Example 1
This example redefines the “increment_cnt()” method as an inline method.
extend meth {
increment_cnt (cnt: *int) is inline only {
cnt = cnt + 1;
};
};

Example 2
In this example, the “show()” method is defined originally to identify the kind of packet. The “show()”
method extension displays a different version of the message when the packet has an error.
type packet_kind: [ETH, ATM] (bits:8);

struct packet {
kind: packet_kind;
has_error: bool;

e Language Reference 7-17


Methods
method [@event] is also | first | only | inline only

show() is {
out("Packet kind is…", kind);
};

when has_error packet{


show() is only {
out("This packet has an error…");
};
};
};

Example 3
This example extends the “execute()” method to return immediately if the “top.interrupt” signal is
active, without executing any of the actions in the original method. Note that the parameter list in the
extension is the same as the parameter list in the original method definition, and the sampling event must
also be repeated for the extension. Similarly, when the original method definition has a return type, it
must be repeated in the method extension.
struct ctrl_stub {
execute(cmd: ctrl_cmd) @cclk is {
out(appendf("Executing a %s (addr %s) control command",
cmd.kind, cmd.addr));
case cmd.kind {
RD: {
wait [2];
};
WR: {
wait [2];
};
};
};
};

extend ctrl_stub {
execute(cmd: ctrl_cmd) @cclk is first {
if ('top.interrupt' == 1) then {
return;
};
};
};

See Also
• method is [inline] on page 7-5

7-18 e Language Reference


Methods
method [@event] is undefined | empty

• method @event is on page 7-8


• method [@event] is undefined | empty on page 7-19
• collect on page 5-8 in the Specman Command Reference
• “Rules for Defining and Extending Methods” on page 7-2
• “Extending Methods in When Subtypes” on page 4-26

7.1.4 method [@event] is undefined | empty

Purpose
Declare an abstract method

Category
Struct member

Syntax
method-name ([parameter-list]) [: return-type] [@event-type] is [undefined|empty]

Syntax Example
struct packet {
show() is undefined;
};

Parameters

method-name A legal e name. See “Chapter 2 “e Basics” for more information on names.

e Language Reference 7-19


Methods
method [@event] is undefined | empty

parameter-list A list composed of zero or more parameter declarations of the form


param-name: [*]param-type separated by commas. The parentheses around the
parameter list are required even if the parameter list is empty.

param-name A legal e name. See Chapter 2 “e Basics” for more


information on names.

* When an asterisk is prefixed to a scalar parameter type, the


location of the parameter, not its value, is passed. When an
asterisk is prefixed to a list or struct type, the method can
completely replace the struct or list. See “Parameter
Passing” on page 7-34 for more information.

param-type Specifies the parameter type.

return-type For methods that return values, specifies the data type of the return value. See
Chapter 3 “Data Types” for more information.

@event-type Specifies a default sampling event that determines the sampling points of the
TCM. This event must be a defined event in e and serves as the default
sampling event for the TCM itself as well as for time consuming actions, such
as wait, within the TCM body. Other sampling points can also be added within
the TCM.

undefined No action block is defined for the method yet; an action block must be defined
in a subsequent module before this method is called. A runtime error is issued
if it is called before it is defined.

empty The action block is empty, but no error is issued if it is called. Empty
value-returning methods return the default value for the type.

Description
Declares an abstract regular method or an abstract TCM with no defined functionality. Abstract methods
are place holders that you can extend at a later point. A TCM is a time-consuming method that is
distinguished from a regular method by the presence of @event and can use time-consuming actions
such as sync and wait.

Notes
The following restrictions apply to all abstract methods:

• The maximum number of parameters you can declare for a TCM is 14.
You can work around this restriction by passing a compound parameter such as a struct or a list.

7-20 e Language Reference


Methods
method [@event] is undefined | empty

• You cannot define methods with variable argument lists.


You can work around this restriction by passing a list, which can have variable lengths, or a struct,
which can have conditional fields.

Example
Undefined or empty methods are often used in base types. This example declares an abstract method
“show()” in the base struct “packet” and defines the appropriate functionality in the “Ethernet packet”
and “IEEE packet” subtypes.
type packet_protocol: [Ethernet, IEEE, foreign];

struct packet {
protocol: packet_protocol;
size: int [0..1k];
data[size]: list of byte;

show() is empty;
};

extend Ethernet packet {


e_field: int;

show() is {out("This is an Ethernet packet")};


};

extend IEEE packet {


i_field: int;

show() is {out("This is an IEEE packet")};


};

extend sys {
a: foreign packet;
b: Ethernet packet;
c: IEEE packet;

run() is also {
a.show();
b.show();
c.show();
};
};

e Language Reference 7-21


Methods
Invoking Methods

Result
Notice that no message is printed by the foreign packet.
Specman > test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
This is an Ethernet packet
This is an IEEE packet
No actual running requested.
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.
Specman >

See Also
• method is [inline] on page 7-5
• method @event is on page 7-8
• method [@event] is also | first | only | inline only on page 7-12
• “Rules for Defining and Extending Methods” on page 7-2

7.2 Invoking Methods


Before invoking a method, you must create an instance of the struct that contains it. The call must
conform to the proper syntax and must be made from an appropriate context, as described below.

The following sections describe the two ways to invoke a TCM:

• tcm() on page 7-23


• start tcm() on page 7-25
The following sections describe how you can call regular methods:

• method() on page 7-27


• compute method() on page 7-29
The last section describes the return action:

• return on page 7-30

7-22 e Language Reference


Methods
tcm()

See Also
• “Rules for Defining and Extending Methods” on page 7-2
• “Parameter Passing” on page 7-34

7.2.1 tcm()

Purpose
Call a TCM

Category
Action or expression

Syntax
[[struct-exp].]method-name([parameter-list])

Syntax Example
init_dut();

Parameters

struct-exp The pathname of the struct that contains the method. If the struct expression is
missing, the implicit variable it is assumed. If both struct expression and the
period (.) are missing, the method name is resolved according to the scoping rules.
In other words,
• .init_dut() means it.init_dut()
• init_dut() means me.init_dut(), or if that does not exist, global.init_dut()
See “Chapter 2 “e Basics” for more information on naming resolution.

method-name The method name as specified in the method definition.

parameter-list A list of zero or more parameters separated by commas, one parameter for each
parameter in the parameter list of the method definition. Parameters are passed by
their relative position in the list, so the name of the parameter being passed does
not have to match the name of the parameter in the method definition. The
parentheses around the parameter list are required even if the parameter list is
empty.

e Language Reference 7-23


Methods
tcm()

Description
You can call a TCM only from another TCM.

A TCM that does not return a value can be started (see start tcm() on page 7-25) or called. A call of a
TCM that does not return a value is syntactically an action.

A call of a TCM that does return a value is an expression, and the return type of the TCM must conform
to the type of the variable or field it is assigned to.

A called TCM begins execution either when its sampling event occurs or immediately, if the sampling
event has already occurred for the current Specman tick.

The calling TCM waits until the called TCM returns before continuing execution. For this reason, a
called TCM is considered a subthread of the calling TCM and shares the same thread handle (thread ID)
with the calling TCM. In contrast, a started TCM runs in parallel with the TCM that started it, on a
separate thread.

Note
You cannot call a TCM from a regular method. To invoke a TCM from within a regular method, use
start.

Example
This example shows how to call a TCM from another TCM.
struct meth {
event pclk is rise('top.pclk')@sim;
event ready is rise('top.ready')@sim;
event init_complete;
init_dut() @pclk is empty;
main() @pclk is {
wait @ready;
wait [2];
init_dut();
emit init_complete;
};
};

See Also
• start tcm() on page 7-25
• Chapter 15 “Time-Consuming Actions”

7-24 e Language Reference


Methods
start tcm()

• “Struct Hierarchy and Name Resolution” on page 2-23


• “Invoking Methods” on page 7-22
• “Rules for Defining and Extending Methods” on page 7-2
• “Parameter Passing” on page 7-34

7.2.2 start tcm()

Purpose
Start a TCM

Category
Action

Syntax
start [[struct-exp].]method-name([parameter-list])

Syntax Example
start main();

Parameters

struct-exp The pathname of the struct that contains the method. If the struct expression is
missing, the implicit variable it is assumed. If both struct expression and the
period (.) are missing, the method name is resolved according to the scoping
rules. See “Chapter 2 “e Basics” for more information on naming resolution.

method-name The method name as specified in the method definition.

parameter-list A list of zero or more parameters separated by commas, one parameter for each
parameter in the parameter list of the method definition. Parameters are passed by
their relative position in the list, so the name of the parameter being passed does
not have to match the name of the parameter in the method definition. The
parentheses around the parameter list are required even if the parameter list is
empty.

e Language Reference 7-25


Methods
start tcm()

Description
You can use a start action within another method, either a TCM or a regular method. A started TCM
begins execution either when its sampling event occurs or immediately, if the sampling event has already
occurred for the current Specman tick.

A started TCM runs in parallel with the TCM that started it on a separate thread. A started TCM has a
unique thread handle (thread ID) that is assigned to it automatically by the scheduler. You can retrieve
this handle using one of the predefined methods of the scheduler.

The recommended way to start an initial TCM, which can then invoke other TCMs, is to extend the
related struct’s predefined run() method.

Notes
• A TCM that has a return value cannot be started with a start action.
• You cannot start a TCM before the run phase begins or after the check phase begins. See “Global
Methods” on page 22-2 for more information on test phases.

Example
This example shows how to extend a struct’s run() method to start a TCM. Note that the start syntax
omits the default sampling event.
struct meth {
event clk is rise('top.clk');
run() is also {
out("Starting main…");
start main();
};
};

See Also
• Global Method run_test() on page 22-6
• The run() Method of any_struct on page 22-39
• Chapter 15 “Time-Consuming Actions”
• “Struct Hierarchy and Name Resolution” on page 2-23
• “Invoking Methods” on page 7-22
• “Rules for Defining and Extending Methods” on page 7-2

7-26 e Language Reference


Methods
method()

• “Parameter Passing” on page 7-34

7.2.3 method()

Purpose
Call a regular method

Category
Action or expression

Syntax
[[struct-exp].]method-name([parameter-list])

Syntax Example
tmp1 = get_free_area_size(size, taken);

Parameters

struct-exp The pathname of the struct that contains the method. If the struct expression is
missing, the implicit variable it is assumed. If both struct expression and the
period (.) are missing, the method name is resolved according to the scoping
rules. See Chapter 2 “e Basics”, for more information about naming resolution.

method-name The method name as specified in the method definition.

parameter-list A list of zero or more parameters separated by commas, one parameter for each
parameter in the parameter list of the method definition. Parameters are passed by
their relative position in the list, so the name of the parameter being passed does
not have to match the name of the parameter in the method definition. The
parentheses around the parameter list are required even if the parameter list is
empty.

Description
The proper context for calling a regular method depends on whether the method returns a value or not.

• If the method returns a value, it is an expression and can be called from any context where an
expression is valid.

e Language Reference 7-27


Methods
method()

• If the method does not return a value, it is an action and can be called from any context where an
action is valid.

Example 1
Two common contexts for calling value-returning methods are shown below.
m() is {
var tmp1: int;
tmp1 = get_free_area_size(size, taken);
print tmp1;
};
keep length <= get_free_area_size(size, taken);

When placed on the right-hand side of an assignment operator, the method’s return value type must
conform to the type of the variable or field it is assigned to.

Example 2
In some cases you may want to call a value-returning method without using the value that is returned. To
do this, you can use the compute action. In the example shown below, the “m()” method increments the
“counter” variable, but does not use the value returned.
inc_counter() : int is {
counter += 1;
result = counter;
};
m() is {
if 'top.b' > 15 {compute inc_counter();};
};

Example 3
You can call regular methods that do not return values either from other methods, including TCMs, from
the Specman command line or from action blocks associated with other constructs, as shown below.
event alu_watcher is {rise('inst_start') exec {
var i: inst;
i = new;
instructions.add(i);
};
};

7-28 e Language Reference


Methods
compute method()

See Also
• compute method() on page 7-29
• “Struct Hierarchy and Name Resolution” on page 2-23
• “Rules for Defining and Extending Methods” on page 7-2
• “Parameter Passing” on page 7-34

7.2.4 compute method()

Purpose
Compute a regular method

Category
Action

Syntax
compute [[struct-exp].]method-name([parameter-list])

Syntax Example
if 'top.b' > 15 {compute inc_counter();};

Parameters

struct-exp The pathname of the struct that contains the method. If the struct expression is
missing, the implicit variable it is assumed. If both struct expression and the
period (.) are missing, the method name is resolved according to the scoping
rules. See Chapter 2 “e Basics”, for more information about naming resolution.

method-name The method name as specified in the method definition.

parameter-list A list of zero or more parameters separated by commas, one parameter for each
parameter in the parameter list of the method definition. Parameters are passed by
their relative position in the list, so the name of the parameter being passed does
not have to match the name of the parameter in the method definition. The
parentheses around the parameter list are required even if the parameter list is
empty.

e Language Reference 7-29


Methods
return

Description
In some cases you may want to call a value-returning method without using the value that is returned. To
do this, you can use the compute action.

Example
In the example shown below, the “m()” method increments the “counter” variable, but does not use the
value returned.
inc_counter() : int is {
counter += 1;
result = counter;
};
m() is {
if 'top.b' > 15 {compute inc_counter();};
};

See Also
• method() on page 7-27
• “Struct Hierarchy and Name Resolution” on page 2-23
• “Rules for Defining and Extending Methods” on page 7-2
• “Parameter Passing” on page 7-34

7.2.5 return

Purpose
Return from regular method or a TCM

Category
Action

Syntax
return [exp]

7-30 e Language Reference


Methods
return

Syntax Example
return i*i;

Parameters

exp In value-returning methods, an expression specifying the return value is required in each
return action. In non-value-returning methods, expressions are not allowed in return
actions.

Description
Returns immediately from the current method to the method that called it. The execution of the calling
method then continues.

It is not always necessary to provide a return action. When a value returning method ends without a
return action, the value of result is returned.

Notes
• The return action must be used carefully in method extensions. See method [@event] is also | first
| only | inline only on page 7-12 for more information.

• Any actions that follow a return action in the method definition are ignored.
• Actions placed in a method extension are performed before the return is executed.

Example 1
This example shows return in a value-returning expression.
<'
extend sys {
sqr(i: uint): uint is {
return i*i;
};
};
'>

Example 2
This example shows return in a non-value-returning method named “start_eng()”.
<'
struct eng_str {
on: bool;

e Language Reference 7-31


Methods
return

};

struct st_eng {
engine: eng_str;
start_eng(e: eng_str) is {
if e.on then {
out("engine is already on");
return;
};
e.on = TRUE;
out("engine has been turned on");
};
};
'>

Example 3
For value-returning methods, instead of a return, the special variable result can be assigned and its
value is returned. In the example below, if “t” is less than 100, the “sqr_1()” method exits, returning “t”.
Otherwise, it returns 101.
<'
extend sys {
sqr_1(i: uint): uint is {
var t := i*i;
if t < 100 then {
return t;
};
result = 101;
};
};
'>

Example 4
This example illustrates that any actions following a return action in a method definition or in a method
extension are ignored:
<'
extend sys {
m1(): int is {
return 5;
result = 0;
out ("FAIL");
};
m1():int is also {
return result + 7;

7-32 e Language Reference


Methods
return

out ("FAIL");
};
};
'>

Result
vrst-tool> print sys.m1() using dec
sys.m1() = 12

Example 5
The following example shows a method that has a compound type as a return value. In the
get_alpha_num() method, the return action calls another method, select_list(), which has an index, slctr,
which can have a value from 0 to 3.

The select_list() method returns a list of strings (“a0”, “a1”, “a2”, “a3”, for example), which is
determined by the value (A, B, C, or D) of the ALPHA field.

In the call to select_list(), the slctr value is used as an index into the list of strings returned from the case
action by select_list(). Thus, the get_alpha_num() method, called in run() in sys, returns the string with
index = slctr from the list for case = ALPHA.
<'
type a_type: [A, B, C, D, E];
struct top {
ALPHA: a_type;
slctr: uint (bits: 2);
select_list() :list of string is {
case ALPHA {
A : { return {"a0"; "a1"; "a2"; "a3"}; };
B : { return {"b0"; "b1"; "b2"; "b3"}; };
C : { return {"c0"; "c1"; "c2"; "c3"}; };
D : { return {"d0"; "d1"; "d2"; "d3"}; };
E : { return {"e0"; "e1"; "e2"; "e3"}; };
};
};

get_alpha_num(slctr: uint): string is {


return select_list()[slctr];
};
};

extend sys {
top;
run() is also {
print top.ALPHA;

e Language Reference 7-33


Methods
Parameter Passing

print top.slctr;
var an_strng: string;
an_strng = top.get_alpha_num(top.slctr);
print an_strng;
};
};
'>

Result
Running the test ...
top.ALPHA = A
top.slctr = 2
an_strng = "a2" // "a2" is the string with index 2 in list A

See Also
• method [@event] is also | first | only | inline only on page 7-12

7.3 Parameter Passing


How a parameter is passed depends on whether the parameter is scalar or compound, as described in
these sections:

• “Scalar Parameter Passing” on page 7-34


• “Compound Parameter Passing” on page 7-35
• “Notes on Passing by Reference” on page 7-36

7.3.1 Scalar Parameter Passing


Scalar parameters include numeric, Boolean, and enumerated types. When you pass a scalar parameter
to a method, by default the value of the parameter is passed. This is called “passing by value”. Any
change to the value of that parameter by the method applies only within that method instance and is lost
when the method returns. For example, the “increment()” method defined below increments the value of
the parameter passed to it.
increment (cnt: int) is {
cnt = cnt + 1;
};
m() is {
var tmp: int = 7;
increment(tmp);
print tmp;

7-34 e Language Reference


Methods
Compound Parameter Passing

};

However, since “cnt” is passed by value, the variable “tmp” retains its original value, and the print
statement displays:
tmp = 7

To allow a method to modify the parameter, prefix the parameter type with an asterisk. This is called
“passing by reference”. If you modify the “increment() “method as follows:
increment (cnt: *int) is {
cnt = cnt + 1;
};
m() is {
var tmp: int = 7;
increment(tmp);
print tmp;
};

“tmp” has the value 8 after the method returns. Note that the asterisk is used only in the method
definition, not in the method call.

7.3.2 Compound Parameter Passing


Compound parameters are either structs or lists. Passing a struct or a list to a method allows the method
to modify the struct fields and the list items. This is called “passing by reference”. Thus, if you modify
the “increment()” method to accept a list:
increment_list (cnt: list of int) is {
for each in cnt {
cnt[index] = cnt[index] + 1;
};
};

and pass a list of integers to it, each item in the list reflects its incremented value after the method
returns.

Placing an asterisk in front of the list or struct type allows the method to completely replace the struct or
list. For example, the “create_if_illegal()” method accepts a struct instance of type packet. If it
determines that the “legal” field of struct instance is FALSE, it allocates a new struct instance of type
“packet”.
create_if_illegal(pkt: *packet) is {
if pkt.legal == FALSE then {
pkt = new;
};
};

e Language Reference 7-35


Methods
Notes on Passing by Reference

7.3.3 Notes on Passing by Reference


There are several restrictions that apply when you pass parameters by reference:

• There is no automatic casting to a reference parameter. Thus, if you try to pass a variable that is
declared as a type other than a 32-bit int to the “increment()” method, you get a compile-time error.
• You cannot pass a list element by reference. Thus, if a variable “tmp” is declared as a list of int, it
is illegal to pass “tmp[index]” to “increment()”, as defined above.
• An expression that cannot be placed on the left-hand-side of an assignment cannot be passed by
reference.
• Called TCMs can accept reference parameters, but started TCMs cannot.

7-36 e Language Reference


8 Creating and Modifying e
Variables
The following sections describe how to create and assign values to e variables:

• “About e Variables” on page 8-1


• var on page 8-2
• = on page 8-4
• op= on page 8-7
• <= on page 8-9

8.1 About e Variables


An e variable is a named data object of a declared type. e variables are declared and manipulated in
methods. They are dynamic; they do not retain their values across subsequent calls to the same method.

The scope of an e variable is the action block that encloses it. If a method contains nested action blocks,
variables in the inner scopes hide the variables in the outer scopes. Variable scoping is described in more
detail in “Struct Hierarchy and Name Resolution” on page 2-23.

Some e actions create implicit variables. They are described in more detail in “Implicit Variables” on page
2-30.

The following sections describe the actions that create and modify e variables explicitly

• var on page 8-2


• = on page 8-4
• op= on page 8-7

e Language Reference 8-1


Creating and Modifying e Variables
var

8.2 var

Title
Variable declaration

Category
Action

Syntax
var name [: [type] [= exp]]

Syntax Example
var a: int;

Parameters

name A legal e name.

type A declared e type. The type can be omitted if the variable name is the same as the name
of a struct type or if the variable is assigned a typed expression.

exp The initial value of the variable. If no initial value is specified, the variables are
initialized to 0 for integer types, NULL for structs, FALSE for Boolean types, and lists
as empty.

Description
Declares a new variable with the specified name as an element or list of elements of the specified type,
and having an optional initial value.

The var action is legal in any place that an action is legal, and the variable is recognized from that point
on. e variables are dynamic; they do not retain their values across subsequent calls to the same method.

The scope of an e variable is the action block that encloses it. If a method contains nested action blocks,
variables in the inner scopes hide the variables in the outer scopes. Variable scoping is described in more
detail in “Struct Hierarchy and Name Resolution” on page 2-23.

8-2 e Language Reference


Creating and Modifying e Variables
var

Example 1
This example shows the declaration of two variables, one with an assigned initial value:
<'
extend sys {
m() is {
var a: int;
var m: int = 2 + a;
};
};
'>

Example 2
This example shows the keywords list of used to create a list.
<'
struct packet {
protocol: [atm, eth, other];
len: uint [0..10];
data[len]: list of byte;
};

extend sys {
m() is {
var packets: list of packet;
};
};
'>

Example 3
This example shows a variable declarations with the type omitted. The variable “packet” is assumed to
be of type “packet”.
<'
struct packet {
protocol: [atm, eth, other];
len: uint [0..10];
data[len]: list of byte;
};

extend sys {
m() is {
var packet;
};

e Language Reference 8-3


Creating and Modifying e Variables
=

};
'>

Example 4
In this example, “p” gets type packet, because that is the type of “my_packets[3]”, and “z” gets type int,
because 5 has type int.
<'
extend sys {
my_packets: list of packet;
m() is {
var p := my_packets[3];
var z := 5;
};
};
'>

8.3 =

Purpose
Simple assignment

Category
Action

Syntax
lhs-exp=exp

Syntax Example
sys.u = 0x2345;

Parameters

lhs-exp A legal e expression that evaluates to a variable of a method, a global variable, a field of
a struct, or an HDL object. The expression can contain the list index operator [n], the bit
access operator [i:j], or the bit concatenation operator %{}.

8-4 e Language Reference


Creating and Modifying e Variables
=

exp A legal e expression, either an untyped expression (such as an HDL object) or an


expression of the same type as the left-hand-side expression.

Description
Assigns the value of the right-hand-side expression to the left-hand-side expression.

Note
There are two other places within the e language which make use of the equal sign. These are a double
equal sign (==) for specifying equality in Boolean expression, and a triple equal sign (===) for the
Verilog-like identity operator. These two operators should not be confused with the single equal sign (=)
assignment operator.

Example 1
This example shows the operators that are allowed in the left-hand-side expression.
<'
struct n {
m() is {
var i: int (bits:16);
var j: int (bits:16);
var lint: list of int = {15;31;63;127};

sys.u = 0x2345;
print sys.u;
lint[0] = 0x98765432;
print lint[0];
i[1:0] = 3;
print i;
%{i,j} = lint[0];
print i, j;
};
};

extend sys {
u:uint;
ni:n;
};
'>

e Language Reference 8-5


Creating and Modifying e Variables
=

Result
vrst-tool> sys.ni.m()
sys.u = 0x2345
lint[0] = 0x98765432
i = 0x0003
i = 0x9876
j = 0x5432

Example 2
This example shows the assignment operator used in initialization.
<'
struct packet {
good : bool;
size : [small, medium, large];
length : int;
};
extend sys {
post_generate() is also {
var p : packet = new;
print p;
var q : packet = new good large packet;
print q;
var x := new packet (p) with {
p.length = 5;
print p;
};
};
};
'>

See Also
• “Reading and Writing HDL Objects” on page 8-21 in the Specman Elite Integrator’s Guide
• “Untyped Expressions” on page 3-17
• “Assignment Rules” on page 3-19
• “Precision Rules for Numeric Operations” on page 3-24
• “Automatic Type Casting” on page 3-29

8-6 e Language Reference


Creating and Modifying e Variables
op=

8.4 op=

Purpose
Compound assignment

Category
Action

Syntax
lhs-exp op=exp

Syntax Example
sys.c.count1 += 5;

Parameters

lhs-exp A legal e expression that evaluates to a variable of a method, a global variable, a field of
a struct, or an HDL object.

exp A legal e expression of the same type as the left-hand-side expression.

op A binary operator, including binary bitwise operators (except ~), the Boolean operators
and and or, and the binary arithmetic operators.

Description
Performs the specified operation on the two expressions and assigns the result to the left-hand-side
expression.

Example 1
This example shows the compound assignment operator used with arithmetic operators.
<'
struct counter {
count1: uint;
mult: uint;

keep count1 == 0;

e Language Reference 8-7


Creating and Modifying e Variables
op=

keep mult == 2;
};

extend sys {
c: counter;
m() is {
var i: int = 2;
sys.c.count1 += 5;
sys.c.mult *= i;
print sys.c.count1, sys.c.mult;
};
};
'>

Result
vrst-tool> sys.m()
sys.c.count1 = 0x5
sys.c.mult = 0x4

Example 2
This example shows the compound assignment operator used with the shift operator.
<'
extend sys {
m() is {
print 'top.address';
'top.address' <<= 4;
print 'top.address';
};
};
'>

Result
vrst-tool> sys.m()
'top.address' = 0xff
'top.address' = 0xff0

Example 3
This example shows the compound assignment operator used with a Boolean operator.
<'
extend sys {

8-8 e Language Reference


Creating and Modifying e Variables
<=

m() is {
var is_ok: bool = TRUE;
var is_legal: bool;
is_ok or= is_legal;
print is_ok;
};
};
'>

Result
vrst-tool> sys.m()
is_ok = TRUE

8.5 <=

Purpose
Delayed assignment

Category
Action

Syntax
[struct-exp.]field-name <= exp

Syntax examples:
da <= da+1;

Parameters

struct-exp A legal e expression that evaluates to a struct. The default


is me.

field-name A field of the struct referenced by struct-exp.

e Language Reference 8-9


Creating and Modifying e Variables
<=

exp A legal e expression, either an untyped expression (such


as an HDL object) or an expression of the same type as the
left-hand-side expression.

Description
The delayed assignment action assigns a struct field just before the next @sys.new_time after the
action. The purpose is to support raceless coding in e by providing the same results regardless of the
evaluation order of TCMs and temporal expressions. (See “Simulation Time and Specman Ticks” on
page 12-14 for a description of @sys.new_time.)

Both expressions are evaluated immediately (not delayed) in the current context. The assignment is not
considered a time-consuming action, so you can use it in both TCMs and in regular methods, in on
action blocks and in exec action blocks.

If a field has multiple delayed assignments in the same cycle, they are performed in the specified order.
The final result is taken from the last delayed assignment action.

Unlike in HDL languages, the delayed assignment in Specman does not emit any events; thus, zero
delay iterations are not supported.

Note
The left-hand-side expression in the delayed assignment action can only be a field. Unlike the
assignment action, the delayed assignment action does not accept assignment to any of the following:

• A variable of a method
• A list item
• A bit
• A bit slice
• A bit concatenation expression

Example
The following example shows how delayed assignment provides raceless coding. In this example there
is one incrementing() TCM, which repeatedly increments the sys.a and sys.da fields, and one observer()
TCM, which observes their value.
<'
extend sys {
!a : int;

8-10 e Language Reference


Creating and Modifying e Variables
<=

!da : int;

incrementing()@any is {
for i from 1 to 5 {
a = a+1;
da <= da+1;
wait cycle;
};
stop_run();
};

observer()@any is {
while (TRUE) {
out( "observing 'a' as ", a, " observing 'da' as ", da );
wait cycle;
};
};

run() is also {
start observer();
start incrementing();
};
};
'>

Result
From the results you can see that the value of sys.a observed by the observer() TCM is order-dependent,
depending whether observer() is executed before or after incrementing(). The observed value of sys.da,
however, is independent of the execution order. Even if incrementing() runs first, sys.da gets its
incremented value just before the next new_time event and thus is not be seen by observer().

If observer() runs before incrementing():


Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
observing 'a' as 0 observing 'da' as 0
-----------------------------
observing 'a' as 1 observing 'da' as 1
-----------------------------
observing 'a' as 2 observing 'da' as 2
-----------------------------
observing 'a' as 3 observing 'da' as 3
-----------------------------
observing 'a' as 4 observing 'da' as 4

e Language Reference 8-11


Creating and Modifying e Variables
<=

-----------------------------
Last specman tick - stop_run() was called
Normal stop - stop_run() is completed
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

If incrementing() runs before observer():


Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
observing 'a' as 1 observing 'da' as 0
-----------------------------
observing 'a' as 2 observing 'da' as 1
-----------------------------
observing 'a' as 3 observing 'da' as 2
-----------------------------
observing 'a' as 4 observing 'da' as 3
-----------------------------
observing 'a' as 5 observing 'da' as 4
-----------------------------
Last specman tick - stop_run() was called
Normal stop - stop_run() is completed
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

See Also
• show delayed on page 22-17 in the Specman Command Reference
• break on contention on page 16-32 in the Specman Command Reference
• trace on contention on page 17-32 in the Specman Command Reference
• “Simulation Time and Specman Ticks” on page 12-14

8-12 e Language Reference


9 Control Flow Actions
The following sections describe the control flow actions:

• “Conditional Actions” on page 9-1


• “Iterative Actions” on page 9-7
• “File Iteration Actions” on page 9-17
• “Actions for Controlling the Program Flow” on page 9-20

9.1 Conditional Actions


The following conditional actions are used to specify code segments that will be executed only if a
certain condition is met:

• if then else on page 9-1


• case labeled-case-item on page 9-3
• case bool-case-item on page 9-5

9.1.1 if then else

Purpose
Perform an action block based on whether a given Boolean expression is TRUE

Category
Action

e Language Reference 9-1


Control Flow Actions
if then else

Syntax
if bool-exp [then] {action; ...} [else if bool-exp [then] {action; ...}] [else {action; ...}]

Syntax Example
if a > b {print a, b;} else {print b, a};

Notes
• Because the if then else clause comprises one action, the semicolon comes at the end of the clause
and not after each action block within the clause. (Do not put a semicolon between the closing curly
bracket for the action block and the else keyword.)
• You can repeat the else if clause multiple times.

Parameters

bool-exp A Boolean expression.

action; ... A series of zero or more actions separated by semicolons and enclosed in curly
braces.

Description
If the first bool-exp is TRUE, the then action block is executed. If the first bool-exp is FALSE, the else
if clauses are executed sequentially: if an else if bool-exp is found that is TRUE, its then action block is
executed; otherwise the final else action block is executed.

The else if then clauses are used for multiple Boolean checks (comparisons). If you require many else if
then clauses, you might prefer to use a case bool-case-item action.

Example 1
Following is the syntax example expressed as a multi-line example rather than a single-line example.
if a > b then {
print a, b;
}
else {
print b, a;
};

Example 2
The following example includes an else if clause:

9-2 e Language Reference


Control Flow Actions
case labeled-case-item

if a_ok {
print x;
}
else if b_ok {
print y;
}
else {
print z;
};

See Also
• case labeled-case-item on page 9-3
• case labeled-case-item on page 9-3
• “Iterative Actions” on page 9-7
• “File Iteration Actions” on page 9-17
• “Actions for Controlling the Program Flow” on page 9-20

9.1.2 case labeled-case-item

Purpose
Execute an action block based on whether a given comparison is true

Category
Action

Syntax
case case-exp {labeled-case-item; … [default: {default-action; …}]}

Syntax Example
case packet.length {
64: {out("minimal packet")};
[65..256]: {out("short packet")};
[257..512]: {out("long packet")};
default: {out("illegal packet length")};
};

e Language Reference 9-3


Control Flow Actions
case labeled-case-item

Parameters

case-exp A legal e expression.

labeled-case-item label-exp[:] action-block


label-range[:] action-block
Where
• label-exp is a scalar
• label-range is a range
• action-block is a list of zero or more actions separated by semicolons and
enclosed in curly braces. Syntax: {action;…}
Note For each label-exp or label-range, there must be at least one
action-block. In other words, the entire labeled-case-item is repeatable, not
just the action-block related to the label-exp.

default-action; ... A sequence of zero or more default actions separated by semicolons and
enclosed in curly braces.

Description
Evaluates the case-exp and executes the first action-block for which label-case-item matches the
case-exp. If no label--case-item equals the case-exp, executes the default-action block, if specified.

After an action-block is executed, Specman proceeds to the line that immediately follows the entire case
statement.

Example
struct m {
counter: uint;
kind: [small, medium, large, xlarge, xxlarge];
c_meth() is {
case me.kind {
small: {print "SMALL"};
[large, medium]: { print "LARGE or MEDIUM";
me.counter += 1;
};
default: {print "OTHER"};
};
};
};

9-4 e Language Reference


Control Flow Actions
case bool-case-item

See Also
• if then else on page 9-1
• case bool-case-item on page 9-5
• “Iterative Actions” on page 9-7
• “File Iteration Actions” on page 9-17
• “Actions for Controlling the Program Flow” on page 9-20

9.1.3 case bool-case-item

Purpose
Execute an action block based on whether a given Boolean comparison is true

Category
Action

Syntax
case {bool-case-item; ... [default {default-action; ...}]}

Syntax Example
case {
packet.length == 64 {out("minimal packet"); };
packet.length in [65..255] {out("short packet"); };
default {out("illegal packet"); };
};

e Language Reference 9-5


Control Flow Actions
case bool-case-item

Parameters

bool-case-item bool-exp[:] action-block


Where
• bool-exp is a Boolean expression.
• action-block is a list of zero or more actions separated by semicolons
and enclosed in curly braces. Syntax: {action;...}
Note that the entire bool-case-item is repeatable, not just the action-block
related to the bool-exp.
Note For each action-block, there must be at least one bool-exp. In other
words, the entire bool-case-item is repeatable, not just the action-block
related to a given bool-exp.

default-action; ... A sequence of zero or more actions separated by semicolons and enclosed in
curly braces.

Description
Evaluates the bool-exp conditions one after the other; executes the action-block associated with the first
TRUE bool-exp. If no bool-exp is TRUE, executes the default-action-block, if specified.

After an action-block is executed, Specman proceeds to the line that immediately follows the entire case
statement.

Each of the bool-exp conditions is independent of the other bool-exp conditions, and there is no main
case-exp to which all cases refer (unlike the case labeled-case-item on page 9-3).

This case action has the same functionality as a single if then else action in which you enter each
bool-case-item as a separate else if then clause.

Example
The bool-exp conditions are totally independent, and can refer to many arbitrary fields and attributes
(not only to a single field as in the example above). For example, here is a set of independent Boolean
conditions:
case {
kind == small { // condition 1: relates to kind
print "SMALL";
};
a > b { // condition 2: relates to a and b
print "a > b";
var temp := a;

9-6 e Language Reference


Control Flow Actions
Iterative Actions

a = b;
b = temp;
};
a < b && kind == large {
// condition 3: relates to a,b,kind
print "a < b && kind == large";
};
default {print "OTHER"};
// condition 4: default
};

See Also
• if then else on page 9-1
• case labeled-case-item on page 9-3
• “Iterative Actions” on page 9-7
• “File Iteration Actions” on page 9-17
• “Actions for Controlling the Program Flow” on page 9-20

9.2 Iterative Actions


This section describes the following iterative actions, which are used to specify code segments that will
be executed in a loop, multiple times, in a sequential order:

• while on page 9-7


• repeat until on page 9-9
• for each in on page 9-11
• for from to on page 9-14
• for on page 9-15

9.2.1 while

Purpose
Execute a while loop

e Language Reference 9-7


Control Flow Actions
while

Category
Action

Syntax
while bool-exp [do] {action; ...}

Syntax Example
while a < b {a += 1;};

Parameters

bool-exp A Boolean expression.

action; ... A sequence of zero or more actions separated by semicolons and enclosed in curly
braces.

Example 1
The while loop in the following example adds 10 to “ctr” as many times as it takes it to get from 100 to
the value of SMAX in steps of 1.
ctr_assn() is {
var i: uint;
i = 100;
while (i <= SMAX) {
ctr = ctr + 10;
i+=1;
};
};

Example 2
The while loop in the following example assigns “top.inc” to “ctr” every two cycles, as long as “done”
remains FALSE.
lp_read()@clk is {
while (!done) {
wait [2]*cycle;
ctr = top.inc;
};
};

9-8 e Language Reference


Control Flow Actions
repeat until

Example 3
The while loop in the following example assigns “top.inc” to “ctr” every two cycles, in an endless loop.
It loops until the test run is stopped.
lp_read()@clk is {
while TRUE {
wait [2]*cycle;
ctr = top.inc;
};
};

Description
Executes the action block repeatedly in a loop while bool-exp is TRUE. You can use this construct to set
up a perpetual loop as “while TRUE {}”.

See Also
• repeat until on page 9-9
• for each in on page 9-11
• for from to on page 9-14
• for on page 9-15
• “Conditional Actions” on page 9-1
• “File Iteration Actions” on page 9-17
• “Actions for Controlling the Program Flow” on page 9-20

9.2.2 repeat until

Purpose
Execute a repeat until loop

Category
Action

e Language Reference 9-9


Control Flow Actions
repeat until

Syntax
repeat {action; ...} until bool-exp

Syntax Example
repeat {i+=1;} until i==3;

Parameters

action; ... A sequence of zero or more actions separated by semicolons and enclosed in curly
braces.

bool-exp A Boolean expression.

Description
Execute the action block repeatedly in a loop until bool-exp is TRUE.

Note
A repeat until action performs the action block at least once. A while action might not perform the
action block at all.

Example
repeat {
i+=1;
print i;
} until i==3;

See Also
• while on page 9-7
• for each in on page 9-11
• for from to on page 9-14
• for on page 9-15
• “Conditional Actions” on page 9-1
• “File Iteration Actions” on page 9-17
• “Actions for Controlling the Program Flow” on page 9-20

9-10 e Language Reference


Control Flow Actions
for each in

9.2.3 for each in

Purpose
Execute a for each loop

Category
Action

Syntax
for each [type] [(item-name)] [using index (index-name)]
in [reverse] list-exp [do] {action; …}

Syntax Example
for each transmit packet (tp) in sys.pkts do {print tp};
// "transmit packet" is a type

Parameters

type A type of the struct comprising the list specified by list-exp. Elements in the list must
match this type to be acted upon.

item-name A name you give to specify the current item in list-exp.


If you do not include this parameter, the item is referred to with the implicit variable
“it”. Verisity recommends that you explicitly name the item to avoid confusion about
the contents of “it”.

index-name A name you give to specify the index of the current list item.
If you do not include this parameter, the item is referred to with the implicit variable
“index”. Verisity recommends that you explicitly name the item to avoid confusion
about the contents of “index”.

list-exp An expression that results in a list.

action; ... A sequence of zero or more actions separated by semicolons and enclosed in curly
braces.

e Language Reference 9-11


Control Flow Actions
for each in

Description
For each item in list-exp, if its type matches type, execute the action block. Inside the action block, the
implicit variable it (or the optional item-name) refers to the matched item, and the implicit variable
index (or the optional index-name) reflects the index of the current item. If reverse is specified, list-exp
is traversed in reverse order, from last to first. The implicit variable index (or the optional index-name)
starts at zero for regular loops, and is calculated to start at “(list.size() - 1)” for reverse loops.

Note The “to” and “from” expressions in a for each loop are evaluated on each iteration of the loop.

The it and index Implicit Variables


Each for each in action defines two new local variables for the loop, named by default it and index.
Keep the following in mind:

• If loops are nested one inside the other, the local variables of the internal loop hide those of the
external loop. To overcome this hiding, specify the item-name and index-name with unique names.
• Within the action block, you cannot assign a value to it or index—or to item-name or index-name.

Example 1
<'
extend sys {
do_it() is {
var numbers := {1; 2; 3};
for each in numbers {
print it;
};
var sum: int;
for each (n) in numbers {
sum += n;
print sum;
};
};
run() is also {
do_it();
};
};
'>

Example 2
for each in reverse pktList do {
// Traverse in reverse order
print it; // "it" can refer to the various subtypes
};

9-12 e Language Reference


Control Flow Actions
for each in

Example 3
This example has two for each loops, each of which invokes a method and an out() routine for the
particular subtype (ATM cell or IP cell).
<'
type cell_t: [ATM,IP];
struct cell{
kind: cell_t;
when ATM cell {
meth() is {
outf("ATM cell: ");
};
};
when IP cell {
meth() is {
outf("IP cell: ");
};
};
};

extend sys {
cell_l[20] : list of cell;
run () is also {
for each ATM cell (a) in cell_l {
a.meth();
out(index);
};
for each IP cell (a) in cell_l {
a.meth();
out(index);
};
}
};
'>

See Also
• while on page 9-7
• repeat until on page 9-9
• for from to on page 9-14
• for on page 9-15
• “Implicit Variables” on page 2-30

e Language Reference 9-13


Control Flow Actions
for from to

• “Conditional Actions” on page 9-1


• “File Iteration Actions” on page 9-17
• “Actions for Controlling the Program Flow” on page 9-20

9.2.4 for from to

Purpose
Execute a for loop for the number of times specified by from to

Category
Action

Syntax
for var-name from from-exp [down] to to-exp [step step-exp] [do] {action; …}

Syntax Example
for i from 5 down to 1 do {out(i);}; // Outputs 5,4,3,2,1

Parameters

var-name A temporary variable of type int.

from-exp, to-exp, Valid e expressions that resolve to type int.


step-exp The default value for step-exp is one.

action; ... A sequence of zero or more actions separated by semicolons and enclosed in
curly braces.

Description
Creates a temporary variable var-name of type int, and repeatedly executes the action block while
incrementing (or decrementing if down is specified) its value from from-exp to to-exp in interval values
specified by step-exp (defaults to 1).

In other words, the loop is executed until the value of var-name is greater than the value of to-exp (if
down is not specified) or until the value of var-name is less than the value of to-exp (if down is
specified). For example, the following line of code prints “in” one time:

9-14 e Language Reference


Control Flow Actions
for

for j from 1 to 1 {out("in");};

Notes
• The temporary variable var-name is visible only within the for from to loop in which it is created.
• The from-exp and to-exp are evaluated on each iteration of the loop.

Example
for i from 2 to 2 * a do {
out(i);
};
for i from 1 to 4 step 2 do {
out(i);
}; // Outputs 1,3
for i from 4 down to 2 step 2 do {
out(i);
}; // Outputs 4,2

See Also
• while on page 9-7
• repeat until on page 9-9
• for each in on page 9-11
• for on page 9-15
• “Conditional Actions” on page 9-1
• “File Iteration Actions” on page 9-17
• “Actions for Controlling the Program Flow” on page 9-20

9.2.5 for

Purpose
Execute a C-style for loop

Category
Action

e Language Reference 9-15


Control Flow Actions
for

Syntax
for {initial-action; bool-exp; step-action} [do] {action; ...}

Syntax Example
for {i=0; i<=10; i+=1} do {out(i);};

Parameters

initial-action An action.

bool-exp A Boolean expression

step-action An action.

action; ... A sequence of zero or more actions separated by semicolons and enclosed in
curly braces.

Description
The for loop works similarly to the for loop in the C language. This for loop executes the initial-action
once, and then checks the bool-exp. If the bool-exp is TRUE, it executes the action block followed by
the step-action. It repeats this sequence in a loop for as long as bool-exp is TRUE.

Notes
• You must enter an initial-action.
• If you use a loop variable within a for loop, you must declare it before the loop (unlike the temporary
variable of type int automatically declared in a for from to loop).
• Although this action is similar to a C-style for loop, keep in mind that the initial-action and step-action
must be e style actions. For example, the following syntax won’t run:
for {i=0,j=0; i < 10; i += 1} //incorrect syntax
While the following syntax will run:
for {{i=0;j=0}; i < 10; i += 1} //correct syntax

Example
var i: int;
var j: int;
for {i = 0; i < 10; i += 1} do {
if i % 3 == 0 then {

9-16 e Language Reference


Control Flow Actions
File Iteration Actions

continue;
};
j = j + i;
if j > 100 then {
break;
};
};

See Also
• while on page 9-7
• repeat until on page 9-9
• for each in on page 9-11
• for from to on page 9-14
• “Conditional Actions” on page 9-1
• “File Iteration Actions” on page 9-17
• “Actions for Controlling the Program Flow” on page 9-20

9.3 File Iteration Actions


This section describes the following two loop constructs, which are used to manipulate general ASCII
files:

• for each line in file on page 9-17


• for each file matching on page 9-19

9.3.1 for each line in file

Purpose
Iterate a for loop over all lines in a text file

Category
Action

e Language Reference 9-17


Control Flow Actions
for each line in file

Syntax
for each [line] [(name)] in file file-name-exp [do] {action; …}

Syntax Example
for each line in file "signals.dat" do {'(it)' = 1};
// Reads a list of signal names and
// assigns to each the value 1

Parameters

name Variable referring to the current line in the file.

file-name-exp A string expression that gives the name of a text file.

action; ... A sequence of zero or more actions separated by semicolons and enclosed in
curly braces.

Description
Executes the action block for each line in the text file file-name. Inside the block, it (or optional name)
refers to the current line (as string) without the final “\n” (the final new line character, CR).

Example
This example reads each line of a file and prints the line if it is not blank. String matching is used to see
if the line is blank: “l !~ "/^$/"” means “l does not match the beginning of a line, ^, followed
immediately by the end of a line, $”.
for each line (l) in file "test.dat" {
// Print all the nonblank lines in the file
if l !~ "/^$/" then { print l; };
};

If the file cannot be opened, an error message similar to the following appears.
for each line in file "er_file" {print it};
*** Error: Cannot open input file 'er_file' for reading

See Also
• for each file matching on page 9-19
• “Conditional Actions” on page 9-1

9-18 e Language Reference


Control Flow Actions
for each file matching

• “Iterative Actions” on page 9-7


• “Actions for Controlling the Program Flow” on page 9-20

9.3.2 for each file matching

Purpose
Iterate a for loop over a group of files

Category
Action

Syntax
for each file [(name)] matching file-name-exp [do] {action; ...}

Syntax Example
for each file matching "*.e" {out(it);}
//lists the e files in the current directory

Parameters

name Variable referring to the current line in the file.

file-name-exp A string expression giving a file name.

action; ... A sequence of zero or more actions separated by semicolons and enclosed in
curly braces.

Description
For each file (in the file search path) whose name matches file-name-exp execute the action block. Inside
the block, it (or optional name) refers to the matching file name.

Example
for each file (f_name) matching "*.txt" do {
for each line in file f_name{
if it ~ "/error/" then {out(it);
};

e Language Reference 9-19


Control Flow Actions
Actions for Controlling the Program Flow

};
};

See Also
• for each line in file on page 9-17
• “Conditional Actions” on page 9-1
• “Iterative Actions” on page 9-7
• “Actions for Controlling the Program Flow” on page 9-20

9.4 Actions for Controlling the Program Flow


The actions described in this section are used to alter the flow of the program in places where the flow
would otherwise continue differently. The e language provides the following actions for controlling the
program flow:

• break on page 9-20


• continue on page 9-21

9.4.1 break

Purpose
Break the execution of a loop

Category
Action

Syntax
break

Syntax Example
break

9-20 e Language Reference


Control Flow Actions
continue

Description
Breaks the execution of the nearest enclosing iterative action (for or while). When a break action is
encountered within a loop, the execution of actions within the loop is terminated, and the next action to
be executed is the first one following the loop.

You cannot place break actions outside the scope of a loop (the compiler will report an error).

Example
for each (p) in packet_list do {
// ... other code
if p.len == 0 then {
break; // Get out of this loop
};
// ... other code
};

See Also
• continue on page 9-21
• “Conditional Actions” on page 9-1
• “Iterative Actions” on page 9-7
• “File Iteration Actions” on page 9-17

9.4.2 continue

Purpose
Stop executing the current loop iteration and start executing the next loop iteration

Category
Action

Syntax
continue

Syntax Example
continue

e Language Reference 9-21


Control Flow Actions
continue

Description
Stops the execution of the nearest enclosing iteration of a for or a while loop, and continues with the
next iteration of the same loop. When a continue action is encountered within a loop, the current
iteration of the loop is aborted, and execution continues with the next iteration of the same loop.

You cannot place continue actions outside the scope of a loop (the compiler will report an error).

Example
for each (p) in packet_list do {
if p.len == 1 then {
continue; // Go to next iteration, skip "print p"
};
print p;
};

See Also
• break on page 9-20
• “Conditional Actions” on page 9-1
• “Iterative Actions” on page 9-7
• “File Iteration Actions” on page 9-17

9-22 e Language Reference


10 Checks and Error Handling
The e language has many constructs that check for errors in the DUT or add exception handling and
diagnostics to an e program. This chapter covers these topics:

• “Handling DUT Errors” on page 10-1


• “Handling User Errors” on page 10-14
• “Handling Programming Errors” on page 10-21

See Also
• “Error Handling: Interactive and Batch Mode” on page 7-10 in the Specman Elite Integrator’s Guide

10.1 Handling DUT Errors


There are several constructs you can use to perform data or protocol checks on the DUT and to specify
how you want to handle any errors that occur:

• check that on page 10-2


• dut_error() on page 10-4
• dut_error_struct on page 10-6
• set_check() on page 10-11

e Language Reference 10-1


Checks and Error Handling
check that

10.1.1 check that

Purpose
Perform a data comparison and, depending on the results, print a message

Category
Action

Syntax
check [that] bool-exp [else dut_error(message: exp, …)]

Syntax Example
check_count(i:int) is {
check that i == expected_count else
dut_error("Bad i: ", i);
};
Note Keep in mind that check that, as with all actions, must be associated with a method. Checks are
also created implicitly from expect struct members.

Parameters

bool-exp Boolean expression that performs a data comparison.

message String or an expression that can be converted to a string. If the bool-exp is FALSE, the
message expressions are converted to strings, concatenated, and printed to the screen
(and to the log file if it is open).

Description
Performs a data comparison and, depending on the results, prints a message. The following example,
check_hard_error() is {
check that 'top.hard_error'== 1 else
dut_error("Error-5 -- Hard error not asserted");
};

displays an error message like this one:


*** Dut error at time 0

10-2 e Language Reference


Checks and Error Handling
check that

Checked at line 4 in check2.e


In [email protected]_hard_error():

Error-5 -- Hard error not asserted

Will stop execution immediately (check effect is ERROR)

*** Error: A Dut error has occurred

Using check that allows you to:

• Manipulate the response to failed checks with the set checks command.
• Show which checks have failed with the show checks command.
• Track the number of failed checks with predefined session fields.

Omitting the else Clause


If you omit the else dut_error clause, Specman uses the check that clause as the error message. For
example,
check_a() is {
check that a < b;
};

displays an error message like this one:


*** Dut error at time 0
Checked at line 6 in check3.e
In [email protected]_a():

check that a < b

Will stop execution immediately (check effect is ERROR)

*** Error: A Dut error has occurred

Example
check_count(i:int) is {
check that i == expected_count else
dut_error("Bad i: ", i);
};

e Language Reference 10-3


Checks and Error Handling
dut_error()

Result
*** Dut error at time 0
Checked at line 6 in check4.e
In [email protected]_count():

Bad i: 4

Will stop execution immediately (check effect is ERROR)

*** Error: A Dut error has occurred

See Also
• “Error Handling: Interactive and Batch Mode” on page 7-10 in Specman Elite Integrator’s Guide

10.1.2 dut_error()

Purpose
Specify a DUT error message string

Category
Action

Syntax
dut_error(message: exp, …)

Syntax Example
if 'data_out' != 'data_in' then
{dut_error("DATA MISMATCH: Expected ", 'data_in')};

Parameters

message String or an expression that can be converted to a string. The message expressions
are converted to strings, concatenated, and printed to the screen (and to the log file
if it is open).

10-4 e Language Reference


Checks and Error Handling
dut_error()

Description
Specifies a DUT error message string. This action is usually associated with an if action, a check that
action, or an expect struct member. If the Boolean expression in the associated action or struct member
evaluates to TRUE, then the error message string is displayed.

Calling dut_error() directly is exactly equivalent to:


check that FALSE else dut_error();

Note
When you call dut_error() directly (not within a check that or an expect), there is no way to see that a
check was successfully performed. session.check_ok is always FALSE after a direct call to
dut_error().

Example
<'
extend sys {
m() is {
if 'data_out' != 'data_in' then
{dut_error("DATA MISMATCH: Expected ", 'data_in')};
};
};
'>

Result
vrst-tool> sys.m()

*** Dut error at time 0


Checked at line 4 in /tests/check6.e
In [email protected]():

DATA MISMATCH: Expected 1

Will stop execution immediately (check effect is ERROR)

*** Error: A Dut error has occurred

See Also
• “Error Handling: Interactive and Batch Mode” on page 7-10 in the Specman Elite Integrator’s Guide

e Language Reference 10-5


Checks and Error Handling
dut_error_struct

10.1.3 dut_error_struct

Purpose
Define DUT error response

Category
Predefined struct

Syntax
struct dut_error_struct {
get_message(): string;
source_struct(): any_struct;
source_location(): string;
source_struct_name(): string;
source_method_name(): string;
check_effect(): check_effect;
set_check_effect(effect:check_effect);
write();
pre_error() is empty;
};

Note The get_message() method is new as of Specman 4.3.1. It replaces the previous message field,
which is now under deprecation. However, the previous message field is still supported at this time, which
means that you do not need to change any existing code. For more information, see “Deprecation and
Backward Compatibility in the Current Release” on page 8-2 and “Understanding the Deprecation
Process” on page 7-1 in About This Specman Elite Release.

Syntax Example
extend dut_error_struct {
write() is also {
if source_struct() is a XYZ_packet (p) then {
print p.parity_calc();
};
};
};

10-6 e Language Reference


Checks and Error Handling
dut_error_struct

Struct Members
get_message() Returns the message that was defined by the temporal or data DUT
check and is printed by dut_error_struct.write().
source_struct() Returns a reference to the struct where the temporal or data DUT check
is defined.
source_location() Returns a string giving the line number and source module name, for
example, “At line 13 in @checker”.
source_struct_name() Returns a string giving the name of the source struct, for example,
“packet”.
source_method_name() Returns a string giving the name of the method containing the DUT
data check, for example, “done()”.
check_effect() Returns the check effect of that DUT check, for example,
ERROR_AUTOMATIC.
set_check_effect() Sets the check effect in this instance of the dut_error_struct. You can
call this method from pre_error() to change the check effect of selected
checks.
pre_error() The first method that is called when a DUT error occurs, unless the
check effect is IGNORE. This method is defined as empty, unless
extended by the user. Extending this method lets you modify error
handling for a particular instance or set of instances of a DUT error.
For a description of the error handling procedure in detail, see “How
Specman Elite Handles Errors” on page 7-12 in the Specman Elite
Integrator’s Guide.
write() The method that is called after dut_error_struct.pre_error() is called
when a DUT error happens. This method causes the DUT message to be
displayed, unless the check effect is IGNORE. You can extend this
method to perform additional actions.
For a description of the error handling procedure in detail, see “How
Specman Elite Handles Errors” on page 7-12 in the Specman Elite
Integrator’s Guide.

Description
The predefined struct dut_error_struct defines the DUT error response. To modify the error response,
extend either write() or pre_error().

Only the write() and pre_error() methods are called directly by Specman, but you can use the other
fields and predefined methods of dut_error_struct when you extend write() or pre_error().

e Language Reference 10-7


Checks and Error Handling
dut_error_struct

Note
Do not use dut_error_struct.write() to change the value of the check effect. Use pre_error() instead.

Example 1
The following code implements a parity checker using DUT error checks. dut_error_struct.write() has
been extended to print additional information.
<'
type XYZ_kind_type : [good, bad] ;

struct XYZ_packet {
kind : XYZ_kind_type ;
%addr : uint (bits : 2) ;
%len : uint (bits : 6) ;
%data [len] : list of byte ;
%parity : byte ;

parity_calc() : byte is {
result = addr | (len << 2) ;
for each (item) in data do {
result ^= item ;
};
};

parity_check(p: XYZ_packet) is {
p.kind = ('data' == p.parity_calc()) ? good : bad;
if (p.kind == good) then {
check that 'err' == 0 else
dut_error ("Err != 0 for good pkt");
}
else {
check that 'err' == 1 else
dut_error ("Err != 1 for bad pkt");
};
};
};

extend dut_error_struct {
write() is also {
if source_struct() is a XYZ_packet (p) then {
print p.parity_calc();
};
};
};

10-8 e Language Reference


Checks and Error Handling
dut_error_struct

extend sys {
packets[10]: list of XYZ_packet;

check_packets() is {
for each XYZ_packet (p) in packets {
p.parity_check(p);
};
};

setup() is also {
set_check("...Err...pkt...", ERROR_CONTINUE);
};

run() is also {
check_packets();
};

};
'>

Result
In this test, 9 DUT errors occur.
Specman > test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...

-------------------------------------------------------
*** Dut error at time 0
Checked at line 24 in check8.e
In [email protected]_check():

Err != 1 for bad pkt


p.parity_calc() = 228
-------------------------------------------------------
Will continue execution (check effect is ERROR_CONTINUE)

...

No actual running requested.


Checking the test ...
Checking is complete - 9 DUT errors, 0 DUT warnings.
Specman >

e Language Reference 10-9


Checks and Error Handling
dut_error_struct

Example 2
This example extends Example 1, extending pre_error() so that no more than 3 parity errors will be
displayed.
<'
extend sys {
num_parity_errors: uint;
keep num_parity_errors == 0;
};
extend dut_error_struct {
pre_error() is also {
if source_struct() is a XYZ_packet then {
sys.num_parity_errors = sys.num_parity_errors +1;
if sys.num_parity_errors > 3 then {
set_check_effect(IGNORE);
};
};
};
};
'>

Result
Specman checking9> test
Doing setup ...
2 checks were modified.
Generating the test using seed 1...
Starting the test ...
Running the test ...

-------------------------------------------------------
*** Dut error at time 0
Checked at line 25 in @checking8
In [email protected]_check():

Err != 1 for bad pkt


p.parity_calc() = 228
-------------------------------------------------------
Will continue execution (check effect is ERROR_CONTINUE)

...

No actual running requested.


Checking the test ...

10-10 e Language Reference


Checks and Error Handling
set_check()

Checking is complete - 3 DUT errors, 0 DUT warnings.


Specman checking9>

Example 3
This example shows how error messages can be handled within units. (See “Units Overview” on page 5-1
for a description of units and modular verification.)

To print some unit status information upon any error happening within a unit, you could extend
dut_error_struct.write() as shown below. The call to try_enclosing_unit() returns NULL if not called
from within a MIPS unit. If called from within a MIPS unit, the status of that MIPS unit is printed.
<'
extend dut_error_struct {
write() is also {
var MIPS:= source_struct().try_enclosing_unit(MIPS);

if MIPS != NULL then {


out("-- Status of ", MIPS.e_path(),
" at time of error: --");
MIPS.show_status();
};
};
};
'>

See Also
• “Error Handling: Interactive and Batch Mode” on page 7-10 in the Specman Elite Integrator’s Guide

10.1.4 set_check()

Purpose
Set check severity

Category
Predefined routine

Syntax
set_check(static-match: string, check-effect: keyword)

e Language Reference 10-11


Checks and Error Handling
set_check()

Syntax Example
<'
extend sys {
setup() is also {
set_check("...", WARNING);
};
};
'>

Parameters

static-match A regular expression enclosed in double quotes. Only checks whose


message string matches this regular expression are modified. The
match string must use either the native Specman syntax or an
AWK-like syntax. See “String Matching” on page 2-65 in the e
Language Reference.

Note You must enclose AWK-like syntax in forward slashes, for


example, “/Vio/”. Also, the * character in native Specman syntax
matches only non-white characters. Use … to match white or
non-white characters.

check-effect is one of the following:

ERROR Specman issues an error message, increases num_of_dut_errors,


halts the run immediately and returns to the simulator prompt.

ERROR_BREAK_RUN Specman issues an error message, increases num_of_dut_errors,


breaks the run at the next cycle boundary and updates the simulation
GUI with the latest values.

ERROR_AUTOMATIC Specman issues an error message, increases num_of_dut_errors,


breaks the run at the next cycle boundary, and performs the end of test
checking and finalization of test data that is normally performed when
stop_run() is called.

ERROR_CONTINUE Specman issues an error message, increases num_of_dut_errors, and


continues execution.

WARNING Specman issues a warning, increases num_of_dut_warnings and


continues execution.

IGNORE Specman issues no messages, does not increase num_of_dut_errors


or num_of_dut_warnings, and continues execution.

10-12 e Language Reference


Checks and Error Handling
set_check()

Description
Sets the severity or the check effect of specific DUT checks, so that failing checks will produce errors or
warnings.

See “How Specman Elite Handles Errors” on page 7-12 in the Specman Elite Integrator’s Guide for a
discussion of how these check effects can be used in interactive and batch mode.

Note
• This command affects only checks that are currently loaded into Specman.
• If a DUT check’s check effect is ERROR and a configure run -error_command option is specified,
the error command actions are also executed.

Example
Loading the following extension changes the check effect of all currently defined checks to WARNING
during the setup phase of test.
<'
extend sys {
setup() is also {
set_check("...", WARNING);
};
};
'>

Result
vrst-tool> setup
Doing setup ...
5 checks were modified.
vrst-tool> show checks

Defined checks =

0. check @sn_cover in simulator.error_from_simulator (WARNING)


count=0 Error from simulator: ...
1. check @sn_cover_misc in covers.cover_dut_error (WARNING)
count=0 Illegal value for cover item ...
2. check @sn_coverage in scheduler.handle_event (WARNING)
count=0 event ... which has a global cover group, occurred
more than once
3. check @check8 in XYZ_packet.parity_check (WARNING) count=0

e Language Reference 10-13


Checks and Error Handling
Handling User Errors

Err != 0 for good pkt


4. check @check8 in XYZ_packet.parity_check (WARNING) count=0
Err != 1 for bad pkt

See Also
• “How Specman Elite Handles Errors” on page 7-12 in the Specman Elite Integrator’s Guide
• set checks on page 12-1 in the Specman Command Reference
• configure run on page 6-51 in the Specman Command Reference

10.2 Handling User Errors


The e language has several constructs that help you handle user errors, such as file I/O errors or semantic
errors. This section describes the constructs used for handling these kinds of errors:

• warning() on page 10-14, which issues a warning message when a given error occurs.
• error() on page 10-16, which issues an error message and exits to the Specman prompt when a given
error is detected.
• fatal() on page 10-17, which issues an error message and exits to the UNIX prompt when a given
error is detected.
• try on page 10-19, which defines an alternative response for fixing or bypassing an error.
Note Errors handled by these constructs do not increase the session.num_of_dut_errors and
session.num_of_dut_warnings fields that are used to track DUT errors. In addition, the error responses
defined with these constructs are not displayed by the show checks command or influenced by the set
checks command or modifications to the dut_error_struct.write() method.

See Also
• configure run on page 6-51 in the Specman Command Reference

10.2.1 warning()

Purpose
Issue a warning message

10-14 e Language Reference


Checks and Error Handling
warning()

Category
Action

Syntax
warning(message: string, …)

Syntax Example
warning("len exceeds 50");

Parameter

message String or an expression that can be converted to a string. When the warning
action is executed, the message expressions are converted to strings,
concatenated, and printed to the screen.

Description
Issues the specified warning error message. Does not halt the methods being currently run.

Example
check_size() is {
if (pkt.size != LARGE) {
warning("packet size is ", pkt.size);
};
};

Result
*** Warning: packet size is SMALL

See Also
• error() on page 10-16
• fatal() on page 10-17
• try on page 10-19
• configure run on page 6-51 in the Specman Command Reference

e Language Reference 10-15


Checks and Error Handling
error()

10.2.2 error()

Purpose
Issue an error message

Category
Action

Syntax
error(message: string, …)

Syntax Example
check_size() is {
if (pkt.size != LARGE) {
error("packet size is ", pkt.size);
};
};

Parameter

message String or an expression that can be converted to a string. When the error action is
executed, the message expressions are converted to strings, concatenated, and
printed to the screen.

Description
Issues the specified error message, halts all methods being currently run, and returns to the Specman
prompt. The only exception to this is if the error action appears inside the first action block given in a
try action. In that case, Specman jumps to the else action block within the try action and continues
running.

Example
<'
type size : [SMALL, LARGE];

struct packet {
size;
};

10-16 e Language Reference


Checks and Error Handling
fatal()

extend sys {
pkt: packet;

check_size() is {
if (pkt.size != LARGE) {
error("packet size is ", pkt.size);
};
};
};
'>

Result
*** Error: packet size is SMALL

See Also
• warning() on page 10-14
• fatal() on page 10-17
• try on page 10-19
• configure run on page 6-51 in the Specman Command Reference

10.2.3 fatal()

Purpose
Issue error message and exit Specman to return to the UNIX prompt

Category
Action

Syntax
fatal(message: string, …)

Syntax Example
fatal("Run-time error - exiting Specman");

e Language Reference 10-17


Checks and Error Handling
fatal()

Parameter

message String or an expression that can be converted to a string. When the fatal()
action is executed, the message expressions are converted to strings,
concatenated, and printed to the screen.

Description
Issues the specified error message, halts all activity, exits Specman immediately, and returns to the
UNIX prompt. (If you are working in Specview, a dialog box appears before you are returned to the
UNIX prompt.)

fatal() returns a non-zero status to the UNIX shell.

Using fatal with config run error_command


You can use fatal() with the -error_command option of the config run command to automatically stop
simulation completely when an error occurs. For example, the following code creates the
“error_actions()” method, which is called when any error occurs:
extend sys {
setup() is also {
set_config(run, error_command, "sys.error_actions()");
};
};

And the following code defines “sys.error-actions()” to exit Specman with the fatal() action when an
error occurs:
extend sys {
error_actions() is {
-- .. Maybe perform other error actions here
fatal("Run-time error - exiting Specman");
};
};

Example
The following code shows the use of warning(), error(), fatal(), and try. The code is intended to open
a log file. If the log file cannot be opened, the simulation issues a warning and tries to open a temporary
log file. If the temporary log file cannot be opened and if the simulation is in batch, it issues an error
message and exits to the UNIX prompt. If the simulation is interactive, it issues an error message only.
open_checking_log_file(file_name:string) is {
try {

10-18 e Language Reference


Checks and Error Handling
try

var my_file :file = files.open(file_name, "w",


"Log file");
} else {
warning("Could not open ", file_name,
"; opening temporary log file sim.log");
try {
var my_file :file = files.open("sim.log", "w",
"Temp Log file");
} else {
close_stimulus_log_files();
if interactive == FALSE {
fatal("Could not open temp file sim.log.\n\n",
"Please check write permissions on current",
" directory, sim.log, and ", file_name,
".\n\nError level is ", error_level, ".");
} else {
error("Could not open temp file sim.log.\n\n",
"Please check write permissions on current",
" directory, sim.log, and ", file_name,
".\n\nError level is ", error_level, ".");
};
};
};
};

See Also
• warning() on page 10-14
• error() on page 10-16
• try on page 10-19
• configure run on page 6-51 in the Specman Command Reference

10.2.4 try

Purpose
Define an alternative response for fixing or bypassing an error

Category
Action

e Language Reference 10-19


Checks and Error Handling
try

Syntax
try {action; …} [else {action; …}]

Syntax Example
try {
var my_file :file = files.open(file_name, "w",
"Log file");
} else {
warning("Could not open ", file_name,
"; opening temporary log file sim.log");
};

Parameters

action; … A series of zero or more actions enclosed in curly braces and separated by
semicolons.
The first action block (following try) cannot include the fatal() action. Subsequent
action blocks (following else) can.

Description
Executes the action block following try. If an error occurs, executes the action block specified in the else
clause, in which the error can be fixed or handled. If no error occurs, the else clause is skipped.

If you do not specify an else clause, execution after errors continues normally from the first action
following the try block.

Example
The following code example shows the use of warning(), error(), fatal(), and try. The code is intended
to open a log file. If the log file cannot be opened, the simulation issues a warning and tries to open a
temporary log file. If the temporary log file cannot be opened and if the simulation is in batch, it issues
an error message and exits to the UNIX prompt. If the simulation is interactive, it issues an error
message only.
open_checking_log_file(file_name:string) is {
try {
var my_file :file = files.open(file_name, "w",
"Log file");
} else {
warning("Could not open ", file_name,
"; opening temporary log file sim.log");
try {

10-20 e Language Reference


Checks and Error Handling
Handling Programming Errors

var my_file :file = files.open("sim.log", "w",


"Temp Log file");
} else {
close_stimulus_log_files();
if interactive == FALSE {
fatal("Could not open temp file sim.log.\n\n",
"Please check write permissions on current",
" directory, sim.log, and ", file_name,
".\n\nError level is ", error_level, ".");
} else {
error("Could not open temp file sim.log.\n\n",
"Please check write permissions on current",
" directory, sim.log, and ", file_name,
".\n\nError level is ", error_level, ".");
};
};
};
};

See Also
• warning() on page 10-14
• error() on page 10-16
• fatal() on page 10-17
• configure run on page 6-51 in the Specman Command Reference

10.3 Handling Programming Errors


The e language has a special construct, the assert action, to help you handle programming errors, such
as internal contradictions or invalid parameters.

10.3.1 assert

Purpose
Check the e code for correct behavior

Category
Action

e Language Reference 10-21


Checks and Error Handling
Handling Programming Errors

Syntax
assert bool-exp [else error(message: string, …)]

Syntax Example
assert a < 20;

Parameters

bool-exp Boolean expression that checks the behavior of the code.

message String or an expression that can be converted to a string. If the bool-exp is FALSE,
the message expressions are converted to strings, concatenated, and printed to the
screen (and to the log file if it is open).

Description
Checks the e code for correct behavior. Use this action to catch coding errors. When an assert fails, it
prints the specified error message plus the line number and name of the file in which the error occurred.
If you omit the else error clause, assert prints a global error message.

Note
When an error is encountered, assert stops the method being executed.

Example
<'
extend sys {
a: uint;

m() is {
assert a < 20 else error("The value of a is ", a);
out("Should never get here if a is 20 or more");
};
};
'>

Result
*** Error: Assertion failed (a programming error):
The value of a is 1840385568
In 'sys.m()' at line 6 in check22.e

10-22 e Language Reference


Checks and Error Handling
Handling Programming Errors

See Also
• warning() on page 10-14
• error() on page 10-16
• fatal() on page 10-17
• try on page 10-19
• configure run on page 6-51 in the Specman Command Reference

e Language Reference 10-23


Checks and Error Handling
Handling Programming Errors

10-24 e Language Reference


11 Generation Constraints
Test generation is the Specman process that produces values for fields and variables (data items).
Constraints are directives that influence the behavior of the Specman test generator. They are declared
within a struct and influence the generation of values for data items within the struct and its subtree.
There are two basic types of constraints:

1. Value constraints restrict the range of possible values that the generator produces for data items, and
they constrain the relationship between multiple items.

2. Order constraints influence the sequence in which data items are generated. Generation order is
important because it affects the distribution of values and the success of generation.

Both value and order constraints can be hard or soft:

• Hard constraints (either value or order) must be met or an error is issued.


• Soft value constraints suggest default values but can be overridden by hard value constraints.
• Soft order constraints suggest modifications to the default generation order, but they can be overridden
by dependencies between data items or by hard order constraints.

You can define constraints in many ways:

• By defining a range of legal values in the field or variable declaration


• By defining a list size in the list declaration
• By using one of the keep construct variations within a struct definition
• By using a gen...keeping action within a method
By default, generation takes place when you enter the test, start, or generate command before invoking
the simulator. However, you can generate values for particular struct instances, fields, or variables
during simulation (on-the-fly generation) with the gen action. You can also set values procedurally
before or after generation within the pre_generate() or post_generate() methods.

e Language Reference 11-1


Generation Constraints
Basic Concepts of Generation

This chapter contains the following sections:

• “Basic Concepts of Generation” on page 11-2


• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55

See Also
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• The Generation Guide provides detailed information on the test generator.

11.1 Basic Concepts of Generation


The following introduce basic concepts related to constraints and generation. See the Generation Guide
for complete information on these concepts.

• “Generation Order” on page 11-2


• “Unidirectional Constraints” on page 11-4
• “Enforceable Expressions” on page 11-7
• “Order of Evaluation of Soft Value Constraints” on page 11-9
• “Constraining Struct Instances” on page 11-10
• “Constraining Lists” on page 11-11
• “Constraining Bit Slices” on page 11-15

11.1.1 Generation Order


The fields in a struct are generated one by one, starting with the first field defined and progressing
through the fields in the order in which they appear in the e code. A struct item is always fully generated,
including all substructs, before the next item is generated. Similarly, within a list, each item is fully
generated, including all substructs, before the next item is generated. Lists are generated in ascending
index order.

User-defined constraints can affect generation order. A constraint for a particular item might create a
dependency that requires a field to be generated before some other fields. For example, the keep
constraint shown below requires that the “kind” field be generated first and passed to the “get_size()”
method in order to determine the value of “size”. Value constraints that induce a generation order are
called unidirectional constraints.

11-2 e Language Reference


Generation Constraints
Generation Order

type kind: [tx, rx];


struct packet {
kind;
size: byte;
keep size == get_size(kind);
};

Generation order is important because it influences the distribution of values. For example, in the keep
constraint shown below, if “kind” is generated first, “kind” is “tx” about 1/2 the time because there are
only two legal values for “kind”:
struct packet {
kind: [tx, rx];
size: byte;
keep size > 15 => kind == rx;
};

On the other hand, if “size” is generated first, there is only a 1 in 16 chance that “size” will be less than
or equal to 15, so “kind” will be “tx” about 1/16 of the time.

To understand why you do not see the distribution of values that you want, you can use the collect gen
and show gen commands to collect and view the order in which items are generated. The show
generation command brings up the generation debugger so you can view information about how ranges
were reduced by constraints during the generation.

11.1.1.1 Subtype Generation Optimization Constraints


In a subtype generation optimization constraint like the keep gen_before_subtypes(kind) constraint
shown below, you specify a field that has at least one value that is used as a when determinant for
creation of a subtype of the struct. In this case, the when determinant is the tx value of the kind field,
since that is the value that determines when a subtype (that is, a tx packet) will be created.
type kind: [tx, rx];
struct packet {
kind;
offset: uint;
keep gen_before_subtypes(kind);
when tx packet {
len: uint;
keep size > 0 => offset == size - 1;
};
size: byte;
};

A subtype generation optimization constraint may change the order of generation by delaying analysis
of constraints under the when until a when determinant value is actually generated. When no subtype
generation optimization constraint is present, the generator analyzes all of the constraints and fields in

e Language Reference 11-3


Generation Constraints
Unidirectional Constraints

the struct before it generates the struct, even fields and constraints that are defined under subtypes.
When a subtype optimization constraint is present, then the generator initially analyzes and generates
only the base type of the struct. It is not until it encounters a subtype optimization when determinant
field that the generator analyzes the fields and constraints in the associated subtype, and then generates
the subtype.

In the example below, the keep gen (size) before (offset) constraint might be ignored if, due to subtype
optimization, the “offset” field is generated before the “kind” field is generated.
type kind: [tx, rx];
struct packet {
kind;
offset: uint;
keep gen_before_subtypes(kind);
when tx packet {
len: uint;
keep gen (size) before (offset);
};
size: byte;
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Generation Guide

11.1.2 Unidirectional Constraints


Value constraints that induce a generation order are called unidirectional constraints. For example, the
keep constraint shown below requires that the “kind” field be generated first. The test generator cannot
determine the value of the expression “get_size(kind)” without first generating the value of “kind”.
type kind: [tx, rx];
struct packet {
kind;
size: byte;
keep size == get_size(kind);
};

11-4 e Language Reference


Generation Constraints
Unidirectional Constraints

Expressions like “get_size(kind)” are treated like constants within the context of a constraint Boolean
expression. That is, any parameters in these expressions are first generated, the operation is performed
on the generated values, and the returned value can be used to constrain other generatable items in the
constraint Boolean expression. In the example above, the field “size” is constrained by return value of
“get_size(kind)”.

Other expressions that are treated as constants within the context of a constraint Boolean expression are:

list slicing lob[7..15]


bitwise ~ ~sigA
most method calls my_method(), b.as_a(int), value()
multiplication, division, and i.address % 2, 3*b, c/4
modulo operations

The only method calls that are not treated as constants are:

• my_list.size()
• my_list.is_all_iterations()
• my_list.is_a_permutation()
When “my_list” is a generatable list, these expressions are also generatable.

A unidirectional constraint can cause a runtime contradiction error if it selects a value for a parameter
that turns out to conflict with a subsequent constraint. In the example below, the first constraint is
unidirectional for b, c, and d because of the multiplication operator. Thus the generator first selects a
value for b from the range [0..16], then selects a value for c from the range [0..4], and for d from the
range [0..1]. Finally, the generator applies the constraint (a + 3*b + 12*c + 48*d) == 48. Most of the time
this constraint results in a contradiction error because the values for three of the integers are selected
before the constraint defining the required relationship between the integers is applied.
a: uint;
b: uint;
c: uint;
d: uint;

keep a + 3*b + 12*c + 48*d == 48; // Usually results in a contradiction error


keep a <= 48;
keep b <= 16;
keep c <= 4;
keep d <= 1;

In some cases you can rewrite the constraints to avoid the contradiction error. To avoid the contradiction
illustrated above, for example, you need define the generation order so that the integers in the
multiplication expressions (d, c, and b) are generated before a. You also must define each integer based

e Language Reference 11-5


Generation Constraints
Unidirectional Constraints

only on constants and the values of the previously generated integers. Modifying the constraints in this
manner avoids the contradiction error. To change the distribution of values (50% of the time d is 1 and
a, b, and c are all 0), you can either add keep soft select constraints or you can constrain one of the other
integers (a, b, or c) to a constant, and then constrain the others based only on constants and products of
previously generated integers.
d: uint;
keep d <= 1;
c: uint;
keep c <= (48 - 48*d)/12;
b: uint;
keep b <= (48 - 48*d - 12*c)/3;
a: uint;
keep a + 3*b + 12*c + 48*d == 48;

Unidirectional constraints can also cause a constraint cycle, which results in a runtime contradiction
error. A constraint cycle occurs when two or more unidirectional constraints impose conflicting
requirements on the generation order. For example, the first constraint shown below requires that the
“kind” field be generated first. The second constraint, however, requires that the “size” field be
generated first.
type kind: [tx, rx];
struct packet {
kind;
size: byte;
keep size == get_size(kind);
keep kind == get_kind(size); // Constraint cycle
};

Sometimes it is useful to be able to continue a test even if constraint cycles exists. See “Constraint
Cycles” on page 3-4 of the Generation Guide for more information on how to do this.

To identify the source of a constraint contradiction, you can use the collect gen and show gen
commands to collect and view the order in which items are generated. The show gen command brings
up the generation debugger so you can view information about how ranges were reduced by constraints
during generation.

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11-6 e Language Reference


Generation Constraints
Enforceable Expressions

11.1.3 Enforceable Expressions


An enforceable constraint Boolean expression is an expression for which the test generator can choose a
value that satisfies the constraint. Expressions that are not enforceable often involve non-generatable
items or expressions that are treated as constants.

The following expressions are not enforceable:

• An expression that contains no generatable item


• An expression that restricts the legal values of an expression that is treated as a constant

Example 1
For a compound constraint Boolean expression that uses and, both subexpressions must be enforceable.
The expression in this example is not enforceable because “sys.x” is not generatable. A runtime error is
issued.
struct cons {
y: int;
z: int;

keep sys.x > 100 and z < 100; // Not enforceable

};
extend sys {
ci: cons;
x: int;
};

Example 2
For a compound constraint Boolean expression that uses or, only one subexpression has to be
enforceable. In this example, the second expression (z < 100) is enforceable, so no runtime error occurs.
The first expression (sys.x > 100) is ignored because “sys.x” is not generatable.
struct cons {
y: int;
z: int;

keep sys.x > 100 or z < 100;

};
extend sys {
ci: cons;
x: int;

e Language Reference 11-7


Generation Constraints
Enforceable Expressions

};

Example 3
This expression is not enforceable because the test generator first generates “address”, then performs the
modulo operation, and then cannot constrain the resulting value to zero.
i.address % 2 == 0 // Not enforceable

Example 4
This expression is not enforceable because the test generator first generates “y”, then passes “y” to the
value() method, and then cannot constrain the returned value to zero.
value(y) == 0 // Not enforceable

Example 5
This expression is enforceable because the test generator first generates “y”, then passes “y” to the
value() method, and then generates “x”.
value(y) == x

Example 6
This expression is enforceable because the test generator first generates “y”, extracts the least significant
bit of “y”, and then generates “x”.
x == y[0:0]

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11-8 e Language Reference


Generation Constraints
Order of Evaluation of Soft Value Constraints

11.1.4 Order of Evaluation of Soft Value Constraints


Soft value constraints on a data item are considered only at the time the data item is generated, after the
hard value constraints on the data item are applied. Soft constraints are evaluated in reverse order of
definition. If a soft constraint conflicts with the constraints that have already been applied, it is skipped.

Notes
• If a soft constraint does not contradict a hard constraint, it will be applied. If your intent is to override
a soft constraint with a hard constraint, use reset_soft(). See “Example 2” on page 11-9.
• Errors encountered by the generator during evaluation of soft constraints—that is, errors initiated in
a method called by the soft constraint or caused by an attempt to access a NULL path in a soft
constraint—are recoverable. This means that they do not stop the simulation run, regardless of the
severity setting for the error. For DUT errors, the error message is displayed, but the simulation run
continues.

Example 1
keep x in [1..10];
keep soft x > 3;
keep soft x==8;
keep soft x < 6;

The evaluation of the constraints is as follows:

1. The hard constraint is applied, so the range is [1..10].

2. The last soft constraint in the code order, x < 6, is considered. It does not conflict with the current
range, so it is applied. The range is now [1..5].

3. The next to last soft constraint, x == 8, conflicts with the current range, so it is skipped. The range
is still [1..5].

4. The first soft constraint in the code order, x > 3, does not conflict with the current range, so it is
applied. The final range of legal values is [4, 5].

Example 2
The constraint shown below sets the default value for num to the range [1..10].
<'
struct x {
num: uint;

keep soft num in [1..10];


};

e Language Reference 11-9


Generation Constraints
Constraining Struct Instances

'>

In order to override the default and change the range with a hard constraint to [10.20] for a particular
test, you must also reset the soft constraint. Because there is one value (10) in the intersection of the soft
and the hard constraint, both constraints are applied and num will always be 10. The example below
shows how to override the soft constraint with reset_soft().
<'
extend sys {
xlist[10]: list of x;

keep for each (n) in xlist {


n.num.reset_soft();
n.num in [10..20];
};

run() is also {
print sys.xlist;
};
};
'>

See the Generation Guide for complete information on the order of evaluation of soft constraints.

See Also
• keep gen-item.reset_soft() on page 11-37
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.1.5 Constraining Struct Instances


You can constrain two struct instances of the same type to have the same contents. The constraint causes
the two struct instances to refer to the same memory location. As a result, changing one of the struct
instances also changes the other struct instance immediately. For example, in the code below, when
scons1.x is set to 5, the value of scons2.x also becomes 5.
struct scons {

11-10 e Language Reference


Generation Constraints
Constraining Lists

x: uint;
blist: list of byte;
};
extend sys {
scons1: scons;
scons2: scons;
keep scons2 == scons1;

run() is also {
scons1.x = 5;
};
};

11.1.6 Constraining Lists


There are several ways that you can constrain a list or its elements. See the following sections for more
information:

• “Constraining List Size” on page 11-11


• “Constraining a List Item” on page 11-12
• “Constraining One List to Another List” on page 11-14
• “Constraining Multiple List Items” on page 11-14
• “Constraining a List of Structs” on page 11-15
• “Constraining Multiple Lists” on page 11-15

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.1.6.1 Constraining List Size


You can constrain the list size of a field either by using a size expression in a field declaration or by
using a keep constraint. The following statements both constrain the number of elements in the “pacs”
list to 10:

e Language Reference 11-11


Generation Constraints
Constraining Lists

pacs[10]: list of pac;


keep pacs.size() == 10;

The key difference between these two methods is that the keep constraint affects only generation,
whereas the field declaration also initializes the list automatically. Note, however, that if you use the
field declaration approach and the size expression cannot be evaluated when init() is called, you will see
an error. For example, if the size expression is struct-field.field and struct-field is NULL when init() is
called, you get an error.

If you unpack data into a field declared as a list, it is better to use the size expression in a field
declaration. That way, the list’s size is always exactly as specified. See “Packing and Unpacking Lists” on
page 18-9 for more information.

To constrain the list size of a variable, you must use the keep constraint. A size expression in a variable
declaration is not allowed.

If there are no explicit constraints on the size of a list, the generated list will have a size between zero
and the value of the configuration variable, default_max_list_size. This variable is set initially to 50.

11.1.6.2 Constraining a List Item


You can constrain an individual item in a list of scalar items using the keep constraint as follows.
keep me.data[0] == 0x9a;

You can constrain an individual item in a list of structs using the keep constraint as follows.
keep dstructs[0].data == 0xff;
Note Neither multiple list indexing nor index expressions may be used in constraints. For example,
top[0].dstruct[0].data is not legal, and dstruct[n+1].data is not legal.

You can propagate values in both directions with a constraint like the following:
keep x == l[i].z

Such constraints are bidirectional, meaning that value can propagate from the list item to x and vise
versa (from x to the list item). These constraints are equivalent to keep for each constraints. For
example, the above constraint is equivalent to:
keep for each in l { index == i => x == it.z};

The bind() attribute for ports is equivalent to constraints of this type. For example, the final line of code
in the following example propagates (binds) the “llp” inputs to the “alp” outputs:
unit left_hand {
llp: list of in simple_port of bit is instance;
keep llp.size() == 10;
};

11-12 e Language Reference


Generation Constraints
Constraining Lists

extend sys {
alp: list of out simple_port of bit is instance;
keep alp.size() == 10;

left_hand is instance;

keep for each in alp {


bind(it,left_hand.llp[i]);
};
};

Backwards Compatibility for List Item Constraints


Prior to Specman version 4.2, constraints of the form:
keep x == l[i].z;

Were treated as unidirectional constraints, rather than bidirectional constraints, which meant that the
value could propagate from l[i].z to x only. If you are migrating from a pre-4.2 version of Specman to
4.2 or later and require that such constraints continue to be treated as unidirectional, you have the
following options:

• Set the list_constraint_is_bidir configuration option to FALSE, as described in configure gen on


page 6-17 in the Specman Command Reference.

• Edit the constraints in your existing code to use value().


For example, you could convert the following constraint:
keep keep x == l[i].z;
// was unidirectional before 4.2, now
// bidirectional by default
To use value() to ensure that the constraint remains unidirectional:
keep x == value(l[i].z);
// is unidirectional regardless of the value
// of the list_constraint_is_bidir option

• Change the value of the list_constraint_is_bidir configuration option before loading modules with
legacy code.
The list_constraint_is_bidir option is effective only during parsing, and thus must be set to the
appropriate value before loading. If your design includes some modules with new code that require
a value of TRUE and some modules with old code that require a value of FALSE, you can change
the value appropriately before each module is loaded into Specman. Note that doing so triggers a
warning from Specman, intended to ensure that you realize what you are doing.

e Language Reference 11-13


Generation Constraints
Constraining Lists

11.1.6.3 Constraining a List To Keep a Specific Item


You can constrain a list to keep a specific item in the list. For example:
<'
extend sys {
x: uint;
keep x == 5;
lu: list of uint;
keep x in lu;
};
'>

This constraint is bidirectional, meaning that it does not imply a generation order for the item and list.
However, the item is always at the last place in the list, regardless of which is generated first, the item or
the list).

In this example, x is generated before lu and therefore the last item in lu is 5.

Therefore, the following code results in a contradiction:


<'
extend sys {
x: uint;
y: uint;
lu: list of uint;
keep x in lu; // last item in lu is x
keep y in lu; // last item in lu is y
keep x != y;
};
'>

11.1.6.4 Constraining One List to Another List


You can constrain one list to contain the same items as another list, using the keep constraint.
data1: list of byte;
data2: list of byte;
keep data2 == data1;

This results in two references to two separate lists which initially contain the same values. Changing one
of the lists does not affect the other list unless one list is assigned to the other, which results in the
references to the two lists pointing to the same memory location.

11.1.6.5 Constraining Multiple List Items


You can constrain multiple items in a list, using the keep for each constraint.

11-14 e Language Reference


Generation Constraints
Constraining Bit Slices

keep for each in pacs {


index == 0 => it.kind == control;
};

11.1.6.6 Constraining a List of Structs


You can constrain a list of structs to have all legal values of one or more fields, using
the .is_all_iterations() method.
keep pacs.is_all_iterations(.kind);

11.1.6.7 Constraining Multiple Lists


You can constrain a list to be a subset of another list, using the in construct. In this example, all the
elements in the “pacs_sub” list are contained in the “pacs” list, but not necessarily in the same order. The
“pacs” list can have elements that are not in “pacs_sub”.
pacs_sub[10]: list of pac;
keep pacs_sub in pacs;

You can constrain a list to have the same elements as another list using the is_a_permutation()
pseudo-method. In this example, the “pacs_dup” list and the “pacs” list have exactly the same elements,
but not necessarily in the same order.
pacs_dup[10]: list of pac;
keep pacs_dup.is_a_permutation(pacs);

11.1.7 Constraining Bit Slices


You can use the bit slice operator in constraints to achieve a variety of purposes. A simple example is
using the bit slice operator to constrain the fields of a CPU instruction:
struct cpu_env {
instr: uint (bits: 16);

keep instr[15:13] == 0b100;


keep instr[12:8] == 0b11001;
keep instr[7:0] == 0b00001111;
};

Another simple but useful application of the bit slice constraint is to generate a list of even integers:
struct cpu_env {
lint: list of int;

keep for each in lint {

e Language Reference 11-15


Generation Constraints
Constraining Bit Slices

it[0:0] == 0;
};
};
Note Using “it%2 == 0” to generate a list of even integers does not work. Since the “%” operator makes
the constraint unidirectional, “it” is generated before the constraint is checked, and a contradiction occurs
about 50% of the time.

You can also use a bit constraint to constrain particular bits in relation to each other. For example, the
following constraint ensures that only one of the lower four bits of “x” is 1:
keep x[3:0] in [1,2,4,8];

You can use non-constant bit indices in bit slice constraints, as in the following example, which
generates a 4-bit integer with 1s in two consecutive bits:
i: int [0..3];
j: int [0..3];
l: int (bits: 4);

keep j - i == 1;
keep l[j:i] == 0b11;

See Also
• “Bit Slice Constraints and Generation Order” on page 11-16
• “Bit Slice Constraints and Signed Entities” on page 11-17
• “Bit Slice Constraints and Soft Constraints” on page 11-18
• “Limitations of Bit Slice Constraints” on page 11-19
• “Debugging Bit Slice Constraints” on page 11-19

11.1.7.1 Bit Slice Constraints and Generation Order


A generatable item can contain a bit slice reference; however, there are implications for generation
order:

Non-constant Bit Indices


Non-constant bit indices must be generated before other entities in the constraint. You cannot override
this order.

For example, the following constraint


keep x[j:i] == y;

11-16 e Language Reference


Generation Constraints
Constraining Bit Slices

implies
keep gen (j, i) before (x, y);
Note A further implication is that constraints like the following, where the bit indices are non-constant
and the other items are constant, cannot be solved.
keep 125[j:i] == 0b101;

Generation of Bit Sliced Items


By default, bit sliced items are generated after other items in the same constraint. You can override this
default with a keep gen constraint.

For example, the following constraint


keep x[j:i] == y;

implies
keep soft gen (y) before (x);

There can be cases where you need to override this default generation order with a keep gen constraint.
For example, to meet the following constraints, “x” must be generated before “y”:
keep y == x[1:0];
keep x in [1,2,5,6];

In order to make this happen, you can add the constraint:


keep gen (x) before (y);

or you can add the value() routine to the existing constraint:


keep y == value(x[1:0])

11.1.7.2 Bit Slice Constraints and Signed Entities


Bit slices in e are treated as unsigned. It is possible, however, to constrain the value of a bit slice (or any
unsigned entity) relative to a signed entity. In the example below, a bit slice of “x” is constrained by a
signed entity, “y”:
x: int;
y: int (bits:5);
keep x[4:0] == y;

There are several implications of constraints that relate a bit slice to a signed entity:

e Language Reference 11-17


Generation Constraints
Constraining Bit Slices

• The value of the bit slice is treated as an unsigned integer; in other words, none of the bits in the slice
is treated as a sign bit. In the example above, although “x” can be a negative number, x[4:0] is treated
as a positive value.
• The value of the signed entity is generated as a non-negative. In the example above, “y” will always
be generated as a non-negative integer.
• The value of both the bit slice and the signed entity must fit into the smaller of
• The bit width of the bit slice
• The bit width of the highest possible value of the signed entity (This width excludes one bit used
to store the sign.)

Example
Given the following integers, “x” and “y”,
x: int;
y: int (bits:5);

any one of the following constraints requires the value of “y” to be a non-negative number no larger than
four bits (the bit width of “y”, minus one bit to store the sign). In other words, the value of both “y” and
the specified bit slice of “x” is generated in the range [0..15]. Any upper bits of the bit slice not required
to store the value are set to 0:
keep x[7:0] == y; // x[7:4] is 0
keep x[4:0] == y; // x[4] is 0
keep x[3:0] == y;

By contrast, the value of “y” in the following constraint must fit into only three bits (the bit width of the
bit slice), so “y” and “x[2:0]” are generated in the range [0..7]:
keep x[2:0] == y;

11.1.7.3 Bit Slice Constraints and Soft Constraints


A hard constraint on a bit slice of a variable always overrides a soft constraint on that variable. For
example, the intention of the following constraints is to make all the bits of a scalar be zero by default,
then set individual bits with bit slice constraints:
keep soft x == 0;
keep x[7:7] == 1; // Doesn't have desired effect

These constraints will not have the desired effect as the soft constraint will always be overridden. The
only way to achieve this purpose is to apply the soft constraint to each individual bit explicitly:
keep soft x[0:0] == 0;

11-18 e Language Reference


Generation Constraints
Defining Constraints

...
keep soft x[31:31] == 0;
keep x[7:7] == 1;

11.1.7.4 Limitations of Bit Slice Constraints


If a bit slice is a function of another bit slice of the same field or variable, in many cases a contradiction
occurs.

In the following example, “x” is an argument to the “bit_parity()” function and must be generated before
the function is called:
keep x[8:8] == bit_parity(x[7:0]); // Usually a contradiction error

The result of the function call is then compared to “x[8:8]” and will fail in 50% of the cases.

The workaround is to assign a new virtual field for “x[7:0]”.


y: uint (bits:8);
keep y == x[7:0];
keep x[8:8] == bit_parity(y);

These constraints cause Specman to generate “y” first, constrain “x[7:0]” to have the value of “y” and
constrain “x[8:8]” to have the return value from the bit_parity() method.

11.1.7.5 Debugging Bit Slice Constraints


For bit slice constraints, the collect gen command displays the item’s range list (enclosed in square
brackets) together with the item’s bit value representation (enclosed in angle brackets) as shown below:
[range-list]: <bit-value-representation>

The bit value representation has a single character, either 0, 1, or X, that represents each bit. The
characters 0 and 1 indicate that a particular bit must be a 0 or a 1, respectively. The character X indicates
that a bit can be either 0 or 1.

For example, the following display describes an 8-bit odd integer within the range 10 to 20 or 50 to 60:
[11..19, 51..59] : <00XXXXX1>

11.2 Defining Constraints


For information on the constructs used to define constraints, see:

• keep on page 11-20


• keep all of {…} on page 11-23

e Language Reference 11-19


Generation Constraints
keep

• keep struct-list.is_all_iterations() on page 11-25


• keep for each on page 11-27
• keep soft on page 11-30
• keep soft… select on page 11-32
• keep gen-item.reset_soft() on page 11-37
• keep gen… before on page 11-38
• keep soft gen … before on page 11-40
• keep gen_before_subtypes() on page 11-42
• keep reset_gen_before_subtypes() on page 11-46
• value() on page 11-47
• constraint-bool-exp on page 11-50
• gen-item on page 11-53
In addition, see the following for helpful information:

• “Constraining Lists” on page 11-11


• “Constraining Bit Slices” on page 11-15
• “Comparison Operators” on page 2-54

11.2.1 keep

Purpose
Define a hard value constraint

Category
Struct member

Syntax
keep constraint-bool-exp

11-20 e Language Reference


Generation Constraints
keep

Syntax Example
keep kind != tx or len == 16;

Parameters

constraint-bool-exp A simple or a compound Boolean expression. See constraint-bool-exp on


page 11-50 for a full description of this parameter.

Description
States restrictions on the values generated for fields in the struct or the struct subtree, or describes
required relationships between field values and other items in the struct or its subtree.

Hard constraints are applied whenever the enclosing struct is generated. For any keep constraint in a
generated struct, the generator either meets the constraint or issues a constraint contradiction message.

Note
If the keep constraint appears under a when construct, the constraint is considered only if the when
condition is true.

Example 1
This example describes a required relationship between two fields, “kind” and “len”. If the current “pkt”
is of kind “tx”, then “len” must be 16.
struct pkt {
kind: [tx, rx];
len: uint;
keep kind == tx => len == 16;
};

Specman translates this constraint internally into an or constraint:


keep kind != tx or len == 16;

Example 2
This example shows a required relationship between two fields, “kind” and “len”, using a local variable,
“p”, to represent “pckt” instances of kind “tx”:
struct pckt {
kind: [tx, rx];

e Language Reference 11-21


Generation Constraints
keep

len: uint;
};
struct top {
packet: pckt;
keep packet is a tx pckt (p) => p.len in [128..255];
};

Example 3
This example shows another way to describe the required relationship between the two fields, “kind”
and “len”. Specman also translates this constraint into an or constraint:
struct pkt {
kind: [tx, rx];
len: uint;
when tx pkt {
keep len == 16;
};
};

Example 4
This example shows how to call the list.is_a_permutation() method to constrain a list to have a random
permutation of items from another list. In this example, “l_1” and “l_2” will have exactly the same
elements. The elements will not necessarily appear in the same order.
struct astr {
l_1: list of int;
l_2: list of int;
keep l_2.is_a_permutation(l_1);
};

Example 5
This example shows a constraint on a single list item (“data[0]”) and the use of path names to identify
the item to be constrained.
type transaction_kind: [good, bad];
struct transaction {
kind: transaction_kind;
address: uint;
length: uint;
data: list of byte;
};

11-22 e Language Reference


Generation Constraints
keep all of {…}

extend transaction {
keep length < 24;
keep data[0] == 0x9a;
keep address in [0x100..0x200];
keep me.kind == good;
};

extend sys {
t: transaction;
keep me.t.length != 0;
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.2.2 keep all of {…}

Purpose
Define a constraint block

Category
Struct member

Syntax
keep all of {constraint-bool-exp; …}

Syntax Example
keep all of {
kind != tx;
len == 16;
};

e Language Reference 11-23


Generation Constraints
keep all of {…}

Parameters

constraint-bool-exp A simple or a compound Boolean expression. See constraint-bool-exp on


page 11-50 for a full description of this parameter.

Description
A keep constraint block is exactly equivalent to a keep constraint for each constraint Boolean
expression in the block. For example, the following constraint block
keep all of {
kind != tx;
len == 16;
};

is exactly equivalent to
keep kind != tx;
keep len == 16;

The all of block can be used as a constraint Boolean expression itself, as is shown in “Example 1” on
page 11-24.

Example 1
type transaction_kind: [VERSION1, VERSION2, VERSION3];
struct transaction {
kind: transaction_kind;
address: uint;
length: uint;
data: list of byte;

keep kind in [VERSION1, VERSION2] => all of {


length < 24;
data[0] == 0x9a;
address in [0x100..0x200];
};
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55

11-24 e Language Reference


Generation Constraints
keep struct-list.is_all_iterations()

• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.2.3 keep struct-list.is_all_iterations()

Purpose
Cause a list of structs to have all iterations of a field

Category
Constraint-specific list method

Syntax
keep gen-item.is_all_iterations(.field-name: exp, …)

Syntax Example
keep packets.is_all_iterations(.kind,.protocol);

Parameters

gen-item A generatable item of type list of struct. See gen-item on page 11-53 for more
information.

field-name The name of a scalar field of a struct. The field name must be prefixed by a period.
The order of fields in this list does not affect the order in which they are iterated.
The specified field that is defined first in the struct is the one that is iterated first.

Description
Causes a list of structs to have all legal, non-contradicting iterations of the fields specified in the field
list. Fields not included in the field list are not iterated; their values can be constrained by other relevant
constraints. The highest value always occupies the last element in the list.

Soft constraints on fields specified in the field list are skipped. For example, given the following
constraints, packet_list will have all legal iterations of the length field, not just iterations within 10 and
100:
keep soft len in [10..100];
keep packet_list.is_all_iterations(.len)

e Language Reference 11-25


Generation Constraints
keep struct-list.is_all_iterations()

All other relevant hard constraints on the list and on the struct are applied. If these constraints reduce the
ranges of some of the fields in the field list, then the generated list is also reduced.

Memory Usage and Performance Considerations


The number of iterations in a list produced by list.is_all_iterations() is the product of the number of
possible values in each field in the list. For example, if you list all iterations of a struct with the
following fields:
i: int [0..4] // 5 possible values
j: int [0..3, 5..7] // 7 possible values
k: int (bits: 8) // 256 possible values

The number of iterations for the list is:


5 * 7 * 256 = 8960

The absolute_max_list_size generation configuration option sets the maximum number of iterations
allowed in a list. The default is 524,288. If the number of iterations in your list exceeds this number, you
can set absolute_max_list_size to a larger number with the config gen command.

Notes
• The list.is_all_iterations() method can only be used in a constraint Boolean expression.
• The fields to be iterated must be of a scalar type, not a list or struct type.

Example
The “sys.packets” list will have six elements (2 “kinds” * 3 “protocols”). The “len” field is not iterated
on; it will get any value from its legal range for each of the list items.
type p_kind: [tx, rx];
type p_protocol: [atm, eth, other];
struct packet {
kind: p_kind;
protocol: p_protocol;
len: int [0..4k];
};
extend sys {
packets: list of packet;
keep packets.is_all_iterations(.kind,.protocol);
};

11-26 e Language Reference


Generation Constraints
keep for each

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.2.4 keep for each

Purpose
Constrain list items

Category
Struct member

Syntax
keep for each [(item-name)] [using [index (index-name)] [prev (prev-name)]] in
gen-item {constraint-bool-exp | nested-for-each; …}

Syntax Example
keep for each (p) in pkl {
soft p.protocol in [atm, eth];
};

Parameters

item-name An optional name used as a local variable referring to the current item in
the list. The default is it.

index-name An optional name referring to index of the current item in the list. The
default is index.

prev-name An optional name referring to the previous item in the list. The default is
prev.

e Language Reference 11-27


Generation Constraints
keep for each

gen-item A generatable item of type list. See gen-item on page 11-53 for more
information.

constraint-bool-exp A simple or a compound Boolean expression. See constraint-bool-exp on


page 11-50 for a full description of this parameter.

nested-for-each A nested for each block, with the same syntax as the enclosing for each
block, except that “keep” is omitted.

Description
Defines a value constraint on multiple list items.

Notes
• You must refer to the items you want to generate using a path name that starts either with it, such as
“it.pk” or with the name that you assigned to the list item (item-name). Items whose pathname does
not start with it can only be sampled; their generated values cannot be constrained.
• Within a for each constraint, prev and index are predefined constants and cannot be constrained or
generated.
• Items in lists are generated in ascending order starting with index zero. Constraints that use an index
expression to refer to other items in a list can only refer to items with lower index values.
• Referencing prev while in the first item of the list causes an error.
• You can nest for each constraints.
• If a for each constraint is contained in a gen … keeping action, you must name the iterated variable.
See “Example 3” on page 11-58 for more information.

Example 1
In this example, the “keep for each in dat” constraint in the “pstr” struct constrains all the “dat” fields
to be less than 64. Note that referring to the list items in the Boolean expression “it < 64” as “dat[index]”
rather than “it” generates an error.
struct pstr {
dat: list of uint;
keep for each in dat {
it < 64;
};
};

11-28 e Language Reference


Generation Constraints
keep for each

Example 2
The following example uses an item name “p” and an index name “pi” to constrain the generation of
values for the variable “indx”:
struct packet {
indx: uint;
};
extend sys {
packets: list of packet;
keep for each (p) using index (pi) in packets {
p.indx == pi;
};
};

Example 3
The following example shows the use of index in a nested for each block. The “x” field receives the
value of the outer index and each byte of “payload” receives the value of the inner index.
struct packet {
x: int;
%payload: list of byte;
keep payload.size() == 10;
};
extend sys {
packets: list of packet;
keep packets.size() == 5;
keep for each (p) in packets {
p.x == index;
for each in p.payload {
it == index;
};
};
post_generate() is also {
for i from 0 to 4 {
print packets[i].x;
print packets[i].payload;
};
};
};

Results
Generating the test using seed 1...
packets[i].x = 0

e Language Reference 11-29


Generation Constraints
keep soft

packets[i].payload = (10 items, dec):


9 8 7 6 5 4 3 2 1 0 .0

packets[i].x = 1
packets[i].payload = (10 items, dec):
9 8 7 6 5 4 3 2 1 0 .0

packets[i].x = 2
packets[i].payload = (10 items, dec):
9 8 7 6 5 4 3 2 1 0 .0

packets[i].x = 3
packets[i].payload = (10 items, dec):
9 8 7 6 5 4 3 2 1 0 .0

packets[i].x = 4
packets[i].payload = (10 items, dec):
9 8 7 6 5 4 3 2 1 0 .0

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.2.5 keep soft

Purpose
Define a soft value constraint

Category
Struct member

Syntax
keep soft constraint-bool-exp

11-30 e Language Reference


Generation Constraints
keep soft

Syntax Example
keep soft legal == TRUE;

Parameters

constraint-bool-exp A simple Boolean expression. See constraint-bool-exp on page 11-50 for


a full description of this parameter.

Description
Suggests default values for fields or variables in the struct or the struct subtree, or describes suggested
relationships between field values and other items in the struct or its subtree.

Soft constraints are order dependent and will not be met if they conflict with hard constraints or soft
constraints that have already been applied. See “Order of Evaluation of Soft Value Constraints” on page
11-9 for more information on this topic.

Note
The soft keyword can be used in simple Boolean expressions, but not in compound Boolean
expressions. Thus the first constraint below is valid, but the second generates a compile-time error:
keep x > 0 => soft y < 0;
keep soft x > 0 => y < 0; // Compile-time error

Example 1
Because soft constraints only suggest default values, it is better not to use them to define architectural
constraints, such as “keep opcode in [ADD, SUB, AND, XOR, RET, NOP]”. If you want to be able to
explicitly override the architectural constraints in order to generate illegal instructions for a particular
test, then you can define a Boolean field for legal instructions and place a soft constraint on that:
struct instr {
%opcode: cpu_opcode;
legal: bool;
keep soft legal == TRUE;
keep legal => opcode in [ADD, SUB, AND, XOR, RET, NOP];
};

Example 2
Individual constraints inside a constraint block can be soft constraints.

e Language Reference 11-31


Generation Constraints
keep soft… select

extend sys {
packets: list of packet;
keep for each in me.packets {
soft .len == 2k;
.kind != tx;
};
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.2.6 keep soft… select

Purpose
Constrain distribution of values

Category
Struct member

Syntax
keep soft gen-item==select {weight: value; …}

Syntax Example
keep soft me.opcode == select {
30: ADD;
20: ADDI;
10: [SUB, SUBI];
};

11-32 e Language Reference


Generation Constraints
keep soft… select

Parameters

gen-item A generatable item. See gen-item on page 11-53 for a full description of
this parameter.

weight Any uint expression. Weights are proportions; they do not have to add up
to 100. A relatively higher weight indicates a greater probability that the
value is chosen.

value is one of the following:

range-list A range list such as [2..7]. A select expression with a range list selects the
portion of the current range that intersects with the specified range list.

exp A constant expression. A select expression with a constant expression


(usually a single number) selects that number, if it is part of the current
range.

others Selects the portions of the current range that do not intersect with other
select expressions in this constraint.

Using a weight of 0 for others causes the constraint to be ignored. That is,
the effect is the same as if the others option were not entered at all.

pass Ignores this constraint and keeps the current range as is.

edges Selects the values at the extreme ends of the current range(s).

min Selects the minimum value of the gen-item.

max Selects the maximum value of the gen-item.

Description
Specifies the relative probability that a particular value or set of values is chosen from the current range
of legal values. The current range is the range of values as reduced by hard constraints and by soft
constraints that have already been applied.

A weighted value will be assigned with the probability of

• weight/(sum of all weights)


Weights are treated as integers. If you use an expression for a weight, take care to avoid a situation
where the value of the expression is larger than the maximum integer size (MAX_INT).

e Language Reference 11-33


Generation Constraints
keep soft… select

Like other soft constraints, keep soft select is order dependent and will not be met if it conflicts with
hard constraints or soft constraints that have already been applied. See “Order of Evaluation of Soft Value
Constraints” on page 11-9 for more information on this topic.

Example 1
The following soft select constraint specifies that there is a 3/6 probability that ADD is selected from the
current range, a 2/6 probability for ADDI, and a 1/6 probability that either SUB or SUBI is selected.
struct instr {
%opcode: cpu_opcode;
keep soft me.opcode == select {
30: ADD;
20: ADDI;
10: [SUB, SUBI];
};
};

Example 2
In the following example, “address” is generated in the range [0..49] 10% of the time, as exactly [50]
60% of the time, and in range [51..99] 30% of the time, assuming that the current range includes all these
values.
struct transaction {
address: uint;
keep soft address == select {
10: [0..49];
60: 50;
30: [51..99];
};
};

Example 3
This particular test uses the distribution described in the original definition of “transaction” only 10% of
the time and uses the range [200..299] 90% of the time.
extend transaction {
keep soft address == select {
10: pass;
90: [200..299];
};
};

11-34 e Language Reference


Generation Constraints
keep soft… select

The final distribution is 90% [200..299], 1% [0..49], 6% [50], 3% [51..99].

Example 4
This extension to “transaction” sets the current range with a hard constraint. 50% of the time the extreme
edges of the range are selected (0, 50, 100, and 150). 50% of the time other values in the range are
chosen.
extend transaction {
keep address in [0..50,100..150];
keep soft address == select {
50: edges;
50: others;
};
};

Example 5
This extension to “transaction” sets the current range with a hard constraint. About 10% of the values are
to be 10 and about 30% of the values are to be 50. The remaining 60% of the values are to be distributed
between 10 and 50.
extend transaction {
keep address in [10..50];
keep soft address == select {
10: min;
60: others;
30: max;
};
};

Example 6
This example shows how to weight the values of generated elements of a list. The it variable is used to
represent a list element in the keep for each construct. The values A, B, and C are given equal weights
of 20, and all other possible values (D through L) are given a collective weight of 40. About 20% of the
generated list elements will be A, 20% will be B, 20% will be C, and the remaining 40% will get random
values in the range D through L.
<'
type alpha: [A, B, C, D, E, F, G, H, I, J, K, L];
struct top {
my_list[50]: list of alpha;

e Language Reference 11-35


Generation Constraints
keep soft… select

keep for each in my_list {


soft it == select {
20: A;
20: B;
20: C;
40: others;
};
};
};

extend sys {
top;
};
'>

Example 7
This example shows how a runtime value from the simulation can be used to weight the selection of a
value. In this case, the generation of the JMPC opcode is controlled by the value of the 'top.carry' signal.
extend instr {
keep soft opcode == select {
40: [ADD, ADDI, SUB, SUBI];
20: [AND, ANDI, XOR, XORI];
10: [JMP, CALL, RET, NOP];
'top.carry' * 90: JMPC;
};
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11-36 e Language Reference


Generation Constraints
keep gen-item.reset_soft()

11.2.7 keep gen-item.reset_soft()

Purpose
Quit evaluation of soft constraints for a field

Category
Struct member

Syntax
keep gen-item.reset_soft()

Syntax Example
keep c.reset_soft();

Parameters

gen-item A generatable item. See gen-item on page 11-53 for a full description of this
parameter.

Description
Causes Specman to quit the evaluation of soft value constraints for the specified field. Specman
continues to evaluate soft constraints for other fields.

Example 1
It is important to remember that soft constraints are considered in reverse order to the order in which
they are defined in the e code. If the following constraints are defined in the order shown, then Specman
applies the “keep soft c > 5 and c < 10” constraint (the last one defined) and then quits the evaluation of
soft value constraints for “c” when it encounters the “keep c.reset_soft()” constraint. It never considers
the “keep soft c < 3” constraint. It does evaluate the “keep soft d< 3” constraint:
struct adder {
c: uint;
d: uint;
keep soft c < 3; // Is never considered
keep soft d < 3; // Is considered
};

e Language Reference 11-37


Generation Constraints
keep gen… before

extend adder {
keep c.reset_soft();
};

extend adder {
keep soft c > 5 and c < 10;
};

Example 2
This example shows the use of reset_soft() in the situation where a soft constraint is written with the
intent that it will be ignored if other constraints are added in an extension. Normally, “address” should
be less than 64. The test writer needs to do nothing additional to get this behavior.

In a few tests, “address” should be any value less than 128. The test writer needs to remove the effect of
the soft constraint so that it does not reduce the range [0..128] to [0..64].
struct transaction {
address: uint;
keep soft address < 64;
};
extend transaction {
keep address.reset_soft();
keep address < 128;
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.2.8 keep gen… before

Purpose
Modify the generation order

11-38 e Language Reference


Generation Constraints
keep gen… before

Category
Struct member

Syntax
keep gen (gen-item: exp, …) before (gen-item: exp, …)

Syntax Example
keep gen (y) before (x);

Parameters

gen-item,… An expression that returns a generatable item. The parentheses are required. See
gen-item on page 11-53 for more information.

Description
Requires the generatable items specified in the first list to be generated before the items specified in the
second list. You can use this constraint to influence the distribution of values by preventing soft value
constraints from being consistently skipped. Before using this constraint for this purpose, read “Basic
Concepts of Generation” on page 11-2 to be sure that you understand how soft constraints are evaluated.

Notes
• This constraint itself can cause constraint cycles. If a constraint cycle involving one of the fields in
the keep gen … before constraint exists and if the resolve_cycles generation configuration option
is TRUE, the constraint can be ignored if Specman cannot satisfy both it and other constraints that
conflict with it.
• This constraint cannot appear on the left-hand side of an implication operator (=>).

Example
In the following example, the constraint requires the test generator to generate values for “length” and
“data” before generating “crc”.
struct packet {
good: bool;
length: byte [1..24];
data [length]: list of byte;
crc: uint;
keep good => crc == crc_calc();

e Language Reference 11-39


Generation Constraints
keep soft gen … before

keep gen (length, data) before (crc);

crc_calc() : uint is {
result = pack(packing.low,length,data).crc_32(0,length);
};
};

extend sys {
p: list of packet;
run() is also {
print sys.p.crc;
};
};

extend packet {
keep good == TRUE; // just to show interesting case
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.2.9 keep soft gen … before

Purpose
Suggest order of generation

Category
Struct member

Syntax
keep soft gen (gen-item: exp, …) before (gen-item: exp, …)

11-40 e Language Reference


Generation Constraints
keep soft gen … before

Syntax Example
keep soft gen (y) before (x);

Parameters

gen-item, … An expression that returns a generatable item. See gen-item on page 11-53 for
more information.

Description
Modifies the “soft” generation order by recommending that the fields specified in the first field list to be
generated before the fields specified in the second field list. This soft generation order is second in
priority to the hard generation order created by dependencies between parameters and keep gen before
constraints.

You can use this constraint to suggest a generation order that you can later override for particular
purposes in individual tests with a hard order constraint.

Note
This constraint cannot appear on the left-hand side of a implication operator (=>).

Example
This example shows how you can use a soft order constraint to get the distribution of values you want.
In the example below, there is a hard value constraint on “length” and “address”.
struct transaction {
address: uint;
};

extend transaction {
length: uint [1..10];
keep length == 5 => address < 50;
};

However, because “address” is generated first (based on coding order), “length” is generated to 5 only a
small percentage of the time (50 out of MAX_UINT). If you want 5 to be as likely as any other value,
the default ordering must be changed with a soft order constraint.
extend transaction {
keep soft gen (length) before (address);
};

e Language Reference 11-41


Generation Constraints
keep gen_before_subtypes()

Since the order constraint is soft, it can be overridden by a hard constraint, such as one that uses a
method. The following hard value constraint requires “address” to be generated before “length”,
overriding the soft generation order suggested by the previous extension to “transaction”.
extend transaction {
keep length == value(address);
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.2.10 keep gen_before_subtypes()

Purpose
Specify a when determinant field for deferred generation

Category
Struct member

Syntax
keep gen_before_subtypes(determinant-field: field, …)

Syntax Example
keep gen_before_subtypes(format);

11-42 e Language Reference


Generation Constraints
keep gen_before_subtypes()

Parameters

determinant-field An expression that evaluates to the name of a field in the struct type. The field
must be one that has at least one value that is used as a when determinant for a
subtype definition. If the field is not a when determinant field, a warning is
issued and the constraint is ignored.
Multiple field expressions can be entered, separated by commas.

Description
To speed up generation of structs with multiple when subtypes, this type of constraint, called a subtype
optimization constraint, causes the generator engine to wait until a when determinant value is generated
for a specified field before it analyzes constraints and generates fields under the when subtype.

When no subtype optimization constraints are present in a struct, the generator analyzes all of the
constraints and fields in the struct before it generates the struct, even those constraints and fields that are
defined under when subtypes. When a subtype optimization constraint is present, the generator initially
analyzes only the constraints and fields of the base struct type. Only when a subtype optimization when
determinant is encountered does the generator analyze the associated when subtype and then generate it.

Notes
• Subtype optimization can handle multiple determinants. Subtypes are analyzed and generated in the
order in which their when determinants are encountered.
• If multiple determinants are specified, and some of them are subtype optimization determinants while
others are not, then a subtype that is a result of multiple inheritance of a subtype optimization
determinant and a non-subtype optimization determinant will be treated the same as a other subtype
optimization determinant subtype.
• The generator engine’s ability to resolve contradictions is diminished somewhat by subtype
optimization constraints. Specifically, the generator might not be able to resolve contradictions arising
from constraints under subtypes that involve fields of the base type.
• The analysis and generation is recursive. If a subtype contains another determinant that is specified
in a subtype optimization constraint, then that sub-subtype is analyzed and generated as soon as its
determinant field is generated under the higher-level subtype.

Example 1
This example shows a subtype optimization constraint on the field named format in the instr_s struct.
The generator defers analysis and generation of constraints and fields under the FMT_A and FMT_B
subtypes, since those are when determinants.

e Language Reference 11-43


Generation Constraints
keep gen_before_subtypes()

type format_t: [FMT_A, FMT_B, FMT_C];


struct instr_s {
intrpt: bool;
format: format_t;
keep gen_before_subtypes(format);
keep format == FMT_A => intrpt != FALSE;

when FMT_A'format instr_s {


a_intrp: bool;
keep intrpt != a_intrp;
keep gen (size) before (offset);
keep offset == 0x10;
};

when FMT_B'format instr_s {


b_intrp: bool;
keep intrpt == TRUE;
};

offset: int;
size: int;
};

The generation order for the example above is:

1. All constraints in the base struct concerning intrpt and format are analyzed.

2. A value is generated for intrpt.

3. A value is generated for format.

4. When format is FMT_A,

• All constraints under subtype FMT_A are analyzed.


• A value is generated for a_intrp.
5. A value is generated for size.

6. A value is generated for offset.

Notes
• The gen...before constraint in the FMT_A subtype can be satisfied because neither offset nor size
has been generated when that constraint is encountered.
• The constraint between intrpt and a_intrp can be satisfied even though it is unidirectional, because
intrpt is generated before a_intrp.

11-44 e Language Reference


Generation Constraints
keep gen_before_subtypes()

• If the gen...before constraint under FMT_A was between intrpt and offset, for example, then it would
be ignored because intrpt is generated before any subtypes are analyzed (unless an explicit order
constraint was added between the format determinant and intrpt).

Example 2
In the following example, the keep op != SUB constraint under the FMT_A subtype might cause a
contradiction, since it involves a field in the base struct. This is because the generator initially generates
the base struct (the op and format fields) before it analyzes the constraints in the subtype. There are no
constraints involving op and format in the base struct, so the generator is free to choose FMT_A and
SUB for those fields. However, once the format determinant is fixed, the generator analyzes the FMT_A
subtype, and finds that op is not allowed to be SUB. This results in a contradiction.
type format_t: [FMT_A, FMT_B, FMT_C];
type opcode_t: [ADD, SUB, MUL, DIV];
struct instr_s {
op: opcode_t;
format: format_t;
keep gen_before_subtypes(format);

when FMT_A'format instr_s {


a_intrp: bool;
keep op != SUB; // Might cause a contradiction
};
};

To avoid the possibility of a contradiction described above, you can elevate the constraint from the
subtype to the base struct:
keep format == FMT_A => op != SUB;

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

e Language Reference 11-45


Generation Constraints
keep reset_gen_before_subtypes()

11.2.11 keep reset_gen_before_subtypes()

Purpose
Disable all previous keep gen_before_subtypes() subtype optimization constraints

Category
Struct member

Syntax
keep reset_gen_before_subtypes()

Syntax Example
keep reset_gen_before_subtypes();

Description
When subtype optimization is turned off by default (config gen
-determinants_before_subtypes=default_off), this constraint causes the generator to ignore all
previously defined gen_before_subtypes() constraints for the enclosing struct or unit. Any
gen_before_subtypes() constraints you define after the reset will be followed.

When subtype optimization is turned on by default (config gen


-determinants_before_subtypes=default_on), this constraint turns off subtype optimization for the
enclosing struct or unit.

When subtype optimization is forced on or off (config gen -determinants_before_subtypes=force_on


| force_off), this constraint has no effect.

Note
• You can define other subtype optimization constraints following a keep
reset_gen_before_subtypes() constraint.

Example
This example shows a reset_gen_before_subtypes() constraint, which disables all previous
gen_before_subtypes() constraints, followed by a new gen_before_subtypes() constraint which is still
effective.

11-46 e Language Reference


Generation Constraints
value()

type format_t: [FMT_A, FMT_B, FMT_C];


struct instr_s {
intrpt: bool;
format: format_t;
keep gen_before_subtypes(format);
};
extend instr_s {
keep reset_gen_before_subtypes();
// Disables previous subtype optimization constraints
keep gen_before_subtypes(intrpt);
// This new subtype optimization constraint is still in effect
};

See Also
• keep gen_before_subtypes() on page 11-42
• -determinants_before_subtypes in configure gen on page 6-17 in the Specman Command
Reference
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.2.12 value()

Purpose
Modify generation sequence

Category
Pseudo-method

Syntax
value(item: exp)

e Language Reference 11-47


Generation Constraints
value()

Syntax Example
keep i < value(j);

Parameters

item A legal e expression.

Description
Generates values for any data items that are contained in the expression and returns the value of the
expression.

This method affects generation order and also makes the constraint unidirectional.
keep a == value(b + c);

The constraint shown above has two results:

• “b” and “c” will be generated before “a”.


• You cannot otherwise constrain the value of “a”.
The value() method is similar to a gen before constraint in that it affects generation order. It can also
provide some performance improvement. The test generator has less work to do because it does not need
to propagate constraint information from “a” to “b” and “c”.

Note
Like most other method calls, the value() method cannot be used to constrain the legal values for any
data item that it contains. A constraint such as “keep value(j) == 16”, which appears to require the test
generator to keep the value of “j” equal to 16, is not enforceable.

Thus, although the following example loads without error, a contradiction almost always occurs during
generation because “j” is generated before the constraint is applied:
extend sys {
j:int;

keep value(j) == 16;


};

Results
In these sample results, “j” was generated as 536940611, and then the constraint was applied, reducing
the valid range to [].

11-48 e Language Reference


Generation Constraints
value()

Specman > test


Doing setup ...
Generating the test using seed 1...
*** Error: Contradiction:
A contradiction has occurred when generating sys-@0.(j) :
Previous constraints reduced its range of possible values,
then the following constraint contradicted these values:
keep 16 == value(j) at line 5 in @test4
Reduced: sys-@0.(j) into []
Using: [email protected] == [536940611]
To see details, reload and rerun with "col gen"

Specman >

See “Enforceable Expressions” on page 11-7 for more information.

Example
“j” is generated first, then “i”. “i” is always less than the value of “j” shifted one bit to the right.
extend sys {
i: int;
j: int;
keep i < value(j >> 1);
};

The code shown below is equivalent:


extend sys {
i: int;
j: int;
keep gen (j) before (i);
keep i < (j >> 1);
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

e Language Reference 11-49


Generation Constraints
constraint-bool-exp

11.2.13 constraint-bool-exp

Purpose
Define a constraint on a generatable item

Category
Expression

Syntax
bool-exp [or | and | => bool-exp] …

Syntax Example
z == x + y

Parameters

bool-exp An expression that returns either TRUE or FALSE when evaluated at run time.

Description
A constraint Boolean expression is a simple or compound Boolean expression that describes the legal
values for at least one generatable item or constrains the relation of one generatable item with others.

A compound Boolean expression is composed of two or more simple expressions joined with the or,
and or implication (=>) operators.

e has several special constructs that are useful in constraint Boolean expressions:

soft A keyword that indicates that the constraint is either a soft value
constraint or a soft order constraint. See “Generation Constraints” on
page 11-1 for a definition of these types of constraints.
soft...select An expression that constrains the distribution of values.
for each Defines a value constraint on multiple list items.
.reset_soft() A pseudo-method that causes the test generator to quit evaluation of
soft constraints for a field, in effect, removing previously defined soft
constraints.

11-50 e Language Reference


Generation Constraints
constraint-bool-exp

.is_all_iterations() A list method used only within constraint Boolean expressions that
causes a list of structs to have all legal, non-contradicting iterations of
the specified fields.
.is_a_permutation() A list method that can be used within constraint Boolean expressions to
constrain a list to have the same elements as another list.
[not] in An operator that can be used within constraints Boolean expressions to
constrain an item to a range of values or a list to be a subset of another
list, or, with not, to be outside the range or absent from another list.
is [not] a An operator that checks the subtype of a struct.

Notes
• The soft keyword can be used in simple Boolean expressions, but not in compound Boolean
expressions. Thus the first constraint below is valid, but the second generates a compile-time error:
keep x > 0 => soft y < 0;
keep soft x > 0 => y < 0; // Compile-time error

• The order of precedence for Boolean operators is: and, or, =>. A compound expression containing
multiple Boolean operators of equal precedence is evaluated from left to right, unless parentheses
are used to indicate expressions of higher precedence. See “Example 3” on page 11-52.
• Any e operator can be used in a constraint Boolean expression. However, certain operators can affect
generation order or can create an constraint that is not enforceable. See “Unidirectional Constraints”
on page 11-4 and “Enforceable Expressions” on page 11-7 for more information.

Example 1
The following are examples of simple constraint Boolean expressions:
long == TRUE
soft x > y
x == WIDTH
x + z == y + 7
x in [0..10]
(list_1) in (list_2)
list_3.is_a_permutation(list_4)
list_of_packets.is_all_iterations(.protocol)
packet.reset_soft()
packet is a legal packet
soft me.opcode == select {
30: ADD;
20: ADDI;
10: [SUB, SUBI];
};

e Language Reference 11-51


Generation Constraints
constraint-bool-exp

Example 2
The following are examples of compound constraint Boolean expressions:
x > 0 and soft x < y
is_a_good_match(x, y) => z < 1024
color != red or resolution in [900..999]
packet is a good packet => length in [0..1023]

Example 3
In compound expressions where multiple implication operators are used, the order in which the
operations are performed is significant. For example, in the following constraint, the first expression (a
=> b) is evaluated first by default:
keep a => b => c; // is equivalent to
keep (not a or b) => c; // is equivalent to
keep a and (not b) or c;

However, adding parentheses around the expression (b => c) causes it to be evaluated first, with very
different results.
keep a => (b => c); // is equivalent to
keep a => (not b) or c; // is equivalent to
keep (not a ) or (not b) or c;

See Also
• keep soft on page 11-30
• keep soft gen … before on page 11-40
• keep gen-item.reset_soft() on page 11-37
• keep struct-list.is_all_iterations() on page 11-25
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide
• “Scalar Types” on page 3-2

11-52 e Language Reference


Generation Constraints
gen-item

11.2.14 gen-item

Purpose
Identifies a generatable item

Category
Expression

Syntax
[me.]field1-name[.field2-name …]

| it | [it].field1-name[.field2-name …]

Syntax Example
me.protocol

Parameters

field-name The name of a field in the current struct or struct type.

Description
A generatable item is an operand in a Boolean expression that describes the legal values for that
generatable item or constrains its relation with another generatable item. Every constraint must have at
least one generatable item or an error is issued.

In a keep constraint, the syntax for specifying a generatable item is a path starting with me of the struct
containing the constraint and ending with a field name. In a gen action, the syntax for specifying a
generatable item is a path starting with it of the struct containing the constraint and ending with a field
name.

Note
A generatable item cannot have an indexed reference in it except as the last item in the path. Thus,
constraints such as “keep a.keys[i] > 10” are legal, while constraints such as “keep packets[0].len > 10”
are illegal.

To work around this restriction, use a keep for each constraint with an implication constraint:

e Language Reference 11-53


Generation Constraints
gen-item

keep for each (p) in packets {


index == 0 => p.len > 10;
};

Example 1
This example illustrates generatable and non-generatable items within a keep constraint. In the
constraint Boolean expression “x > sys.yy + y” shown in the example below, “x” is a generatable item.
“y” is also generatable, even though it is marked with ! as do-not-generate. On the other hand, “sys.yy”
is not a generatable item because its path does not start with me.
extend sys {
yy: int;
};
struct tmp {
!y: int;
x: int;
keep x > sys.yy + y;
};

Example 2
This example illustrates generatable and non-generatable items within a gen action. In the gen action
shown below, it is the only generatable item. “i” is a local variable, and the paths of the other variables
do not start with it.
extend sys {
yy: int;
};
struct tmp {
!y: int;
x: int;
m() is {
var i: int;
gen y keeping {
it > i - me.x + sys.yy;
};
};
};

See Also
• “Basic Concepts of Generation” on page 11-2

11-54 e Language Reference


Generation Constraints
Invoking Generation

• “Defining Constraints” on page 11-19


• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide
• “Implicit Variables” on page 2-30

11.3 Invoking Generation


For information on constructs used to control or invoke generation, see:

• ! described in field on page 4-11


• gen on page 11-55
• pre_generate() on page 11-59
• post_generate() on page 11-60
• test on page 11-9, start on page 11-8, and generate on page 11-5 in the Specman Command
Reference

11.3.1 gen

Purpose
Generate values for an item

Category
Action

Syntax
gen gen-item [keeping {[it].constraint-bool-exp; …}]

Syntax Example
gen next_packet keeping {
.kind in [normal, control];
};

e Language Reference 11-55


Generation Constraints
gen

Parameters

gen-item A generatable item. If the expression is a struct, it is automatically


allocated, and all fields under it are generated recursively, in depth-first
order.

constraint-bool-exp A simple or a compound Boolean expression. See constraint-bool-exp on


page 11-50 for more information.

Description
Generates a random value for the instance of the item specified in the expression and stores the value in
that instance, while considering all the constraints specified in the keeping block as well as other
relevant constraints at the current scope on that item or its children. Constraints defined at a higher scope
than the enclosing struct are not considered. See “Example 1” on page 11-56.

You can generate values for particular struct instances, fields, or variables during simulation (on-the-fly
generation) with the gen action.

This constraint allows you to specify constraints that apply only to one instance of the item.

Notes
• You can use the soft keyword in the list of constraints within a gen action.
• The gen action cannot be used from the vrst-tool> prompt.
• The earliest the gen action can be called is from a struct’s pre_generate() method.
• The generatable item for the gen action cannot include an index reference. For example, “gen
sys.pckts[index].dat;” and “gen sys.pckts.dat[index];” are both illegal.
• If a gen … keeping action contains a for each constraint, you must name the iterated variable. See
“Example 3” on page 11-58 for more information.

Example 1
This example uses the gen action within a TCM called “gen_next()” to create packets to send to the
device under test. A constraint within the gen action keeps “len” with a range of values. A constraint
defined at a lower scope level, “packet”, is also applied when the gen action is executed, keeping the
size of the “data” field equal to the “len” field. The constraint defined at the sys level “keep
sp.next_packet.len == 4;” is not considered because it is not at the current scope of the gen action.
extend sys {
event event_clk is @sys.any;
sp: send_packet;

11-56 e Language Reference


Generation Constraints
gen

keep sp.next_packet.len == 4;
};

struct packet {
len: int [0..10];
kind: [normal, control, ack];
data: list of int;
keep me.data.size() == len;
};

struct send_packet {
num_of_packets_to_send: int [0..20];
!next_packet: packet;

gen_next() @sys.event_clk is {
gen num_of_packets_to_send; // Random loop delimiter
for i from 0 to num_of_packets_to_send - 1 do {
wait ([100]*cycle);
gen next_packet keeping {
.len in [5..10];
.kind in [normal, control];
};
};
};
run() is also {
start gen_next();
};
};

Example 2
This example shows a keep soft … select constraint on the gen action, which weights the distribution of
values for the len field of a packet.
struct packet {
len: int [0..10];
kind: [normal, control, ack];
};
struct top {
!packet_list: list of packet;
pkt_gen() is {
var pkt: packet;
for i from 0 to 100 {
gen pkt keeping {
soft it.len == select {
20: [0..3];

e Language Reference 11-57


Generation Constraints
gen

60: [4..6];
20: [7..10];
};
};
packet_list.add(pkt);
};
};
};

Example 3
This example shows how to generate a struct containing a list on the fly, while constraining each item in
the list.

Note You must provide a name for the list item that is iterated. In other words substituting “for each
in .data” for “for each (item) in .data” causes an error.
struct packet {
addr: uint;
data: list of byte;
};

extend sys {

send_packet()@sys.any is {
var p: packet;

gen p keeping {
it.addr > 450000;
for each (item) in .data { // name is required
item > 10 and item < 30;
};
};
};
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches

11-58 e Language Reference


Generation Constraints
pre_generate()

• Generation Guide

11.3.2 pre_generate()

Purpose
Method run before generation of struct

Category
Method of any struct

Syntax
[struct-exp.]pre_generate()

Syntax Example
pre_generate() is also {
m = 7;
};

Parameters

struct-exp An expression that returns a struct. The default is the current struct.

Description
The pre_generate() method is run automatically after an instance of the enclosing struct is allocated but
before generation is performed. This method is initially empty, but you can extend it to apply values
procedurally to prepare constraints for generation. The pre_generate() method allows you to simplify
constraint expressions before they are analyzed by the constraint solver.

The order of generation is recursively as follows:

1. Allocate the new struct.

2. Call pre_generate().

3. Perform generation

4. Call post_generate().

e Language Reference 11-59


Generation Constraints
post_generate()

Note
Prefix the ! character to the name of any field whose value is determined by pre_generate(). Otherwise,
normal generation will overwrite this value.

Example
struct a {
!m: int;
m1: int;
keep m1 == m + 1;
pre_generate() is also {
m = 7;
};
};
extend sys {
A: a;
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19
• “Invoking Generation” on page 11-55
• Chapter 5 “Debugging Generation Problems” in the Usage and Concepts Guide for e Testbenches
• Generation Guide

11.3.3 post_generate()

Purpose
Method run after generation of struct

Category
Predefined method of any struct

Syntax
[struct-exp.]post_generate()

11-60 e Language Reference


Generation Constraints
post_generate()

Syntax Example
post_generate() is also {
m = m1 + 1;
};

Parameters

struct-exp An expression that returns a struct. The default is the current struct.

Description
The post_generate() method is run automatically after an instance of the enclosing struct is allocated
and both pre-generation and generation have been performed. You can extend the predefined
post_generate() method for any struct to manipulate values produced during generation. The
post_generate() method allows you to derive more complex expressions or values from the generated
values.

The order of generation is recursively as follows:

1. Allocate the new struct.

2. Call pre_generate().

3. Perform generation.

4. Call post_generate().

Example
struct a {
!m: int;
m1: int;
post_generate() is also {
m = m1 + 1;
};
};
extend sys {
A: a;
};

See Also
• “Basic Concepts of Generation” on page 11-2
• “Defining Constraints” on page 11-19

e Language Reference 11-61


Generation Constraints
post_generate()

• “Invoking Generation” on page 11-55


• Generation Guide

11-62 e Language Reference


12 Events
The e language provides temporal constructs for specifying and verifying behavior over time. All e
temporal language features depend on the occurrence of events, which are used to synchronize activity
with a simulator and within Specman.

This chapter contains the following sections:

• “Events Overview” on page 12-1


• “Defining and Emitting Named Events” on page 12-4
• “Sampling Events Overview” on page 12-8
• “Predefined Events Overview” on page 12-10

See Also
• “Defining Structs” on page 4-2
• “Rules for Defining and Extending Methods” on page 7-2
• “Invoking Methods” on page 7-22
• Chapter 13 “Temporal Expressions”
• Chapter 14 “Temporal Struct Members”
• Chapter 15 “Time-Consuming Actions”

12.1 Events Overview


An example of an event definition is shown in Figure 12-1. An event named “rclk” is defined to be the
rising edge of a signal named “top.clk” at another event named “sim”. The @ symbol is used with an
event name, @event, to mean “when the event is true”. The special @sim syntax means at a callback

e Language Reference 12-1


Events
Events Overview

from the simulator. The rise() expression always causes a callback when the signal rises. Therefore, this
event definition means “a rise of top.clk causes rclk to occur”. Occurrences of the “rclk” event are
represented by arrows.

Figure 12-1 Event Definition Example

event rclk is rise('top.clk')@sim

'top.clk'

rclk

time

Once an event has been defined, it can be used in as the sampling event in temporal constructs such as
temporal expressions (see Chapter 13 “Temporal Expressions”) like the following:
expect {[1]; true(chk)@rclk};
on rclk { ... };

Events also are used as the sampling points in time-consuming methods (see “Rules for Defining and
Extending Methods” on page 7-2):

set_chk()@rclk is { ... };

The occurrence of any event is counted as a Specman tick. Ticks are the means by which Specman
marks the passage of time.

Many events are predefined in e. You can use event struct members to define your own events, called
named events, like the “rclk” example above.

All user-defined events are automatically included in functional coverage. A field named events in the
session struct holds the user-defined event coverage data.

See Also
• “Causes of Events” on page 12-3
• “Scope of Events” on page 12-3
• “Defining and Emitting Named Events” on page 12-4
• “Sampling Events Overview” on page 12-8
• “Predefined Events Overview” on page 12-10

12-2 e Language Reference


Events
Causes of Events

12.1.1 Causes of Events


The ways in which an event are made to occur are described below.

Syntax Cause of the Event

event a is (@b and @c)@d Derived from other events (see Chapter 13
“Temporal Expressions”).

event a is rise('top.b')@sim Derived from behavior of a simulated device (see


Chapter 13 “Temporal Expressions”).

event a is { @b; @c; @d }@e A sequence of other events (see Chapter 13


“Temporal Expressions”)

event a; By the emit action in procedural code (see “emit”


meth_b()@c is { … ; emit a; … }; on page 12-6).

You can use the emit action in any method to cause an event to occur, whether it has an attached
temporal expression or not.

See Also
• “Events Overview” on page 12-1

12.1.2 Scope of Events


The scoping rules for events are similar to other struct members, such as fields.

Events are defined as a part of a struct definition. When a struct is instantiated, each instance has its own
event instances. Each event instance has its own schedule of occurrences. There is no relation between
occurrences of event instances of the same type.

All references to events are to event instances. The scoping rules are as follows:

• If a path is provided, use the event defined in the struct instance pointed to by the path.
• If no path is provided, the event is resolved at compile time. The current struct instance is searched.
• If the event instance is not found, a compile-time error is issued.

See Also
• “Events Overview” on page 12-1

e Language Reference 12-3


Events
Defining and Emitting Named Events

12.2 Defining and Emitting Named Events


This section describes the following constructs:

• event on page 12-4


• emit on page 12-6

See Also
• “Events Overview” on page 12-1
• “Sampling Events Overview” on page 12-8
• “Predefined Events Overview” on page 12-10

12.2.1 event

Purpose
Define a named event

Category
Struct member

Syntax
event event-type[is [only] temporal-expression]

Syntax Example
event clk is rise('top.cpu_clk') @sim;

Parameters

event-type The name you give the event type. It can be any legal e
identifier.

12-4 e Language Reference


Events
event

temporal-expression An event or combination of events and temporal operators.


To use an event name alone as a temporal expression, you
must prefix the event name with the @ sign. For example,
to define event A to succeed whenever event D succeeds,
you must use the @ in front of D: “event A is @D”. For
more information about temporal expressions, see Chapter
13 “Temporal Expressions”.

Description
Events can be attached to temporal expressions, using the option is [only] temporal-expression syntax,
or they can be unattached. An attached event is emitted automatically during any Specman tick in which
the temporal expression attached to it succeeds.

Events, like methods, can be redefined in struct extensions. The is only temporal-expression syntax in a
struct extension is used to change the definition of an event. You can define an event once, and then
attach it to several different temporal expressions under different when struct subtypes, using the is only
syntax.

Example 1
In the following, “start_ct” is an unattached event, and “top_clk” and “stop_ct” are attached events. The
“m_str” extension contains a redefinition of the “top_ct” event.
struct m_str {
event start_ct;
event top_clk is fall('top.r_clk') @sim;
event stop_ct is {@start_ct; [1]} @top_clk;
};
extend m_str {
event stop_ct is only {@start_ct; [3]}@top_clk;
};

Example 2
One way to cause a Specman callback from the simulator is to sample a change, rise, or fall of a
simulator object using @sim. The following causes a callback and a “sim_ready” event whenever the
value of the simulator object “top/ready” changes.
event sim_ready is change('top/ready') @sim;

e Language Reference 12-5


Events
emit

Example 3
The emit action can be used to force any event to occur. The emit action in the following forces the
“sim_ready” event to occur even if the “change('top/ready') @sim” temporal expression has not
succeeded.
struct sys_ready {
event sim_ready is change('top/ready') @sim;
bar() @sys.clk is {
while TRUE {
wait until @sys.ok;
wait [1] *cycle;
emit sim_ready;
};
};
};

See Also
• Chapter 13 “Temporal Expressions”
• “Rules for Defining and Extending Methods” on page 7-2
• show events on page 8-5 in the Specman Command Reference
• echo events on page 8-3 in the Specman Command Reference
• emit on page 12-6
• “Events Overview” on page 12-1
• “Sampling Events Overview” on page 12-8
• “Predefined Events Overview” on page 12-10

12.2.2 emit

Purpose
Cause a named event to occur

Category
Action

12-6 e Language Reference


Events
emit

Syntax
emit [struct-exp.]event-type

Syntax Example
emit ready;

Parameters

struct-exp An expression referring to the struct instance in which the event is defined.

event-type The type of event to emit.

Description
Causes an event of the specified type to occur.

The simplest usage of emit is to synchronize two TCMs, where one TCM waits for the named event and
the other TCM emits it.

Emitting an event causes the immediate evaluation of all temporal expressions that contain that event.

The emit event does not consume time. It can be used in regular methods and in TCMs.

Example
<'
struct xmit_recv {
event rec_ev;
transmit() @sys.clk is {
wait cycle;
emit rec_ev;
out("rec_ev emitted");
};
receive() @sys.clk is {
wait until @rec_ev;
out("rec_ev occurred");
stop_run();
};
run() is also {
start transmit();
start receive();
};
};

extend sys {

e Language Reference 12-7


Events
Sampling Events Overview

event clk is @sys.any;


xmtrcv_i: xmit_recv;
};
'>

See Also
• event on page 12-4
• “Events Overview” on page 12-1
• “Sampling Events Overview” on page 12-8
• “Predefined Events Overview” on page 12-10

12.3 Sampling Events Overview


Events are used to define the points at which temporal expressions and TCMs are sampled. An event
attached to a temporal expression becomes the sampling event for the temporal expression. The event is
attached using the @sampling-event syntax:

temporal-expression @sampling-event

The temporal expression is evaluated at every occurrence of the sampling event. The sampling period is
the time from after one sampling event up to and including the next sampling event. All event
occurrences within the same sampling period are considered simultaneous. Multiple occurrences of a
particular event within one sampling period are considered to be one occurrence of that event.

In Figure 12-2, Q and R are previously defined events that occur at the points shown. The temporal
expression “Q@R” means “evaluate Q every time the sampling event R occurs”. If Q has occurred since
the previous R event, then “Q@R” succeeds upon the next occurrence of R. The final “Q@R” success
happens because the sampling period for the expression includes the last R event, which occurs at the
same time as the last Q.

Figure 12-2 Sampling Event for a Temporal Expression

cycle of Q
Q
cycle of R
R

Q@R

time

12-8 e Language Reference


Events
Sampling Events Overview

If “Q” in the figure above is a temporal expression that includes other events, “R” is the default sampling
event of the temporal expression. The default sampling event of a temporal expression applies to all
subexpressions within the expression, except where it is overridden explicitly by another event
embedded in the expression.

For a TCM, the sampling event is written as:

time-consuming-method(…)@sampling-event is {...}

The default sampling event specified for a TCM drives or synchronizes actions within the TCM. It is not
a trigger that launches the TCM, but is rather the event to which temporal actions and expressions in the
TCM relate.

The predefined sys.any event occurs every time any other event occurs in the test. Expressions that need
the highest time resolution can be attached to the sys.any event. The sys.any event is the default
sampling event for all temporal expressions.

When a callback to Specman is needed upon a change in a simulator variable, you can attach the name
sim to the simulator variable. A change in a simulator variable to which sim is attached always causes a
callback. The term @sim just represents a callback to Specman from the simulator; no sim event ever
actually occurs.

In Figure 12-3, “S” and “T” are previously defined events. Attaching @sim to each of these event names
causes the event to occur when its conditions are true at the time of a Specman callback. The sys.any
event occurs at every “S” event and every “T” event. The temporal expression “S@T” succeeds at every
occurrence of T where “S” has occurred since the last T event.

Figure 12-3 Occurrences of the sys.any Event

S@sim

T@sim

sys.any

S@T

time

See Also
• “Events Overview” on page 12-1
• “Defining and Emitting Named Events” on page 12-4
• “Predefined Events Overview” on page 12-10

e Language Reference 12-9


Events
Predefined Events Overview

12.4 Predefined Events Overview


Predefined events are emitted by the Specman at particular points in time. They are described in the
following sections:

• “General Predefined Events” on page 12-10


• “Events for Aiding Debugging” on page 12-13
• “Simulation Time and Specman Ticks” on page 12-14

See Also
• “Events Overview” on page 12-1
• “Defining and Emitting Named Events” on page 12-4
• “Sampling Events Overview” on page 12-8

12.4.1 General Predefined Events


Table 12-1 lists the general predefined events. The events are described in more detail after the table.

Table 12-1 Predefined Events

Predefined Event Description

sys.any Emitted on every Specman tick.

sys.tick_start Emitted at the start of every Specman tick.

sys.tick_end Emitted at the end of every Specman tick.

session.start_of_test Emitted once at test start.

session.end_of_test Emitted once at test end.

struct.quit Emitted when a struct’s quit() method is called. Only exists in structs that
contain events or have members that consume time (for example,
time-consuming methods and on struct members).

sys.new_time In stand-alone operation (no simulator), this event is emitted on every


sys.any event. When a simulator is being used, this event is emitted every
time a callback occurs, if the attached simulator’s time has changed since
the previous callback.

12-10 e Language Reference


Events
General Predefined Events

sys.any
Emitted on every Specman tick.

This is a special event that defines the highest granularity of time. The occurrence of any event in the
system causes an occurrence of the any event at the same tick. For any temporal expression used without
an explicit sampling event, sys.any is used by default.

In stand-alone Specman operation (that is, with no simulator attached), the sys.any event is the only one
that occurs automatically. It typically is used as the clock for stand-alone operation, as in the following
example.

Original clock definition for simulation:


<'
extend sys {
event clk is rise('top.clk')@sim; // clk drives the system
};
'>

Extension to override the clock to tie it to sys.any for stand-alone operation:


<'
extend sys {
event clk is only cycle @sys.any;
};
'>

sys.tick_start
Emitted at the start of every tick.

This event is provided mainly for visualizing and debugging the program flow in the event viewer.

sys.tick_end
Emitted at the end of every tick.

This event is provided mainly for visualizing and debugging the program flow in the event viewer. It also
can be used to provide visibility into changes of values that are computed during the tick, such as the
values of coverage items.

session.start_of_test
Emitted once at the start of the test.

e Language Reference 12-11


Events
General Predefined Events

The first action the predefined run() method executes is to emit the session.start_of_test event. This
event is typically used to anchor temporal expressions to the beginning of a test.

For example, in the following, the “watchdog” time is anchored to the beginning of the test by
session.start_of_test:
<'
extend sys {
event clk is cycle @sys.any;
event watchdog is {@session.start_of_test; [100]}@clk;
on watchdog {
out("Watchdog triggered");
stop_run();
};
};
'>

session.end_of_test
Emitted once at the end of the test.

This event is typically used to sample data at the end of the test. This event cannot be used in temporal
expressions as it is emitted after evaluation of temporal expression has been stopped. The on
session.end_of_test struct member is typically used to prepare the data sampled at the end of the test.

struct.quit
Exists only in structs that contain temporal members (events, on, expect, TCMs). Emitted when the
struct’s quit() method is called, to signal the end of time for the struct.

The first action executed during the check test phase is to emit the quit event for each struct that contains
it. It can be used to cause the evaluation of temporal expressions that contain the eventually temporal
operator. This allows you to check for eventually temporal expressions that have not been satisfied.

See Also
• “Events Overview” on page 12-1
• “Defining and Emitting Named Events” on page 12-4
• “Sampling Events Overview” on page 12-8
• “Predefined Events Overview” on page 12-10
• “Events for Aiding Debugging” on page 12-13
• “Simulation Time and Specman Ticks” on page 12-14

12-12 e Language Reference


Events
Events for Aiding Debugging

12.4.2 Events for Aiding Debugging


Table 12-2 shows predefined events intended as aids in debugging. By setting trace on event, you can
see occurrences of events as the program runs. For example, entering “trace on tcm_start” before a test
displays every occurrence of the session.tcm_start event.

Note The predefined events in the session struct are not graded until the end of the test run, unlike
user-defined events which are graded during the run. If you look at the session events grades during the
run, you will see grades of 0.

Table 12-2 Debugging Events Predefined in the session Struct

Debugging Event Description

tcm_start Emitted when any TCM is started

tcm_end Emitted when any TCM finishes

tcm_call Emitted when any TCM is called or gets started

tcm_return Emitted when any TCM returns

call Emitted when any method is called

return Emitted when any method returns

output Emitted when any output is issued

line Shows line numbers for all traced events

tcm_wait Emitted when a wait action is performed

tcm_state Emitted when a state of a state machine transitions

sim_read Emitted when Specman reads a simulator variable (reads a


value from the DUT)

sim_write Emitted when Specman writes to a simulator variable


(writes a value to the DUT)

check Emitted when a check action is performed

e Language Reference 12-13


Events
Simulation Time and Specman Ticks

Table 12-2 Debugging Events Predefined in the session Struct

Debugging Event Description

dut_err Emitted when a dut_error action is performed

Note The session.dut_err event is new as of Specman


4.3.1. It replaces the previous session.dut_error event,
which is now under deprecation. However, the previous
session.dut_error event is still supported at this time, which
means that you do not need to change any existing code. For
more information, see “Deprecation and Backward
Compatibility in the Current Release” on page 8-2 and
“Understanding the Deprecation Process” on page 7-1 in
About This Specman Elite Release.

See Also
• “Events Overview” on page 12-1
• trace on special event on page 17-18 in the Specman Command Reference
• ltrace on special event on page 17-20 in the Specman Command Reference
• “Defining and Emitting Named Events” on page 12-4
• “Predefined Events Overview” on page 12-10

12.4.3 Simulation Time and Specman Ticks


Using any of the following expressions causes Specman to monitor the DUT for a change in that
expression:

• rise | fall | change (HDL expression) @sim


• wait delay expression
• Verilog event
For each simulation delta cycle in which a change in at least one of these monitored expressions occurs,
the simulator passes control to Specman. If simulation time has advanced since the last time control was
passed to Specman, Specman issues a new_time event. In any case, Specman issues tick_start and any
events. Then, after emitting all events initiated by changes in monitored expressions in that simulation
delta cycle, Specman issues a tick_end event.

Thus, the Specman new_time event corresponds to a new simulation time slot, and a Specman tick
corresponds to a simulation delta cycle in which at least one monitored expression changes.

12-14 e Language Reference


Events
Simulation Time and Specman Ticks

Multiple Specman ticks can occur in the same simulation time slot under the following conditions:

• When Specman drives a new value into the DUT and that value causes a change in a monitored HDL
object, as in a clock generator
• When a monitored event is derived from another monitored event, as in a clock tree
• When a zero delay HDL subprogram is call from e
Note Specman ignores glitches that occur in a single simulation time slot. Only the first occurrence of
a particular monitored event in a single simulation time slot is recognized by Specman. For example, if
a signal transitions from 0 to 1 and back to 0 in the same time slot, Specman sees only the 0 to 1 transition;
the 1 to 0 transition is ignored. See “Example 4” on page 12-22 for ways to handle glitches.

For an explanation of when values are assigned, see <= on page 8-9.

In TCMs it is preferred to use change()@sim, rise()@sim, and fall()@sim temporal expressions in a


sync action rather than a wait action. When used in a sync action, the monitoring of changes in signal
value begins immediately and includes changes in subsequent delta cycles in the current simulation
time. When used in a wait action, the monitoring of changes in signal value begins in the next simulation
time. In both actions, the initial value of the signal is sampled as soon as the sync or wait action is
reached.

For example, if a TCM uses


sync rise('my_sig')@sim;

and if the value of 'my_sig' falls in a later delta-cycle of the same simulation time as the sync action is
reached, Specman records the change of the value and could observe a rise in the following simulation
time.

However if the TCM uses


sync wait('my_sig')@sim;

and the value of a signal 'my_sig' falls in a later delta-cycle of the same simulation time as the wait
action is reached, this fall is not observed by the temporal expression. Consequently, the next rise of the
value of the 'my_sig' signal is ignored by the temporal expression as a change in the signal value that did
not rise with respect to the signal's value at the time the wait action was reached.

Example 1
This example shows the most simple case, where there is only one monitored event, “clk”.

clk.v
module top;
reg clk;

e Language Reference 12-15


Events
Simulation Time and Specman Ticks

initial begin
clk = 1'b1;
$display("clk is %h", clk);
end

always #10 clk = ~clk;

endmodule

clk.e
<'
struct dut {
event clk is rise ('top.clk') @sim;

go()@clk is {
wait [10]* cycle;
stop_run();
};

run() is also {
start go();
};
};

extend sys {
dut;
};
'>

Result
Assuming that the following Specman commands have been executed
echo events sys.*
echo events dut.*

the following display appears when the run is started:


--------------------------------------------------
-> 0 [email protected]_start
# clk is 1 // display from simulator

-> 0 [email protected]
-> 0 [email protected]
-> 0 [email protected]_end
--------------------------------------------------

12-16 e Language Reference


Events
Simulation Time and Specman Ticks

-> 10 [email protected]_time
-> 10 [email protected]_start
-> 10 [email protected]
-> 10 [email protected]_end
--------------------------------------------------
-> 20 [email protected]_time
-> 20 [email protected]_start
-> 20 [email protected]
-> 20 [email protected]
-> 20 [email protected]_end
--------------------------------------------------
-> 30 [email protected]_time
-> 30 [email protected]_start
-> 30 [email protected]
-> 30 [email protected]_end
--------------------------------------------------
...

Note that control is passed to Specman at each change in the clk signal, while the clk event is emitted
only when clk transitions to 1. A new_time event is emitted every time control passes to Specman
because simulation time has changed. In this example, there is only one Specman tick per simulation
time slot.

Example 2
This example shows a clock generator and illustrates how two Specman ticks can occur at the same
simulation time.

clock_gen.v
module top;
reg clk;

initial clk = 0;

reg [31:0] data;


endmodule

clock_gen.e
<'
extend sys {

event clk is change('top.clk')@sim;

event boot;

e Language Reference 12-17


Events
Simulation Time and Specman Ticks

clk_gen()@boot is {
var clk_value: bit = 0;

for j from 0 to 9 {
'top.clk' = clk_value;
wait delay(5);
clk_value = ~clk_value;
};
stop_run();
};

run() is also {
start clk_gen();
emit boot;
};
};

extend sys {
setup() is also {
specman("echo event");
};
};
'>

Result
There are two Specman ticks in each simulation time slot. The first tick is caused by the elapse of the
wait delay; the second, by the new value applied to top.clk.
Starting the test ...
Running the test ...

-> 0 [email protected]
Running should now be initiated from the simulator side
Specman clock_gen>
-> 0 [email protected]_start
-> 0 [email protected]
-> 0 [email protected]_end

-> 5 [email protected]_time
-> 5 [email protected]_start
-> 5 [email protected]
-> 5 [email protected]_end
-> 5 [email protected]_start
-> 5 [email protected]
-> 5 [email protected]

12-18 e Language Reference


Events
Simulation Time and Specman Ticks

-> 5 [email protected]_end

-> 10 [email protected]_time
-> 10 [email protected]_start
-> 10 [email protected]
-> 10 [email protected]_end
-> 10 [email protected]_start
-> 10 [email protected]
-> 10 [email protected]
-> 10 [email protected]_end

-> 15 [email protected]_time
-> 15 [email protected]_start
-> 15 [email protected]
-> 15 [email protected]_end
-> 15 [email protected]_start
-> 15 [email protected]
-> 15 [email protected]
-> 15 [email protected]_end
...

Example 3
This example shows a clock tree and illustrates how two Specman ticks can occur at the same simulation
time.

tree.v
module top;

reg prim_clk;
reg sec_clk;

initial begin
prim_clk = 0;
sec_clk = 0;
end

always #10 prim_clk = ~prim_clk;

always @(prim_clk)
sec_clk <= prim_clk;

endmodule

e Language Reference 12-19


Events
Simulation Time and Specman Ticks

tree.e
In this example, the wait statement marked with a comment is expected to miss one edge of the
secondary clock because Specman samples the old value of top.sec_clk — one delta cycle before it
changes. Note that wait action cannot resume in zero time, even if there are multiple delta cycles.
<'
extend sys {
event prim_clk is change('top.prim_clk')@sim;
event sec_clk is change('top.sec_clk')@sim;

verify() @prim_clk is {
var sec_clk_value: int;

wait cycle;
print sys.time;
sec_clk_value = 'top.sec_clk';

// Following wait misses one edge of secondary clock


wait change('top.sec_clk')@sim;
print sys.time;
out("TCM reacts at edge of 'top.sec_clk': ", 'top.sec_clk');
check that 'top.sec_clk' != sec_clk_value;
wait change('top.sec_clk')@sim;
print sys.time;
stop_run();
};

on sec_clk {
out("Specman observes an edge of 'top.sec_clk': ",
'top.sec_clk');
};

run() is also {
start verify();
};
};

'>

Result
There are two Specman ticks in each simulation time slot. The first tick is caused by the primary clock
event; the second, by the secondary clock event.
--------------------------------------------------
-> 0 [email protected]_start

12-20 e Language Reference


Events
Simulation Time and Specman Ticks

-> 0 [email protected]
-> 0 [email protected]_end
--------------------------------------------------
-> 10 [email protected]_time
-> 10 [email protected]_start
-> 10 [email protected]
-> 10 [email protected]_clk
-> 10 [email protected]_end
-> 10 [email protected]_start
-> 10 [email protected]
Specman observes an edge of 'top.sec_clk': 1
-> 10 [email protected]_clk
-> 10 [email protected]_end
--------------------------------------------------
-> 20 [email protected]_time
-> 20 [email protected]_start
-> 20 [email protected]
-> 20 [email protected]_clk
sys.time = 20
-> 20 [email protected]_end
-> 20 [email protected]_start
-> 20 [email protected]
Specman observes an edge of 'top.sec_clk': 0
-> 20 [email protected]_clk
-> 20 [email protected]_end
--------------------------------------------------
-> 30 [email protected]_time
-> 30 [email protected]_start
-> 30 [email protected]
-> 30 [email protected]_clk
-> 30 [email protected]_end
-> 30 [email protected]_start
-> 30 [email protected]
Specman observes an edge of 'top.sec_clk': 1
-> 30 [email protected]_clk
-> 30 [email protected]_end
--------------------------------------------------
-> 40 [email protected]_time
-> 40 [email protected]_start
-> 40 [email protected]
-> 40 [email protected]_clk
-> 40 [email protected]_end
-> 40 [email protected]_start
-> 40 [email protected]
Specman observes an edge of 'top.sec_clk': 0
-> 40 [email protected]_clk
sys.time = 40

e Language Reference 12-21


Events
Simulation Time and Specman Ticks

TCM reacts at edge of 'top.sec_clk': 0


-> 40 [email protected]_end
--------------------------------------------------

Example 4
If multiple edges occur in a single simulation time slot on a signal monitored with @sim, Specman sees
only the first one. For example, if you have an event defined as
event my_event is change('~/top/wireA')@sim;

and wireA transitions from 1 to 0 and back to 1 in the same time slot, Specman emits my_event and
stores 0 as the value of wireA. Then, if wireA changes to 0 in a subsequent time slot, Specman does not
see this as a change and does not emit my_event.

There are two ways to handle this situation.

1. Change the sampling event of wireA to a clock sampling event:


event clk is change('~/top/clk')@sim;
event my_event is change('~/top/wireA')@clk;

2. Use the strobe option of verilog variable to filter out the glitch:
verilog variable '~/top/wireA' using wire, strobe = "#1";

See Also
• “Events Overview” on page 12-1
• “Defining and Emitting Named Events” on page 12-4
• “Predefined Events Overview” on page 12-10
• <= on page 8-9

12-22 e Language Reference


13 Temporal Expressions
Temporal expressions provide a declarative way to describe temporal behavior. The e language provides
a set of temporal operators and keywords that you can use to construct temporal expressions.

This chapter contains the following sections:

• “Temporal Expressions Overview” on page 13-1


• “Temporal Operators and Constructs” on page 13-11

See Also
• “Invoking Methods” on page 7-22
• Chapter 12 “Events”
• Chapter 14 “Temporal Struct Members”
• Chapter 15 “Time-Consuming Actions”

13.1 Temporal Expressions Overview


A temporal expression (TE) is a combination of events and temporal operators that describes behavior.
A TE expresses temporal relationships between events, values of fields, variables, or other items during
a test.

Temporal expressions are used to define the occurrence of events, specify sequences of events as
checkers, and suspend execution of a thread until the given sequence of events occurs. Temporal
expressions are only legal in the following constructs:

• wait and sync actions in time-consuming methods


• event definitions and expect or assume struct members.

e Language Reference 13-1


Temporal Expressions
Evaluating Temporal Expressions

The following sections provide more information about temporal expressions, how they are evaluated
over time, and how the context in which they are used affects their interpretation.

• “Evaluating Temporal Expressions” on page 13-2


• “Using HDL Objects in Temporal Expressions” on page 13-5
• “Selected Applications of Temporal Expressions” on page 13-6
• “Forms for Common Temporal Expressions” on page 13-7
• “Translation of Temporal Expressions” on page 13-10

See Also
• “Temporal Operators and Constructs” on page 13-11
• Chapter 12 “Events”
• Chapter 15 “Time-Consuming Actions”

13.1.1 Evaluating Temporal Expressions


Evaluating a temporal expression is more difficult than evaluating an arithmetic or Boolean expression
since it might require several clock cycles to complete. Every temporal expression has a default clock,
called its sampling event, either stated specifically for the TE, or inherited from the context in which it
appears. In the following example three cycles of the clk sampling event are needed before the TE
terminates:
{rise('top.req'); [1]; @ack} @clk;

The “@clk” syntax means “evaluate when clk occurs”. The above expression is a sequence temporal
expression containing three simpler temporal expressions:

• rise('top.req') - a rise in the level of an HDL signal, followed by


• [1] - one cycle of the clk sampling event, followed by
• @ack - an occurrence of the ack event
Evaluation of this temporal expression commences with a rise of the top.req signal when sampled at the
clk event. Evaluation then continues for two more clk cycles, and terminates successfully in the third
cycle if, in that cycle, there is an occurrence of the ack event. Evaluation of the temporal expression
terminates without success in the third clk cycle if the ack event does not occur in that cycle.

An evaluation of a TE thus succeeds, fails, or remains open on every occurrence of the sampling event.
The period between occurrences of the sampling event is called the sampling period.

13-2 e Language Reference


Temporal Expressions
Evaluating Temporal Expressions

The context in which a TE is used determines when TE evaluation commences. In general a new
evaluation commences on every occurrence of the sampling event, so that there may be several open
evaluations of the TE at any one time. The context also determines the effect of success or failure of TE
evaluation.

• A wait or sync action in a TCM operates on a temporal expression. See “Synchronization Actions”
on page 15-1.

For example, to wait three pclk cycles after a rise on the request line before driving the data:
drive(data: byte) @pclk is {
wait {rise('top.req'); [3]};
'top.inbuf' = data;
};

A wait TE is first evaluated on the next pclk after the drive() TCM is started or called. When the
temporal expression succeeds, the wait or sync construct terminates any open evaluations before
resuming the thread. The TE will not be evaluated again until the drive() method is reinvoked. See
“Invoking Methods” on page 7-22.

• An event definition is a struct member. An event definition binds a named event to a temporal
expression:
event drive is {rise('top.req'); [3]} @pclk;

The TE in an event definition commences evaluation when the run() method of the struct in which it is
declared is invoked, at the time the struct is initialized. Thereafter a new evaluation of the TE
commences on every occurrence of the sampling event. Whenever the TE succeeds the event will be
emitted. No action is taken when an event temporal expression fails. See Chapter 12 “Events”.

• An expect or an assume is a struct member that binds a named behavioral rule to a temporal
expression. For example a done event must occur no more than three pclk cycles after a drive event
occurs:
expect drive_check is @drive => {[..2]; @done} @pclk
else dut_error{"drive_check failed at ", sys.time, ".");

The TE in the declaration of an expect commences evaluation when the run() method of the struct in
which it is declared is invoked, at the time the struct is initialized. Thereafter a new evaluation of the TE
commences on every occurrence of the sampling event. Whenever the TE fails the exception associated
with the rule is invoked causing the test to be aborted, or a warning message to be printed. No action is
taken when an expect TE succeeds. See expect | assume on page 14-3

A struct is terminated by calling the struct.quit() method, which is predefined for any struct that contains
time-consuming constructs. When the quit() method is called any TE evaluation that succeeds or fails at
the same time is allowed to do so, but all open temporal expression evaluations are terminated.

e Language Reference 13-3


Temporal Expressions
Evaluating Temporal Expressions

Figure 13-1 shows the graphical notation used in illustrations in the Specman temporals documentation.
The illustrations do not show evaluations that start and immediately fail.

Figure 13-1 Legend for Temporals Graphics

event emitted evaluation starts evaluation succeeds evaluation fails

An example of the graphical notation to represent evaluation of temporal sequences is shown in Figure
13-2.

Figure 13-2 Evaluation of Three Sequences

pclk 1 2 3 4 5

req

ack

{@req; @ack} @pclk

{@req; [1]; @ack} @pclk

{@req; @req} @pclk

Figure 13-2 shows occurrences of three events, pclk, req, and ack. The pclk event is the sampling event
for three sequences involving req and ack.

• The {@req; @ack} sequence starts evaluating each time req occurs at pclk. When ack occurs one
pclk after req, the sequence succeeds.
• The {@req; [1]; @ack} sequence likewise starts evaluating at the first req occurrence at pclk, and
shifts at the next pclk occurrence. When ack occurs at the third pclk, the sequence succeeds.
• The {@req; @req} sequence starts evaluating each time req occurs at pclk, and fails when req does
not occur again at the next pclk.

13-4 e Language Reference


Temporal Expressions
Using HDL Objects in Temporal Expressions

Some sequences can succeed more than once during a particular evaluation. Figure 13-3 shows an
evaluation of a temporal expression that is the OR of two sequences. The first sequence (a), {@req;
@ack}@pclk, succeeds at the first ack occurrence (second pclk occurrence). The second sequence (b),
{@req; [1]; @ack}@plck, succeeds at the second ack occurrence (third pclk).

When req occurs again at the fourth pclk occurrence, a new evaluation of the sequence starts. This
evaluation succeeds upon the occurrence of ack at the fifth pclk cycle. Evaluation of the (b) branch
continues at the sixth pclk, where it fails and terminates.

Figure 13-3 Evaluation of the OR of Two Sequences

pclk 1 2 3 4 5

req

ack

( {@req; @ack} // a
(a) (b) (a) (b)
or {@req; [1]; @ack} // b
) @pclk

13.1.2 Using HDL Objects in Temporal Expressions


To synchronize Specman to a simulator define an event that depends on a simulator variable (typically a
clock), and use the event as the sampling event for a TCM, or as part of a temporal expression.

To create an event dependent on an HDL object or expression, use the following syntax:

event event-name is (rise | fall | change) ('HDL-expression') @sim

Using the @sim syntax activates Specman whenever the HDL-expression changes in the designated way
(rises, falls, or changes value). The event is emitted by Specman at that time.

Note For HDL expressions that contain vectors or bit selects of vectors, Specman detects changes on
all bits of the vector. Thus, if the HDL expression is a bit select of a multibit clock signal, for example
‘/clockbus(1)’, a callback occurs whenever any bit of clockbus changes, not just when clockbus(1)
changes.

HDL expressions can be used in TEs sampled by any Specman event, not just @sim. The HDL values
are sampled at each occurrence of the given sampling event.

e Language Reference 13-5


Temporal Expressions
Selected Applications of Temporal Expressions

In the following example, an event named clk is defined as the fall of a simulator signal named
xor_top.clk. The clk event is used as the sampling event for a TCM named body() so that every
time-consuming action in the TCM is synchronized to clk.
struct verify {
event clk is fall('xor_top.clk')@sim;
// Causes simulator callback
event rdy is fall('xor_top.ready')@clk;
// Does not cause callback
body() @clk is {
for each operation (op) in sys.ops {
'xor_top.a' = op.a;
'xor_top.b' = op.b;
wait @rdy;
op.result_from_dut = 'xor_top.out';
print sys.time;
print op;
check that op.result_from_dut == (op.a ^ op.b);
wait [1]*cycle;
};
};
};

Verilog events can also be used to create Specman events. To create a Specman event from a Verilog
event, use change('VL-event') @sim, as in the following example:
event vl_event1 is change('xor_top.verilog_event1')@sim;

See Also
• “Temporal Expressions Overview” on page 13-1

13.1.3 Selected Applications of Temporal Expressions


This section describes the following:

• “Handling Overlapping Transactions” on page 13-6


• “Restricting TE Matches” on page 13-7

13.1.3.1 Handling Overlapping Transactions


Transactions can overlap in the sense that many of them can be active at the same time. These can be
purely pipelined transactions or transactions that are identified by some key.

13-6 e Language Reference


Temporal Expressions
Forms for Common Temporal Expressions

Handling pipelined transactions is easy in e. For example, the following is a behavioral rule for a buffer
with a latency of three cycles:
expect @buf.in => {[2]; @buf.out};

Often data need to be carried with the transaction. These may be input our output data associated with
the transaction, or some identification of the specific transaction.

In such cases the solution is to create a “transaction” struct that carries the data. The struct also contains
the temporal rule describing the expected behavior of the struct. A new transaction struct needs to be
created every time a transaction starts.

13.1.3.2 Restricting TE Matches


A temporal expression is re-evaluated at every occurrence of the sampling event to see if there is any
possible match of the behavior it describes. Sometimes a different behavior is expected, where not all
matches are considered.

For example, consider a component that handles fixed length transactions. The basic behavior we want
to check for is “every transaction that starts will end after N cycles”:
expect @trans.start => {[N]; @trans.end} @clk;

However, suppose that the design under test can only handle one transaction at a time. If a new
transaction starts while the previous one is being processed, the component cannot handle the second
transaction. The expect check fails because the component does not emit the expected transaction end.
Since an expect automatically traces multiple transactions, you must explicitly rule out such cases. For
example:
expect @trans.start =>
{[N]* not @trans.start;@trans.end}@clk;

This formulation explicitly states that a transaction start must not occur while a transaction is being
processed.

See Also
• “Temporal Expressions Overview” on page 13-1

13.1.4 Forms for Common Temporal Expressions


The natural way to specify future behavior is in terms of “cause yields effect”, which is done with the
temporal yield operator (=>). The following is equivalent to the statement, “A transaction start is
followed within 1 to 4 cycles by a transaction end”:
@transaction.start => {[..3]; @transaction.end};

e Language Reference 13-7


Temporal Expressions
Forms for Common Temporal Expressions

The language also provides a way to maintain information about past events, which you can then use in
yield expressions like the above. This is done with the detach operator. The following implements the
requirement that “a transaction end is preceded by a transaction start within the previous 1 to 4 cycles:
@transaction.end => detach({@transaction.start; ~[2..5]});

The detach() operator causes the embedded temporal expression to be evaluated in parallel with the
main temporal expression. See detach on page 13-31.

Temporal expressions for many situations are shown below. The desired conditions are stated, and then
an expression is shown for those conditions. In these expressions, TEn is a temporal subexpression,
which can be an event.

See Also
• “Examples of Sequence Expressions” on page 13-8
• “Examples of Behavioral Rule Checks” on page 13-9

13.1.4.1 Examples of Sequence Expressions


• TE1 and TE2 at the same time:
TE1 and TE2

• TE1 followed by TE2:


{TE1; TE2}

• TE1 any number of times, then TE2:


{[..] * TE1; TE2}

• TE2 in the nth cycle after TE1:


{TE1; [n - 1]; TE2}

• TE2 within n cycles after TE1:


{TE1; [..n-1]; TE2}

• TE2 within n1 to n2 cycles after TE1:


{TE1; [n1-1..n2-1]; TE2}

• TE2 any number of cycles after TE1:


{TE1; [..]; TE2}

• No TE2 before TE1:


{[..] * not TE2; TE1 and not TE2}

13-8 e Language Reference


Temporal Expressions
Forms for Common Temporal Expressions

• TE2 after n cycles of no TE1:


{[n] * not TE1; TE2}

• TE2 any number of cycles after TE1, with no TE3 in between:


{TE1; [..] * not TE3; TE2}

• TE2 after TE1, repeated n times:


{@session.start_of_test; [n] * {[..]; detach({TE1; TE2})}

• TE1 after the last TE2 and before TE3:


{TE2; [..] * not TE2; (TE1 and not TE3 and not TE2);
[..] * not TE2; TE3}

13.1.4.2 Examples of Behavioral Rule Checks


• If TE1 succeeds TE2 must follow:
expect TE1 => TE2
else dut_error("TE2 did not occur 1 cycle after TE1")

• TE2 must succeed within n1 to n2 cycles of TE1:


expect TE1 => {[n1-1..n2-1]; TE2}
else dut_error("No TE2 ",n1," to ",n2," cycles after TE1")

• If TE1 succeeds then TE2 should eventually succeed:


expect TE1 => (eventually TE2)
else dut_error("TE1 occurred but not TE2")

• If TE1, then TE2 must not succeed for n cycles:


expect TE1 => [n] * not TE2
else dut_error("TE2 less than ",n," cycles after TE1")

• If TE2, then TE1 must have succeeded n cycles earlier:


expect TE2 => detach({TE1; [n + 1]})
else dut_error("TE2 without TE1 ",n," cycles earlier")

• If TE2, then TE1 must have succeeded sometime earlier:


expect TE2 => detach({TE1; ~[2..]})
else dut_error("TE2 without a previous TE1")

• TE2 should succeed after TE1 and no more that n occurrences of TE3:
expect {TE1; [n] * {[..]; TE3}} => {[..] * not TE3; TE2}
else dut_error("TE1 not followed by TE2")

e Language Reference 13-9


Temporal Expressions
Translation of Temporal Expressions

• TE must not succeed more than n times during the test:


expect @session.start_of_test => fail{[n + 1] * {[..]; TE}}
else dut_error("TE occurred more than ",n," times")

See Also
• “Temporal Expressions Overview” on page 13-1

13.1.5 Translation of Temporal Expressions


Certain temporal expressions that describe unusually complex temporal behavior cannot be processed
by the static analysis of the temporal engine. Errors can result from:

• Analysis capacity overflow


• Limited analysis capability
If Specman identifies a failure to translate a complex temporal expression at load or compile time, you
will have to decompose the expression into several smaller expressions. If you have difficulty
decomposing complex temporal expressions, contact [email protected].

Examples of Analysis Capacity Overflow


The following types of temporal expressions may produce complexity beyond the capacity of the static
analysis:

• Multiple bounded repeats (such as [3], [..i] or [n..]) combined by the and or or temporal operator.
The complexity is much higher when using such a temporal expression within expect struct members,
fail or not temporal operators. For example:
[3] or [4] or [7] or [17]
expect @a => {[..i];@b} or {[..j];@c} or {[n..];@f}

• Nested sampling of multiple temporal expressions combined by temporal and operator. For example:
(@a and @b and @c and @d .. and @k) @q

• Use of long temporal sequence or complex nested sampling (as described above) in the match part
of a first-match repeat operator. For example:
{[..];(@a and @b and @c and @k) @q} @sys.any
Note There is no complexity issue if the repeat part and the match part are mutually exclusive. For
example:
{[..]*fail @a;(@a and @b and @c and @k)@q} @sys.any

13-10 e Language Reference


Temporal Expressions
Temporal Operators and Constructs

This may also hold when the match part uses a small constant in a simple repeat temporal
expression. For example:
{[..n]; [3] *@a}.

• Combinations of smaller examples of the above.

Examples of Limited Analysis Capability


The following types of temporal expressions are certain to produce complexity beyond the capabilities
of the static analysis:

• A bounded repeat (such as [m]) in the match expression of a first match repeat. For example:
{[..n]; [m] *@a}
Note There is no complexity issue if the repeat part and the match part are mutually exclusive. For
example:
{[..n] * fail @a ; [m] *@a}
There is no complexity issue if the match part uses a small constant bound in a simple repeat as
described in 1.c above. For example:
{[..n]; [2] *@a}

• A temporal expression that has multiple successes (such as @a or {@b;@b}) as the repeat expression
of a bounded first match repeat. For example:
{[..n]*{@a or {@b;@b}};@c}

• A true match repeat (such as (~[..m]*@a)) as the repeat expression of a bounded first match
repeat. For example:
{[..n]*(~[..m]*@a);@c}

• A bounded true match repeat in an expect struct member or with fail or not temporal operators. For
example:
not {~[..n]*{@a or {@b;@b}; @c}

13.2 Temporal Operators and Constructs


This section describes the constructs you can use in temporal expressions:

e Language Reference 13-11


Temporal Expressions
Precedence of Temporal Operators

• not on page 13-13 • detach on page 13-31


• fail on page 13-14 • delay on page 13-34
• and on page 13-16 • @ unary event operator on page
• or on page 13-19 13-35
• { exp ; exp } on page 13-21 • @ sampling operator on page 13-37
• eventually on page 13-23 • cycle on page 13-38
• [ exp ] on page 13-24 • true(exp) on page 13-40
• [ exp..exp ] on page 13-26 • change(exp), fall(exp), rise(exp) on
• ~[ exp..exp ] on page 13-28 page 13-41
• => on page 13-30 • consume on page 13-45
• exec on page 13-48

In addition, it describes:

• “Precedence of Temporal Operators” on page 13-12

See Also
• “Temporal Expressions Overview” on page 13-1

13.2.1 Precedence of Temporal Operators


The precedence of temporal operators is shown in Table 13-1, listed from highest precedence to lowest.

Table 13-1 Precedence of Temporal Operators

Operator Name Operator Example

named event @event-name

exec TE exec action-block


consume consume (@event-name)

repeat [ ] * TE

fail fail TE
not not TE

and TE1 and TE2

or TE1 or TE2

sequence {TE1 ; TE2}

13-12 e Language Reference


Temporal Expressions
not

Table 13-1 Precedence of Temporal Operators (continued)

Operator Name Operator Example

yield TE1 => TE2

sample event TE @ event-name

See Also
• “Temporal Expressions Overview” on page 13-1

13.2.2 not

Purpose
Temporal expression inversion operator

Category
Temporal expression

Syntax
not temporal-expression

Syntax Example
not {@ev_b;@ev_c}

Parameters

temporal-expression A temporal expression.

Description
The not temporal expression succeeds if the evaluation of the subexpression does not succeed during the
sampling period. Thus not TE succeeds on every occurrence of the sampling event if TE does not
succeed.

e Language Reference 13-13


Temporal Expressions
fail

Note
If an event is explicitly emitted (using emit on page 12-6), a race condition can arise between the event
occurrence and the not of the event when used in some temporal expression.

Example 1
In the following, the event ev_d occurs every time there is an occurrence of ev_c that is not preceded by
an occurrence of ev_a and then two consecutive occurrences of ev_b.
event ev_d is {not{ @ev_a; @ev_b; @ev_b}}; @ev_c} @clk;

See { exp ; exp } on page 13-21 for information about the “;” sequence operator.

Example 2
The fail operator (see fail on page 13-14) differs from the not operator. Figure 13-4 on page 13-16
illustrates the differences in behavior of not and fail for the sequence of ev_a, ev_b, and ev_c events
shown at the top of the figure. (See { exp ; exp } on page 13-21 for information about the “;” sequence
operator.)

See Also
• “Sampling Events Overview” on page 12-8
• fail on page 13-14
• “Temporal Operators and Constructs” on page 13-11

13.2.3 fail

Purpose
Temporal expression failure operator

Category
Temporal expression

Syntax
fail temporal-expression

13-14 e Language Reference


Temporal Expressions
fail

Syntax Example
fail{@ev_b; @ev_c}

Parameters

temporal-expression A temporal expression.

Description
A fail succeeds whenever the temporal expression fails. If the temporal expression has multiple
interpretations (for example, fail (TE1 or TE2)), the expression succeeds if and only if all the
interpretations fail.

The expression fail TE succeeds at the point where all possibilities to satisfy TE have been exhausted.
Any TE can fail at most once per sampling event.

Note
The not operator differs from the fail operator.

Example
The expression
fail {@ev_b;@ev_c}

succeeds for any of the following conditions:

• event ev_b does not occur in the first cycle


• ev_b succeeds in the first cycle, but event ev_c does not occur in the second cycle
Figure 13-4 on page 13-16 illustrates the differences in behavior of not and fail.

e Language Reference 13-15


Temporal Expressions
and

Figure 13-4 Comparison of Temporal not and fail Operators

@pclk

@ev_a

@ev_b

@ev_c

{@ev_b;@ev_c} @pclk

not{@ev_b;@ev_c} @pclk

fail{@ev_b;@ev_c} @pclk

{@ev_a; not{@ev_b;@ev_c}} @pclk

{@ev_a; fail{@ev_b;@ev_c}} @pclk

event emitted evaluation starts evaluation succeeds evaluation fails

See Also
• not on page 13-13
• “Temporal Operators and Constructs” on page 13-11

13.2.4 and

Purpose
Temporal expression and operator

13-16 e Language Reference


Temporal Expressions
and

Category
Temporal expression

Syntax
temporal-expression and temporal-expression

Syntax Example
(@TE1 and @TE2)@clk

Parameters

temporal-expression A temporal expression.

Description
The temporal and succeeds when both temporal expressions start evaluating in the same sampling
period, and succeed in the same sampling period.

Example 1
Evaluation of the and temporal expression:
event TE3 is (TE1 and TE2) @qclk

for the following conditions:

• Evaluation of both TE1 and TE2 begins on the first qclk. Both TE1 and TE2 succeed between the
second and third qclk so the event TE3 is emitted at the third qclk.
• The evaluations of TE1 and TE2 that begin on the fourth qclk eventually result in success of both
TE1 and TE2, but TE1 succeeds before the fifth qclk, and TE2 succeeds before the sixth qclk.
Therefore, TE1 and TE2 does not succeed.
• On the seventh qclk, evaluation of TE1 begins, and it succeeds before the eighth qclk. However, the
corresponding evaluation of TE2 fails during that period, so TE3 fails.

is shown in Figure 13-5 on page 13-18.

e Language Reference 13-17


Temporal Expressions
and

Figure 13-5 Example 1 of Temporal and Operator Behavior

1 2 3 4 5 6 7 8 9 10
qclk

TE1

TE2

(TE1 and TE2)@qclk

TE3

event emitted evaluation starts evaluation succeeds evaluation fails

Example 2
Evaluation of the and temporal expression:
event TE3 is (TE1 and TE2) @qclk

for the following conditions:

• TE1 and TE2 both start evaluating at the first qclk.


• TE1 and TE2 both succeed at the third qclk.
The and succeeds because both sides started evaluating at the same time and both succeeded at the
same time.
• TE1 starts evaluating at the fourth qclk.
• TE2 starts evaluating at the fifth qclk.
• TE1 and TE2 both succeed at the sixth qclk.
The and does not succeed because the two sides started evaluating at different time.

is shown in Figure 13-6 on page 13-19,

13-18 e Language Reference


Temporal Expressions
or

Figure 13-6 Example 2 of Temporal and Operator Behavior

1 2 3 4 5 6 7 8 9 10
qclk

TE1

TE2

(TE1 and TE2)@qclk

TE3

event emitted evaluation starts evaluation succeeds evaluation fails

See Also
• “Sampling Events Overview” on page 12-8
• “Temporal Operators and Constructs” on page 13-11

13.2.5 or

Purpose
Temporal expression or operator

Category
Temporal expression

Syntax
temporal-expression or temporal-expression

Syntax Example
(@TE1 or @TE2)@clk

e Language Reference 13-19


Temporal Expressions
or

Parameters

temporal-expression A temporal expression.

Description
The or temporal expression succeeds when either temporal expression succeeds.

An or operator creates a parallel evaluation for each of its subexpressions. It can create multiple
successes for a single temporal expression evaluation.

Example
Evaluation of the temporal or operator:
event TE3 is (@TE1 or @TE2) @qclk;

for the following conditions:

• Evaluation of both TE1 and TE2 begins on the first qclk, and succeed between the second and third
qclk, so TE1 or TE2 succeeds at the third qclk.
• The evaluations of TE1 and TE2 that begin on the fourth qclk result in success of TE2 before the
fifth qclk, so TE3 succeeds at the fifth qclk.
• Evaluation of TE1 or TE2 begins again at the seventh qclk, and TE1 succeeds before the ninth qclk,
so TE3 succeeds at the ninth qclk.

is shown in Figure 13-7 on page 13-21.

13-20 e Language Reference


Temporal Expressions
{ exp ; exp }

Figure 13-7 Example of Temporal or Operator Behavior

1 2 3 4 5 6 7 8 9 10
qclk

TE1

TE2

(TE1 or TE2) @qclk

TE3

event emitted evaluation starts evaluation succeeds evaluation fails

See Also
• “Sampling Events Overview” on page 12-8
• “Temporal Operators and Constructs” on page 13-11

13.2.6 { exp ; exp }

Purpose
Temporal expression sequence operator

Category
Temporal expression

Syntax
{temporal-expression; temporal-expression; …}

Syntax Example
{@ev_d; @ev_e} @ev_f

e Language Reference 13-21


Temporal Expressions
{ exp ; exp }

Parameters

temporal-expression A temporal expression.

Description
The semicolon (;) sequence operator evaluates a series of temporal expressions over successive
occurrences of a specified sampling event. Each temporal expression following a “;” starts evaluating in
the sampling period following that in which the preceding temporal expression succeeded. The sequence
succeeds whenever its final expression succeeds.

Note
Curly braces ({}) in the scope of a temporal expression define a sequence. They should not be used in
any other way.

Example
Figure 13-8 on page 13-22 shows the results of evaluating the temporal sequence:

{@ev_a; @ev_b; @ev_c} @qclk;

over the series of ev_a, ev_b, and ev_c events shown at the top of the figure. Evaluation of the sequence
starts whenever event ev_a occurs.

Figure 13-8 Example Evaluations of a Temporal Sequence

1 2 3 4 5
qclk

ev_a

ev_b

ev_c

{@ev_a;@ev_b;@ev_c}@qclk

event emitted evaluation starts evaluation succeeds evaluation fails

13-22 e Language Reference


Temporal Expressions
eventually

See Also
• “Sampling Events Overview” on page 12-8
• “Temporal Operators and Constructs” on page 13-11

13.2.7 eventually

Purpose
Temporal expression success check

Category
Temporal expression

Syntax
eventually temporal-expression

Syntax Example
{@ev_d; eventually @ev_e}

Parameters

temporal-expression A temporal expression.

Description
Used to indicate that the temporal expression should succeed at some unspecified time.

Typically, eventually is used in an expect struct member to specify that a temporal expression is
expected to succeed sometime before the quit event occurs for the struct.

Example
The following instance of the temporal yield operator (see => on page 13-30) succeeds after the event
ev_c occurs only if event ev_a occurs in the next cycle, and then event ev_b occurs sometime before the
example struct instance is terminated. See { exp ; exp } on page 13-21 for information about the “;”
sequence operator.
struct example {

e Language Reference 13-23


Temporal Expressions
[ exp ]

event ev_a;
event ev_b;
event ev_c;
expect @ev_c => {@ev_a; eventually @ev_b};
};

See Also
• The quit() Method of any_struct on page 22-36
• “Temporal Operators and Constructs” on page 13-11

13.2.8 [ exp ]

Purpose
Fixed repetition operator

Category
Temporal expression

Syntax
[exp] [* temporal-expression]

Syntax Example
wait [2]*cycle;

Parameters

exp A 32-bit, non-negative integer expression, which specifies the number of


times to repeat the evaluation of the temporal expression. This cannot
contain functions.

temporal-expression A temporal expression. If “* temporal-expression” is omitted, “* cycle” is


automatically used in its place.

13-24 e Language Reference


Temporal Expressions
[ exp ]

Description
Repetition of a temporal expression is frequently used to describe cyclic or periodic temporal behavior.
The [exp] fixed repeat operator specifies a fixed number of occurrences of the same temporal expression.

If the numeric expression evaluates to zero, the temporal expression succeeds immediately.

Examples
The {…;…} syntax used in the examples below specifies a temporal sequence. The expressions are
evaluated one after another, in consecutive sampling periods. See { exp ; exp } on page 13-21 for
information about the “;” sequence operator.

In the following example, the wait action proceeds after the sequence event ev_a, then three occurrences
of event ev_b, then event ev_c, all sampled at the default sampling event:
wait {@ev_a; [3]*@ev_b; @ev_c};

In the following example, the wait action proceeds after M+2 consecutive pclk cycles in which
sys.interrupt occurs. If there is a pclk cycle without a sys.interrupt, the count restarts from 0:
wait ([M+2] * @sys.interrupt)@pclk;

In the following example, the wait action proceeds on the occurrence of the ev_a event:
wait {@ev_a; [0]*@ev_b};

In the following example, the wait action proceeds five sampling event cycles after event ev_a:
wait {@ev_a; [5]};

The numeric expression cannot include any functions. The following two examples show how to
substitute temporary variables for functions in repeat expressions.

In a TCM, this is not legal:


wait [my_func()] * cycle; // illegal

To overcome this restriction, use a variable to hold the function value:


var t: int = my_func();
wait [t] * cycle;

In expect, assume or event struct members, this is not legal:


event my_ev is { @ev_a; [my_func()] } @clk; // illegal

In this situation, use a field to hold the function value and an exec expression to execute the function:
!temp: int;

e Language Reference 13-25


Temporal Expressions
[ exp..exp ]

event my_ev is { @ev_a exec {temp=my_func()}; [temp] } @clk;

See Also
• “Temporal Operators and Constructs” on page 13-11

13.2.9 [ exp..exp ]

Purpose
First match variable repeat operator

Category
Expression

Syntax
{ ... ; [[from-exp]..[to-exp] ] [* repeat-expression]; match-expression; ... }

Syntax Example
{[2..4]*@pclk;@reset}

Parameters

from-exp An optional non-negative 32 bit numeric expression that specifies the


minimum number of repetitions of the repeat-expression. If the from-exp is
missing, zero is used.

to-exp An optional non-negative 32 bit numeric expression that specifies the


maximum number of repetitions of the repeat-expression. If the to-exp is
missing, infinity is used.

repeat-expression The temporal expression that is to be repeated a certain number of times


within the from-exp..to-exp range. If the “*repeat-expression” is omitted,
“*cycle” is assumed.

match-expression The temporal expression to match.

13-26 e Language Reference


Temporal Expressions
[ exp..exp ]

Description
The first match repeat operator is only valid in a temporal sequence {TE; TE; TE}. The first match
repeat expression succeeds on the first success of the match-expression between the lower and upper
bounds specified for the repeat-expression.

First match repeat also enables specification of behavior over infinite sequences by allowing an infinite
number of repetitions of the repeat-expression to occur before the match-expression succeeds.

Where @ev_a is an event occurrence, {[..]*TE1;@ev_a} is equivalent to:

{@ev_a} or {[1]*TE1; @ev_a} or {[2]*TE1; @ev_a} or {[3]*TE1; @ev_a}…

Examples
The following examples all make use of the {...;...} syntax for sequence temporal expressions since the
first match repeat operator is only allowed inside a sequence. See { exp ; exp } on page 13-21 for
information about the “;” sequence operator.

In the following example, the wait action proceeds after the first occurrence of ev_a followed by ev_b at
pclk:
wait {[..]; {@ev_a; @ev_b}}@pclk

In the following example, the wait action proceeds after one or more occurrences of ev_a at consecutive
pclk events, followed by one occurrence of ev_b at the next pclk event:
wait {[1..]*@ev_a; @ev_b}@pclk

In the following example, the wait action proceeds after between zero and three occurrences of the
sequence {ev_a; ev_b} (sampled by pclk), followed by an occurrence of ev_c at the next pclk event:
wait {[..3]*{@ev_a; @ev_b}; @ev_c}@pclk

In the following example,


wait {@ev_a; [0..2]*@ev_b; @ev_c}@pclk

the wait action proceeds after any one of the three sequences sampled at consecutive sampling events:

• {@ev_a; @ev_c}
• {@ev_a; @ev_b; @ev_c}
• {@ev_a; @ev_b; @ev_b; @ev_c}

See Also
• ~[ exp..exp ] on page 13-28

e Language Reference 13-27


Temporal Expressions
~[ exp..exp ]

• cycle on page 13-38


• [ exp ] on page 13-24
• “Temporal Operators and Constructs” on page 13-11

13.2.10 ~[ exp..exp ]

Purpose
True match variable repeat operator

Category
Expression

Syntax
~[[from-exp]..[to-exp]] [* temporal-expression]

Syntax Example
~[2..4]*@pclk

Parameters

from-exp An optional non-negative 32 bit numeric expression that specifies the


minimum number of repetitions of the temporal expression. If the from-exp
is missing, zero is used.

to-exp An optional non-negative 32 bit numeric expression that specifies the


maximum number of repetitions of the temporal expression. If the to-exp is
missing, infinity is used.

temporal-expression The temporal expression that is to be repeated some number of times


within the from-expr..to-exp range. If “*temporal-expression” is omitted,
“* cycle” is assumed.

Description
You can use the true match repeat operator to specify a variable number of consecutive successes of a
temporal expression.

13-28 e Language Reference


Temporal Expressions
~[ exp..exp ]

True match variable repeat succeeds every time the subexpression succeeds. This expression creates a
number of parallel repeat evaluations within the range.

True match repeat also enables specification of behavior over infinite sequences by repeating an infinite
number of occurrences of a temporal expression. The expression ~[..]*TE is equivalent to:

[0] or [1]*TE or [2]*TE…

This construct is mainly useful for maintaining information about past events. See [ exp ] on page 13-24.

The following are examples of both forms of variable repeats, using implicit and explicit from - to range
expressions:

Example 1
In the examples below, the {...;...} syntax specifies a temporal sequence. See { exp ; exp } on page 13-21
for information about the “;” sequence operator.

The following temporal expression succeeds if A has occurred sometime during an earlier cycle:
{@A;~[..]}

The following temporal expression succeeds after any of the sequences {A}, {A; B}, {A; B; B}, or {A;
B; B; B}:
{@A;~[..3]*@B}

Example 2
The following temporal expression succeeds three pclk cycles after reset occurs, again at four pclk
cycles after reset, and again five pclk cycles after reset (with reset also sampled at pclk):
{@reset; ~[3..5]} @pclk

Example 3
The following temporal expression using the and temporal operator succeeds if A is followed at any
time by B, or if A and B both occur during the same initial cycle:
{@A; ~[..]} and {[..]; @B}
Note A more efficient way to write the above example is:
(@A and @B) or {@A; [..]; @B}

See Also
• [ exp..exp ] on page 13-26

e Language Reference 13-29


Temporal Expressions
=>

• cycle on page 13-38


• [ exp ] on page 13-24
• “Temporal Operators and Constructs” on page 13-11

13.2.11 =>

Purpose
Temporal yield operator

Category
Temporal expression

Syntax
temporal-expression1 => temporal-expression2

Syntax Example
@A => {[1..2]*@clk; @B}

Parameters

temporal-expression1 The first temporal expression. The second temporal expression is expected
to succeed if this expression succeeds.

temporal-expression2 The second temporal expression. If the first temporal expression succeeds,
this expression is also expected to succeed.

Description
The yield operator is used to assert that success of one temporal expression depends on the success of
another temporal expression. The yield expression TE1 => TE2 is equivalent to (fail TE1) or {TE1 ;
TE2}.

The yield expression succeeds without evaluating the second expression if the first expression fails. If
the first expression succeeds, then the second expression must succeed in sequence.

Yield is typically used in conjunction with the expect struct member to express temporal rules.

13-30 e Language Reference


Temporal Expressions
detach

The sampling event from the context applies to both sides of the yield operator expression. The entire
expression is essentially a single temporal expression, so that
(TE1 => TE2)@sampling_event

is effectively
(TE)@sampling_event

where TE is the temporal expression made up of TE1 => TE2.

Example
The following temporal expression succeeds if acknowledge occurs 1 to 100 cycles after request occurs.
(The {...;...} syntax specifies a temporal sequence. See { exp ; exp } on page 13-21 for information about
the “;” sequence operator).
expect @request => {[..99]; @acknowledge};

See Also
• expect | assume on page 14-3
• “Temporal Operators and Constructs” on page 13-11

13.2.12 detach

Purpose
Detach a temporal expression

Category
Temporal expression

Syntax
detach(temporal-expression)

Syntax Example
@trans.end => detach({@trans.start; ~[2..5]})@pclk

e Language Reference 13-31


Temporal Expressions
detach

Parameters

temporal-expression A temporal expression to be independently evaluated.

Description
A detached temporal expression is evaluated independently of the expression in which it is used. It starts
evaluation when the main expression does. Whenever the detached TE succeeds it emits an “implicit”
event which will only be recognized by the main TE. The detached temporal expression inherits the
sampling event from the main temporal expression.

Example 1
In the following example, both S1 and S2 start with @Q. However, the S1 temporal expression expects
E to follow Q, while the S2 temporal expression expects E to precede Q by one cycle.

The detach() construct causes the temporal expressions to be evaluated separately. As a result, the S3
temporal expression is equivalent to the S2 expression. See Figure 13-9.
struct s {
event pclk is @sys.pclk;
event Q;
event E;
event T is {@E; [2]} @pclk;
event S1 is {@Q; {@E; [2]}} @pclk;
event S2 is {@Q; @T} @pclk;
event S3 is {@Q; detach({@E; [2]})} @pclk;
};

13-32 e Language Reference


Temporal Expressions
detach

Figure 13-9 Examples Illustrating Detached Temporal Expressions

pclk

S1 is {@Q; {@E; [2]}}

T is {@E; [2]}

S2 is {@Q; @T}

S3 is {@Q; detach({@E; [2]})}

event emitted evaluation starts evaluation succeeds evaluation fails

Example 2
Since a detached expression is evaluated independently and in parallel with the main temporal
expression the two events below are not the same:
event ev_a is {@TE1; {@TE1; @TE2}};
event ev_b is {@TE1; detach({@TE1; @TE2})};

The first expression is equivalent to:


event ev_a is {@TE1; @TE1; @TE2};

While the second is equivalent to:


event ev_b is {@TE1; @ev_c};
event ev_c is {@TE1; @TE2};

Example 3
The following two expressions are equivalent:
fail detach({@ev_a; @ev_b})
not({@ev_a; @ev_b})

e Language Reference 13-33


Temporal Expressions
delay

See Also
• “Temporal Operators and Constructs” on page 13-11

13.2.13 delay

Purpose
Specify a simulation time delay

Category
Temporal expression

Syntax
delay(int: exp)

Syntax Example
wait delay(3);

Parameters

int An integer expression or time expression no larger than 64 bits. The number
specifies the amount of simulation time to delay. The time units are in the
timescale used in the HDL simulator.

Description
Succeeds after a specified simulation time delay elapses. A callback to Specman occurs after the
specified time. A delay of zero succeeds immediately.

Attaching a sampling event to delay has no effect. The delay ignores the sampling event and succeeds
as soon as the delay period elapses.

Note
• This expression is not legal in standalone mode. It can only be used if Specman is being run with an
attached HDL simulator.
• The delay temporal expression is only supported for the cases:

13-34 e Language Reference


Temporal Expressions
@ unary event operator

wait delay(x);
event e is {@a;delay(x)};

Example 1
The following specifies a delay of 20 simulator time units:
wait delay(20);

Example 2
The following specifies a delay of df*5 simulator time units:
wait delay(df*5);

Example 3
The following use of the delay expression generates an error:
// event del_b is {@set_a; delay(10)} @clk; // Load-time error

See Also
• wait on page 15-4
• verilog time on page 17-14
• vhdl time on page 17-51
• “Temporal Operators and Constructs” on page 13-11

13.2.14 @ unary event operator

Purpose
Use an event as a temporal expression

Category
Temporal expression

e Language Reference 13-35


Temporal Expressions
@ unary event operator

Syntax
@[struct-exp.]event-type

Syntax Example
wait @rst;

Parameters

struct-exp.event-type The name of an event. This can be either a predefined event or a


user-defined event, optionally including the name of the struct instance
in which the event is defined.

Description
An event can be used as the simplest form of a temporal expression. The temporal expression
@event-type succeeds every time the event occurs. Success of the expression is simultaneous with the
occurrence of the event.

The struct-exp is an expression that evaluates to the struct instance that contains the event instance. If no
struct expression is specified, the default is the current struct instance.

Note
If a struct expression is included in the event name, the value of the struct expression must not change
throughout the evaluation of the temporal expression.

Examples
In the following, pclk is a temporal expression:
@pclk

The predefined sys.any event occurs at every Specman tick. As a sampling event, use it as follows:
@sys.any

See Also
• event on page 12-4
• “Predefined Events Overview” on page 12-10
• “Temporal Operators and Constructs” on page 13-11

13-36 e Language Reference


Temporal Expressions
@ sampling operator

13.2.15 @ sampling operator

Purpose
Specify a sampling event for a temporal expression

Category
Temporal expression

Syntax
temporal-expression @event-name

Syntax Example
wait cycle @sys.reset;

Parameters

temporal-expression A temporal expression.

event-name The sampling event.

Description
Used to specify the sampling event for a temporal expression. The specified sampling event overrides
the default sampling event.

Every temporal expression has a sampling event. The sampling event applies to all subexpressions of the
temporal expression. It can be overridden for a subexpression by attaching a different sampling event to
the subexpression.

A sampled temporal expression succeeds when its sampling event occurs with or after the success of the
temporal expression.

The sampling event for a temporal expression is one of the following, in decreasing precedence order:

1. For any expression or subexpression, a sampling event specified with the @ binary event operator.

2. For a subexpression, the sampling event inherited from its parent expression.

3. For an expression in a TCM, the default sampling event of the TCM.

4. If none of the above applies, the predefined sys.any event.

e Language Reference 13-37


Temporal Expressions
cycle

Examples
The reset event is sampled at the pclk event:
@reset @pclk

The reset event is sampled by the predefined sys.any event:


@reset @sys.any

Event ev_a occurs when the reset event occurs, sampled at the rclk event:
event ev_a is @reset @rclk;

The following is the same as event ev_b is @reset @sys.any:


event e_b is @reset;

See Also
• true(exp) on page 13-40
• event on page 12-4
• “Predefined Events Overview” on page 12-10
• “Sampling Events Overview” on page 12-8
• “Temporal Operators and Constructs” on page 13-11

13.2.16 cycle

Purpose
Specify an occurrence of a sampling event

Category
Temporal expression

Syntax
cycle

Syntax Example
wait cycle;

13-38 e Language Reference


Temporal Expressions
cycle

Description
Represents one cycle of some sampling event. With no explicit sampling event specified, this represents
one cycle of the sampling event from the context (that is, the sampling event from the overall temporal
expression, or the sampling event for the TCM that contains the temporal expression). When a sampling
event is specified, as in cycle@sampling-event, this is equivalent to @sampling-event@sampling-event.

In the following, the event named sys.pclk is the sampling event for the TCM named proc(). The wait
cycle action is the same as wait @sys.pclk.
proc() @sys.pclk is { wait cycle; };

Example 1
The following event definition replicates sys.clk as the local clk for the struct:
event clk is cycle @sys.clk;

This is equivalent to “event clk is @sys.clk @sys.clk”. It is also equivalent to “event clk is @sys.clk”.

Example 2
The following expression succeeds as soon as ev_a occurs:
m_tcm() @ev_s is {
wait cycle @ev_a;
out("Done");
};

See Also
• event on page 12-4
• “Predefined Events Overview” on page 12-10
• “Sampling Events Overview” on page 12-8
• @ sampling operator on page 13-37
• “Temporal Operators and Constructs” on page 13-11

e Language Reference 13-39


Temporal Expressions
true(exp)

13.2.17 true(exp)

Purpose
Boolean temporal expression

Category
Temporal expression

Syntax
true(bool: exp)

Syntax Example
event rst is true(reset == 1) @clk;

Parameters

bool A Boolean expression.

Description
Use a Boolean expression as a temporal expression. Each occurrence of the sampling event causes an
evaluation of the Boolean expression. The Boolean expression is evaluated only at the sampling point.

The temporal expression succeeds each time the expression evaluates to TRUE.

Note
The expression exp will be evaluated after pclk. Changes in exp after true(exp) @pclk has been
evaluated will be ignored.

Example 1
The following causes the TCM to suspend until reset is high. The condition is checked for the first time
at the first occurrence of clk after the wait is encountered; it is then checked every clk cycle after that.
See wait on page 15-4.
notify_reset() @clk is {
wait true(reset == 1);
out("reset is 1");

13-40 e Language Reference


Temporal Expressions
change(exp), fall(exp), rise(exp)

};

Example 2
The temporal expression below succeeds when the Boolean condition sys.number_of_packets == 5
evaluates to TRUE at the default sampling event. Execution of the TCM containing the wait action
suspends until the Boolean condition is true.
wait true(sys.number_of_packets == 5);

See Also
• Boolean scalar type in “Scalar Types” on page 3-2
• “Sampling Events Overview” on page 12-8
• “Temporal Operators and Constructs” on page 13-11

13.2.18 change(exp), fall(exp), rise(exp)

Purpose
Transition or edge temporal expression

Category
Temporal expression

Syntax
change | fall | rise(scalar: exp) [@event-type]

change | fall | rise(’HDL-pathname’) @sim

Syntax Example
event hv_c is change('top.hold_var')@sim;

Parameters

scalar A Boolean expression or an integer expression.

e Language Reference 13-41


Temporal Expressions
change(exp), fall(exp), rise(exp)

event-type The sampling event for the expression.

’HDL-pathname’ An HDL object enclosed in single quotes (' ').

@sim A special annotation used to detect changes in HDL signals.

Description
Detects a change in the sampled value of an expression.

The behavior of each of the three temporal expressions (change, fall, and rise) is described in Table 13-2
on page 13-42.

Table 13-2 Edge Condition Options

Edge Condition Meaning

rise(exp) Triggered when the expression changes from FALSE to TRUE. If it is an


integer expression, the rise() temporal expression succeeds upon any change
from x to y>x. Signals wider than one bit are allowed. Integers larger than 32
bits are not allowed.

fall(exp) Triggered when the expression changes from TRUE to FALSE. If it is an


integer expression, the fall() temporal expression succeeds upon any change
from x to y<x. Signals wider than one bit are allowed. Integers larger than 32
bits are not allowed.

change(exp) Triggered when the value of the expression changes. The change() temporal
expression succeeds upon any change of the expression. Signals wider than
one bit are allowed. Integers larger than 32 bits are not allowed.

The expression is evaluated at each occurrence of the sampling event, and is compared to the value it had
at the previous sampling point. Only the values at sampling points are detected. The value of the
expression between sampling points is invisible to the temporal expression.

A special notation, @sim, can be used in place of a sampling event for rise, fall, or change of HDL
objects. If @sim is used, the HDL object is watched by the simulator. The @sim notation does not
signify a Specman event, but is used only to cause a callback to Specman any time there is a change in
the value of the HDL object to which it is attached.

When a sampling event other than @sim is used, changes to the HDL object are detected only if they are
visible at the sampling rate of the sampling event. In Figure 13-10 on page 13-43, evaluations of rise,
fall, and change expressions for the HDL signal V are shown, with the sampling event @sim and with
the sampling event @qclk. The qclk event is an arbitrary event that is emitted at the indicated points.

13-42 e Language Reference


Temporal Expressions
change(exp), fall(exp), rise(exp)

The V signal rises and then falls between the second and third occurrences of event qclk. Since the
signal’s value is the same at the third qclk event as it was at the second qclk event, the
change('V')@qclk expression does not succeed at the third qclk event.

Figure 13-10 Effects of the Sampling Rate on Detecting HDL Object Changes

'V'

change('V')@sim

rise('V')@sim

fall('V')@sim

qclk

change('V')@qclk

rise('V')@qclk

fall('V')@qclk

When applied to HDL variables, the expressions examine the value after each bit is translated from the
HDL four-value or nine-value logic representation to the Specman two-value logic representation. Table
13-3 on page 13-43 describes the default translation of HDL values to Specman values. The ‘@x’
and ‘@z’ HDL value modifiers can be used to override the default translation.

Table 13-3 Transition of HDL Values

HDL Values Specman Value

0, X, U, W, L, - 0

1, Z, H 1

In TCMs it is preferred to use change()@sim, rise()@sim, and fall()@sim temporal expressions in a


sync action rather than a wait action. When used in a sync action, the monitoring of changes in signal
value begins immediately and includes changes in subsequent delta cycles in the current simulation
time. When used in a wait action, the monitoring of changes in signal value begins in the next simulation
time. In both actions, the initial value of the signal is sampled as soon as the sync or wait action is
reached.

For example, if a TCM uses


sync rise('my_sig')@sim;

e Language Reference 13-43


Temporal Expressions
change(exp), fall(exp), rise(exp)

and if the value of 'my_sig' falls in a later delta-cycle of the same simulation time as the sync action is
reached, Specman records the change of the value and could observe a rise in the following simulation
time.

However if the TCM uses


sync wait('my_sig')@sim;

and the value of a signal 'my_sig' falls in a later delta-cycle of the same simulation time as the wait
action is reached, this fall is not observed by the temporal expression. Consequently, the next rise of the
value of the 'my_sig' signal is ignored by the temporal expression as a change in the signal value that did
not rise with respect to the signal's value at the time the wait action was reached.

Notes
• You can use the === operator to detect a change between two-state and four-state logic, as in the
following:
change('top.hold_var' === two_state_hold_var)@clk;

• Specman ignores glitches that occur in a single simulation time slot. Only the first occurrence of a
particular monitored event in a single simulation time slot is recognized by Specman. For example,
if a signal transitions from 0 to 1 and back to 0 in the same time slot, Specman sees only the 0 to 1
transition; the 1 to 0 transition is ignored. For information on how to handle glitches, see “Simulation
Time and Specman Ticks” on page 12-14.

Examples
The following defines an event that occurs at any change in the value of an HDL signal named top.clk:
event clk_c is change('top.clk')@sim;

The following defines an event that occurs when the Boolean expression pkt_size > 20 changes from
FALSE to TRUE:
event big_pkt is rise(pkt.size > 20);

The following defines an event that occurs at a fall in the value of an HDL signal named ~/top/reset,
sampled by an event named rsmp:
event rst is fall('~/top/reset')@rsmp;

See Also
• “Sampling Events Overview” on page 12-8
• “Using HDL Objects in Temporal Expressions” on page 13-5

13-44 e Language Reference


Temporal Expressions
consume

• “'HDL-pathname'” on page 17-65


• “Reading and Writing HDL Objects” on page 8-21 in the Specman Elite Integrator’s Guide
• “Temporal Operators and Constructs” on page 13-11

13.2.19 consume

Purpose
Consume an occurrence of an event

Category
Temporal expression

Syntax
consume(@event-type)

Syntax Example
sync consume(@counter);
wait consume(@done)@sys.any;

Parameters

event-type The name of the event that is to be consumed.

Description
Removes the occurrence of an event so that it is not available for other temporal expressions. The
consume expression succeeds whenever the event occurs. If the event occurs more than once during any
given cycle, all occurrences are consumed.

After an event occurrence is consumed, that occurrence will not be recognized by any temporal
expression during the current Specman tick, unless the event is emitted again.

An event cannot be consumed by more then one consume expression. Care should be used to avoid
creating race conditions between multiple events that use an event that is consumed.

e Language Reference 13-45


Temporal Expressions
consume

Notes
• The consume(@event-type) temporal expression can only be used in one of the following time
consuming actions:
sync consume(@event-type) [@sampling_event];
wait consume(@event-type) [@sampling_event];
When an optional sampling event is specified, then the sync or wait action finishes with the first
occurrence of the sampling event after the consume succeeds.
If no sampling event is specified, the default sampling event of the TCM applies.
• An event can either be used in a consume(@event-type) expression or be used in another temporal
expression, but not in both.

Example
The following code shows how you can use consume() to handle concurrent requests from multiple
clients in an orderly manner.

The example enables the following behaviors:

• The requests are granted on a First-In-First-Out basis.


• A client may hold the grant for several Specman cycles.
• The server can accumulate requests during several Specman cycles.
• Multiple clients requests can be granted sequentially at the same Specman time.
In this example there are four client structs and one server struct. The server ensures that all requests are
granted and that there are no simultaneous grants.

When multiple clients issue a request at the same time the server is using a counter to keep track of the
number of requests. The server consumes all the requests, and then issues a grant event. The first client
to issue a request consumes the grant, making it unavailable to the other clients. When this client is done
with the grant it issues a done event. The server consumes the done event and issues a release event. The
release event is consumed by the client. The server repeats this process until the request counter is zero.
<'
struct server {
event clk is rise('top.clock');
event request;
event grant;
event done;
event release;
!req_counter: int;
on request {

13-46 e Language Reference


Temporal Expressions
consume

req_counter += 1;
out("req_counter = ", req_counter);
};
serv() @clk is {
while TRUE {
if (req_counter == 0 || now @request) {
sync consume(@request);
out("Requests consumed...");
};
req_counter -= 1;
emit grant;
sync consume(@done);
emit release;
};
};

run() is also {start serv();};


};
struct client {
id: string;
s: server;
handshake() @s.clk is { // Zero delay handshake
out(id, ": Starting handshake at time ", sys.time);
emit s.request;
sync consume(@s.grant);
out(id, ": Granted, releasing");
emit s.done;
sync consume(@s.release);
};

run() is also {start handshake();};


};

extend sys {
event clk;

s: server;
c1: client; keep { c1.s==s; c1.id=="client 1" };
c2: client; keep { c2.s==s; c2.id=="client 2" };
c3: client; keep { c3.s==s; c3.id=="client 3" };
c4: client; keep { c4.s==s; c4.id=="client 4" };

go()@any is {
for i from 0 to 40 do {
wait cycle;
emit clk;
};

e Language Reference 13-47


Temporal Expressions
exec

stop_run();
};

run() is also {start go()};


};
'>

Result
Running the test ...
client 1: Starting handshake at time 1
req_counter = 1
client 2: Starting handshake at time 1
req_counter = 2
client 3: Starting handshake at time 1
req_counter = 3
client 4: Starting handshake at time 1
req_counter = 4
Requests consumed...
client 1: Granted, releasing
client 2: Granted, releasing
client 3: Granted, releasing
client 4: Granted, releasing
Last specman tick - stop_run() was called
Normal stop - stop_run() is completed

See Also
• event on page 12-4
• “Temporal Operators and Constructs” on page 13-11

13.2.20 exec

Purpose
Attach an action block to a temporal expression

Category
Temporal expression side effect

13-48 e Language Reference


Temporal Expressions
exec

Syntax
temporal-expression exec action; ...

Syntax Example
wait @watcher_on exec {print watcher_status_1;};

Parameters

temporal-expression The temporal expression that invokes the action block.

action A series of actions to perform when the expression succeeds.

Description
Invokes an action block when a temporal expression succeeds. The actions are executed immediately
upon the success of the expression, but not more than once per Specman tick.

To support extensibility of your e code, use method calls in the exec action block rather than calling the
actions directly.

The usage of exec is similar to the on struct member, except that:

• Any temporal expression can be used as the condition for exec, while only an event can be used as
the condition for on.
• exec must be used in the context of a temporal expression in a TCM or an event definition, while on
can only be a struct member.

You cannot attach an exec action to a first match variable repeat expression:
([7..10] *@b) exec {out("in exec")} -- is not allowed

However, you can attach an exec action to the repeat expression of a first match variable repeat
expression as follows:
[7..10] *@b exec {out("in exec")} -- is allowed
[7..10] * (@b exec {out("in exec")}) -- is allowed
Note The two expressions above are equivalent. They will both execute the exec action once for each
occurrence of b.

An exec action cannot be attached to an implicit repeat expression:


expect @e => {
[..20]; -- exec is not allowed here
@a;

e Language Reference 13-49


Temporal Expressions
exec

};

You must make the implicit repeat expression explicit in order to attach an exec action:
expect @e => {
[..20] * (cycle exec {out("in exec")}); -- is allowed
@a;
};

Note
• The action block cannot contain any time-consuming actions.

Example
The following code maintains a pipeline of instruction instances.
struct pipelined_alu {
instructions: list of inst;
ck_inst: inst;
event alu_watcher is {
rise('inst_start') exec {
var i: inst = new;
instructions.add(i);
};
[..];
rise('inst_end') exec {
ck_inst = instructions.pop()
}
}@sys.alu.aclk;
};

See Also
• Action blocks, described in “Actions” on page 2-16
• on on page 14-1
• “Temporal Operators and Constructs” on page 13-11

13-50 e Language Reference


14 Temporal Struct Members
In addition to the event struct member (see event on page 12-4), there are two struct members used for
temporal coding. These struct members are described in this chapter:

• on on page 14-1
• expect | assume on page 14-3

See Also
• “Invoking Methods” on page 7-22
• Chapter 12 “Events”
• Chapter 13 “Temporal Expressions”
• Chapter 15 “Time-Consuming Actions”

14.1 on

Purpose
Specify a block of actions that execute on an event

Category
Struct member

e Language Reference 14-1


Temporal Struct Members
on

Syntax
on event-type {action; …}

Syntax Example
on xmit_ready {transmit();};

Parameters

event-type The name of an event that invokes the action block.

action; … A block of non-time-consuming actions.

Description
Defines a struct member that executes a block of actions immediately whenever a specified event
occurs. An on struct member is similar to a regular method except that the action block for an on struct
member is invoked immediately upon an occurrence of the event. An on action block is executed before
TCMs waiting for the same event.

The on action block is invoked every time the event occurs. The actions are executed in the order in
which they appear in the action block.

You can extend an on struct member by repeating its declaration, with a different action block. This has
the same effect as using is also to extend a method.

The on struct member is implemented as a method, named on_event-type(). You can invoke the action
block without the occurrence of the event by calling the on_event-type() method. You can extend the
on_event-type() method like any other method, using is, is also, is only, or is first.

Notes
• The named event must be local to the struct in which the on is defined.
• The on action block must not contain any time-consuming actions.

Example 1
struct cnt_e {
event ready;
event start_count;
on ready {sys.req = 0};
on start_count {
sys.count = 0;
sys.counting = 1;

14-2 e Language Reference


Temporal Struct Members
expect | assume

out("Starting to count");
};
};

Example 2
The following example shows how to invoke an on action block with an event that is defined in a
different struct, by defining a local event that uses the nonlocal event as its temporal expression.
<'
extend sys {
event global_clk is change('top.clk') @sim;
// system clock
card_i: card;
};
struct card {
event clk is cycle @sys.global_clk;
// replicates the global
on clk { // clock locally
out("local clock tick");
};
};
'>

See Also
• event on page 12-4
• Action block, in “Actions” on page 2-16
• method [@event] is also | first | only | inline only on page 7-12

14.2 expect | assume

Purpose
Define a temporal behavioral rule

Category
Struct member

e Language Reference 14-3


Temporal Struct Members
expect | assume

Syntax
expect | assume [rule-name is [only]] temporal-expression
[else dut_error(string-exp)]

or

expect | assume rule-name

Syntax Example
expect @a => {[1..5];@b} @clk;

Parameters

rule-name An optional name that uniquely identifies the rule from other rules or events
within the struct. You can use this name to override the temporal rule later
on in the code or change from expect to assume or vice versa.

temporal-expression A temporal expression that is always expected to succeed. Typically


involves a temporal yield (=>) operation.

string-exp A string or a method that returns a string. If the temporal expression fails,
the string is printed, or the method is executed and its result is printed.

Description
Both the expect and assume struct members define temporal rules. If the temporal expression fails at its
sampling event, the temporal rule is violated and an error is reported. If there is no dut_error() clause,
the rule name is printed.

If you are not using Specman linked with a formal verification tool, you can use expect and assume
interchangeably to define temporal rules with no difference in behavior.

When using Specman linked with a formal verification (FV) tool, you can use assume to identify
temporal sequences that the FV tool must not apply to the DUT. Use expect to identify temporal
sequences that the FV tool must verify. In this manner, you avoid applying illegal inputs to the DUT and
you improve the performance of the FV tool by requiring it to verify only a subset of the temporal rules
defined.

Once a rule has been defined, it can be modified using the is only syntax and it can be changed from an
expect to an assume or vice versa. You can perform multiple verification runs either varying the rules
slightly or using the same set of rules in different expect/assume combinations. See the examples below
for information on how to do this.

14-4 e Language Reference


Temporal Struct Members
expect | assume

Note
The is also, is undefined, and is empty forms are not supported for this construct.

Example 1
This example defines an expect, “bus_cycle_length”, which requires that the length of the bus cycle be
no longer than 1000 cycles.
struct bus_e {
event bus_clk is change('top.b_clk') @sim;
event transmit_start is rise('top.trans') @bus_clk;
event transmit_end is rise('top.transmit_done') @bus_clk;
event bus_cycle_length;
expect bus_cycle_length is
@transmit_start => {[0..999];@transmit_end} @bus_clk
else dut_error("Bus cycle did not end in 1000 cycles");
};

Result
If the bus cycle is longer than 1000 cycles, the following message will be issued.
-------------------------------------------------------
*** Dut error at time 1000
Checked at line 7 in @expect_msg
In bus_e-@0:

bus_cycle_length: Bus cycle did not end in 1000 cycles


-------------------------------------------------------
Will stop execution immediately (check effect is ERROR)

*** Error: A Dut error has occurred

Example 2
In this example, the “bus_e” struct from “Example 1” on page 14-5 is extended and two subtypes are
created, “Slow” and “Fast”. For the “Fast” subtype, the bus_cycle_length is modified to be shorter. e
inheritance allows subtypes to override rules defined in the base struct using the is only syntax.
extend bus_e {
type: [Slow, Fast];
when Fast bus_e {
expect bus_cycle_length is only
@transmit_start => {[0..99]; @transmit_end} @bus_clk
else dut_error("Bus cycle did not end \

e Language Reference 14-5


Temporal Struct Members
expect | assume

within 100 cycles");


};
};

Example 3
In this example, the “bus_e” struct from “Example 1” on page 14-5 and “Example 2” on page 14-5 is
extended. The bus cycle rule is changed from an expect rule to an assume rule.
<'
struct bus_e {
event bus_clk is change('top.b_clk') @sim;
event transmit_start is rise('top.trans') @bus_clk;
event transmit_end is rise('top.transmit_done') @bus_clk;
expect bus_cycle_length is
@transmit_start => {[0..999];@transmit_end} @bus_clk
else dut_error("Bus cycle did not end in 1000 cycles");
};
extend bus_e {
assume bus_cycle_length;
};
extend sys {
bus_e;
};
'>

Example 4
In the following example, two expect statements are used to specify that the “transmit_end” event must
occur within three to six “bus_clk” cycles after the “transmit_start” event. If fewer than three cycles
occur, the “DRV_SHORT” err_id is passed to the “m_error()” method. If more than six cycles occur, the
“DRV_LONG” err_id is passed to the method. The “m_error()” method adds one to the “error_count”
value, and returns a string that states which type of error occurred.
<'
type watcher_errors :[DRV_LONG, DRV_SHORT];
// Enumerated error conditions

extend sys {
event clk is @sys.any;
event start_drive;
event stop_drive;
!error_count: int; // Counts number of errors
my_watcher: watcher;
};

struct watcher {

14-6 e Language Reference


Temporal Struct Members
expect | assume

expect @sys.start_drive =>


[2] * not @sys.stop_drive @sys.clk
else dut_error("Drive Rule 1: ",
m_error(DRV_SHORT));
expect @sys.start_drive =>
{[..5];@sys.stop_drive}@sys.clk
else dut_error("Drive Rule 1: ",
m_error(DRV_LONG));
m_error(err_id: watcher_errors):string is {
case err_id {
DRV_LONG: {
result = "Driving strobe too long";
sys.error_count += 1;
};
DRV_SHORT: {
result = "Driving strobe too short";
sys.error_count += 1;
};
default: { result = "No error"; };
};
};
};
'>

See Also
• Chapter 13 “Temporal Expressions”, in particular, => on page 13-30

e Language Reference 14-7


Temporal Struct Members
expect | assume

14-8 e Language Reference


15 Time-Consuming Actions
This chapter contains the following sections:

• “Synchronization Actions” on page 15-1


• “Concurrency Actions” on page 15-6

See Also
• “Invoking Methods” on page 7-22
• Chapter 12 “Events”
• Chapter 13 “Temporal Expressions”
• Chapter 14 “Temporal Struct Members”

15.1 Synchronization Actions


The following actions are used to synchronize temporal test activities within Specman and between the
DUT and Specman:

• sync on page 15-1


• wait on page 15-4

15.1.1 sync

Purpose
Synchronize an executing TCM

e Language Reference 15-1


Time-Consuming Actions
sync

Category
Action

Syntax
sync [temporal-expression]

Syntax Example
sent_data_tcm();
sync;

Parameters

temporal-expression A temporal expression that specifies what the TCM synchronizes to.

Description
Suspends execution of the current TCM until the temporal expression succeeds. Evaluation of the
temporal expression starts immediately when the sync action is reached. If the temporal expression
succeeds within the current Specman tick, the execution continues immediately.

If no temporal expression is provided, the TCM synchronizes to its default sampling event. The TCM
suspends until the occurrence of its sampling event, or continues immediately if the sampling event
succeeds in the current Specman tick.

You can use the sync action after a call to another TCM to align the continuation of the calling TCM
with its sampling event when the called TCM returns.

Execution of a thread is atomic: it cannot be interrupted except by a sync action or a wait action. When
one of those actions is encountered, control can be passed from the TCM to other TCMs.

The sync action is similar to the wait action, except that a wait action always requires at least one cycle
of the TCM’s sampling event before execution can continue. With a sync action, execution can continue
in the same Specman tick.

Example
In the following example, the wait action in the “driver()” TCM causes at least a one-cycle delay, since
the true() temporal expression is evaluated for the first time at the next occurrence of the sampling
event. The wait consumes one occurrence of the “clk” event, and then execution of the TCM continues
at the second occurrence of “clk”.

15-2 e Language Reference


Time-Consuming Actions
sync

On the other hand, the sync action in the “shadow()” TCM does not result in a delay if its true temporal
expression succeeds immediately. Execution of the TCM continues at the next occurrence of the “clk”
event.
<'
struct data_drive {
event clk is rise('top.clk') @sim;
data: list of int;
driver() @clk is {
for each in data {
wait true('top.data_ready'== 1);
// Will not fall through, even if the condition
// holds when the wait is reached.
'top.in_reg' = it;
};
stop_run();
};
shadow() @clk is {
while TRUE {
sync true('top.data_ready' == 0);
// If the condition holds, the sync falls through.
out("Shadow read ", 'top.in_reg');
wait cycle;
// This wait is necessary to prevent
// an infinite loop.
};
};
run() is also {
start driver();
start shadow();
};
};
'>

See Also
• event on page 12-4
• “Sampling Events Overview” on page 12-8
• Chapter 13 “Temporal Expressions”
• wait on page 15-4

e Language Reference 15-3


Time-Consuming Actions
wait

15.1.2 wait

Purpose
Wait until a temporal expression succeeds

Category
Action

Syntax
wait [[until] temporal-expression]

Syntax Example
wait [3]*cycle;

Parameters

temporal-expression A temporal expression that specifies what the TCM is to wait for.

Description
Suspend execution of the current time-consuming method until a given temporal expression succeeds. If
no temporal expression is provided, the TCM waits for its default sampling event. The until option is for
users who find that it clarifies what the wait action does. The option has no effect on the results of the
action.

When a VHDL or Verilog simulator is linked to Specman, the syntax wait delay(exp) can be used to
wait for a specific simulation time period. Because not all simulators support delay values greater than
32 bits, the value of the expression in wait delay(exp) cannot exceed 32 bits. A wait delay(exp) is
influenced by the timescale. See verilog time on page 17-14 and vhdl time on page 17-51 for more
information on how Specman determines the timescale.

The TCM cannot continue during the same cycle in which it reaches a wait, unless the temporal
expression evaluates to 0. That is, if the temporal expression evaluates to “[0] * something”, execution
can continue in the same cycle.

If the wait action’s temporal expression contains a variable subexpression, such as “wait [var1 + var2] *
cycle”, the subexpression is only evaluated once, when the wait is encountered. Any changes in the
value of the subexpression during subsequent cycles are ignored.

15-4 e Language Reference


Time-Consuming Actions
wait

Execution of a thread is atomic: it cannot be interrupted except by a wait action or a sync action. When
one of those actions is encountered, control can be passed from the TCM to other TCMs.

The wait action is similar to the sync action, except that a wait action always requires at least one cycle
of the TCM’s sampling event before execution can continue (unless a wait of zero is specified). With a
sync action, execution can continue immediately upon encountering the sync, if the temporal expression
succeeds at that time See“sync” on page 15-1 for an example comparing the behavior of sync and wait.

Note
The cycle-based simulator SpeedSim does not support the wait delay(exp) action.

Example 1
Several examples of temporal expressions for wait actions are shown below:
wait [3]*cycle;
// Continue on the fourth cycle from now
wait delay(30);
// Wait 30 simulator time units
wait [var1 + var2]*cycle;
// Calculate the number of cycles to wait
wait until [var1 + var2]*cycle;
// Same as wait [var1 + var2]*cycle
wait true(sys.time >= 200);
// Continue when sys.time is greater than or equal to 200
wait cycle @sys.reset;
// Continue on reset even if it is not synchronous with
// the TCMs default sampling event
wait @sys.reset;
// Continue on the next default sampling event after reset

Example 2
In the following example, the wait action in the “driver()” TCM causes a one-cycle delay even if the
true temporal expression succeeds immediately. The wait consumes one occurrence of the “clk” event,
and then execution of the TCM continues at the second occurrence of “clk”.
<'
struct data_drive {
event clk is rise('top.clk') @sim;
data: list of int;
driver() @clk is {
for each in data {
wait true('top.data_ready'== 1);

e Language Reference 15-5


Time-Consuming Actions
Concurrency Actions

'top.in_reg' = it;
};
stop_run();
};
run() is also {
start driver();
};
};
'>

See Also
• event on page 12-4
• “Sampling Events Overview” on page 12-8
• Chapter 13 “Temporal Expressions”
• sync on page 15-1

15.2 Concurrency Actions


The actions that control concurrent execution of time-consuming methods are described in this section:

• all of on page 15-6


• first of on page 15-8
Both of these actions create parallel action blocks which might start or call TCMs. The first action
awaits completion of all “branches”, while the second terminates at the first completion of any “branch”.

Control of individual branches or TCMs can also be accomplished using predefined methods of the
predefined scheduler struct.

15.2.1 all of

Purpose
Execute action blocks in parallel

Category
Action

15-6 e Language Reference


Time-Consuming Actions
all of

Syntax
all of {{action; …}; … }

Syntax Example
all of { {block_a}; {block_b}; };

Parameters

{action; …}; … Action blocks that are to execute concurrently. Each action block is a separate
branch.

Description
Execute multiple action blocks concurrently, as separate branches of a fork. The action following the all
of action will be reached only when all branches of the all of have been fully executed. All branches of
the fork are automatically joined at the termination of the all of action block.

Example 1
Execute the following three TCMs concurrently, and continue after they all have finished:
all of {
{check_bus_controller();};
{check_memory_controller();};
{wait cycle; check_alu();};
};

Example 2
The all of construct can be used to wait for several events, no matter what order they arrive in. This can
be used as an AND relation between events as shown below.
<'
extend sys {
event aclk is @any;
event a;
event b;
detect_all() @aclk is {
all of {
{ wait @a; };
{ wait @b; };
};
out("Both a and b occurred");

e Language Reference 15-7


Time-Consuming Actions
first of

};
};
'>

See Also
• first of on page 15-8

15.2.2 first of

Purpose
Execute action blocks in parallel

Category
Action

Syntax
first of {{action; …}; … }

Syntax Example
first of { {wait [3]*cycle@ev_a}; {wait @ev_e; }; };

Parameters

{action; …}; … Action blocks that are to execute concurrently. Each action block is a separate
branch.

Description
Execute multiple action blocks concurrently, as separate branches of a fork. The action following the
first of action will be reached when any of the branches in the first of has been fully executed. All
branches of the fork are automatically joined at the termination of the first of action block.

The parallel branches can be thought of as racing each other until one completes. Once one branch
terminates, Specman terminates the execution of each of the other branches.

When two branches finish executing during the same cycle, it is not possible to determine which will
prevail. One will complete successfully and the other will terminate.

15-8 e Language Reference


Time-Consuming Actions
first of

Example 1
The first of construct can be used in order to wait for one of several events. This can be used as an OR
relation between events:
<'
extend sys {
event c;
event d;
event fclk is @any;
detect_first() @fclk is {
first of {
{ wait @c; };
{ wait @d; };
};
out("Either c or d occurred");
};
};
'>

Example 2
The all of and first of actions can be used together to combine wait actions. In the following, the first of
action block terminates when “event2” is seen:
<'
struct tcm_struct {
event clk is @sys.any;
event event1;
event event2;
main() @clk is {
all of {
{wait [10] * cycle;
emit event1;
emit event2;
out("Branch #1 done");};
{first of {
{wait @event1; out("Branch #2-1 done"); };
{wait @event2; out("Branch #2-2 done"); };
// One of the branches will never print
};
};
};
stop_run();
};
};
'>

e Language Reference 15-9


Time-Consuming Actions
first of

Example 3
In the following example, first of is used to create two branches, one of which continues after a
“sys.reset” event, and the other of which calls a method named “sys.pdata()” and then waits one cycle.
The number of cycles required by the “pdata()” method is the main factor in determining which branch
finishes first.
<'
struct mv_data {
data: int;
mdata() @sys.clk is {
first of {
{wait cycle @sys.reset;};
{sys.pdata(); wait cycle;};
};
stop_run();
};
run() is also {
start mdata();
};
};
'>

See Also
• all of on page 15-6

15-10 e Language Reference


16 Coverage Constructs
This chapter contains the following sections:

• “Defining Coverage Groups” on page 16-1


• “Defining Basic Coverage Items” on page 16-8
• “Defining Cross Coverage Items” on page 16-31
• “Defining Transition Coverage Items” on page 16-42
• “Defining External Coverage Groups” on page 16-48
• “Extending Coverage Groups” on page 16-53
• “Extending Coverage Items” on page 16-58
• “Coverage API Methods” on page 16-64

16.1 Defining Coverage Groups

16.1.1 cover

Purpose
Define a coverage group

Category
Struct member

e Language Reference 16-1


Coverage Constructs
Defining Coverage Groups

Syntax
cover event-type [using coverage-group-option, ...] is {coverage-item-definition; ...};

cover event_type is empty;

Syntax Example
cover inst_driven is {
item opcode;
item op1;
cross opcode, op1;
};

Parameters

event-type The name of the group. This must be the name of an event type defined
previously in the struct. The event must not have been defined in a subtype.

The event is the sampling event for the coverage group. Coverage data for
the group is collected every time the event occurs.

The full name of the coverage group is struct-exp.event-name. The full


name must be specified for the show cover command and other coverage
commands and methods.

coverage-group- The coverage group options listed in Table 16-1 can be specified with the
option using keyword.

Each coverage group can have its own set of options. The options can
appear in any order after the using keyword.

coverage-item- The definition of a coverage item. Coverage items are described in “Defining
definition Basic Coverage Items” on page 16-8.

is also See “Extending Coverage Groups” on page 16-53.

is empty The empty keyword can be used to define an empty coverage group that
will be extended later, using a cover is also struct member with the same
name.

16-2 e Language Reference


Coverage Constructs
Defining Coverage Groups

Table 16-1 Coverage Group Options

Option Description

no_collect=bool When no_collect[=TRUE], this coverage group is not displayed in


coverage reports and is not saved in the coverage files. This option
enables tracing of coverage information and enables event viewing with
echo event, without saving the coverage information. Setting this option
to TRUE overrides the global config cover mode setting.

You can use using also no_collect=FALSE to override a previous


no_collect[=TRUE] setting.

text=string A text description for this coverage group.

This can only be a quoted string, not a variable or expression. The text is
shown at the beginning of the information for the group in the coverage
report (displayed using the show cover command). In the Show Coverage
GUI, the text is shown for each item.

when=bool-exp The coverage group is sampled only when bool-exp is TRUE. The
bool-exp is evaluated in the context of the parent struct.

global=bool When global[=TRUE], this coverage group is defined as a global group.


A global coverage group is a group whose sampling event is expected to
occur only once. If the sampling event occurs more than once, Specman
issues a DUT error. If items from a global group are used in interactive
cross coverage, no timing relationships exist between the items.

You can use using also global=FALSE to override a previous


global[=TRUE] setting.

radix=DEC|HEX|BIN Buckets for items of type int or uint are given the item value ranges as
names.This option specifies which radix the bucket names are displayed
in.

The global print radix option does not affect the bucket name radix.

Legal values are DEC (decimal), HEX (hexadecimal), and BIN (binary).
The value must be in upper case letters.

If the radix is not used, int or uint bucket names are displayed in decimal.

The names for per_instance subgroups must always be expressed in DEC


(decimal), regardless of the radix that you set. For more information, see
“Instance Sub-group Names and the Coverage Item Radix” on page 7-32
in the Usage and Concepts Guide for e Testbenches.

e Language Reference 16-3


Coverage Constructs
Defining Coverage Groups

Table 16-1 Coverage Group Options (continued)

Option Description

weight=uint This option specifies the grading weight of the current group relative to
other groups. It is a nonnegative integer with a default of 1.

Description
Defines a coverage group. A coverage group is struct member that contains a list of data items for which
data is collected over time.

Note If cover groups are defined in the e code, coverage mode is “on” by default. The cover
configuration mode parameter controls the coverage mode. In the following example, the cover
configuration option is used to set the mode to “off”. See configure cover on page 6-3 in the Specman
Command Reference for more information.
extend sys {
setup() is also {
set_config(cover, mode, off); //turns off coverage collection
};
};

Once coverage items have been defined in a coverage group, you can use them to define special
coverage group items called transition and cross items. See “Defining Transition Coverage Items” on
page 16-42 and “Defining Cross Coverage Items” on page 16-31 for information about those coverage
items.

The is keyword is used to define a new coverage group. See “Extending Coverage Groups” on page
16-53 for information on using is also to extend an existing coverage group.

All basic items in a coverage group are enabled for echo event.

Coverage groups should not be initially defined in when constructs, although they can be extended in
when constructs.

If you extend a coverage group in a when construct by adding a per_instance item, then the instances
refer only to the when subtype. If you define a per_instance item in a base type and then add additional
items under when construct, then the cover group instances refer to the base type, and the cover item
values refer to the when subtype. See “Coverage Per Instance” on page 16-15.

Example 1
A coverage group named “inst_driven” is defined in the example below. The sampling event
“inst_driven” is declared earlier in the same struct. The coverage group contains definitions of three
basic coverage items named “opcode”, “op1”, and “op2”.

16-4 e Language Reference


Coverage Constructs
Defining Coverage Groups

type cpu_opcode: [ADD, SUB, OR, AND, JMP, LABEL];


type cpu_reg: [reg0, reg1, reg2, reg3];
struct inst {
opcode: cpu_opcode;
op1: cpu_reg;
op2: byte;
event inst_driven;
cover inst_driven is {
item opcode;
item op1;
item op2;
};
};

Example 2
The code below contains examples of the coverage group options.
type cpu_opcode: [ADD, SUB, OR, AND, JMP, LABEL];
type cpu_reg: [reg0, reg1, reg2, reg3];
struct inst {
cache: c_mem;
opcode: cpu_opcode;
event info;
event data_change;
cover data_change using no_collect is {
item data: uint(bits:16) = cache.data;
};
cover info is {
item opcode;
};
};
type memory_mode: [full, partial];
type cpu_state: [START, FETCH1, FETCH2, EXEC];
struct cpu {
memory: memory_mode;
init_complete: bool;
event state_change;
event reset_event;
cover state_change using text = "Main state-machine",
when = (init_complete == TRUE) is {
item st: cpu_state = 'top.cpu.main_cur_state';
};
cover reset_event using global is {
item memory;
};

e Language Reference 16-5


Coverage Constructs
Defining Coverage Groups

};

The effects of the options in the example above are:

• no_collect option: For the “data_change” group, do not save coverage data, but provide data for
show event.
• text option: The text “Main state machine” appears at the beginning of the data for the group in the
ASCII coverage report.
• when option: Coverage is collected for “st” when the “state_change” event occurs and
“init_complete” is TRUE.
• global option: The “reset_event” is expected to occur only once. If it occurs more than once, a DUT
error is issued.

Example 3
The code below shows the radix coverage group option.
cover done using radix = HEX is {
item len: uint (bits: 3) = sys.len;
item data: byte = data using
ranges = {range([0..0xff], "", 4)},
radix = HEX;
item mask: uint (bits: 2) = sys.mask using radix = BIN;
};

For the “len” item, the bucket names are: 0x0, 0x1, ... 0x7 (using the HEX radix specified for the group).

For the “data” item, the bucket names are: [0x0..0x03], [0x04..0x07], … [0xfc..0xff] (using the HEX
radix specified for the item).

For the “mask” item, the bucket names are 0b00, 0b01, 0b10, and 0b11 (since the radix = BIN option is
used for this item to override the group’s HEX radix.)

Example 4
The code below shows the weight coverage group option.
cover done using weight = 3 is {
item len: uint (bits: 3) = sys.len;
item data: byte = data;
item mask;
};

The “done” coverage group is assigned a weight of 3. If there are 10 other coverage groups that all have
default weights of 1, the “done” group contributes (3/13)*grading(done) to the “all” grade.

16-6 e Language Reference


Coverage Constructs
Defining Coverage Groups

Example 5
The code below shows how to use the empty coverage group keyword.
<'
struct inst {
cover done is empty;
};
'>
<'
extend inst {
cover done is also {
item len: uint (bits: 3) = sys.len;
item data: byte = data;
item mask;
};
};
'>

Example 6
The code below shows how to define coverage items in a when construct, by extending a coverage
group defined previously but initially left empty.
<'
struct inst {
size: [WIDE, REG];
event done;
cover done is {};
};
'>
<'
extend inst {
when WIDE inst {
cover done is also {
item len: uint (bits: 3) = sys.len;
item data: byte = data;
item mask;
};
};
};
'>

See Also
• “Defining Basic Coverage Items” on page 16-8

e Language Reference 16-7


Coverage Constructs
Defining Basic Coverage Items

• “Defining Cross Coverage Items” on page 16-31


• “Defining Transition Coverage Items” on page 16-42
• “Extending Coverage Groups” on page 16-53
• “Coverage Grading” on page 7-41 in the Usage and Concepts Guide for e Testbenches
• Chapter 12 “Events”
• Chapter 4 “Structs, Fields, and Subtypes”
• show cover on page 10-6 in the Specman Command Reference
• configure cover on page 6-3 in the Specman Command Reference

16.2 Defining Basic Coverage Items

16.2.1 item

Purpose
Define a coverage item

Category
Coverage group item

Syntax
item item-name[:type=exp] [using coverage-item-option, …]

Syntax Example
cover inst_driven is {
item op1;
item op2;
item op2_big: bool = (op2 >= 64);
item hdl_sig: int = 'top.sig_1';
};

16-8 e Language Reference


Coverage Constructs
Defining Basic Coverage Items

Parameters

item-name The name you assign to the coverage item.

If you do not specify the optional type=exp, the value of the field named
item-name is used as the coverage sample value.The field may be a scalar not
larger than 32 bits, or a string.

If you specify the optional type=exp, the value of the expression is used as
the coverage sample value.

type The type of the item. The type expression must evaluate to a scalar not larger
than 32 bits, or a string.

exp The expression is evaluated at the time the whole coverage group is sampled.
This value is used for the item.

coverage-item- Coverage item options are listed in Table 16-2. The options can appear in any
option order after the using keyword.

Table 16-2 Coverage Item Options

Option Description

per_instance=bool When per_instance[=TRUE], coverage data is collected and graded for


all the other items in a separate listing for each bucket of this item. This
option can only be used for basic items (not for cross or transition items,
or items whose ranges are not known at generation time).

You can use using also per_instance=FALSE to override a previous


setting of per_instance[=TRUE].

e Language Reference 16-9


Coverage Constructs
Defining Basic Coverage Items

Table 16-2 Coverage Item Options (continued)

Option Description

no_collect=bool When no_collect[=TRUE], this coverage item is not displayed in


coverage reports and is not saved in the coverage files.

The primary use of this option is to specify cover items whose individual
coverage grades are of no interest, but whose cross coverage grade is
desired. For example:
item x using no_collect; // Not interested in x itself
item y using no_collect; // Not interested in y itself
cross x, y; // Interested in the cross of x an y

This option also enables tracing of coverage information and enables


event viewing with echo event, without saving the coverage information.
Setting this option to TRUE overrides the global config cover mode
setting of on or on_interactive.

You can use using also no_collect=FALSE to override a previous setting


of no_collect[=TRUE].

no_trace=bool When no_trace[=TRUE], this item is not traced by the simulator. Use
this option to collect data for echo event.

You can use using also no_trace=FALSE to override a previous setting


of no_trace[=TRUE].

text=string A text description for this coverage item. This can only be a quoted
string, not a variable or expression. In the ASCII coverage report the text
is shown along with the item name at the top of the coverage information
for the item. In the Show Coverage GUI, the text is shown for each item.

when=bool-exp The item is sampled only when bool-exp is TRUE. The bool-exp is
evaluated in the context of the parent struct.

The sampling is done at run time.

at_least=num The minimum number of samples for each bucket of the item. Anything
less than num is considered a hole.

This option cannot be used with string items or for unconstrained integer
items (items that do not have specified ranges).

You cannot specify a negative number. The default is 1.

16-10 e Language Reference


Coverage Constructs
Defining Basic Coverage Items

Table 16-2 Coverage Item Options (continued)

Option Description

ranges = Create buckets for this item’s values or ranges of values. This option
{range(parameters);…} cannot be used for string items.

The range() has up to four parameters. The parameters specify how the
values are separated into buckets. The first parameter, range, is required.
The other three are optional. The syntax for range options is:

range(range: range, name: string, every-count: int,


at_least-num: int)

The parameters are:

• range:The range for the bucket. The range must be a literal range such
as “[1..5]”, of the proper type. Even a single value must be specified
in brackets (for example “[7]”). If you specify ranges that overlap,
values in the overlapping region go into the first of the overlapping
buckets. The specified range for a bucket is the bucket name. That is,
the buckets above are named “[1..5]” and “[7]”.
• name: A name for the bucket.
If you use the name parameter, you cannot use an every-count value.
Instead, you must enter UNDEF for the every-count parameter.
item p using ranges =
{range([[0..7], "low ranges", UNDEF,> 1);};
// no error because UNDEF is used as
// placeholder for every-count

• every-count: The size of the buckets to create within the range.


If you use the every-count parameter, you cannot use a name.
Instead, you must enter an empty string (“”) as a placeholder for the
name parameter. For example:
item p using ranges =
{range([[0..7], "", 1, 1);};
// no error because "" is used as
// placeholder for name

• at-least-num: A number that specifies the minimum number of


samples required for a bucket. If the item occurs fewer times than this,
a hole is marked. This parameter overrides the global at_least option
and the per-item at_least option. The value of at-least-num can be set
to zero, meaning “do not show holes for this range”.

e Language Reference 16-11


Coverage Constructs
Defining Basic Coverage Items

Table 16-2 Coverage Item Options (continued)

Option Description

ignore=item-bool-exp Define values that are to be completely ignored. They do not appear in
the statistics at all. The expression is a Boolean expression that can
contain a coverage item name and constants.

The Boolean expression is evaluated in a global context, not in instances


of the struct. In other words, the expression must be valid at all times,
even before generation. Therefore, you can only use constants and the
item itself in the expression. In a cross, that means any of the
participating items. In a transition, that means the item or prev_item.

For example, if “i” is a coverage item and “j” is a reference to a struct


field, the expression “i > 5” is a valid expression, but “i > me.j” is not
legal.

Using ignore has two effects:

1. If the ignore expression is TRUE when the data is sampled, the


sampled value is ignored (that is, not added to the bucket count).

2. When you view the results with show cover or with the coverage
GUI, Specman queries the ignore expression for each hole in the
coverage results. If the ignore expression is TRUE:

• The bucket is hidden, rather than identified as a hole.


• Coverage grades are computed without taking into account the
bucket contents.

If you want to achieve the first effect (ignore specific samples), but you
do not want to hide buckets containing holes and you want the grade to
reflect all generated values, use the when option instead. See “Effects of
the ignore and illegal Options” on page 7-11 in Usage and Concepts
Guide for e Testbenches for more information about the effects of the
ignore option.

Note You can use the show cover -space command to reports the
number of legal buckets defined for the item versus the number of buckets
that would be defined if the illegal and ignore coverage options did not
apply.

16-12 e Language Reference


Coverage Constructs
Defining Basic Coverage Items

Table 16-2 Coverage Item Options (continued)

Option Description

illegal=item-bool-exp Define values that are illegal. An illegal value causes a DUT error. If the
check_illegal_immediately coverage configuration option is FALSE,
the DUT error occurs during the check_test phase of the test. If that
configuration option is TRUE, the DUT error occurs immediately (on the
fly). Note that checking illegal values immediately has a significant
negative impact on Specman performance.

See “illegal Example” on page 16-21 for an example of how to set the error
effect of this check to WARNING instead of ERROR.

The Boolean expression is evaluated in a global context, not in instances


of the struct. In other words, the expression must be valid at all times,
even before generation. Therefore, you can only use constants and the
item itself in the expression. In a cross, that means any of the
participating items. In a transition, that means the item or prev_item.

For example, if “i” is a coverage item and “j” is a reference to a struct


field, the expression “i > 5” is a valid expression, but “i > me.j” is not
legal.

When you view result with show cover or the coverage GUI, Specman
queries the illegal expression. If the illegal expression is TRUE, coverage
grades are computed without taking into account the bucket contents.

If, on the other hand, you want the coverage grades to reflect all bucket
contents, use the when option instead to specify the circumstances under
which a given value is counted. See “Effects of the ignore and illegal
Options” on page 7-11 in Usage and Concepts Guide for e Testbenches
for more information about the effects of the illegal option.

Note You can use the show cover -space command to reports the
number of legal buckets defined for the item versus the number of buckets
that would be defined if the illegal and ignore coverage options did not
apply.

e Language Reference 16-13


Coverage Constructs
Defining Basic Coverage Items

Table 16-2 Coverage Item Options (continued)

Option Description

radix=DEC|HEX|BIN For items of type int or uint, specifies the radix used in coverage reports
for implicit buckets. If the ranges option is not used to create explicit
buckets for an item, a bucket is created for every value of the item that
occurs in the test. Each different value sampled gets its own bucket, with
the value as the name of the bucket. These are called implicit buckets.

Legal values are DEC (decimal), HEX (hexadecimal), and BIN (binary).
The value must be in upper case letters. If the radix is not used, int or
uint bucket names are displayed in decimal.

The global print radix option does not affect the bucket name radix.

If no radix is specified for an item, but a radix is specified for the item’s
group, the group’s radix applies to the item.

Note The names for per_instance subgroups must always be expressed


in DEC (decimal), regardless of the radix that you set. For more
information, see “Instance Sub-group Names and the Coverage Item
Radix” on page 7-32 in the Usage and Concepts Guide for e Testbenches.

weight=uint Specifies the weight of the current item relative to other items in the same
coverage group. It is a non-negative integer with a default of 1.

name=alt-name Assign an alternative name for a cross or transition item. For example:
transition len using name = t_len;
transition ptype using name = t_ptype;
cross t_len, t_ptype;

This option cannot be modified by using also.

Description
Defines a new basic coverage item with an optional type. Options specify how coverage data is collected
and reported for the item. The item can be an existing field name, or a new name. If you use a new name
for a coverage item, you must specify the item’s type and the expression that defines it.

If a value for an item falls outside all of the buckets for the item, that value does not count toward the
item’s grade.

The max_int_buckets coverage configuration option sets the number of buckets beyond which integer
items that do not use the ranges option are considered ungradeable.The item ranges option determines
the number and size of buckets into which values for the item will be placed. If ranges is not specified,

16-14 e Language Reference


Coverage Constructs
Defining Basic Coverage Items

the potential number of buckets is determined by the width of the item type, and is not limited to
max_int_buckets. If the item type is integer and the number of buckets is greater than
max_int_buckets, then the item is ungradeable, which means that buckets are created only for those
values that are hit, no holes are shown, and no grade is calculated for the item. An enumerated type, on
the other hand, can be gradeable even if the number of buckets for the enumerated type is greater than
max_int_buckets. See “Coverage Grading” on page 7-41 in the Usage and Concepts Guide for e
Testbenches for a detailed explanation of coverage grading and buckets.

By default, basic items are enabled for echo event. You can use the no_trace option to disable tracing
for an item.

Below are some general examples of coverage item definitions. For examples of each of using the
coverage item options, see “Coverage Item Options Examples” on page 16-18.

Coverage Per Instance


The coverage per instance feature (per_instance option) allows you to collect coverage information for
separate instances of structs or units, and to see the coverage data and grade associated with each
particular instance.

When you use the per_instance option in a cover item definition, that item becomes a “per_instance
item”. Each bucket of that item gets its own coverage grade and is shown separately in the coverage
report and coverage GUI. For example, if a struct has a field named packet_type and the value of the
packet_type field can be either Ethernet or ATM, then making that field a per_instance item results in a
grade and a coverage report listing for Ethernet instances and a separate grade and coverage report
listing for ATM instances.

Typically, you use per-instance coverage on one item and transition or cross coverage on other items to
see transitions or crosses of values within the different subtypes determined by the per_instance item.
See “Example 5” on page 16-25 and “Example 6” on page 16-27. Also see “Coverage Per Instance” on
page 7-27 in the Usage and Concepts Guide for e Testbenches.

An instance is created for every valid bucket of the per_instance item. Any instance that is not sampled
is marked as a hole.

Along with the per_instance item data, coverage data is also collected for the original, per_type item as
if it were not a per_instance item. This coverage data for the per_type item is the accumulated
information for all the instances, using the coverage options defined for the item.

Grading is calculated for each instance separately. The grade of the cover group is the weighted grades
of all the per_instance items. The per_type item receives the same grade it would get if there were no
per_instance items.

An instance item name is the name of the per_type item followed by “==” and the name of the instance
bucket. For example, the instance item names for the case above are:

e Language Reference 16-15


Coverage Constructs
Defining Basic Coverage Items

packet_type==Ethernet
packet_type==ATM

An item my_b of type boolean will have the following instance names:

my_b==TRUE
my_b==FALSE

An item my_u of type uint(bits:2) will have the following instance names:

my_u==0
my_u==1
my_u==2
my_u==3

An item my_num of type uint with ranges={range( [0], “Zero”); range, [1..1000], “”, 500)} will have
the following instance names:

my_num==Zero
my_num==[1..500]
my_num==[501..1000]
my_num==others

where others is the bucket for all uint values higher than 1000.

For more information about instance names, see “Understanding Instance Names” on page 7-31 and
“Instance Sub-group Names and the Coverage Item Radix” on page 7-32 in the Usage and Concepts
Guide for e Testbenches.

You can define more than one per_instance item in the same cover group. In this case, the total number
of instances is the sum of all valid buckets for all the per_instance items plus one (the per_instance
bucket).

If a per_instance item definition is changed in an extension, then the coverage data for the original
per_type item might not accurately reflect nor agree with the coverage data collected per instance.

You cannot define a per_instance item under a specific instance.

You can define items with the same name under two different instances, with the condition that they
must have the same definition (type and expression).

If a per_instance item is participating in a cross item or a transition item, then the cross or transition
item is not added to the instances created by the per_instance item.

You can use the ignore option to ignore a particular instance or the illegal option to define a particular
instance as illegal. For example, if an item named port_id has a bucket PORT_3, you can use “ignore =
port_id == PORT_3”.

16-16 e Language Reference


Coverage Constructs
Defining Basic Coverage Items

To cancel per instance coverage collection in an extension, use the also per_instance = FALSE option.
For example: item my_item using also per_instance = FALSE.

Per_Instance Item Errors


Table 16-3 lists errors that might occur when coverage per instance is used.

Table 16-3 Coverage Per Instance Errors

Error Description

Using a non-gradeable item as a User defines a per_instance item option for a


per_instance item non-gradeable item.

Runtime error, “Items used with per_instance option must


be gradeable”.

Using a cross or transition item as a User defines a per_instance item for a cross item or a
per_instance item transition item.

Load fails with the message “Not supported”.

Trying to extend an invalid instance User tries to extend (using cover ... is also) a group instance
that does not exist.

Load fails.

Recursively split instances User defines a per_instance item option for an instance
group extension.

Load fails with the message “Not supported”.

Trying to extend specific instances User tries to extend a specific group instance using is instead
without using is also of is also.

Trying to define multiple items with User tries to define an item with the same name under two
the same name but different different instances.
definitions under different instances

Specifying an invalid instance name User specifies an invalid instance name (possibly using wild
cards). No matching instance is found.

Command is ignored.

e Language Reference 16-17


Coverage Constructs
Defining Basic Coverage Items

Coverage Item Options Examples


Examples of all the coverage item options are shown below. More examples of coverage item definitions
are shown in “Additional Examples” on page 16-22.

per_instance Example
struct instruction {
alu: [ALU_0, ALU_1];
opcode: [ADD, SUB, AND, XOR];
event stimulus;
cover stimulus is {
item alu using per_instance;
item opcode;
};
};

For alu bucket ALU_0, coverage information is collected and graded for all other items, and listed under
instance stimulus(alu==ALU_0) in the coverage report. Likewise, for ALU_1, coverage is collected and
graded for all other items and listed under stimulus(alu==ALU_1) in the report.

no_collect Example
struct sm {
cpu: top_cpu;
event cs;
cover cs is {
item cb: bit = cpu.carry using no_collect;
};
};

Coverage information is not collected for item “cb”, but the item can be used in cross coverage, and
Verilog tracing can be done on it and it is displayed by the echo event command.

text Example
type state_name: [S1, S2];
struct sm {
st: state_name;
event state_change;
cover state_change is {
item st using text = "The CPU state";
};
};

The text is displayed with the data for item “st” in the coverage report.

16-18 e Language Reference


Coverage Constructs
Defining Basic Coverage Items

when Example
type state_name: [S1, S2];
struct sm {
cpu: top_cpu;
st: state_name;
event state_change;
cover state_change is {
item st using when = (cpu.init_complete == TRUE);
};
};

Coverage information is collected for item “st” only when the Boolean expression is TRUE at the time
the “state_change” event occurs.

at_least Example
type cpu_opcode: [ADD, SUB, OR, AND, JMP, LABEL];
struct inst {
opcode: cpu_opcode;
op1: byte;
op2: byte;
event inst_driven;
cover inst_driven is {
item op1;
item op2;
};
when JMP inst {
op3: byte;
cover inst_driven is also {
item op3 using ranges =
{range([0..255], "", 16)}, at_least = 10;
};
};
};

The ranges option creates a bucket for each set of 16 values (0-15, 16 -31, ... , 240-255) for item “op3”.
Any of those buckets for which fewer than 10 samples is collected is a hole.

ranges Example
struct pcc {
pc_on_page_boundary: uint (bits: 15);
pc: uint (bits: 15);
stack_change: byte;
event pclock;
cover pclock is {

e Language Reference 16-19


Coverage Constructs
Defining Basic Coverage Items

item pc_on_page_boundary using


ranges = {
range([0], "0"); range([4k], "4k");
range([8k], "8k"); range([12k], "12k");
range([16k], "16k"); range([20k], "20k");
range([24k], "24k"); range([28k], "28k");
range([0..32k-1], "non-boundary");
};
item pc using radix = HEX,
ranges = {
range([0..4k-1], "page_0", UNDEF, 4);
range([4k..32k-1], "", 8k, 2);
};
item stack_change using
ranges = { range( [0..32], "", 1); };
};
};

The range specifications in this example create the following buckets:

• Item pc_on_page_boundary:
Bucket names: 0, 4k, 8k, 12k, 16k, 20k, 24k, 28k
Each of these buckets will hold the given value.
Bucket name: non-boundary:
This bucket will hold all values from 0 to 32k-1 that are not put into one of the buckets above.
• Item pc:
Bucket name: page_0
This bucket will hold values from 0 to 4095, and must contain at least four samples (because
at_least_num is 4).
Bucket names: 0x1000..ex2fff, 0x3000..0x4fff, 0x5000..0x6fff, 0x7000..0x7cff
Each of these buckets will hold values in the given range and must contain at least two samples
(because every_count is 8k, and at_least_num is 2).
• Item stack_change:
Bucket names: 0, 1, 2, …, 32
Each of these buckets will hold the given value (because every_count is 1).

ignore Example
struct packet {

16-20 e Language Reference


Coverage Constructs
Defining Basic Coverage Items

len: uint (bytes: 2);


event xfer;
cover xfer is {
item len using ignore = (len > 32k);
};
};

Any “len” value greater than 32,768 is ignored.

illegal Example
struct packet {
packet_len: uint (bits: 12);
event rcv_clk;
cover rcv_clk is {
item len: uint (bits: 12) = packet_len using
ranges = {
range( [16..255], "small");
range( [256..3k-1], "medium");
range( [3k..4k], "big");
},
illegal = (len < 16 or len > 4000);
};
};

Any “len” value less than 16 or greater than 4,096 is illegal. If an illegal “len” value occurs, a DUT error
is issued during the check_test phase of the test. The ranges option creates buckets for values from 16
to 4,096.

You can use the set check command to set the effect of the DUT error to WARNING, to allow continued
execution of the test even if illegal values occur. For example:
set check "Illegal value for cover item..." WARNING

radix Example
cover done is {
item len: uint (bits: 3) = packet_len;
item data: byte = data using
ranges = {range([0..0xff], "", 16)};
item mask: uint (bits: 2) = mask using radix = BIN;
};

For the “len” item, the bucket names are: 0, 1, ... 7 (using the default decimal radix).

For the “data” item, the bucket names are: [0..15], [16..31], … [240..255] (using the default decimal
radix).

e Language Reference 16-21


Coverage Constructs
Defining Basic Coverage Items

For the “mask” item, the bucket names are 0b00, 0b01, 0b10, and 0b11 (using the radix = BIN option
specified for this item).

weight Example
cover done is {
item len: uint (bits: 3) = packet_len;
item data: byte = data;
item mask using weight = 2;
};

The “mask” item is assigned a weight of 2. Since there are two other items, “len” and “data”, with
default weights of 1, the “mask” item contributes (2/4)*grading(done) to the grade for the group.

no_trace Example
struct packet {
event done;
mask: uint (bits: 2);
packet_data: byte;
cover done is {
item data: byte = packet_data;
item mask using no_trace;
};
};

The “done” event is marked for tracing, but the “mask” item in the “done” coverage group is marked
no_trace, so it is not traced in the simulator and is not displayed by echo event.

Additional Examples

Example 1
The following example uses type=exp to define coverage for a list element. In the b0 item definition, the
type is byte and exp is b_list[0]. This collects coverage data for the value of the first byte in b_list.

This example also shows a predefined list method, b_list.size(), used in the item definition expression.
struct mem {
b_list: list of byte;
keep b_list.size() in [2..16];
event mem_ch;
cover mem_ch is {
item b0: byte = b_list[0];
item b_list_size: uint (bits: 4) = b_list.size();
};

16-22 e Language Reference


Coverage Constructs
Defining Basic Coverage Items

};

Example 2
The following example uses the type=exp parameter in the mem_mode item definition to define
coverage for a struct field which is instantiated through a hierarchy of struct instances. The type is
memory_type. The exp is the hierarchical path sys.config.mem_type.
struct mem {
event mem_ch;
cover mem_ch is {
item mem_mode: memory_mode = sys.config.mem_mode;
};
};
struct config {
mem_mode: memory_mode;
keep mem_mode == 'top.mem_mode';
};

Example 3
The following example demonstrates a way to cover different combinations of values for particular bits
of an item. It uses type=exp and the when coverage item option to collect coverage for bit 14 = 0, bit 15
= 0 versus bit 14 = 0, bit 15 = 1 of a 16-bit unit item named opcode.
struct inst {
opcode: uint (bits: 16);
len: int [1..3];
event fetch;
cover fetch is {
item opcode using radix = BIN;
item opcode0: uint (bits: 2) = opcode
using when = (opcode[15:14] == 2'b00);
item opcode1: uint (bits: 2) = opcode
using when = (opcode[15:14] == 2'b01);
item len;
};
run() is also {
emit fetch;
};
};

e Language Reference 16-23


Coverage Constructs
Defining Basic Coverage Items

Example 4
In the following example, coverage data is collected for a field generated on the fly. The field is
addr_tmp, which has been added just to serve as a coverage item. The addr_tmp values replace the addr
field values in a previously generated list of packets structs.

For each addr_tmp value generated in the for loop, the cov_addr event is emitted to take a coverage
sample of the addr_tmp value. The the new addr_tmp value is then placed in the addr field in the current
packet instance.

The ranges option is used in the addr_tmp coverage item definition to create four buckets, for values
from 0 to 63, 64 to 127, 128 to 191, and 192 to 255. The at_least option is also used, to specify that any
bucket that does not get at least three values is a hole.
struct packet {
%addr: byte;
%len: uint (bytes: 2);
%data[len]: list of byte;
};
struct pkts {
packets: list of packet;
keep packets.size() == 12;
};
extend pkts {
addr_tmp: byte;
add_addr()@sys.clk is {
for i from 0 to packets.size() - 1 do {
gen addr_tmp;
emit cov_addr;
packets[i].addr = addr_tmp;
wait cycle;
};
stop_run();
};
event cov_addr;
cover cov_addr is {
item addr_tmp using ranges = {range([0..255], "", 64)},
at_least = 3;
};
run() is also {
start add_addr();
};
};

16-24 e Language Reference


Coverage Constructs
Defining Basic Coverage Items

Example 5
The following example specifies that the alu item is a per_instance item. For each of the buckets of the
alu item, ALU_0 and ALU_1, coverage data will be collected and grades will be calculated for the
opcode, operand1, and operand2 items in each of the two alu buckets. The coverage report follows the
sample code.
struct instruction {
alu: [ALU_0, ALU_1];
opcode: [ADD, SUB, AND, XOR];
operand1 : byte;
operand2 : byte;

event stimulus;
cover stimulus is {
item alu using per_instance;
item opcode;
item operand1 using
ranges = { range([0..15]); range([16..0xff]); };
};
};

Output
The following is the coverage report displayed by the show cover instruction command for “Example 5”
on page 16-25.

Specman Coverage report


=======================

Command: show cover -kind = full instruction.*.*


Grading_formula: linear
At least multiplier: 1
Show mode: both
Number of tests: 1
Note: %t is a percent from total, %p is a percent from parent

Cover group: instruction.stimulus


=================================

Grade: 0.83 Weight: 1

** alu **
Samples: 26 Tests: 1 Grade: 1.00 Weight: 1

e Language Reference 16-25


Coverage Constructs
Defining Basic Coverage Items

grade goal samples tests %t alu

1.00 1 12 1 46 ALU_1

** opcode **
Samples: 26 Tests: 1 Grade: 1.00 Weight: 1

grade goal samples tests %t opcode

1.00 1 4 1 15 ADD
1.00 1 7 1 27 SUB
1.00 1 6 1 23 AND
1.00 1 9 1 35 XOR

** operand1 **
Samples: 26 Tests: 1 Grade: 0.50 Weight: 1

grade goal samples tests %t operand1

0.00 1 0 0 0 [0..15]
1.00 1 26 1 100 [16..255]

Cover group: instruction.stimulus(alu==ALU_0)


=============================================

Grade: 0.75 Weight: 1

** opcode **
Samples: 12 Tests: 1 Grade: 1.00 Weight: 1

grade goal samples tests %t opcode

1.00 1 1 1 8 ADD
1.00 1 3 1 25 SUB
1.00 1 3 1 25 AND
1.00 1 5 1 42 XOR

** operand1 **
Samples: 12 Tests: 1 Grade: 0.50 Weight: 1

grade goal samples tests %t operand1

16-26 e Language Reference


Coverage Constructs
Defining Basic Coverage Items

0.00 1 0 0 0 [0..15]
1.00 1 12 1 100 [16..255]

Cover group: instruction.stimulus(alu==ALU_1)


=============================================

Grade: 0.75 Weight: 1

** opcode **
Samples: 14 Tests: 1 Grade: 1.00 Weight: 1

grade goal samples tests %t opcode

1.00 1 3 1 21 ADD
1.00 1 4 1 29 SUB
1.00 1 3 1 21 AND
1.00 1 4 1 29 XOR

** operand1 **
Samples: 14 Tests: 1 Grade: 0.50 Weight: 1

grade goal samples tests %t operand1

0.00 1 0 0 0 [0..15]
1.00 1 14 1 100 [16..255]

Example 6
The example below shows the ignore option used to ignore particular instances, that is, alu==ALU_0 of
the alu item. The coverage report shows grades for alu overall and all ALU_1 instances. The output,
shown following the code, does not contain any data for instances where alu is ALU_0.
struct instruction {
alu: [ALU_0, ALU_1];
opcode: [ADD, SUB, AND, XOR];
operand1 : byte;
operand2 : byte;

event stimulus;
cover stimulus is {
item alu using per_instance, ignore = (alu==ALU_0);
item opcode;

e Language Reference 16-27


Coverage Constructs
Defining Basic Coverage Items

item operand1 using


ranges = { range([0..15]); range([16..0xff]); };
};
};

Output
The following is the coverage report displayed by the show cover instruction command for “Example 6”
on page 16-27.

Specman Coverage report


=======================

Command: show cover -kind = full instruction.*.*


Grading_formula: linear
At least multiplier: 1
Show mode: both
Number of tests: 1
Note: %t is a percent from total, %p is a percent from parent

Cover group: instruction.stimulus


=================================

Grade: 0.83 Weight: 1

** alu **
Samples: 14 Tests: 1 Grade: 1.00 Weight: 1

grade goal samples tests %t alu

1.00 1 14 1 100 ALU_1

** opcode **
Samples: 26 Tests: 1 Grade: 1.00 Weight: 1

grade goal samples tests %t opcode

1.00 1 4 1 15 ADD
1.00 1 7 1 27 SUB
1.00 1 6 1 23 AND
1.00 1 9 1 35 XOR

** operand1 **

16-28 e Language Reference


Coverage Constructs
Defining Basic Coverage Items

Samples: 26 Tests: 1 Grade: 0.50 Weight: 1

grade goal samples tests %t operand1

0.00 1 0 0 0 [0..15]
1.00 1 26 1 100 [16..255]

Cover group: instruction.stimulus(alu==ALU_1)


=============================================

Grade: 0.75 Weight: 1

** opcode **
Samples: 14 Tests: 1 Grade: 1.00 Weight: 1

grade goal samples tests %t opcode

1.00 1 3 1 21 ADD
1.00 1 4 1 29 SUB
1.00 1 3 1 21 AND
1.00 1 4 1 29 XOR

** operand1 **
Samples: 14 Tests: 1 Grade: 0.50 Weight: 1

grade goal samples tests %t operand1

0.00 1 0 0 0 [0..15]
1.00 1 14 1 100 [16..255]

Example 7
The example below shows the illegal option used with a per_instance item.
define MAX_PORTS 4;
type port_id_kind: [PORT_0, PORT_1, PORT_2, PORT_3];
struct port {
port_id: port_id_kind;
status: uint(bits:2);
event pkt_ended;
cover pkt_ended is {
item port_id using per_instance,
illegal = (port_id.as_a(int) < MAX_PORTS);

e Language Reference 16-29


Coverage Constructs
Defining Basic Coverage Items

item status;
};
};

Example 8
The example below shows an extension of the stimulus cover group in “Example 6” on page 16-27, to
add the at_least option to the opcode item. For additional information about extending coverage items,
see. “Extending Coverage Items” on page 16-58.
struct instruction {
alu: [ALU_0, ALU_1];
opcode: [ADD, SUB, AND, XOR];
operand1 : byte;
operand2 : byte;

event stimulus;
cover stimulus is {
item alu using per_instance, ignore = (alu==ALU_0);
item opcode;
item operand1 using
ranges = { range([0..15]); range([16..0xff]); };
};
};

extend instruction {
cover stimulus is also {
item opcode using also at_least = 4;
};
};

See Also
• “Coverage Grading” on page 7-41 in the Usage and Concepts Guide for e Testbenches
• “Defining Coverage Groups” on page 16-1
• “Defining Cross Coverage Items” on page 16-31
• “Defining Transition Coverage Items” on page 16-42
• “Extending Coverage Items” on page 16-58
• “Defining Structs” on page 4-2
• show cover on page 10-6 in the Specman Command Reference

16-30 e Language Reference


Coverage Constructs
Defining Cross Coverage Items

• configure cover on page 6-3 in the Specman Command Reference

16.3 Defining Cross Coverage Items


Cross items are combinations of items from the same coverage group. The cross coverage construct is
used to define cross items.

16.3.1 cross

Purpose
Define a cross coverage item

Category
Coverage group item

Syntax
cross item-name-1, item-name-2, ... [using coverage-item-option, ...]

Syntax Example
cover inst_driven is {
item opcode;
item op1;
cross opcode, op1;
};

Parameters

item-name-1, Each item name must be one of the following.


item-name-2, ...
• the name of an item defined previously in the current coverage group
• the name of a transition item defined previously in the current coverage
group
• the name of a cross item defined previously in the current coverage group
coverage-item- An option for the cross item. The options are listed in Table 16-4.
option

e Language Reference 16-31


Coverage Constructs
Defining Cross Coverage Items

Table 16-4 Cross Coverage Item Options

Option Description

name=label Specifies a name for a cross coverage item. No white spaces are allowed in
the label. The default is cross__item-a__item-b.

text=string A text description for this coverage item. This can only be a quoted string,
not a variable or expression. For text-mode Specman, the text is shown
along with the item name at the top of the coverage information for the
item. In the Show Coverage GUI, the text is shown at the top of the display
for the item.

when=bool-exp The item is sampled only when bool-exp is TRUE. The bool-exp is
evaluated in the context of the parent struct.

at_least=num The minimum number of samples for each bucket of the item. Anything
less than num is considered a hole.

This option cannot be used with string items or for unconstrained integer
items (items that do not have specified ranges).

You cannot specify a negative number. The default is 1.

16-32 e Language Reference


Coverage Constructs
Defining Cross Coverage Items

Table 16-4 Cross Coverage Item Options (continued)

Option Description

ignore=item-bool-exp Define values that are to be completely ignored. They do not appear in the
statistics at all. The expression is a Boolean expression that can contain a
coverage item name and constants.

The Boolean expression is evaluated in a global context, not in instances of


the struct. In other words, the expression must be valid at all times, even
before generation. Therefore, you can only use constants and the item itself
in the expression. In a cross, that means any of the participating items. In a
transition, that means the item or prev_item.

For example, if “i” is a coverage item and “j” is a reference to a struct field,
the expression “i > 5” is a valid expression, but “i > me.j” is not legal.

Using ignore has two effects:

1. If the ignore expression is TRUE when the data is sampled, the sampled
value is ignored (that is, not added to the bucket count).

2. When you view the results with show cover or with the coverage GUI,
Specman queries the ignore expression for each hole in the coverage
results. If the ignore expression is TRUE:

• The bucket is hidden, rather than identified as a hole.


• Coverage grades are computed without taking into account the
bucket contents.

If you want to achieve the first effect (ignore specific samples), but you do
not want to hide buckets containing holes and you want the grade to reflect
all generated values, use the when option instead. See “Effects of the ignore
and illegal Options” on page 7-11 in Usage and Concepts Guide for e
Testbenches for more information about the effects of the ignore option.

Note You can use the show cover -space command to reports the number
of legal buckets defined for the item versus the number of buckets that
would be defined if the illegal and ignore coverage options did not apply.

e Language Reference 16-33


Coverage Constructs
Defining Cross Coverage Items

Table 16-4 Cross Coverage Item Options (continued)

Option Description

illegal=item-bool-exp Define values that are illegal. An illegal value causes a DUT error. If the
check_illegal_immediately coverage configuration option is FALSE, the
DUT error occurs during the check_test phase of the test. If that
configuration option is TRUE, the DUT error occurs immediately (on the
fly). Note that checking illegal values immediately has a significant
negative impact on Specman performance.

See “illegal Example” on page 16-21 for an example of how to set the error
effect of this check to WARNING instead of ERROR.

The Boolean expression is evaluated in a global context, not in instances of


the struct. In other words, the expression must be valid at all times, even
before generation. Therefore, you can only use constants and the item itself
in the expression. In a cross, that means any of the participating items.

For example, if “i” is a coverage item and “j” is a reference to a struct field,
the expression “i > 5” is a valid expression, but “i > me.j” is not legal.

When you view result with show cover or the coverage GUI, Specman
queries the illegal expression. If the illegal expression is TRUE, coverage
grades are computed without taking into account the bucket contents.

If, on the other hand, you want the coverage grades to reflect all bucket
contents, use the when option instead to specify the circumstances under
which a given value is counted. See “Effects of the ignore and illegal
Options” on page 7-11 in Usage and Concepts Guide for e Testbenches for
more information about the effects of the illegal option.

Note You can use the show cover -space command to reports the number
of legal buckets defined for the item versus the number of buckets that
would be defined if the illegal and ignore coverage options did not apply.

weight=uint Specifies the weight of the current cross item relative to other items in the
same coverage group. It is a non-negative integer with a default of 1.

Description
Defines cross coverage between items in the same coverage group. Creates a new item with a name
specified using a name option, or with a default name of “cross__item-name-1__item-name-2…” (with
two underscores separating the parts of the name). This shows every combination of values of the first
and second items, and every combination of the third item and the first item, the third item and the
second item, and so on.

16-34 e Language Reference


Coverage Constructs
Defining Cross Coverage Items

You can cross any combination of basic coverage items, cross items, and transitions defined in the same
coverage group.

When there is a hole in one of the items of a cross, the whole branch of samples that is spawned under
the hole is, by default, omitted from the coverage report. To see the full report, including all the holes,
set the coverage configuration show_sub_holes to TRUE.

Note
You can view cross coverage interactively using the Show Coverage GUI or the show coverage
command, between items in the same coverage group or in several groups.

Example 1
In the following example, cross coverage is collected for the three coverage items “op1”, “op2”, and
“opcode”. Constraints are applied to limit “opcode” values to either ADD or SUB, to limit “op1” values
to reg0 or reg1, and to limit “op2” values to the range 1 to 24.

The coverage group is named “inst_driven”. The “inst_driven” event is emitted elsewhere in the code
whenever an instruction is generated.

The “op2” coverage item definition uses the ranges option with a range of 1 to 16 and “every-count”
equal to 4. This creates a bucket for values 1 to 16, which is divided into four smaller buckets for values
from 1 to 4, 5 to 8, 9 to 12, and 13 to 16. Values from 17 to 24 go into the default “others” bucket, since
they are not in the specified range.

The coverage report will show holes for all instances of “opcode” that are not “ADD” or “SUB”, and for
all instances of “op1” that are not “reg0” or “reg1”.
type cpu_opcode: [ADD, SUB, OR, AND, JMP, LABEL];
type cpu_reg: [reg0, reg1, reg2, reg3];
struct inst {
opcode: cpu_opcode;
keep opcode in [ADD, SUB];
op1: cpu_reg;
keep op1 in [reg0, reg1];
op2: byte;
keep op2 in [1..24];
event inst_driven;
cover inst_driven is {
item opcode;
item op1;
item op2 using ranges = {range([1..16], "", 4)};
cross opcode, op1, op2 using name = opcode_op1_op2;
};
};

e Language Reference 16-35


Coverage Constructs
Defining Cross Coverage Items

The cross of opcode, op1, and op2 shows all the combinations of values for those three items, sorted first
by opcode value, by op1 under each opcode value, and by op2 under each op1 value.

For a sample test in which 10 instances of the “inst” struct were generated, the item values are shown in
Figure 16-1 on page 16-36, and a chart of the cross coverage information is shown in Figure 16-2 on
page 16-37.

The data shown in Figure 16-2 on page 16-37 is shown again in Figure 16-3 on page 16-38, as displayed
by the show cover command.

In the Specview GUI, you can view a graphical view of the data by using the Cover button to open the
Show Coverage GUI. See the Usage and Concepts Guide for e Testbenches for information on using the
GUI.

Figure 16-1 Description of Generated Instances of “inst”


instance opcode op1 op2
1 SUB reg0 18
2 SUB reg0 18
3 ADD reg0 17
4 ADD reg0 1
5 SUB reg1 6
6 ADD reg0 14
7 ADD reg1 16
8 SUB reg0 13
9 SUB reg1 4
10 ADD reg1 1

16-36 e Language Reference


Coverage Constructs
Defining Cross Coverage Items

Figure 16-2 Cross Coverage Sample Results

op2 in 1-4 (1 time, value: 1)


op2 in 5-8 (0 times)
op1=reg0 (3 times) op2 in 9-12 (0 times)
op2 in 13-16 (1 time, value: 14)
op2 in 17-24 (1 time, value: 17)
opcode=ADD (5 times)
op2 in 1-4 (1 time, value: 1)
op2 in 5-8 (0 times)
op1=reg1 (2 times) op2 in 9-12 (0 times)
op2 in 13-16 (1 time, value: 16)
op2 in 17-24 (0 times)

op2 in 1-4 (0 times)


op2 in 5-8 (0 times)
op1=reg0 (3 times) op2 in 9-12 (0 times)
op2 in 13-16 (1 time, value: 13)
op2 in 17-24 (2 times, values: 18, 18)
opcode=SUB (5 times)
op2 in 1-4 (1 time, value: 4)
op2 in 5-8 (1 time, value: 6)
op1=reg1 (2 times) op2 in 9-12 (0 times)
op2 in 13-16 (0 times)
op2 in 17-24 (0 times)

e Language Reference 16-37


Coverage Constructs
Defining Cross Coverage Items

Figure 16-3 Cross Coverage Example Results Displayed by show cover

** cross__opcode__op1__op2 **
Samples: 10 Tests: 1 Grade: 0.07 Weight: 1

grade goal samples tests %p/%t opcode/op1/op2

0.25 - 5 1 50/50 ADD


0.50 - 3 1 60/30 ADD/reg0
1.00 1 1 1 33/10 ADD/reg0/[1..4]
0.00 1 0 0 0/0 ADD/reg0/[5..8]
0.00 1 0 0 0/0 ADD/reg0/[9..12]
1.00 1 1 1 33/10 ADD/reg0/[13..16
]
NA 0 1 1 33/10 ADD/reg0/others
0.50 - 2 1 40/20 ADD/reg1
1.00 1 1 1 50/10 ADD/reg1/[1..4]
0.00 1 0 0 0/0 ADD/reg1/[5..8]
0.00 1 0 0 0/0 ADD/reg1/[9..12]
1.00 1 1 1 50/10 ADD/reg1/[13..16
]
0.00 - 0 0 0/0 ADD/reg2
0.00 - 0 0 0/0 ADD/reg3
0.19 - 5 1 50/50 SUB
0.25 - 3 1 60/30 SUB/reg0
0.00 1 0 0 0/0 SUB/reg0/[1..4]
0.00 1 0 0 0/0 SUB/reg0/[5..8]
0.00 1 0 0 0/0 SUB/reg0/[9..12]
1.00 1 1 1 33/10 SUB/reg0/[13..16
]
NA 0 2 1 67/20 SUB/reg0/others
0.50 - 2 1 40/20 SUB/reg1
1.00 1 1 1 50/10 SUB/reg1/[1..4]
1.00 1 1 1 50/10 SUB/reg1/[5..8]
0.00 1 0 0 0/0 SUB/reg1/[9..12]
0.00 1 0 0 0/0 SUB/reg1/[13..16
]
0.00 - 0 0 0/0 SUB/reg2
0.00 - 0 0 0/0 SUB/reg3

16-38 e Language Reference


Coverage Constructs
Defining Cross Coverage Items

Example 2
The example below shows the name option. For all occurrences of the “opcode” item together with the
“op1” item, the coverage report shows the cross item name and its definition, “code_and_reg (cross
opcode, op1)”.
type cpu_opcode: [ADD, SUB, OR, AND, JMP, LABEL];
type cpu_reg: [reg0, reg1, reg2, reg3];
struct inst {
opcode: cpu_opcode;
op1: cpu_reg;
event inst_driven;
cover inst_driven is {
item opcode;
item op1;
cross opcode, op1 using name = code_and_reg;
};
};

Example 3
The example below shows how to define cross coverage for two items sampled at different events. The
events named request and grant are driven by HDL signals of the same names. The event named
cov_req_ack occurs whenever a grant event follows a request event by any number of cycles in which
request does not occur. Upon a request event, the request_type field is assigned the value of the HDL
req_type signal, by the exec expression. Thus, the request_type field gets its value upon occurrence of
the request event. This can be thought of as sampling request_type on the request event.

Since the cover_req_ack event occurs when grant occurs (when the sequence in the cov_req_ack
definition succeeds), the items in the cov_req_ack group are sampled upon the occurrence of grant. Thus
the request_type item depends on both the request event and the grant event, and the burst_mode item
depends on the grant event. This has the effect of sampling request_type on the request event, and
sampling burst_mode on the grant event.
struct monitor {
request_type: uint;
event request is rise('top.request')@sim;
event grant is rise('top.grant')@sim;
event cov_req_ack is {
@request exec {request_type = 'top.req_type';};
[..]* not @request;
@grant;
} @sys.clk;
cover cov_req_ack is {
item request_type using

e Language Reference 16-39


Coverage Constructs
Defining Cross Coverage Items

ranges = {
range([0..3], "", 1);
range(others, "invalid")
};
item burst_mode: bool = 'top.burst_mode';
cross request_type, burst_mode;
};
};

Example 4
The example below shows cross coverage per instance. The alu item is defined as a per_instance item,
so coverage is collected for the cross of opcode and operand1 when alu==ALU_0 and when
alu==ALU_1.
struct instruction {
alu: [ALU_0, ALU_1];
opcode: [ADD, SUB, AND, XOR];
operand1 : byte;
operand2 : byte;

event stimulus;
cover stimulus is {
item alu using per_instance;
item opcode;
item operand1;
cross opcode, operand1;
};
};

Example 5
The example below shows how to extend a cross coverage item. In this case, the cross item, “cross
opcode, operand1”, is initially defined without the name option, so the default name,
“cross__opcode_operand1”, is required in the extension. If the cross item is initially defined using the
name option, the given name is used in place of the default name. For additional information about
extending coverage items, see “Extending Coverage Items” on page 16-58.
struct instruction {
alu: [ALU_0, ALU_1];
opcode: [ADD, SUB, AND, XOR];
operand1 : byte;
operand2 : byte;

event stimulus;

16-40 e Language Reference


Coverage Constructs
Defining Cross Coverage Items

cover stimulus is {
item opcode;
item operand1;
cross opcode, operand1;
};
};

extend instruction {
cover stimulus is also {
item cross__opcode__operand1 using also text =
"Cross of opcode and operand1";
};
};

Example 6
The example below shows a cross of two cross items. The items alu and operand1 are crossed, and the
items opcode and operand2 are crossed, and then those two cross items are crossed.
struct instruction {
alu: [ALU_0, ALU_1];
opcode: [ADD, SUB, AND, XOR];
operand1 : byte;
operand2 : byte;

event stimulus;
cover stimulus is {
item alu;
item opcode;
item operand1;
item operand2;
cross alu, operand1 using name=x_alu_op1;
cross opcode, operand2 using name=x_opc_op2;
cross x_alu_op1, x_opc_op2;
};
};

See Also
• “Defining Coverage Groups” on page 16-1
• “Defining Basic Coverage Items” on page 16-8
• “Coverage Item Options Examples” on page 16-18

e Language Reference 16-41


Coverage Constructs
Defining Transition Coverage Items

• “Extending Coverage Items” on page 16-58


• show cover on page 10-6 in the Specman Command Reference

16.4 Defining Transition Coverage Items


Transition items are items for which value changes are collected in the coverage data. The transition
coverage group item is used to define transition items.

16.4.1 transition

Purpose
Define a coverage transition item

Category
Coverage group item

Syntax
transition item-name [using coverage-item-option, ...]

Syntax Example
cover state_change is {
item st: cpu_state = 'top.cpu.main_cur_state';
transition st;
};

Parameters

item-name A coverage item defined previously in the current coverage group.

coverage-item- The coverage item options are listed in Table 16-5.


option

16-42 e Language Reference


Coverage Constructs
Defining Transition Coverage Items

Table 16-5 Transition Coverage Item Options

Option Description

name=string Specifies a name for a transition coverage item. The default name is
transition__item-name (where two underscores separate “transition” and
“item-name”).

text=string A text description for this coverage item. This can only be a quoted string,
not a variable or expression. For text-mode Specman, the text is shown
along with the item name at the top of the coverage information for the
item. In the Show Coverage GUI, the text is shown at the top of the item.

when=bool-exp The item is sampled only when bool-exp is TRUE. The bool-exp is
evaluated in the context of the parent struct.

at_least=num The minimum number of samples for each bucket of each of the transition
items. Anything less than num is considered a hole.

This option cannot be used with string items or for unconstrained integers
(items that have no specified ranges).

You cannot specify a negative number. The default is 1.

e Language Reference 16-43


Coverage Constructs
Defining Transition Coverage Items

Table 16-5 Transition Coverage Item Options (continued)

Option Description

ignore=item-bool-exp Define values that are to be completely ignored. They do not appear in the
statistics at all. The expression is a Boolean expression that can contain a
coverage item name and constants.

The previous value can be accessed as prev_item-name. The prev prefix is


predefined for this purpose.

The Boolean expression is evaluated in a global context, not in instances of


the struct. In other words, the expression must be valid at all times, even
before generation. Therefore, you can only use constants and the item itself
in the expression. In a cross, that means any of the participating items. In a
transition, that means the item or prev_item.

For example, if “i” is a coverage item and “j” is a reference to a struct field,
the expression “i > 5” is a valid expression, but “i > me.j” is not legal.

Using ignore has two effects:

1. If the ignore expression is TRUE when the data is sampled, the sampled
value is ignored (that is, not added to the bucket count).

2. When you view the results with show cover or with the coverage GUI,
Specman queries the ignore expression for each hole in the coverage
results. If the ignore expression is TRUE:

• The bucket is hidden, rather than identified as a hole.


• Coverage grades are computed without taking into account the
bucket contents.

If you want to achieve the first effect (ignore specific samples), but you do
not want to hide buckets containing holes and you want the grade to reflect
all generated values, use the when option instead. See “Effects of the ignore
and illegal Options” on page 7-11 in Usage and Concepts Guide for e
Testbenches for more information about the effects of the ignore option.

Note You can use the show cover -space command to reports the number
of legal buckets defined for the item versus the number of buckets that
would be defined if the illegal and ignore coverage options did not apply.

16-44 e Language Reference


Coverage Constructs
Defining Transition Coverage Items

Table 16-5 Transition Coverage Item Options (continued)

Option Description

illegal=item-bool-exp Define values that are illegal. An illegal value causes a DUT error. If the
check_illegal_immediately coverage configuration option is FALSE, the
DUT error occurs during the check_test phase of the test. If that
configuration option is TRUE, the DUT error occurs immediately (on the
fly). Note that checking illegal values immediately has a significant
negative impact on Specman performance.

See “illegal Example” on page 16-21 for an example of how to set the error
effect of this check to WARNING instead of ERROR.

The Boolean expression is evaluated in a global context, not in instances of


the struct. In other words, the expression must be valid at all times, even
before generation. Therefore, you can only use constants and the item itself
in the expression. In a transition, that means the item or prev_item.

For example, if “i” is a coverage item and “j” is a reference to a struct field,
the expression “i > 5” is a valid expression, but “i > me.j” is not legal.

When you view result with show cover or the coverage GUI, Specman
queries the illegal expression. If the illegal expression is TRUE, coverage
grades are computed without taking into account the bucket contents.

If, on the other hand, you want the coverage grades to reflect all bucket
contents, use the when option instead to specify the circumstances under
which a given value is counted. See “Effects of the ignore and illegal
Options” on page 7-11 in Usage and Concepts Guide for e Testbenches for
more information about the effects of the illegal option.

Note You can use the show cover -space command to reports the number
of legal buckets defined for the item versus the number of buckets that
would be defined if the illegal and ignore coverage options did not apply.

weight=uint Specifies the weight of the current transition item relative to other items in
the same coverage group. It is a non-negative integer with a default of 1.

Description
Defines coverage for changes from one value to another of a coverage item. If no name is specified for
the transition item with the name option, it gets a default name of “transition__item-name” (with two
underscores between “transition” and “item-name”). If item-name had n samples during the test, then the
transition item has n-1 samples, where each sample has the format previous-value, value.

e Language Reference 16-45


Coverage Constructs
Defining Transition Coverage Items

Example 1
Any change from the previous value of “st” to the current value of “st” that is not one of the listed
changes is illegal and causes a DUT error during check_test. This example uses the prev_item-name
syntax, which refers to the previous value of the item (“st” in this case).
type cpu_state: [START, FETCH1, FETCH2, EXEC];
struct cpu {
st: cpu_state;
event state_change is
change('top.cpu.main_cur_state') @sim;
cover state_change is {
item st;
transition st using illegal =
not ((prev_st == START and st == FETCH1)
or (prev_st == FETCH1 and st == FETCH2)
or (prev_st == FETCH1 and st == EXEC)
or (prev_st == FETCH2 and st == EXEC)
or (prev_st == EXEC and st == START));
};
};

Example 2
The example below shows the name option. For all transitions of the “st” item, the coverage report
shows the item name and its definition, “st_change (transition st)”.
type cpu_state: [START, FETCH1, FETCH2, EXEC];
struct cpu {
st: cpu_state;
event state_change is
change('top.cpu.main_cur_state') @sim;
cover state_change is {
item st;
transition st using name = st_change;
};
};

Example 3
The example below shows transition coverage of a cross coverage item (see “Defining Cross Coverage
Items” on page 16-31).

struct instruction {
alu: [ALU_0, ALU_1];

16-46 e Language Reference


Coverage Constructs
Defining Transition Coverage Items

opcode: [ADD, SUB, AND, XOR];


operand1 : byte;
operand2 : byte;

event stimulus;
cover stimulus is {
item alu;
item opcode;
item operand1;
item operand2;
cross opcode, operand1 using name=x_opc_op1;
transition x_opc_op1;
};
};

Example 4
The example below shows transition coverage per instance. The alu item is defined as a per_instance
item, so coverage is collected for the opcode transitions when alu==ALU_0 and when alu==ALU_1.
struct instruction {
alu: [ALU_0, ALU_1];
opcode: [ADD, SUB, AND, XOR];
operand1 : byte;
operand2 : byte;

event stimulus;
cover stimulus is {
item alu using per_instance;
item opcode;
transition opcode;
};
};

See Also
• “Defining Coverage Groups” on page 16-1
• “Defining Basic Coverage Items” on page 16-8
• “Coverage Item Options Examples” on page 16-18
• “Extending Coverage Items” on page 16-58

e Language Reference 16-47


Coverage Constructs
Defining External Coverage Groups

Example 5
The example below shows how to extend a transition coverage item. In this case, the transition item,
“transition opcode”, is initially defined without the name option, so the default name,
“transition__opcode”, is required in the extension. If the transition item is initially defined using the
name option, the given name is used in place of the default name. For additional information about
extending coverage items, see “Extending Coverage Items” on page 16-58.
struct instruction {
alu: [ALU_0, ALU_1];
opcode: [ADD, SUB, AND, XOR];
operand1 : byte;
operand2 : byte;

event stimulus;
cover stimulus is {
item opcode;
item operand1;
transition opcode;
};
};

extend instruction {
cover stimulus is also {
item transition__opcode using also at_least = 2;
};
};

16.5 Defining External Coverage Groups


You can import code coverage data from Verisity’s SureCov product into Specman and view the
integrated data in the Specman coverage browser and ASCII reports. The code-coverage grades for each
SureCov cover group and cover item are imported, and these grades are factored into the overall test
grade.

To import SureCov data into Specman, you have to create a SureCov coverage group in e. For
information on how to do this, see cover … using external=surecov on page 16-49.

For information on how to enable and disable the import and display of SureCov coverage groups, see
set_external_cover() on page 22-92.

For information on using SureCov coverage groups, see “Integrating SureCov Data” on page 7-62 in
Usage and Concepts Guide for e Testbenches.

16-48 e Language Reference


Coverage Constructs
Defining External Coverage Groups

16.5.1 cover … using external=surecov

Purpose
Create a customized SureCov cover group

Category
Struct member

Syntax
cover group-name using external=surecov [,agent_options=SureCov-options]
[, Specman-Elite-options] is {
item item-name using [,agent_options=SureCov-options] [, Specman-Elite-options];

};

Parameters

group-name The group-name is informational and can be any name you want—except that it
cannot be an event name.

using external = Identifies SureCov as the external coverage tool to integrate with Specman.
surecov

item-name The item-name is informational and can be any name you want

e Language Reference 16-49


Coverage Constructs
Defining External Coverage Groups

SureCov-options The SureCov-options are the same for both the cover group definition and the
item definitions. SureCov concatenates the cover group SureCov-options with
each cover item SureCov-options to define the coverage parameters.

In general:

• The cover group SureCov-options are intended to define whether you want
module or instance coverage
• The cover item SureCov-options are intended to define which type of code
coverage to import.

However, you can mix the two, as described below and as shown in the
examples:

• Options specified for the cover group apply to all items in the group.
• Options specified for a cover item apply for that item only.
You must include one of the following either in the group definition or in each
item definition:

module[=Verilog_module_name]
instance[=absolute_Verilog_instance_path]

If you specify a particular instance (with a path), you can also enter the
following option to ask for coverage statistics for the entire subdesign rooted at
that instance (rather than for coverage statistics for the instance alone):

hier

If you specify module or instance without a name, data is collected for all
Verilog modules or all Verilog instances. (The data for a given module consists
of the cumulative data for all the instances of that module.) If you specify a
module name or instance path without hier, data is collected for that particular
module or instance only.

You must also include at least one of the following either in the group definition
or in each item definition to define the type of code coverage you want to
import:

block
arc
state
trans
expr
event
toggle

16-50 e Language Reference


Coverage Constructs
Defining External Coverage Groups

Specman-Elite- The Specman-Elite-options are also the same for both the cover group definition
options and the cover item definitions.

The legal Specman-Elite-options are the regular cover text option and weight
option:

text=string
weight=uint

Set the weight for a given cover group or item to reflect the risk associated with
low coverage for that group or item compared to other cover groups or items. If
the risk is higher, set the weight higher.

Description
Defines a SureCov coverage group.

The mechanism for integrating SureCov with Specman is e code that defines SureCov coverage groups.
If you want to import all types of code coverage for all Verilog modules and instances, you can create
this e code automatically when you invoke SureCov to instrument the Verilog HDL design description.
See “Simulating with SureCov and Specman” on page 7-64 in Usage and Concepts Guide for e
Testbenches for information on how to do this.

You should manually create the SureCov coverage groups if you want to

• Limit the import of SureCov data to particular Verilog modules or instances or to particular kinds of
code coverage
• Associate the SureCov coverage group definition with a particular struct or unit.
• Supply a descriptive text string or set the weight for a SureCov coverage group or item.

Notes
• You can define as many SureCov coverage groups as you want under any struct or unit that you want.
• You cannot extend a SureCov coverage group using the is also syntax.
• To disable or enable the importing of SureCov data, use the set_external_cover() routine.

Cover Group Examples


Importing data for all modules:
cover sv_data using external=surecov, agent_options="module" is ...

e Language Reference 16-51


Coverage Constructs
Defining External Coverage Groups

Importing data for all instances:


cover sv_data using external=surecov, agent_options="instance" is ...

Importing data for the ALU module only:


cover sv_data using external=surecov, agent_options="module=ALU" is ...

Importing data for the ALU0 instance only:


cover sv_data using external=surecov, agent_options="instance=top.ALU0" is
...

Importing data for the ALU module only and specifying a grading weight of 4 for the current group
relative to other groups:
cover sv_data using external=surecov, agent_options="module=ALU", weight=4
is ...

Importing block and arc data for all modules. The following example shows the entire cover group
definition. Note that this example gives you one combined grade for block and arc data. To get a separate
grade for each type of coverage, you must define the types of coverage individually in item definitions:
cover sv_data using external=surecov, agent_options="module, block, arc"
is {
item sv_block_arc;
};

Cover Item Examples


Importing block and arc data for all modules:
cover sv_data using external=surecov, agent_options="module" is {
item sv_block using agent_options="block";
item sv_arc using agent_options="arc";
};

Importing block and arc data for all modules—this example is exactly the same as the previous example:
cover sv_data using external=surecov is { //Note that no module or
//instance is specified.
item block using agent_options="block, module";
item arc using agent_options="arc, module";
};

Importing block and arc data for the ALU_0 instance and importing state and trans data for the ALU_1
instance:
cover sv_data using external=surecov is {

16-52 e Language Reference


Coverage Constructs
Extending Coverage Groups

item block using agent_options="block,instance=top.ALU_0";


item arc0 using agent_options="arc, instance=top.ALU_0";
item state using agent_options="state, instance=top.ALU_1";
item arc1 using agent_options="trans, instance=top.ALU_1";
};

Importing block and arc data for the ALU_0 instance and importing state and trans data for the ALU
module:
cover sv_data using external=surecov is {
item block using agent_options="block, instance=top.ALU_0";
item arc0 using agent_options="arc, instance=top.ALU_0";
item state using agent_options="state, module=ALU";
item arc using agent_options="trans, module=ALU";
};

See Also
• “Defining Coverage Groups” on page 16-1 in the e Language Reference
• “Defining Basic Coverage Items” on page 16-8 in the e Language Reference

16.6 Extending Coverage Groups

16.6.1 cover ... using also ... is also

Purpose
Extend a coverage group

Category
Struct member

Syntax
cover event-type using also cover-option, …[ is also {coverage-item-definition; … } ]

Syntax examples:
cover rclk is also {
item rflag;
};

e Language Reference 16-53


Coverage Constructs
Extending Coverage Groups

cover rclk using also text = “RX clock”;

cover rclk using also no_collect is also {


item rvalue;
};

Parameters

event-type The name of the coverage group. This must be an event defined previously
in the struct. The event is the sampling event for the coverage group.

coverage-item- The definition of a coverage item.


definition

Description
The using also clause changes, overrides, or extends options previously defined for the coverage group.
The is also clause adds new items to a previously defined coverage group, or can be used to change the
options for previously defined items. See “Extending Coverage Items” on page 16-58.

Options for coverage-item-definition are listed in Table 16-1.

If a coverage group is defined under a when subtype, it can only be extended under that subtype.

If, in an extension of a cover group, you override a cover group when option, then the overriding
condition is only considered after the condition in the base group is satisfied. That is, sampling of the
item is only performed when the logical AND of the cover group when options is true.

When you use using also to extend or change a when, illegal, or ignore option, a special variable named
prev is automatically created. The prev variable holds the results of all previous when, illegal, or
ignore options, so you can use it as a shorthand to assert those previous options combined with a new
option value. For example, if a base struct cover group definition has “when = size == 5”, and an
extension has “using also when = (prev and size <= 10)”, the result is the same as “when = (size == 5 and
size <= 10)”.

If you have defined per_instance coverage (see “Coverage Per Instance” on page 16-15), you can
extend a particular cover group instance to complement or override options set in the base type cover
group. To change an item’s options in particular instance, enter the instance name in the cover is also
construct. For example, if a cover group named done contains a cover item named packet which has
buckets named Ethernet and ATM, use “cover done(packet==ATM) is also {...}” to extend the cover
group in ATM instances. Note also the following:

• If you extend an instance that never gets created (due to an ignore or illegal option), a warning is
issued and no information for the extension is put in the coverage data.

16-54 e Language Reference


Coverage Constructs
Extending Coverage Groups

• If you change the coverage options of an instance, the coverage data for the per_type item might no
longer reflect or agree with the per-instance coverage data.
• If you extend a sub-group using an illegal sub-group name, the extension is ignored. In particular,
be careful to express the sub-group name in decimal radix, even if another radix is defined for the
group or item. For more information, see “Instance Sub-group Names and the Coverage Item Radix”
on page 7-32 in the Usage and Concepts Guide for e Testbenches.

Example 1
The following example extends a coverage group named “info” by adding two cover items, “op2” and
“cross op1, op2”.
struct op_st {
op1: byte;
op2: byte;
event info;
cover info is {
item op1;
};
};
extend op_st {
cover info is also {
item op2;
cross op1, op2;
};
};

Example 2
In the following example, the cover done extension in the inst struct extension adds text to the cover
group named done, and adds a new item named interrupt to the group for instances of cpu_id==CPU_1:
type cpu_type: [CPU_1, CPU_2];
struct inst {
cpu_id: cpu_type;
cpu_on: bool;
interrupt: uint(bits:2);
event done;
cover done is {
item cpu_id using per_instance;
item cpu_on;
};
run() is also {
emit done;
};

e Language Reference 16-55


Coverage Constructs
Extending Coverage Groups

};
extend inst {
cover done(cpu_id==CPU_1) using also text="CPU #1" is also {
item interrupt;
};
};

Example 3
In the following example, the using also is used to cancel the global option:
struct packet{
len: uint (bits: 4);
kind: bool;
a: int (bits: 4);
event packet_gen;
cover packet_gen using global is {
item len;
item kind;
cross len, kind using text = "cross_l_k";
};
};
extend packet {
cover packet_gen using also global = FALSE;
};

Example 4
The following example show how to use using also to override and to narrow a when option:
// Original definition:
struct packet{
len: uint (bits: 4);
kind: bool;
event packet_gen;
cover packet_gen using when = len >= 3 is {
item len;
};
};

// Overriding the when definition:


extend packet {
cover packet_gen using also when = len == 4;
};

16-56 e Language Reference


Coverage Constructs
Extending Coverage Groups

// Narrowing the when definition:


extend packet {
cover packet_gen using also when = (prev and len <= 7);
};

Example 5
This example uses using also to extend the original definition of the cover done group by adding “when
= id > 64”, and then uses is also to add new coverage item, port, to the coverage group. Since the
coverage group is initially defined under a when subtype, the coverage group extensions can only be
done in an extension of that subtype.
<'
struct packet {
len: uint (bits: 4);
ptype: [ATM, Eth];
good: bool;
id: byte;
port: uint (bits: 2);
event done;
when good packet {
cover done is {
item len;
item ptype;
};
};
};
'>
<'
extend good packet {
cover done using also when = id > 64 is also {
item port;
};
};
'>

Example 6
The following example uses using also to set the weight of the per_type cover instance to zero so it will
not affect the overall grade.
type cpu_type: [CPU_1, CPU_2];
struct inst {
cpu_id: cpu_type;
cpu_on: bool;

e Language Reference 16-57


Coverage Constructs
Extending Coverage Items

event done;
cover done is {
item cpu_id using per_instance;
item cpu_on;
};
run() is also {
emit done;
};
};
extend inst {
cover done(per_type) using also weight = 0;
};

See Also
• “Defining Coverage Groups” on page 16-1
• “Defining Basic Coverage Items” on page 16-8

16.7 Extending Coverage Items

16.7.1 item ... using also

Purpose
Change or extend the options on a cover item.

Category
Coverage group item

Syntax
item item-name using also coverage-item-option, …

Syntax Example
item len using also radix = HEX;

16-58 e Language Reference


Coverage Constructs
Extending Coverage Items

Parameters

item-name The name you assign to the coverage item.

If you do not specify the optional type=exp, the value of the field named
item-name is used as the coverage sample value.

coverage-item- Coverage item options are listed in Table 16-2. The options can appear in any
option order after the using keyword.

Description
Cover item extensibility allows you to extend, change, or override a previously defined coverage item.
Coverage item options are listed in Table 16-2.

To extend a coverage item, you must also use “is also” for its coverage group: “cover event-type is also
{ item item-name using also …};”. See “Extending Coverage Groups” on page 16-53.

If a coverage item is originally defined under a when subtype, it can only be extended in the same
subtype of the base type.

When you extend an item, you must refer to the item by its full name. If an item with that name does not
exist, an error is issued.

For example, if an item “cross a, b” was defined previously without the name option, then you extend it
by creating a new item with the cross item’s default name, cross__a__b:
item cross__a__b using also ... // Cross item was defined with no name

If a cross item was defined using the name option, such as “cross a, b using name = c_a_b”, then you
extend it by creating a new item using the name “c_a_b”:
item c_a_b using also ... // Cross item was defined with a name

Similarly, for a transition item that was defined without the name option, such as “transition b”, you
extend it by creating a new item with the transition item’s default name, transition__b:
item transition__b using also ...// Transition item was defined with no name

If a transition item was defined using the name option, such as “transition b using name = t_b”, then you
extend it by creating a new item using the name “t_b”:
item t_b using also ... // Transition item was defined with a name

If an item is defined with an expression assigned to it, do not include the expression when you extend the
item:
item b: bool = f(a,c) ... // Item was defined with expression f(a,c)

e Language Reference 16-59


Coverage Constructs
Extending Coverage Items

item b using also ... // Omit the type and expression in the extension

When you use using also to extend or change a when, illegal, or ignore option, a special variable named
prev is automatically created. The prev variable holds the results of all previous when, illegal, or
ignore options, so you can use it as a shorthand to assert those previous options combined with a new
option value. For example, if an original coverage item definition has “when = size == 5”, and an
extension has “using also when = (prev and size <= 10)”, the result is the same as “when = (size == 5 and
size <= 10)”.

Example 1
In this example, an item named len is defined in the base type, then a new option, radix = HEX, is added,
and finally the option is redefined to radix = BIN.
<'
struct packet {
len: uint (bits: 4);
event done;
cover done is {
item len;
};
};
'>
<'
extend packet {
cover done is also {
item len using also radix = HEX;
};
};
'>
<'
extend packet {
cover done is also {
item len using also radix = BIN;
};
};
'>

Example 2
In this example, an item named good_short is defined using an expression involving two other fields in
the struct. The good_short coverage item is then extended by adding an at_least option. Note that the “:
bool = (good == TRUE and len < 4)” part of the original item definition is left out of the extension.
<'

16-60 e Language Reference


Coverage Constructs
Extending Coverage Items

struct packet {
len: uint (bits: 4);
good: bool;
event done;
cover done is {
item good_short: bool = (good == TRUE and len < 4);
};
};
'>
<'
extend packet {
cover done is also {
item good_short using also at_least = 4;
};
};
'>

Example 3
In this example, the automatic prev variable is used to combine the coverage item option in the original
coverage group definition with a narrower definition in the coverage item extension. The combined
result is that coverage is collected for the logical AND of (len < 8 and len > 4).
<'
struct packet {
len: uint (bits: 4);
good: bool;
event done;
cover done is {
item good using when = (len < 8), at_least = 10;
};
};
'>
<'
extend packet {
cover done is also {
item good using also when = (prev and len > 4);
};
};
'>

Example 4
This example extends the done coverage group in the good packet subtype, to restrict the sampling of the
len item to when the port item is either 0 or 1.

e Language Reference 16-61


Coverage Constructs
Extending Coverage Items

<'
struct packet {
len: uint (bits: 4);
good: bool;
port: uint (bits: 2);
event done;
when good packet {
cover done is {
item len;
};
};
};
'>
<'
extend good packet {
cover done is also {
item len using also when = port in [0,1];
};
};
'>

Example 5
The following shows several examples of coverage group and coverage item extensions, with comments
explaining what each one does.
<'
struct packet {
len: uint (bits: 6);
kind: bool;
port: int (bits: 4);
event packet_gen;
// Original group and item definition:
cover packet_gen using global, text = "Packet info" is {
item len using ranges = {range([0..63], "", 16)}, at_least = 5;
item kind;
cross len, kind using name = l_k;
};
run() is also {emit packet_gen;};
};
'>
<'
extend packet {
// Cancel the global option:
cover packet_gen using also global = FALSE;
};

16-62 e Language Reference


Coverage Constructs
Extending Coverage Items

'>
<'
extend packet {
// Add a new illegal option to the cross item:
cover packet_gen is also {
item l_k using also illegal = len == 3;
};
};
'>
<'
extend packet {
// Override the previous illegal option of the cross item:
cover packet_gen is also {
item l_k using also illegal = len == 4;
};
};
'>
<'
extend packet {
// Extend the illegal option, combining the previous definition
// (prev) with a new condition (len > 10):
cover packet_gen is also {
item l_k using also illegal = prev or (len > 10);
};
};
'>
<'
extend packet {
// Override the text option of the group, and add a weight option
// to the kind item:
cover packet_gen using also text = "Packet Information " is also {
item kind using also weight = 10;
};
};
'>
<'
extend packet {
// Add a new per_instance item to the packet_gen cover group:
cover packet_gen is also {
item port using per_instance;
};
};
'>
<'
extend packet {
// Exclude instances where the port number is 0:
cover packet_gen is also {

e Language Reference 16-63


Coverage Constructs
Coverage API Methods

item port using also ignore = (port == 0);


};
};
'>
<'
extend sys {
packet_list[10]: list of packet;
};
'>

See Also
• “Defining Coverage Groups” on page 16-1
• “Defining Basic Coverage Items” on page 16-8

16.8 Coverage API Methods


This section contains descriptions of the following predefined methods:

• scan_cover() on page 16-64


• start_group() on page 16-66
• start_instance() on page 16-67
• start_item() on page 16-68
• scan_bucket() on page 16-70
• end_item() on page 16-71
• end_instance() on page 16-72
• end_group() on page 16-73

16.8.1 scan_cover()

Purpose
Activate the Coverage API and specify items to cover

Category
Method

16-64 e Language Reference


Coverage Constructs
scan_cover()

Syntax
scan_cover(item-names: string): int;

Syntax Example
num_items = cover_info.scan_cover("cpu.inst_driven.*");

Parameters

item-names The names of the coverage items that should be scanned by scan_cover(). This is a
string of the form struct-name.group-name.item-name (for example,
“inst.start.opcode”). Wild cards are allowed.

Description
The scan_cover() method initiates the coverage data-scanning process. It goes through all the items in
all the groups specified in the item-names parameter in the order that groups and items have been
defined.

For each group, scan_cover() calls start_group(). For each instance in the group, scan_cover() calls
start_instance() . For each item in the current instance, scan_cover() calls start_item(). Then for each
bucket of the item, it calls scan_bucket(). After all of the buckets of the item have been processed, it
calls end_item(). After all items of the instance have been processed, it calls end_instance(). After all
instances in the group have been processed, it calls end_group().

Before each call to any of the above methods, the relevant fields in the user_cover_struct are updated
to reflect the current item (and also the current bucket for scan_bucket()).

The scan_cover() method returns the number of coverage items actually scanned.

Note
The scan_cover() method cannot be extended. The methods called by scan_cover() — start_group()),
start_instance(), start_item(), scan_bucket(), end_item(), end_instance() and end_group() — are
initially empty and are meant to be extended.

Example
<'
struct simple_cover_struct like user_cover_struct {
};
extend sys {
!cover_info: simple_cover_struct;
simple_cover_report() is {

e Language Reference 16-65


Coverage Constructs
start_group()

var num_items: int;


num_items = cover_info.scan_cover("cpu.inst_driven.*");
};
};
'>

See Also
• Chapter 7 “Analyzing Coverage” in the Usage and Concepts Guide for e Testbenches
• “The Coverage API” on page 7-95 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Methods” on page 16-64 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Example” on page 7-103 in the Usage and Concepts Guide for e Testbenches

16.8.2 start_group()

Purpose
Process coverage group information according to user preferences

Category
Method

Syntax
start_group();

Syntax Example
start_group() is {
if group_text != NULL {out("Description: ", group_text)};
};

Description
When the scan_cover() method initiates the coverage data scanning process for a group, it updates the
group-related fields within the containing user_cover_struct and then calls the start_group() method.
The start_group() method is called for every group to be processed by scan_cover(). For every instance
within a group, scan_cover() calls the start_instance() method.

16-66 e Language Reference


Coverage Constructs
start_instance()

The start_group() method is originally empty. It is meant to be extended to process group data
according to user preferences.

Note
start_group(), start_instance() and scan_cover() are all methods of the user_cover_struct.

Example
<'
struct simple_cover_struct like user_cover_struct {
start_group() is {
if group_text != NULL {out("Description: ", group_text)};
};
};
'>

See Also
• Chapter 7 “Analyzing Coverage” in the Usage and Concepts Guide for e Testbenches
• “The Coverage API” on page 7-95 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Methods” on page 16-64 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Example” on page 7-103 in the Usage and Concepts Guide for e Testbenches

16.8.3 start_instance()

Purpose
Process coverage instance information according to user preferences.

Category
Method

Syntax
start_instance();

Syntax Example
start_instance() is {

e Language Reference 16-67


Coverage Constructs
start_item()

if instance_text != NULL {out("Description: ", instance_text)};


};

Description
When the scan_cover() method initiates the coverage data scanning process for an instance, it updates
the instance-related fields within the containing user_cover_struct and then calls the start_instance()
method. The start_instance() method is called for every instance to be processed by scan_cover().

The start_instance() method is originally empty. It is meant to be extended to process instance data
according to user preferences.

Note
start_instance() and scan_cover() are methods of the user_cover_struct.

Example
<'
struct simple_show_cover_struct like user_cover_struct {
start_instance() is {
out("instance ", struct_name, ".", group_name, ".",
instance_name, ":");
if instance_text != NULL {out("Description: ", instance_text)};
};
};
'>

See Also
• Chapter 7 “Analyzing Coverage” in the Usage and Concepts Guide for e Testbenches
• “The Coverage API” on page 7-95 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Methods” on page 16-64 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Example” on page 7-103 in the Usage and Concepts Guide for e Testbenches

16.8.4 start_item()

Purpose
Process coverage item information according to user preferences

16-68 e Language Reference


Coverage Constructs
start_item()

Category
Method

Syntax
start_item();

Syntax Example
start_item() is {
if item_text != NULL {out("Description: ", item_text)};
};

Description
When the scan_cover() method initiates the coverage data scanning process for an item, it updates the
item-related fields within the containing user_cover_struct and then calls the start_item() method. The
start_item() method is called for every item to be processed by scan_cover().

The start_item() method is originally empty. It is meant to be extended to process item data according
to user preferences.

Note
start_item() and scan_cover() are methods of the user_cover_struct.

Example
<'
struct simple_show_cover_struct like user_cover_struct {
start_item() is {
out("item ", struct_name, ".", group_name, ".",
item_name, ":");
if item_text != NULL {out("Description: ", item_text)};
};
};
'>

See Also
• Chapter 7 “Analyzing Coverage” in the Usage and Concepts Guide for e Testbenches
• “The Coverage API” on page 7-95 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Methods” on page 16-64 in the Usage and Concepts Guide for e Testbenches

e Language Reference 16-69


Coverage Constructs
scan_bucket()

• “Coverage API Example” on page 7-103 in the Usage and Concepts Guide for e Testbenches

16.8.5 scan_bucket()

Purpose
Process coverage item information according to user preferences

Category
Method

Syntax
scan_bucket();

Syntax Example
scan_bucket() is {
out(count, " ", percent, "% ", bucket_name);
};

Description
When the scan_cover() method processes coverage data, then for every bucket of the item it updates the
bucket-related fields within the containing user_cover_struct and calls scan_bucket().

The scan_bucket() method is originally empty. It is meant to be extended to process bucket data
according to user preferences.

Note
scan_bucket() and scan_cover() are methods of the user_cover_struct.

Example
<'
struct simple_show_cover_struct like user_cover_struct {
scan_bucket() is {
out(str_repeat(" ", cross_level), count, " - ",
percent, "% - ", status, " - ", bucket_name);
};
};

16-70 e Language Reference


Coverage Constructs
end_item()

'>

See Also
• Chapter 7 “Analyzing Coverage” in the Usage and Concepts Guide for e Testbenches
• “The Coverage API” on page 7-95 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Methods” on page 16-64 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Example” on page 7-103 in the Usage and Concepts Guide for e Testbenches

16.8.6 end_item()

Purpose
Report end of item coverage information according to user preferences

Category
Method

Syntax
end_item();

Syntax Example
end_item() is {
out("finished item ", item_name, "\n");
};

Description
When the scan_cover() method completes the processing of coverage data for an item, it calls the
end_item() method to report the end of item information according to user preferences.

When all items in the current group have been processed, scan_cover() calls the start_instance()
method for the next instance.

The end_item() method is originally empty. It is meant to be extended so as to process item data
according to user preferences.

e Language Reference 16-71


Coverage Constructs
end_instance()

Note
end_item(), start_instance() and scan_cover() are all methods of the user_cover_struct.

Example
<'
struct simple_show_cover_struct like user_cover_struct {
end_item() is {
out("end of item ", item_name, "\n");
};
};
'>

See Also
• Chapter 7 “Analyzing Coverage” in the Usage and Concepts Guide for e Testbenches
• “The Coverage API” on page 7-95 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Methods” on page 16-64 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Example” on page 7-103 in the Usage and Concepts Guide for e Testbenches

16.8.7 end_instance()

Purpose
Process end of instance coverage information according to user preferences.

Category
Method

Syntax
end_instance();

Syntax Example
end_instance() is {
out("finished instance ", instance_name, "\n");
};

16-72 e Language Reference


Coverage Constructs
end_group()

Description
When the scan_cover() method completes the processing of coverage data for an instance, it calls the
end_instance() method to report the end of instance information according to user preferences.

When all instances in the current group have been processed, scan_cover() calls the start_group()
method for the next group.

The end_instance() method is originally empty. It is meant to be extended so as to process instance data
according to user preferences.

Note
end_instance(), start_group() and scan_cover() are all methods of the user_cover_struct.

Example
<'
struct simple_show_cover_struct like user_cover_struct {
end_instance() is {
out("end of instance ", instance_name, "\n");
};
};
'>

See Also
• “Analyzing Coverage” on page 7-1 in the Usage and Concepts Guide for e Testbenches
• “The Coverage API” on page 7-95 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Methods” on page 16-64 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Example” on page 7-103 in the Usage and Concepts Guide for e Testbenches

16.8.8 end_group()

Purpose
Report end of group coverage information according to user preferences

Category
Method

e Language Reference 16-73


Coverage Constructs
end_group()

Syntax
end_group();

Syntax Example
end_group() is {
out("finished group", group_name, "\n");
};

Description
When the scan_cover() method completes the processing of coverage data for a group, it calls the
end_group() method to report the end of group information according to user preferences.

The end_group() method is originally empty. It is meant to be extended so as to process item data
according to user preferences.

Note
end_group() and scan_cover() are both methods of the user_cover_struct.

Example
<'
struct simple_show_cover_struct like user_cover_struct {
end_group() is {
out("end of group", group_name, "\n");
};
};
'>

See Also
• “Analyzing Coverage” on page 7-1 in the Usage and Concepts Guide for e Testbenches
• “The Coverage API” on page 7-95 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Methods” on page 16-64 in the Usage and Concepts Guide for e Testbenches
• “Coverage API Example” on page 7-103 in the Usage and Concepts Guide for e Testbenches

16-74 e Language Reference


17 Simulation-Related Constructs
This chapter describes the following e constructs:

• “Verilog Statements or Unit Members” on page 17-1


• “VHDL Statements and Unit Members” on page 17-27
• “Simulation-Related Actions” on page 17-53
• “Simulation-Related Expressions” on page 17-64
• “Simulation-Related Routines” on page 17-68

See Also
• “Simulation-Related Methods” on page 22-52

17.1 Verilog Statements or Unit Members


Some basic functionality of the Verilog simulator interface, such as setting or sampling the values of
some Verilog objects, is enabled without any action on your part. However, some features, such as the
continuous driving of Verilog signals or calling of Verilog tasks and functions, requires some
user-specified declarations—verilog statements or unit members. The following sections describe these
constructs:

• verilog code on page 17-2


• verilog function on page 17-5
• verilog import on page 17-7
• verilog task on page 17-12
• verilog time on page 17-14

e Language Reference 17-1


Simulation-Related Constructs
verilog code

• verilog variable reg | wire on page 17-16


• verilog variable memory on page 17-24

17.1.1 verilog code

Purpose
Write Verilog code directly to the stubs file

Category
Statement or unit member

Syntax
verilog code {list-of-strings}

Syntax examples:
verilog code {"initial clk = 1'b1;"};
unit router {
verilog code { "initial "; s};
verilog code ls;
};

Parameters

list-of-strings Any list of strings that after concatenation creates any sequence of legal Verilog
code. Specman does not check for Verilog syntax errors. Verilog syntax errors are
identified only when you compile or interpret the file with the Verilog compiler.
The curly braces are required only if the list of strings contains more than one string.

Description
Specifies a list of Verilog strings to be included in the Verilog stubs file each time it is generated. The
stubs file contains code that enables some Verilog-related features. It is recommended to use verilog
code statements or unit members to modify this file rather than to modify it by hand.

17-2 e Language Reference


Simulation-Related Constructs
verilog code

When verilog code is used as a unit member, any non-constant expressions in the list of strings are
calculated within the context of a unit instance. Each unit instance adds a separate fragment of Verilog
code to the stubs file. When used as a statement, any non-constant expressions in the list of strings are
calculated within the context of sys.

Note
Whenever you add or modify a verilog code statement or unit member or add an instance of a unit
containing a verilog code unit member, you must create a new stubs file:

• For SpeXsim users, look for information related to generating SpeXsim stubs files in the SpeXsim
Users Guide
• For other simulators, see “Creating HDL Stubs Files” on page 8-4 in the Specman Elite Integrator’s
Guide for more information.

Example 1
This example uses a verilog code statement to define a Verilog event, clk_rise, in the stubs file. The
Verilog clk_rise event is triggered on every positive edge of the HDL signal, top.clk. Deriving an e event
from the Verilog clk_rise event rather than from the HDL signal top.clk itself reduces the number of
callbacks to Specman by half.

top.v
module top();
reg clk;

initial clk = 0;
forever begin
#50 clk = ~clk;
end

endmodule

clk.e
verilog code {
"event clk_rise;";
"always @(posedge top.clk) begin";
" ->clk_rise;";
"end"
};
extend sys {
event clk_rise is change('specman.clk_rise')@sim;

e Language Reference 17-3


Simulation-Related Constructs
verilog code

on clk_rise {
print sys.time;
};
};

Result
vrst-tool> load clk
Loading clk.e ...
read...parse...update...patch...h code...code...clean...GC(simulator)...

Specman clk> test


Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
Running should now be initiated from the simulator side
Specman clk>
sys.time = 50
sys.time = 150
sys.time = 250
sys.time = 350
sys.time = 450
sys.time = 550
sys.time = 650
...

Example 2
This example initializes an HDL clock by adding code to the stubs file. It uses verilog code as a unit
member so that the clock name and its initial value can be configured on a unit instance basis.
<'
unit channel {
clk_name: string;
keep soft clk_name == "clk";
clk_init: bit;
keep soft clk_init == 1;
s: string;
keep s == append("initial ", full_hdl_path(),".",clk_name,
"= ",clk_init,";");
verilog code {s};
};

extend sys {
chan: channel is instance;

17-4 e Language Reference


Simulation-Related Constructs
verilog function

keep chan.hdl_path() == "top";


};
'>

See Also
• $sn | sn | call sn on page 13-10 in the Specman Command Reference
• write stubs on page 13-7 in the Specman Command Reference

17.1.2 verilog function

Purpose
Declare a Verilog function

Category
Statement or unit member

Syntax
verilog function 'HDL-pathname' (verilog-function-parameter[, … ]): result-size-exp

Syntax examples:
verilog function 'top.write_mem'(addr:32, data:32):32;

extend my_unit {
verilog function '(read_mem_name)'(addr:addr_width):ret_size;
}

Parameters

HDL-pathname The full path to the Verilog function. If this name is not a constant, it is
calculated after the final step of pre-run generation. See “'HDL-pathname'” on
page 17-65 for a complete description of HDL path syntax.

e Language Reference 17-5


Simulation-Related Constructs
verilog function

verilog-function- The syntax for each parameter is parameter_name:size_exp. The parameter


parameter name need not match the name in Verilog. All parameters are passed by
position, not name. All parameters must be inputs, and the number of
parameters must match the number declared in the Verilog function.
The size-exp must be a legal unsigned integer expression specifying the size in
bits of the parameter. No default size is assumed. If the size expression is not a
constant, it is calculated after the final step of pre-run generation.

result-size-exp A legal unsigned integer expression specifying the size in bits of the returned
value. No default size is assumed. If the size expression is not a constant, it is
calculated after the final step of pre-run generation.

Description
Declares a Verilog function in e so that it can be called from a time-consuming method (TCM).

When verilog function is used as a unit member, any non-constant expressions in the list of strings are
calculated within the context of a unit instance. Each unit instance adds a separate fragment of Verilog
code to the stubs file. When used as a statement, any non-constant expressions in the list of strings are
calculated within the context of sys.

Notes
• Calls to Verilog functions are value-returning expressions.
• Even though Verilog functions do not consume time in Verilog, they do so on the Specman side
because they require a context switch between Specman and the simulator. Thus, Verilog functions
can be called only from TCMs.
• Specman does not support concurrent calls to a Verilog function. In other words, you cannot call the
same Verilog function from more than one thread in the same Specman tick.
• You must explicitly pack all structs before passing them in as inputs to the function.
• Whenever you add or modify a verilog function statement or unit member or add an instance of a
unit containing a verilog function unit member, you must create a new stubs file and then load the
file into the Verilog simulator.
• For SpeXsim users, look for information related to generating SpeXsim stubs files in the SpeXsim
Users Guide
• For other simulators, see “Creating HDL Stubs Files” on page 8-4 in the Specman Elite Integrator’s
Guide for more information.

17-6 e Language Reference


Simulation-Related Constructs
verilog import

Example
The following function has two 32-bit inputs and returns a 32-bit error status. The memory_driver unit
calls the top.write_mem() function.
unit memory_driver {
addr_width: uint;
keep soft addr_width == 32;
data_width: uint;
keep soft data_width == 32;
verilog function 'top.write_mem'(addr:addr_width,data:data_width):32;

event mem_enable is rise ('top.enable') @sim;


write() @mem_enable is {
var error_status: int;
error_status = 'top.write_mem'(31,45);
};
};

See Also
• “'HDL-pathname'” on page 17-65
• show functions on page 13-3 in the Specman Command Reference
• write stubs on page 13-7 in the Specman Command Reference
• “Rules for Defining and Extending Methods” on page 7-2

17.1.3 verilog import

Purpose
Read in Verilog text macros

Category
Statement

Syntax
verilog import file-name

e Language Reference 17-7


Simulation-Related Constructs
verilog import

Syntax Example
verilog import defines_MCP.v;

Parameters

file-name Specman searches for imported files in the directories specified in $SPECMAN_PATH.
If the file is not found in $SPECMAN_PATH, Specman then searches the directory
where the importing file resides.

Description
Reads in a file that includes Verilog `define text macros. After reading in the file, you can use these text
macros in Specman expressions.

Specman understands several Verilog language constructs when reading the `define macros:

• It recognizes the Verilog `include directive and reads in the specified file.
• It recognizes the Verilog `ifdef, `else, and `endif directives and skips the irrelevant parts of the file
according to the currently defined symbols.

Notes
• verilog import statements cannot be used as unit members.
• verilog import statements must appear in the e file before any other statement except package,
define, and import statements. package statements must appear first in the file.
• Whenever you add or redefine an imported Verilog macro that appears in an HDL declaration, you
need to create a new stubs file and then load the file into the simulator. For example, if you use a
Verilog macro to specify the width of the parameters in a task identified with verilog task, then you
need to recreate the stubs file if the macro is redefined.
• For SpeXsim users, look for information related to generating SpeXsim stubs files in the SpeXsim
Users Guide
• For other simulators, see “Creating HDL Stubs Files” on page 8-4 in the Specman Elite Integrator’s
Guide for more information.

Example 1
To import more than one file, you must use multiple verilog import statements or use the Verilog
compiler directive `include. You can import the same file more than once. If you define the same macro
with different values before using it, Specman uses the definition that is loaded last. Once you use the
macro, however, you cannot redefine it. Subsequent definitions are ignored without warning.

17-8 e Language Reference


Simulation-Related Constructs
verilog import

The following example shows how to import multiple files. Note that once X is used in the x.e file, its
value of 7 (the last loaded definition before it is used) cannot be changed.

a.v
'define X 5

b.v
'define X 7

x.e
verilog import a.v ;
verilog import b.v ;
extend sys {
run() is also {
print 'X;
};
};

y.e
verilog import a.v ;
extend sys {
run() is also {
print 'X;
};
};

z.e
verilog import b.v ;

Result
vrst-tool> load x.e
Reading Verilog a.v (imported by x.e) ...

Read 1 defines (+0 deferred defines) from a.v

Reading Verilog b.v (imported by x.e) ...


Loading x.e ...
read...parse...update...patch...h code...code...clean...
Specman x> show defines

e Language Reference 17-9


Simulation-Related Constructs
verilog import

Currently verilog defined symbols =


Index Name Value Type
---------------------------------------------------------------
0 'X 7
Specman x> load y.e
Loading y.e ...
read...parse...update...patch...h code...code...clean...
Specman y> show defines
Currently verilog defined symbols =
Index Name Value Type
---------------------------------------------------------------
0 'X 7
Specman y> test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
7 = 7
7 = 7
No actual running requested.
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.
Specman y> load z.e
Loading z.e ...
read...parse...update...patch...h code...code...clean...
Specman z> show defines
Currently verilog defined symbols =
Index Name Value Type
---------------------------------------------------------------
0 'X 7
Specman z> test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
7 = 7
7 = 7
No actual running requested.
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.
Specman z> quit

Example 2
You can use Verilog macros everywhere a Specman macro is allowed. For example, you can use Verilog
macros in width declarations or when assigning values to enumerated items.

17-10 e Language Reference


Simulation-Related Constructs
verilog import

macros.v
'define BASIC_DELAY 2
'ifdef OLD_TECH
'define TRANS_DELAY 'BASIC_DELAY+3
'else
'define TRANS_DELAY `BASIC_DELAY
'endif
'define TOP tb
'define READY `TOP.ready
'define WORD_WIDTH 8
'define HIGH_BIT 7

dut_driver.e
verilog import macros.v;

extend sys {
event pclk;
driver: dut_driver;
event pclk is only @any; -- for stand-alone mode
};

struct dut_driver {
ld: list of int(bits: `WORD_WIDTH);
keep ld.size() in [1..30];

stimuli() @sys.pclk is {
'`READY' = 1;
for each in ld {
wait until true('`READY' == 1);
'`TOP.data_in' = it;
wait [`TRANS_DELAY];
};
stop_run();
};
run() is also {
start stimuli();
};
};

See Also
• “Using Verilog Defines” on page 8-72 in the Specman Elite Integrator’s Guide
• “specman deferred” on page 17-66

e Language Reference 17-11


Simulation-Related Constructs
verilog task

• show defines on page 13-1 in the Specman Command Reference


• “Environment Variables, Initialization Files, and Scripts” on page 7-24 in the Specman Elite Integrator’s
Guide

17.1.4 verilog task

Purpose
Declare a Verilog task

Category
Statement or unit member

Syntax
verilog task 'HDL-pathname' (verilog-task-parameter[, …])

Syntax examples:
verilog task 'top.read'(addr: 64, cell: 128:out);
verilog task 'top.(read_task_name)'(addr:addr_width, cell:cell_width:out);

Parameters

HDL-pathname The full path to the Verilog task. If this name is not a constant, it is
calculated after the final step of pre-run generation. See
“'HDL-pathname'” on page 17-65 for a complete description of HDL
path syntax.

verilog-task-parameter The verilog-task-parameter has the syntax name:size-exp[:direction].


The name need not match the name in Verilog. All parameters are
passed by position, not name. The number of parameters must match
the number of parameters in the task declaration in Verilog.
The size-exp must be a legal unsigned integer expression specifying
the size in bits of the parameter. No default size is assumed. If the size
expression is not a constant, it is calculated after the final step of
pre-run generation.
The direction is one of the following keywords: input (or in), output
(or out), inout. The default is input.

17-12 e Language Reference


Simulation-Related Constructs
verilog task

Description
Declares a Verilog user-defined task or system task in e so that it can be called from a TCM. In the
following example, “addr” is a 64-bit input and “cell” is a 128-bit output. $display is a Verilog system
task.
verilog task 'top.read'(addr: 64, cell: 128:out);
verilog task '$display'(int:32);

When verilog task is used as a unit member, any non-constant expressions in the list of strings are
calculated within the context of a unit instance. Each unit instance adds a separate fragment of Verilog
code to the stubs file. When used as a statement, any non-constant expressions in the list of strings are
calculated within the context of sys.

Notes
• Calls to Verilog tasks are time-consuming actions and can only be made from TCMs.
• Specman does not support concurrent calls to a Verilog task. In other words, you cannot call the same
Verilog task from multiple threads in the same Specman tick.
• You must explicitly pack all structs before passing them in as inputs to the task.
• Whenever you add or modify a verilog task statement or unit member or add an instance of a unit
containing a verilog task unit member, you must create a new stubs file and then load the file into
the Verilog simulator.
• For SpeXsim users, look for information related to generating SpeXsim stubs files in the SpeXsim
Users Guide
• For other simulators, see “Creating HDL Stubs Files” on page 8-4 in the Specman Elite Integrator’s
Guide for more information.

Example
This task is similar to the Verilog function “write_mem” shown in the example for the verilog function
unit member (verilog function on page 17-5). This task returns an error status as an output parameter.
struct mem_w {
addr: int;
data: int(bits: 64);
};

unit receiver {
read_task_name: string;
addr_width: uint;
keep soft addr_width == 32;

e Language Reference 17-13


Simulation-Related Constructs
verilog time

data_width: uint;
keep soft data_width == 64;
verilog task 'top.(read_task_name)'
(addr:addr_width:in,data:data_width:out,status:32:out);
event mem_read_enable;

get_mem(mw: mem_w) @mem_read_enable is {


var error_status: int;

'top.(read_task_name)'(mw.addr, mw.data, error_status);


check that error_status == 0;
};
};

See Also
• “'HDL-pathname'” on page 17-65
• show tasks on page 13-4 in the Specman Command Reference
• write stubs on page 13-7 in the Specman Command Reference
• “Rules for Defining and Extending Methods” on page 7-2

17.1.5 verilog time

Purpose
Set the Verilog time resolution

Category
Statement

Syntax
verilog time verilog-time-scale

Syntax examples:
verilog time 100ns/10ns;
verilog time num1 ns/num2 ns;

17-14 e Language Reference


Simulation-Related Constructs
verilog time

Parameters

verilog-time-scale The Verilog specification for time scale has the syntax time-exp unit /
precision-exp unit.
time-exp and precision-exp must be integer expressions. If the expression is
not a constant, it is calculated after the final step of pre-run generation.
According to Verilog standards, the legal values for the integer expressions
are 1, 10 and 100, but Specman does not check whether the value is legal or
not.
unit is any unit of time measurement. According to Verilog standards, the
valid character strings are s, ms, us, ns, ps, and fs, but Specman does not check
whether the value is legal or not.

Description
Sets the time resolution in the Verilog stubs file to the specified verilog-time-scale.

If you do not use the verilog time statement, Specman uses the time scale from the simulator side.

Specman uses the verilog time statement to scale the following:

• # delays in verilog variable or verilog code statements


• delays in Specman temporal expressions
• simulation time as shown in sys.time, a 64-bit integer field that stores Specman time.

Notes
• When the DUT contains more than one `timescale directive, using the verilog time statement is
strongly recommended. Otherwise, Specman time becomes dependent on the order of the Verilog
modules.
• If you need to call Specman (using $sn) from Verilog code explicitly, use the verilog code statement
to put the Specman call in the stubs file. This ensures that the call to Specman has the time scale
shown in the stubs file instead of a time scale from other parts of the Verilog code.
• The Verilog time scale precision in the verilog time statement must be set to the precision required
for # delays in verilog variable or verilog code statements.
• verilog time statements cannot be used as unit members.
• If you use a non-constant expression for the time or the precision, this expression is computed in the
context of sys and so must be visible in that context.

e Language Reference 17-15


Simulation-Related Constructs
verilog variable reg | wire

• Whenever you add or modify a verilog time statement in an e module, you must create a new stubs
file and then load the file into the Verilog simulator.
• For SpeXsim users, look for information related to generating SpeXsim stubs files in the SpeXsim
Users Guide
• For other simulators, see “Creating HDL Stubs Files” on page 8-4 in the Specman Elite Integrator’s
Guide for more information.

Example 1
verilog time 10ns/1ns;

Example 2
verilog time (num1)ns/(num2)ns;
extend sys {
num1:int;
num2:int;

keep num1 == 100;


keep num2 == 10;
};

See Also
• $sn | sn | call sn on page 13-10 in the Specman Command Reference
• write stubs on page 13-7 in the Specman Command Reference

17.1.6 verilog variable reg | wire

Purpose
Identify a Verilog register or wire

Category
Statement or unit member

Syntax
verilog variable 'HDL-pathname' using option, …

17-16 e Language Reference


Simulation-Related Constructs
verilog variable reg | wire

Syntax examples:
verilog variable 'top.dbus[5:0]' using wire,drive="@(posedge top.m)";
verilog variable 'i1.(reset_name)[m:l]' using wire,drive_hold=dh_opt;

Parameters

HDL-pathname The complete path to the Verilog object, a register or a net.If this name
is not a constant, it is calculated after the final step of pre-run
generation. See “'HDL-pathname'” on page 17-65 for a complete
description of HDL path syntax.
Note If the register or wire has a width greater than 1, the bit range
must be explicitly declared in order to create internal temporary
registers of the correct width.

The width range has the syntax


[right-bound-exp:left-bound-exp]

where right-bound-exp and left-bound-exp are any legal integer


expressions. The width range must be the same (including the
descending or ascending order) as in the Verilog declaration. If these
expressions are not constants, they are calculated after the final step of
pre-run generation.

option A list of one or more of the following options separated by commas.

drive=string-exp Specifies that the Verilog object is driven when the event specified by
string-exp occurs. string-exp is any legal string expression specifying
a legal Verilog timing control. If this expression is not a constant, it is
calculated after the final step of pre-run generation.
Note When you force an HDL object, the value is applied
immediately, without a delay, even if a drive delay has been specified
for the object.

drive_hold=string-exp Specifies a Verilog event after which the HDL object’s value is set to
z. string-exp is any legal string expression specifying a legal Verilog
timing control. If this expression is not a constant, it is calculated after
the final step of pre-run generation. The drive_hold option requires
that you also specify the drive option.

e Language Reference 17-17


Simulation-Related Constructs
verilog variable reg | wire

net, Specifies that the Verilog object is a net (wire).

wire • Some simulators, including SpeXsim, require this option only


when you drive from within the model as well as from e and you
want the Verilog wire to be resolved.
• Other simulators (VCS and ModelSim) require this option anytime
you drive a Verilog wire from e.

If not used, Specman will simply “deposit” a value on the wire at the
end of the timestep, overwriting values driven by the simulator at that
time. Deposited values can be changed by the simulator at the next
simulation time-step.

forcible Allows forcing of Verilog wires. By default Verilog wires are not
forcible. This option requires that you also specify the net or wire
option.

strobe=string-exp Specifies that the value of the Verilog object is sampled at the event
specified using string-exp. string-exp is any legal string expression
specifying a legal Verilog timing control. If this expression is not a
constant, it is calculated after the final step of pre-run generation.

Description
Allows access in Specman to the Verilog object named in 'HDL-pathname', a register or a net. In general,
you can access Verilog objects using the 'HDL-pathname' expression. The verilog variable statement is
necessary only when you want to

• drive or force a wire


• drive or sample a wire or reg with an offset from the Specman callback
By default the value driven by Specman is always driven last, overwriting all values driven by Verilog.

If you have not included verilog variable statement and one is required, you will see an error message
such as
*** Error: Cannot drive 'top.sig_wire'. Driving a wire which is not declared
with 'verilog variable suing wire' is not allowed by the simulator.
at line 6 in @your_module

verilog variable declarations for the same object can be repeated (to allow incremental building of e
code), but each repeated declaration must be identical.

17-18 e Language Reference


Simulation-Related Constructs
verilog variable reg | wire

When verilog variable is used as a unit member, any non-constant expressions in the list of strings are
calculated within the context of a unit instance. Each unit instance adds a separate fragment of Verilog
code to the stubs file. When used as a statement, any non-constant expressions in the list of strings are
calculated within the context of sys.

Notes
• Assignments to Verilog nets are implemented through the Verilog code in the stubs file. These
assignments are not propagated until the start of simulation, so no pre-run initialization of Verilog
nets can be performed by Specman.
• Whenever you add or modify a verilog variable statement or unit member or add an instance of a
unit containing a verilog variable unit member, you must create a new stubs file and then load the
file into the Verilog simulator.
• For SpeXsim users, look for information related to generating SpeXsim stubs files in the SpeXsim
Users Guide
• For other simulators, see “Creating HDL Stubs Files” on page 8-4 in the Specman Elite Integrator’s
Guide for more information.

Example 1
The following example sets drive and drive_hold timing controls on a register:
verilog variable 'top.reset_request' using
drive="#5",drive_hold="@(negedge clock)";

struct controller {
event reset_request;
on reset_request {
'top.reset_request' = 1;
};
};

If, for example, the Specman event “reset_request” is emitted at time 100ns, then the Verilog top-level
register “reset_request” is set at time 105ns, and it is disconnected (assigned Z value) at the next
negative edge of the clock.

Example 2
The following example sets strobe and drive delays for a wire using a verilog variable unit member
and a non-constant expression.
unit box {
bus_name: string;

e Language Reference 17-19


Simulation-Related Constructs
verilog variable reg | wire

bus_width: uint;
strobe_option: string;
drive_option: string;
drive_hold_option: string;

verilog variable '(bus_name)[bus_width-1:0]' using


strobe=strobe_option,
drive=drive_option,
drive_hold=drive_hold_option,
wire;
};
extend sys {
box: box is instance;
keep box.hdl_path() == "top_box";
keep box.bus_name == "xx_bus";
keep box.bus_width == 64;
keep box.strobe_option == "@(posedge top.clk_b)";
keep box.drive_option == "@(negedge top.clk_b) #3";
keep box.drive_hold_option == "@(negedge top.clk_b) #10";
};

The verilog variable … using strobe statement creates an additional temporary variable in the Verilog
stubs file that strobes the value of the real Verilog object, according to the timing conditions specified for
this option. Any read operation of the real Verilog object in e code accesses the temporary variable and
thus gets the latest strobed value. In this example, an additional register, “top__xx_bus”, is created and
this register gets the current value of “top.xx_bus[63:0]” at every positive edge on “top.clk_b”.

Example 3
Here is a complete example of how to drive a clock wire from Specman.

clk.e
verilog time 1ns / 1ns;
verilog variable 'top.ev_clock' using wire ;
define CLOCK_HALF_PERIOD 50;

extend sys {
dut: dut;
};

struct dut {
clk: uint (bits:1);
event dut_evclk is rise ('top.ev_clock')@sim;

driver() @sys.any is {

17-20 e Language Reference


Simulation-Related Constructs
verilog variable reg | wire

var drive_var: int = 1;


'top.ev_clock' = 0;
while(TRUE) {
wait delay(CLOCK_HALF_PERIOD);
'top.ev_clock' = drive_var;
drive_var = ~drive_var;
};
};

wait_and_stop() @sys.any is {
wait [100] * cycle;
stop_run();
};

run() is also {
start driver();
start wait_and_stop();
};
};

clk.v
'timescale 1 ns / 1ns
module top;
wire ev_clock ;

endmodule

Example 4
This example shows how to use verilog variable as a unit member with a relative path. In this case, the
full HDL path of the unit driver is prefixed to the relative path ‘rxd’ in order to access the rxd signal in
each of the DUT receivers. For example ‘~/top.chan0.rx.rxd’ accesses the rxd signal in the first
channel’s receiver.

enet_env.e
<'
unit enet_env {
keep hdl_path() == "~/top";
ports : list of enet_port is instance;

keep soft ports.size() == 4;

e Language Reference 17-21


Simulation-Related Constructs
verilog variable reg | wire

keep for each in ports {


.number == index;
.hdl_path() == append("chan", index);
};
};

unit enet_port {
number : int;

injector : driver is instance;


collector : receiver is instance;

keep injector.parent_port == me;


keep injector.number == number;
keep injector.hdl_path() == "rx";
keep collector.parent_port == me;
keep collector.number == number;
keep collector.hdl_path() == "tx";
};

unit driver {
parent_port : enet_port;
number : int;

event clk is rise ('~/top.clock')@sim;

verilog variable 'rxd[7:0]' using wire;// Unit member with relative path

send_data() @clk is {
out("Injecting data at ", full_hdl_path());
var pkt: packet;
gen pkt;
var total_data : list of byte;
total_data = pack(packing.low, pkt);
print total_data;
wait cycle;
for each (data) in total_data {
'rxd' = data; // inject data
wait cycle;
};
wait [50] * cycle;
stop_run();
};

run() is also {
start send_data();
};

17-22 e Language Reference


Simulation-Related Constructs
verilog variable reg | wire

};
unit receiver {
parent_port : enet_port;
number : int;
};

struct packet {
%data: list of byte;
};

extend sys {
enet: enet_env is instance;
};
'>

top.v
module top ();
reg clock;

initial clock = 0;
always #50 clock = ~clock;

channel chan0();
channel chan1();
channel chan2();
channel chan3();

endmodule

module channel();
receiver rx();
transmitter tx();

endmodule

module receiver();
wire [7:0] rxd;

endmodule

module transmitter();

endmodule

e Language Reference 17-23


Simulation-Related Constructs
verilog variable memory

Results
C1> run
Injecting data at ~/top.chan0.rx
total_data = (27 items, dec):
201 120 34 42 158 187 67 96 255 147 240 2 .0
38 21 43 49 151 151 10 79 181 102 176 145 .12
249 124 77 .24

Injecting data at ~/top.chan1.rx


total_data = (12 items, dec):
70 48 246 35 78 170 156 136 10 133 33 156 .0

Injecting data at ~/top.chan2.rx


total_data = (22 items, dec):
170 70 48 175 50 112 39 26 109 53 65 156 .0
152 108 147 136 83 239 62 217 131 249 .12

Injecting data at ~/top.chan3.rx


total_data = (3 items, dec):
146 71 163 .0

Last specman tick - stop_run() was called


Normal stop - stop_run() is completed
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.
Memory Usage - 24.5M program + 17.7M data = 42.3M total
CPU Usage - 0.4s system + 4.0s user = 4.4s total (87.8% cpu)
Simulation stopped via $stop(2) at time 5450 NS + 1
C2> exit

See Also
• “'HDL-pathname'” on page 17-65
• write stubs on page 13-7 in the Specman Command Reference
• force on page 17-53
• release on page 17-59

17.1.7 verilog variable memory

Purpose
Identify a Verilog memory

17-24 e Language Reference


Simulation-Related Constructs
verilog variable memory

Category
Statement or unit member

Syntax
verilog variable 'HDL-pathname [mem-range] [verilog-reg-range]' [using vcs_pli]

Syntax Example
verilog variable 'top.my_mem[1:10000][31:0]';

Parameters

HDL-pathname The full path to the Verilog memory. If this name is not a constant, it is
calculated after the final step of pre-run generation. See “'HDL-pathname'” on
page 17-65 for a complete description of HDL path syntax.

mem-range A legal expression specifying the range of the memory elements. A legal
expression has the syntax [exp:exp]. If this expression is not a constant, it is
calculated after the final step of pre-run generation.

verilog-reg-range A legal expression specifying the width of each memory element. A legal
expression has the syntax [exp:exp]. If this expression is not a constant, it is
calculated after the final step of pre-run generation.

using vcs_pli Enables the propagation of Verilog memory updates with VCS. If Specman is
not linked to the VCS simulator, this option is ignored.
Note Due to a limitation of the VCS simulator extension, changes to bits
containing x or z values are not propagated.

Description
Allows access in Specman to a Verilog memory. verilog variable declarations for the same memory can
be repeated (to allow incremental building of e code), but each repeated declaration must be identical.

Note that the order of the range specifiers in the Specman syntax is the reverse of the Verilog declaration
order.

For example, if a memory is defined in Verilog as follows:


module top;
reg[31:0] my_mem[1:10000];
endmodule

e Language Reference 17-25


Simulation-Related Constructs
verilog variable memory

The corresponding verilog variable statement is:


verilog variable 'top.my_mem[1:10000][31:0]';

When verilog variable is used as a unit member, any non-constant expressions in the list of strings are
calculated within the context of a unit instance. Each unit instance adds a separate fragment of Verilog
code to the stubs file. When used as a statement, any non-constant expressions in the list of strings are
calculated within the context of sys.

Notes
• SpeXsim users: this statement is not required in order to access Verilog memories.
• Only a single register element from the Verilog memory can be accessed in one e expression (such
as 'top.my_mem[0]' or 'top.my_mem[j]').
• Verilog memories are always accessed directly, not cached, for reading and writing. You must organize
how reading and writing memories occurs within a Specman tick.
• Verilog memories cannot be accessed before simulation starts. This means that memories cannot be
initialized during Specman pre-run generation. You must provide code to generate initial memory
contents on the fly at time zero.
• For NC Verilog, code that contains memory declarations must be compiled with a NC Verilog
command line option, -nomempack.
• Access to Verilog memories is not supported when Specman is linked with SpeedSim.
• Whenever you add or modify a verilog variable statement or unit member or add an instance of a
unit containing a verilog variable unit member, you must create a new stubs file and then load the
file into the Verilog simulator.
• For SpeXsim users, look for information related to generating SpeXsim stubs files in the SpeXsim
Users Guide
• For other simulators, see “Creating HDL Stubs Files” on page 8-4 in the Specman Elite Integrator’s
Guide for more information.

Example
This example shows one possible way of initializing a Verilog memory at the beginning of the
simulation.

xmem.v
module xmem;
reg [63:0] bank [1:10];

17-26 e Language Reference


Simulation-Related Constructs
VHDL Statements and Unit Members

endmodule

module topmod;
reg clk;
initial clk = 0;
always #10 clk = ~clk;
xmem m1();
endmodule

memstarter.e
verilog variable 'topmod.m1.bank[1:10][63:0]';

struct mem_starter {
event init_event is rise('topmod.clk')@sim;
on init_event {
var rand_s: int (bits: 64);

for j from 1 to 10 {
gen rand_s;
'topmod.m1.bank[j]' = rand_s;
};
quit();
};
};

extend sys {

ms: mem_starter;
event clk is fall('topmod.clk')@sim;
};

See Also
• “'HDL-pathname'” on page 17-65
• write stubs on page 13-7 in the Specman Command Reference

17.2 VHDL Statements and Unit Members


Some basic functionality of the VHDL simulator interface, such as setting or sampling the values of
some VHDL objects, is enabled without any action on your part. However, some features, such as the
continuous driving of VHDL signals or calling of VHDL subprograms, requires some user-specified
declarations - vhdl statements. The following sections describe these statements and unit members:

e Language Reference 17-27


Simulation-Related Constructs
vhdl code

• vhdl code on page 17-28


• vhdl driver on page 17-31
• vhdl function on page 17-38
• vhdl procedure on page 17-43
• vhdl time on page 17-51

17.2.1 vhdl code

Purpose
Write VHDL code directly to the stubs file

Category
Statement or unit member

Syntax
vhdl code {list-of-strings}

Syntax Example
vhdl code {
"library common_lib;";
"use common_lib.common_types.all;";
};
unit router {
vhdl code {
"library my_lib;";
"use my_lib.my_types.all;";
};
};

Parameters

list-of-strings Any list of strings that after concatenation creates any sequence of legal VHDL code.
Specman does not check for VHDL syntax errors. VHDL syntax errors are identified
only when you compile the file with the VHDL compiler.
The curly braces are required only if the list of strings contains more than one string.

17-28 e Language Reference


Simulation-Related Constructs
vhdl code

Description
Specifies a list of VHDL strings to be included in the stubs file (“specman_sim.vhd”) before the
SPECMAN_REFERENCE entity. The stubs file contains code that enables some simulation-related
features. It is recommended to use vhdl code statements or unit members to modify this file rather than
to modify it by hand.

When vhdl code is used as a unit member, any non-constant expressions in the list of strings are
calculated within the context of a unit instance. Each unit instance adds a separate fragment of VHDL
code to the stubs file. When used as a statement, any non-constant expressions in the list of strings are
calculated within the context of sys.

Note
• Whenever you add or modify a vhdl code statement or unit member or add an instance of a unit
containing a vhdl code unit member, you must create a new stubs file.
• For SpeXsim users, look for information related to generating SpeXsim stubs files in the SpeXsim
Users Guide
• For other simulators, see “Creating HDL Stubs Files” on page 8-4 in the Specman Elite Integrator’s
Guide for more information.

Example 1
A common use for the vhdl code statement is to include packages. For example, parameter types may be
declared in a different package from the one where the subprogram is declared. The example below adds
the “common_types” package defined in the “common_lib” library to the stubs file.
vhdl code {
"library common_lib;";
"use common_lib.common_types.all;";
};

The VHDL stubs file generated with this statement looks like this:
library common_lib;
use common_lib.common_types.all;

entity SPECMAN_REFERENCE is
end SPECMAN_REFERENCE;

e Language Reference 17-29


Simulation-Related Constructs
vhdl code

Example 2
You can also use non-constants in vhdl code expressions. The following example configures the DUT
clock differently for each channel instance.
<'
unit channel {
chan_number: string;
keep chan_number == hdl_path();

s: string;
keep s == append("library worklib; \n",
"configuration phased_clocks of TOP is \n",
" use worklib.all; \n",
" for behavioral \n",
" for CLK: clock \n",
" use entity clkgen(",chan_number,"_clock); \n",
" end for; \n",
" end for; \n",
"end phased_clocks;" );
vhdl code {s};
};
'>

This vhdl code unit member inserts the following VHDL code into the VHDL stubs file:
library worklib;
configuration phased_clocks of TOP is
use worklib.all;
for behavioral
for CLK: clock
use entity clkgen(CHAN0_clock);
end for;
end for;
end phased_clocks;
library worklib;
configuration phased_clocks of TOP is
use worklib.all;
for behavioral
for CLK: clock
use entity clkgen(CHAN1_clock);
end for;
end for;
end phased_clocks;

17-30 e Language Reference


Simulation-Related Constructs
vhdl driver

See Also
• “VHDL Statements and Unit Members” on page 17-27
• write stubs on page 13-7 in the Specman Command Reference

17.2.2 vhdl driver

Purpose
Drive a VHDL signal continuously via the resolution function

Category
Unit member

Syntax
vhdl driver 'HDL-pathname' using option, …

Syntax examples:
unit top {
vhdl driver '~/top/data' using initial_value=32'bz,
disconnect_value=32'bz;
vhdl driver '(addr_name)' using initial_value= 1'bz,
delay= addr_delay;
};

Parameters

HDL-pathname A full or a relative VHDL path to the signal. If the signal has more than
one driver, one driver in the DUT and one in Specman, for example, then
the signal must be of a resolved type (such as std_logic). If this name is
not a constant, it is calculated after the final step of pre-run generation.
See “'HDL-pathname'” on page 17-65 for a complete description of HDL
path syntax.

option A list of one or more of the following options separated by commas.


None of the options is required.

e Language Reference 17-31


Simulation-Related Constructs
vhdl driver

disconnect_value= Any legal integer expression specifying the value to be used on Specman
[integer-expression | restore to disconnect the driver. The default is z. If this expression is not
verilog-literal] a constant, it is calculated after the final step of pre-run generation.
This value is used when you restore Specman after issuing a test
command but do not restart the simulator. This value should be set to a
value that does not affect the overall value of the resolved signal. For
std_logic signals, the value should be z.
Note If the VHDL signal name is a computed name then it will be
computed again at the before the restore. Thus, in order to correctly
assign a disconnect_value, it is important to keep the expressions used in
the computed name unchanged during the simulation session.

Use a Verilog literal to specify values containing x or z. A Verilog literal


is a sized literal that can contain 0, 1, x, and z, for example 16'bx.

delay= Any legal integer expression specifying a delay for all assignments. The
integer-expression delay time units are determined by the current time unit setting. See vhdl
time on page 17-51 for information on how to set time units for
Specman. If this expression is not a constant, it is calculated after the
final step of pre-run generation.

mode=[INERTIAL | Used only when delay is also specified, this option specifies whether
TRANSPORT] pulses whose period is shorter than the delay are propagated through the
driver. INERTIAL specifies that such pulses are not propagated.
TRANSPORT, the default, specifies that all pulses, regardless of length,
are propagated.
The mode option also influences what happens if another driver (either
VHDL or another unit) schedules a signal change and before that change
occurs, this driver schedules a different change. With INERTIAL, the
first change never occurs.

initial_value= Any legal integer expression specifying an initial value for the signal. If
[integer-expression | this expression is not a constant, it is calculated after the final step of
verilog-literal] pre-run generation.
When Specman is driving a resolved signal that is also driven from
VHDL, unless an initial value is specified, the signal value is X until the
first value is driven from Specman, even if a 0 or a 1 is driven from
VHDL.
Use a Verilog literal to specify values containing x or z. A Verilog literal
is a sized literal that can contain 0, 1, x, and z, for example 16'bx.

17-32 e Language Reference


Simulation-Related Constructs
vhdl driver

Description
The vhdl driver unit member identifies a VHDL signal that, when assigned to by an e method of that
unit, is driven continuously using the resolution function. In contrast, signal assignments made without
vhdl driver are over-ridden by any subsequent assignment from a VHDL process or from another e
method, rather than the two driven values being resolved.

Any non-constant expressions in the list of strings are calculated within the context of a unit instance.
Each unit instance adds a separate fragment of Verilog code to the stubs file.

To require resolution between VHDL process assignments and an e method assignment or between e
method assignments, you can use the vhdl driver unit member. The vhdl driver unit member creates a
driver that influences any assignments to the specified VHDL signal made by a method in the enclosing
unit or by a method in a struct enclosed by this unit.

You can create multiple drivers for the same signal by making multiple instances of a unit that contains
a vhdl driver unit member. In this case, the driver is created for every unit instance. This may be useful
when modeling multiple modules on a tri-state bus, for example. Multiple drivers can be created only for
signals of a resolved type.

Note that there is a significant semantic difference between a verilog variable using drive
statement/unit member and a vhdl driver unit member. verilog variable using drive creates a single
Verilog always block for each actual Verilog signal. This means that there is one and only one driver for
this signal.

Notes
• vhdl driver influences only assignments made by methods of the unit in which it was declared or by
methods of the structs nested in this unit. Therefore, you must use the vhdl driver unit member in
each unit that drives a particular signal; adding a vhdl driver unit member in only one of the units
that drives it is not sufficient.
• vhdl driver is a unit member, not a statement. If you need to declare a vhdl driver and your
verification environment does not have any user-defined units, then you must explicitly extend sys
(sys is a unit):
<'
extend sys {
vhdl driver '/top/comp_io' using initial_value=1'bz;
};
'>

• The vhdl driver unit member is supported with SpeXsim with certain limitations. Furthermore, usage
of this unit member requires that both VHDL and Verilog stubs files be generated. See the SpeXsim
User Guide for important information concerning vhdl driver.

e Language Reference 17-33


Simulation-Related Constructs
vhdl driver

• The vhdl driver unit member is supported with ModelSim VHDL, but not other third-party
simulators. For multi-bit signal support, ModelSim version 5.4c is earliest version that can be used.
• For ModeSim users only:The vhdl driver unit member does not affect the VHDL stubs file, so
it is not necessary to rewrite the stubs file if you add or modify a vhdl driver unit member in
your e code.
• The pathname for multi-bit signals must be specified without a bit range, for example, 'sig'. If you
include the bit range, for example, 'sig[1:0]', Specman does not apply the driver.

Example Using SpeXsim

top.vhd
library IEEE;
use IEEE.std_logic_1164.all;

entity top is
end top;

architecture arch of top is

signal a : std_logic := '0';


signal b : std_logic := '0';
signal c : std_logic := '0';
signal s : std_logic := '1';
signal t : std_logic ;

signal clk : std_logic := '0';

begin

clk_pr:process(clk) begin
clk <= not clk after 50 ns;
end process clk_pr;

shifter: process(clk) begin


if (clk'event AND clk = '1') THEN
a <= not a ;
b <= a xor b ;
c <= (a and b) xor c ;

if (b = '0' and c = '1') THEN


t <= '1' ;
elsif (b = '1' and c = '1') THEN
t <= '0' ;

17-34 e Language Reference


Simulation-Related Constructs
vhdl driver

else t <= 'Z' ;


end if ;
end if ;
end process shifter ;

end arch ;

driver.e
<'
extend sys {
event clk is fall('~/top/clk')@sim ;
drive0 : drive is instance ;
drive1 : drive is instance ;
keep drive0.hdl_path() == "~/top";
keep drive0.name == "t";
keep drive1.hdl_path() == "~/top";
keep drive1.name == "t";
};

unit drive {
name: string;
vhdl driver '(name)' using disconnect_value=1'bz,
initial_value = 1'bz;
driver() @sys.clk is {
'(name)' = 1 ;
wait cycle ;
'(name)' = 1'bz ;
wait [7] ;
'(name)' = 0 ;
wait cycle ;
stop_run() ;
};
run() is also { start driver() } ;
};
'>

Result
spexsim -s
C1> .
0 : t = U
50 : t = Z
100 : t = 1
200 : t = Z
450 : t = 1

e Language Reference 17-35


Simulation-Related Constructs
vhdl driver

650 : t = 0
850 : t = Z
900 : t = 0
Simulation stop requested
C2> #finish;

Example Using ModelSim

top.vhd
library IEEE;
use IEEE.std_logic_1164.all;

entity top is
end top;

architecture arch of top is

signal a : std_logic := '0';


signal b : std_logic := '0';
signal c : std_logic := '0';
signal s : std_logic := '1';
signal t : std_logic ;

signal clk : std_logic := '0';

component comspec
end component;
for all: comspec use entity work.SPECMAN_REFERENCE (arch);

begin

clk_pr:process(clk) begin
clk <= not clk after 50 ns;
end process clk_pr;

shifter: process(clk) begin


if (clk'event AND clk = '1') THEN
a <= not a ;
b <= a xor b ;
c <= (a and b) xor c ;

if (b = '0' and c = '1') THEN


t <= '1' ;
elsif (b = '1' and c = '1') THEN
t <= '0' ;

17-36 e Language Reference


Simulation-Related Constructs
vhdl driver

else t <= 'Z' ;


end if ;
end if ;
end process shifter ;

I: comspec;
end arch ;

driver.e
<'
extend sys {
event clk is fall('~/top/clk')@sim ;
drive0 : drive is instance ;
drive1 : drive is instance ;
keep drive0.hdl_path() == "~/top";
keep drive0.name == "t";
keep drive1.hdl_path() == "~/top";
keep drive1.name == "t";
};

unit drive {
name: string;
vhdl driver '(name)' using disconnect_value=1'bz,
initial_value = 1'bz;
driver() @sys.clk is {
'(name)' = 1 ;
wait cycle ;
'(name)' = 1'bz ;
wait [7] ;
'(name)' = 0 ;
wait cycle ;
stop_run() ;
};
run() is also { start driver() } ;
};
'>

Result (ModelSim waveform)


run -all
# 0 : t = U
# 50 : t = Z
# 100 : t = 1
# 200 : t = Z

e Language Reference 17-37


Simulation-Related Constructs
vhdl function

# 450 : t = 1
# 650 : t = 0
# 850 : t = Z
# 900 : t = 0
# Simulation stop requested
quit

See Also
• “'HDL-pathname'” on page 17-65
• “VHDL Statements and Unit Members” on page 17-27

17.2.3 vhdl function

Purpose
Declare a VHDL function defined in a VHDL package

Category
Statement or unit member

Syntax
vhdl function 'identifier' using option, …

Syntax examples:
unit calc {
vhdl function 'max' using
interface="(op1:word64; op2:word64) return word64",
library="work", package="arith_pkg";

vhdl function '(vhdl_min_name)' using


interface=intf,library=lib_name,package=package_name;
};

17-38 e Language Reference


Simulation-Related Constructs
vhdl function

Parameters

identifier The operator symbol (for example '"and”') or the name of the
VHDL function as specified in the package. If the identifier
is not a constant, it is calculated after the final step of pre-run
generation.

option A comma-separated list of two or more of the following


options. The interface, library and package options are
required.

interface= A legal string expression that specifies the interface list for
“(string-exp) return return-subtype” the function. If this expression is not a constant, it is
calculated after the final step of pre-run generation.
The legal syntax for this string is
[parameter-class] identifier :subtype[;…]
The only output of the function is the returned value.
The optional parameter class is constant or signal — as
specified in the VHDL declaration — and is transparent for
Specman.
The identifier does not have to be the name of the parameter
as specified in the package but the parameter subtype must
match exactly the package specification.
The type of the returned value must match exactly the
package specification. The type must also be one of the types
supported by Specman. See “VHDL Object Types” on page
8-10 in the Specman Elite Integrator’s Guide.

library=string-exp A legal string expression specifying the name of the VHDL


library containing the package where the function is defined.
If this expression is not a constant, it is calculated after the
final step of pre-run generation.

package= A legal string expression specifying the package name. If this


string-exp expression is not a constant, it is calculated after the final step
of pre-run generation.

e Language Reference 17-39


Simulation-Related Constructs
vhdl function

alias=string-exp A legal string expression that specifies the name with which
the function will be called from e. If this expression is not a
constant, it is calculated after the final step of pre-run
generation.
There are various reasons to use aliases. For example, an alias
is required when there are overloaded functions with the same
names but different interfaces. It must also be used for VHDL
functions that overload operator symbols (for example,
function “+”…) because the call from e cannot contain
double quotes.

declarative_item=string-exp A legal string expression that specifies one or more use


clauses that are placed in the stubs file at the local scope of the
function call rather than at the global scope of the
SPECMAN_REFERENCE entity. If this expression is not a
constant, it is calculated after the final step of pre-run
generation.
This option may prevent unwanted overwriting of
declarations in the stubs file. See “Example 1” on page 17-46
for an example of declarative_item used with vhdl
procedure.

Description
Declares a VHDL function in e so that it can be called from a time-consuming method (TCM).

When there is a call to a procedure with a constant or signal parameter, the value of the constant or signal
is passed.

If there are functions in a single package that have the same name but different numbers or types of
parameters, make a separate declaration in e for each one you plan to call and specify a unique alias for
each declaration.

When vhdl function is used as a unit member, any non-constant expressions in the list of strings are
calculated within the context of a unit instance. Each unit instance adds a separate fragment of Verilog
code to the stubs file. When used as a statement, any non-constant expressions in the list of strings are
calculated within the context of sys.

Notes
• The VHDL function specifiers “pure” and “impure” are not supported.

17-40 e Language Reference


Simulation-Related Constructs
vhdl function

• If an alias is not used, then a call to a VHDL function requires the full VHDL name in the following
format: library_name.package_name.function_name.
• Calls to VHDL functions are value-returning expressions. They are time-consuming and can only be
made from TCMs.
• Function calls must explicitly specify actual values—either scalars or lists of scalars—for all
parameters. Default values for parameters are not supported.
• Whenever you add or modify a vhdl function statement in an e module, you must create a new stubs
file.
• For SpeXsim users, look for information related to generating SpeXsim stubs files in the SpeXsim
Users Guide
• For other simulators, see “Creating HDL Stubs Files” on page 8-4 in the Usage and Concepts
Guide for e Testbenches for more information.

Example 1
VHDL allows overloading of subprogram names. It is possible, for example, to define two functions
with the name “increment” where the number and type of arguments or the return type may differ:
function increment (a: integer) return integer is …
function increment (a: integer; n:integer) return integer is …

In cases like this, you must create an alias for each version that you intend to call.
vhdl function 'increment' using
interface="(a: integer) return integer",
library="work", package="pkg", alias="integer_inc_1";

vhdl function 'increment' using


interface="(a: integer; n: integer) return integer",
library="work", package="pkg",
alias="integer_inc_n";

extend sys {
event clk is rise ('top.clk') @sim;

test(a:int)@clk is {
check that 'integer_inc_1'(a) == 'integer_inc_n'(a,1);
};
};

e Language Reference 17-41


Simulation-Related Constructs
vhdl function

Example 2
Another case where aliasing may be required is when a subprogram contains unconstrained array
parameters or unconstrained return values. For example, “ToStdLogicVector” accepts an integer and
converts it to a STD_LOGIC_VECTOR of the given length, probably truncating the value.

In order to support subprograms with unconstrained array parameters or return values, Specman must be
notified about all (or maximal) potential lengths in the given test. This is required because Specman
must provide a VHDL stub code that will specify the exact returned value type. Accordingly you may
need to use multiple aliases for the same VHDL function.
library ieee;
use IEEE.std_logic_1164.all;

package pkg is
function ToStdLogicVector(oper:INTEGER; length:NATURAL) \
return STD_LOGIC_VECTOR;
end pkg;

You must create an alias for each of the possible lengths of the returned value.
vhdl function 'ToStdLogicVector' using
interface= "(oper:INTEGER; length:NATURAL) \
return STD_LOGIC_VECTOR(0 to 31)",
library="lib", package="pkg",
alias="ToStdLogicVector32";

vhdl function 'ToStdLogicVector' using


interface="(oper:INTEGER; length:NATURAL) \
return STD_LOGIC_VECTOR(15 downto 0)",
library="lib", package="pkg",
alias="ToStdLogicVector16";

See Also
• “'HDL-pathname'” on page 17-65
• “VHDL Statements and Unit Members” on page 17-27
• show functions on page 13-3 in the Specman Command Reference
• show subprograms on page 13-6 in the Specman Command Reference
• write stubs on page 13-7 in the Specman Command Reference

17-42 e Language Reference


Simulation-Related Constructs
vhdl procedure

17.2.4 vhdl procedure

Purpose
Declare a VHDL procedure defined in a VHDL package

Category
Statement or unit member

Syntax
vhdl procedure 'identifier' using option, …

Syntax Example
unit calc {
vhdl procedure 'do_arith_op' using
interface="(op1:integer; op2: integer; \
op_code: func_code; result: out integer)",
library="work", package="arith_pkg";

vhdl procedure '(vhdl_min_name)' using


interface=intf,library=lib_name,package=package_name;
};

Parameters

identifier The name of the VHDL procedure as specified in the package. If this
identifier is not a constant, it is calculated after the final step of pre-run
generation.

e Language Reference 17-43


Simulation-Related Constructs
vhdl procedure

option A comma-separated list of two or more of the following options. The


library and package options are required.

interface= A legal string expression that specifies the interface list for the procedure.
“(string-exp)” If this expression is not a constant, it is calculated after the final step of
pre-run generation.
The legal syntax for this string is
[ parameter_class ] identifier : [mode] subtype[;…]
The optional parameter class is constant, variable, or signal — as
defined in the VHDL declaration — and is transparent for Specman.
Mode is in, inout or out. The default mode is in.
The identifier does not have to be the name of the parameter as specified
in the package but the subtype must match exactly the specification in the
package. The subtype must also be one of the types supported by
Specman. See “VHDL Object Types” on page 8-10 in the Specman Elite
Integrator’s Guide.

library= A legal string expression specifying the name of the library containing
string-exp the package where the procedure is defined. If this expression is not a
constant, it is calculated after the final step of pre-run generation.

package= A legal string expression specifying the package name. If this expression
string-exp is not a constant, it is calculated after the final step of pre-run generation.

alias= A legal string expression that specifies the name with which the
string-exp procedure will be called from e. If this expression is not a constant, it is
calculated after the final step of pre-run generation.
There are various reasons to use aliases. For example, an alias is required
when there are overloaded procedures with the same names but different
interfaces. It is also useful when two different procedures have the same
name but belong to different packages.

declarative_item= A legal string expression that specifies a use clause that is placed at the
string-exp local scope of the procedure call rather than at the global scope of the
SPECMAN_REFERENCE entity in the stubs file. If this expression is
not a constant, it is calculated after the final step of pre-run generation.
This option prevents unwanted overwriting of declarations in the stubs
file. See “Example 1” on page 17-46.

Description
Declares a VHDL procedure in e so that it can be called from a time-consuming method (TCM).

17-44 e Language Reference


Simulation-Related Constructs
vhdl procedure

When vhdl procedure is used as a unit member, any non-constant expressions in the list of strings are
calculated within the context of a unit instance. Each unit instance adds a separate fragment of Verilog
code to the stubs file. When used as a statement, any non-constant expressions in the list of strings are
calculated within the context of sys.

When there is a call to a procedure with a constant or variable parameter, the value of the constant or
variable is passed. Signal parameters are handled differently.

When there is a call to a procedure with a signal parameter of mode in, instead of passing the value of
the signal, it passes the signal object itself. Any reference to the formal parameter within the procedure
is exactly like a reference to the actual signal itself. A consequence of this is that if the procedure
executes a wait statement, the signal value may be different after the wait statement is completed and the
procedure resumes.

When there is a call to a procedure with a signal parameter of mode out, the procedure receives a
reference for the signal. When the procedure performs a signal assignment statement on the formal
parameter, the value is propagated to the actual signal parameter. Note that output parameters are
assigned in the default Specman way; the value is assigned immediately but is not forced and not
assigned via a VHDL driver.

If there are procedures in a single package that have the same name but different numbers or types of
parameters, you must make a separate declaration in e for each one you plan to call and specify a unique
alias for each declaration.

In order to allow multiple Specman threads to call the same time-consuming VHDL procedure
simultaneously and in parallel, you must create multiple unit members - one per such a thread. This may
be done, for example, by placing a vhdl procedure declaration in a unit, which logically maps the block
of the DUT to a Specman thread, and creating multiple instances of that unit. Specman creates a separate
VHDL process in the stubs file for each unit member, and you can then invoke the procedure
simultaneously from different unit instances.

There is a significant semantic difference between VHDL procedure/function and Verilog task/function
unit members. Verilog tasks are always located within Verilog modules. Thus, there may be multiple
instances of those tasks within a DUT. Accordingly, an HDL path of a corresponding unit in e maps
between the unit and a Verilog task instances. On the VHDL side, Specman supports only subprograms
that are declared in VHDL packages. Such subprograms have nothing to do with HDL paths.
Accordingly, the correspondence between e unit instance and a VHDL procedure unit member is
completely abstract—it just creates a separate process in the VHDL stub file. Such correspondence is
natural, because in VHDL the time-consuming package subprograms are re-entrant and may be called
simultaneously from parallel VHDL component instances.

The fact that VHDL subprogram unit members are not bound to HDL paths causes a difference in how
these subprograms may be called from nested unit instances. The essence of this difference is that if
some VHDL procedure/function is declared in a parent unit instance, then it may be called from other
units, instantiated below, without a duplication of the subprogram declaration.

e Language Reference 17-45


Simulation-Related Constructs
vhdl procedure

Notes
• Calls to VHDL procedures are time-consuming and can only be made from TCMs.
• Passing a bit select of a signal parameter (for example, 'signal_name[3:7]') is not supported. (Passing
a bit select of a constant or variable is supported.)
• Passing a signal parameter with @x, @z, or @n (for example, 'signal_name@x') is not supported.
(Passing a constant or variable with @x, @n, or @z is supported.)
• If an alias is not used, then a call to VHDL procedure requires the full VHDL name in the following
format: library_name.package_name.function_name
• You must explicitly pack all structs before passing them in as inputs to a procedure.
• Procedure calls must explicitly specify actual values for all parameters. Default values for parameters
are not supported.
• Whenever you add or modify a vhdl procedure statement in an e module, you must create a new
stubs file.
• For SpeXsim users, look for information related to generating SpeXsim stubs files in the SpeXsim
Users Guide
• For other simulators, see “Creating HDL Stubs Files” on page 8-4 in the Usage and Concepts
Guide for e Testbenches for more information.

Example 1
This example shows how to handle the case where two different types from two different packages have
the same name (“state”). Using the declarative_item option to specify a use clause at the scope local to
the procedure avoids name collision.
vhdl procedure 'check_state' using
interface="(s:state)",
library="lib1",
package="procedures_pkg",
declarative_item="use lib1.fsm_types.all;";

vhdl procedure 'show' using


interface="(s:state)",
library="lib2",
package="display_pkg",
declarative_item="use lib2.widget_types.all;";

17-46 e Language Reference


Simulation-Related Constructs
vhdl procedure

Result
The specman_qvh.vhd file has the following structure. Note that the library declarations appear at the
global scope of the SPECMAN_REFERENCE entity. Any use clauses included with vhdl code
declarations would also appear at this scope. In contrast, the use clauses declared with declarative_item
appear at the scope of the appropriate function call.
entity SPECMAN_FMI is
end SPECMAN_FMI;
architecture fmi_stub of SPECMAN_FMI is
...
library IEEE;
use IEEE.std_logic_1164.all;

entity specman_wave is

This example shows how to allow parallel invocation of the same procedure. There are two instances of
the unit “transactor”, which contains a vhdl procedure unit member. The TCM “test()” of each unit
instance is called during the run phase, simultaneously invoking two different VHDL processes. Notice
that the parentheses are required when calling the procedure from e, even though “send_packet()” has no
interface.
unit transactor {
vhdl procedure 'send_packet' using library="work",
package="pkg";

test() @sys.clk is {
'work.pkg.send_packet'();
};
};

extend sys {
event clk is rise ('top.clk') @sim;

transactor1: transactor is instance;


transactor2: transactor is instance;

run() is also {
start transactor1.test();
start transactor2.test();
};
};

e Language Reference 17-47


Simulation-Related Constructs
vhdl procedure

Example 2
This example illustrates the transmitting and receiving of a one-byte packet. The unit “driver” uses the
VHDL procedure “transmit_packet_data” to drive one bit of data per cycle. This procedure accepts two
input parameters by value and two signal parameters: an input, “clock”, and an output, the data bit.

The unit “receiver” uses the VHDL procedure “receive_packet” for reading the data. This procedure
accepts two input signal parameters: the clock and one bit of data (both are changing during the running
of the procedure) and one output parameter: the resulting package. The procedure waits for the rise of
the clock and then reads the new data.

The VHDL package:


package transmit_receive_pkg is

subtype data_range is integer range 1 to 8;


type packet_array is array (data_range) of bit;

procedure receive_packet (signal rx_data: in bit;


signal rx_clock: in bit;
data_buffer: out packet_array);

procedure transmit_packet_data (packet_type: in bit;


data_buffer: in bit_vector(6 downto 0);
signal rx_clock: in bit;
signal rx_data: out bit);

end transmit_receive_pkg;

package body transmit_receive_pkg is

procedure receive_packet (signal rx_data: in bit;


signal rx_clock: in bit;
data_buffer: out packet_array) is
begin
for index in data_range loop
wait until rx_clock = '1';
data_buffer(index) := rx_data;
end loop;
end receive_packet;

procedure transmit_packet_data ( packet_type: in bit;


data_buffer: in bit_vector(6 downto 0);
signal rx_clock: in bit;
signal rx_data: out bit ) is
begin
for index in 0 to 6 loop

17-48 e Language Reference


Simulation-Related Constructs
vhdl procedure

wait until rx_clock = '0';


rx_data <= data_buffer(index);
end loop;

wait until rx_clock = '0';


rx_data <= packet_type;
end transmit_packet_data;
end;

The entity and architecture:


use work.transmit_receive_pkg.all;
entity receiver is
end receiver;

architecture behavioral of receiver is

component SN
end component;
for all: SN use entity work.specman_reference (arch);

signal data : bit;


signal clock: bit;

begin

clock_generator : process
begin
clock <= '0' after 2 ns, '1' after 10 ns;
wait for 10 ns;
end process clock_generator;

SN_INST: SN;

end behavioral;

The receiver unit


<'

unit receiver {

vhdl procedure 'receive_packet' using interface= "( \


signal rx_data: bit; signal rx_clock: bit; \

e Language Reference 17-49


Simulation-Related Constructs
vhdl procedure

data_buffer: out packet_array)", library= "work",


package = "transmit_receive_pkg";

!received_packet : byte;
event clk is fall ('clock')@sim;

receive_packet() @clk is {
'work.transmit_receive_pkg.receive_packet'('data',
'clock',received_packet);

wait cycle;
outf("The packet that was received : \
%#x\n",received_packet);

wait cycle;
};
};

unit driver{

vhdl procedure 'transmit_packet_data' using interface= "( \


packet_type:in bit; \
data_buffer : in bit_vector(6 downto 0); \
signal rx_clock : in bit; signal rx_data : out bit )",
library= "work", package = "transmit_receive_pkg";

transmit_data : list of bit;


keep transmit_data.size() == 7;

packet_type : bit;

event clk is rise ('clock')@sim;

send_packet()@clk is{
'work.transmit_receive_pkg.transmit_packet_data'(
packet_type,transmit_data,'clock','data');
};
};

extend sys{

driver :driver is instance;


receiver :receiver is instance;

keep driver.hdl_path() == "/";


keep receiver.hdl_path() == "/";

17-50 e Language Reference


Simulation-Related Constructs
vhdl time

run() is also {
start driver.send_packet();
start receiver.receive_packet();
start do_check();
};

do_check()@receiver.clk is {
var transmit_packet: byte;
unpack(NULL,driver.transmit_data.reverse(),
transmit_packet[7:1]);
transmit_packet[0:0] = driver.packet_type;
outf("The packet that was transmitted : \
%#x\n",transmit_packet);
wait [10]*cycle;
check that (transmit_packet == receiver.received_packet)
else dut_error(" the data did not pass correctly");

stop_run();
};
};
'>

See Also
• “'HDL-pathname'” on page 17-65
• “VHDL Statements and Unit Members” on page 17-27
• show procedures on page 13-5 in the Specman Command Reference
• show subprograms on page 13-6 in the Specman Command Reference
• write stubs on page 13-7 in the Specman Command Reference

17.2.5 vhdl time

Purpose
Sets VHDL time resolution

Category
Statement

e Language Reference 17-51


Simulation-Related Constructs
vhdl time

Syntax
vhdl time integer-exp time-unit

Syntax Example
vhdl time 100 ns;

Parameters

integer-exp A legal integer expression. If the expression is not a constant, it is calculated after
the final step of pre-run generation.

time-unit Any valid VHDL time unit.

Description
Sets the time resolution to the specified time scale. This time scale is used to scale:

• Delays in Specman temporal expressions


• Delays specified in vhdl driver unit members
• Simulation time as shown in sys.time, a 64-bit integer field that stores Specman time.
If you use NC simulator and do not specify a time resolution, the default resolution for Specman is 1ns.
(NC VHDL always uses a time scale of 1 fs.). Likewise for SpeXsim users who enable NC SIM
compatibility mode by passing the -ncsim switch to the sxbuild compiler.

If you use ModelSim, the default resolution always matches the settings chosen on the simulator side in
the initialization file or with the simulator invocation option. Likewise for SpeXsim users who enable
ModelSim compatibility mode by passing the -mti runtime switch to the runtime executable.

You can change the default to take into account vhdl time statements in your code by setting the
-enable_vhdl_time_mti simulation config option, as described in configure simulationc on page 6-54
in the Specman Command Reference.

Notes
• The vhdl time statement does not affect the stubs file, so it is not necessary to rewrite the stubs file
if you change the time scale.
• vhdl time cannot be used as a unit member.
• If you use a non-constant expression in a vhdl time statement, this expression is computed in the
context of sys and so must be visible in that context.

17-52 e Language Reference


Simulation-Related Constructs
Simulation-Related Actions

Example 1
The following statement sets the time resolution to 100ns.
vhdl time 100 ns;

Example 2
In this example, the time resolution is not calculated until after the final step of pre-run generation.
vhdl time num ns;

extend sys {

num:int;
keep num == 100;
};

See Also
• “VHDL Statements and Unit Members” on page 17-27
• vhdl driver on page 17-31

17.3 Simulation-Related Actions


There are two simulation-related actions in e:

• force on page 17-53


• release on page 17-59

17.3.1 force

Purpose
Force a value on an HDL object

Category
Action

e Language Reference 17-53


Simulation-Related Constructs
force

Syntax
force 'HDL-pathname' = exp

Syntax Example
force '~/top/sig' = 7;

Parameters

HDL-pathname The full path name of an HDL object, optionally including expressions. See
“'HDL-pathname'” on page 17-65 for more information.

exp Any scalar expression or literal constant, as long as it is composed only of 1's and
0's. No x or z values are allowed. Thus “16'hf0f1” or (sys.my_val + 5) are legal.

Description
Forces an HDL object to a specified value, overriding the current value and preventing the DUT from
driving any value. If you force a part of a vectored object, the force action is propagated to the rest of the
object.

SpeXsim with a Verilog Design or Third-Party Verilog Simulators

When Specman is linked with a Verilog simulator, you can apply a force action to any net or wire that
has been declared forcible with the verilog variable statement.

The effect of a force action is that all preceding and subsequent non-forced assignments from Specman
or from the DUT to the same object —including those within the same Specman tick — are ignored until
a subsequent force action from e or until freed by a release action from e. The only exception is that if
you force different parts of a vectored object in the same Specman tick, the actions are accumulated and
applied together at the end of the tick.

SpeXsim with a VHDL Design or Third-Party VHDL Simulators

When Specman is linked with a VHDL simulator, you can force signals of a scalar integer or enumerated
type as well as binary array type, such as arrays of std_logic and bit vectors. No declaration is required
for VHDL objects.

When Specman is linked with ModelSim VHDL simulator, you can force single elements of an array of
a scalar integer or enumerated type using the predefined routine simulator_command().

With Verisity-supplied VHDL adapters, the effect of the force action is:

• A release action is required to allow the object to be driven by the DUT.


• Each new action from e overrides the previous one without an explicit release action.

17-54 e Language Reference


Simulation-Related Constructs
force

To change the behavior of proprietary VHDL adapters to be compatible with this behavior of Specman
VHDL adapters, you can call the global set_assign_after_force_compatible() method as follows
before simulation starts:
Specman > set_assign_after_force_compatible(TRUE)

Notes
• Forcing of Verilog registers is not supported.
• The interface with SpeedSim does not support force or release.
• Forcing signals is always costly to performance. In VCS, forcing signals is disabled by default. If it
is not enabled and you try to force a signal, you will see an error such as the following:
*** Error: acc_set_value: Pli force not enabled.
Please add capability frc to module your_module.
To enable forcing in VCS, you need to add the force option manually to the pli.tab by changing
“acc=rw,cbk:*” to “acc=frc,cbk:*”. To decrease the performance hit, you can change “*” to just the
levels of DUT hierarchy that you want Specman to access, for example,
“acc=frc,cbk:TOP.DMA.*;TOP.USB.*”.
• When you force an HDL object, the value is applied immediately, without a delay, even if a drive
delay has been specified for the object.

Example 1
This example shows the effect of force and release actions in a Verilog environment.

top.v
module top();
reg clk;
wire [7:0] data;

initial begin
clk = 0;
forever begin
#50 clk = ~clk;
end
end

// monitors
always @(data) $display ("%t : data = %b", $time, data);

endmodule

e Language Reference 17-55


Simulation-Related Constructs
force

test.e
struct sim {
event clk is rise ('~/top/clk')@sim;

m() @clk is {
'~/top/data' = 8'b10101010;
force '~/top/data[3:0]' =0;
'~/top/data[7:4]' = 4'b0000;

wait cycle;
'~/top/data' = 8'b10011001;

wait cycle;
release '~/top/data[7:0]';

wait cycle;
'~/top/data' = 8'b11111111;

wait [2]* cycle;


stop_run();
};

};

extend sys {
sim;

setup() is also {
set_config(print, radix, bin);
};

run() is also {
start sys.sim.m();
};
};

verilog.e
verilog variable '~/top/data[7:0]' using wire, forcible;

Result (SpeXsim output)


spexsim -s
C1> .
0 : data = zzzzzzzz

17-56 e Language Reference


Simulation-Related Constructs
force

50 : data = 10100000
250 : data = 10011001
250 : data = zzzzzzzz
350 : data = 11111111
Simulation stop requested
C2> $finish;

Example 2
This example shows the effect of force and release actions with a Verisity-supplied VHDL adapter.

top.vhd
use std.textio.all;
library IEEE;
use IEEE.std_logic_1164.all;
entity top is
end top;

architecture arc of top is

signal clk : std_logic := '0';


signal data: std_logic_vector (7 downto 0);

component comspec
end component;

for all: comspec use entity work.SPECMAN_REFERENCE (arch);


begin

I: comspec;

clk <= not clk after 50 ns;

end arc;

test.e
struct sim {
event clk is rise ('~/top/clk')@sim;

m() @clk is {
'~/top/data' = 8'b10101010;
force '~/top/data[3:0]' =0;
'~/top/data[7:4]' = 4'b0000;

e Language Reference 17-57


Simulation-Related Constructs
force

wait cycle;
'~/top/data' = 8'b10011001;

wait cycle;
release '~/top/data[7:0]';

wait cycle;
'~/top/data' = 8'b11111111;

wait [2]* cycle;


stop_run();
};

};

extend sys {
sim;

setup() is also {
set_config(print, radix, bin);
};

run() is also {
start sys.sim.m();
};
};

Result
0 : data = UUUUUUUU
50 : data = 10100000
150 : data = 10011001
350 : data = 11111111

See Also
• “'HDL-pathname'” on page 17-65
• release on page 17-59

17-58 e Language Reference


Simulation-Related Constructs
release

17.3.2 release

Purpose
Remove a force action from an HDL object

Category
Action

Syntax
release 'HDL-pathname'

Syntax Example
release 'TOP.sig';

Parameters

HDL-pathname The full path name of an HDL object previously specified in a force action.

Description
Releases the HDL object that you have previously forced.

SpeXsim with a Verilog Design or Third-Party Verilog Simulators

If the released object is a Verilog register and it has no other driver, the current value of the register is
retained. If the release object is a Verilog wire and it has no other driver, it floats to high-impedance (all
z).

SpeXsim with a VHDL Design or Third-Party VHDL Simulators

The effect of a release action depends on the simulator’s procedural interface.

For ModelSim, releasing a forced signal immediately unfreezes its drivers and the resolved value is
assigned to the signal. Likewise for SpeXsim users, when running in ModelSim compatibility mode by
passing the -mti switch to the runtime executable.

For example:
ModelSim
DUT: sig <= '1';

e Language Reference 17-59


Simulation-Related Constructs
release

Specman: force sig = '0';


Specman: release sig
print sig -> '1'

If the signal does not have drivers (for example, if it is forced and assigned only from e), the last forced
value is retained.If there was no forced value, the default value is assigned. For example:
ModelSim with no driver
Specman: force sig = '0';
Specman: release sig
print sig -> '0'

For NC VHDL, Specman has, in releases prior to 4.3.4, used the VHDL Design Access procedural
interface. The semantics of that procedural interface was to leave the signal value untouched. The only
effect of a release action was that the signal can be assigned. For example:
NC VHDL (old behavior)
DUT: sig <= '1';
Specman: force sig = '0';
Specman: release sig
print sig -> '0'

Since LDV4.1, the VHPI enables a ModelSim-like semantics—releasing a forced signal immediately
unfreezes its drivers, and the resolved value is assigned to the signal. For example:
NC VHDL (new behavior)
DUT: sig <= '1';
Specman: force sig = '0';
Specman: release sig
print sig -> '1'

However, for signals with no drivers, the semantics differ from that of ModelSim.The last assigned value
before the force action is re-assigned. If there was no assignment, the initial value is assigned. If there
was no initial value, the default value is assigned. For example:

NC VHDL with no driver


signal sig : std_logic := 'Z'
Specman: sig = 'X'
Specman: force sig = '0'
Specman: release sig
print sig -> 'X'

NC VHDL with no driver


signal sig : std_logic := 'Z'
Specman: force sig = '0'
Specman: release sig
print sig -> 'Z'

17-60 e Language Reference


Simulation-Related Constructs
release

NC VHDL with no driver


Specman: force sig = '0'
Specman: release sig
print sig -> 'U'

For SpeXsim and NC VHDL you can select between the two semantics. The default behavior is the
semantics described above. To retain the forced value after the release action, you must call
sys.retain_forced_value_after_release() before the test phase.

Note
The interface with SpeedSim does not support force or release.

Example 1
This example shows the effect of force and release actions in a Verilog environment.

top.v
module top();
reg clk;
wire [7:0] data;

initial begin
clk = 0;
forever begin
#50 clk = ~clk;
end
end

// monitors
always @(data) $display ("%t : data = %b", $time, data);

endmodule

test.e
struct sim {
event clk is rise ('~/top/clk')@sim;

m() @clk is {
'~/top/data' = 8'b10101010;
force '~/top/data[3:0]' =0;
'~/top/data[7:4]' = 4'b0000;

wait cycle;

e Language Reference 17-61


Simulation-Related Constructs
release

'~/top/data' = 8'b10011001;

wait cycle;
release '~/top/data[7:0]';

wait cycle;
'~/top/data' = 8'b11111111;

wait [2]* cycle;


stop_run();
};

};

extend sys {
sim;

setup() is also {
set_config(print, radix, bin);
};

run() is also {
start sys.sim.m();
};
};

verilog.e
verilog variable '~/top/data[7:0]' using wire, forcible;

Result (SpeXsim output)


spexsim -s
C1> .
0 : data = zzzzzzzz
50 : data = 10100000
250 : data = 10011001
250 : data = zzzzzzzz
350 : data = 11111111
Simulation stop requested
C2> $finish;

Example 2
This example shows the effect of force and release actions with a Verisity-supplied VHDL adapter.

17-62 e Language Reference


Simulation-Related Constructs
release

top.vhd
use std.textio.all;
library IEEE;
use IEEE.std_logic_1164.all;
entity top is
end top;

architecture arc of top is

signal clk : std_logic := '0';


signal data: std_logic_vector (7 downto 0);

component comspec
end component;

for all: comspec use entity work.SPECMAN_REFERENCE (arch);


begin

I: comspec;

clk <= not clk after 50 ns;

end arc;

test.e
struct sim {
event clk is rise ('~/top/clk')@sim;

m() @clk is {
'~/top/data' = 8'b10101010;
force '~/top/data[3:0]' =0;
'~/top/data[7:4]' = 4'b0000;

wait cycle;
'~/top/data' = 8'b10011001;

wait cycle;
release '~/top/data[7:0]';

wait cycle;
'~/top/data' = 8'b11111111;

wait [2]* cycle;


stop_run();
};

e Language Reference 17-63


Simulation-Related Constructs
Simulation-Related Expressions

};

extend sys {
sim;

setup() is also {
set_config(print, radix, bin);
};

run() is also {
start sys.sim.m();
};
};

Result (SpeXsim output)


spexsim -s
C1> .
0 : data = UUUUUUUU
50 : data = 10100000
150 : data = 10011001
350 : data = 11111111
Simulation stop requested
C2> $finish;

See Also
• “'HDL-pathname'” on page 17-65
• force on page 17-53

17.4 Simulation-Related Expressions


This section contains:

• 'HDL-pathname' on page 17-65


• specman deferred on page 17-66

17-64 e Language Reference


Simulation-Related Constructs
'HDL-pathname'

17.4.1 'HDL-pathname'

Purpose
Accessing HDL objects, using full-path-names

Category
Expression

Syntax
'HDL-pathname[index-exp | bit-range] [@(x | z | n)]'

Syntax Example
'~/top/sig' = 7;
print '~/top/sig';

Parameters

HDL-pathname The full path name of an HDL object, optionally including expressions and
composite data. The name must comply with one of the conventions described
in “HDL Object Names” on page 8-12 in the Specman Elite Integrator’s Guide.
The object type must be one of the object types described in “Supported HDL
Object Types” on page 8-10 in the Specman Elite Integrator’s Guide.

bit-range A bit range has the format [high-bit-num:low-bit-num] and is extracted from the
object from high bit to low bit. Slices of buses are treated exactly as they are in
HDL languages. They must be specified in the same direction as in the HDL
code and reference the same bit numbers.

index-exp Accesses a single bit of a Verilog vector, a single element of a Verilog memory,
or a single vector of a VHDL array of vectors.

e Language Reference 17-65


Simulation-Related Constructs
specman deferred

@x | z Sets or gets the x or z component of the value. When this notation is not used in
accessing an HDL object, Specman translates the values of x to zero and z to
one.
When reading HDL objects using @x (or @z), Specman translates the specified
value (x or z) to one, and all other values to zero. When writing HDL objects, if
@x (or @z) is specified, Specman sets every bit that has a value of one to x (or
z). In this way, @x or @z acts much like a data mask, manipulating only those
bits that match the value of x or z.
Note If you are using NC VHDL or NC SIM, set the config option
-compatibility_vhdl_at_x_nc to TRUE to ensure that the x value is translated
to one during a read using @x. For more information, see configure
simulationc on page 6-54 in the Specman Command Reference.

@n When this specifier is used for driving HDL objects, the new value is visible
immediately (now). The default mode is to buffer projected values and update
only at the end of the Specman tick. If reading a value using @n then the
projected simulator value can be seen.

Description
Accesses Verilog and VHDL objects from e.

Note
In general, you can access HDL objects using the 'HDL-pathname' expression. In order to enable some
non-trivial capabilities, however, you must also use verilog or vhdl statements.

See Also
• For SpeXsim users, see “Accessing HDL Objects from e ” in the SpeXsim User Guide
• “Reading and Writing HDL Objects” on page 8-21 in the Specman Elite Integrator’s Guide

17.4.2 specman deferred

Purpose
Identify a deferred Verilog `define

17-66 e Language Reference


Simulation-Related Constructs
specman deferred

Category
Verilog expression

Verilog Syntax
`define macro-name default-value // specman deferred

Syntax Example
`define bus_width 64 // specman deferred

Parameters

macro-name Any legal Verilog identifier.

default-value A constant expression. This value is used as the definition of the `define
unless you over-write it with another value. The size and type of this value is
used to determine the expected type and size of the runtime expressions.
Thus, if this value is longer than 32 bits, its size must be explicitly specified.

// specman deferred The “// specman deferred” comment must appear on the same line of the file
that specifies the `define. This comment can contain any number of spaces or
tabs.

Description
Deferred Verilog `defines let you use Verilog definitions without specifying their final values at compile
time. Instead, you can redefine their values just prior to use.

This feature lets you compile and link a single executable for all tests and then load in different Verilog
`defines definitions for different tests.

All non-deferred `defines are substituted in place during parsing. References to deferred 'defines are
resolved at run time.

Notes
• Deferred 'defines cannot be used in other Verilog 'defines used by Specman.
• You can only redefine the value of a 'define; you cannot redefine its type or width. For example:
The following lines define a 'define with the default width of 32 bits:
'define MY_MASK 0 // specman deferred
If later on during the run MY_MASK is defined with a different type or length, for example,

e Language Reference 17-67


Simulation-Related Constructs
Simulation-Related Routines

'define MY_WRONG_MASK 64'bz


a Specman error occurs.
• Whether a 'define is deferred or not is established at its very first occurrence and cannot be changed
by any subsequent occurrence of this macro.
• The use of deferred macros causes some performance overhead, which is equivalent to accessing an
entry in a table when using a function call for this purpose.

See Also
• “Using Verilog Defines” on page 8-72 in the Specman Elite Integrator’s Guide
• show defines on page 13-1 in the Specman Command Reference
• “Environment Variables, Initialization Files, and Scripts” on page 7-24 in the Specman Elite Integrator’s
Guide
• verilog import on page 17-7

17.5 Simulation-Related Routines


The following routines perform functions related to simulation:

• simulator_command() on page 17-68


• stop_run() on page 17-69

17.5.1 simulator_command()

Purpose
Issue a simulator command

Category
Predefined routine

Syntax
simulator_command(command: string)

17-68 e Language Reference


Simulation-Related Constructs
stop_run()

Syntax Example
simulator_command("force -deposit memA(31:0)");
simulator_command(“force top.dut.sig=1;”);

Parameters

command A valid simulator command, enclosed in double quotes. Commands that change the
state of simulation, such as run, restart, restore, or exit, cannot be passed to the
simulator with simulator_command().

Description
Passes a command to the HDL simulator from e. The command returns no value. The output of the
command is sent to standard output and to the log file.

Note
This routine can be used only with SpeXsim, and the ModelSim, SpeedSim, and NC (VHDL)
simulators.

See Also
• force on page 17-53

17.5.2 stop_run()

Purpose
Stop a simulation run cleanly

Category
Predefined routine

Syntax
stop_run()

e Language Reference 17-69


Simulation-Related Constructs
stop_run()

Syntax Example
stop_run();

Description
Stops the simulator and initiates post-simulation phases. The following things occur when stop_run() is
invoked:

1. The quit() method of each struct under sys is called. Each quit() method emits a “quit” event for that
struct instance at the end of the current tick.

2. The scheduler continues running all threads until the end of the current tick.

3. At the end of the current tick, the extract, check, and finalize test phases are performed.

4. If a simulator is linked in to Specman, Specman terminates the simulation cleanly after the test is
finalized.

Notes
• This method must be called by a user-defined method or TCM to stop the simulation run cleanly.
• You should not extend or modify the stop_run() method. If you want something to happen right after
you stop the run, you can extend sys.extract().
• Executing a tick after calling stop_run() is considered an error. This includes executing a tick to call
a Verilog function or task.
• The actual threads are not removed until the end of the tick, so that you can see them using the
debugger.
• If the simulator exit command is called before stop_run(), the global methods for extracting, checking
and finalizing the test are called.

Example
verilog import macros.v;

extend sys {
event pclk is rise ('`TOP.pclk');
driver: dut_driver;
};

struct dut_driver {
ld: list of int(bits: `WORD_WIDTH);

17-70 e Language Reference


Simulation-Related Constructs
stop_run()

keep ld.size() in [1..30];

stimuli() @sys.pclk is {
'`READY' = 1;
for each in ld {
wait until true('`READY' == 1);
'`TOP.data_in' = it;
wait [`TRANS_DELAY];
};
stop_run();
};
run() is also {
start stimuli();
};
};

See Also
• The quit() Method of any_struct on page 22-36
• configure run on page 6-51 in the Specman Command Reference

e Language Reference 17-71


Simulation-Related Constructs
stop_run()

17-72 e Language Reference


18 Packing and Unpacking
Packing performs concatenation of scalars, strings, list elements, or struct fields in the order that you
specify. Unpacking performs the reverse operation, splitting a single expression into multiple
expressions.

As part of the concatenation or splitting process, packing and unpacking also perform type conversion
between any of the following:

• scalars
• strings
• lists and list subtypes (same type but different width)
For type conversion, Specman provides additional techniques. Here are some general recommendations
on when to use each technique:

as_a() Recommended for converting a single scalar to another scalar type, for
example, from a 32-bit integer to an 8-bit integer. It is also recommended
for conversion between strings and lists of ASCII bytes. For more
information, see as_a() on page 3-40.
sublisting with [..] Recommended for converting a single scalar to a list of bit. For more
information, see Chapter 2 “e Basics”.
bit extraction with [:] Recommended for converting a list of bit into a single scalar. For more
information, see Chapter 2 “e Basics”.
unpacking Recommended for converting from a list of bit to strings, lists, structs, or
multiple scalars.
packing Recommended for all other purposes.

This chapter contains the following sections

• “Basic Packing” on page 18-2

e Language Reference 18-1


Packing and Unpacking
Basic Packing

• “Advanced Packing” on page 18-12


• “How to Debug Packing” on page 18-25
• “Constructs for Packing and Unpacking” on page 18-26

18.1 Basic Packing


Packing and unpacking operate on scalars, strings, lists and structs. The following sections show how to
perform basic packing and unpacking of these data types using two of Specman’s basic packing tools,
the pack() and unpack() methods.

• “A Simple Example of Packing” on page 18-2


• “A Simple Example of Unpacking” on page 18-4
• “Packing and Unpacking Scalar Expressions” on page 18-6
• “Packing and Unpacking Strings” on page 18-7
• “Packing and Unpacking Structs” on page 18-8
• “Packing and Unpacking Lists” on page 18-9
For information on two other basic tools for packing, see:

• %{… , …} on page 2-79


• swap() on page 18-36

See Also
• “Advanced Packing” on page 18-12
• “How to Debug Packing” on page 18-25
• “Constructs for Packing and Unpacking” on page 18-26

18.1.1 A Simple Example of Packing


This example shows how packing converts data from a struct into a stream of bits. An “instruction”
struct is defined as:
struct instruction {
%opcode : uint (bits : 3);
%operand : uint (bits : 5);
%address : uint (bits : 8);

18-2 e Language Reference


Packing and Unpacking
A Simple Example of Packing

!data_packed_high : list of bit;


!data_packed_low : list of bit;

keep opcode == 0b100;


keep operand == 0b11001;
keep address == 0b00001111;
};

The post_generate() method of this struct is extended to pack the “opcode” and the “operand” fields
into two variables. The order in which the fields are packed is controlled with the packing.low and
packing.high options:
data_packed_low = pack(packing.low, opcode, operand);
data_packed_high = pack(packing.high, opcode, operand);

With the packing.low option, the least significant bit of the first expression in pack(), “opcode”, is
placed at index [0] in the resulting list of bit. The most significant bit of the last expression, “operand”,
is placed at the highest index in the resulting list of bit. Figure 18-1 on page 18-3 shows this packing
order.

packing.low is the default packing order.

Figure 18-1 Simple Packing Example Showing packing.low

The “instruction” struct with two fields:

opcode == 0x4 1 0 0

operand == 0x19 1 1 0 0 1

The two fields packed into a bit stream, using the default ordering

operand opcode

1 1 0 0 1 1 0 0
list of bit [7] list of bit [0]

With packing.high, the least significant bit of the last expression, “operand”, is placed at index [0] in the
resulting list of bit. The most significant bit of the first expression, “opcode”, is placed at the highest
index in the resulting list of bit. Figure 18-2 shows this packing order.

e Language Reference 18-3


Packing and Unpacking
A Simple Example of Unpacking

Figure 18-2 Simple Packing Example Showing packing.high

The “instruction” struct with two fields:

opcode == 0x4 1 0 0

operand == 0x19 1 1 0 0 1

The two fields packed into a bit stream, using the packing.high ordering

opcode operand

1 0 0 1 1 0 0 1
list of bit [7] list of bit [0]

Pack expressions, like the ones shown in the example above, are untyped expressions. In many cases, as
in this example, Specman can deduce the required type from the context of the pack expression. See
“Untyped Expressions” on page 3-17 for more information.

See Also
• “A Simple Example of Unpacking” on page 18-4
• “Packing and Unpacking Scalar Expressions” on page 18-6
• “Packing and Unpacking Strings” on page 18-7
• “Packing and Unpacking Structs” on page 18-8
• “Packing and Unpacking Lists” on page 18-9

18.1.2 A Simple Example of Unpacking


This example shows how packing fills the fields of a struct instance with data from a bit stream. An
“instruction” struct is defined as:
struct instruction {
%opcode : uint (bits : 3);
%operand : uint (bits : 5);
%address : uint (bits : 8);
};

18-4 e Language Reference


Packing and Unpacking
A Simple Example of Unpacking

The extension to post_generate() shown below unpacks a list of bits, “packed_data”, into a variable
“inst” of type “instruction” using the packing.high option. The results are shown in Figure 18-3.
extend sys {
post_generate() is also {
var inst : instruction;
var packed_data: list of bit;
packed_data = {1;1;1;1;0;0;0;0;1;0;0;1;1;0;0;1};

unpack(packing.high, packed_data, inst);


};
};

Figure 18-3 Simple Unpacking Example Showing packing.high

The packed data

1 0 0 1 1 0 0 1 0 0 0 0 1 1 1 1

The result of unpacking the data with packing.high:

opcode == 0x4 1 0 0

operand == 0x19 1 1 0 0 1

address == 0x0f 0 0 0 0 1 1 1 1

In this case, the expression that provides the value, “packed_data”, is a list of bits. When a value
expression is not a list of bit, Specman uses implicit packing to store the data in the target expression.
See “Implicit Packing and Unpacking” on page 18-25 for more details.

See Also
• “A Simple Example of Packing” on page 18-2
• “Packing and Unpacking Scalar Expressions” on page 18-6
• “Packing and Unpacking Strings” on page 18-7
• “Packing and Unpacking Structs” on page 18-8

e Language Reference 18-5


Packing and Unpacking
Packing and Unpacking Scalar Expressions

• “Packing and Unpacking Lists” on page 18-9

18.1.3 Packing and Unpacking Scalar Expressions


Packing a scalar expression creates an ordered bit stream by concatenating the bits of the expression
together. Unpacking a bit stream into a scalar expression fills the scalar expression, starting by default
by putting the lowest bit of the bit stream into the lowest bit of the scalar expression.

Packing and unpacking of a scalar expression is performed using the expression’s inherent size, except
when the expression contains a bit slice operator. Missing bits are assumed to be zero, and extra bits are
allowed and ignored. See “Scalar Types” on page 3-2 for information on how the size of a scalar
expression is determined. See also “Bit Slice Operator and Packing” on page 18-24.

Example
The example below packs two integers, “int_5” and “int_2” and then unpacks a new list of bit “lob” into
the same two integers. In the unpack action, the first five bits of “lob” are assigned to “int_5” and the
next two to “int_2”. The remaining bits in “lob” are not used.
var int_5: int(bits:5) = 3;
var int_2: int(bits:2);
print pack(packing.low, int_5, int_2) using bin;
var lob:list of bit = {1;1;1;1;1;1;0;0;0;0;1;0;0;};
unpack(packing.low,lob,int_5,int_2);
print int_5, int_2;

Result
pack(packing.low, int_5, int_2) = (7 items, bin):
0 0 0 0 0 1 1 .0

int_5 = 31
int_2 = 1

Note
If you unpack a list into one or more scalar expressions and there are not enough bits in the list to put a
value into each scalar, a runtime error is issued.

See Also
• “A Simple Example of Packing” on page 18-2
• “A Simple Example of Unpacking” on page 18-4

18-6 e Language Reference


Packing and Unpacking
Packing and Unpacking Strings

• “Packing and Unpacking Strings” on page 18-7


• “Packing and Unpacking Structs” on page 18-8
• “Packing and Unpacking Lists” on page 18-9

18.1.4 Packing and Unpacking Strings


Packing a string creates an ordered bit stream by concatenating each ASCII byte of the string together
from left to right ending with a byte with the value zero (the final NULL byte). Unpacking a string
places the bytes of the string into the target expression, starting with the first ASCII byte in the string up
to and including the first byte with the value zero.

To obtain different results, you can use the as_a() method, which converts directly between the string
and list of byte types. See as_a() on page 3-40 for more information.

Example
In this example, the packed string is implicitly unpacked into a list of byte.

The last byte is zero since it is the final NULL byte.


var my_string: string = "ABC";
print pack(packing.low, my_string);

var my_list_of_byte: list of byte = pack(packing.low, my_string);


print my_list_of_byte using hex;

Result
pack(packing.low,my_string) = (32 items, hex):
0 0 4 3 4 2 4 1 .0

my_list_of_byte = (4 items, hex):


00 43 42 41 .0

See Also
• “A Simple Example of Packing” on page 18-2
• “A Simple Example of Unpacking” on page 18-4
• “Packing and Unpacking Scalar Expressions” on page 18-6
• “Packing and Unpacking Structs” on page 18-8

e Language Reference 18-7


Packing and Unpacking
Packing and Unpacking Structs

• “Packing and Unpacking Lists” on page 18-9

18.1.5 Packing and Unpacking Structs


Packing a struct creates an ordered bit stream from all the physical fields (marked with %) in the struct,
starting by default, with the first physical field declared. Other fields (called virtual fields) are ignored
by the packing process. If a physical field is of a compound type (struct or list) the packing process
descends recursively into the struct or list.

Unpacking a bit stream into a struct fills the physical fields of the struct, starting by default with the first
field declared and proceeding recursively through all the physical fields of the struct. Unpacking a bit
stream into a field that is a list follows some additional rules described in “Packing and Unpacking Lists”
on page 18-9.

Unpacking a struct that has not yet been allocated (with new) causes Specman to allocate the struct and
run the struct’s init() method. Unlike new, the struct’s run() method is not called.

A struct is packed or unpacked using its predefined methods do_pack() and do_unpack(). It is possible
to modify these predefined methods for a particular struct. See do_pack() on page 18-38 and
do_unpack() on page 18-42 for more information.

Example
This example packs the two physical fields in “my_struct” into the variable “ms”. The resulting bit
stream is 14 bits, which is exactly the combination of both the physical fields. The virtual field “int_15”
does not participate in the pack process at all.
struct my_struct{
%int_4: int(bits:4);
%int_10: int(bits:10);
int_15: int(bits:15);
init() is also {
int_4 = 3;
int_10 = 15;
};
};

struct pac {
m() is {
var ms: my_struct = new;
print pack(packing.low, ms) using hex;
};
};

18-8 e Language Reference


Packing and Unpacking
Packing and Unpacking Lists

Result
pack(packing.low,ms) = (14 items, bin):
0 0 0 0 0 0 1 1 1 1 0 0 1 1 .0

See Also
• “A Simple Example of Packing” on page 18-2
• “A Simple Example of Unpacking” on page 18-4
• “Packing and Unpacking Scalar Expressions” on page 18-6
• “Packing and Unpacking Strings” on page 18-7
• “Packing and Unpacking Lists” on page 18-9

18.1.6 Packing and Unpacking Lists


Packing a list creates a bit stream by concatenating the list items together, starting by default with the
item at index 0.

Unpacking a bit stream into a list fills the list item by item, starting by default with the item at index
zero. The size of the list that is unpacked into is determined by whether the list is sized and whether it is
empty:

• Unpacking into an empty list expands the list as needed to contain all the available bits.
• Unpacking into a non-empty list unpacks only until the existing list size is reached.
• Unpacking to a struct fills the sized lists only to their defined size, regardless of their actual size at
the time.
Note When a struct is allocated, the lists within it are empty. If the lists are sized, unpacking is
performed until the defined size is reached.

See Chapter 2 “e Basics”, for more information on sizing lists.

Example 1
This first example shows the effect of packing a list of integers.
var my_list: list of int(bits:4) = {3;5;7;9;11;13;15};
print pack(packing.low,my_list);

Result
pack(packing.low,my_list) = (28 items, hex):

e Language Reference 18-9


Packing and Unpacking
Packing and Unpacking Lists

f d b 9 7 5 3 .0

Example 2
The list “my_list” is empty, so it is expanded to contain all 32 bits of the integer.
var my_list: list of int(bits:4);
unpack(packing.low,5,my_list);
print my_list using hex;

Result
my_list = (8 items, hex):
0 0 0 0 0 0 0 5 .0

Example 3
The list was not empty because it was initialized to have four items. Thus it is not expanded and the
resulting list has four items.
var my_list: list of int(bits:4) = {0;0;0;0};
unpack(packing.low,5,my_list);
print my_list using hex;

Result
my_list = (4 items, dec):
0 0 0 5 .0

Example 4
The “my_list” field is cleared in order to demonstrate that although the procedural code has corrupted
the list’s initial size, it is restored when unpack is performed.
struct my_struct{
%my_list[4]: list of int(bits:4);
};

struct pac {
m() is {
var t:my_struct = new;
t.my_list.clear();
print t.my_list;
unpack(packing.low,5,t);
print t.my_list;
};

18-10 e Language Reference


Packing and Unpacking
Packing and Unpacking Lists

};

Result
t.my_list = (empty)
t.my_list = (4 items, hex):
0 0 0 5 .0

Example 5
Unpacking into an unsized, uninitialized list causes a runtime error message because the list is expanded
as needed to consume all the given bits. The field “int_1” remains bit-less.
struct my_struct{
%my_list: list of int(bits:4);
%int_1: bit;
};

struct pac {
m() is {
var t:my_struct = new;
unpack(packing.low,5,t);
};
};

Example 6
This example shows the recommended way to get a variable number of list items. The specification
order is important because the “len1” and “len2” values must be set before initializing “data1” and
“data2”. Declaring “len1” and “len2” before “data1” and “data2” ensures that the list length is generated
first. When unpacking into a list with a variable number of items, you will have to calculate the number
of items in the list before unpacking. See do_unpack() on page 18-42 for an example of how to do this.
struct packet{
%len1: int;
%len2: int;
%data1[len1]: list of byte;
%data2[len1 + len2]: list of byte;
};

See Also
• “A Simple Example of Packing” on page 18-2
• “A Simple Example of Unpacking” on page 18-4

e Language Reference 18-11


Packing and Unpacking
Advanced Packing

• “Packing and Unpacking Scalar Expressions” on page 18-6


• “Packing and Unpacking Strings” on page 18-7
• “Packing and Unpacking Structs” on page 18-8

18.2 Advanced Packing


The following sections describe how to use the Specman advanced packing features and provide you
with the concepts you need to use them efficiently:

• “Using the Predefined pack_options Instances” on page 18-12


• “Customizing Pack Options” on page 18-18
• “Customizing Packing for a Particular Struct” on page 18-23
• “Bit Slice Operator and Packing” on page 18-24
• “Implicit Packing and Unpacking” on page 18-25
• “Untyped Expressions” on page 3-17

See Also
• “Basic Packing” on page 18-2
• “How to Debug Packing” on page 18-25
• “Constructs for Packing and Unpacking” on page 18-26

18.2.1 Using the Predefined pack_options Instances


Packing and unpacking are controlled using a struct under global named packing. There are five
predefined instances of the pack_options struct that you can use with or without modification to control
the way packing or unpacking is performed. You are probably familiar with two of these pack_options
instances, packing.low and packing.high.

When you call pack(), unpack(), do_pack() or do_unpack() you pass one of the predefined
pack_options instances as the first parameter. In the example below, packing.high is passed as the
pack_options instance:
data_packed_high = pack(packing.high, opcode, operand);

The following sections describe the pack_options instances:

• packing.low on page 18-13

18-12 e Language Reference


Packing and Unpacking
Using the Predefined pack_options Instances

• packing.low_big_endian on page 18-14


• packing.high on page 18-15
• packing.high_big_endian on page 18-16
• packing.network on page 18-17
• packing.global_default on page 18-18

See Also
• “Customizing Pack Options” on page 18-18
• “Customizing Packing for a Particular Struct” on page 18-23
• “Bit Slice Operator and Packing” on page 18-24
• “Implicit Packing and Unpacking” on page 18-25
• “Untyped Expressions” on page 3-17

18.2.1.1 packing.low
This pack_options instance traverses the source fields or variables in the order they appear in code,
placing the least significant bit of the first field or list item at index [0] in the resulting list of bit. The
most significant bit of the last field or list item is placed at the highest index in the resulting list of bit.
<'
struct instruction {
%opcode : uint (bits : 3);
%operand : uint (bits : 5);
%address : uint (bits : 8);

!data_packed_low : list of bit;

keep opcode == 0b100;


keep operand == 0b11001;
keep address == 0b00001111;

post_generate() is also {
data_packed_low = pack(packing.low, me);
print me using bin;
print data_packed_low using bin;
};
};
'>

e Language Reference 18-13


Packing and Unpacking
Using the Predefined pack_options Instances

Result
me = instruction-@0: instruction
@packing20
0 %opcode: 0b100
1 %operand: 0b11001
2 %address: 0b00001111
3 !data_packed_low: (16 items)
data_packed_low = (16 items, bin):
0 0 0 0 1 1 1 1 1 1 0 0 1 1 0 0 .0

See Also
• “Using the Predefined pack_options Instances” on page 18-12

18.2.1.2 packing.low_big_endian
This pack_options instance, like packing.low, traverses the source fields or variables in the order they
appear in code. In addition, for every scalar field or variable, it

• Swaps every byte in each pair of bytes


• Swaps every two bytes in each 32-bit word
Note If the scalar’s width is not a multiple of 16, no swapping is performed

The example below shows the difference between packing.low and packing.low_big_endian.
struct pac {
%opcode: uint (bits:4);
%operand1: uint (bytes:2);
%operand2: uint (bytes:2);

keep opcode == 0xf;


keep operand1 == 0xcc55;
keep operand2 == 0xff00;

m() is {
var i_stream: list of bit;
i_stream = pack(packing.low, opcode,
operand1, operand2);
print i_stream using bin;
i_stream = pack(packing.low_big_endian, opcode,
operand1, operand2);
print i_stream using bin;
};
};

18-14 e Language Reference


Packing and Unpacking
Using the Predefined pack_options Instances

Result
i_stream = (36 items, bin):
0 0 0 0 1 1 0 0 1 1 0 0 0 1 0 1 0 1 0 1 1 1 1 1 .0
1 1 1 1 1 1 1 1 0 0 0 0 .24

i_stream = (36 items, bin):


1 1 1 1 0 1 0 1 0 1 0 1 1 1 0 0 1 1 0 0 1 1 1 1 .0
0 0 0 0 0 0 0 0 1 1 1 1 .24

See Also
• “Using the Predefined pack_options Instances” on page 18-12

18.2.1.3 packing.high
This pack_options instance traverses the source fields or variables in the reverse order from the order in
which they appear in code, placing the least significant bit of the last field or list item at index [0] in the
resulting list of bit. The most significant bit of the first field or list item is placed at the highest index in
the resulting list of bit.
<'
struct instruction {
%opcode : uint (bits : 3);
%operand : uint (bits : 5);
%address : uint (bits : 8);

!data_packed_high : list of bit;

keep opcode == 0b100;


keep operand == 0b11001;
keep address == 0b00001111;

post_generate() is also {
data_packed_high = pack(packing.high, opcode, operand);
print me using bin;
print data_packed_high using bin;
};
};
'>

Result
me = instruction-@0: instruction
@packing18
0 %opcode: 0b100

e Language Reference 18-15


Packing and Unpacking
Using the Predefined pack_options Instances

1 %operand: 0b11001
2 %address: 0b00001111
3 !data_packed_high: (8 items)
data_packed_high = (8 items, bin):
1 0 0 1 1 0 0 1 .0

See Also
• “Using the Predefined pack_options Instances” on page 18-12

18.2.1.4 packing.high_big_endian
This pack_options instance, like packing.high, traverses the source fields or variables in the reverse
order from the order in which they appear in code. In addition, for every scalar field or variable, it

• Swaps every byte in each pair of bytes


• Swaps every two bytes in each 32-bit word
Note If the scalar’s width is not a multiple of 16, no swapping is performed.

The example below shows the difference between packing.high and packing.high_big_endian.
struct pac {
%opcode: uint (bits:4);
%operand1: uint (bytes:2);
%operand2: uint (bytes:2);

keep opcode == 0xf;


keep operand1 == 0xcc55;
keep operand2 == 0xff00;

m() is {
var i_stream: list of bit;
i_stream = pack(packing.high, opcode,
operand1,operand2);
print i_stream using bin;
i_stream = pack(packing.high_big_endian, opcode,
operand1,operand2);
print i_stream using bin;
};
};

Result
i_stream = (36 items, bin):
0 1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 .0

18-16 e Language Reference


Packing and Unpacking
Using the Predefined pack_options Instances

1 1 1 1 1 1 0 0 1 1 0 0 .24

i_stream = (36 items, bin):


1 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 .0
1 1 1 1 0 1 0 1 0 1 0 1 .24

See Also
• “Using the Predefined pack_options Instances” on page 18-12

18.2.1.5 packing.network
This packing option is the same as packing.high if the total number of bits that will comprise the target
is not a multiple of 8. When it is a multiple of 8, then the target bits of the entire bit stream are byte-order
reversed.
<'
struct instruction {
%opcode : uint (bits : 3);
%operand : uint (bits : 5);
%address : uint (bits : 8);

!data_packed_high : list of bit;


!data_packed_network : list of bit;

keep opcode == 0b100;


keep operand == 0b11001;
keep address == 0b00001111;

post_generate() is also {
data_packed_high = pack(packing.high, opcode, operand,
address);
data_packed_network = pack(packing.network, opcode,
operand, address);

print me using bin;


print data_packed_high using bin;
print data_packed_network using bin;
};
};
'>

Results
vrst-tool> gen
Doing setup ...

e Language Reference 18-17


Packing and Unpacking
Customizing Pack Options

Generating the test using seed 1...


me = instruction-@0: instruction
---------------------------------------------- @packing13
0 %opcode: 0b100
1 %operand: 0b11001
2 %address: 0b00001111
3 !data_packed_high: (16 items)
4 !data_packed_network: (16 items)
data_packed_high = (16 items, bin):
1 0 0 1 1 0 0 1 0 0 0 0 1 1 1 1 .0

data_packed_network = (16 items, bin):


0 0 0 0 1 1 1 1 1 0 0 1 1 0 0 1 .0

18.2.1.6 packing.global_default
This pack_options instance is used when the first parameter of pack(), unpack(), do_pack(), or
do_unpack() is NULL. It has the same flags as packing.low.

See Also
• “Using the Predefined pack_options Instances” on page 18-12

18.2.2 Customizing Pack Options


Each of the predefined instances described in “Using the Predefined pack_options Instances” on page
18-12 is an instance of the pack_options struct. The pack_options declaration is as follows:

struct pack_options {
reverse_fields: bool;
reverse_list_items: bool;
final_reorder: list of int;
scalar_reorder: list of int;
};

To customize packing options, you can create an instance of the pack_options struct, modify one or
more of its fields, and pass the struct instance as the first parameter to pack(), unpack(), do_pack(), or
do_unpack().

The following sections describe each field of the pack_options struct:

• reverse_fields on page 18-19


• reverse_list_items on page 18-20
• scalar_reorder on page 18-20

18-18 e Language Reference


Packing and Unpacking
Customizing Pack Options

• final_reorder on page 18-22

See Also
• “Using the Predefined pack_options Instances” on page 18-12
• “Customizing Packing for a Particular Struct” on page 18-23
• “Bit Slice Operator and Packing” on page 18-24
• “Implicit Packing and Unpacking” on page 18-25
• “Untyped Expressions” on page 3-17

18.2.2.1 reverse_fields
If this flag is set to be FALSE, the fields in a struct are packed in the order they appear in the struct
declaration; if TRUE, they are packed in reverse order. The default is FALSE.

Example
When reverse_fields is FALSE, “first” is packed and then “second”. When the flag is set to TRUE,
“second” is packed before “first”. Thus, the first result is 0b01; the second result is 0b10.
struct my_struct{
%first :int(bits:1); -- value 1
%second :int(bits:1); -- value 0;
init() is also {
first = 1;
};
};

extend sys{
my_struct;
foo() is {
var p1:pack_options = new;
var p2:pack_options = new;
p2.reverse_fields = TRUE;
my_struct = new;
print pack(p1,my_struct);
print pack(p2,my_struct);
};
};

e Language Reference 18-19


Packing and Unpacking
Customizing Pack Options

Result
pack(p1,my_struct) = (2 items, hex):
1 .0

pack(p2,my_struct) = (2 items, hex):


2 .0

See Also
• “Customizing Pack Options” on page 18-18

18.2.2.2 reverse_list_items
If this flag is set to be FALSE, the items in a list are packed in ascending order; if TRUE, they are packed
in descending order. The default is FALSE.

Example
The second print statement shows that “my_list” is packed in reverse order.
var my_list:list of int(bits:1) = {1;0;0};
var p1:pack_options = new;
var p2:pack_options = new;
p2.reverse_list_items = TRUE;
print pack(p1,my_list) using bin;
print pack(p2,my_list) using bin;

Result
pack(p1,my_list) = (3 items, bin):
0 0 1 .0

pack(p2,my_list) = (3 items, bin):


1 0 0 .0

See Also
• “Customizing Pack Options” on page 18-18

18.2.2.3 scalar_reorder
You can perform one or more swap() operations on each scalar before packing using the scalar_reorder
field.

18-20 e Language Reference


Packing and Unpacking
Customizing Pack Options

The list in the scalar_reorder field must include an even number of items. Each pair of items in the list
is the parameter list of a swap() operation (see swap() on page 18-36). By entering multiple pairs of
parameters, you can perform multiple swaps, using each pair of parameters as a pair of swap parameters.

Unlike swap(), if the large parameter is not a factor of the number of bits in the list, scalar_reorder
ignores it, while swap() gives an error.

Example 1
The bits in “mid” and “sma” are swapped using 4 and 2 as parameters. See swap() on page 18-36. Thus,
within every four bits the first two bits and the last two are swapped.
var p1:pack_options = new;
var mid:int(bits:8) = 0xcc;
var sma:int(bits:4) = 0x6;
print pack(p1,mid) using bin;
print pack(p1,sma) using bin;
p1.scalar_reorder = {2;4};
print pack(p1,mid) using bin;
print pack(p1,sma) using bin;

Result
pack(p1,mid) = (8 items, bin):
1 1 0 0 1 1 0 0 .0

pack(p1,sma) = (4 items, bin):


0 1 1 0 .0

pack(p1,mid) = (8 items, bin):


0 0 1 1 0 0 1 1 .0

pack(p1,sma) = (4 items, bin):


1 0 0 1 .0

Example 2
The bits in “midb” are swapped, first using 8 and 4 as parameters, and then using 16 and 8 as parameters.
See swap() on page 18-36. Thus, within every eight bits the first four bits and the last four are swapped,
and then within the entire 16-bit number, the first eight bits and the last eight bits are swapped.
var p1:pack_options = new;
var midb:int(bits:16) = 0xc5fd;
print pack(p1,midb) using bin;
p1.scalar_reorder = {4;8;8;16};
print pack(p1,midb) using bin;

e Language Reference 18-21


Packing and Unpacking
Customizing Pack Options

Result
pack(p1,midb) = (16 items, bin):
1 1 0 0 0 1 0 1 1 1 1 1 1 1 0 1 .0

pack(p1,midb) = (16 items, bin):


1 1 0 1 1 1 1 1 0 1 0 1 1 1 0 0 .0

See Also
• “Customizing Pack Options” on page 18-18

18.2.2.4 final_reorder
After packing each element in the packing expression you can perform final swapping on the resulting
bit stream, using the final_reorder field.

The list in the final_reorder field must include an even number of items. Each pair of items in the list is
the parameter list of a swap() operation (see swap() on page 18-36). By entering multiple pairs of
parameters, you can perform multiple swaps, using each pair of parameters as a pair of swap parameters.

Unlike swap(), if the large parameter is not a factor of the number of bits in the list, final_reorder
ignores it, while swap() gives an error.

Example 1
After performing the second pack, a swap is performed using 4 and 8 as parameters, thus reversing the
order of nibbles in every byte. See swap() on page 18-36.
var p1:pack_options = new;
var int__4: int(bits:4) = 0x7;
var int__12: int(bits:12) = 0x070;
print pack(p1,int__4,int__12) using bin;
p1.final_reorder = {4;8};
print pack(p1,int__4,int__12) using bin;

Result
pack(p1,int__4,int__12) = (16 items, bin):
0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 .0

pack(p1,int__4,int__12) = (16 items, bin):


0 1 1 1 0 0 0 0 0 1 1 1 0 0 0 0 .0

18-22 e Language Reference


Packing and Unpacking
Customizing Packing for a Particular Struct

Example 2
The bits in “midb” are swapped, first using 8 and 4 as parameters, and then using 16 and 8 as parameters.
See swap() on page 18-36. Thus, within every eight bits the first four bits and the last four are swapped,
and then within the entire 16-bit number, the first eight bits and the last eight bits are swapped.
var p1:pack_options = new;
var midb:int(bits:16) = 0xc5fd;
print pack(p1,midb) using bin;
p1.scalar_reorder = {4;8;8;16};
print pack(p1,midb) using bin;

Result
pack(p1,midb) = (16 items, bin):
1 1 0 0 0 1 0 1 1 1 1 1 1 1 0 1 .0

pack(p1,midb) = (16 items, bin):


1 1 0 1 1 1 1 1 0 1 0 1 1 1 0 0 .0

See Also
• “Customizing Pack Options” on page 18-18

18.2.3 Customizing Packing for a Particular Struct


You can customize packing for a particular struct by modifying the do_pack() or do_unpack() methods
of the struct. These methods are called automatically whenever data is packed from or unpacked into the
struct. See do_pack() on page 18-38 and do_unpack() on page 18-42 for more information.

See Also
• “Using the Predefined pack_options Instances” on page 18-12
• “Customizing Pack Options” on page 18-18
• “Bit Slice Operator and Packing” on page 18-24
• “Implicit Packing and Unpacking” on page 18-25
• “Untyped Expressions” on page 3-17

e Language Reference 18-23


Packing and Unpacking
Bit Slice Operator and Packing

18.2.4 Bit Slice Operator and Packing


You can use the bit slice operator [ : ] to select a subrange of an expression to be packed or unpacked.
The bit slice operator does not change the type of the pack or unpack expression.

Example 1
In the following example, the result of the first print statement is 20 bits long. However, the pack
expression, which extracts only 2 bits of “int_20”, is only 2 bits long.
var int_20: int(bits:20) = 7;
print int_20[1:0] using bin;
print pack(packing.low,int_20[1:0]) using bin;

Result
int_20[1:0] = 0b00000000000000000011
pack(packing.low,int_20[1:0]) = (2 items, bin):
1 1 .0

Example 2
“int_5” did not consume five bits as its type suggests. Because of the bit slice operator, it consumed only
two bits. Thus “int_1” gets the third bit from “lob” and remains 0.
var int_5: int(bits:5);
var int_1: bit;
var lob: list of bit = {1;1;0;1;1;1;1};
unpack(packing.low, lob, int_5[1:0], int_1);
print int_5, int_1 using bin;

Result
int_5 = 0b00011
int_1 = 0b0

See Also
• “Using the Predefined pack_options Instances” on page 18-12
• “Customizing Pack Options” on page 18-18
• “Customizing Packing for a Particular Struct” on page 18-23
• “Implicit Packing and Unpacking” on page 18-25
• “Untyped Expressions” on page 3-17

18-24 e Language Reference


Packing and Unpacking
Implicit Packing and Unpacking

18.2.5 Implicit Packing and Unpacking


Implicit packing and unpacking is always performed using the parameters of packing.low and takes
place in the following cases:

• When an untyped expression is assigned to a scalar or list of scalars, it is implicitly unpacked before
it is assigned.
var my_list: list of int = {1;2;3};
var int_10: int(bits:10);
my_list = 'top.foo';
int_10 = pack(NULL, 5);
Untyped expressions include HDL signals, pack expressions and bit concatenations. See “Untyped
Expressions” on page 3-17 for more information.

Note Implicit packing and unpacking is not supported for strings, structs, or lists of non-scalar
types. As a result, the following causes a load-time error if “i” is a string, a struct, or a list of a
non-scalar type:
i = pack(packing.low, 5); // Load-time error

• When a scalar or list of scalars is assigned to an untyped expression, it is implicitly packed before it
is assigned:
'top.foo' = {1;2;3};

• When the value expression of an unpack action is other than a list of bit, it is implicitly packed before
it is unpacked:
unpack(packing.low,5,my_list);

See Also
• “Using the Predefined pack_options Instances” on page 18-12
• “Customizing Pack Options” on page 18-18
• “Customizing Packing for a Particular Struct” on page 18-23
• “Bit Slice Operator and Packing” on page 18-24
• “Untyped Expressions” on page 3-17

18.3 How to Debug Packing


You can use the show pack and show unpack commands to display the results of packing or unpacking.

e Language Reference 18-25


Packing and Unpacking
Constructs for Packing and Unpacking

The trace packing command can help you debug your packing results. If you suspect that something
went wrong during packing or unpacking, you might want to set the trace pack flag. This trace follows
the packing process as it progresses and displays intermediate results to the screen.

See Also
• trace on packing on page 17-25 in the Specman Command Reference
• show pack on page 19-1 in the Specman Command Reference
• show unpack on page 19-3 in the Specman Command Reference
• “Basic Packing” on page 18-2
• “Advanced Packing” on page 18-12
• “Constructs for Packing and Unpacking” on page 18-26

18.4 Constructs for Packing and Unpacking


The following sections describe the constructs used in packing and unpacking:

• pack() on page 18-27


• unpack() on page 18-31
• %{… , …} on page 2-79
• swap() on page 18-36
• do_pack() on page 18-38
• do_unpack() on page 18-42

See Also
• “Basic Packing” on page 18-2
• “Advanced Packing” on page 18-12
• “How to Debug Packing” on page 18-25

18-26 e Language Reference


Packing and Unpacking
pack()

18.4.1 pack()

Purpose
Perform concatenation and type conversion

Category
Pseudo-method

Syntax
pack(option:pack option, item: exp, …): list of bit

Syntax Example
i_stream = pack(packing.high, opcode, operand1, operand2);

Parameters

option For basic packing, this parameter is one of the following. See “Using the
Predefined pack_options Instances” on page 18-12 for information on other
pack options.

packing.high Places the least significant bit of the last physical field declared or the highest
list item at index [0] in the resulting list of bit. The most significant bit of the
first physical field or lowest list item is placed at the highest index in the
resulting list of bit.

packing.low Places the least significant bit of the first physical field declared or lowest list
item at index [0] in the resulting list of bit. The most significant bit of the last
physical field or highest list item is placed at the highest index in the resulting
list of bit.

NULL If NULL is specified, the global default is used. This global default is set
initially to packing.low.

item A legal e expression that is a path to a scalar or a compound data item, such as
a struct, field, list, or variable.

e Language Reference 18-27


Packing and Unpacking
pack()

Description
Performs concatenation of items, including items in a list or fields in a struct, in the order specified by
the pack options parameter and returns a list of bits. This method also performs type conversion between
any of the following:

• scalars
• strings
• lists and list subtypes (same type but different width)
Packing is commonly used to prepare high-level e data into a form that can be applied to a DUT. For
other uses, see “Packing and Unpacking” on page 18-1.

Packing operates on scalar or compound (struct, list) data items. For more information and examples of
how packing operates on different data types, see “Basic Packing” on page 18-2.

Pack expressions are untyped expressions. In many cases, Specman can deduce the required type from
the context of the pack expression. See “Untyped Expressions” on page 3-17 for more information.

Note
You cannot pack an unbounded integer.

Example 1
The extension to post_generate() shown below packs the “opcode” and the “operand” fields of the
“instruction” struct from the low bit of the last field defined (“operand”) to the high bit of the first field
defined (“opcode”) into the “data_packed_high” field. It also packs all the physical fields into
“data_packed_low” using the packing.low option. The results are shown in Figure 18-4 on page 18-29.
<'
struct instruction {
%opcode : uint (bits : 3);
%operand : uint (bits : 5);
%address : uint (bits : 8);

!data_packed_high : list of bit;


!data_packed_low : list of bit;

keep opcode == 0b100;


keep operand == 0b11001;
keep address == 0b00001111;

post_generate() is also {
data_packed_high = pack(packing.high,
opcode,operand);

18-28 e Language Reference


Packing and Unpacking
pack()

data_packed_low = pack(packing.low, me);


print me using bin;
print data_packed_low using bin;
print data_packed_high using bin;
};
};
'>

Figure 18-4 Packed Instruction Data

The “instruction” struct:

opcode == 0x4 1 0 0

operand == 0x19 1 1 0 0 1

address == 0x0f 0 0 0 0 1 1 1 1

The fields “opcode” and “operand” packed, using packing.high

opcode operand

1 0 0 1 1 0 0 1

list of bit [7] list of bit [0]

The instruction packed, using packing.low

address operand opcode

0 0 0 0 1 1 1 1 1 1 0 0 1 1 0 0
list of bit [15] list of bit [0]

Example 2
In this example, post_generate() is extended to pack the packet data. The “header” field of the “packet”
struct is a struct itself, so this is a recursive pack. The results are shown in Figure 18-5 on page 18-31.
<'

e Language Reference 18-29


Packing and Unpacking
pack()

struct packet {
%header : header;
%payload : list of byte;

!data_packed_low : list of byte;

keep payload.size() == 6;
keep for each in payload {
it == index;
};

post_generate() is also {
data_packed_low = pack(packing.low, me);
out("payload: ", payload);
out("data packed low: ", data_packed_low);
};
};

struct header {
%dest : int (bits : 8);
%version : int (bits : 2);
%type : uint (bits : 6);

keep dest == 0x55;


keep version == 0x0;
keep type == 0x3f;
post_generate() is also {
print me;
};
};
'>

Result
Note that the “out()” action displays the bytes from least significant to most significant (from left to
right), whereas the print action displays the bytes from most significant to least significant (from left to
right).
vrst-tool> test
Doing setup …
Generating the test using seed 0x1…
me = header-@0: header
--------------------------------------------- @pack23
0 %dest: 0x55
1 %version: 0x0
2 %type: 0x3f

18-30 e Language Reference


Packing and Unpacking
unpack()

payload : 0x00 0x01 0x02 0x03 0x04 0x05


packet packed low: 0x55 0xfc 0x00 0x01 0x02 0x03 0x04 0x05

Figure 18-5 Packed Packet Data

The “packet” struct:


Header:

dest 0 1 0 1 0 1 0 1

version 0 0

type 1 1 1 1 1 1

Payload
0 0 0 0 0 1 0 1 ..... 0 0 0 0 0 0 0 0

The “packet” data packed, using packing.low

payload type version dest

..... 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 1 0 1 0 1 0 1
list of bit [127] list of bit [0]

See Also
• unpack() on page 18-31
• %{… , …} on page 2-79
• swap() on page 18-36
• do_pack() on page 18-38
• do_unpack() on page 18-42

18.4.2 unpack()

Purpose
Unpack a bit stream into one or more expressions

e Language Reference 18-31


Packing and Unpacking
unpack()

Category
Pseudo-method

Syntax
unpack(option: pack option, value: exp, target1: exp [, target2: exp, …])

Syntax Example
unpack(packing.high, lob, s1, s2);

Parameters

option For basic packing, this parameter is one of the following. See “Using the
Predefined pack_options Instances” on page 18-12 for information on other
pack options.

packing.high Places the most significant bit of the list of bit at the most significant bit of the
first field or lowest list item. The least significant bit of the list of bit is placed
into the least significant bit of the last field or highest list item.

packing.low Places the least significant bit of the list of bit into the least significant bit of
the first field or lowest list item. The most significant bit of the list of bit is
placed at the most significant bit of the last field or highest list item.

NULL If NULL is specified, the global default is used. This global default is set
initially to packing.low.

value A scalar expression or list of scalars that provides a value that is to be


unpacked.

target1, target2 One or more expressions separated by commas. Each expression is a path to a
scalar or a compound data item, such as a struct, field, list, or variable.

Description
Converts a raw bit stream into high level data by storing the bits of the value expression into the target
expressions.

If the value expression is not a list of bit, it is first converted into a list of bit by calling pack() using
packing.low. (See “Implicit Packing and Unpacking” on page 18-25 for more information.) Then the list
of bit is unpacked into the target expressions.

18-32 e Language Reference


Packing and Unpacking
unpack()

The value expression is allowed to have more bits than are consumed by the target expressions. In that
case, if packing.low is used, the extra high-order bits are ignored; if packing.high is used, the extra
low-order bits are ignored.

Unpacking is commonly used to convert raw bit stream output from the DUT into high-level e data.

Unpacking operates on scalar or compound (struct, list) data items. For more information and examples
of how packing operates on different data types, see “Basic Packing” on page 18-2.

Example 1
The extension to post_generate() shown below unpacks a list of bits into a variable “inst”. The results
are shown in Figure 18-6 on page 18-33.
extend sys {
post_generate() is also {
var inst : instruction;
var packed_data: list of bit;
packed_data = {1;1;1;1;0;0;0;0;1;0;0;1;1;0;0;1};

unpack(packing.high, packed_data, inst);

print packed_data using bin;


out("the result of unpacking it: ");
print inst using bin;
};
};

struct instruction {
%opcode : uint (bits : 3);
%operand : uint (bits : 5);
%address : uint (bits : 8);
};

Figure 18-6 Unpacked Instruction Data

e Language Reference 18-33


Packing and Unpacking
unpack()

The packed data

1 0 0 1 1 0 0 1 0 0 0 0 1 1 1 1

The result of unpacking the data with packing.high:

opcode == 0x4 1 0 0

operand == 0x19 1 1 0 0 1

address == 0x0f 0 0 0 0 1 1 1 1

Example 2
The extension to post_generate() shown below unpacks a list of bytes into a variable “pkt” using
packing.low. This is a recursive unpack because the “header” field of “packet” is a struct itself. The
results are shown in Figure 18-7 on page 18-35.
extend sys {
post_generate() is also {
var pkt : packet;
var packed_data : list of byte;
packed_data =
{0x55;0xfc;0x00;0x01;0x02;0x03;0x04;0x05};

unpack(packing.low, packed_data, pkt);

print packed_data;
out("the unpacked struct:");
print pkt.header, pkt.payload;
};
};

struct packet {
%header : header;
%payload : list of byte;
};

struct header {
%dest : int (bits : 8);
%version : int (bits : 2);
%type : int (bits : 6);

18-34 e Language Reference


Packing and Unpacking
unpack()

};

Figure 18-7 Unpacked Packet Data

The packed data

..... 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 1 0 1 0 1 0 1

The unpacked struct

Header:

dest 0 1 0 1 0 1 0 1

version 0 0

type 1 1 1 1 1 1

Payloa
0 0 0 0 0 1 0 1 ..... 0 0 0 0 0 0 0 0

Example 3
This example uses unpack() sequentially to set up virtual fields that are required for the full unpack.
struct packet {
%header: header;
len : uint;
%data[len] : list of byte;
};
struct header {
%code : uint;
};
extend sys {
m() is {
var DUT_bytes: list of byte = {0x11;0xff;0x22;
0xee;0x33;0xdd;0x44;0xcc;0x55;0xbb;0x66};
var p : packet = new;
unpack(packing.low, DUT_bytes, p.header);
if p.header.code > 1500 {
p.len = 10;

e Language Reference 18-35


Packing and Unpacking
swap()

} else {
p.len = 20;
};
unpack(packing.low, DUT_bytes,p);
print p;
print p.data;
};
};

See Also
• pack() on page 18-27
• %{… , …} on page 2-79
• swap() on page 18-36
• do_pack() on page 18-38
• do_unpack() on page 18-42

18.4.3 swap()

Purpose
Swap small bit chunks within larger chunks

Category
Pseudo-method

Syntax
list-of-bit.swap(small: int, large: int): list of bit

Syntax Example
s2 = s1.swap(2, 4);

Parameters

small An integer that is a factor of large.

18-36 e Language Reference


Packing and Unpacking
swap()

large An integer that is either UNDEF or a factor of the number of bits in the entire list. If
UNDEF, the method reverses the order of small chunks within the entire list. Thus,
“lob.swap(1, UNDEF)” is the same as “lob.reverse()”.

Description
This predefined list method accepts a list of bits, changes the order of the bits, and then returns the
reordered list of bits. This method is often used in conjunction with pack() or unpack() to reorder the
bits in a bit stream going to or coming from the DUT.

Notes
• If large is not a factor of the number of bits in the entire list, an error message results.
• If small is not a factor of large, you will see an error message. The only exception is if large is UNDEF
and small is not a factor, no swap is performed and no error is issued.

Example 1
This example shows two swaps. The first swap reverses the order of nibbles in every byte. The second
swap reverses the whole list.

my_list

0 1 0 1 0 0 0 0 1 1 1 1 0 1 0 1

my_list.swap(4, 8)

0 0 0 0 0 1 0 1 0 1 0 1 1 1 1 1

my_list.swap(1, UNDEF)

1 0 1 0 1 1 1 1 0 0 0 0 1 0 1 0

Example 2
This example shows swap() used with unpack() to reorder the bits before unpacking them.
extend sys {
post_generate() is also {

e Language Reference 18-37


Packing and Unpacking
do_pack()

var num1 : uint (bits : 32);


var num2 : uint (bits : 32);
num1 = 0x12345678;

unpack(NULL, pack(NULL, num1).swap(16, -1), num2);


print num2;
unpack(NULL, pack(NULL, num1).swap(8, -1), num2);
print num2;
};
};

Results
num2 = 0x56781234
num2 = 0x78563412

See Also
• pack() on page 18-27
• unpack() on page 18-31
• %{… , …} on page 2-79
• do_pack() on page 18-38
• do_unpack() on page 18-42

18.4.4 do_pack()

Purpose
Pack the physical fields of the struct

Category
Predefined method of any struct

Syntax
do_pack(options:pack options, l: *list of bit)

Syntax Example
do_pack(options:pack_options, l: *list of bit) is only {

18-38 e Language Reference


Packing and Unpacking
do_pack()

var L : list of bit = pack(packing.low, operand2,


operand1,operand3);
l.add(L);
};

Parameters

options This parameter is an instance of the pack options struct. See “Using the
Predefined pack_options Instances” on page 18-12 for information on this
struct.

l An empty list of bits that is extended as necessary to hold the data from the
struct fields.

Description
The do_pack() method of a struct is called automatically whenever the struct is packed. This method
appends data from the physical fields (the fields marked with %) of the struct into a list of bits according
to flags determined by the pack options parameter. The virtual fields of the struct are skipped. The
method issues a runtime error message if this struct has no physical fields.

For example, the following assignment to “lob”


lob = pack(packing.high, i_struct, p_struct);

makes the following calls to the do_pack method of each struct, where tmp is an empty list of bits:
i_struct.do_pack(packing.high, *tmp)
p_struct.do_pack(packing.high, *tmp)

You can extend the do_pack() method for a struct in order to create a unique packing scenario for that
struct. You should handle variations in packing that apply to many structs by creating a custom
pack_options instance. See “Customizing Pack Options” on page 18-18 for information on how to do
this.

Notes
• Do not call the do_pack() method of any struct directly, for example “my_struct.do_pack()”. Instead
use pack(), for example “pack(packing.high, my_struct)”.
• Do not call pack(me) in the do_pack() method. This causes infinite recursion. Call
packing.pack_struct(me) instead. You can call pack() within the do_pack() method to pack objects
other than me.

e Language Reference 18-39


Packing and Unpacking
do_pack()

• Do not forget to append the results of any pack operation within do_pack() to the empty list of bits
referenced in the do_pack() parameter list.
• If you modify the do_pack() method and then later add physical fields in an extension to the struct,
you may have to make adjustments in the modifications to do_pack().

Example 1
This example shows how to override the do_pack() method for a struct called “cell”. The extension to
do_pack() overrides any packing option passed in and always uses packing.low. It packs “operand2”
first, then “operand1” and “operand3”.
<'
struct cell {
%operand1: uint(bytes:2);
%operand2: uint(bytes:2);
%operand3: uint(bytes:2);
};

extend cell {
do_pack(options:pack_options, l: *list of bit) is only {
var L : list of bit = pack(packing.low, operand2,
operand1,operand3);
l.add(L);
};
};

Result
Specman pack33> print sys.pi using bin
sys.pi = cell-@0: cell
---------------------------------------------- @pack33
0 %operand1: 0b0010001000111001
1 %operand2: 0b0001101001110101
2 %operand3: 0b0001001010110010
Specman pack33> var L : list of bit = pack(packing.high, sys.pi)
Specman pack33> print L using bin
L = (48 items, bin):
0 0 1 1 1 0 0 1 0 0 0 1 1 0 1 0 0 1 1 1 0 1 0 1 .0
0 0 0 1 0 0 1 0 1 0 1 1 0 0 1 0 0 0 1 0 0 0 1 0 .24

Example 2
In the following example, the do_pack() method for “cell” is overwritten to use the low_big_endian
packing option by default.

18-40 e Language Reference


Packing and Unpacking
do_pack()

struct cell {
%operand1: uint(bytes: 2);
%operand2: uint(bytes: 2);
%operand3: uint(bytes: 2);
};

extend cell {
do_pack(options: pack_options, l: *list of bit) is only {
if (options == NULL) then {
packing.pack_struct(me,
packing.low_big_endian,l);
} else {
packing.pack_struct(me, options, l);
};
};
};

extend sys {
pi: cell;
};

Result
Specman pack34> print sys.pi using bin
sys.pi = cell-@0: cell
---------------------------------------------- @pack34
0 %operand1: 0b0010001000111001
1 %operand2: 0b0001101001110101
2 %operand3: 0b0001001010110010
Specman pack34> var M : list of bit = pack(NULL, sys.pi)
Specman pack34> print M using bin
M = (48 items, bin):
0 0 0 1 1 0 1 0 0 0 1 1 1 0 0 1 0 0 1 0 0 0 1 0 .0
1 0 1 1 0 0 1 0 0 0 0 1 0 0 1 0 0 1 1 1 0 1 0 1 .24

Example 3
This example swaps every pair of bits within each 4-bit chunk after packing with the packing options
specified in the pack() call.
struct cell {
%operand1: uint(bytes: 2);
%operand2: uint(bytes: 2);
%operand3: uint(bytes: 2);
};

extend cell {

e Language Reference 18-41


Packing and Unpacking
do_unpack()

do_pack(options:pack_options, l: *list of bit) is only {


var L1 : list of bit;
packing.pack_struct(me, options, L1);
var L2 : list of bit = L1.swap(2,4);
l.add(L2);
};
};

Result
Specman pack35> print sys.pi using bin
sys.pi = cell-@0: cell
---------------------------------------------- @pack35
0 %operand1: 0b0010001000111001
1 %operand2: 0b0001101001110101
2 %operand3: 0b0001001010110010
Specman pack35> var M : list of bit = pack(NULL, sys.pi)
Specman pack35> print M using bin
M = (48 items, bin):
1 1 0 1 0 1 0 1 1 0 0 0 1 0 0 0 1 1 0 0 0 1 1 0 .0
0 1 0 0 1 0 0 0 1 1 1 0 1 0 0 0 0 1 0 0 1 0 1 0 .24

See Also
• pack() on page 18-27
• unpack() on page 18-31
• %{… , …} on page 2-79
• swap() on page 18-36
• do_unpack() on page 18-42

18.4.5 do_unpack()

Purpose
Unpack a packed list of bit into a struct

Category
Predefined method of any struct

18-42 e Language Reference


Packing and Unpacking
do_unpack()

Syntax
do_unpack(options:pack options, l: list of bit, begin: int): int

Syntax Example
do_unpack(options:pack_options, l: list of bit, begin: int):int is only {
var L : list of bit = l[begin..];
unpack(packing.low, L, op2, op1, op3);
return begin + 8 + 5 + 3;
};

Parameters

options This parameter is an instance of the pack options struct. See


“Using the Predefined pack_options Instances” on page 18-12 for
information on this struct.

l A list of bits containing data to be stored in the struct fields.

from An integer that specifies the index of the bit to start unpacking.

int (return value) An integer that specifies the index of the last bit in the list of bits
that was unpacked.

Description
The do_unpack() method is called automatically whenever data is unpacked into the current struct. This
method unpacks bits from a list of bits into the physical fields of the struct. It starts at the bit with the
specified index, unpacks in the order defined by the pack options, and fills the current struct’s physical
fields in the order they are defined.

For example, the following call to unpack()


unpack(packing.low, lob, c1, c2);

makes the following calls to the do_unpack method of each struct:


c1.do_unpack(packing.low, lob, index);
c2.do_unpack(packing.low, lob, index);

The method returns an integer, which is the index of the last bit unpacked into the list of bits.

The method issues a runtime error message if the struct has no physical fields. If at the end of packing
there are leftover bits, it is not an error. If more bits are needed than currently exist in the list of bits, a
runtime error is issued (“Ran out of bits while trying to unpack into struct_name”).

e Language Reference 18-43


Packing and Unpacking
do_unpack()

You can extend the do_unpack() method for a struct in order to create a unique unpacking scenario for
that struct. You should handle variations in unpacking that apply to many structs by creating a custom
pack_options instance. See “Customizing Pack Options” on page 18-18 for information on how to do
this.

Notes
• Do not call the do_unpack() method of any struct directly, for example “my_struct.do_unpack()”.
Instead use unpack(), for example “unpack(packing.high, lob, my_struct)”.
• When you modify the do_unpack() method, you need to calculate and return the index of the last
bit in the list of bits that was unpacked. In most cases, you simply add the bit width of each physical
field in the struct to the starting index parameter. If you are unpacking into a struct that has conditional
physical fields (physical fields defined under a when, extend, or like construct), this calculation is
a bit tricky. See the Verification Advisor’s patterns on packing for an example of how to do this.

Example 1
This first example shows how to modify do_unpack() to change the order in which the fields of a struct
are filled. In this case, the order is changed from “op1”, “op2”, “op3” to “op2”, “op1”, “op3”. You can
see also that do_unpack() returns the bit widths of the three physical fields, “op1”, “op2”, and “op3”, to
the starting index, “begin”.
struct cell {
%op1: uint(bytes:1);
%op2: uint(bits:5);
%op3: uint(bits:3);
};

extend cell {
do_unpack(options:pack_options, l: list of bit,
begin: int) :int is only {
var L : list of bit = l[begin..];
unpack(packing.low, L, op2, op1, op3);
return begin + 8 + 5 + 3;
};
};

Result
Specman pack36> var P : list of bit
{0;0;0;0;1;1;0;1;1;1;0;0;0;0;1;0;};
Specman pack36> unpack(NULL, P, sys.pi)
Specman pack36> print sys.pi using bin
sys.pi = cell-@0: cell

18-44 e Language Reference


Packing and Unpacking
do_unpack()

---------------------------------------------- @pack36
0 %op1: 0b00011101
1 %op2: 0b10000
2 %op3: 0b010

Example 2
This example modifies the do_unpack method of the “frame” struct to first calculate the length of the
“data” field. The calculation uses “begin”, which indicates the last bit to be unpacked, to calculate the
length of “data”.
extend sys {
!packet1 : packet;
!packet2 : packet;

post_generate() is also {
var raw_data : list of byte;
for i from 0 to 39 {
raw_data.add(i);
};
unpack(packing.low, raw_data, packet1);
print packet1.header, packet1.frame.data,
packet1.frame.crc;
unpack(packing.high, raw_data, packet2);
print packet2.header, packet2.frame.data,
packet2.frame.crc;
};
};

struct packet {
%header : int (bits : 16);
%frame : frame;
};

struct frame {
%data[len] : list of byte;
%crc : int (bits : 32);
len : int;

do_unpack(options :pack_options, l :list of bit,


begin :int):int is first {

if options.reverse_fields then {
len = (begin - 32 + 1) / 8;
} else {
len = (l.size() - begin - 32) / 8;
};

e Language Reference 18-45


Packing and Unpacking
do_unpack()

};
};

Results
packet1.header = 256
packet1.frame.data = (34 items, dec):
13 12 11 10 9 8 7 6 5 4 3 2 .0
25 24 23 22 21 20 19 18 17 16 15 14 .12
35 34 33 32 31 30 29 28 27 26 .24

packet1.frame.crc = 656811300
packet2.header = 10022
packet2.frame.data = (34 items, dec):
26 27 28 29 30 31 32 33 34 35 36 37 .0
14 15 16 17 18 19 20 21 22 23 24 25 .12
4 5 6 7 8 9 10 11 12 13 .24

packet2.frame.crc = 50462976

See Also
• pack() on page 18-27
• unpack() on page 18-31
• %{… , …} on page 2-79
• swap() on page 18-36
• do_pack() on page 18-38

18-46 e Language Reference


19 Macros
This chapter describes the constructs used to create and debug e macros. Macro definitions specify a
name or a pattern that is to be replaced by e code text. The constructs for defining and debugging macros
are:

• define as on page 19-1


• define as computed on page 19-10
• “Debugging e Macros” on page 19-15

See Also
• “#define” on page 20-5
• Chapter 20 “Preprocessor Directives”
• Chapter 21 “Importing e Files”

19.1 define as

Purpose
Define a simple replacement macro

Category
Statement

e Language Reference 19-1


Macros
define as

Syntax
define <macro-name'nonterminal-type> match-string as {“replacement”}

Syntax Example
define <largest'action> "largest <exp> <num>" as {
if <num> > <exp> then {<exp> = <num>};
};

Parameters

macro-name, A name you give to the macro and the syntactic type for the macro. The macro
nonterminal-type can be used wherever it is legal to use the nonterminal-type. The macro-name
and nonterminal-type together form a unique internal macro name. They must
be separated by an apostrophe (').

The e nonterminal types are shown in Table 19-1.

The combination macro-name'nonterminal-type must be unique over all e


modules. For example, it is possible to have both a <do_it’statement> and a
<do_it’action>, but there cannot be two <do_it’action> macros.

match-string A quoted string containing text and parsing elements. It may be an expression.
Items represented by parsing elements in the match-string are passed to
corresponding parsing elements in the replacement.

Parsing elements for both match-string and replacement are shown in Table
19-2. Parsing elements must be used exactly as shown in the table, including
the angle brackets (<>). They may be preceded by an identifier and apostrophe
(for example, <num> or <big’num>).

19-2 e Language Reference


Macros
define as

replacement A string containing text and parsing elements, all of which must be legal types
in a construct of the nonterminal-type. Each parsing element in the replacement
corresponds to a parsing element of the same name in the match-string.

When the macro is used in the e code, the match-string parsing elements are
passed to the replacement.

The replacement can contain replacement terms in angle brackets. If there are
any replacement terms in the replacement string, they represent items for which
corresponding items exist in the match-string. When the macro is used, the
items provided with the macro are substituted for the replacement terms in the
replacement.

Forms for replacement terms are shown in Table 19-3. You can combine the
forms in replacement terms.

Table 19-1 e Language Nonterminal Types

Nonterminal Type Description

statement The basic element type of e.

action A procedural element.

command A command that can be entered at the vrst-tool> prompt.

struct_member A part of a struct definition.

exp A construct that has a value.

type A type.

block A series of actions enclosed in curly braces ({}).

num A number.

file A file name.

Table 19-2 e Language Parsing Elements

Parsing Element Description

<statement> Any legal statement.

<action> An action.

<command> A command.

e Language Reference 19-3


Macros
define as

Table 19-2 e Language Parsing Elements (continued)

Parsing Element Description

<struct_member> A struct member (event, field, method, coverage group, when struct
member, or constraint definition).

<exp> An expression.

<name> A legal name: it must start with a letter, and consist of letters, digits,
underscores (_) and single quotes (').

<file> A file name.

<num> A number.

<block> A series of actions enclosed by {}.

<Type> A type name: this can be used any place in the replacement where a type
is expected.

<any> Anything: any text can be entered for this item when the macro is used;
<any> items in the match-string must have corresponding <any> items in
the replacement.

[] Items enclosed in square brackets are optional.

| Items separated by | (OR bar) are alternatives.

() Parentheses group items for associativity or for readability.

Table 19-3 Replacement Term Syntax for define as

Replacement
Notation What it Represents Examples

<x_string> A string matching <x_string> in the input. <exp> <b'exp>

<x_string|y_string> The y_string is the default value if no match is found for the <num|0>
x_string in the input. This notation can be used only in the <big'num|100>
replacement, not in the match-string.

19-4 e Language Reference


Macros
define as

Table 19-3 Replacement Term Syntax for define as

Replacement
Notation What it Represents Examples

<n> The number of the nth substring in the input string. Each <1>
<x_string> is a substring, and thus can be represented by a <2>
number using this syntax. Similarly, each term enclosed in
square brackets ([]), parentheses (()), or curly braces ({}) is
a substring that can be represented by a number using this
syntax.

<?> A character sequence of the form __n__, where n is a var a<?>: int;
number that is unique over all expansions of this macro.
This is useful for creating unique variable names that will
not collide in the various places this macro will be used.

Description
You can use replacement macros to extend the e language, by defining new syntactic elements (actions,
commands, and so on). The define as statement creates a new syntactic element for the e parser.

You assign a macro name and an e nonterminal type (see Table 19-1 on page 19-3) to a string pattern.
When the e parser finds a string that matches the pattern, it replaces that string with the replacement
string. The replacement specifies what is to be done each time the parser finds the string pattern.

To find a definition of a macro it currently is parsing, the e parser searches definitions having the desired
nonterminal type, starting with the most recent definitions.

Notes
• A define as computed macro takes precedence over a define as macro when the match string satisfies
either one, regardless of the order in which the macro definitions appear in the code. For example,
the command “find least” matches either of the following macros:
define <my_first'command> "find least" as {
action; ...
};

define <my_second'command> "find <any>" as computed {


action; ...
};
However, the second macro, the define as computed macro, will always be the one that is applied
when “find least”, or “find anything”, is executed.

e Language Reference 19-5


Macros
define as

• The maximum number of replacement terms you can us in a replacement string is 14. (For some
replacement term types, this number may be exceeded, but the results of exceeding 14 replacement
terms are unpredictable, and doing so is not recommended.)
• To continue a string over multiple lines, put the line continuation character “\” at the end of each line
except the last.

Example 1
Define a new Specman command with the internal name “dir_lis” that executes the UNIX ls command
with any of its flags. The new command is invoked by “lis” with a list of flags. It executes the UNIX ls
command with those flags:
define <dir_lis'command> "lis[<any>]" as {
print output_from("ls <any>") using items=UNDEF;
};

At the vrst-tool> prompt you can enter the following commands, for example, which list files in the
current directory. The “-lt” flags and the “*.e” syntax are the same as for the UNIX ls command:
vrst-tool> lis
vrst-tool> lis -lt *.e

Example 2
Define a macro that creates a new action with the internal name “simple_frame” to generate a frame
with specified field values, and call a method named “send()”:
define <simple_frame'action> "send simple frame \
<dest_addr'num> <source_addr'num> <size'num>" as {
var f: frame;
gen f keeping {
.kind not in [SRAM,DUT];
.size == <size'num>;
.dest_address == <dest_addr'num>;
.source_address == <source_addr'num>;
};
start f.send();
};

Example of using the “send simple frame” macro:


extend sys {
run() is also { send simple frame 0x00fe 0x0010 0xff };
};

19-6 e Language Reference


Macros
define as

Example 3
Define a new action with the internal name “configure_frame” to generate a frame of a specified “kind”
and with an optional “dest_address” value, and call the “send()” method. The “name” element in the
match string will be replaced by “.kind” when the macro is used, and the “dest_addr'num” element will
be replaced by “.dest_address” if one is entered. If no “dest_address” is given with the macro, a
generated value is used:
<'
define <configure_frame'action>
"<name> config frame[ <dest_addr'num>]" as {
var f: frame;
if str_empty("<dest_addr'num>") {
gen f keeping {
.kind == <name>;
.size == 64;
};
} else {
gen f keeping {
.kind == <name>;
.dest_address == <dest_addr'num|0>;
.size == 64;
};
};
f.send();
};
type frame_kind: [SRAM, DUT];
struct frame {
kind: frame_kind;
size: uint (bits: 16);
data: byte;
dest_address: uint;
send() is {
'top.frame.addr' = me.dest_address;
'top.frame.data' = me.data;
};
};
extend sys {
run() is also {
SRAM config frame;
DUT config frame 0x1001;
};
};
'>

e Language Reference 19-7


Macros
define as

In the “else” block above, the “| 0” following “dest_addr'num” is required, even though this is the
condition where a “dest_address” is provided when the macro is used. This is because, even though it is
in the else block that is only used when a “dest_address” is provided, the line parses to the following for
the case where the optional “dest_addr'num” string is empty:
.dest_address == ;

Because that syntax is not allowed by the e parser, writing just “<dest_addr'num>” in this line of the
macro definition results in an illegal action error at load time. A default number must be included. It can
be any value that is legal for “dest_address”.

Example 4
Define a new action named “issue_struct”, which generates a struct and calls a method named “send()”.
Constraints may optionally be entered for struct members. In the sys extension the macro is used four
times, to generate four “transaction” structs, with constraints specified for the last two.

The Type nonterminal represents “transaction” structs. The <?> element attaches “__n__” to the “x”
variable, where n is a number that is unique for every usage of the macro. The <2> parsing element,
which is replaced by the second element of the match string, is determined by counting "<", "[" and "("
characters, starting from the left-most element. Thus, the <2> parsing element in this example is
“keeping <block>” and the second element of the match string must have the form “keeping
{constraint;…};”.
<'
define <issue_struct'action>
"issue <Type>[ keeping <block>]" as {
var x<?>: <Type>;
gen x<?> <2>;
x<?>.send();
};
type command_type: [opA, opB, opC];
struct transaction {
command: command_type;
value: int;
send() is {
out("\t command: ", command, ", value: ", value, "\n");
};
};
extend sys {
!transaction;
post_generate() is also {
issue transaction;
issue opA transaction;
issue transaction keeping {.command==opB; .value==5};
issue opC transaction keeping {.value == 6};
};

19-8 e Language Reference


Macros
define as

};
'>

To see how “x<?>” is expanded when the macro is parsed, the trace reparse command is entered before
the example file is loaded. The following is a printout of the results. For each call to the macro, the <?>
element is replaced by a unique number.
D> <issue_struct'action> 'issue transaction'
D> reparsed as: '{var x__14841__: transaction;gen x__14841__
;x__14841__.send()}'
D> <issue_struct'action> 'issue opA transaction'
D> reparsed as: '{var x__14842__: opA transaction;gen x__14842__
;x__14842__.send()}'
D> <issue_struct'action> 'issue transaction keeping {...}'
D> reparsed as: '{var x__14843__: transaction;gen x__14843__ keeping
{...};x__14843__.send()}'
D> <issue_struct'action> 'issue opC transaction keeping {...}'
D> reparsed as: '{var x__14844__: opC transaction;gen x__14844__ keeping
{...};x__14844__.send()}'
D> esb_reparse: <outf'exp> reparsed as 'out(...)'
D> esb_reparse: <out'exp> reparsed as 'append(...)'

Example 5
The following is a definition of an action with the internal name “swap_var”. The match string contains
two parsing element items, “<var1'exp>” and “<var2'exp>”, so the “<1>” in the third line corresponds to
“<var1'exp>”, the first parsing element in the match string. The notation “<2>” could likewise be used
for “<var2'exp>”. Thus, the third line could be written as “<1> = <2|z>”.
<'
define <swap_var'action> "swap <var1'exp>[ <var2'exp>]" as {
var tmp<?> := <var1'exp>;
<1> = <var2'exp|z>;
<var2'exp|z> = tmp<?>;
};
extend sys {
run() is also {
var a:= 5;
var b:= 9;
var z:= 13;
swap a b; // a becomes 9, b becomes 5
print a, b, z;
swap a; // a becomes 13, z becomes 9
print a, b, z;
};
};
'>

e Language Reference 19-9


Macros
define as computed

Once the macro is loaded, it can be used from the Specman command line as shown below:
vrst-tool> var m:= 5; var n:= 9; var z:= 13
vrst-tool> swap m n // m becomes 9, n becomes 5
vrst-tool> swap m // m becomes 13, z becomes 9

See Also
• #define on page 20-5
• define as computed on page 19-10

19.2 define as computed

Purpose
Define an advanced replacement macro

Category
Statement

Syntax
define <macro-name`nonterminal-type> match-string as computed {action; …}

Syntax Example
<'
define <time_command'action> "time <string>" as computed {
if <1> == "on" {
return( "{tprint = TRUE; print sys.time;}" );
} else if <1> == "off" {
return("tprint = FALSE");
} else {
out("Usage: time [on|off]");
};
};
'>

19-10 e Language Reference


Macros
define as computed

Parameters

macro-name, A name you give to the macro, and the syntactic type for the macro. The
nonterminal-type macro-name and nonterminal-type together form a unique internal name for the
macro. They must be separated by an apostrophe (').

The macro can be used wherever it is legal to use the nonterminal-type. The e
nonterminal types are shown in Table 19-1 on page 19-3.

The combination macro-name'nonterminal-type must be unique over all e


modules. For example, it is possible to have both a <do_it’statement> and a
<do_it’action>, but there cannot be two <do_it’action> macros.

match-string A double-quoted string consisting of text and parsing elements. It may be an


expression. Items represented by parsing elements in the match-string are
passed to corresponding parsing elements in the replacement.

Parsing elements for both match-string and replacement are shown in Table
19-2 on page 19-3, with the exception that <string> and <num> cannot be used
in the define as computed replacement string. Parsing elements must be used
exactly as shown in the table, including the angle brackets (<>). They may be
preceded by an identifier and apostrophe (for example, <exp> or <big’exp>).

action; ... A block of actions that are executed each time match-string is found. The
action block is treated by the parser as the body of a method. Thus you can use
the result variable or the return action to return a result from the action block.

The action block can contain replacement terms in angle brackets which
represent items that will actually be input to the macro when it is used. When
the macro is used, the items provided with the macro are substituted for the
replacement terms in the action block.

Legal forms for the replacement terms are shown in Table 19-4.

You cannot use explicit syntactic parameters such as <name> or <string> in the
action block or the computed replacement text.

e Language Reference 19-11


Macros
define as computed

Table 19-4 Replacement Term Syntax for define as computed

Replacement
Notation What it Represents Examples

<n> The number of the nth substring in the input string. Each <1> <2>
<x_string> is a substring, and thus can be represented by a number
using this syntax. Similarly, each term enclosed in square brackets
([]), parentheses (()), or curly braces ({}) is a substring that can be
represented by a number using this syntax.

<?> A character sequence of the form __n__, where n is a number that var a<?>:
is unique over all expansions of this macro. This is useful for int;
creating unique variable names that will not collide in the various
places this macro will be used.

Description
This statement creates a new syntactic element that constructs a block of actions based on the inputs to
the macro. These actions are executed like a method when the macro is encountered. The actions
produce an output string that replaces the match string. The output string is a set of actions that are
executed as e code.

For simple text replacement, use the define as statement rather than define as computed.

Space Removal in String Patterns


Specman first compresses all sequences of blanks and tabs into a single blank, before initial matching is
done, except that blanks and tabs inside double quotes are not compressed.

Finding Submatches
The same text may be part of more than one match. For example, “ exp” matches both “ exp” and “exp”.
Thus, “ +sim” matches “ +sim” and “+sim”. If you are not interested in the outer match, you can ignore
it.

Expanding Matches
Anything that is in “{}”, “()”, “[]”, or inside double quotes is replaced during preprocessing by a
notation of the form “_number_”. If you want to further parse the match, use str_expand_dots() to
expand it back to its actual string form.

19-12 e Language Reference


Macros
define as computed

Notes
• The returned string cannot contain any newline (\n) characters.
• If the returned string contains more than one action, the actions must be grouped into an action block
by enclosing it in curly braces ({}). That is also true of statements and other kinds of struct members:
Any semicolon-separated list of constructs in the return string must be enclosed in curly braces.
• The define as computed construct actually creates a method that is called during parsing. This method
extension does not understand types because the parsing is done before types are identified. For this
reason, notations such as <string> and <num> cannot appear in the replacement-string.
• define as computed macros cannot be used in event declarations that use @sim.
• define as computed macros cannot be used in the same file they are defined in. To use a computed
macro in a loaded file, you must also load the file that contains the define as computed statement.
See the next paragraph for the procedure for using computed macros in compiled files.
• When a file needs to be compiled that uses a define as computed macro, first compile the file that
defines the macro. The result of the compilation (the executable that includes the macro definition)
can then be used to compile any file that uses this newly defined syntactic element.
• When preprocessing define as computed macros, Specman might return syntactic blocks in a
compressed notation, with dots as placeholders for substrings. If you need to expand these
placeholders, use the str_expand_dots() routine described in the section on String Routines.
• A define as computed macro takes precedence over a define as macro when the match string satisfies
either one, regardless of the order in which the macro definitions appear in the code. For example,
the command “find least” matches either of the following macros:
define <my_first'command> "find least" as {
action; ...
};

define <my_second'command> "find <any>" as computed {


action; ...
};
However, the second macro, the define as computed macro, will always be the one that is applied
when “find least”, or “find anything”, is executed.
• The maximum number of replacement terms you can us in a replacement string is 14. (For some
replacement term types, this number may be exceeded, but the results of exceeding 14 replacement
terms are unpredictable, so doing so is not recommended.)
• To continue a string over multiple lines, put the line continuation character “\” at the end of each line
except the last.

e Language Reference 19-13


Macros
define as computed

Example
The macro in this example defines a new “add to list” statement. The statement adds a given number to
the list named “num_list” in sys, if the number is not already in the list. (A duplicate keyed list is used to
check whether the number is already in num_list.) If the given number is already in the list, the macro
returns without error.
// def_add_to_list.e module:
<'

extend sys {
!keyed_list: list (key: it) of string;
adder() is empty;
!num_list: list of int (bits: 5);
run() is also {
adder();
print num_list;
};
};

define <num_adder'statement> "add <exp> to list" as computed {


if sys.keyed_list.key_exists(<1>) { return("{}");}
else {
sys.keyed_list.add(<1>);
result = append( "extend sys { adder() is also \
{num_list.add(",<1>,")};}");
};
};

'>

The following is an example of using this macro:

1. Load the “def_add_to_list.e” module.

2. Load a module that contains one or more “add n to list” statements, such as the following:
// use_add_to_list.e module:
<'
add 3 to list;
add 5 to list;
add 7 to list;
add 3 to list;
add 11 to list;
'>

3. Execute the test command.

19-14 e Language Reference


Macros
Debugging e Macros

The list will contain four items.


Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
num_list = (4 items, dec):
11 7 5 3 .0

See Also
• #define on page 20-5
• define as on page 19-1

19.3 Debugging e Macros


To see how macros are expanded by the parser, type the following Specman command at the vrst-tool>
prompt:
vrst-tool> trace reparse

For commands typed at the prompt and for files loaded into Specman, any macro expansion that is done
after you enter the trace reparse command is printed to the screen. For the “swap_var” macro defined
in “Example 5” on page 19-9, the results of “swap x” and of “swap x y” are shown below:
vrst-tool> var x:= 5
vrst-tool> var y:= 9
vrst-tool> var def:= 0
vrst-tool> trace reparse
vrst-tool> swap x
D> <swap_var'action> 'swap x'
D> reparsed as: '{var tmp__124__ := x; x = def;
def = tmp__124__}'
vrst-tool> swap x y
D> <swap_var'action> 'swap x y'
D> reparsed as: '{var tmp__125__ := x;x = y; y = tmp__125__}'

e Language Reference 19-15


Macros
Debugging e Macros

19-16 e Language Reference


20 Preprocessor Directives
This chapter contains the following sections:

• #ifdef, #ifndef on page 20-1. You use these preprocessor directives used to control e processing. The
preprocessor directives check for the existence of a #define for a given name:
• #ifdef directive: if a given name is defined, use the attached code, otherwise, use different code
• #ifndef: if a given name is not defined, use the attached code, otherwise, use different code
The #ifdef and #ifndef directives can be used as statements, struct members, or actions.
• #define on page 20-5, which defines a name macro, also called a replacement macro.
• #undef on page 20-8, which removes the definition of a name macro.
• “Predefined Macros for Specman Version Number” on page 20-10. You can use these macros in e
code or in C code to verify the Specman version you are running.

See Also
• Chapter 19 “Macros”
• Chapter 21 “Importing e Files”
• Chapter 11 “Using the C Interface” in the Usage and Concepts Guide for e Testbenches

20.1 #ifdef, #ifndef

Purpose
Define a preprocessor directive

e Language Reference 20-1


Preprocessor Directives
#ifdef, #ifndef

Category
Statement, struct member, action

Syntax
#if[n]def [`]name then {e-code}
[#else {e-code}]

Syntax Example
#ifdef MEM_LG then {
import mml.e;
};
Note The import statement in the syntax example above must be on a line by itself. The syntax “#ifdef
MEM_LG then {import mml.e};”, where the import statement is part of the #ifdef statement line, will
not work.

Parameters

name Without a backtick, a name defined in a define statement. For information about define,
see Chapter 19 “Macros”.

With a backtick (`name), a name defined with a Verilog `define directive, or in a


Specman define statement where the macro is defined in Verilog style.

e-code e code to be included based on whether the name macro has been defined.

• For an #ifdef or #ifndef statement, only e statements can be used in e-code.


• For an #ifdef or #ifndef struct member, only struct members can be used in e-code.
• For an #ifdef or #ifndef action, only actions can be used in e-code.

Description
The #ifdef and #ifndef preprocessor directives are used together with define name macros to cause the
e parser to process particular code or ignore it, depending on whether a given name macro has been
defined.

• The #ifdef syntax checks whether the name macro has been defined and, if it has, includes the code
following then.
• The #ifndef syntax checks whether the name macro has been defined and if it has not, includes the
code following then.

20-2 e Language Reference


Preprocessor Directives
#ifdef, #ifndef

The optional #else syntax provides an alternative statement when the #ifdef or #ifndef is not true. For
#ifdef, if the name macro has not been defined, the #else code is included. For #ifndef, if the name
macro has been defined, the #else text is included.

Note
Except when it is within an #else block, the #ifdef or #ifndef keyword must be the first keyword on the
line.

Example 1
In this example, #ifdef is used as statements. The module named “t_1.e” contains the statement “define
test_C”. Neither “test_A” nor “test_B” is defined anywhere. Thus, only the “t_4.e” module is imported
by the #ifdef statements.
<'
import t_1.e;// defines test_C;
#ifdef test_A then {
import t_2;
}
#else {
#ifdef test_B then {
import t_3;
};
#ifdef test_C then {
import t_4;
};
};
'>

Example 2
In this example, #ifdef is used as a struct member. The module contains the statement “define test_C”.
Neither “test_A” nor “test_B” is defined anywhere. Thus, only the “keep t_data in [300..399]” constraint
is applied to the generator after the #ifdef statements have been processed.
<'
define test_C;
struct exa_str {
t_data: uint;
#ifdef test_A then {
keep t_data in [100..199];
}
#else {
#ifdef test_B then {
keep t_data in [200..299];

e Language Reference 20-3


Preprocessor Directives
#ifdef, #ifndef

};
#ifdef test_C then {
keep t_data in [300..399];
};
};
};
'>

Example 3
In this example, #ifdef is used as an action. The module contains the statement “define test_C”. Neither
“test_A” nor “test_B” is defined anywhere. Thus, only the “gen t_data keeping it in [300..399]” action
is applied by the #ifdef statements.
<'
define test_C;
struct t_str {
!t_data: int;
t_meth() is {
#ifdef test_A then {
gen t_data keeping {it in [100..199]};
}
#else {
#ifdef test_B then {
gen t_data keeping {it in [200..299]};
};
#ifdef test_C then {
gen t_data keeping {it in [300..399]};
};
};
};
};
'>

Example 4
In this example, #ifdef is used as a command in a .ecom batch file. In the first #ifdef line, the specman()
routine is needed because that is the way to execute a command, config gen in this case, from inside an
action block. In the second #ifdef line, the specman() routine is not needed, since the action block
contains a routine, out(), rather than a command.
// file: test_A.ecom
load test_A
#ifdef TEST_LARGE then {specman("config gen -max_structs = 50000")}
#ifdef TEST_A then {out("This is test_A.")}
test

20-4 e Language Reference


Preprocessor Directives
#define

See Also
• Chapter 19 “Macros”
• Chapter 21 “Importing e Files”

20.2 #define

Purpose
Define a name macro

Category
Statement

Syntax
[#]define [`]name [replacement]

Syntax Example
define PLIST_SIZE 100;

Parameters

name Any e name.

This is used with no replacement parameter for conditional code processing. An


#ifdef preprocessor directive later in the e code that has the name as its argument
evaluates to TRUE. See “#ifdef, #ifndef” on page 20-1 for more information.

When a replacement is given, the parser substitutes the replacement for the macro
name everywhere name appears, except inside strings.

The name can be preceded with a backtick, `. This defines a constant with the
appearance of a Verilog `define name, but it is distinct from the same name without
a backtick.

The name is case sensitive: “LEN” is not the same as “len”.

e Language Reference 20-5


Preprocessor Directives
#define

replacement Any syntactic element, for example, an expression or an HDL variable. This
replaces the name wherever the name appears in the e code that follows the define
statement.

Notes
Be sure to use parentheses around the replacement when they are needed to ensure proper associativity.
For example, the effect of:
define LX 2*len+m;

Is different from the effect of:


define LX 2*(len+m);

In an expression like “lenx = LX”, the first case becomes “lenx = 2*len + m”, while the second case
becomes “lenx = 2*len + 2*m”.

The leading “#” is shown as optional in the syntax, in order to support the define statement syntax from
previous Specman versions, in which the # does not appear.

Description
With a replacement, defines a macro that replaces the name wherever it occurs in the e code. With no
replacement, specifies a name that can be used in #ifdef preprocessor directives for conditional code. A
subsequent evaluation of an #ifdef that has the name as its argument returns TRUE.

Notes
• A #define statement must be on a line by itself. The following is illegal:
#define BIGMEM; import mod1.e; // Illegal syntax
The correct way to write the above is:
#define BIGMEM;
import mod1.e;

• A define statement only applies to e code that is loaded after the define.
• The replacement must not contain the name. A statement like the following causes a runtime error:
define bus_width top.bus_width; // Run-time error
This causes the parser to recursively replace “bus_width” with “top.bus_width”. That is,
“bus_width” would become “top.bus_width”, as desired, but then “top.bus_width” would become
“top.top.bus_width”, and so on.

20-6 e Language Reference


Preprocessor Directives
#define

Example 1
The following are name macro definitions:
#define OFFSET 5;
#define FIRST (OFFSET + 1);
#define SECOND (FIRST + 1);
#define MULTIPLY_I_J i * j;
#define LG_CASE;
#define ‘bus_width 64;
#define bus_width_1 'top.bus_wire';
#define bus_width_2 top.bus_wire;

Example 2
To use a #define macro, refer to the name. Given the definitions above, you could use them as in the
following:
struct example {
test_defines() is {
var i: int;
var j: int;
print OFFSET, FIRST, SECOND; // Prints 5, 6, 7
i = 5;
j = 6;
print MULTIPLY_I_J + 3; // Prints 33 (5 * 6 + 3)
#ifdef LG_CASE then {
i = j * 2;
print i; // Prints 12 (6 * 2)
}
#else {
out(“LG_CASE is not defined”);
};
j = `bus_width * 2;
print j; // Prints 128 (64 * 2)
};
};

See Also
• #undef on page 20-8
• #define on page 20-5
• define as computed on page 19-10

e Language Reference 20-7


Preprocessor Directives
#undef

20.3 #undef

Purpose
Undefine a name macro

Category
Statement

Syntax
undef [`]name

Syntax Example
#undef PLIST_SIZE;

Parameters

name Any e name.

This is used with no replacement parameter for conditional code processing. An


#ifndef preprocessor directive later in the e code that has the name as its argument
evaluates to FALSE, while an #ifndef preprocessor directive later in the e code that
has the name as its argument evaluates to TRUE. See “#ifdef, #ifndef” on page 20-1
for more information.

When a replacement is given, the parser substitutes the replacement for the macro
name everywhere name appears, except inside strings.

The name can be preceded with a backtick, `. This makes the name look like a
Verilog `define name, but it is treated the same as a name without a backtick.

The name is case sensitive: “LEN” is not the same as “len”.

Description
Removes a name macro that was defined using the #define statement. The #undef statement can appear
anywhere in the e code. The name macro is not recognized from the point where the #undef statement
appears onward. The effect is propagated to all files that are loaded after the #undef statement is
encountered.

20-8 e Language Reference


Preprocessor Directives
#undef

Notes
• If the undefined name macro was not previously defined, #undef has no effect – it is not an error.
• A name macro that is undefined in a compiled e module is not accessible to the C interface at any time.
• A name macro that has been undefined can be redefined later, with any value. The last value is
accessible to the C interface.

Example
Say you have two e files, my_design.e and external_code.e, and the following appears in the
my_design.e module:
<'
struct semaphore {
// Contents of the user-defined semaphore struct
};
'>

The following appears in the external_code.e module:


<'
extend sys{
event clk is rise('~/top/clk')@sim;
sem: semaphore; // Uses the built-in Specman semaphore struct
increment()@clk is {
sem.up()
};
};
'>

In the external_code.e file, the built-in Specman struct is used. In order to be able to use the built-in
semaphore struct, you can put the following in a top file, which imports both my_design.e and
external_code.e. This first defines a name macro that replaces “semaphore” with “my_semaphore, and
then, after the my_design.e module is loaded, undefines semaphore so that the built-in semaphore struct
is used from that point on:
<'
#define semaphore my_semaphore;
import my_design.e;
#undef semaphore;
import external_code.e;
'>

e Language Reference 20-9


Preprocessor Directives
Predefined Macros for Specman Version Number

See Also
• #define on page 20-5
• define as on page 19-1
• define as computed on page 19-10

20.4 Predefined Macros for Specman Version


Number
The following predefined macros lets you verify from e or from C which version of Specman you are
running:
SPECMAN_VERSION_n_n[_n]
SPECMAN_VERSION_n_n[_n]_OR_LATER

where n_n[_n] is the version number. The version number will have the same digits that are displayed in
the Specman invocation banner and all “.” characters are replaced by underscores.

These macros are defined in Specman as well as in specman_.h and in any C header file generated by
sn_compile.sh.

20.4.1 SPECMAN_VERSION_n_n_n
For a given release, there is only one SPECMAN_VERSION_n_n[_n]. For example:

• In version 3.3.2, this macro is defined as SPECMAN_VERSION_3_3_2.


• In version 4.0, this macro is defined as SPECMAN_VERSION_4_0.
Use this macro to implement conditional compilation of code based on the Specman version.

Example
<'
#ifdef SPECMAN_VERSION_4_0 then {
import new_code.e;
}
#else {
import old_code.e;
}
'>

You can also execute actions at the Specman prompt, based on the version number. For example:

20-10 e Language Reference


Preprocessor Directives
SPECMAN_VERSION_n_n_n_OR_LATER

Specman> #ifdef SPECMAN_VERSION_4_0 {specman("set back compat 3.3 on")}


Activating backward compatibility mode as version 3.3

20.4.2 SPECMAN_VERSION_n_n_n_OR_LATER
The SPECMAN_VERSION_n_n[_n]_OR_LATER macro is useful for creating reusable verification
components that apply to multiple Specman versions. From a user perspective, such components are
version-independent.

For example, with this define and the appropriate code for each Specman version, the same eVC can be
used with Specman 4.0 and every version thereafter. Even if Specman 4.5 introduces new features or
enhancements that cause the eVC code that worked fine up to version 4.4 to now result in errors, users
of both 4.4 and 4.5 would install the same eVC.

This macro is cumulative. So, with version 4.0.1, the following three defines exist:
SPECMAN_VERSION_4_0_1
SPECMAN_VERSION_4_0_1_OR_LATER
SPECMAN_VERSION_4_0_OR_LATER

Example
// ...
#ifdef SPECMAN_VERSION_4_0_OR_LATER then {
sync consume (@request);
}
#else {
sync cycle @request;
sync consume (@request);
};
// ...

See Also
• #ifdef, #ifndef on page 20-1
• Chapter 11 “Using the C Interface” in the Usage and Concepts Guide for e Testbenches

e Language Reference 20-11


Preprocessor Directives
SPECMAN_VERSION_n_n_n_OR_LATER

20-12 e Language Reference


21 Importing e Files
Imports (import statement, verilog import statement) load a given e file or Verilog file This chapter
describes the import statement.

See Also
• “File Structure” on page 2-2
• verilog import on page 17-7

21.1 import

Purpose
Load other e modules

Category
Statement

Syntax
import file-name, … | ( file-name, … )

Syntax Example
import test_drv.e;

e Language Reference 21-1


Importing e Files
import

Parameters

file-name, … The names of files, separated by commas, that contain e modules to be imported. If
no extension is given for a file name, an “.e” extension is assumed.

The (file-name, …) syntax is for cyclic importing, in which one module references
a field in a second module, and the second module references a field in the first
module.

File names can contain references to environment variables using the UNIX
notation “$name” or “${name}”.

Relative path indicators “./” and “../” can be used in filenames.

Description
Loads additional e modules before continuing to load the current file.

If a specified module has already been loaded or compiled, the statement is ignored. For modules not
already loaded or compiled, the search sequence is:

1. Directories specified by the SPECMAN_PATH environment variable.

2. The current directory.

3. The directory in which the importing module resides.

If you need to refer in struct A to a struct member of struct B, and you also need to refer in struct B to a
struct member of struct A, that is called a cyclic reference. The import statement can handle cyclic
references if you do the following:

1. Before the definition of struct A in module A, add an import of module B in which struct B is
defined.

2. Before the definition of struct B in module B, add an import of module A.

This is called implicit cyclic importing.

Another way to do a cyclic import is to use the import ( file-name, … ) syntax, which resolves cycles by
loading the two or more modules as one.

When multiple modules are loaded together, the behavior is as if the files are concatenated.

No module is imported more than once. If an import statement includes a module that has already been
loaded, that module is not imported.

21-2 e Language Reference


Importing e Files
import

Notes
• Within a given e module, import statements must appear before any other statements except
preprocessor directives (#ifdef, and so on), define statements, verilog import statements and
package statements. (package statements must always precede any other statements.) Any other
type of statement preceding an import statement causes a load-time or compile-time error. See
“Example 6” on page 21-7 for a special case where this restriction also applies to import statements
in different e modules.
• You cannot import modules that reside in different directories but have the same base names, even
if they have different extensions. This is because Specman internally uses only the base name, without
its extension.
• If you do not enter at least one file name after the import keyword, a load or compile-time error is
issued.
• Cyclic importing requires more memory to load multiple modules together than it takes to import
modules singly, and it takes longer, which delays the automatic consistency checking of the e code.
• Cyclic importing can also mask problems with the ability of a module to be used standalone, in future
applications, due to one module relying on another module being loaded.
• Attention must be given to the import order in implicit cyclic importing just as it is in non-cyclic
importing. You cannot reference or extend a struct before it is defined. If module A imports module
B, and if you do load A from the command line or import A from another module, the body of
module B is parsed before module A. However, if you use explicit cyclic importing, import (A, B),
then the body of module A is parsed before module B is imported.

Example 1
The following UNIX commands are executed prior to starting Specman and loading the e module shown
below:
setenv S_PATH /specman/top
cd /cad/test

All of the import statements in the following e module are legal:


import t_fil_1.e;
// Load /cad/test/t_fil_1.e if it exists, otherwise load
// $SPECMAN_PATH/t_fil_1.e
import ./t_fil_2.e;
// Load /cad/test/t_fil_2.e (relative path)
import ../t_fil_3.e;
// Load /cad/t_fil_3.e (relative path)
import /cad/test/t_fil_4.e;
// Load /cad/test/t_fil_4.e (absolute path)
import $S_PATH/t_fil_5.e;

e Language Reference 21-3


Importing e Files
import

// Load /specman/top/t_fil_5.e

Example 2
In the following example, a struct named “pci_transaction” is defined in one module, which is then
imported into another module where additional fields and constraints are added in an extension to the
struct definition.
<'
// module pci_transaction_definition.e
type PCICommandType: [ IO_READ=0x2, IO_WRITE=0x3,
MEM_READ=0x6, MEM_WRITE=0x7 ];
struct pci_transaction {
address: uint;
command: PCICommandType;
bus_id: uint;
};
'>
------------------------------------------------------------
<'
// module pci_transaction_extension.e
import pci_transaction_definition;
extend pci_transaction {
data: list of uint;
num_data_phases: uint;
keep num_data_phases in [0..7];
keep data.size() == num_data_phases;
};
'>

Example 3
In the following example, three modules are involved in cyclic referencing:

• the switch.e module references the packet struct definition in the packet.e module
• the packet.e module references the cell struct definition in the cell.e module
• the cell.e module references the switch struct definition in the switch.e module.
You only need to load the switch.e module into Specman. The switch.e module imports the packet.e
module, which imports the cell.e module. Then the cell.e module imports the switch.e module,
completing the cycle. This is implicit cyclic importing, since each import statement imports only one of
the other modules.
<'
// module switch.e - needs packet.e for the list of packet

21-4 e Language Reference


Importing e Files
import

import packet;
struct switch {
packets: list of packet;
};
'>
------------------------------------------------------------
<'
// module packet.e - needs cell.e for the list of cell
import cell;
struct packet {
!cells: list of cell;
len: uint;
};
'>
------------------------------------------------------------
<'
// module cell.e - needs switch.e for the switch definition
import switch;
struct cell {
parent: switch;
data[20]: list of byte;
};
'>

Example 4
This example shows the explicit cyclic import syntax, import (file-name, …), using the same modules
as “Example 3” on page 21-4. All three of the modules involved in the cyclic referencing are imported by
one import statement in a fourth module named top_imp.e. You only need to load the top_imp.e module
into Specman.
<'
// module top_imp.e
import (switch, packet, cell);
'>
------------------------------------------------------------
<'
// module switch.e - needs packet.e for the list of packet
struct switch {
packets: list of packet;
};
'>
------------------------------------------------------------
<'
// module packet.e - needs cell.e for the list of cell
struct packet {
!cells: list of cell;

e Language Reference 21-5


Importing e Files
import

len: uint;
};
'>
------------------------------------------------------------
<'
// module cell.e - needs switch.e for the switch definition
struct cell {
parent: switch;
data[20]: list of byte;
};
'>

Example 5
This example shows how to load the files in “Example 3” on page 21-4 while avoiding the loss of
modularity that results from cyclic importing.

In Example 3, the cell.e module relies on a type (switch) that is defined in the switch.e module. This
means that a cell struct cannot be used without also using a switch struct, so that cell.e cannot stand
alone.

In this example, the switch struct instance has been moved from the cell.e module to an extension of cell
in the switch.e module, so that the cell.e module does not rely on the presence of the switch.e module.
<'
// module switch.e - needs packet.e for the list of packet
import packet;
struct switch {
packets: list of packet;
};
extend cell {
parent: switch;
};
'>
------------------------------------------------------------
<'
// module packet.e - needs cell.e for the list of cell
import cell;
struct packet {
!cells: list of cell;
len: uint;
};
'>
------------------------------------------------------------
<'
// module cell.e
struct cell {

21-6 e Language Reference


Importing e Files
import

data[20]: list of byte;


};
'>

Example 6
The case of an import followed by an #ifdef which, in turn, imports another module causes a load error
if the second imported module has a statement other than a macro, preprocessor directive, or another
import preceding one of those types of statements. This is a special case which causes a violation of the
statement order rule given in “Statements” on page 2-13. The three e modules below illustrate this.
// module top.e
===============
<'
import defs.e;
#ifdef VENUS then {
import venus.e;
};
'>

// module defs.e
================
<'
type d_type: [A_DR, X_DR]; // At this location, this causes an error
define VENUS;
'>

// module venus.e
=================
<'
extend sys {
event venus_init_done;
};
'>

Trying to load top.e results in this load error. The type statement preceding the #ifdef statement in the
defs.e module is seen as out of order with respect to the import venus.e statement. The error is shown
below:
*** Error: Import Statements should be placed at the top of the file -
please change the statements order, pay attention to the imported module
'venus.e'.
at line 6 in top.e
import venus.e;

This error can be avoided by simply moving the define VENUS statement above the type statement in
the defs.e module:

e Language Reference 21-7


Importing e Files
import

// module defs.e
================
<'
define VENUS;
type d_type: [A_DR, X_DR]; // At this location, no error occurs
'>

See Also
• #define on page 20-5
• #ifdef, #ifndef on page 20-1
• verilog import on page 17-7

21-8 e Language Reference


22 Predefined Methods
A significant part of Specman functionality is implemented as set of predefined methods defined
directly under the global and sys structs.

Furthermore, every struct that is already available to you or is defined by you inherits a set of predefined
methods. Some of these methods can be extended to add functionality, and some of them are empty,
allowing you to define their function.

Three other predefined structs, semaphore, locker, and scheduler, provide predefined methods that are
useful in controlling TCMs and in controlling resource sharing between TCMs. A third predefined
struct, the simulator struct, has a predefined method that allows access to Verilog macros during a run.

Finally, there are pseudo-methods. Calls to pseudo-methods look like method calls. However, they are
associated not with struct expressions, but with other kinds of expressions.

The following sections describe the predefined methods:

• “Global Methods” on page 22-2


• “Methods of sys” on page 22-8
• “Methods of Any Struct” on page 22-18
• “Pseudo-Methods” on page 22-44
• “Simulation-Related Methods” on page 22-52
• “Semaphore Methods” on page 22-54
• “TCM Related Methods” on page 22-69
• “Coverage Methods” on page 22-81
• “Time Conversion Methods” on page 22-99

e Language Reference 22-1


Predefined Methods
Global Methods

See Also
• Chapter 23 “List Pseudo-Methods”
• “File Routines” on page 24-91
• Chapter 24 “Predefined Routines”

22.1 Global Methods


Predefined global methods can be called from anywhere without the need to create any struct instances.
The global methods are described in this section:

• “Test Phase Methods” on page 22-2


• Global Method setup_test() on page 22-4
• Global Method generate_test() on page 22-5
• Global Method start_test() on page 22-5
• Global Method run_test() on page 22-6
• Global Method extract_test() on page 22-6
• Global Method check_test() on page 22-7
• Global Method finalize_test() on page 22-8
Note It is not recommended to extend the predefined methods of global. Instead, you can extend a
related method of the sys struct or of any struct.

22.1.1 Test Phase Methods


Most of the methods of the global struct control the execution of the phases of a test run, including
setting up the test and test data, executing the test, checking the test results, and finalizing the test data.
These methods are invoked when you enter the test command or any of the other test phase commands,
such as setup, generate, run, and check. In turn these methods invoke related test-phase predefined
methods of sys and of any struct or unit.

The test phases and the predefined methods associated with each phase are shown in Figure 22-1 on
page 22-3. The following sections describe the test phase methods in detail.

22-2 e Language Reference


Predefined Methods
Test Phase Methods

Figure 22-1 Test Phases and Predefined Methods

load phase
sys.init()

test phase - global.do_test()

start phase - global.start_test()

generate phase - global.generate_test()

setup phase - global.setup_test()

sys.wave_setup()

struct.init()
sys.setup()
struct.pre_generate()

sys.generate() struct.post_generate()

Start test

run phase -
global.run_test() sys.run() struct.run()

struct.init()
Start simulation on-the-fly
Run TCM’s generation struct.pre_generate()
struct.post_generate()

stop_run() struct.quit()

check phase -
global.extract_test() sys.extract() struct.extract()
global.check_test()
sys.check() struct.check()

finalize phase -
global.finalize_test() sys.finalize()

e Language Reference 22-3


Predefined Methods
Global Method setup_test()

The following sections describe the function of each global method in more detail:

• Global Method setup_test() on page 22-4


• Global Method generate_test() on page 22-5
• Global Method start_test() on page 22-5
• Global Method run_test() on page 22-6
• Global Method extract_test() on page 22-6
• Global Method check_test() on page 22-7
• Global Method finalize_test() on page 22-8

22.1.2 Global Method setup_test()

Function
Initializes test parameters, such as the initial seed for random generation.

This method is called automatically when you issue a test, start, generate or setup command from the
Specman command line. In turn, it invokes sys.wave_setup() and sys.setup().

Suggested Use
It is not recommended to extend setup_test(). If you need to perform a task before generation is run, you
can extend sys.wave_setup() or sys.setup().

See Also
• “Global Methods” on page 22-2
• The setup() Method of sys on page 22-12
• The wave_setup() Method of sys on page 22-11

22-4 e Language Reference


Predefined Methods
Global Method generate_test()

22.1.3 Global Method generate_test()

Function
Performs pre-run generation by calling sys.generate() and the following predefined methods of every
struct under sys:

1. struct.init()

2. struct.pre_generate()

3. struct.post_generate()

This method is called when you issue a test, start, or generate command from the Specman command
line.

Suggested Use
You should not extend or modify the generate_test() or the sys.generate() method. Instead, you can
modify or extend the init(), pre_generate(), or post_generate() method of a particular struct to perform
initialization or to setup or finalize generation.

See Also
• “Global Methods” on page 22-2
• The init() Method of any_struct on page 22-27
• pre_generate() on page 11-59
• post_generate() on page 11-60

22.1.4 Global Method start_test()

Function
Prepares Specman to start the simulation run.

This method is called when you issue a test or start command from the Specman command line.

e Language Reference 22-5


Predefined Methods
Global Method run_test()

Suggested Use
You should not extend or modify the start_test() method. Instead, you can extend the post_generate()
method of a particular struct if you need to perform some task after generation and before starting the
run.

See Also
• “Global Methods” on page 22-2
• post_generate() on page 11-60

22.1.5 Global Method run_test()

Function
Executes sys.run() and for every struct under sys in depth-first search order, executes the struct’s run()
method.

This method is called when you issue a test or run command from the Specman command line.

Suggested Use
You should not extend or modify the run_test() method. Instead, you can modify or extend sys.run() or
the run() method of a particular struct to start any TCM that you want to begin execution when
simulation starts.

See Also
• “Global Methods” on page 22-2
• The run() Method of sys on page 22-13
• The run() Method of any_struct on page 22-39

22.1.6 Global Method extract_test()

Function
Collects data from the DUT before the post-run checking is performed.

This method is called when you issue a test or check command from the Specman command line. It is
also called under the following conditions:

22-6 e Language Reference


Predefined Methods
Global Method check_test()

• When a run is stopped by a call to stop_run()


• When a run is stopped by a simulator exit command
• When a DUT error occurs and the check effect is ERROR_AUTOMATIC

Suggested Use
You should not extend or modify the extract_test() method. Instead, you can modify or extend
sys.extract() or the extract() method of a particular struct to perform any tasks you want completed
before checking is performed.

See Also
• “Global Methods” on page 22-2
• The extract() Method of sys on page 22-15
• The extract() Method of any_struct on page 22-24

22.1.7 Global Method check_test()

Function
Runs check() for every struct under sys.

This method is called when you issue a test or check command from the Specman command line. It is
also called under the following conditions:

• When a run is stopped by a call to stop_run()


• When a run is stopped by a simulator exit command
• When a DUT error occurs and the check effect is ERROR_AUTOMATIC

Suggested Use
Do not extend or modify the check_test() method. Instead, you can extend the check() method of a
particular struct, or to perform checking of global data, you can extend the sys.check() method.

See Also
• “Global Methods” on page 22-2
• The check() Method of sys on page 22-16

e Language Reference 22-7


Predefined Methods
Global Method finalize_test()

• The check() Method of any_struct on page 22-19

22.1.8 Global Method finalize_test()

Function
Finalizes the test data, including the emitting of the session.end_of_test event and the writing of
coverage information.

Suggested Use
Do not extend or modify the finalize_test() method. Instead, you can extend sys.finalize() or the
finalize() method of a particular struct to perform any tasks you want completed after checking has been
performed.

This method is called when you issue a test or finalize command from the Specman command line. It is
also called under the following conditions:

• When a run is stopped by a call to stop_run()


• When a run is stopped by a simulator exit command
• When a DUT error occurs and the check effect is ERROR_AUTOMATIC

See Also
• “Global Methods” on page 22-2
• The finalize() Method of sys on page 22-17
• The finalize() Method of any_struct on page 22-26

22.2 Methods of sys


This section contains descriptions of the extendable methods of sys:

• The init() Method of sys on page 22-9


• The wave_setup() Method of sys on page 22-11
• The setup() Method of sys on page 22-12
• The run() Method of sys on page 22-13
• The extract() Method of sys on page 22-15

22-8 e Language Reference


Predefined Methods
The init() Method of sys

• The check() Method of sys on page 22-16


• The finalize() Method of sys on page 22-17
It is not recommended to extend sys.generate(). Instead, you should extend the related pre_generate()
or post_generate() method of a particular struct or unit. See “Methods of Any Struct” on page 22-18 for
more information on these methods.

22.2.1 The init() Method of sys

Purpose
Perform general preparations for the test

Category
Predefined method for sys

Syntax
[sys.]init()

Syntax Example
extend sys {
init() is also {
out("Performing initialization of sys...");
};
};

Description
This method is called when you load an e file with the load command or when you invoke an extended
Specman executable that contains compiled e code.

It is not invoked when you restore an environment from a save file.

You can extend this method to perform general preparations for the test.

Example
This example illustrates when sys.init() is called from compiled e code.
extend sys {

e Language Reference 22-9


Predefined Methods
The init() Method of sys

init() is also {
out("This is sys.init()...");
};
};

Results
bash$ sn_compile.sh top.e
# sn_compile.sh: reading specman ini file - $SPECMAN_HOME/system.specman
#------------------------------------------------------------
# Welcome to sn_compile.sh (version: 3.3b3.0)
# sn_compile.sh: executing with args:
# sn_compile.sh top.e
#------------------------------------------------------------
#------------------------------------------------------------
# Translating using
/export/home/opt/specman33/sn_rel3.3b3.0/solaris/specman
#------------------------------------------------------------
#
# Compiling the following files:
# ------------------------------
# top.e
#
Welcome to Specman (3.3b3.0) - Linked on Mon Aug 21 13:06:31 2000

Checking license ... OK


Translating top.e ...
read...parse...update...patch...h code...code...clean...save...
Translation complete

#------------------------------------------------------------
# Compiling C modules using gcc
#------------------------------------------------------------
#------------------------------------------------------------
# Compiling Specman main
#------------------------------------------------------------
#------------------------------------------------------------
# Linking 'top' using gcc
#------------------------------------------------------------
# ./top is ready.

bash$ top
Welcome to Specman top (3.3) - Linked on Fri Sep 8 2000

This is sys.init()...
Checking license ... OK

22-10 e Language Reference


Predefined Methods
The wave_setup() Method of sys

Specman top>

See Also
• The init() Method of any_struct on page 22-27
• generate on page 11-5 in the Specman Command Reference

22.2.2 The wave_setup() Method of sys

Purpose
Initialize waveform viewer parameters

Category
Predefined method for sys

Syntax
[sys.]wave_setup()

Syntax Example
wave_setup() is also {
set_config(wave, working_mode, off_line);
};

Description
When you issue a test, start, generate or setup command from the Specman command line, the
global.setup_test() method is called. This method in turn calls sys.wave_setup() method. (See Figure
22-1 on page 22-3 for more information on test phases.)

You can extend this method by adding calls to the set_config() method to initialize waveform viewer
configuration parameters. This method is initially empty and is meant to be extended. It is automatically
called before the stubs file is generated, and is therefore the place to set configuration options that affect
the stubs file.

e Language Reference 22-11


Predefined Methods
The setup() Method of sys

Example
If you are using the MTI waveform viewer and want to use short buffers for errors and messages, in
order to be able to see the messages, you can use wave_setup() to set the buffer lengths as shown in the
following example.
extend sys {
wave_setup() is also {
var buffer_size := 12;
set_config(wave, stub_message_len, buffer_size);
set_config(wave, stub_strings_len, buffer_size);
};
};

See Also
• configure wave on page 6-58 in the Specman Command Reference
• Chapter 10 “Using a Waveform Viewer” in the Specman Elite Integrator’s Guide
• setup on page 11-7 in the Specman Command Reference

22.2.3 The setup() Method of sys

Purpose
Initialize test parameters

Category
Predefined method for sys

Syntax
[sys.]setup()

Syntax Example
setup() is also {
set_config_max(memory, gc_threshold, 100m);
};

22-12 e Language Reference


Predefined Methods
The run() Method of sys

Description
When you issue a test, start, generate or setup command from the Specman command line, the
global.setup_test() method is called. This method in turn calls the sys.setup() method to initialize test
parameters, such as the initial seed for random generation, in preparation for running a test. (See Figure
22-1 on page 22-3 for more information on test phases.)

You can extend this method to set configuration options. See “Configuring the Run” on page 7-4 in the
Specman Elite Integrator’s Guide for more information.

Example
extend sys {
setup() is also {
set_config_max(memory, gc_threshold, 100m);
};
};

See Also
• set_config_max() on page 5-37
• setup on page 11-7 in the Specman Command Reference

22.2.4 The run() Method of sys

Purpose
Recommended place for starting TCMs

Category
Predefined method for sys

Syntax
[sys.]run()

Syntax Example
run() is also {
start monitor();
};

e Language Reference 22-13


Predefined Methods
The run() Method of sys

Description
Can be extended to start user-defined TCMs. The method is initially empty.

The run() methods of all structs under sys are called, starting from sys in depth-first search order, by the
global.run_test() method when you execute a test or a run command.

After this initial pass, when any struct is generated (with the gen action) or allocated (with new), its
run() method is also invoked. This ensures that:

• The run() method of each struct instance is called exactly once, thus avoiding multiple instances of
the same started TCM;
• TCMs do not start and events do not occur before Specman is ready to accept them;
• The run() method is called after generation and uses the generated values.
If you run multiple tests in the same session, the run() method is called once for each test in the session.
The init() method is called only once before the first test.

Note
Starting a TCM before the end of start_test() causes a runtime error.

Example
<'
extend sys {
id : int;
monitor() @sys.any is {
while (TRUE) {
wait [2] * cycle;
out("cycle ", sys.time,
" Packet id ", id, " is still running");
};
};

run() is also {
start monitor();
};
};
'>

See Also
• The run() Method of any_struct on page 22-39

22-14 e Language Reference


Predefined Methods
The extract() Method of sys

• start tcm() on page 7-25


• run on page 11-6 in the Specman Command Reference

22.2.5 The extract() Method of sys

Purpose
Extract test data

Category
Predefined method for sys

Syntax
[sys.]extract()

Syntax Example
extend sys {
extract() is also {
me.flag = 'top.overflow';
print me.flag;
};
};

Description
This method is called before the post-run checking is performed when you issue a check or finalize
command from the Specman command line. (See Figure 22-1 on page 22-3 for more information on test
phases.)

You can extend this method to extract data from the DUT before checking the test results.

Example
extend sys {
extract() is also {
me.flag = 'top.overflow';
print me.flag;
};
};

e Language Reference 22-15


Predefined Methods
The check() Method of sys

See Also
• The extract() Method of any_struct on page 22-24
• extract on page 11-3 in the Specman Command Reference

22.2.6 The check() Method of sys

Purpose
Perform DUT checks

Category
Predefined method for sys

Syntax
[sys.]check()

Syntax Example
check() is also {
check that pending == 0
else dut_error("Still have ", pending, " test(s) to do");
};

Description
This method is called to perform the post-run checking when you issue a check or finalize command
from the Specman command line. (See Figure 22-1 on page 22-3 for more information on test phases.)

You can extend this method to perform post-test checks.

Example
extend sys {
!pending: uint;
more_tests() is {pending += 1;};
fewer_tests() is {pending -= 1;};
check() is also {
check that pending == 0
else dut_error("Still have ", pending, " test(s) to do");
};

22-16 e Language Reference


Predefined Methods
The finalize() Method of sys

};

See Also
• The check() Method of any_struct on page 22-19
• check on page 11-2 in the Specman Command Reference

22.2.7 The finalize() Method of sys

Purpose
Finalize test data

Category
Predefined method for sys

Syntax
[sys.]finalize()

Syntax Example
extend sys {
finalize() is also {
specman("show cover XYZ_router.log");
};
};

Description
This method is called when you issue a test or finalize command from the Specman command line. It is
called after checking has been performed but before coverage data is written to a file. (See Figure 22-1
on page 22-3 for more information on test phases.)

You can extend this method to display or manipulate test data.

Example
extend sys {
finalize() is also {
specman("show cover XYZ_router.log");

e Language Reference 22-17


Predefined Methods
Methods of Any Struct

};
};

See Also
• The finalize() Method of any_struct on page 22-26
• finalize on page 11-4 in the Specman Command Reference

22.3 Methods of Any Struct


Specman has a predefined struct, any_struct, which in turn has many predefined methods. Some of
these predefined methods, such as init() and run(), are invoked automatically when you execute the test
command. Other predefined methods, such as copy() or do_print(), manipulate data within the struct.

All user-defined structs inherit from any_struct, so all its predefined methods are available to any struct
you define. The predefined methods of any_struct are also available for any user-defined unit.

The following sections describe the predefined methods that are invoked automatically when you
execute the test command. (See Figure 22-1 on page 22-3 for more information on test phases,
commands, and related methods.)

• The check() Method of any_struct on page 22-19


• The extract() Method of any_struct on page 22-24
• The finalize() Method of any_struct on page 22-26
• The init() Method of any_struct on page 22-27
• pre_generate() on page 11-59
• post_generate() on page 11-60
• The visualize() Method of any_struct on page 22-32
• The quit() Method of any_struct on page 22-36
• The run() Method of any_struct on page 22-39
The following section describe the predefined method that you can use to kill the threads for a struct and
then start it running again:

• The rerun() Method of any_struct on page 22-40


The following sections describe the predefined methods that manipulate data within the struct:

• The copy() Method of any_struct on page 22-20

22-18 e Language Reference


Predefined Methods
The check() Method of any_struct

• The do_print() Method of any_struct on page 22-22


• The print_line() Method of any_struct on page 22-30
• do_pack() on page 18-38
• do_unpack() on page 18-42
• The print_line() Method of any_struct on page 22-30

22.3.1 The check() Method of any_struct

Purpose
Check for DUT errors

Category
Predefined method of any struct or unit

Syntax
[exp.]check()

Syntax Example
check() is also {
check that pending == 0
else dut_error("Still have ", pending, " test(s) to do");
};

Parameters

exp An expression that returns a unit or a struct.

Description
This is an empty method that you can extend for performing post-test checks.

This method is called by global.check_test() when you issue a test or check command from the
Specman command line.

e Language Reference 22-19


Predefined Methods
The copy() Method of any_struct

Example
struct track_pending {
!pending: uint;
more_tests() is {pending += 1;};
fewer_tests() is {pending -= 1;};

check() is also {
check that pending == 0
else dut_error("Still have ", pending, " test(s) to do");
};
};

See Also
• The check() Method of sys on page 22-16
• check that on page 10-2
• check on page 11-2 in the Specman Command Reference

22.3.2 The copy() Method of any_struct

Purpose
Make a shallow copy

Category
Predefined method of any struct or unit

Syntax
exp.copy(): exp

Syntax Example
var pmv: packet = sys.pmi.copy();

Parameters

exp Any legal e expression.

22-20 e Language Reference


Predefined Methods
The copy() Method of any_struct

Description
Returns a shallow, non-recursive copy of the expression. This means that if the expression is a list or a
struct that contains other lists or structs, the second-level items are not duplicated. Instead, they are
copied by reference.

The following list details how the copy is made, depending on the type of the expression:

scalar The scalar value is simply assigned as in a normal assignment.


string The whole string is copied.
scalar list If exp is a scalar list, a new list with the same size as the original list is allocated.
The contents of the original list is duplicated.
list of structs A new list with the same size as the original list is allocated. The contents of the list
is copied by reference, meaning that each item in the new list points to the
corresponding item in the original list.
struct If exp is a struct instance, a new struct instance with the same type as the original
struct is allocated. All scalar fields are duplicated. All compound fields (lists or
structs) in the new struct instance point to the corresponding fields in the original
struct.

Notes
• Do not use the assignment operator (=) to copy structs or lists into other data objects. The assignment
operator simply manipulates pointers to the data being assigned and does not create new struct
instances or lists.
• Use the deep_copy() method if you want a recursive copy of a struct or list that contains compound
fields or items.

Example
<'
struct packet {
header: header;
data[10] :list of byte;
type: [ATM, ETH, IEEE];
};

struct header {
code: uint;
};

extend sys {
pmi: packet;

e Language Reference 22-21


Predefined Methods
The do_print() Method of any_struct

m() is {
var pmv: packet = sys.pmi.copy();
pmv.data[0] = 0xff;
pmv.header.code = 0xaa;
pmv.type = IEEE;
print pmi.data[0], pmi.header.code, pmi.type;
print pmv.data[0], pmv.header.code, pmv.type;
};
};
'>

Result
This example shows that any changes in value to lists and structs contained in the copied struct instance
(“pmv”) are reflected in the original struct instance (“pmi”) because these items are copied by reference.
vrst-tool> sys.m()
pmi.data[0] = 0xff
pmi.header.code = 0xaa
pmi.type = ATM
pmv.data[0] = 0xff
pmv.header.code = 0xaa
pmv.type = IEEE

See Also
• deep_copy() on page 24-2

22.3.3 The do_print() Method of any_struct

Purpose
Print struct info

Category
Predefined method of any struct or unit

Syntax
[exp.]do_print()

22-22 e Language Reference


Predefined Methods
The do_print() Method of any_struct

Syntax Example
do_print() is first {
outf("Struct %s :", me.s);
};

Parameters

exp An expression that returns a unit or a struct.

Description
Controls the printing of information about a particular struct. You can extend this method to customize
the way information is displayed.

This method is called by the print action whenever you print the struct.

Example
<'
struct a {
i: int;
s: string;
do_print() is first {
outf("Struct %s :", me.s);
};
};
extend sys {
m() is {
var aa := a new a with {
.i = 1;
.s = "AA";
};
print aa;
};
};
'>

Result
vrst-tool> sys.m()
aa = Struct AA :a-@0: a
----------------------------------------------
@predefined_methods5
0 i: 0x1

e Language Reference 22-23


Predefined Methods
The extract() Method of any_struct

1 s: "AA"

See Also
• print on page 9-2 in the Specman Command Reference

22.3.4 The extract() Method of any_struct

Purpose
Extract DUT information

Category
Predefined method of any struct or unit

Syntax
[exp.]extract()

Syntax Example
extract() is also {
me.flag = 'top.overflow';
print me.flag;
};

Parameters

exp An expression that returns a unit or a struct.

Description
This method is called before the post-run checking is performed when you issue a check or finalize
command from the Specman command line. (See Figure 22-1 on page 22-3 for more information on test
phases.)

The method is initially empty. You can extend this method to extract data from the DUT before checking
the test results.

This method is called automatically by the global.extract_test() method.

22-24 e Language Reference


Predefined Methods
The extract() Method of any_struct

Example
<'
struct packet {
header: header;
data[10] :list of byte;
type: [ATM, ETH, IEEE];
flag: bit;

extract() is also {
me.flag = 'top.overflow';
print me.flag;
};
};

struct header {
code: uint;
};

extend sys {
pmi: packet;
};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 0x1...
Starting the test ...
Running the test ...
No actual running requested.
Checking the test ...
me.flag = 0x1
Checking is complete - 0 DUT errors, 0 DUT warnings.

See Also
• The extract() Method of sys on page 22-15
• extract on page 11-3 in the Specman Command Reference

e Language Reference 22-25


Predefined Methods
The finalize() Method of any_struct

22.3.5 The finalize() Method of any_struct

Purpose
Finalize test data

Category
Predefined method for any struct or unit

Syntax
[exp.]finalize()

Syntax Example
finalize() is also {
specman("show cover XYZ_router.log");
};

Parameters

exp An expression that returns a unit or a struct.

Description
The global.finalize_test() method calls the finalize() method of each struct or unit as part of the
post-checking activities, which include writing coverage information. You can also call this method
from the command line with the finalize command.

You can extend the finalize() method of a unit or struct to display or manipulate data.

Example
<'
extend XYZ_router {
finalize() is also {
specman("show cover XYZ_router.log");
};
};
'>

22-26 e Language Reference


Predefined Methods
The init() Method of any_struct

Results
vrst-tool> test
Doing setup ...
10 checks were modified.
Generating the test using seed 1...
Starting the test ...
Running the test ...
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

Specman Coverage report


=======================

Command: show cover -kind = full XYZ_router.log.*


Grading_formula: linear
At least multiplier: 1
Show mode: both
Number of tests: 1
Note: %t is a percent from total, %p is a percent
from parent

Cover group: XYZ_router.log


===========================
"End of package transaction"
....

See Also
• finalize on page 11-4 in the Specman Command Reference
• The finalize() Method of sys on page 22-17

22.3.6 The init() Method of any_struct

Purpose
Initialize struct

Category
Predefined method of any struct or unit

e Language Reference 22-27


Predefined Methods
The init() Method of any_struct

Syntax
[exp.]init()

Syntax Example
init() is also {
is_ok = TRUE;
list_subs = {320; 330; 340; 350; 360};
list_color = {black; red; green; blue; yellow; white};
};

Parameters

exp An expression that returns a unit or a struct.

Description
The init() method of a struct is called when you create a new instance with a test, start or generate
command (pre-run generation) or with a new, gen or unpack() action (on-the-fly generation). (See
Figure 22-1 on page 22-3 for more information on test phases.)

You can extend the init() method of a struct to set values for fields that you want to have a different
value than the default value. By default, all fields of scalar type are initialized to zero. The initial value
of a struct or list is NULL, unless the list is a sized list of scalars, in which case it is initialized to the
proper size with each item set to the default value.

You should consider initializing the non-generated fields of a struct, especially fields of an enumerated
scalar type or unsized lists. Enumerated scalar types are initialized to zero, even if that is not a legal
value for that type. If the field is sampled before it is assigned, you should initialize it. As for lists, if you
intend to fill a list with data from the DUT, you should either size the list or initialize it. Unpacking data
from the DUT into an unsized, uninitialized list causes a runtime error.

If a field is initialized but not marked as non-generated, the initialization is overwritten during
generation. To mark a field as non-generated, place a ! character in front of the field name.

Example
<'
type color: [black, red, green, blue, yellow, white];
type sub_rang1: int [300..500];
struct pm {
!list_color: list of color;
!list_subs: list of sub_rang1;
!is_ok:bool;

22-28 e Language Reference


Predefined Methods
The init() Method of any_struct

init() is also {
is_ok = TRUE;
list_subs = {320; 330; 340; 350; 360};
list_color = {black; red; green; blue; yellow; white};
};
};

extend sys {
pmi:pm;
};
'>

Result
vrst-tool> print sys.pmi.list_color, sys.pmi.list_subs,
sys.pmi.is_ok
sys.pmi.list_color =
0. black
1. red
2. green
3. blue
4. yellow
5. white
sys.pmi.list_subs =
0. 320
1. 330
2. 340
3. 350
4. 360
sys.pmi.is_ok = TRUE

See Also
• The init() Method of sys on page 22-9
• generate on page 11-5 in the Specman Command Reference
• “Packing and Unpacking Lists” on page 18-9
• “e Data Types” on page 3-1
• {… ; …} on page 2-77

e Language Reference 22-29


Predefined Methods
The print_line() Method of any_struct

22.3.7 The print_line() Method of any_struct

Purpose
Print a struct or a unit in a single line

Category
Predefined method of any struct or unit

Syntax
[exp.]print_line(NULL | struct-type.type())

Syntax Example
sys.pmi[0].print_line(sys.pmi[0].type());
sys.pmi[0].print_line(NULL);

Parameters

exp An expression that returns a struct or a unit.

NULL | To print a row representation of the struct or unit, the parameter is NULL.To
struct-type.type() print the header for the list, the parameter is of the form:
struct-type.type()

Description
You can call this method to print lists of structs of a common struct type in a tabulated table format. Each
struct in the list is printed in a single line of the table.

When printing the structs, there is a limit on the number of fields printed in each line. The first fields that
fit into a single line are printed; the rest are not printed at all. Each field is printed in a separate column,
and there is a limitation on the column width. When a field exceeds this width, it is truncated and an
asterisk is placed as the last character of that field’s value.

Example
<'
struct packet {
protocol: [eth, ieee, atm];
size: int [0..1k];

22-30 e Language Reference


Predefined Methods
The print_line() Method of any_struct

data[size]: list of byte;


};

extend eth packet {


e: int;
};

extend ieee packet {


i: int;
};
extend atm packet {
a: int;
};

extend sys {
pmi[5]: list of packet;

m() is {
sys.pmi[0].print_line(sys.pmi[0].type());
sys.pmi[0].print_line(NULL);
sys.pmi[1].print_line(NULL);
sys.pmi[2].print_line(NULL);
sys.pmi[3].print_line(NULL);
sys.pmi[4].print_line(NULL);
};
};
'>

Result
vrst-tool> sys.m()
item type protocol size data eth'e ieee'i
packet eth 872 (872 item* -481087693
packet eth 830 (830 item* 2019716495
packet eth 834 (834 item* -20064418*
packet ieee 663 (663 item* 1557645288
packet eth 213 (213 item* 1797949675

See Also
• print on page 9-2 in the Specman Command Reference

e Language Reference 22-31


Predefined Methods
The visualize() Method of any_struct

22.3.8 The visualize() Method of any_struct

Purpose
Show struct information graphically

Category
Predefined method of any struct or unit

Syntax
[exp.]visualize()

Syntax Example
visualize() is {
var page := new MY_PAGE vt_page with {
.set_window_kind(MY_WINDOW);
.set_html_body(my_vt_method());
};
};

Parameters

exp An expression that returns a struct or a unit.

Description
You can call this method to display a graphical representation of struct information, which you have
created using the Visualization Toolkit (VT) capabilities of Specman.The visualize() method is initially
empty, and you can extend it as desired by adding VT constructs to it.

The Visualization Toolkit provides a large set of constructs that you can use to create visual
representations of your design, which may include menus, toolbars, hyperlinks, and other HTML
features, for example. The visualize() method invokes your VT display in the context of the current
struct or unit.

Complete information about the VT constructs and usage is contained in “Using the Visualization Toolkit”
and “Visualization Toolkit Method Reference” on page 2-58 in the Specman Beta Features.

22-32 e Language Reference


Predefined Methods
The visualize() Method of any_struct

Example
The following example shows how the visualize() method can be used to invoke Visualization Toolkit
methods that create and open a simple HTML window. The features of the HTML window are defined
in the VT code in the vis_example.e module. The call to the visualize() method is in the visualize.e
module.

In this example, the HTML window opens automatically at the end of the test, due to the page.show()
call in the visualize() method extension.

For details about how to use all of the VT constructs, see “Using the Visualization Toolkit” in the Specman
Beta Features.
<’
import (vis_example.e, visualize.e);
’>

// visualize.e:
<’
struct instruction_s {
alu: [ALU_0, ALU_1, ALU_2, ALU_3, ALU_4];
opcode: [ADD, SUB, AND, XOR];
operand1 : byte;
operand2 : byte;
};
extend sys {
instructions_l: list of instruction_s;
visualize() is {
var page:= new INSTR_LIST_PAGE vt_page with {
.set_window_kind(INSTR_VIEWER_WINDOW);
.set_html_body(instruction_viewer_s.create_instructions_\
list_html_body());
.set_title(append("List of Instructions"));
};
page.show();
};
run() is also {
visualize();
};
};
’>

// vis_example.e:
<’
extend vt_page_kind: [INSTR_LIST_PAGE, INSTR_DETAILS_PAGE];
extend vt_window_kind: [INSTR_VIEWER_WINDOW];
extend INSTR_VIEWER_WINDOW vt_window {

e Language Reference 22-33


Predefined Methods
The visualize() Method of any_struct

configure() is also {
set_size(600, 500);
add_menu("Instructions");
set_symbol_value("app", "sys.instruction_viewer_s");
set_title_prefix("Instruction Viewer");
};
};
struct instruction_viewer_s {
create_instructions_list_html_body(): list of string is {
result.add(appendf("List of instructions contains %s
instructions:", str_dec(sys.instructions_l.size())));
result.add(vt.HTML_NEWLINE);
if (sys.instructions_l.is_empty()) {
return result;
};
var line: string;
var instr_name: string;
var cmd: string;
var instr_link: string;
for each (instr) in sys.instructions_l {
instr_name = vt.instance_to_string(instr);
instr_link = vt.lnk_instance(instr, instr_name);
cmd = appendf("%%app.show_instruction_details(%s)",
instr_name);
line = appendf("%s %s %s", vt.btn_command(cmd, "Show Details"),
instr.opcode.as_a(string), instr_link);
result.add(line);
result.add(vt.HTML_NEWLINE);
};
};
create_instruction_details_html_body(instr: instruction_s):
list of string is {
result.add(append("Instruction details: ", instr));
result.add("");
if (instr == NULL) {
return result;
};
var instr_name: string = vt.instance_to_string(instr);
var instr_link: string = vt.lnk_instance(instr, instr_name);
result.add(append("Name: ", instr_link));
result.add(append("ALU: ", instr.alu));
result.add(append("Opcode: ", instr.opcode));
result.add(append("Operand1: ", instr.operand1));
result.add(append("Operand2: ", instr.operand2));
};
show_instruction_details(instr: instruction_s) is {
var page:= new INSTR_DETAILS_PAGE vt_page with {

22-34 e Language Reference


Predefined Methods
The visualize() Method of any_struct

.set_window_kind(INSTR_VIEWER_WINDOW);
.set_html_body(sys.instruction_viewer_s.create_instruction_\
details_html_body(instr));
.set_title(append("Instruction Details - ", instr));
};
page.show();
};
};
extend sys {
!instruction_viewer_s;
init() is also {
instruction_viewer_s = new instruction_viewer_s;
};
};
’>

Result
The window created by the preceding sample code is shown below. Clicking any of the Show Details
buttons in the window switches the window contents to the details about the values of the fields in the
instruction_s struct instance. Clicking any of the hyperlinks in the window opens the Data Browser on
that instance. Those features of the window are all defined in the sample VT code above.

e Language Reference 22-35


Predefined Methods
The quit() Method of any_struct

See Also
• “Using the Visualization Toolkit” in the Specman Beta Features
• “Opening Visualization Toolkit Windows” on page 3-19 in the Specman Beta Features
• The auto_visualize parameter in configure databrowser on page 6-11 in the Specman Command
Reference

22.3.9 The quit() Method of any_struct

Purpose
Kill all threads of a struct or unit instance

Category
Predefined method of any struct or unit

Syntax
[exp.]quit()

Syntax Example
packet.quit();

Parameters

exp An expression that returns a unit or a struct.

Description
Deactivates a struct instance, killing all threads associated with the struct and enabling garbage
collection. The quit() method emits a quit event for that struct instance at the end of the current tick. At
the end of the current tick, the quit() method kills any TCM threads that were started within the struct in
which the quit() method is called. All attached events and expect members of the struct that are still
running are also killed.

A thread is any started TCM. If a started TCM calls other TCMs, those TCMs are considered subthreads
of the started TCM thread, and the quit() method kills those subthreads, too.

22-36 e Language Reference


Predefined Methods
The quit() Method of any_struct

If a struct has more than one started TCM, each TCM runs on a separate, parallel thread. Each thread
shares a unique identifier, or thread handle, with its subthreads. The thread handle is automatically
assigned by the scheduler. You can access threads using the predefined methods of the scheduler.

The quit() method is called by the global.stop_run() method. You can also call it explicitly.

Example
This example shows the quit() method used in conjunction with the stop_run() routine to stop a run
cleanly. When a “packet” struct is generated by the “inject_packets()” method, its TCM “monitor()” is
also started. The TCM monitor checks the status of the “inject_packets()” method. Four cycles after the
“packet” is generated, it is killed by the quit() method. After all packet have been generated and killed,
the stop_run() method is called to stop the simulator.
<'
extend sys {
inject_packets() @sys.any is {
var packet : packet;
for i from 0 to 5 {
wait [1] * cycle;
gen packet;
out("\nInject packet id ", packet.id);
wait [4] * cycle;
packet.quit();
};
stop_run();
};

run() is also {
start inject_packets();
};
};

struct packet {
id : int;
monitor() @sys.any is {
while (TRUE) {
wait [2] * cycle;
out("cycle ", sys.time, " Packet id ", id,
" is still running");
};
};

run() is also {
start monitor();
};

e Language Reference 22-37


Predefined Methods
The quit() Method of any_struct

};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...

Inject packet id 134576642


cycle 3 Packet id 134576642 is still running
cycle 5 Packet id 134576642 is still running

Inject packet id -1767441690


cycle 8 Packet id -1767441690 is still running
cycle 10 Packet id -1767441690 is still running

Inject packet id 1480193010


cycle 13 Packet id 1480193010 is still running
cycle 15 Packet id 1480193010 is still running

Inject packet id 370225594


cycle 18 Packet id 370225594 is still running
cycle 20 Packet id 370225594 is still running

Inject packet id 595104854


cycle 23 Packet id 595104854 is still running
cycle 25 Packet id 595104854 is still running

Inject packet id 631871925


cycle 28 Packet id 631871925 is still running
Last specman tick - stop_run() was called
cycle 30 Packet id 631871925 is still running
Normal stop - stop_run() is completed
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

See Also
• stop_run() on page 17-69
• kill() on page 22-76
• terminate_branch() on page 22-78

22-38 e Language Reference


Predefined Methods
The run() Method of any_struct

• terminate_thread() on page 22-80

22.3.10 The run() Method of any_struct

Purpose
Recommended place for starting TCMs

Category
Method of any struct or unit

Syntax
[exp.]run()

Syntax Example
run() is also {
start monitor();
};

Parameters

exp An expression that returns a unit or a struct.

Description
Can be extended to start user-defined TCMs. The method is initially empty.

The run() methods of all structs under sys are called, starting from sys in depth-first search order, by the
global.run_test() method, when you execute a test or a run command.

After this initial pass, when any struct is generated (with the gen action) or allocated (with new), its
run() method is also invoked. This ensures that:

• The run() method of each struct instance is called exactly once, thus avoiding multiple instances of
the same started TCM;
• TCMs do not start and events do not occur before Specman is ready to accept them;
• The run() method is called after generation and uses the generated values.

e Language Reference 22-39


Predefined Methods
The rerun() Method of any_struct

If you run multiple tests in the same session, the run() method is called once for each test in the session.
The init() method is called only once before the first test.

Note
Starting a TCM before the run test phase causes a runtime error. See “Test Phases and Predefined
Methods” on page 22-3 for more information on test phases.

Example
<'
struct packet {
id : int;
monitor() @sys.any is {
while (TRUE) {
wait [2] * cycle;
out("cycle ", sys.time,
" Packet id ", id, " is still running");
};
};

run() is also {
start monitor();
};
};
'>

See Also
• The run() Method of sys on page 22-13
• start tcm() on page 7-25
• run on page 11-6 in the Specman Command Reference

22.3.11 The rerun() Method of any_struct

Purpose
Kill all threads of a struct or unit instance and then call its run() method.

22-40 e Language Reference


Predefined Methods
The rerun() Method of any_struct

Category
Method of any struct or unit

Syntax
[exp.]rerun()

Syntax Example
rerun();

Parameters

exp An expression that returns a unit or a struct.

Description
The rerun() method:

1. Deactivates a struct or unit instance at the end of the current tick by calling its quit() method. The
quit() method kills any TCM threads, attached events, or expect members that are still running.

2. Reactivates the struct or unit instance at the beginning of the next cycle (new specman time) by
calling its run() method and activating the attached event and expect members.

Similarly to the quit() method, rerun() is not called recursively for struct sub-structs. If required, you
can extend rerun() to call sub-struct rerun() methods also.

To pause a struct action, first call its quit() method and after the required time call its rerun() method to
reactivate it.

Example
This example suggests how rerun() can be used to verify a DUT reset. In this example, the do_reset()
TCM emulates a reset twice by assigning its reset field to one, waiting for the reset duration, and then
reassigning reset to zero.

Upon instantiation, the device instance activates the events reset_start and reset_end and starts its
monitor() TCM. The events look for changes in the sys.reset field. The monitor() TCM reports the times
when the instance is running.

e Language Reference 22-41


Predefined Methods
The rerun() Method of any_struct

On the device.reset_start event, the device calls rerun(), which kills the monitor() TCM thread. At the
next tick, device.run() is called again, and the test and monitor() TCM are restarted. Once sys.reset is
assigned to zero, it enters its loop again. The event reset_end occurs, and the device calls
check_register_default_values().

Notice that monitor() does not sync with reset_end because the test might start with sys.reset equal to
zero. In this case you would want monitor() to enter its loop and not wait for a reset fall.
<'
extend sys {
device : device is instance;

!reset : uint;

do_reset() @any is {
for i from 1 to 2 {
wait [3];
reset = 1;
wait [10]; // 'reset' duration
reset = 0;
};
wait [3];
stop_run();
};

run() is also {
start do_reset();
};
};

unit device {
event reset_start is rise(sys.reset)@sys.any;
event reset_end is fall(sys.reset)@sys.any;

on reset_start {
out("=== Device saw RESET at ", sys.time, " ===");
rerun();
};

on reset_end {
check_register_default_values();
};

check_register_default_values() is {
out("Device checking registers default values at ",sys.time);
};

22-42 e Language Reference


Predefined Methods
The rerun() Method of any_struct

monitor()@sys.any is {
sync true(sys.reset == 0);
while (TRUE) {
out("Device is running at ", sys.time );
wait cycle;
};
};

run() is also{
out("Device run() is called at ", sys.time );
start monitor();
};
};
'>

Results
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
Device run() is called at 0
Device is running at 0
Device is running at 1
Device is running at 2
Device is running at 3
=== Device saw RESET at 4 ===
Device is running at 4
Device run() is called at 5
Device checking registers default values at 14
Device is running at 14
Device is running at 15
Device is running at 16
=== Device saw RESET at 17 ===
Device is running at 17
Device run() is called at 18
Device checking registers default values at 27
Device is running at 27
Device is running at 28
Last specman tick - stop_run() was called
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

e Language Reference 22-43


Predefined Methods
Pseudo-Methods

See Also
• The quit() Method of any_struct on page 22-36
• The run() Method of any_struct on page 22-39
• run on page 11-6 in the Specman Command Reference

22.4 Pseudo-Methods
Pseudo-methods calls look like method calls, but unlike methods they are not associated with structs and
are applied to other types of expressions, such as lists.

Pseudo-methods cannot be changed or extended through use of the is only, is also or is first constructs.

The following sections provide descriptions of the pseudo-methods:

• declared_type() on page 22-45


• type() on page 22-45
• field() on page 22-46
• unsafe() on page 22-47
• source_location() on page 22-47
• source_method() on page 22-49
• writef() on page 22-50
• as_a() on page 3-40
• swap() on page 18-36

See Also
• Chapter 23 “List Pseudo-Methods”
• “File Routines” on page 24-91
• Chapter 24 “Predefined Routines”

22-44 e Language Reference


Predefined Methods
declared_type()

22.4.1 declared_type()

Purpose
Get a handle for the declared type of an expression

Category
Pseudo-method

Syntax
exp.declared_type(): type_descriptor

Syntax Example
if pkt1.declared_type() != pkt1.type() then {out("Got a mismatch!")};

Parameters

exp Any legal e expression.

Description
Returns a handle for the declared type of an expression

The use of this pseudo-method is strongly discouraged.

22.4.2 type()

Purpose
Get a handle for the type of an expression

Category
Pseudo-method

e Language Reference 22-45


Predefined Methods
field()

Syntax
exp.type(): type_descriptor

Syntax Example
if pkt1.type() == pkt2.type() then {out("Got a match!")};

Parameters

exp Any legal e expression.

Description
Returns a handle for the type of an expression.

The use of this pseudo-method is strongly discouraged.

22.4.3 field()

Purpose
Get the handle for a field

Category
Pseudo-method

Syntax
struct-exp.field(field-name): field

Parameters

struct-exp An expression that returns a struct.

Description
Returns the handle for the specified field.

The use of this pseudo-method is strongly discouraged.

22-46 e Language Reference


Predefined Methods
unsafe()

22.4.4 unsafe()

Purpose
Bypass type checking

Category
Pseudo-method

Syntax
exp.unsafe(): type

Parameters

exp Any legal e expression.

Description
Passes the expression with no type checking or auto-casting.

This method should be used only when calling C routines that perform their own type checking.

See Also
• declared_type() on page 22-45
• type() on page 22-45
• field() on page 22-46
• Chapter 3 “Data Types”

22.4.5 source_location()

Purpose
Get source reference string

e Language Reference 22-47


Predefined Methods
source_location()

Category
Pseudo-method

Syntax
source_location(): string

Syntax Example
print source_location();

Description
Returns the source location string. The string describes the line number and the module name in which
the source_location() method was invoked. The format of the string is:
at line line-number in @module-name

Example
<'
extend sys {
m() is {
out("I'm ",source_location());
};
};
'>

Result
vrst-tool> sys.m()
I'm at line 4 in @xxx

See Also
• dut_error_struct on page 10-6
• source_method() on page 22-49

22-48 e Language Reference


Predefined Methods
source_method()

22.4.6 source_method()

Purpose
Get name of executing method

Category
Pseudo-method

Syntax
source_method(): string

Syntax Example
print source_method();

Description
Returns the name of the enclosing method. The string describes the line number and the module name in
which the source_method() method was invoked. The format of the string is:
method-name at line line-number in @module-name

Example
<'
extend sys {
run() is also {
out("location = '", source_location(),
"'\nmethod = '", source_method(), "'");
};
};
'>

Result
vrst-tool> run
location = 'at line 4 in @method'
method = 'sys.run() at line 3 in @method'

e Language Reference 22-49


Predefined Methods
writef()

See Also
• source_location() on page 22-47

22.4.7 writef()

Purpose
Write to a file in a specified format, with no new line at the end

Category
Pseudo-method

Syntax
writef(output_file: file-descriptor, format: string, item: exp, …)

Syntax Example
var m_file: file = files.open("a_f.txt", "w", "My data");
var m_i := new m_struct_s;
writef(m_file, "Type: %s\tData: %s\n", m_i.s_type, m_i.data);

Parameters

file The file descriptor of the file to write into.

format A string containing a standard C formatting mask for each item. See “Format String”
on page 24-65 for information about formatting masks.

item An e expression to write to the file.

Description
Adds a formatted string to the end of the specified file. No newline is automatically added. (Use “\n” in
the formatting mask to add a newline).

The file must already have been opened with open() on page 24-98, otherwise an error is issued.

If the number of items in the formatting mask is different than the number of item expressions, an error
is issued.

22-50 e Language Reference


Predefined Methods
writef()

How the data is written to the file is affected by the open() mode “w” or “a” option and by whether or
not the file already exists, as follows:

• If the file did not previously exist and the “w” (write) option is used with open(), then writef() writes
the data into a new file.
• If the file did not previously exist and the “a” (append) option is used with open(), then no data is
written.
• If the file did previously exist and the “w” (write) option is used with open(), then writef() overwrites
the contents of the file.
• If the file did previously exist and the “a” (append) option is used with open(), then writef() appends
the data to the existing contents of the file.

Example
In the following example, a file named “pkts_file.txt” is opened in write (“w”) mode, with file descriptor
mypkts. The writef() pseudo-method writes the contents of a list of pkt_s structs to the pkts_file, using
a new line (\n) for each struct instance, with tabs (\t) after the struct instance name and the ptype field.
The struct instance and the ptype are written as strings (%s) and pdata is written as a number (%d).
<’
type pkt_t: [PKT1, PKT2, PKT3];
struct pkt_s {
ptype: pkt_t;
pdata: byte;
};
extend sys {
pkt_l[5]: list of pkt_s;
run() is also {
var mypkts: file = files.open("pkts_file.txt", "w", "");
for each (pkt) in pkt_l {
writef(mypkts, "Struct: %s\tType: %s\tData: %d\n",
pkt, pkt.ptype, pkt.pdata);
};
files.close(mypkts);
};
};
’>

Result
This is what the contents of the pkts_file.txt file look like:
Struct: pkt_s-@0 Type: PKT2 Data: 148
Struct: pkt_s-@1 Type: PKT3 Data: 198

e Language Reference 22-51


Predefined Methods
Simulation-Related Methods

Struct: pkt_s-@2 Type: PKT3 Data: 61


Struct: pkt_s-@3 Type: PKT2 Data: 18
Struct: pkt_s-@4 Type: PKT1 Data: 82

See Also
• close() on page 24-95
• open() on page 24-98
• write() on page 24-103
• write_lob() on page 24-105
• “Format String” on page 24-65

22.5 Simulation-Related Methods

22.5.1 get_define()

Purpose
Get the value of a Verilog define

Category
Predefined method

Syntax
simulator.get_define(macro: string): string

Syntax Example
s = simulator.get_define("‘WORD_WIDTH");

Parameters

macro A currently defined Verilog macro, with the leading ` character, enclosed in double quotes.

22-52 e Language Reference


Predefined Methods
Simulation-Related Methods

Description
Returns the value of the Verilog macro as a string. If no such define exists, an error occurs. A typical
reason to use this method, rather than the more concise `macro notation, is when you need to compute
the define string during run time.

This method works for both normal and deferred defines.

Example

macros.v
‘define BASIC_DELAY 2
‘ifdef OLD_TECH
‘define TRANS_DELAY ‘BASIC_DELAY+3
‘else
‘define TRANS_DELAY ‘BASIC_DELAY
‘endif
‘define TOP tb
‘define READY ‘TOP.ready
‘define WORD_WIDTH 8
‘define HIGH_BIT 7

defs.e
<'
verilog import macros.v;
struct defs {
m() is {
var s : string;
s = simulator.get_define("‘WORD_WIDTH");
print s;
};
};

extend sys {
pmi: defs;
};
'>

Result
vrst-tool> sys.pmi.m()
s = "8"

e Language Reference 22-53


Predefined Methods
Semaphore Methods

See Also
• verilog import on page 17-7
• “specman deferred” on page 17-66
• show defines on page 13-1 of the Specman Command Reference

22.6 Semaphore Methods


The e language provides three predefined structs that are useful in controlling resource sharing among
TCMs:

• semaphore
This is the typical semaphore. The maximum value ranges between 1 and MAX_INT. By default, it
is MAX_INT, and the initial value (number of available resources) is 0. (See “Example 1” on page
22-58.)

• rdv_semaphore
A rendezvous semaphore is a semaphore with no resources. It requires the meeting of a producer
and a consumer for either to proceed. When they finally proceed, the down() thread always runs
first, followed immediately by the up(). (See “Example 2” on page 22-59.)
• locker
The methods of this struct provide a fair, FIFO ordered sharing of resources between multiple
competing methods.

A locker is useful when a single entity needs to prevent others from a shared resource. lock() and free()
must be issued by the same entity. A semaphore is more flexible. You could implement the locker
functionality with a semaphore by initializing the semaphore count to 1, then changing all locker.lock()
to semaphore.down() and all locker.free() to semaphore.up(). You can also use a semaphore when the
need is for a producer and consumer, that is, one entity “locks” and the other one “frees”. Finally, you
could also use a semaphore if you had more than one shared resource available by initializing the count

Table 22-1 gives a brief description of the predefined methods of the semaphore and rdv_semaphore
structs. Table 22-2 describes the predefined methods of the locker struct.

Table 22-1 Semaphore Methods

Method Description

up() Increments the semaphore's value. Blocks if the value is already the
maximum possible.

down() Decrements the semaphore's value. Blocks if the value is already 0.

22-54 e Language Reference


Predefined Methods
Semaphore Methods

Table 22-1 Semaphore Methods

Method Description

try_up() Increments the semaphore's value. If the value is already the maximum
possible, returns without blocking.

try_down() Decrements the semaphore's value. If the value is already 0, returns without
blocking.

set_value() Sets the initial value of the semaphore.

get_value() Returns the current value of the semaphore.

set_max_value() Sets an upper limit to the possible value of the semaphore.

get_max_value() Returns the maximum possible value.

Table 22-2 Locker Methods

Method Description

lock() The first TCM to call the lock() method of a field of type locker gets the
lock and can continue execution. The execution of the other TCMs is
blocked.

free() When a TCM that has the lock calls free(), control goes to the next TCM
serviced by the scheduler that is waiting on the locker. The order in which
the lock is granted is by a FIFO (First In First Out) order of client lock()
requests.

See Also
• “Lockers Versus Semaphores” on page 22-56
• “How to Use the Semaphore Struct” on page 22-56
• up() and down() on page 22-57
• try_up() and try_down() on page 22-61
• set_value() and get_value() on page 22-62
• set_max_value() and get_max_value() on page 22-64
• lock() and free() on page 22-65

e Language Reference 22-55


Predefined Methods
Lockers Versus Semaphores

22.6.1 Lockers Versus Semaphores


A locker is useful when a single entity needs to prevent others from a shared resource. lock() and free()
must be issued by the same entity.

A semaphore is more flexible. You can implement the locker functionality with a semaphore by
initializing the semaphore count to 1, then changing all locker.lock() to semaphore.down() and all
locker.free() to semaphore.up().

You can also use a semaphore when the need is for a producer and consumer, that is, one entity “locks”
and the other one “frees”. Finally, you can also use a semaphore if you have more than one shared
resource available. You initialize the number of resources available with set_value().

Note The rerun() predefined method does not release existing locker requests. After rerun() is called,
any remaining lock requests remain in the locker structure. Only the thread that locked the locker can
release it. You can get around this limitation by using a semaphore, rather than a locker.

22.6.2 How to Use the Semaphore Struct


A field of type semaphore typically serves as a synchronization object between two types of TCMs:
producer and consumer.

A consumer TCM uses the predefined down() time-consuming method of the semaphore to gain control
of a new resource managed by the semaphore. If no resources are available at the time down() is called,
the consumer TCM is blocked until such a resource is available.

A producer TCM uses the predefined up() time-consuming method of the semaphore to increase the
amount of available resources of the semaphore. This resource is made available for consumer TCMs. If
the semaphore already contains the maximum number of resources at the time up() is called, the
producer TCM is blocked until a semaphore resource is consumed.

The amount of available resources is zero by default but can be set otherwise using the set_value()
method. The current amount of available resources can be obtained using the get_value() method.

There is a limit to the possible number of available resources. Typically, the maximum is MAX_INT, but
it can be set to other values between 0 and MAX_INT using the set_max_value() method. The current
limit for available resources can be obtained using the get_max_value() method.

Any producer TCM is blocked if the semaphore already holds the maximum number of available
resources.

22-56 e Language Reference


Predefined Methods
up() and down()

22.6.3 up() and down()

Purpose
Synchronize producer and consumer TCMs

Category
Predefined TCM of semaphore struct

Syntax
semaphore.up()

semaphore.down()

Syntax Example
sem1.up();
sem1.down();

Parameters

semaphore An expression of type semaphore or rdv_semaphore

Description
The up() time-consuming method increases the number of available resources of the semaphore by 1. If
the number of available resources is already the maximum, the TCM is blocked. Blocked calls to up()
are serviced according to their request order (on a First In First Out basis).

The down() time consuming method decreases the number of resources of the semaphore by 1. If no
resources are available, the TCM is blocked. Blocked calls to down() are serviced according to their
request order (on a First In First Out basis).

With an rdv_semaphore, up() and down() are blocked unless they coincide. The down() TCM always
breaks the block first.

e Language Reference 22-57


Predefined Methods
up() and down()

Example 1
The following example shows how you can use a semaphore to handle concurrent requests for exclusive
access from multiple clients in an orderly manner. In this example there are two client structs and one
server struct. The server has a semaphore to ensure that all requests are granted and that there are no
simultaneous grants.

When both clients issue a request at the same time the semaphore keeps track of the order of the
requesting TCMs. The first client to issue a request is granted the single resource, making it unavailable
to the other client. When this client is done with the resource, it uses the up() method of the semaphore
to make the resource available to the other requesting client.
<'
struct server {
event clk;
sem: semaphore;

run() is also {
sem.set_value(1);
};
};

struct client {
id: string;
s: server;

handshake()@s.clk is { // A single-cycle delay handshake


out(id,": Starting handshake at time ",sys.time);
s.sem.down();
out(id,": Granted at time ",sys.time);
wait [1];
out(id,": Releasing at time ",sys.time);
s.sem.up();
};

run()is also {start handshake();};


};

extend sys {
s: server;
c1: client; keep {c1.s==s; c1.id=="client 1"};
c2: client; keep {c2.s==s; c2.id=="client 2"};

go()@any is {
for i from 0 to 40 do {
wait cycle;
emit s.clk;

22-58 e Language Reference


Predefined Methods
up() and down()

};
stop_run();
};
run()is also {start go()};
};
'>

Result:
client 1: Starting handshake at time 1
client 1: Granted at time 1
client 2: Starting handshake at time 1
client 1: Releasing at time 2
client 2: Granted at time 2
client 2: Releasing at time 3

Example 2
The following example shows how to use an rdv_semaphore to synchronize several reading TCMs that
share a common input source.

In this example there is one writer and two readers. It takes the writer 3 cycles to write its data, and then
it calls the up() method. When a reader appears, it calls the down() method and waits for the data to be
ready. When both the writer and the reader are ready, at the two sides of the channel, the data exchange
takes place: the reader breaks the block first, which allows it to read the data before it is overwritten by
the writer. Then comes the writer and starts preparing for the next data exchange.
<'
extend sys {
rdv_semaphore;
reg :int;

writer(id : int) @any is {


var v : int = 0;
while TRUE {
out(time, " -> writer ", dec(id), ": start preparing data.");
wait [3];
v += 1;
reg = v;
out(time, " -> writer ", dec(id),
": done writing to register [ v = ",hex(v),"].");
rdv_semaphore.up();
};
};

reader(id : int) @any is {

e Language Reference 22-59


Predefined Methods
up() and down()

while TRUE {
out(time, " -> reader ", dec(id),
": ready to read from register.");
rdv_semaphore.down();
out(time, " -> reader ", dec(id),
": reading from register [ reg = ",hex(reg),"].");
wait [id];
};
};

run() is also {
start writer(1);
start reader(2);
start reader(3);
};

event terminate is [10] exec {stop_run();};


};
'>

Result:
0 -> writer 1: start preparing data.
0 -> reader 2: ready to read from register.
0 -> reader 3: ready to read from register.
3 -> writer 1: done writing to register [ v = 0x1].
3 -> reader 2: reading from register [ reg = 0x1].
3 -> writer 1: start preparing data.
5 -> reader 2: ready to read from register.
6 -> writer 1: done writing to register [ v = 0x2].
6 -> reader 3: reading from register [ reg = 0x2].
6 -> writer 1: start preparing data.
9 -> reader 3: ready to read from register.
9 -> writer 1: done writing to register [ v = 0x3].
9 -> reader 2: reading from register [ reg = 0x3].
9 -> writer 1: start preparing data.

See Also
• “How to Use the Semaphore Struct” on page 22-56
• try_up() and try_down() on page 22-61
• set_value() and get_value() on page 22-62
• set_max_value() and get_max_value() on page 22-64

22-60 e Language Reference


Predefined Methods
try_up() and try_down()

22.6.4 try_up() and try_down()

Purpose
Synchronize producer and consumer methods

Category
Predefined method of semaphore struct

Syntax
semaphore.try_up(): bool

semaphore.try_down(): bool

Syntax Example
compute sem1.try_up();
compute sem1.try_down();

Parameters

semaphore An expression of type semaphore or rdv_semaphore.

Description
The try_up() and try_down() methods try to increment or decrement the number of available resources
by 1, respectively. If the number of available resources is already at its maximum or minimum
respectively, these methods return immediately without any effect (in particular, no blocking). If the
number of resources was changed, the returned value is TRUE. If the number of resources was not
changed, the returned value is FALSE. The FIFO ordered of service of the semaphore is kept even when
the try_up() and try_down() methods are involved. For example, a try_up() will never succeed if there
are pending calls to up().

Note Being regular methods (not TCMs), try_up() and try_down() never generate a context switch.

Example
The following example shows a driver that sends information at each clock. If there is valid data in reg
that is protected by the semaphore reg_sem, it sends its contents. Otherwise, it sends 0.
driver()@any is {

e Language Reference 22-61


Predefined Methods
set_value() and get_value()

while TRUE {
if sem.try_down() {
send( reg );
} else {
send( 0 );
};
wait cycle;
};
};

See Also
• “How to Use the Semaphore Struct” on page 22-56
• up() and down() on page 22-57
• set_value() and get_value() on page 22-62
• set_max_value() and get_max_value() on page 22-64

22.6.5 set_value() and get_value()

Purpose
Set and get the number of available resources of a semaphore

Category
Predefined method of semaphore struct

Syntax
semaphore.set_value(new_value: int)

semaphore.get_value(): int

Syntax Example
sem1.set_value(7);
cur_value = sem1.get_value();

Parameters

new_value An expression of type signed int

22-62 e Language Reference


Predefined Methods
set_value() and get_value()

Description
The set_value() method sets the number of available resources of the semaphore. By default, a
semaphores are initialized with zero available resources.

The new value must be a non-negative integer, no larger than MAX_INT. If the set_max_value()
method of the struct was used, the new value must also be smaller or equal to the last setting of the
maximum number of resources. If these conditions do not hold, Specman issues a runtime error.

set_value() cannot be called if either up() or down() was previously called. In such case, Specman
issues an error. Setting the value of an rdv_semaphore to something other than zero also results in a
runtime error.

The get_value() method returns the current number of available resources of the semaphore.

Example
<'
extend sys {
sem : semaphore;
run() is also {
sem.set_value(5);
print sem.get_value();
};
};
'>

Result:
sem.get_value() = 5

See Also
• “How to Use the Semaphore Struct” on page 22-56
• up() and down() on page 22-57
• try_up() and try_down() on page 22-61
• set_max_value() and get_max_value() on page 22-64

e Language Reference 22-63


Predefined Methods
set_max_value() and get_max_value()

22.6.6 set_max_value() and get_max_value()

Purpose
Set and get the maximum number of available resources of a semaphore

Category
Predefined method of semaphore struct

Syntax
semaphore.set_max_value(new_value: int)

semaphore.get_max_value(): int

Syntax Example
sem1.set_max_value(17);
cur_max_value = sem1.get_max_value();

Parameters

new_value An expression of type signed int

Description
The set_max_value() method sets the maximum number of available resources of the semaphore. By
default, a semaphore is initialized with a maximum of MAX_INT available resources.

The new value must be a positive integer, no larger than MAX_INT. If set_value() was used, the new
value must not be smaller than the number of available resources. If these conditions do not hold,
Specman issues a runtime error.

The value of an rdv_semaphore is constantly zero. Therefore its default maximum value is zero, and it
cannot be set to a value other than that. Trying to do so also results in a runtime error.

set_max_value() cannot be called if either up() or down() was previously called. In such case, Specman
issues an error.

It is safer to invoke the set_max_value() method before any other semaphore method.

The get_max_value() method returns the current limit for available resources of the semaphore.

22-64 e Language Reference


Predefined Methods
lock() and free()

Example
<'
extend sys {
sem : semaphore;
run() is also {
sem.set_max_value(5);
print sem.get_max_value();
};
};
'>

Result:
sem.get_max_value() = 5

See Also
• “How to Use the Semaphore Struct” on page 22-56
• up() and down() on page 22-57
• try_up() and try_down() on page 22-61
• set_value() and get_value() on page 22-62

22.6.7 lock() and free()

Purpose
Control access to a shared resource

Category
Predefined TCM of locker struct

Syntax
locker-exp.lock()

locker-exp.free()

e Language Reference 22-65


Predefined Methods
lock() and free()

Note The free() method is new as of Specman 4.3.1. It replaces the previous locker-exp.release()
method, which is now under deprecation. However, the previous locker-exp.release() method is still
supported at this time, which means that you do not need to change any existing code. For more
information, see “Deprecation and Backward Compatibility in the Current Release” on page 8-2 and
“Understanding the Deprecation Process” on page 7-1 in About This Specman Elite Release.

Syntax Example
lckr.lock();
lckr.free();

Parameters

locker-exp An expression of type locker.

Description
locker is a predefined struct with two predefined methods, lock() and free(). These methods are TCMs.

Once a field is declared to be of type locker, that field can be used to control the execution of TCMs by
making calls from the TCMs to locker.lock() and locker.free().

If you call locker-exp.lock() from multiple TCMs, the first TCM gets the lock and can continue
execution. The execution of the other TCMs is blocked. Thus any resources that are shared among the
TCMs will be available only to the TCM that gets the lock.

When a TCM calls free(), control goes to the next TCM serviced by the scheduler that is waiting on the
locker. The order in which the lock is granted is by a FIFO (First In First Out) order of client lock()
requests.

Specman uses non-preemptive scheduling, which means that thread execution is interrupted only when
the executing thread reaches a wait, sync, TCM call, free(), or lock() request. This has two implications:

• You do not need to use locks unless the code to be executed between the lock() and the free() contains
a wait, sync, or TCM call.
• Code that is not time-consuming and is used by multiple threads should be put in a regular method
so no locks are needed.

Notes
• Calling lock() again before calling free() results in a deadlock. The TCM attempting to acquire the
locker stops and waits for the locker to be freed. This TCM never executes because it cannot free the
locker. Naturally none of the other TCMs that wait for the locker is executed.

22-66 e Language Reference


Predefined Methods
lock() and free()

• The release of the locker must be explicit. If the locking thread ends (either normally or abnormally)
without a call to free(), the locker is not released. Again, none of the other TCMs that wait for the
locked is executed.
Note that the rerun() method does not release the locker. After rerun() is called, any remaining
lock requests remain in the locker structure.

See Also
• “Lockers Versus Semaphores” on page 22-56

Example 1
This example illustrates how the execution of two TCMs are controlled using a field of type locker.
<'
struct foo {
lckr: locker;
tcm1(id: uint) @sys.any is {
all of {
{
lckr.lock();
out("first branch got the lock");
wait [2];
out("first branch frees the lock");
lckr.free();
};
{
lckr.lock();
out("second branch got the lock");
wait [2];
out("second branch frees the lock");
lckr.free();
};
};
wait [10] * cycle;
out("******After 10 cycles*********");
stop_run();
};
tcm2() @sys.any is {
lckr.lock();
out("tcm2 got the lock");
wait [2] * cycle;
out("tcm2 frees the lock");
lckr.free();
};
run() is also {

e Language Reference 22-67


Predefined Methods
lock() and free()

start tcm2();
start tcm1(1);
};
};

extend sys {
foo_inst: foo;
};
'>

Result
Note that tcm2 gets the lock first, then the first all of branch of tcm1 and finally the last all of branch of
tcm1.
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
tcm2 got the lock
tcm2 frees the lock
first branch got the lock
first branch frees the lock
second branch got the lock
second branch frees the lock
******After 10 cycles*********
Last specman tick - stop_run() was called
Normal stop - stop_run() is completed
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

Example 2
<'
struct st {
lckr: locker;
ftcm(id: uint) @sys.any is {
for i from 0 to 2 do {
lckr.lock();
out("Id ", id, " got the resource");
wait cycle;
lckr.free();
};
};
run() is also {
start ftcm(1);
start ftcm(2);

22-68 e Language Reference


Predefined Methods
TCM Related Methods

};
};
extend sys {
sti: st;
};
'>

Result
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
Thread 1 got the resource
Thread 2 got the resource
Thread 1 got the resource
Thread 2 got the resource
Thread 1 got the resource
Thread 2 got the resource
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

22.7 TCM Related Methods


The scheduler is a predefined struct containing methods that let you access active TCMs and terminate
them.

A TCM that is invoked with a start action is a thread. If a started TCM calls other TCMs, those TCMs
are considered subthreads of the started TCM thread. If a struct has more than one started TCM, each
TCM runs on a separate, parallel thread. Each thread shares a unique identifier, or thread handle, with its
subthreads. The thread handle is automatically assigned by the scheduler.

The following sections describe how to retrieve the handle for active threads:

• get_current_handle() on page 22-70


• get_handles_by_name() on page 22-72
• get_handles_by_type() on page 22-74
The following sections describe how to terminate active threads:

• kill() on page 22-76


• terminate_branch() on page 22-78
• terminate_thread() on page 22-80

e Language Reference 22-69


Predefined Methods
get_current_handle()

22.7.1 get_current_handle()

Purpose
Obtain the handle of the current TCM

Category
Predefined method

Syntax
scheduler.get_current_handle(): thread handle

Syntax Example
out ("(started) I = ",i," in Thread " ,
scheduler.get_current_handle(),".");

Description
Returns the handle of the currently running TCM. The handle is of the predefined type named
“thread_handle”.

This method must ultimately be invoked from a TCM. You can call it from a non-TCM method, but that
method must, at some point, be called from a TCM. That is, you can call get_current_handle() from a
non-TCM, which, in turn, is called from another non-TCM, and so on, but at the top of the chain of
method calls must be a TCM.

Note
A runtime error is produced if get_current_handle() is called from within a regular (not
time-consuming) method, if that method is not ultimately called from a TCM.

Example
<'
struct sch {
run() is also {
start started_tcm(13);
start started_tcm(29);
};

22-70 e Language Reference


Predefined Methods
get_current_handle()

started_tcm(i:int) @sys.any is {
out ("(started) I = ",i," in Thread " ,
scheduler.get_current_handle(),".");
called_tcm(i);
wait [1];
out ("(cont ..) I = ",i," in Thread " ,
scheduler.get_current_handle(),". (same thread handle)");
};

called_tcm(i:int) @sys.any is {
out ("(called ) I = ",i," in Thread " ,
scheduler.get_current_handle(),". (same thread handle)");
};
};

extend sys {
pmi: sch;
};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
(started) I = 13 in Thread 1.
(called ) I = 13 in Thread 1. (same thread handle)
(started) I = 29 in Thread 2.
(called ) I = 29 in Thread 2. (same thread handle)
(cont ..) I = 13 in Thread 1. (same thread handle)
(cont ..) I = 29 in Thread 2. (same thread handle)
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

See Also
• get_handles_by_name() on page 22-72
• get_handles_by_type() on page 22-74

e Language Reference 22-71


Predefined Methods
get_handles_by_name()

22.7.2 get_handles_by_name()

Purpose
Get list of thread handles on a struct instance basis

Category
Predefined method

Syntax
scheduler.get_handles_by_name(struct-inst: exp, method-name: string): list of thread handle

Syntax Example
hs = scheduler.get_handles_by_name(a1,"yy");

Parameters

struct-exp NULL, or an expression of type struct that specifies the owning struct instance for
the started TCMs with the specified name.

method-name NULL, or the name of a method in the specified struct, enclosed in double quotes.

Description
Returns a list of handles of all started TCMs of the specified name associated with the specified struct
instance.

When the struct expression is NULL the resulting list contains handles for all the started TCMs of the
given name. When the method name is NULL, the returned list contains thread handles for all the
currently running threads for the specified struct. In the case when both parameters are NULL, the list of
handles for all currently running threads is returned.

A thread is any started TCM. If a started TCM calls other TCMs, those TCMs are considered subthreads
of the started TCM thread. If a struct has more than one started TCM, each TCM runs on a separate,
parallel thread. Each thread shares a unique identifier, or thread handle, with its subthreads. The thread
handle is automatically assigned by the scheduler.

Example
<'

22-72 e Language Reference


Predefined Methods
get_handles_by_name()

struct a {
xx() @sys.any is {
wait [1]*cycle;
};
yy() @sys.any is {
wait [1]*cycle;
};
};

extend sys {
a1:a;
a2:a;

run() is also {
var hs:list of thread_handle;
start a1.xx();
start a1.yy();
start a2.yy();
hs = scheduler.get_handles_by_name(a1,"yy");
print hs;
print scheduler.get_handles_by_name(NULL,NULL);
};
};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
hs =
0. 2
scheduler.get_handles_by_name(NULL,NULL) =
0. 1
1. 2
2. 3
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

See Also
• get_current_handle() on page 22-70
• get_handles_by_type() on page 22-74

e Language Reference 22-73


Predefined Methods
get_handles_by_type()

22.7.3 get_handles_by_type()

Purpose
Get list of thread handles on a struct type basis

Category
Predefined method

Syntax
scheduler.get_handles_by_type(struct-inst: exp, method-name: string): list of thread handle

Syntax Example
hs = scheduler.get_handles_by_type("a","yy");

Parameters

struct-exp NULL, or an expression of type struct that specifies the owning struct type for the
top-level TCMs of the specified method.

method-name NULL, or the name of a method in the specified struct, enclosed in double quotes

Description
Returns handles to all TCMs associated with the specified struct type.

When the struct expression is NULL the resulting list contains handles for all the started TCMs of the
given name. When the method name is NULL, the returned list contains thread handles for all the
currently running threads for the specified struct. If both struct expression and method name are NULL,
then all handles of all currently running threads are returned.

A thread is any started TCM. If a started TCM calls other TCMs, those TCMs are considered subthreads
of the started TCM thread. If a struct has more than one started TCM, each TCM runs on a separate,
parallel thread. Each thread shares a unique identifier, or thread handle, with its subthreads. The thread
handle is automatically assigned by the scheduler.

Example
<'
struct a {

22-74 e Language Reference


Predefined Methods
get_handles_by_type()

xx() @sys.any is {
wait [1]*cycle;
};
yy() @sys.any is {
wait [1]*cycle;
};
};

extend sys {
a1:a;
a2:a;

run() is also {
var hs:list of thread_handle;
start a1.xx();
start a2.yy();
start a2.yy();
hs = scheduler.get_handles_by_type("a","yy");
print hs;
print scheduler.get_handles_by_type("a",NULL);
};
};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
hs =
0. 2
1. 3
scheduler.get_handles_by_type("a",NULL) =
0. 1
1. 2
2. 3
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

See Also
• get_current_handle() on page 22-70
• get_handles_by_name() on page 22-72

e Language Reference 22-75


Predefined Methods
kill()

22.7.4 kill()

Purpose
Kill a specified thread

Category
Predefined method

Syntax
scheduler.kill(handle: thread handle)

Syntax Example
for each (h) in hs {
{scheduler.kill(h)};
};

Parameters

handle The handle for the thread, as returned by scheduler.get_current_handle(),


scheduler.get_handles_by_name(), or scheduler.get_handles_by_type().

Description
Kills a started TCM (a thread) and any TCMs that it has called (its subthreads). A killed method cannot
be revived.

Notes
• Killing a method before it frees an active lock can result in a dead lock.
• A thread cannot kill itself. Use terminate_thread() on page 22-80 instead.

Example
<'
struct p_agent {
killer_tcm() @sys.any is {
wait [1]*cycle;
var hs :=

22-76 e Language Reference


Predefined Methods
kill()

scheduler.get_handles_by_type("p_agent","send");
for each (h) in hs {
out("Killing thread ",h);
{scheduler.kill(h)};
};
};

send() @sys.any is {
wait [5]*cycle;
out ("this line is never executed. ");
};
};

extend sys {
x:p_agent;
run() is also {
start x.killer_tcm();
start x.send();
start x.send();
start x.send();
};
};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
Killing thread 2
Killing thread 3
Killing thread 4
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

See Also
• terminate_branch() on page 22-78
• terminate_thread() on page 22-80

e Language Reference 22-77


Predefined Methods
terminate_branch()

22.7.5 terminate_branch()

Purpose
Terminate a specific branch in a first of action

Category
Predefined method

Syntax
scheduler.terminate_branch()

Syntax Example
scheduler.terminate_branch();

Description
This method can be used only within a first of action to terminate the branch. When a branch is
terminated using this method, the rest of the branches within the first of action remain active.

Example
The TCM “monitor()” in the example below begins several threads. Each waits for a sequence of events.
Under some conditions, some of the sequences should be halted.
<'
extend sys {
monitor() @sys.any is {
wait until rise('top.started');
first of {
{
wait [4] * cycle;
if 'top.out_of_sync' == 1 then {
out("### Went out of sync");
scheduler.terminate_branch();
};
wait until rise('top.ended');
out("Normal end");
};
{
wait until rise('top.aborted');

22-78 e Language Reference


Predefined Methods
terminate_branch()

out("Aborted");
};
};
// continue monitoring...
stop_run();
};

run() is also {
start monitor();
};
};
extend sys {
drive() @sys.any is {
wait [2] * cycle;
'top.started' = 1;
wait [5] * cycle;
'top.out_of_sync' = 1;
};

run() is also {
start drive();
};
};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
### Went out of sync
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

See Also
• kill() on page 22-76
• terminate_thread() on page 22-80

e Language Reference 22-79


Predefined Methods
terminate_thread()

22.7.6 terminate_thread()

Purpose
Terminate the current thread

Category
Predefined method

Syntax
scheduler.terminate_thread()

Syntax Example
scheduler.terminate_thread();

Description
Terminates the current thread immediately, not at the end of the current tick. To terminate the current
thread at the end of the current tick, use quit().

A thread is any started TCM. If a started TCM calls other TCMs, those TCMs are considered subthreads
of the started TCM thread. If a struct has more than one started TCM, each TCM runs on a separate,
parallel thread. Each thread shares a unique identifier, or thread handle, with its subthreads. The thread
handle is automatically assigned by the scheduler.

Example
The TCM inject() in the example below assigns the DUT signals. There are some conditions during the
run that indicate that the injection should stop.
<'
extend sys {
inject() @sys.any is {
'top.data' = 1;
wait [10] * cycle;
// continue reading/writing...
if ('top.status' == 0) then {
out("'top.status' == 0, Stop injection");
scheduler.terminate_thread();
};
// continue reading/writing...

22-80 e Language Reference


Predefined Methods
Coverage Methods

};

run() is also {
start inject();
};
};
'>

Result
vrst-tool> test
Doing setup ...
Generating the test using seed 1...
Starting the test ...
Running the test ...
'top.status' == 0, Stop injection
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

See Also
• The quit() Method of any_struct on page 22-36
• kill() on page 22-76
• terminate_branch() on page 22-78

22.8 Coverage Methods


The covers struct is a predefined struct containing methods that you use for coverage and coverage
grading. With the exception of the set_external_cover() and write_cover_file() methods, all of these
methods are methods of the covers struct.

• include_tests() on page 22-82


• set_weight() on page 22-83
• set_at_least() on page 22-85
• set_cover() on page 22-86
• get_contributing_runs() on page 22-89
• get_unique_buckets() on page 22-90
• set_external_cover() on page 22-92
• write_cover_file() on page 22-93

e Language Reference 22-81


Predefined Methods
include_tests()

• get_overall_grade() on page 22-94


• get_ecov_name() on page 22-96
• get_test_name() on page 22-97
• get_seed() on page 22-98

See Also
The following section describes another predefined method you use for coverage:

• set_check() on page 10-11

22.8.1 include_tests()

Purpose
Specify which test runs coverage information will be displayed for.

Category
Predefined method

Syntax
covers.include_tests(full-run-name: string, bool: exp)

Syntax Example
covers.include_tests("tests_A:run_A_10", TRUE);

Parameters

full-run-name The name of the test to include or exclude.

bool-exp Set to TRUE to include the specified test, FALSE to exclude it.
After the read cover command has been executed, all tests are
included.

22-82 e Language Reference


Predefined Methods
set_weight()

Description
The show coverage command displays coverage data for a test or series of tests. This method allows
you to specify which test runs you want to see coverage information for. It also determines which test
runs will be included in the Show Coverage GUI and by the Coverage API.

If you are reading in .ecov files to load coverage information, this method should be called only after
the .ecov files have been read.

Example
The following example shows several ways to specify test runs for display by show coverage.
<'
extend sys {
setup() is also {
covers.include_tests("tests_A:...", FALSE);
covers.include_tests("...crc_test", TRUE);
covers.include_tests("/.*crc_test.*/", TRUE);
};
};
'>

See Also
• “Test Identification Items” on page 7-78 in the Usage and Concepts Guide for e Testbenches
• show cover on page 10-6 in the Specman Command Reference

22.8.2 set_weight()

Purpose
Specify the coverage grading weight of a group or item

Category
Predefined method

Syntax
covers.set_weight(entity-name: string, value: int, bool: exp)

e Language Reference 22-83


Predefined Methods
set_weight()

Syntax Example
covers.set_weight("inst.done", 4, FALSE);

Parameters

entity-name The group or item to set the weight for. May include wild cards.

value The integer weight value to set.

bool When this is FALSE, it changes the weights of all matching groups or items to
value. When this is TRUE, the weights of all matching groups or items are
multiplied by value.

Description
Coverage grading uses weights to emphasize the affect of particular groups or items relative to others.
The weights can be specified in the coverage group or item definitions. This method sets the weights
procedurally. It overrides the weights set in the group or item definitions. Weights can be set explicitly,
or can be multiplied by a given value.

If you are reading in .ecov files to load coverage information, this method should be called only after
the .ecov files have been read.

Example
The following example shows several ways to set coverage grading weights.
<'
extend sys {
pre_generate() is also {
// change the weight of done group to 4:
covers.set_weight("inst.done", 4, FALSE);
// multiply the len item weight by 5:
covers.set_weight("inst.done.len", 5, TRUE);
// set the weight of all groups in intrp to 0:
covers.set_weight("intrp.*", 0, FALSE);
// multiply by 3 the weights of items that start with cross:
covers.set_weight("inst.done.cross*", 3, TRUE);
};
};
'>

22-84 e Language Reference


Predefined Methods
set_at_least()

See Also
• “Coverage Grading” on page 7-41 in the Usage and Concepts Guide for e Testbenches
• cover on page 16-1
• item on page 16-8
• set_at_least() on page 22-85

22.8.3 set_at_least()

Purpose
Set the minimum number of samples needed to fill a bucket

Category
Predefined method

Syntax
covers.set_at_least(entity-name: string, value: int, exp: bool)

Syntax Example
covers.set_at_least("inst.done", 4, FALSE);

Parameters

entity-name The group or item to set the at_least number for. May include wild cards.

value The “at-least” integer value to set.

bool When this is FALSE, it sets the “at-least” number for all matching items
to value. When this is TRUE, it multiplies the “at-least” number for all
matching items by value.

Description
The minimum number of samples required to fill a bucket can be set in the coverage group or item
definitions. This method can be used to set the number procedurally. It overrides the numbers set in the
group or item definitions.

e Language Reference 22-85


Predefined Methods
set_cover()

If the entity-name is a coverage group name, all items in the group are affected. If the entity-name
matches items within a coverage group, only those items are affected.

If you are reading in .ecov files to load coverage information, this method should be called only after
the .ecov files have been read.

Example
The following example shows several ways to set coverage “at-least” numbers.
<'
extend sys {
pre_generate() is also {
// set at-least to 4 for all for done group items:
covers.set_at_least("inst.done", 4, FALSE);
// multiply at-least by 4 for the len item:
covers.set_at_least("inst.done.len", 5, TRUE);
// set at-least to 1 for all items in the intrp struct:
covers.set_at_least("intrp.*", 1, FALSE);
// multiply at-least by 3 for items that start with cross:
covers.set_at_least("inst.done.cross*", 3, TRUE);
};
};
'>

See Also
• “Bucket Hierarchy” on page 7-42 in the Usage and Concepts Guide for e Testbenches
• “Default Buckets” on page 7-51 in the Usage and Concepts Guide for e Testbenches
• cover on page 16-1
• item on page 16-8

22.8.4 set_cover()

Purpose
Turns coverage data collection and display on or off for specified items or events

Category
Predefined method

22-86 e Language Reference


Predefined Methods
set_cover()

Syntax
covers.set_cover(item|event: string, bool: exp)

Syntax Example
covers.set_cover("packet.*", FALSE);

Parameters

item A string, enclosed in double quotes, specifying the coverage item you want to turn on or
off. This may include wild cards.

event A string, enclosed in double quotes, specifying the event you want to turn on or off. This
may include wild cards.
Enter the name of the event using the following syntax:
session.events.struct_type__event_name
where the struct type and the event name are separated by two underscores. Wild cards
may be used.
If you enter only one name, it is treated as a struct type, and the method affects all events
in that struct type.

bool Set to TRUE to turn on coverage for the item or FALSE to turn coverage off.

Description
By default, coverage data is collected for all defined coverage items and groups, and for all user-defined
events. This method selectively turns data collection on or off for specified items, groups, or events.

After coverage data has been collected and written by a test or set of tests, this method can be used to
selectively turn on or off the display of the coverage data for specified items, groups, or events, by the
show cover command.

Although this method can be used to filter samples during periods in which they are not valid, for
performance reasons, filtering should be done using when subtypes instead.

Additionally, if the test ends while coverage collection is turned off by set_cover() for one or more
coverage groups, then set_cover() must be called again to re-enable sampling before the .ecov file is
written, in order to include the previously collected samples for those groups in the .ecov file.

e Language Reference 22-87


Predefined Methods
set_cover()

Example 1
The following example turns off coverage data collection for all items in all coverage groups defined in
the “inst” struct, and then turns back on the collection of data for the “len” item in the “done” group in
that struct.
<'
extend sys {
setup() is also {
covers.set_cover("inst.*.*", FALSE);
covers.set_cover("inst.done.len", TRUE);
};
};
'>

Example 2
The following example turns off coverage data collection for an event named “my_event” defined in the
“inst” struct.
<'
extend sys {
setup() is also {
covers.set_cover("session.events.inst__my_event", FALSE);
};
};
'>

Example 3
The following example turns off coverage data collection for all events in the struct named my_struct:.
<'
extend sys {
setup() is also {
covers.set_cover("my_struct", FALSE);
};
};
'>

See Also
• “Understanding Test Coverage” on page 7-1 in the Usage and Concepts Guide for e Testbenches
• show cover on page 10-6 in the Specman Command Reference

22-88 e Language Reference


Predefined Methods
get_contributing_runs()

22.8.5 get_contributing_runs()

Purpose
Return a list of the test runs that contributed samples to a bucket

Category
Predefined method

Syntax
covers.get_contributing_runs(item-name: string, bucket-name: string): list of string

Syntax Example
bkl=covers.get_contributing_runs("inst.done.len", "[0..4]");

Parameters

item-name A string, enclosed in double quotes, specifying the coverage item


that contains bucket-name.

bucket-name A string, enclosed in double quotes, specifying the bucket for which
contributing test run names are to be listed.

Description
This method returns a list of strings that are the full run names of the test runs that placed samples in a
specified bucket. For a cross item, the bucket-name may be a bucket of any level, with the bucket set
names separated by slashes, for example: “ADD/REG1” or “ADD/REG1/[0xC0..0xCF]”.

Example
The following example shows several ways to list test runs that put samples in particular buckets.
<'
type cpu_opcode: [ADD, SUB, OR, AND, JMP, LABEL];
type cpu_reg: [reg0, reg1, reg2, reg3];
struct inst {
opcode: cpu_opcode;
op1: cpu_reg;
op2: byte;

e Language Reference 22-89


Predefined Methods
get_unique_buckets()

event done;
cover done is {
item opcode;
item op1;
item op2;
cross opcode, op1 using name = opcode_op1;
};
};
extend sys {
pre_generate() is also {
var bl_1: list of string =
covers.get_contributing_runs("inst.done.opcode",
"ADD");
var bl_2: list of string =
covers.get_contributing_runs("inst.done.opcode_op1",
"ADD/reg2");
var bl_3: list of string =
covers.get_contributing_runs("inst.done.opcode_op1",
"SUB");
};
};
'>

See Also
• “Test Identification Items” on page 7-78 in the Usage and Concepts Guide for e Testbenches
• “Bucket Hierarchy” on page 7-42 in the Usage and Concepts Guide for e Testbenches
• “Default Buckets” on page 7-51 in the Usage and Concepts Guide for e Testbenches

22.8.6 get_unique_buckets()

Purpose
Return a list of the names of unique buckets from specific tests.

Category
Predefined method

Syntax
covers.get_unique_buckets(file-name: string): list of string

22-90 e Language Reference


Predefined Methods
get_unique_buckets()

Syntax Example
print covers.get_unique_buckets("test_rx")

Parameters

file-name A string, enclosed in double quotes, specifying the coverage database files for
which you want to see unique buckets. You cannot use wild cards in the file name.

Description
A unique bucket is a bucket that is covered by only one test. This command reports, for each specified
test, the full names of its unique buckets, if there are any.

Note
You must rank the tests with the rank cover command before calling covers.get_unique_buckets().

Example
The following example shows how to display a list of unique buckets that are covered by a test. The
results of the test ranking show that the test “CPU_tst2_1” has three unique buckets. Passing this test
name to covers.get_unique_buckets() retrieves the names of the buckets.
vrst-tool> restore top // Restore the cover definitions
Specman CPU_top> read cover * // Read in test data
Reading CPU_tst1_1.ecov ...
Reading CPU_tst2_1.ecov ...
Reading CPU_tst3_7.ecov ...
Reading CPU_tst4_7.ecov ...
Reading CPU_tst8_7.ecov ...

5 coverage files read in.


Specman CPU_top> rank cover -sort_only // Rank the tests

Coverage Ranking Report


========================

Specman Coverage Test-Ranking report


====================================

Command: rank cover -sort_only *.*.*


Grading_formula: linear
Ranking Cost: cpu_time
At least multiplier: 1

e Language Reference 22-91


Predefined Methods
set_external_cover()

Number of tests: 5
Maximal Grade: 0.87
Note: All test grades are given as precentage from Maximal
Grade

The Sorted Test List:


-----------------------
Cum. Rel. Cum. Abs. Effic-
Num Test name Grade Grade Cost Cost Grade iency UB
--- ------------------------- ------ ------ ----- ----- ---- ------ ----
1 CPU_tst3_7 N/A N/A N/A 7 0.86 0.74 0
2 CPU_tst4_7 N/A N/A N/A 7 0.86 0.74 0
3 CPU_tst8_7 N/A N/A N/A 7 0.86 0.74 0
4 CPU_tst2_1 N/A N/A N/A 7 0.85 0.72 3
5 CPU_tst1_1 N/A N/A N/A 6 0.66 0.66 0
--- --------------------------- ------ ------ ------ ------ ------
Specman CPU_top> print covers.get_unique_buckets("CPU_tst2_1")
covers.get_unique_buckets("CPU_tst2_1") =
0. "instr.start_drv_DUT.cross__opcode__carry: ANDI/1"
1. "instr.start_drv_DUT.cross__opcode__carry: XORI/1"
2. "instr.start_drv_DUT.cross__opcode__carry: NOP/1"
Specman CPU_top>

See Also
• “Test Identification Items” on page 7-78 in the Usage and Concepts Guide for e Testbenches
• “Bucket Hierarchy” on page 7-42 in the Usage and Concepts Guide for e Testbenches
• “Default Buckets” on page 7-51 in the Usage and Concepts Guide for e Testbenches

22.8.7 set_external_cover()

Purpose
Enable or disable the import and display of SureCov data

Category
Predefined method

Syntax
set_external_cover(“surecov”, bool);

22-92 e Language Reference


Predefined Methods
write_cover_file()

Syntax Example
covers.set_external_cover("surecov", FALSE);

Parameters

bool TRUE, the default, enables the import of all SureCov data. FALSE disables
the import.

Description
By default, coverage data is collected for all defined SureCov coverage items and groups. This method
disables all import of SureCov data, even if SureCov coverage groups are defined. If disabled, all
additional behavior regarding SureCov is cancelled and the SureCov groups are not displayed.

You can call set_external_cover() at any time during a run.

Example
This example shows how to turn off the import and display of SureCov data.
<'
extend sys {
setup() is also {
covers.set_external_cover("surecov", FALSE);
};
};
'>

See Also
• “Integrating SureCov Data” on page 7-62 in Usage and Concepts Guide for e Testbenches
• cover … using external=surecov on page 16-49

22.8.8 write_cover_file()

Purpose
Write the coverage results during a test

e Language Reference 22-93


Predefined Methods
get_overall_grade()

Category
Predefined method

Syntax
write_cover_file();

Syntax Example
write_cover_file();

Description
This method writes the coverage results .ecov file during a test run. It can only be invoked during a test,
not before the run starts nor after it ends.

The coverage file written by this method does not contain the session.end_of_test or session.events
coverage groups.

Example
This example writes the current coverage results to the .ecov file whenever the event named sys.cntr is
emitted.
<'
struct top {
event wr_cov is @sys.cntr;
on wr_cov {
write_cover_file();
};
};
'>

See Also
• configure cover on page 6-3 in the Specman Command Reference

22.8.9 get_overall_grade()

Purpose
Return the normalized overall coverage grade

22-94 e Language Reference


Predefined Methods
get_overall_grade()

Category
Predefined method

Syntax
covers.get_overall_grade(): int;

Syntax Example
grade = covers.get_overall_grade();

Description
This method returns an integer that represents the overall coverage grade for the current coverage
results. Since Specman does not handle floating point types, the value is a normalized value between 1
and 100M. To obtain a value equivalent to the overall grade, divide the returned value by 100M.

Example
<'
struct top{
event e;
a: uint(bits: 4);
b: uint(bits: 4);
cover e is {
item a;
item b;
};
run() is also {emit e;};
};

extend sys {
toplist[10]: list of top;
finalize() is also {
var grade: int;
grade = covers.get_overall_grade();
print grade;
};
};
'>

See Also
• “Coverage Grading” on page 7-41 in the Usage and Concepts Guide for e Testbenches

e Language Reference 22-95


Predefined Methods
get_ecov_name()

• get_ecov_name() on page 22-96


• get_test_name() on page 22-97
• get_seed() on page 22-98

22.8.10 get_ecov_name()

Purpose
Return the name of the .ecov file

Category
Predefined method

Syntax
covers.get_ecov_name(): string;

Syntax Example
ecov_file = covers.get_ecov_name();

Description
This method returns the name of the .ecov file in which the current coverage results will be stored.

Example
<'
extend sys {
finalize() is also {
var ecov_file: string;
ecov_file = covers.get_ecov_name();
print ecov_file;
};
};
'>

See Also
• configure cover on page 6-3 in the Specman Command Reference

22-96 e Language Reference


Predefined Methods
get_test_name()

• get_overall_grade() on page 22-94


• get_test_name() on page 22-97
• get_seed() on page 22-98

22.8.11 get_test_name()

Purpose
Return the name of the most recently loaded e file (the file containing the top module for the current test)

Category
Predefined method

Syntax
covers.get_test_name(): string;

Syntax Example
test_file = covers.get_test_name();

Description
This method returns the name of the most recently loaded e file, minus the .e extension.

When you execute this method in code, the most recently loaded e file is the file that contains the top
module for the current test. The name of this file is generally referred to as the test name. Thus, you can
think of this method as a way to return the current test name.

Example
<'
extend sys {
finalize() is also {
var test_id: string;
test_id = covers.get_test_name();
print test_id;
};
};
'>

e Language Reference 22-97


Predefined Methods
get_seed()

Result

test_id = "cpu_test1"

This result tells you that the file “cpu_test1.e” contains the top module for the current test.

See Also
• configure cover on page 6-3 in the Specman Command Reference
• get_overall_grade() on page 22-94
• get_ecov_name() on page 22-96
• get_seed() on page 22-98

22.8.12 get_seed()

Purpose
Return the value of the seed for the current test

Category
Predefined method

Syntax
covers.get_seed(): int

Syntax Example
seed_val= covers.get_seed();

Description
This method returns the current test seed.

Example
<'
extend sys {
finalize() is also {

22-98 e Language Reference


Predefined Methods
Time Conversion Methods

var test_seed: int;


test_seed = covers.get_seed();
print test_seed;
};
};
'>

Result

test_seed = 1

See Also
• configure cover on page 6-3 in the Specman Command Reference
• get_overall_grade() on page 22-94
• get_ecov_name() on page 22-96
• get_test_name() on page 22-97

22.9 Time Conversion Methods


The following methods are useful for manipulating expressions of type time:

• from_specman_scale() on page 22-99


• to_specman_scale() on page 22-101

22.9.1 from_specman_scale()

Purpose
Convert a time expression to a specified time scale

Category
Pseudo-method

Syntax
from_specman_scale(exp: time, unit: time-unit-designator): time

e Language Reference 22-99


Predefined Methods
from_specman_scale()

Syntax Example
out("Time ", from_specman_scale(sys.time,fs));

Parameters

exp An expression of type time. (Expressions of type uint or


int are automatically converted to type time.).

unit One of the time unit designators defined by the


enumerated type e_time_units: fs, ps, ns, us, ms, sec,
min, hr. This designator specifies the time scale of the
returned value.

Description
Converts an expression of type time from the Specman time scale to the specified time scale and returns
the result as an expression of type time. You can use this method to print and display values consistently,
regardless of what Specman time scale is used in other parts of the verification environment.

Note
• If the Specman time scale does not have sufficient precision for the scaling operation, this method
returns 0.

Example 1
<'
verilog time 1ns/1ps; -- defines the Specman time scale
extend sys {
run() is also {
out("Time ", from_specman_scale(sys.time,fs));
};
};
'>

Results
Assuming sys.time is 10, the above call to out() prints:
Time 10000000 fs

22-100 e Language Reference


Predefined Methods
to_specman_scale()

Example 2
The following code prints the variable “delay” in nanoseconds, regardless of what the Specman time
scale is.
<'
verilog time 1ps/1ps; -- defines the Specman time scale
extend sys {
clock_period: time;
keep clock_period == 2 ns;
run() is also {
out("Duty cycle is ", from_specman_scale(clock_period/2,ns));
};
};
'>

Results
Duty cycle is 1

See Also
• to_specman_scale() on page 22-101

22.9.2 to_specman_scale()

Purpose
Convert a time expression to the Specman time scale

Category
Pseudo-method

Syntax
to_specman_scale(exp: time, unit: time-unit-designator): time

Syntax Example
wait delay(to_specman_scale(clock_period, ns));

e Language Reference 22-101


Predefined Methods
to_specman_scale()

Parameters

exp An expression of type time. (Expressions of type uint or


int are automatically converted to type time.).

unit One of the time unit designators defined by the


enumerated type e_time_units: fs, ps, ns, us, ms, sec,
min, hr. This designator specifies the time unit of the
expression to be converted.

Description
Converts an expression from the specified time scale to the Specman time scale and returns the result as
an expression of type time. This method is useful to convert expressions into the appropriate time scale
for the simulator. For example, you can define delay expressions independent of time scale or simulator
and use this method to convert the expression to the appropriate time scale.

Note
• If the Specman time scale does not have sufficient precision for the scaling operation, this method
returns 0.

Example 1
This example shows how you can specify a delay in nanoseconds, regardless of what the Specman time
scale is.

top.v
`timescale 1ps/1ps

module top;
reg clk;

initial clk = 1;

always clk = #500 ~clk;

endmodule

top1.e
<'
verilog time 1ps/1ps;

22-102 e Language Reference


Predefined Methods
to_specman_scale()

extend sys {
clock_period : uint;
keep clock_period == 1;

event clk is rise('top.clk');

write() @clk is {
wait delay(to_specman_scale(clock_period, ns));
print sys.time;
set_config(print, scale, ns);
print sys.time;
stop_run();
};

run() is also {
start write();
};
};

'>

Results
sys.time = 2000
sys.time = 2 ns

Example 2
This example has similar results to “Example 1” on page 22-102, except that a field of type time is used,
instead of a field of type uint. In this approach, to_specman_scale() is not required because the
conversion is performed implicitly when the field clock_period is generated as “1 ns”.

top.e
<'
verilog time 1ps/1ps;

extend sys {
clock_period : time;
keep clock_period == 1 ns;

event clk is rise('top.clk');

write() @clk is {
wait delay(clock_period);

e Language Reference 22-103


Predefined Methods
to_specman_scale()

print sys.time;
set_config(print, scale, ns);
print sys.time;
stop_run();
};

run() is also {
start write();
};
};

'>

Results
sys.time = 2000
sys.time = 2 ns

See Also
• from_specman_scale() on page 22-99

22-104 e Language Reference


23 List Pseudo-Methods
This chapter describes pseudo-methods used to work with lists. It contains the following sections:

• “Pseudo-Methods Overview” on page 23-1


• “Using List Pseudo-Methods” on page 23-2
• “Pseudo-Methods to Modify Lists” on page 23-3
• “General List Pseudo-Methods” on page 23-27
• “Sublist Pseudo-Methods” on page 23-71
• “Math and Logic Pseudo-Methods” on page 23-77
• “List CRC Pseudo-Methods” on page 23-85
• “Keyed List Pseudo-Methods” on page 23-91
• “Restrictions on Keyed Lists” on page 23-98

23.1 Pseudo-Methods Overview


A pseudo-method is a type of method unique to the e language. Pseudo-methods are e macros that look
like methods. They have the following characteristics:

• Unlike methods, pseudo-methods are not restricted to structs.


• They can be applied to any expression, including literal values, scalars, and compound arithmetic
expressions.
• You cannot extend pseudo-methods.
• You can define your own pseudo-methods using define as on page 19-1 or define as computed on
page 19-10.

e Language Reference 23-1


List Pseudo-Methods
Using List Pseudo-Methods

• The Specman debugger does not recognize pseudo-methods.


• List pseudo-methods are associated with list data types, as opposed to being within the scope of a
struct.

See Also
• “e Data Types” on page 3-1
• list-method() on page 2-86
• in on page 2-62
• Chapter 22 “Predefined Methods”

23.2 Using List Pseudo-Methods


Once a list field or variable has been declared, you can operate on it with a list pseudo-method by
attaching the pseudo-method name, preceded by a period, to the list name. Any parameters required by
the pseudo-method go in parentheses after the pseudo-method name.

Many of the list pseudo-methods take expressions as parameters, an operate on every item in the list.

For example, the following calls the apply() pseudo-method for the list named “p_list”, with the
expression “.length + 2” as a parameter. The pseudo-method returns a list of numbers found by adding 2
to the “length” field value in each item in the list.
n_list = p_list.apply(.length + 2);

It is important to put a period (.) in front of field names being accessed by pseudo-methods, as in
“.length +2”, above.

In pseudo-methods that take expressions as parameters, the it variable can be used in the expression to
refer to the current list item, and the index variable can be used to refer to the current item’s list index
number.

Pseudo-methods that return values can only be used in expressions.

See Also
• “Pseudo-Methods Overview” on page 23-1
• “e Data Types” on page 3-1
• list-method() on page 2-86

23-2 e Language Reference


List Pseudo-Methods
Pseudo-Methods to Modify Lists

23.3 Pseudo-Methods to Modify Lists


This section describes the pseudo-methods that change one or more items in a list.

The pseudo-methods in this section are:

• add(item) on page 23-3


• add(list) on page 23-5
• add0(item) on page 23-7
• add0(list) on page 23-9
• clear() on page 23-10
• delete() on page 23-11
• fast_delete() on page 23-13
• insert(index, item) on page 23-15
• insert(index, list) on page 23-16
• pop() on page 23-18
• pop0() on page 23-19
• push() on page 23-20
• push0() on page 23-21
• resize() on page 23-23

See Also
• “Pseudo-Methods Overview” on page 23-1
• “Using List Pseudo-Methods” on page 23-2

23.3.1 add(item)

Purpose
Add an item to the end of a list

e Language Reference 23-3


List Pseudo-Methods
add(item)

Category
Pseudo-method

Syntax
list.add(item: list-type)

Syntax Example
var i_list: list of int;
i_list.add(5);

Parameters

list A list.

item An item of the same type as the list type, which is to be added to the list. The item is added
at index list.size(). That is, if the list contains five items, the last item is at index list.size() -
1, or 4. Adding an item to this list places it at index 5.

Description
Adds the item to the end of the list.

If the item is a struct, no new struct instance is generated, a pointer to the existing instance of the struct
is simply added to the list. For information about creating new structs, use the new, gen, copy(),
deep_copy(), and unpack() links in the “See Also” list below.

Example 1
The following adds 2 to the end of the list named “i_list” (that is, to index position 3).
var i_list: list of int = {3; 4; 6};
i_list.add(2);

Result
print i_list
i_list =
0. 3
1. 4
2. 6
3. 2

23-4 e Language Reference


List Pseudo-Methods
add(list)

Example 2
The following generates an instance of a “packet” struct and adds it to the list of packets named “p_lst”.
struct p_l {
!packet_i: packet;
!p_lst: list of packet;
mk_lst()@sys.clk is {
gen packet_i;
p_lst.add(packet_i);
stop_run();
};
};

See Also
• new on page 2-90
• gen on page 11-55
• The copy() Method of any_struct on page 22-20
• deep_copy() on page 24-2
• unpack() on page 18-31
• add(list) on page 23-5
• add0(item) on page 23-7
• add0(list) on page 23-9
• insert(index, item) on page 23-15
• insert(index, list) on page 23-16
• push() on page 23-20
• push0() on page 23-21
• resize() on page 23-23

23.3.2 add(list)

Purpose
Add a list to the end of another list

e Language Reference 23-5


List Pseudo-Methods
add(list)

Category
Pseudo-method

Syntax
list_1.add(list_2: list)

Syntax Example
i_list.add(l_list);

Parameters

list_1 A list.

list_2 A list of the same type as list_1, which is to be added to the end of list_1. The list is added
at index list.size(). That is, if the list contains five lists, the last list is at index list.size() - 1,
or 4. Adding a list to this list places it at index 5.

Description
Adds list_2 to the end of list_1.

Example 1
The following adds “blue”, “green”, and “red” to the list named “colors_1”.
<'
type color: [blue, green, yellow, orange, red];
extend sys {
run() is also {
var colors_1: list of color = {red; red; blue};
var colors_2: list of color = {blue; green; red};
colors_1.add(colors_2);
print colors_1;
};
};
'>

Example 2
The following example adds the literal list {“blue”; “green”; “red”} to the list named “colors_3”. The
“colors_3” list then contains “red”, “red”, “blue”, “blue”, “green”, “red”.
var colors_3 := {"red"; "red"; "blue"};

23-6 e Language Reference


List Pseudo-Methods
add0(item)

colors_3.add({"blue"; "green"; "red"});

See Also
• add(item) on page 23-3
• add0(item) on page 23-7
• add0(list) on page 23-9
• insert(index, item) on page 23-15
• insert(index, list) on page 23-16
• push() on page 23-20
• push0() on page 23-21
• resize() on page 23-23

23.3.3 add0(item)

Purpose
Add an item to the head of a list

Category
Pseudo-method

Syntax
list.add0(item: list-type)

Syntax Example
var l_list: list of int = {4; 6; 8};
l_list.add0(2);

Parameters

list A list.

item An item of the same type as the list items, which is to be added to the head of the list.

e Language Reference 23-7


List Pseudo-Methods
add0(item)

Description
Adds a new item to an existing list. The item is placed at the head of the existing list, as the first position
(that is, at index 0). All subsequent items are then reindexed by incrementing their old index by one.

If the item is a struct, no new struct instance is generated: a pointer to the existing instance of the struct
is simply added to the list. For information about generating new struct instances, use the new, gen, and
unpack() links in the “See Also” list below.

Example
The following example adds 1 to the beginning of the list named “i_list”. The “i_list” then contains 1, 1,
2, 3, 4, 5.
var i_list: list of int = {1;2;3;4;5};
i_list.add0(1);

See Also
• new on page 2-90
• gen on page 11-55
• The copy() Method of any_struct on page 22-20
• deep_copy() on page 24-2
• unpack() on page 18-31
• add(item) on page 23-3
• add(list) on page 23-5
• add0(list) on page 23-9
• insert(index, item) on page 23-15
• insert(index, list) on page 23-16
• push() on page 23-20
• push0() on page 23-21
• resize() on page 23-23

23-8 e Language Reference


List Pseudo-Methods
add0(list)

23.3.4 add0(list)

Purpose
Add a list to the head of another list

Category
Pseudo-method

Syntax
list_1.add0(list_2: list)

Syntax Example
var i_list: list of int = {1; 3; 5};
var l_list: list of int = {2; 4; 6};
i_list.add0(l_list);

Parameters

list_1 A list.

list_2 A list of the same type as list_1, which is to be added to the beginning of list_1 (at list_1
index 0)

Description
Adds a new list to an existing list. The list_2 list is placed at the head of the existing list_1 list, starting
at the first list_1 index. All subsequent items are then reindexed by incrementing their old index by the
size of the new list being added.

Example
The following adds 1, 2, 3, and 4 to the beginning of the list named “b_list”. The “b_list” then contains
1, 2, 3, 4, 5, 6.
var a_list: list of int = {1;2;3;4};
var b_list: list of int = {5;6};
b_list.add0(a_list);

e Language Reference 23-9


List Pseudo-Methods
clear()

Note
b_list.add0(a) returns the same result as a_list.add(b) in the above example, except that in the example,
“b_list” is added into “a_list”, while b_list.add0(a) adds “a_list” into “b_list”.

See Also
• add(item) on page 23-3
• add(list) on page 23-5
• add0(item) on page 23-7
• insert(index, item) on page 23-15
• insert(index, list) on page 23-16
• push() on page 23-20
• push0() on page 23-21
• resize() on page 23-23

23.3.5 clear()

Purpose
Delete all items from a list

Category
Pseudo-method

Syntax
list.clear()

Syntax Example
a_list.clear();

Parameters

list A list.

23-10 e Language Reference


List Pseudo-Methods
delete()

Return Value
None

Description
Deletes all items in the list.

Example
The following removes all items from the list named “l_list”.
l_list.clear();

See Also
• delete() on page 23-11
• fast_delete() on page 23-13
• resize() on page 23-23
• pop() on page 23-18
• pop0() on page 23-19

23.3.6 delete()

Purpose
Delete an item from a list

Category
Pseudo-method

Syntax
list.delete(index: int)

Syntax Example
var l_list: list of int = {2; 4; 6; 8};
l_list.delete(2);

e Language Reference 23-11


List Pseudo-Methods
delete()

Parameters

list A list.

index The index of the item that is to be deleted from the list.

Description
Removes item number index from list (indexes start counting from 0). The indexes of the remaining
items are adjusted to keep the numbering correct.

If the index does not exist in the list, an error is issued.

Note In a keyed list, if two or more list items have the same key, the results of using list
pseudo-methods are unpredictable. See “Keyed List Pseudo-Methods” on page 23-91.

Example 1
The following deletes 7 from index position 1 in the list named “y_list”. The list then consists of 5
(index 0) and 9 (index 1).
var y_list := {5; 7; 9};
y_list.delete(1);

Example 2
Since list.delete() only accepts a single item as its argument, you cannot use it to delete a range of items
in one call. This example shows a way to do that.

The following shows a user-defined method named del_range() which, given a list, a from value, and a
to value, produces a new list (with the same name) of the items in the previous list, minus the items with
indexes in the given range. If the range of values is not legal for the given list, the method fails with an
error message.
<'
extend sys {
my_list: list of byte;
keep my_list.size() == 20;

del_range(in_l:list of byte,from:int,to:int):list of byte


is {
result.add(in_l[..from-1]);
result.add(in_l[to+1..]);
};

23-12 e Language Reference


List Pseudo-Methods
fast_delete()

post_generate() is also {
my_list = del_range(my_list,5,15);
};
};
'>

See Also
• clear() on page 23-10
• fast_delete() on page 23-13
• pop() on page 23-18
• pop0() on page 23-19
• resize() on page 23-23
• first_index() on page 23-37
• get_indices() on page 23-39
• last_index() on page 23-47
• max_index() on page 23-50
• min_index() on page 23-55

23.3.7 fast_delete()

Purpose
Delete an item without adjusting all indexes

Category
Pseudo-method

Syntax
list.fast_delete(index: int)

Syntax Example
var l_list: list of int = {2; 4; 6; 8};
l_list.fast_delete(2);

e Language Reference 23-13


List Pseudo-Methods
fast_delete()

Parameters

list A list.

index The index that is to be deleted from the list.

Description
Removes item number index from list (indexes start counting from 0). The index of the last item in the
list is changed to the index of the item that was deleted, so all items following the deleted item keep their
original indexes except that the original last index is removed.

If the index does not exist in the list, an error is issued.

Example
The following deletes “C” from index position 2 in the list named “y_list”, and changes the index of the
last item from 4 to 2. The new “y_list” is “A”, “B”, “E”, “D”.
<'
extend sys {
run() is also {
var y_list := {"A"; "B"; "C"; "D"; "E"};
y_list.fast_delete(2);
for i from 0 to 3 do {
print y_list[i];
};
};
};
'>

See Also
• clear() on page 23-10
• delete() on page 23-11
• pop() on page 23-18
• pop0() on page 23-19
• resize() on page 23-23
• first_index() on page 23-37
• get_indices() on page 23-39

23-14 e Language Reference


List Pseudo-Methods
insert(index, item)

• last_index() on page 23-47


• max_index() on page 23-50
• min_index() on page 23-55

23.3.8 insert(index, item)

Purpose
Insert an item in a list at a specified index

Category
Pseudo-method

Syntax
list.insert(index: int, item: list-type)

Syntax Example
var l_list := {10; 20; 30; 40; 50};
l_list.insert(3, 99);

Parameters

list A list.

index The index in the list where the item is to be inserted.

item An item of the same type as the list.

Description
Inserts the item at the index location in the list. If index is the size of the list, then the item is simply
added at the end of the list. All indexes in the list are adjusted to keep the numbering correct.

If the number of items in the list is smaller than index, an error is issued.

If the item is a struct, no new struct instance is generated: a pointer to the existing instance of the struct
is simply added to the list. For information about generating new struct instances, use the new, gen, and
unpack() links in the “See Also” list below.

e Language Reference 23-15


List Pseudo-Methods
insert(index, list)

Example
In the following example, 10 is first inserted into position 2 in “s_list”, and then 77 is inserted into
position 1. The resulting list contains 5, 77, 1, 10.
var s_list := {5; 1};
s_list.insert(2,10);
s_list.insert(1,77);

See Also
• new on page 2-90
• gen on page 11-55
• The copy() Method of any_struct on page 22-20
• deep_copy() on page 24-2
• unpack() on page 18-31
• add(item) on page 23-3
• add(list) on page 23-5
• add0(item) on page 23-7
• add0(list) on page 23-9
• insert(index, list) on page 23-16
• push() on page 23-20
• push0() on page 23-21
• resize() on page 23-23

23.3.9 insert(index, list)

Purpose
Insert a list in another list starting at a specified index

Category
Pseudo-method

23-16 e Language Reference


List Pseudo-Methods
insert(index, list)

Syntax
list_1.insert(index: int, list_2: list)

Syntax Example
var l_list := {10; 20; 30; 40; 50};
var m_list := {11; 12; 13};
l_list.insert(1, m_list);

Parameters

list_1 A list.

index The index of the position in list_1 where list_2 is to be inserted.

list_2 A list that is to be inserted into list_1.

Description
Inserts all items of list_2 into list_1 starting at index. The index must be a positive integer. The size of
the new list size is equal to the sum of the sizes of list_1 and list_2.

If the number of items in list_1 is smaller than index, an error is issued.

Example
In the following example, “blue”, “green”, and “red” are inserted after “red” in the “colors_1” list. The
“colors_l” list is then “red”, “blue”, “green”, “red”, “green”, “blue”.
var colors_14 := {"red"; "green"; "blue"};
var colors_15 := {"blue"; "green"; "red"};
colors_14.insert(1, colors_15);

See Also
• add(item) on page 23-3
• add(list) on page 23-5
• add0(item) on page 23-7
• add0(list) on page 23-9
• insert(index, item) on page 23-15
• push() on page 23-20

e Language Reference 23-17


List Pseudo-Methods
pop()

• push0() on page 23-21


• resize() on page 23-23

23.3.10 pop()

Purpose
Remove and return the last list item

Category
Pseudo-method

Syntax
list.pop(): list-type

Syntax Example
var i_list:= {10; 20; 30};
var i_item: int;
i_item = i_list.pop();

Parameters

list A list.

Description
Removes the last item (the item at index list.size() - 1) in the list and returns it. If the list is empty, an
error is issued.

Note
Use list.top() to return the last item in list without removing it from the list.

Example
In the following example, the “s_item” variable gets “d”, and the “s_list” becomes “a”, “b”, “c”.
var s_item: string;

23-18 e Language Reference


List Pseudo-Methods
pop0()

var s_list := {"a"; "b"; "c"; "d"};


s_item = s_list.pop();

See Also
• pop0() on page 23-19
• delete() on page 23-11
• top() on page 23-67

23.3.11 pop0()

Purpose
Remove and return the first list item

Category
Pseudo-method

Syntax
list.pop0(): list-type

Syntax Example
var i_list:= {10; 20; 30};
var i_item: int;
i_item = i_list.pop0();

Parameters

list A list.

Description
Removes the first item (the item at index 0) from the list and returns it. Subtracts 1 from the index of
each item remaining in the list. If the list is empty, an error is issued.

e Language Reference 23-19


List Pseudo-Methods
push()

Note
Use list.top0() to return the first item in list without removing it from the list.

Example
In the following example, the “s_item” variable gets “a” and “s_list” becomes “b”, “c”, “d”.
var s_item: string;
var s_list := {"a"; "b"; "c"; "d"};
s_item = s_list.pop0();

See Also
• delete() on page 23-11
• pop() on page 23-18
• top0() on page 23-68

23.3.12 push()

Purpose
Add an item to the end of a list (same as add(item) on page 23-3)

Category
Pseudo-method

Syntax
list.push(item: list-type)

Syntax Example
var i_list: list of int;
i_list.push(5);

Parameters

list A list.

23-20 e Language Reference


List Pseudo-Methods
push0()

item An item of the same type as the list type, which is to be added to the list. The item is added
at index list.size(). That is, if the list contains five items, the last item is at index list.size() -
1, or 4. Adding an item to this list places it at index 5.

Description
This pseudo-method performs the same function as add(item) on page 23-3.

If the item is a struct, no new struct instance is generated: a pointer to the existing instance of the struct
is simply added to the list. For information about generating new struct instances, use the new, gen, and
unpack() links in the “See Also” list below.

See Also
• new on page 2-90
• gen on page 11-55
• The copy() Method of any_struct on page 22-20
• deep_copy() on page 24-2
• unpack() on page 18-31
• add(item) on page 23-3
• add(list) on page 23-5
• add0(item) on page 23-7
• add0(list) on page 23-9
• insert(index, item) on page 23-15
• insert(index, list) on page 23-16
• push0() on page 23-21

23.3.13 push0()

Purpose
Add an item to the head of a list (same as add0(item) on page 23-7)

e Language Reference 23-21


List Pseudo-Methods
push0()

Category
Pseudo-method

Syntax
list.push0(item: list-type)

Syntax Example
var l_list: list of int = {4; 6; 8};
l_list.push0(2);

Parameters

list A list.

item An item of the same type as the list items, which is to be added to the head of the list.

Description
This pseudo-method performs the same function as add0(item) on page 23-7.

If the item is a struct, no new struct instance is generated: a pointer to the existing instance of the struct
is simply added to the list. For information about generating new struct instances, use the new, gen, and
unpack() links in the “See Also” list below.

See Also
• new on page 2-90
• gen on page 11-55
• The copy() Method of any_struct on page 22-20
• deep_copy() on page 24-2
• unpack() on page 18-31
• add(item) on page 23-3
• add(list) on page 23-5
• add0(item) on page 23-7
• add0(list) on page 23-9
• insert(index, item) on page 23-15

23-22 e Language Reference


List Pseudo-Methods
resize()

• insert(index, list) on page 23-16


• push() on page 23-20

23.3.14 resize()

Purpose
Change the size of a list

Category
Pseudo-method

Syntax
list.resize(size: int [, full: bool, filler: exp, keep_old: bool])

Syntax Example
var r_list := {2; 3; 5; 6; 8; 9};
r_list.resize(10, TRUE, 1, TRUE);

Parameters

list A list.

size A positive integer specifying the desired size.

full A Boolean value specifying all items will be filled with filler. Default: TRUE.

filler An item of the same type of the list items, used as a filler when FULL is TRUE.

keep_old A Boolean value specifying whether to keep existing items already in the list. Default:
FALSE.

Description
Allocates a new list of declared size, or resizes an old list if keep_old is TRUE. If full is TRUE, sets all
new items to have filler as their value.

If only the first parameter, size, is used, this method allocates a new list of the given size and all items
are initialized to the default value for the list type.

e Language Reference 23-23


List Pseudo-Methods
resize()

If any of the three parameters after size are used, all three of them must be used.

To resize and list and keep its old values, set both full and keep_old to TRUE. If the list is made longer,
additional items with the value of filler are appended to the list.

Following is the behavior of this method for all combinations of full and keep_old.

• full is FALSE, keep_old is FALSE:


An empty list (that is, a list of zero size) is created, and memory is allocated for a list of the given
size.
• full is TRUE, keep_old is FALSE:
The list is resized to size, and filled completely with filler.
• full is FALSE, keep_old is TRUE:
• If size is greater than the size of the existing list, the list is enlarged to the new size, and the new
positions are filled with the default value of the list type.
• If size is less than or equal to the size of the existing list, the list is shortened to the new size, and
all of the existing values up to that size are retained.
• full is TRUE, keep_old is TRUE:
• If size is greater than the size of the existing list, the list is enlarged to the new size, and the new
positions are filled with filler.
• If size is less than or equal to the size of the existing list, the list is shortened to the new size, and
all of the existing values up to that size are retained.

Example 1
The following example puts 200 NULL “packet” instances into “q_list”. The initial size of the list is 0
when it is created by the var command. The packets are NULL because that is the default value for a
struct instance.
<'
struct packet {
len: uint;
addr: byte;
};
extend sys {
run() is also {
var q_list: list of packet;
print q_list.size();
q_list.resize(200);
print q_list.size();

23-24 e Language Reference


List Pseudo-Methods
resize()

};
};
'>

Result
q_list.size() = 0
q_list.size() = 200

Example 2
The following example puts 20 NULL strings in “r_list”. The initial size of the list is 0 when it is created
by the var command.
var r_list: list of string;
r_list.resize(20, TRUE, NULL, FALSE);
print r_list.size();
print r_list;

Result
r_list.size() = 20
r_list =
0. ""
1. ""
2. ""
3. ""
4. ""
5. ""
6. ""
7. ""
8. ""
9. ""
10. ""
11. ""
12. ""
13. ""
14. ""
15. ""
16. ""
17. ""
18. ""
19. ""

e Language Reference 23-25


List Pseudo-Methods
resize()

Example 3
The following example makes “s_list” an empty list, but allocates space for it to hold 20 integers. The
initial size of the list is 0 when it is created by the var command, since “full” is FALSE.
var s_list: list of int;
s_list.resize(20, FALSE, 0, FALSE);
print s_list.size();
print s_list;

Result
s_list.size() = 0
s_list = (empty)

Example 4
The following example adds four items to an existing list.
var r_list := {2; 3; 5; 6; 8; 9};
r_list.resize(10, TRUE, 1, TRUE);
print r_list.size();
print r_list;

Result
r_list.size() = 10
r_list =
0. 2
1. 3
2. 5
3. 6
4. 8
5. 9
6. 1
7. 1
8. 1
9. 1

Example 5
This example shortens an existing list.
var r_list := {2; 3; 5; 6; 8; 9};
r_list.resize(4, TRUE, 7, TRUE);
print r_list.size();
print r_list;

23-26 e Language Reference


List Pseudo-Methods
General List Pseudo-Methods

Result
r_list.size() = 4
r_list =
0. 2
1. 3
2. 5
3. 6

See Also
• add(item) on page 23-3
• add(list) on page 23-5
• add0(item) on page 23-7
• add0(list) on page 23-9
• insert(index, item) on page 23-15
• insert(index, list) on page 23-16
• push() on page 23-20
• push0() on page 23-21
• max_index() on page 23-50
• size() on page 23-59

23.4 General List Pseudo-Methods


This section describes the syntax for pseudo-methods that perform various operations on lists.

The pseudo-methods in this section are:

• apply() on page 23-29


• copy() on page 23-31
• count() on page 23-32
• exists() on page 23-33
• field on page 23-35
• first() on page 23-36
• first_index() on page 23-37

e Language Reference 23-27


List Pseudo-Methods
General List Pseudo-Methods

• get_indices() on page 23-39


• has() on page 23-40
• is_a_permutation() on page 23-42
• is_empty() on page 23-44
• last() on page 23-45
• last_index() on page 23-47
• max() on page 23-48
• max_index() on page 23-50
• max_value() on page 23-51
• min() on page 23-53
• min_index() on page 23-55
• min_value() on page 23-56
• reverse() on page 23-58
• size() on page 23-59
• sort() on page 23-61
• sort_by_field() on page 23-62
• split() on page 23-64
• top() on page 23-67
• top0() on page 23-68
• unique() on page 23-69

See Also
• “Pseudo-Methods Overview” on page 23-1
• “Using List Pseudo-Methods” on page 23-2

23-28 e Language Reference


List Pseudo-Methods
apply()

23.4.1 apply()

Purpose
Perform a computation on each item in a list

Category
Pseudo-method

Syntax
list.apply(item: exp): list

Syntax Example
var p_list:= {1; 3; 5};
var n_list: list of int;;
n_list = p_list.apply(it*2);

Parameters

list A list.

item Any expression. The it variable can be used to refer to the current list item, and the index
variable can be used to refer to its index number.

Description
Applies the exp to each item in the list and returns the changed list.

Note
The expression “list.apply(it.field)” is the same as “list.field” when field is a scalar type. For example,
the following expressions both return a concatenated list of the “addr” field in each packet item:
packets.apply(it.addr)
sys.packets.addr

The two expressions are different, however, if the field not scalar. For example, assuming that “data” is
a list of byte, the first expression returns a list containing the first byte of “data” of each packet item. The
second expression is a single item, which is the first item in the concatenated list of all “data” fields in
all packet items.

e Language Reference 23-29


List Pseudo-Methods
apply()

packets.apply(it.data[0])
packets.data[0]

Example 1
In the following example, the “n_list” in the sys struct gets a list of integers resulting from adding 1 to
each “len” value in the list of packets.
<'
struct packet {
len: uint;
addr: byte;
data: list of bit;
!%crc: uint;
};
extend sys {
p_list: list of packet;
!n_list: list of uint;
run() is also {
n_list = p_list.apply(it.len + 1);
};
};
'>

Example 2
In the following example, the “packet” struct contains a “get_crc()” method that calls the predefined
crc_32() on page 23-87. The “crc_plus” list gets the values returned by applying the “get_crc()” method
to every packet in the “p_list” list.
<'
struct packet {
%len: uint;
%addr: byte;
%data: list of byte;
!%crc: int;
get_crc(): int is {
return data.crc_32(0, data.size());
};
};
extend sys {
p_list: list of packet;
!crc_plus: list of int;
post_generate() is also {
crc_plus = p_list.apply(it.get_crc());
};
};

23-30 e Language Reference


List Pseudo-Methods
copy()

'>

Example 3
In the following example, the “ind_list” gets the indexes (0, 1, 2) of the items in the “l_list”.
var l_list: list of int = {5; 7; 9};
var ind_list: list of int = l_list.apply(index);
print ind_list;

See Also
• field on page 23-35
• all() on page 23-72

23.4.2 copy()

Purpose
Make a shallow copy of a list

Category
Predefined method of any struct or unit

Syntax
list.copy(): list

Syntax Example
var strlist_1: list of string = {"A"; "B"; "C"};
var strlist_2: list of string;
strlist_2 = strlist_1.copy();

Description
This is a specific case of exp.copy(), where exp is the name of a list. See The copy() Method of
any_struct on page 22-20 for additional information and examples.

e Language Reference 23-31


List Pseudo-Methods
count()

23.4.3 count()

Purpose
Return the number of items that satisfy a given condition

Category
Pseudo-method

Syntax
list.count(exp: bool): int

Syntax Example
var ct: int;
ct = instr_list.count(it.op1 > 200);

Parameters

list A list.

exp A Boolean expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the number of items for which the exp is TRUE.

Note
The syntax list.all(exp).size() returns the same result as the list.count(exp) pseudo-method, but
list.all(exp).size() creates a new list while list.count(exp) does not.

Example 1
The following example prints 3, since there are three items in “l_list” with values greater than 3.
var l_list: list of int = {2; 3; 4; 5; 6};
print l_list.count(it > 3)

23-32 e Language Reference


List Pseudo-Methods
exists()

Example 2
The following example prints the number of “packet” struct instances in the “packets” list that have a
“length” field value smaller than 5.
<'
struct packet {
length: uint (bits: 4);
};
extend sys {
packets: list of packet;
post_generate() is also {
var pl: int;
pl = packets.count(.length < 5);
print pl;
};
};
'>

See Also
• has() on page 23-40
• all() on page 23-72
• all_indices() on page 23-74
• key() on page 23-92
• key_exists() on page 23-97

23.4.4 exists()

Purpose
Check if an index exists in a list

Category
Pseudo-method

Syntax
list.exists(index: int): bool

e Language Reference 23-33


List Pseudo-Methods
exists()

Syntax Example
var i_chk: bool;
i_chk = packets.exists(5);

Parameters

list A list.

index An integer expression representing an index to the list.

Description
Returns TRUE if an item with the index number exists in the list, or returns FALSE if the index does not
exist.

Example
The first print action in the following prints TRUE, because the “int_list” contains an item with an
index of 1. The second print action prints FALSE, because there is no item with index 7 in the list.
<'
extend sys {
run() is also {
var int_lst: list of int = {1; 2; 3; 4; 5};
var ind_ex: bool;
ind_ex = int_lst.exists(1);
print ind_ex;
ind_ex = int_lst.exists(7);
print ind_ex;
};
};
'>

See Also
• first_index() on page 23-37
• all_indices() on page 23-74

23-34 e Language Reference


List Pseudo-Methods
field

23.4.5 field

Purpose
Specifying a field from all items in a list

Category
Pseudo-method

Syntax
list.field-name

Syntax Example
s_list.fld_nm

Parameters

list A list of structs.

field-name A name of a field or list in the struct type.

Description
Returns a list containing the contents of the specified field-name for each item in the list. If the list is
empty, it returns an empty list. This syntax is the same as list.apply(field).

An error is issued if the field name is not the name of a struct or if the struct type does not have the
specified field

Example
The following prints the values of the “length” fields in all the items in the “packets” list.
<'
struct packet {
length: uint;
};
extend sys {
packets: list of packet;
run() is also {

e Language Reference 23-35


List Pseudo-Methods
first()

print packets.length;
};
};
'>

See Also
• apply() on page 23-29

23.4.6 first()

Purpose
Get the first item that satisfies a given condition

Category
Pseudo-method

Syntax
list.first(exp: bool): list-type

Syntax Example
var i_item: instr;
i_item = instr_list.first(it.op1 > 15);

Parameters

list A list.

exp A Boolean expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the first item for which exp is TRUE. If there is no such item, the default for the item’s type is
returned (see “e Data Types” on page 3-1).

For a list of scalars, a value of zero is returned if there is no such item. Since zero might be confused
with a value found, it is safer to use list.first_index() for lists of scalars.

23-36 e Language Reference


List Pseudo-Methods
first_index()

Example 1
The first command below creates a list of five integers. The second command prints the first item in the
list smaller than 5 (that is, it prints 3).
var i_list :list of int = {8;3;7;3;4};
print i_list.first(it < 5 );

Example 2
In the following example, the list.first.() pseudo-method is used to make sure all items in the “packets”
list contain non-empty “cells” lists.
<'
struct cell {
data: list of byte;
};
struct packet {
cells: list of cell;
};
extend sys {
packets: list of packet;
post_generate() is also {
check that sys.packets.first(.cells is empty) == NULL;
};
};
'>

See Also
• first_index() on page 23-37
• has() on page 23-40
• last() on page 23-45

23.4.7 first_index()

Purpose
Get the index of the first item that satisfies a given condition

e Language Reference 23-37


List Pseudo-Methods
first_index()

Category
Pseudo-method

Syntax
list.first_index(exp: bool): int

Syntax Example
var i_item: int;
i_item = instr_list.first_index(it.op1 > 15);

Parameters

list A list.

exp A Boolean expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the index of the first item for which exp is TRUE or return UNDEF if there is no such item.

Example 1
The first command below creates a list of five integers. The second command prints 1, which is the
index of the first item in the list smaller than 5.
var i_list :list of int = {8;3;7;3};
print i_list.first_index(it < 5);

Example 2
In the following example, the list.first_index.() pseudo-method is used to make sure all items in the
“packets” list contain non-empty “cells” lists.
<'
struct cell {
data: list of byte;
};
struct packet {
cells: list of cell;
};
extend sys {
packets: list of packet;

23-38 e Language Reference


List Pseudo-Methods
get_indices()

post_generate() is also {
check that
packets.first_index(.cells is empty) == UNDEF;
};
};
'>

See Also
• first() on page 23-36
• has() on page 23-40
• last_index() on page 23-47

23.4.8 get_indices()

Purpose
Return a sublist of another list

Category
Pseudo-method

Syntax
list.get_indices(index-list: list of int): list-type

Syntax Example
var i_list: list of packet;
i_list = packets.get_indices({0; 1; 2});

Parameters

list A list.

index-list A list of indexes within the list. Each index must exist in the list.

e Language Reference 23-39


List Pseudo-Methods
has()

Description
Copies the items in list that have the indexes specified in index-list and returns a new list containing
those items. If the index-list is empty, an empty list is returned.

Example
The following example puts “green” and “orange” in the list named “o_list”.
var c_list := {"red"; "green"; "blue"; "orange"};
var o_list := c_list.get_indices({1;3});

See Also
• first_index() on page 23-37
• has() on page 23-40
• last_index() on page 23-47
• all_indices() on page 23-74

23.4.9 has()

Purpose
Check that a list has at least one item that satisfies a given condition

Category
Pseudo-method

Syntax
list.has(exp: bool): bool

Syntax Example
var i_ck: bool;
i_ck = sys.instr_list.has(it.op1 > 31);

23-40 e Language Reference


List Pseudo-Methods
has()

Parameters

list A list.

exp A Boolean expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns TRUE if the list contains at least one item for which the exp is TRUE, or returns FALSE if the
expression is not TRUE for any item.

Example 1
The first command below creates a list containing the integers 8, 3, 7, and 3. The second command
checks that the list contains 7, and prints TRUE.
var l: list of int = {8;3;7;3};
print l.has(it == 7);

Example 2
The command below checks that there is no packet in the “packets” list that contains an empty “cells”
list.
<'
struct cell {
data: list of byte;
};
struct packet {
cells: list of cell;
};
extend sys {
packets: list of packet;
post_generate() is also {
check that not sys.packets.has(.cells is empty);
};
};
'>

See Also
• first() on page 23-36
• last() on page 23-45

e Language Reference 23-41


List Pseudo-Methods
is_a_permutation()

• max() on page 23-48


• min() on page 23-53
• all() on page 23-72

23.4.10 is_a_permutation()

Purpose
Check that two lists contain exactly the same items

Category
Pseudo-method

Syntax
list_1.is_a_permutation(list_2: list): bool

Syntax Example
var lc: bool;
lc = packets_1a.is_a_permutation(packets_1b);

Parameters

list_1 A list.

list_2 A list that is to be compared to list_1. Must be the same type as list_1.

Description
Returns TRUE if list_2 contains the same items as list_1, or FALSE if any items in one list are not in the
other list. The order of the items in the two lists does not need to be the same, but the number of items
must be the same for both lists. That is, items that are repeated in one list must appear the same number
of times in the other list for one list to be a permutation of the other list.

Notes
• If the lists are lists of structs, list_1.is_a_permutation(list_2) compares the addresses of the struct
items, not their contents.

23-42 e Language Reference


List Pseudo-Methods
is_a_permutation()

• This pseudo-method can be used in a keep constraint to fill list_1 with the same items contained in
the list_2, although not necessarily in the same order.

Example 1
In the following example, the “l_comp” variable is TRUE because the two lists contain the same items.
<'
extend sys {
run() is also {
var l_1 := {1;3;5;7;9};
var l_2 := {1;9;7;3;5};
var l_comp: bool;
l_comp = l_1.is_a_permutation(l_2);
print l_comp;
};
};
'>

Example 2
In the following example, the keep constraint causes the list named “l_2” have the same items the
Specman generator puts in the list named “l_1”. Since “l_1” will have the same number of items as
“l_2”, there is an implicit constraint that “l_2” will be the same size at “l_1”. To constrain the size of the
two lists, you can specify a keep constraint on the size of either “l_1” or “l_2”. Using a keep soft
constraint to try to constrain the size of “l_2” is an error.
<'
extend sys {
l_1: list of int;
l_2: list of int;
keep l_2.is_a_permutation(l_1);
};
'>

See Also
• keep on page 11-20
• has() on page 23-40

e Language Reference 23-43


List Pseudo-Methods
is_empty()

23.4.11 is_empty()

Purpose
Check if a list is empty

Category
Pseudo-method

Syntax
list.is_empty(): bool

Syntax Example
var no_l: bool;
no_l = packets.is_empty();

Parameters

list A list.

Description
Returns TRUE if list is empty, or FALSE if the list is not empty.

Note
You can use “list is empty” as a synonym for “list.is_empty()”.

Similarly, you can use “list is not empty” to mean “not(list.is_empty())”.

Example 1
In the following example, the first print action prints TRUE because the “int_lst” is initially empty.
After an item is added, the second print action prints TRUE because the list is not empty.
<'
extend sys {
int_list: list of int;
run() is also {
var emp: bool;

23-44 e Language Reference


List Pseudo-Methods
last()

emp = int_list.is_empty();
print emp;
int_list.add(3);
emp = int_list is not empty;
print emp;
};
};
'>

Example 2
The following gives the same result as the “ck_instr()” method in the previous example.
ck_instr() is {
if int_list is not empty {
print int_list;
}
else {
outf("list is empty\n");
return;
};
};

See Also
• clear() on page 23-10
• exists() on page 23-33
• size() on page 23-59

23.4.12 last()

Purpose
Get the last item that satisfies a given condition

Category
Pseudo-method

Syntax
list.last(exp: bool): list-type

e Language Reference 23-45


List Pseudo-Methods
last()

Syntax Example
var i_item: instr;
i_item = sys.instr_list.last(it.op1 > 15);

Parameters

list A list.

exp A Boolean expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the last item in the list that satisfies the Boolean expression. If there is no such item, the default
for the item’s type is returned (see “e Data Types” on page 3-1).

For a list of scalars, a value of zero is returned if there is no such item. Since zero might be confused
with a found value, it is safer to use list.last_index() for lists of scalars.

Example 1
The first command below creates a list containing the integers 8, 3, 7, 3, and 4. The second command
prints 4.
var l :list of int = {8;3;7;3;4};
print l.last(it < 5);

Example 2
The command below checks that there is no packet in the “packets” list that contains an empty “cells”
list.
<'
struct cell {
data: list of byte;
};
struct packet {
cells: list of cell;
};
extend sys {
packets: list of packet;
post_generate() is also {
check that sys.packets.last(.cells is empty) == NULL;
};
};

23-46 e Language Reference


List Pseudo-Methods
last_index()

'>

See Also
• first() on page 23-36
• has() on page 23-40
• last_index() on page 23-47
• all() on page 23-72

23.4.13 last_index()

Purpose
Get the index of the last item that satisfies a given condition

Category
Pseudo-method

Syntax
list.last_index(exp: bool): int

Syntax Example
var i_item: int;
i_item = instr_list.last_index(it.op1 > 15);

Parameters

list A list.

exp A Boolean expression. The it variable can be used to refer to the current list
item, and the index variable can be used to refer to its index number.

Description
Returns the index of the last item for which exp is TRUE, or returns UNDEF if there is no such item.

e Language Reference 23-47


List Pseudo-Methods
max()

Example 1
The first command below creates a list containing the integers 8, 3, 7, 3, and 4. The second command
prints 3.
var l: list of int = {8;3;7;3;4};
print l.last_index(it == 3);

Example 2
The command below checks that every packet in the “packets” list has a non-empty “cells” list: if the
index of the last packet that has a non-empty “cells” list is one less than the size of the list, the check
succeeds.
check that
sys.packets.last_index(.cells is not empty) ==
sys.packets.size() - 1;

See Also
• first_index() on page 23-37
• has() on page 23-40
• last() on page 23-45
• all_indices() on page 23-74

23.4.14 max()

Purpose
Get the item with the maximum value of a given expression

Category
Pseudo-method

Syntax
list.max(exp: int): list-type

Syntax Example
var high_item: item_instance;

23-48 e Language Reference


List Pseudo-Methods
max()

high_item = item_list.max(it.f_1 + it.f_2);

Parameters

list A list.

exp An integer expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the item for which the exp evaluates to the largest value. If more than one item results in the
same maximum value, the item latest in the list is returned.

If the list is empty, an error is issued.

Example
In the example below, the “high_item” variable gets the “instr” instance that has the largest value of the
sum of “op1” and “op2”.
<'
struct instr {
op1: int;
op2: int;
};
extend sys {
instr_list: list of instr;
keep instr_list.size() > 5;
post_generate() is also {
var high_item: instr;
high_item = instr_list.max(.op1 + .op2);
};
};
'>

See Also
• has() on page 23-40
• max_index() on page 23-50
• max_value() on page 23-51
• min() on page 23-53

e Language Reference 23-49


List Pseudo-Methods
max_index()

• all() on page 23-72

23.4.15 max_index()

Purpose
Get the index of the item with the maximum value of a given expression

Category
Pseudo-method

Syntax
list.max_index(exp: int): int

Syntax Example
var item_index: index;
item_index = sys.item_list.max_index(it.f_1 + it.f_2);

Parameters

list A list.

exp An integer expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the index of the item for which the exp evaluates to the largest value. If more than one item
results in the same maximum value, the index of the item latest in the list is returned.

If the list is empty, and error is issued.

Example
In the example below, the “high_indx” variable gets the index of the “instr” instance that has the largest
value of the sum of “op1” and “op2”.
<'
struct instr {

23-50 e Language Reference


List Pseudo-Methods
max_value()

op1: int;
op2: int;
};
extend sys {
instr_list: list of instr;
keep instr_list.size() > 5;
post_generate() is also {
var high_indx: int;
high_indx = instr_list.max_index(.op1 + .op2);
};
};
'>

See Also
• first_index() on page 23-37
• has() on page 23-40
• last_index() on page 23-47
• max() on page 23-48
• max_value() on page 23-51
• min_index() on page 23-55
• all_indices() on page 23-74

23.4.16 max_value()

Purpose
Return the maximum value found by evaluating a given expression for all items

Category
Pseudo-method

Syntax
list.max_value(exp: int): (int | uint)

Syntax Example
var item_val: int;

e Language Reference 23-51


List Pseudo-Methods
max_value()

item_val = sys.item_list.max_value(it.f_1 + it.f_2);

Parameters

list A list.

exp An integer expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the largest integer value found by evaluating the exp for every item in the list. If more than one
item results in the same maximum value, the value of the expression for the item latest in the list is
returned.

For lists of integer types, one of the following is returned if the list is empty:

List Item Type Value Returned by list.max_value()

signed integer MIN_INT (see “Predefined Constants” on page 2-8)

unsigned integer zero

long integer error

Example 1
The example below prints the largest absolute value in the list of integers named “i_list”.
<'
extend sys {
i_list: list of int;
post_generate() is also {
print i_list.max_value(abs(it));
};
};
'>

Example 2
In the example below, the “high_val” variable gets the “instr” instance that has the largest value of the
sum of “op1” and “op2”.
<'
struct instr {

23-52 e Language Reference


List Pseudo-Methods
min()

op1: int;
op2: int;
};
extend sys {
instr_list: list of instr;
keep instr_list.size() < 10;
post_generate() is also {
var high_val: int;
high_val = instr_list.max_value(.op1 + .op2);
print high_val;
};
};
'>

See Also
• has() on page 23-40
• max() on page 23-48
• max_index() on page 23-50
• min_value() on page 23-56

23.4.17 min()

Purpose
Get the item with the minimum value of a given expression

Category
Pseudo-method

Syntax
list.min(exp: int): list-type

Syntax Example
var low_item: item_instance;
low_item = sys.item_list.min(it.f_1 + it.f_2);

e Language Reference 23-53


List Pseudo-Methods
min()

Parameters

list A list.

exp An integer expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the item for which the exp evaluates to the smallest value. If more than one item results in the
same minimum value, the item latest in the list is returned.

Example
In the example below, the “low_item” variable gets the “instr” instance that has the smallest value of the
sum of “op1” and “op2”.
<'
struct instr {
op1: int;
op2: int;
};
extend sys {
instr_list: list of instr;
keep instr_list.size() < 10;
post_generate() is also {
var low_item: instr;
low_item = instr_list.min(.op1 + .op2);
};
};
'>

See Also
• first() on page 23-36
• has() on page 23-40
• last() on page 23-45
• max() on page 23-48
• min_index() on page 23-55
• min_value() on page 23-56
• all() on page 23-72

23-54 e Language Reference


List Pseudo-Methods
min_index()

23.4.18 min_index()

Purpose
Get the index of the item with the minimum value of a given expression

Category
Pseudo-method

Syntax
list.min_index(exp: int): int

Syntax Example
var item_index: index;
item_index = sys.item_list.min_index(it.f_1 + it.f_2);

Parameters

list A list.

exp An integer expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Return the index of the item for which the specified exp gives the minimal value. If more than one item
results in the same minimum value, the index of the item latest in the list is returned.

If the list is empty, an error is issued.

Example
In the example below, the “low_indx” variable gets the index of the “instr” instance that has the smallest
value of the sum of “op1” and “op2”.
<'
struct instr {
op1: int;
op2: int;
};

e Language Reference 23-55


List Pseudo-Methods
min_value()

extend sys {
instr_list: list of instr;
keep instr_list.size() < 10;
post_generate() is also {
var low_indx: int;
low_indx = instr_list.min_index(.op1 + .op2);
};
};
'>

See Also
• first_index() on page 23-37
• has() on page 23-40
• last_index() on page 23-47
• max_index() on page 23-50
• min() on page 23-53
• min_value() on page 23-56
• all_indices() on page 23-74

23.4.19 min_value()

Purpose
Return the minimum value found by evaluating a given expression for all items

Category
Pseudo-method

Syntax
list.min_value(exp: int): (int | uint)

Syntax Example
var item_val: int;
item_val = sys.item_list.min_value(it.f_1 + it.f_2);

23-56 e Language Reference


List Pseudo-Methods
min_value()

Parameters

list A list.

exp An integer expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the smallest integer value found by evaluating the exp for every item in the list. If more than one
item results in the same minimum value, the value of the expression for the item latest in the list is
returned.

For lists of integer types, one of the following is returned if the list is empty:

List Item Type Value Returned

signed integer MAX_INT (see “Predefined Constants” on page 2-8)

unsigned integer zero

long integer error

Example
In the example below, the “low_val” variable gets the “instr” instance that has the smallest value of the
sum of “op1” and “op2”.
<'
struct instr {
op1: int;
op2: int;
};
extend sys {
instr_list: list of instr;
keep instr_list.size() < 10;
post_generate() is also {
var low_val: int;
low_val = instr_list.min_value(.op1 + .op2);
print low_val;
};
};
'>

e Language Reference 23-57


List Pseudo-Methods
reverse()

See Also
• has() on page 23-40
• max_value() on page 23-51
• min() on page 23-53
• min_index() on page 23-55

23.4.20 reverse()

Purpose
Reverse the order of a list

Category
Pseudo-method

Syntax
list.reverse(): list

Syntax Example
var s_list := {"A"; "B"; "C"; "D"};
var r_list := s_list.reverse();

Parameters

list A list.

Description
Returns a new list of all the items in list in reverse order.

Example 1
In the following example the “r_list” variable gets a list that contains all the items in the “packets” list,
but in reverse order.
<'
struct cell {

23-58 e Language Reference


List Pseudo-Methods
size()

data: list of byte;


};
struct packet {
cells: list of cell;
};
extend sys {
packets: list of packet;
r_packets: list of packet;
post_generate() is also {
r_packets = sys.packets.reverse();
};
};
'>

Example 2
The following example prints 2, 1, 2, 4.
var i_list: list of int = {4; 2; 1; 2};
var r_list: list of int = i_list.reverse();
print r_list;

See Also
• sort() on page 23-61
• sort_by_field() on page 23-62

23.4.21 size()

Purpose
Return the size of a list

Category
Pseudo-method

Syntax
list.size(): int

e Language Reference 23-59


List Pseudo-Methods
size()

Syntax Example
print packets.size();

Parameters

list A list.

Description
Returns an integer equal to the number of items in the list.

A common use for this method is in a keep constraint, to specify an exact size or a range of values for
the list size. The default maximum list size for generated lists is 50, set by the default_max_list_size
generation configuration option. Generated lists have a random size between 0 and that number. You can
control the list size using a construct like “keep list.size() == n”, where n is an integer expression.

The list[n] index syntax is another way to specify an exact size of a list, when you use it in the list
declaration, such as “p_list[n]: list of p”.

See “Constraining List Size” on page 11-11 for more information about constraining the size of lists.

Example 1
In the following example, the “lsz” variable gets the number of items in the list named “s_list”.
<'
extend sys {
s_list: list of string;
keep s_list == {"Aa"; "Ba"; "Cc"};
post_generate() is also {
var lsz: int;
lsz = sys.s_list.size();
print lsz;
};
};
'>

Example 2
In the following example, a list of packets named p_list will be generated. A keep constraint is used to
set the size of the list to exactly 10 packets.
<'
extend sys {
p_list: list of packet;

23-60 e Language Reference


List Pseudo-Methods
sort()

keep p_list.size() == 10;


};
'>

See Also
• resize() on page 23-23
• count() on page 23-32
• keep on page 11-20
• [ ] on page 2-69

23.4.22 sort()

Purpose
Sort a list

Category
Pseudo-method

Syntax
list.sort(sort-exp: exp): list

Syntax Example
var s_list: list of packet;
s_list = packets.sort(it.f_1 + it.f_2);

Parameters

list A list of integers, strings, enumerated items, or Boolean values to sort.

sort-exp A scalar or nonscalar expression. The expression may contain references to fields or
structs. The it variable can be used to refer to the current list item.

Description
Returns a new list of all the items in list, sorted in increasing order of the values of the sort-exp.

e Language Reference 23-61


List Pseudo-Methods
sort_by_field()

If the sort-exp is a scalar value, the list is sorted by value. If the sort-exp is a nonscalar, the list is sorted
by address.

Example 1
The following example prints 1, 2, 2, 4.
var sl: list of int = {4; 2; 1; 2};
print sl.sort(it);

Example 2
In the following example, the “s_list” variable gets the items in the “packets” list, sorted in increasing
value of the product of the “length” and “width” fields.
<'
struct packet {
length: uint;
width: uint;
};
extend sys {
packets: list of packet;
post_generate() is also {
var s_list: list of packet;
s_list = packets.sort(.length * .width);
};
};
'>

See Also
• reverse() on page 23-58
• sort_by_field() on page 23-62

23.4.23 sort_by_field()

Purpose
Sort a list of structs by a selected field

Category
Pseudo-method

23-62 e Language Reference


List Pseudo-Methods
sort_by_field()

Syntax
struct-list.sort_by_field(field: field-name): list

Syntax Example
var s_list: list of packet;
s_list = sys.packets.sort_by_field(length);

Parameters

struct-list A list of structs.

field The name of a field of the list’s struct type. Enter the name of the field only, with no
preceding “.” or “it.”.

Description
Returns a new list of all the items in struct-list, sorted in increasing order of their field values.

Note
The list.sort() pseudo-method returns the same value as the list.sort_by_field() pseudo-method, but
list.sort_by_field() is more efficient.

Example
In the following example, the “sf_list” variable gets the items in the “packets” list, sorted in increasing
value of the “ptype” field (first “ATM”, then “ETH”, then “foreign”).
<'
type pkt_type: [ATM, ETH, foreign];
struct packet {
length: uint;
width: uint;
ptype: pkt_type;
};
extend sys {
packets: list of packet;
post_generate() is also {
var sf_list: list of packet;
sf_list = packets.sort_by_field(ptype);
print sf_list;
};
};

e Language Reference 23-63


List Pseudo-Methods
split()

'>

See Also
• reverse() on page 23-58
• sort() on page 23-61

23.4.24 split()

Purpose
Splits a list at each point where an expression is true

Category
Pseudo-method

Syntax
list.split(split-exp: exp): list, …

Syntax Example
var sl_hold := s_list.split(it.f_1 == 16);

Parameters

list A list of type struct-list-holder.

split-exp An expression. The it variable can be used to refer to the current list item, and the index
variable can be used to refer to its index number.

Description
Splits the items in list into separate lists, each containing consecutive items in list which evaluate to the
same exp value.

Since Specman does not support lists of lists, this pseudo-method returns a list of type struct-list-holder.
The struct-list-holder type is a struct with a single field, “value: list of any-struct;”. A struct-list-holder
is a list of structs, with each struct containing a list of items of the original list type.

23-64 e Language Reference


List Pseudo-Methods
split()

Each struct-list-holder in the returned list contains consecutive items from the list that have the same
split-exp value.

Note
Fields used in the expression must be defined in the base type definition, not in when subtypes.

Example 1
Suppose “packets” is a list that contains packet instances that have the following “length” values:

3; 5; 5; 7; 7; 7; 5;

The “packets.split(.length)” pseudo-method in the following creates a list of four lists by splitting the
“packets” list at each point where the “length” value changes, that is, between 3 and 5, between 5 and 7,
and between 7 and 5.
<'
struct packet {
length: uint;
};
extend sys {
packets: list of packet;
post_generate() is also {
var sl_hold := packets.split(.length);
print sl_hold[2].value;
print sl_hold.value[4];
};
};
'>

The struct-list-holder variable “sl_hold” then contains four lists:

5, 5

7, 7, 7

The “print sl_hold[2].value” action prints the third list, which is the one containing three items whose
“length” values are 7.

The print sl_hold.value[4]” action prints the fifth item in the “sl_hold” list, which is the same as the
fifth item in the “packets” list.

e Language Reference 23-65


List Pseudo-Methods
split()

Example 2
In the following example, the “length” field values used in “Example 1” on page 23-65, are assigned to a
list of seven “packet” structs. The list.split() pseudo-method is then called to split the list of packets on
the “length” values. This creates the following four lists in the “sl_hold” struct list holder variable:

list sl_hold[1] : length value 3


list sl_hold[2] : length values 5, 5
list sl_hold[3] : length values 7, 7, 7
list sl_hold[4] : length value 5

The “sl_hold” list values are then printed in the for loop.
<'
struct packet {
address: byte;
length: uint;
};
extend sys {
packets: list of packet;
keep packets.size() == 7;
post_generate() is also {
packets[0].length = 3;
packets[1].length = 5;
packets[2].length = 5;
packets[3].length = 7;
packets[4].length = 7;
packets[5].length = 7;
packets[6].length = 5;
var sl_hold: list of struct_list_holder;
sl_hold = packets.split(.length);
for i from 0 to sl_hold.size() - 1 do {
print sl_hold[i].value;
};
};
};
'>

The output of the “print sl_hold[i].value” loop is shown below. The “length” field values for the
“packet” items are in the column on the right.
p[i].value =
item type
0. packet 112 3

p[i].value =
item type
0. packet 32 5

23-66 e Language Reference


List Pseudo-Methods
top()

1. packet 78 5

p[i].value =
item type
0. packet 172 7
1. packet 172 7
2. packet 25 7

p[i].value =
item type
0. packet 70 5

Example 3
The following splits the list in the preceding example at each point where the value of the expression
“.length > 5” changes, that is, between 5 and 7 and between 7 and 5.
var sl_hold := sys.packets.split(.length > 5);

The struct-list-holder variable “sl_hold” then contains three lists:

3, 5, 5

7, 7, 7

Example 4
To sort the list before you split it, you can use the following syntax.
var sl_hold := sys.packets.sort(.length).split(.length);

See Also
• get_indices() on page 23-39
• has() on page 23-40
• all() on page 23-72

23.4.25 top()

Purpose
Return the last item in a list

e Language Reference 23-67


List Pseudo-Methods
top0()

Category
Pseudo-method

Syntax
list.top(): list-item

Syntax Example
var pk: packet;
pk = sys.packets.top();

Parameters

list A list.

Description
Returns the last item in the list without removing it from the list. If the list is empty, an error is issued.

Example
The following example prints the contents of the last packet in the “packets” list.
print sys.packets.top();

See Also
• pop() on page 23-18
• top0() on page 23-68

23.4.26 top0()

Purpose
Return the first item of a list

Category
Pseudo-method

23-68 e Language Reference


List Pseudo-Methods
unique()

Syntax
list.top0(): list-item

Syntax Example
var pk: packet;
pk = sys.packets.top0();

Parameters

list A list.

Description
Returns the first item in the list without removing it from the list. If the list is empty, an error is issued.

This pseudo-method can be used with pop0() to emulate queues.

Example
The following example prints the contents of the first packet in the “packets” list.
print sys.packets.top0();

See Also
• pop0() on page 23-19
• top() on page 23-67

23.4.27 unique()

Purpose
Collapse consecutive items that have the same value into one item

Category
Pseudo-method

e Language Reference 23-69


List Pseudo-Methods
unique()

Syntax
list.unique(select-exp: exp): list

Syntax Example
var u_list: list of l_item;
u_list = sys.l_list.unique(it.f_1);

Parameters

list A list.

select-exp An expression. The it variable can be used to refer to the current list item, and the index
variable can be used to refer to its index number.

Description
Returns a new list of all the distinct values in list. In the new list, all consecutive occurrences of items for
which the value of exp are the same are collapsed into one item.

Note This pseudo-method was at one time named list.uniq(). The syntax and semantics of list.unique()
and list.uniq() are identical.

Example 1
In the following example, the list.unique() pseudo-method collapses the consecutive 5s and the
consecutive 7s in “i_list” into a single 5 and a single seven. The example prints 3, 5, 7, 5.
var i_list := {3; 5; 5; 7; 7; 7; 5};
var pl: list of int;
pl = i_list.unique(it);
print pl;

Example 2
Suppose the “packets” list contains seven packets with the following “length” field values: 3, 5, 5, 7, 7,
7, 5. The list.unique() pseudo-method collapses the consecutive packets with lengths of 5 into a single
item, and collapses the consecutive items with lengths of 7 into a single item. The “pl” list gets four
packets, with lengths of 3, 5, 7, and 5.
var pl: list of packet;
pl = packets.unique(.length);

23-70 e Language Reference


List Pseudo-Methods
Sublist Pseudo-Methods

Example 3
In the following example, the list.unique() pseudo-method removes any packet items with repeated
“length” values from the “packets” list before the list is sorted using the list.sort() pseudo-method.
<'
struct packet {
length: uint (bits: 8);
width: uint (bits: 8);
};
extend sys {
packets: list of packet;
post_generate() is also {
var s_list: list of packet;
s_list= packets.sort(.length).unique(.length);
print s_list;
};
};
'>

See Also
• count() on page 23-32
• size() on page 23-59
• sort() on page 23-61
• sort_by_field() on page 23-62
• all() on page 23-72

23.5 Sublist Pseudo-Methods


This section describes the syntax for pseudo-methods that construct a new list from all the items in
another list that satisfy specified conditions.

The pseudo-methods in this section are:

• all() on page 23-72


• all_indices() on page 23-74

See Also
• “Pseudo-Methods Overview” on page 23-1

e Language Reference 23-71


List Pseudo-Methods
all()

• “Using List Pseudo-Methods” on page 23-2


• “Additional Type-Related Constructs” on page 3-39

23.5.1 all()

Purpose
Get all items that satisfy a condition

Category
Pseudo-method

Syntax
list.all(exp: bool): list

Syntax Example
var l_2: list of packet;
l_2 = sys.packets.all(it.length > 64);

Parameters

list A list.

exp A Boolean expression. The it variable can be used to refer to the current item, and the index
variable can be used to refer to its index number.

Description
Returns a list of all the items in list for which exp is TRUE. If no items satisfy the Boolean expression,
an empty list is returned.

Example 1
The following example prints 7, 9, 11, since those are the values in “l_list” that are greater than 5.
var l_list: list of int = {1; 3; 5; 7; 9; 11};
print l_list.all(it > 5);

23-72 e Language Reference


List Pseudo-Methods
all()

Example 2
The following example creates a list named “pl” of all packets that have a “length” field value less than
5, and prints the “pl” list.
<'
type packet_type: [ETH, ATM];
struct packet {
length: uint (bits: 4);
ptype: packet_type;
};
extend sys {
packets: list of packet;
post_generate() is also {
var pl: list of packet;
pl = packets.all(.length < 5);
print pl;
};
};
'>

Example 3
The following creates a list named “pt” of all packets that have a “ptype” field value of “ETH”, and
prints the “pt” list. This example uses the “it is a type” syntax to specify which subtype of the packet
struct to look for.
<'
type packet_type: [ETH, ATM];
struct packet {
length: uint (bits: 4);
ptype: packet_type;
};
extend sys {
packets: list of packet;
post_generate() is also {
var pt:= packets.all(it is a ETH packet);
print pt;
};
};
'>

See Also
• is [not] a on page 2-88
• first() on page 23-36

e Language Reference 23-73


List Pseudo-Methods
all_indices()

• has() on page 23-40


• last() on page 23-45
• max() on page 23-48
• min() on page 23-53
• all_indices() on page 23-74

23.5.2 all_indices()

Purpose
Get indexes of all items that satisfy a condition

Category
Pseudo-method

Syntax
list.all_indices(exp: bool): list of int

Syntax Example
var l_2: list of int;
l_2 = sys.packets.all_indices(it.length > 5);

Parameters

list A list.

exp A Boolean expression.

Description
Returns a list of all indexes of items in list for which exp is TRUE. If no items satisfy the Boolean
expression, an empty list is returned.

23-74 e Language Reference


List Pseudo-Methods
all_indices()

Example 1
The following example creates a list name “tl” that contains the index numbers of all the “instr”
instances in the list named “i_list” which have “op1” field values greater than 63.
<'
type op_code: [ADD, SUB, MLT];
struct instr {
op1: int (bits: 8);
op2: int;
opcode: op_code;
};
extend sys {
i_list: list of instr;
post_generate() is also {
var tl: list of int;
tl = i_list.all_indices(it.op1 > 63);
print tl;
};
};
'>

Results
tl =
0. 0
1. 1
2. 2
3. 3
4. 4
5. 8
6. 12
7. 28
8. 29
9. 30
10. 31
11. 33

Example 2
In the following example, the list.all_indices() pseudo-method is used to create a list named “pl” of the
indexes of the “packets” list items that are of subtype “small packet”.
<'
type pkt_type: [small, medium, large];
struct packet {
address: byte;

e Language Reference 23-75


List Pseudo-Methods
all_indices()

ptype: pkt_type;
};
extend sys {
packets: list of packet;
keep packets.size() == 10;
run() is also {
print packets;
var pl: list of int;
pl = packets.all_indices(it is a small packet);
print pl;
};
};
'>

Results
packets =
item type address ptype

0. packet 97 medium
1. packet 66 large
2. packet 10 large
3. packet 180 medium
4. packet 235 small
5. packet 196 small
6. packet 85 large
7. packet 163 small
8. packet 62 large
9. packet 86 large
pl =
0. 4
1. 5
2. 7

Example 3
Using all_indices() on an empty list produces another empty list. Trying to use this result in a gen
keeping constraint can cause a generation contradiction error. To avoid this, you can use a check like “if
!test_ix.is_empty()” in the following example.
<'
struct st_eng {
v_list: list of uint (bits: 7);
ameth(): list of int is {
var test_ix: list of int;
test_ix = v_list.all_indices(it > 100);
var s_index: uint;

23-76 e Language Reference


List Pseudo-Methods
Math and Logic Pseudo-Methods

if !test_ix.is_empty() {
gen s_index keeping {it in test_ix};
return test_ix;
};
};
};
extend sys {
st_i: st_eng;
s_list: list of int;
run() is also {
s_list = st_i.ameth();
print s_list;
};
};
'>

Results
s_list =
0. 9
1. 20
2. 21
3. 37
4. 39
5. 44

See Also
• field on page 23-35
• first_index() on page 23-37
• has() on page 23-40
• last_index() on page 23-47
• max_index() on page 23-50
• min_index() on page 23-55
• all() on page 23-72

23.6 Math and Logic Pseudo-Methods


This section describes the syntax for pseudo-methods that perform arithmetic or logical operations to
compute a value using all items in a list.

e Language Reference 23-77


List Pseudo-Methods
and_all()

The pseudo-methods in this section are:

• and_all() on page 23-78


• average() on page 23-79
• or_all() on page 23-81
• product() on page 23-82
• sum() on page 23-84

See Also
• “Pseudo-Methods Overview” on page 23-1
• “Using List Pseudo-Methods” on page 23-2

23.6.1 and_all()

Purpose
Compute the logical AND of all items

Category
Pseudo-method

Syntax
list.and_all(exp: bool): bool

Syntax Example
var bool_val: bool;
bool_val = m_list.and_all(it >= 1);

Parameters

list A list.

exp A Boolean expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

23-78 e Language Reference


List Pseudo-Methods
average()

Description
Returns a TRUE if all values of the exp are true, or returns FALSE if the exp is false for any item in the
list.

Example
The following command prints TRUE if the “length” field value of all items in the “packets” list is
greater than 63. If any packet has a length less than or equal to 63, it prints FALSE.
print sys.packets.and_all(it.length > 63);

See Also
• average() on page 23-79
• or_all() on page 23-81
• product() on page 23-82
• sum() on page 23-84

23.6.2 average()

Purpose
Compute the average of an expression for all items

Category
Pseudo-method

Syntax
list.average(exp: int): int

Syntax Example
var list_ave: int;
list_ave = sys.item_list.average(it.f_1 * it.f_2);

e Language Reference 23-79


List Pseudo-Methods
average()

Parameters

list A list.

exp An integer expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the integer average of the exp computed for all the items in the list. Returns UNDEF if the list is
empty.

Example 1
The following example prints 6 ((3 + 5 + 10)/3).
var a_list := {3; 5; 10};
print a_list.average(it);

Example 2
The following example prints the average value of the “length” fields for all the items in the “packets”
list.
<'
struct packet {
length: uint (bits: 4);
width: uint (bits: 4);
};
extend sys {
packets: list of packet;
post_generate() is also {
print packets.average(it.length);
};
};
'>

See Also
• and_all() on page 23-78
• or_all() on page 23-81
• product() on page 23-82

23-80 e Language Reference


List Pseudo-Methods
or_all()

• sum() on page 23-84

23.6.3 or_all()

Purpose
Compute the logical OR of all items

Category
Pseudo-method

Syntax
list.or_all(exp: bool): bool

Syntax Example
var bool_val: bool;
bool_val = m_list.or_all(it >= 100);

Parameters

list A list.

exp A Boolean expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns a TRUE if any value of the exp is true, or returns FALSE if the exp is false for every item in the
list. Returns FALSE if the list is empty.

Example
The following command prints TRUE if the “length” field value of any item in the “packets” list is
greater than 150. If no packet has a length greater than 150, it prints FALSE.
<'
struct packet {
length: uint (bits: 4);
width: uint (bits: 4);

e Language Reference 23-81


List Pseudo-Methods
product()

};
extend sys {
packets: list of packet;
post_generate() is also {
print packets.or_all(it.length > 150);
};
};
'>

See Also
• and_all() on page 23-78
• average() on page 23-79
• product() on page 23-82
• sum() on page 23-84

23.6.4 product()

Purpose
Compute the product of an expression for all items

Category
Pseudo-method

Syntax
list.product(exp: int): int

Syntax Example
var list_prod: int;
list_prod = sys.item_list.product(it.f_1);

Parameters

list A list.

23-82 e Language Reference


List Pseudo-Methods
product()

exp An integer expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the integer product of the exp computed over all the items in the list. Returns 1 if the list is
empty.

Example 1
The following example prints 150 (3 * 5 * 10).
var p_list := {3; 5; 10};
print p_list.product(it);

Example 2
The following example prints the product of the “mlt” fields in all the items in the “packets” list.
<'
struct packet {
mlt: uint (bits: 3);
keep mlt > 0;
};
extend sys {
packets[5]: list of packet;
post_generate() is also {
print packets.product(it.mlt);
};
};
'>

See Also
• and_all() on page 23-78
• average() on page 23-79
• or_all() on page 23-81
• sum() on page 23-84

e Language Reference 23-83


List Pseudo-Methods
sum()

23.6.5 sum()

Purpose
Compute the sum of all items

Category
Pseudo-method

Syntax
list.sum(exp: int): int

Syntax Example
var op_sum: int;
op_sum = sys.instr_list.sum(.op1);

Parameters

list A list.

exp An integer expression. The it variable can be used to refer to the current list item, and the
index variable can be used to refer to its index number.

Description
Returns the integer sum of the exp computed over all the items in the list. Returns 0 if the list is empty.

The following example prints 18 (3 + 5 + 10).


var s_list := {3; 5; 10};
print s_list.sum(it);

Example
The following example prints the sum of the “length” field values for all the items in the “packets” list.
<'
struct packet {
length: uint (bits: 4);
keep length in [1..5];
width: uint (bits: 4);

23-84 e Language Reference


List Pseudo-Methods
List CRC Pseudo-Methods

keep width in [1..5];


};
extend sys {
packets[5]: list of packet;
post_generate() is also {
print packets.sum(it.length);
};
};
'>

See Also
• and_all() on page 23-78
• average() on page 23-79
• or_all() on page 23-81
• product() on page 23-82

23.7 List CRC Pseudo-Methods


This section describes the syntax for pseudo-methods that perform CRC (cyclic redundancy check)
functions on lists.

The pseudo-methods in this section are:

• crc_8() on page 23-85


• crc_32() on page 23-87
• crc_32_flip() on page 23-90

See Also
• “Pseudo-Methods Overview” on page 23-1
• “Using List Pseudo-Methods” on page 23-2

23.7.1 crc_8()

Purpose
Compute the CRC8 of a list of bits or a list of bytes

e Language Reference 23-85


List Pseudo-Methods
crc_8()

Category
Pseudo-method

Syntax
list.crc_8(from-byte: int, num-bytes: int): int

Syntax Example
print b_data.crc_8(2,4);

Parameters

list A list of bits or bytes.

from-byte The index number of the starting byte.

num-bytes The number of bytes to use.

Description
Reads the list byte-by-byte and returns the integer value of the CRC8 function of a list of bits or bytes.
Only the least significant byte (LSB) is used in the result.

The CRC is computed starting with the from-byte, for num-bytes. If from-byte or from-byte+num-bytes
is not in the range of the list, an error is issued.

Note
The algorithm for computing CRC8 is specific for the ATM HEC (Header Error Control) computation.
The code used for HEC is a cyclic code with the following generating polynomial:

x**8 + x**2 + x + 1

Example
In the example below, the “e_crc” variable gets the CRC8 of the bytes 2, 3, 4, and 5 in the list named
“b_data”.
<'
extend sys {
post_generate() is also {
var b_data: list of byte =
{0xff;0xaa;0xdd;0xee;0xbb;0xcc};

23-86 e Language Reference


List Pseudo-Methods
crc_32()

print b_data.crc_8(2,4);
};
};
'>

Results
b_data.crc_8(2,4) = 0x63

See Also
• crc_32() on page 23-87
• crc_32_flip() on page 23-90
• product() on page 23-82
• sum() on page 23-84
• pack() on page 18-27
• unpack() on page 18-31

23.7.2 crc_32()

Purpose
Compute the CRC32 of a list of bits or a list of bytes

Category
Pseudo-method

Syntax
list.crc_32(from-byte: int, num-bytes: int): int

Syntax Example
print b_data.crc_32(2,4);

Parameters

list A list of bits or bytes.

e Language Reference 23-87


List Pseudo-Methods
crc_32()

from-byte The index number of the starting byte.

num-bytes The number of bytes to use.

Description
Reads the list byte-by-byte and returns the integer value of the CRC32 function of a list of bits or bytes.
Only the least significant word is used in the result.

The CRC is computed starting with the from-byte, for num-bytes. If from-byte or from-byte+num-bytes
is not in the range of the list, an error is issued.

Note
The algorithm for computing CRC32 generates a 32-bit CRC that is used for messages up to 64
kilobytes in length. Such a CRC can detect 99.999999977% of all errors. The generator polynomial for
the 32-bit CRC used for both Ethernet and token ring is:

x**32 + x**26 + x**23 + x**22 + x**16 + x**12 + x**11 + x**10 + x**8 + x**7 + x**5 + x**4
+x**2 + x + 1

Example 1
In the example below, the “b_data” variable gets the packed “packet” struct instance as a list of bytes,
and the CRC32 of bytes 2, 3, 4, and 5 of “b_data” is printed.
<'
struct packet {
%byte_1: byte;
%byte_2: byte;
%byte_3: byte;
%byte_4: byte;
%byte_5: byte;
%byte_6: byte;
};
extend sys {
packet;
post_generate() is also {
var b_data: list of byte = pack(NULL, me.packet);
print b_data.crc_32(2,4);
};
};
'>

23-88 e Language Reference


List Pseudo-Methods
crc_32()

Example 2
In the example below, the CRC32 value is calculated for the data field value. The “is_good_crc()”
method checks the value and returns TRUE if it is good, FALSE if it is bad.
<'
struct packet {
%data: list of byte;
!%crc: uint;
packed: list of byte;
post_generate() is also {
crc = (data.crc_32(0, data.size()) ^ 0xffff_ffff);
packed = pack(packing.low, me);
};
is_good_crc(): bool is {
result = (packed.crc_32(0, packed.size()) ==
0xffff_ffff);
};
};
extend sys {
packets: list of packet;
post_generate() is also {
for each in packets {
outf("frame %d ", index);
print it.is_good_crc();
};
};
};
'>

See Also
• crc_8() on page 23-85
• crc_32_flip() on page 23-90
• product() on page 23-82
• sum() on page 23-84
• pack() on page 18-27
• unpack() on page 18-31

e Language Reference 23-89


List Pseudo-Methods
crc_32_flip()

23.7.3 crc_32_flip()

Purpose
Compute the CRC32 of a list of bits or a list of bytes, flipping the bits

Category
Pseudo-method

Syntax
list.crc_32_flip(from-byte: int, num-bytes: int): int

Syntax Example
print b_data.crc_32_flip(2,4);

Parameters

list A list of bits or bytes.

from-byte The index number of the starting byte.

num-bytes The number of bytes to use.

Description
Reads the list byte-by-byte and returns the integer value of the CRC32 function of a list of bits or bytes,
with the bits flipped. Only the least significant word is used in the result.

The CRC is computed starting with the from-byte, for num-bytes. If from-byte or from-byte+num-bytes
is not in the range of the list, an error is issued.

The bits are flipped as follows:

1. The bits inside each byte of the input are flipped.

2. The bits in the result are flipped.

Example
In the example below, the “tc_crc” variable gets the CRC32 of the bytes 2, 3, 4, and 5 in the list named
“b_data”, with the bits flipped.

23-90 e Language Reference


List Pseudo-Methods
Keyed List Pseudo-Methods

<'
struct packet {
%byte_1: byte;
%byte_2: byte;
%byte_3: byte;
%byte_4: byte;
%byte_5: byte;
%byte_6: byte;
};
extend sys {
packet;
post_generate() is also {
var b_data: list of byte = pack(NULL, me.packet);
print b_data.crc_32_flip(2,4);
};
};
'>

See Also
• crc_8() on page 23-85
• crc_32() on page 23-87
• product() on page 23-82
• sum() on page 23-84
• pack() on page 18-27
• unpack() on page 18-31

23.8 Keyed List Pseudo-Methods


This section describes the syntax for pseudo-methods that can be used only on keyed lists.

Keyed lists are list in which each item has a key associated with it. For a list of structs, the key typically
is the name of a particular field in each struct. Each unique value for that field may be used as a key. For
a list of scalars, the key can be the it variable referring to each item.

While creating a keyed list, you must ensure that the key has a unique value for each item.

Keyed lists can be searched quickly, by searching on a key value.

This section contains descriptions of pseudo-methods that can only be used for keyed lists. Using one of
these methods on a regular list results in an error.

The pseudo-methods in this section are:

e Language Reference 23-91


List Pseudo-Methods
key()

• key() on page 23-92


• key_index() on page 23-95
• key_exists() on page 23-97

See Also
• “Pseudo-Methods Overview” on page 23-1
• “Using List Pseudo-Methods” on page 23-2

23.8.1 key()

Purpose
Get the item that has a particular key

Category
Pseudo-method

Syntax
list.key(key-exp: exp): list-item

Syntax Example
var loc_list_item: location;
var i_key: uint;
i_key = 5;
loc_list_item = locations.key(i_key);

Parameters

list A keyed list.

key-exp The key of the item that is to be returned.

Description
Returns the list item that has the specified key, or NULL if no item with that key exists in the list.

23-92 e Language Reference


List Pseudo-Methods
key()

For a list of scalars, a value of zero is returned if there is no such item. Since zero might be confused
with a found value, it is not advisable to use zero as a key for scalar lists.

If there is more than one item in the list with the same key value, this method returns the last item with
that key value (the item with the highest index number). Other items in the list that have the same key
value are ignored.

Example 1
The following example uses a list of integers for which the key is the item itself. This example prints 5.
var l_list: list(key: it) of int = {5; 4; 3; 2; 1};
print l_list.key(5);

Example 2
In the following example, the “mklist()” method generates a list of 10 “location” instances with even
numbered address from 2 to 20. The “locations” list is a list of “location” instances with “address” as its
key. The “l_item” variable gets the “locations” list item that has an “address” value of 6. If there is no
item in the list with an address of 6, the locations.key() pseudo-method returns NULL.
<'
struct location {
address: int;
value: int;
};
struct l_s {
mklist() is {
var l: location;
for i from 1 to 10 do {
gen l keeping {it.address == 2*i};
sys.locations.add(l);
};
};
};
extend sys {
l_s;
!locations: list(key: address) of location;
run() is also {
l_s.mklist();
print locations;
var l_item: location;
l_item = locations.key(6);
print l_item;
};
};

e Language Reference 23-93


List Pseudo-Methods
key()

'>

Results
locations =
item type address value

0. location 2 -396796955
1. location 4 1796592623
2. location 6 2081332301
3. location 8 -15822625*
4. location 10 116159091
5. location 12 -15052943*
6. location 14 1128419469
7. location 16 -20275240*
8. location 18 -508036604
9. location 20 116597347
l_item = location-@0: location
----------------------------------------------@kl_2
0 address: 6
1 value: 2081332301

Example 3
The following example shows how to use a keyed list on the lefthand side of assignment. The “mklist()”
method generates a list of 10 “location” instances with even-numbered address values from 2 to 20.

The “locations” list is a list of “location” instances with “address” as its key. The “l_item” variable is a
location instance which is generated with a constraint to keep its value equal to 100000. That location
instance’s value field is then assigned to the locations list item that has the address key value of 6.
<'
struct location {
address: int;
value: int;
};
struct l_s {
mklist() is {
var l: location;
for i from 1 to 10 do {
gen l keeping {it.address == 2*i};
sys.locations.add(l);
};
};
};
extend sys {
l_s;

23-94 e Language Reference


List Pseudo-Methods
key_index()

!locations: list(key: address) of location;


run() is also {
l_s.mklist();
var l_item: location;
gen l_item keeping {it.value == 100000};
print l_item;
locations.key(6).value = l_item.value;
print locations.key(6);
};
};
'>

Results
l_item = location-@0: location
----------------------------------------------@kl_assign_3
0 address: -513087844
1 value: 100000
locations.key(6) = location-@1: location
----------------------------------------------@kl_assign_3
0 address: 6
1 value: 100000

See Also
• key_index() on page 23-95
• key_exists() on page 23-97

23.8.2 key_index()

Purpose
Get the index of an item that has a particular key

Category
Pseudo-method

Syntax
list.key_index(key-exp: exp): int

e Language Reference 23-95


List Pseudo-Methods
key_index()

Syntax Example
var loc_list_ix: int;
loc_list_ix = locations.key_index(i);

Parameters

list A keyed list.

key-exp The key of the item for which the index is to be returned.

Description
Returns the integer index of the item that has the specified key, or returns UNDEF if no item with that
key exists in the list.

Example 1
The following example uses a list of integers for which the key is the item itself. This example prints 1,
since that is the index of the list item with a value of 2.
var l_list: list(key: it) of int = {1; 2; 3; 4; 5};
print l_list.key_index(2);

Example 2
The locations.key_index() pseudo-method in the following gets the index of the item in the “locations”
list that has an address of 9, if any item in the list has that address.
<'
struct location {
address: int;
value: int;
};
extend sys {
!locations: list(key: address) of location;
post_generate() is also {
var l_ix: int;
l_ix = locations.key_index(9);
if l_ix != UNDEF {print locations[l_ix].value}
else {outf("key_index %d does not exist\n", 9)};
};
};
'>

23-96 e Language Reference


List Pseudo-Methods
key_exists()

See Also
• key() on page 23-92
• key_exists() on page 23-97

23.8.3 key_exists()

Purpose
Check that a particular key is in a list

Category
Pseudo-method

Syntax
list.key_exists(key-exp: exp): bool

Syntax Example
var loc_list_k: bool;
var i:= 5;
loc_list_k = locations.key_exists(i);

Parameters

list A keyed list.

key The key that is to be searched for.

Description
Returns TRUE if the key exists in the list, or FALSE if it does not.

Example 1
The following example uses a list of integers for which the key is the item itself. The first print action
prints TRUE, since 2 exists in the list. The second print action prints FALSE, since 7 does not exist in
the list.
var l_list: list(key: it) of int = {1; 2; 3; 4; 5};

e Language Reference 23-97


List Pseudo-Methods
Restrictions on Keyed Lists

print l_list.key_exists(2);
print l_list.key_exists(7);

Example 2
The locations.key_exists() pseudo-method in the following example returns TRUE to “k” if there is an
item in the “locations” list that has a key value of 30, or FALSE if there is no such item.
<'
struct location {
address: int;
value: int;
};
extend sys {
!locations: list(key: address) of location;
post_generate() is also {
var k: bool;
k = locations.key_exists(30);
if k {outf("key %d exists\n", 30)}
else {outf("key %d does not exist\n", 30)};
};
};
'>

See Also
• key() on page 23-92
• key_index() on page 23-95

23.9 Restrictions on Keyed Lists


• The following pseudo-methods cannot be used on keyed lists:
• list.resize()
• list.apply()
• list.field
• Keyed lists and regular (unkeyed) lists are different types. Assignment is not allowed between a
keyed list and a regular list.
• Keyed lists cannot be generated. Trying to generate a keyed list results in an error. Therefore, keyed
lists must be defined with the do-not-generate sign, an exclamation mark, as in the example below.

23-98 e Language Reference


List Pseudo-Methods
Restrictions on Keyed Lists

• Some operations are less efficient for keyed lists than for unkeyed lists, because after they change
the list they must also update the keys. The following operations are not recommended on keyed lists:
• list.insert()
• list.delete()
• slice assignment
• list.reverse()
• Prior to using list.insert() or list.delete, you can make the operation more efficient by using one of
the following pseudo-methods to find the desired index or item in a keyed list:
• list.first()
• list.first_index()
• list.has()
For example, the recommended way to delete an item from a keyed list is to check for the existence
of the key first as in the following:
!locations: list (key: address) of location;
if (locations.key_exists(38)) then {
locations.delete(location.key_index(38));
};
The above example searches for the key in the fastest way, and it updates the keyed list only if the
key exists.

See Also
• “Keyed List Pseudo-Methods” on page 23-91
• “Pseudo-Methods Overview” on page 23-1
• “Using List Pseudo-Methods” on page 23-2

e Language Reference 23-99


List Pseudo-Methods
Restrictions on Keyed Lists

23-100 e Language Reference


24 Predefined Routines
Predefined routines are e macros that look like methods. The distinguishing characteristics of predefined
routines are:

• They are not associated with any particular struct


• They share the same name space for user-defined routines and global methods
• They cannot be modified or extended with the is only, is also or is first constructs
• They have no debug information
The following sections describe the predefined routines:

• “Deep Copy and Compare Routines” on page 24-2


• “Arithmetic Routines” on page 24-13
• “Bitwise Routines” on page 24-25
• “String Routines” on page 24-28
• “Output Routines” on page 24-61
• “Configuration Routines” on page 24-66
• “Specman Command Routine” on page 24-80
• “OS Interface Routines” on page 24-82
• “File Routines” on page 24-91
• “On-the-Fly Garbage Collection Routine” on page 24-139
• “Calling Predefined Routines” on page 24-140

e Language Reference 24-1


Predefined Routines
Deep Copy and Compare Routines

See Also
• “Invoking Methods” on page 7-22
• Chapter 22 “Predefined Methods”

24.1 Deep Copy and Compare Routines


The following routines perform recursive copies and comparisons of nested structs and lists:

• deep_copy() on page 24-2


• deep_compare() on page 24-5
• deep_compare_physical() on page 24-11

24.1.1 deep_copy()

Purpose
Make a recursive copy of a struct and its descendants

Category
Predefined routine

Syntax
deep_copy(struct-inst: exp): struct instance

Syntax Example
var pmv: packet = deep_copy(sys.pmi);

Parameters

struct-inst An expression that returns a struct instance.

Description
Returns a deep, recursive copy of the struct instance. This routine descends recursively through the fields
of a struct and its descendants, copying each field by value, copying it by reference, or ignoring it,
depending on the deep_copy attribute set for that field.

24-2 e Language Reference


Predefined Routines
deep_copy()

The return type of deep_copy() is the same as the declared type of the struct instance.

The following table details how the copy is made, depending on the type of the field and the deep_copy
attribute (normal, reference, ignore) set for that field. For an example of how field attributes affect
deep_copy(), see attribute field on page 4-28.

Field Type/
Attribute Normal Reference Ignore

scalar The new field holds a The new field holds a The new field holds a
copy of the original copy of the original copy of the original
value. value. value.

string The new field holds a The new field holds a The new field holds a
copy of the original copy of the original copy of the original
value. value. value.

scalar list A new list is The new list field A new list is
allocated with the holds a copy of the allocated with zero
same size and same original list pointer. 1 size.
elements as the
original list.

struct A new struct instance The new struct field A new struct instance
with the same type as holds a pointer to the is allocated and it is
the original struct is original struct. 1 NULL.
allocated. Each field
is copied or ignored,
depending on its
deep_copy attribute.

list of structs A new list is allocated The new list field A new list is
with the same number holds a copy of the allocated with zero
of elements as the original list pointer. 1 size.
original list.
New struct instances
are also allocated and
each field in each
struct is copied or
ignored, depending
on its deep_copy
attribute.

e Language Reference 24-3


Predefined Routines
deep_copy()

1. If the list or struct that is pointed to is duplicated (possibly because another field
with a normal attribute is also pointing to it) the pointer in this field is updated to
point to the new instance. This duplication applies only to instances duplicated by
the deep_copy() itself, and not duplications made by the extended/overridden
copy() method.

Notes
• A deep copy of a scalar field (numeric, Boolean, enumerated) or a string field is the same as a shallow
copy performed by a call to copy().
• A struct or list is duplicated no more than once during a single call to deep_copy().
If there is more than one reference to a struct or list instance, and that instance is duplicated by the
call to deep_copy(), every field that referred to the original instance is updated to point to the new
instance.
• The copy() method of the struct is called by deep_copy().
The struct’s copy() method is called before its descendants are deep copied. If the default copy()
method is overwritten or extended, this new version of the method is used.
• You should apply the reference attribute to fields that store shared data and to fields that are
backpointers (pointers to the parent struct). Shared data in this context means data shared between
objects inside the deep copy graph and objects outside the deep copy graph. A deep copy graph is
the imaginary directed graph created by traversing the structs and lists duplicated, where its nodes
are the structs or lists, and its edges are deep references to other structs or lists.

Example
<'
struct packet {
header: header;
data[10]: list of byte;
protocol: [ATM, ETH, IEEE];
};
struct header {
code: uint;
};
extend sys {
pmi: packet;
m1() is {
var pmv: packet = deep_copy(sys.pmi);
pmv.data[0] = 0xff;
pmv.header.code = 0xaa;

24-4 e Language Reference


Predefined Routines
deep_compare()

pmv.protocol = IEEE;
print pmi.data[0], pmi.header.code, pmi.protocol;
print pmv.data[0], pmv.header.code, pmv.protocol;
};
};
'>

Result
This example shows that any changes in value to lists and structs contained in the copied struct instance
(pmv) are not propagated to the original struct instance (pmi) because the struct has been recursively
duplicated.
vrst-tool> sys.m()
pmi.data[0] = 0x1b
pmi.header.code = 0x43dfc545
pmi.protocol = ATM
pmv.data[0] = 0xff
pmv.header.code = 0xaa
pmv.protocol = IEEE

See Also
• The copy() Method of any_struct on page 22-20
• deep_compare() on page 24-5
• deep_compare_physical() on page 24-11
• attribute field on page 4-28
• trace deep on page 17-30

24.1.2 deep_compare()

Purpose
Perform a recursive comparison of two struct instances

Category
Predefined routine

e Language Reference 24-5


Predefined Routines
deep_compare()

Syntax
deep_compare(struct-inst1: exp, struct-inst2: exp, max-diffs: int): list of string

Syntax Example
var diff: list of string = deep_compare(pmi[0], pmi[1], 100);

Parameters

struct-inst1, An expression returning a struct instance.


struct-inst2

max-diffs An integer representing the maximum number of differences you want reported.

Description
Returns a list of strings, where each string describes a single difference between the two struct instances.
This routine descends recursively through the fields of a struct and its descendants, comparing each field
or ignoring it, depending on the deep_compare attribute set for that field.

The two struct instances are “deep equal” if the returned list is empty.

“Deep equal” is defined as follows:

• Two struct instances are deep equal if they are of the same type and all their fields are deep equal.
• Two scalar fields are deep equal if an equality operation applied to them is TRUE.
• Two list instances are deep equal if they are of the same size and all their items are deep equal.
Topology is taken into account. If two non-scalar instances are not in the same location in the deep
compare graphs, they are not equal. A deep compare graph is the imaginary directed graph created by
traversing the structs and lists compared, where its nodes are the structs or lists, and its edges are deep
references to other structs or lists.

The following table details the differences that are reported, depending on the type of the field and the
deep_compare attribute (normal, reference, ignore) set for that field. For an example of how field
attributes affect deep_copy(), see attribute field on page 4-28.

Field Type/
Attribute Normal Reference Ignore

scalar Their values, if Their values, if The fields are not


different, are reported. different, are reported. compared.

24-6 e Language Reference


Predefined Routines
deep_compare()

Field Type/
Attribute Normal Reference Ignore

string Their values, if Their values, if The fields are not


different, are reported. different, are reported. compared.

scalar list Their sizes, if different, The fields are equal if The fields are not
are reported. All items their addresses are the compared.
in the smaller list are same. The items are not
compared to those in compared.
the longer list and their
differences are
reported.

struct If two structs are not of The fields are equal if The fields are not
the same type, their type they point to the same compared and no
difference is reported. struct instance. 2 differences for them
Also, any differences in or their descendants
If the fields do not point
common fields is are reported.
to the same instance,
reported. 1 only the addresses are
If two structs are of the reported as different;
same type, every field the data is not
difference is reported. compared.

list of structs Their sizes, if different, The fields are equal if The fields are not
are reported. All structs their addresses are the compared and no
in the smaller list are same and they point to differences for them
deep compared to those the same struct or their descendants
in the longer list and instance. 2 are reported.
their differences are
reported.

1. Two fields are considered common only if the two structs are the same type, if they are
both subtypes of the same base type, or if one is a base type of the other.

2. If the reference points inside the deep compare graph, a limited topological equivalence
check is performed, not just an address comparison.

Difference String Format


The difference string is in the following format:
Differences between <inst1-id> and <inst2-id>
---------------------------------------------

e Language Reference 24-7


Predefined Routines
deep_compare()

<path>: <inst1-value> != <inst2-value>

path A list of field names separated by periods (.) from (and not including) the struct
instances being compared to the field with the difference.
value For scalar field differences, value is the result of out(field).
For struct field type differences, type() is appended to the path and value is the result of
out(field.type()).
For list field size differences, size() is appended to the path and value is the result of
out(field.size()).
For a shallow comparison of struct fields that point outside the deep compare graph,
value is the struct address.
For a comparison of struct fields that point to different locations in the deep compare
graphs (topological difference), value is struct# appended to an index representing its
location in the deep compare graph.

Note
The same two struct instances or the same two list instances are not compared more than once during a
single call to deep_compare().

Example
This example uses deep_compare() to show the differences between copying nested structs by
reference (with copy()) and copying nested structs by allocation (with deep_copy()).
<'
struct a {
x: byte;
};
struct b {
as: list of a;
keep as.size() in [2 .. 3];
};
struct c {
bs: list of b;
keep bs.size() in [2 .. 3];

print() is {
var idx: uint;
for each b (b) in bs {
idx = index;

24-8 e Language Reference


Predefined Routines
deep_compare()

for each a (a) in b.as {


out ("b[",idx,"] - a[",index,"] : ",
hex(bs[idx].as[index].x));
};
};
};
};

extend sys {
c1: c;
post_generate() is also {
var c2: c = new;
var c3: c = new;

out("C1:");
c1.print();

// copy by allocation

out("C2:");
c2 = deep_copy(c1);
c2.print();
print deep_compare(c1,c2,20);

// copy by reference

out("C3:");
c3 = c1.copy();
c3.print();
print deep_compare(c1,c3,20);

// demonstrate difference - change original

out("Change C1:");
c1.bs[0].as[0].x = 0;
c1.print();
print deep_compare(c1,c2,20);
print deep_compare(c1,c3,20);
};
};
'>

e Language Reference 24-9


Predefined Routines
deep_compare()

Result
The results show the differences between the two ways of copying. The c2 instance is copied by
deep_copy(), so when the value of x is changed in the original instance, c1, the value of x in c2 is not
changed. In contrast, the value of x in c3 is changed because c3 was copied by reference. Note that
“deep_compare() = empty” means that the two struct instances are deep equal.
Specman deep5> gen
Doing setup ...
Generating the test using seed 0x1...
C1:
b[0x0] - a[0x0] : 0x75
b[0x0] - a[0x1] : 0x8a
b[0x1] - a[0x0] : 0x0a
b[0x1] - a[0x1] : 0x2a
C2:
b[0x0] - a[0x0] : 0x75
b[0x0] - a[0x1] : 0x8a
b[0x1] - a[0x0] : 0x0a
b[0x1] - a[0x1] : 0x2a
deep_compare(c1,c2,20) = (empty)
C3:
b[0x0] - a[0x0] : 0x75
b[0x0] - a[0x1] : 0x8a
b[0x1] - a[0x0] : 0x0a
b[0x1] - a[0x1] : 0x2a
deep_compare(c1,c3,20) = (empty)
Change C1:
b[0x0] - a[0x0] : 0x00
b[0x0] - a[0x1] : 0x8a
b[0x1] - a[0x0] : 0x0a
b[0x1] - a[0x1] : 0x2a
deep_compare(c1,c2,20) =
0. "Differences between c-@0 and c-@1
--------------------------------------------------"
1. "bs[0x0].as[0x0].x: 0x00 != 0x75"
deep_compare(c1,c3,20) = (empty)

See Also
• deep_compare_physical() on page 24-11
• deep_copy() on page 24-2
• attribute field on page 4-28
• trace deep on page 17-30

24-10 e Language Reference


Predefined Routines
deep_compare_physical()

24.1.3 deep_compare_physical()

Purpose
Perform a recursive comparison of the physical fields of two struct instances

Category
Predefined routine

Syntax
deep_compare_physical(struct-inst1: exp, struct-inst2: exp, max-diffs: int): list of string

Syntax Example
var diff: list of string = deep_compare_physical(pmi[0],
pmi[1], 100);

Parameters

struct-inst1, An expression returning a struct instance.


struct-inst2

max-diffs An integer representing the maximum number of differences you want reported.

Description
Returns a list of strings, where each string describes a single difference between the two struct instances.
This routine descends recursively through the fields of a struct and its descendants, ignoring all
non-physical fields and comparing each physical field or ignoring it, depending on the
deep_compare_physical attribute set for that field.

This routine is the same as the deep_compare() routine except that only physical fields (indicated with
the % operator prefixed to the field name) are compared.

The two struct instances are “deep equal” if the returned list is empty.

“Deep equal” is defined as follows:

• Two struct instances are deep equal if they are of the same type and all their fields are deep equal.
• Two scalar fields are deep equal if an equality operation applied to them is TRUE.

e Language Reference 24-11


Predefined Routines
deep_compare_physical()

• Two list instances are deep equal if they are of the same size and all their items are deep equal.

Example
<'
struct packet {
%header: header;
%data[10] :list of byte;
protocol: [ATM, ETH, IEEE];
};
struct header {
%code: uint;
};
extend sys {
pmi[2]: list of packet;
post_generate() is also {
var diff: list of string = deep_compare_physical(pmi[0],
pmi[1], 100);
if (diff.size() != 0) {
out(diff);
};
};
};
'>

Result
This example shows the differences between the physical fields of the packet instances. The differences
between the protocol fields are not reported.
Differences between packet-@0 and packet-@1
--------------------------------------------------
header.code: 1138738501 != 3071222567
data[0]: 27 != 37
data[1]: 132 != 56
data[2]: 163 != 69
data[3]: 71 != 236
data[4]: 178 != 120
data[5]: 230 != 100
data[6]: 116 != 239
data[7]: 241 != 216
data[8]: 238 != 144
data[9]: 150 != 253

24-12 e Language Reference


Predefined Routines
Arithmetic Routines

See Also
• deep_compare() on page 24-5
• deep_copy() on page 24-2
• attribute field on page 4-28
• trace deep on page 17-30

24.2 Arithmetic Routines


The following sections describe the predefined arithmetic routines in e:

• min() on page 24-13


• max() on page 24-15
• abs() on page 24-16
• odd() on page 24-17
• even() on page 24-18
• ilog2() on page 24-19
• ilog10() on page 24-20
• ipow() on page 24-21
• isqrt() on page 24-22
• div_round_up() on page 24-23

24.2.1 min()

Purpose
Get the minimum of two numeric values

Category
Pseudo method

e Language Reference 24-13


Predefined Routines
min()

Syntax
min(x: numeric-type, y: numeric-type): numeric-type

Syntax Example
print min((x + 5), y);

Parameters

x A numeric expression.

y A numeric expression.

Description
Returns the smaller of the two numeric values.

Example
<'
extend sys {
m1() is {
var x:int = 5;
var y: int = 123;
print min((x + 5), y);
};
};
'>

Result
Specman > sys.m1()
min((x + 5), y) = 10

See Also
• “Arithmetic Routines” on page 24-13

24-14 e Language Reference


Predefined Routines
max()

24.2.2 max()

Purpose
Get the maximum of two numeric values

Category
Pseudo method

Syntax
max(x: numeric-type, y: numeric-type): numeric-type

Syntax Example
print max((x + 5), y);

Parameters

x A numeric expression.

y A numeric expression.

Description
Returns the larger of the two numeric values.

Example
<'
extend sys {
m1() is {
var x:int = 5;
var y: int = 123;
print max((x + 5), y);
};
};
'>

Result
Specman > sys.m1()

e Language Reference 24-15


Predefined Routines
abs()

max((x + 5), y) = 123

See Also
• “Arithmetic Routines” on page 24-13

24.2.3 abs()

Purpose
Get the absolute value

Category
Routine

Syntax
abs(x: numeric-type): numeric-type

Syntax Example
print abs(x);

Parameter

x A numeric expression.

Description
Returns the absolute value of the expression.

Example
<'
extend sys {
m1() is {
var x: int = -5;
print abs(x);
};
};
'>

24-16 e Language Reference


Predefined Routines
odd()

Result
Specman > sys.m1()
abs(x) = 5

See Also
• “Arithmetic Routines” on page 24-13

24.2.4 odd()

Purpose
Check if an integer is odd

Category
Routine

Syntax
odd(x: int): bool

Syntax Example
print odd(x);

Parameter

x An integer expression.

Description
Returns TRUE if the integer is odd, FALSE if the integer is even.

Example
<'
extend sys {
m1() is {
var x: int = -5;
print odd(x);

e Language Reference 24-17


Predefined Routines
even()

};
};
'>

Result
Specman > sys.m1()
odd(x) = TRUE

See Also
• “Arithmetic Routines” on page 24-13

24.2.5 even()

Purpose
Check if an integer is even

Category
Routine

Syntax
even(x: int): bool

Syntax Example
print even(x);

Parameter

x An integer expression.

Description
Returns TRUE if the integer passed to it is even, FALSE if the integer is odd.

Example
<'

24-18 e Language Reference


Predefined Routines
ilog2()

extend sys {
m1() is {
var x: int = -5;
print even(x);
};
};
'>

Result
Specman > sys.m1()
even(x) = FALSE

See Also
• “Arithmetic Routines” on page 24-13

24.2.6 ilog2()

Purpose
Get the base-2 logarithm

Category
Routine

Syntax
ilog2(x: uint): int

Syntax Example
print ilog2(x);

Parameter

x An unsigned integer expression.

Description
Returns the integer part of the base-2 logarithm of x.

e Language Reference 24-19


Predefined Routines
ilog10()

Example
<'
extend sys {
m1() is {
var x: int = 1034;
print ilog2(x);
};
};
'>

Result
Specman > sys.m1()
ilog2(x) = 10

See Also
• “Arithmetic Routines” on page 24-13

24.2.7 ilog10()

Purpose
Get the base-10 logarithm

Category
Routine

Syntax
ilog10(x: uint): int

Syntax Example
print ilog10(x);

Parameter

x An unsigned integer expression.

24-20 e Language Reference


Predefined Routines
ipow()

Description
Returns the integer part of the base-10 logarithm of x.

Example
<'
extend sys {
m1() is {
var x: int = 1034;
print ilog10(x);
};
};
'>

Result
Specman > sys.m1()
ilog10(x) = 3

See Also
• “Arithmetic Routines” on page 24-13

24.2.8 ipow()

Purpose
Raise to a power

Category
Routine

Syntax
ipow(x: int, y: int): int

Syntax Example
print ipow(x, y);

e Language Reference 24-21


Predefined Routines
isqrt()

Parameters

x An integer expression.

y An integer expression.

Description
Raises x to the power of y and returns the integer result.

Example
<'
extend sys {
m1() is {
var x: int = 4;
var y: int = 3;
print ipow(x, y);
};
};
'>

Result
Specman > sys.m1()
ipow(x, y) = 64

See Also
• “Arithmetic Routines” on page 24-13

24.2.9 isqrt()

Purpose
Get the square root

Category
Routine

24-22 e Language Reference


Predefined Routines
div_round_up()

Syntax
isqrt(x: uint): int

Syntax Example
print isqrt(x);

Parameter

x An unsigned integer expression.

Description
Returns the integer part of the square root of x.

Example
<'
extend sys {
m1() is {
var x: int = 67;
print isqrt(x);
};
};
'>

Result
Specman > sys.m1()
isqrt(x) = 8

See Also
• “Arithmetic Routines” on page 24-13

24.2.10 div_round_up()

Purpose
Division rounded up

e Language Reference 24-23


Predefined Routines
div_round_up()

Category
Routine

Syntax
div_round_up(x: int, y: int): int

Syntax Example
print div_round_up(x, y);

Parameters

x An integer expression. to use as the dividend.

y An integer expression to use as the divisor.

Description
Returns the result of x / y rounded up to the next integer.

Example
<'
extend sys {
m1() is {
var x: int = 5;
var y: int = 2;
print div_round_up(x, y);
};
};
'>

Result
Specman > sys.m1()
div_round_up(x, y) = 3

See Also
• “Arithmetic Routines” on page 24-13
• “/” arithmetic operator in + - * / % on page 2-52

24-24 e Language Reference


Predefined Routines
Bitwise Routines

24.3 Bitwise Routines


The predefined bitwise routines perform Boolean operations bit-by-bit and return a single-bit result.

24.3.1 bitwise_op()

Purpose
Perform a Verilog-style unary reduction operation

Category
Pseudo-method

Syntax
bitwise_op(exp: int|uint): bit

Syntax Example
print bitwise_and(b);

Parameters

op One of and, or, xor, nand, nor, xnor.

exp A 32-bit numeric expression.

Description
Performs a Verilog-style unary reduction operation on a single operand to produce a single bit result.
There is no reduction operator in e, but the bitwise_op() routines perform the same functions as
reduction operators in Verilog. For example, you can use bitwise_xor() to calculate parity.

For bitwise_nand(), bitwise_nor(), and bitwise_xnor(), the result is computed by inverting the result of
the bitwise_and(), bitwise_or(), and bitwise_xor() operation, respectively.

Table 24-1 shows the predefined pseudo-methods for bitwise operations.

e Language Reference 24-25


Predefined Routines
Bitwise Routines

Table 24-1 Bitwise Operation Pseudo-Methods

Pseudo-Method Operation

bitwise_and() Boolean AND of all bits

bitwise_or() Boolean OR of all bits

bitwise_xor() Boolean XOR of all bits

bitwise_nand() !bitwise_and()

bitwise_nor() !bitwise_or()

bitwise_xnor() !bitwise_xor()

Note
These routines cannot be used to perform bitwise operations on unbounded integers.

Example 1
<'
struct nums {
m1() is {
var b: uint = 0xffffffff;
print bitwise_and(b);
print bitwise_nand(b);
};
};

extend sys {
pmi:nums;
};
'>

Result
vrst-tool> sys.pmi.m()
bitwise_and(b) = 1
bitwise_nand(b) = 0

Example 2
<'
struct nums {
m1() is {

24-26 e Language Reference


Predefined Routines
Bitwise Routines

var b: uint = 0xcccccccc;


print bitwise_or(b);
print bitwise_nor(b);
};
};

extend sys {
pmi:nums;
};
'>

Result
vrst-tool> sys.pmi.m()
bitwise_or(b) = 1
bitwise_nor(b) = 0

Example 3
<'
struct nums {
m1() is {
var b: uint = 0x1;
print bitwise_xor(b);
print bitwise_xnor(b);
};
};

extend sys {
pmi:nums;
};
'>

Result
vrst-tool> sys.pmi.m()
bitwise_xor(b) = 1
bitwise_xnor(b) = 0

See Also
• “Arithmetic Routines” on page 24-13

e Language Reference 24-27


Predefined Routines
String Routines

24.4 String Routines


None of the string routines in e modify the input parameters. When you pass a parameter to one of these
routines, the routine makes a copy of the parameter, manipulates the copy, and returns the copy.

You can use the as_a() casting operator to convert strings to integers or bytes. See Table 3-5, Type
Conversion Between Strings and Scalars or Lists of Scalars.

Routines that convert expressions into a string:

• append() on page 24-29


• appendf() on page 24-31
• quote() on page 24-36
• to_string() on page 24-59
Routines that manipulate substrings:

• str_join() on page 24-44


• str_split() on page 24-54
• str_split_all() on page 24-56
• str_sub() on page 24-57
Routines that manipulate regular expressions:

• str_match() on page 24-47


• str_replace() on page 24-51
• str_insensitive() on page 24-43
Routines that change the radix of a numeric expression:

• bin() on page 24-32


• dec() on page 24-34
• hex() on page 24-35
Routines that manipulate the length of an expression:

• str_chop() on page 24-38


• str_empty() on page 24-39
• str_exactly() on page 24-40

24-28 e Language Reference


Predefined Routines
append()

• str_len() on page 24-45


• str_pad() on page 24-50
Routines that are useful within Specman macros:

• quote() on page 24-36


• str_expand_dots() on page 24-41
Routines that manipulate the case of characters within a string:

• str_lower() on page 24-46


• str_upper() on page 24-58
• str_insensitive() on page 24-43

See Also
• “String Matching” on page 2-65
• “The string Type” on page 3-15
• Table 3-5 on page 3-43
• “File Routines” on page 24-91

24.4.1 append()

Purpose
Concatenate expressions into a string

Category
Routine

Syntax
append(): string

append(item: exp, …): string

Syntax Example
message = append(list1, " ", list2);

e Language Reference 24-29


Predefined Routines
append()

Parameter

item A legal e expression. String expressions must be enclosed in double quotes. If the
expression is a struct instance, the struct ID is printed. If no items are passed to append(),
it returns an empty string.

Description
Calls to_string() on page 24-59 to convert each expression to a string using the current radix setting for
any numeric expressions, then concatenates them and returns the result as a single string.

Note
If you are concatenating a very large number of strings (for example, a long list of strings) into a single
string, it is better to use str_join(), for performance reasons. If there are 10000 items in my_list, the for
loop shown below makes 10000 copies of the lengthening string, hence creating an n**2 effect:
foo = "";
for each in l {
foo = append(foo, it);
};

In contrast, the following will create a string of the right length and do a single copy operation:
foo = str_join(l, "");

Example
extend sys {
m1() is {
var message: string;
var u1:uint = 55;
var u2:uint = 44;
message = append(u1, " ", u2);
print message;
var list1:list of bit = {0;1;0;1};
var list2:list of bit = {1;1;1;0};
message = append(list1, " ", list2);
print message;
};
};

Result
The radix setting for this example was hex.

24-30 e Language Reference


Predefined Routines
appendf()

Specman > sys.m1()


message = "0x37 0x2c"
message = "0x0 0x1 0x0 0x1 0x1 0x1 0x1 0x0"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.2 appendf()

Purpose
Concatenate expressions into a string according to a given format

Category
Routine

Syntax
appendf(format: string, item: exp, …): string

Syntax Example
message = appendf("%4d\n %4d\n %4d\n", 255, 54, 1570);

Parameters

format A string expression containing a standard C formatting mask for each item. See “Format
String” on page 24-65 for more information.

item A legal e expression. String expressions must be enclosed in double quotes. If the
expression is a struct instance, the struct ID is printed.

Description
Converts each expression to a string using the current radix setting for any numeric expressions and the
specified format, then concatenates them and returns the result as a single string.

e Language Reference 24-31


Predefined Routines
bin()

Note
If the number and type of masks in the format string does not match the number and type of expressions,
an error is issued.

Example
<'
extend sys {
m1() is {
var message: string;
message = appendf("%4d\n %4d\n %4d\n", 255, 54, 1570);
out(message);
};
};
'>

Result
The radix setting for this example was DEC.
Specman > sys.m1()
255
54
1570

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.3 bin()

Purpose
Concatenate expressions into string, using binary representation for numeric types

Category
Routine

24-32 e Language Reference


Predefined Routines
bin()

Syntax
bin(item: exp, …): string

Syntax Example
var my_string: string = bin(pi.i, " ", list1, " ",8);

Parameter

item A legal e expression. String expressions must be enclosed in double quotes.


If the expression is a struct instance, the struct ID is printed.

Description
Concatenates one or more expressions into a string, using binary representation for any expressions of
numeric types, regardless of the current radix setting.

Example
<'
struct p {
i:int;
};

extend sys {
pi:p;
m1() is {
pi = new;
pi.i = 11;
var list1:list of bit = {0;1;1;0};
var my_string: string = bin(pi.i, " ", list1, " ",8);
print my_string;
};
};
'>

Result
Specman > sys.m1()
my_string = "0b1011 0b0 0b1 0b1 0b0 0b1000"

See Also
• “String Routines” on page 24-28

e Language Reference 24-33


Predefined Routines
dec()

• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.4 dec()

Purpose
Concatenate expressions into string, using decimal representation for numeric types

Category
Routine

Syntax
dec(item: exp, …): string

Syntax Example
var my_string: string = dec(pi.i, " ", list1, " ",8);

Parameter

item A legal e expression. String expressions must be enclosed in double quotes. If the
expression is a struct instance, the struct ID is printed.

Description
Concatenates one or more expressions into a string, using decimal representation for any expressions of
numeric types, regardless of the current radix setting.

Example
<'
struct p {
i:int;
};

extend sys {
pi:p;
m1() is {
pi = new;
pi.i = 11;

24-34 e Language Reference


Predefined Routines
hex()

var list1:list of bit = {0;1;1;0};


var my_string: string = dec(pi.i, " ", list1, " ",8);
print my_string;
};
};
'>

Result
Specman > sys.m1()
my_string = "11 0 1 1 0 8"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.5 hex()

Purpose
Concatenate expressions into string, using hexadecimal representation for numeric types

Category
Routine

Syntax
hex(item: exp, …): string

Syntax Example
var my_string: string = hex(pi.i, " ", list1, " ",8);

Parameter

item A list of one or more legal e expressions. String expressions must be enclosed in double
quotes. If the expression is a struct instance, the struct ID is printed.

e Language Reference 24-35


Predefined Routines
quote()

Description
Concatenates one or more expressions into a string, using hexadecimal representation for any
expressions of numeric types, regardless of the current radix setting.

Example
<'
struct p {
i: int;
};

extend sys {
pi: p;
m1() is {
pi = new;
pi.i = 11;
var list1:list of bit = {0;1;1;0};
var my_string: string = hex(pi.i, " ", list1, " ",8);
print my_string;
};
};
'>

Result
Specman > sys.m1()
my_string = "0xb 0x0 0x1 0x1 0x0 0x8"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.6 quote()

Purpose
Enclose a string within double quotes

24-36 e Language Reference


Predefined Routines
quote()

Category
Routine

Syntax
quote(text: string): string

Syntax Example
out(quote(message));

Parameter

text An expression of type string.

Description
Returns a copy of the text, enclosed in double quotes (" "), with any internal quote or backslash preceded
by a backslash (\).

This routine is useful when creating commands with define.

Example
<'
extend sys {
m1() is {
var message: string = "Error occurred in \"D\" block...";
out(message);
out(quote(message));
};
};
'>

Result
Specman > sys.m1()
Error occurred in "D" block...
"Error occurred in \"D\" block..."

See Also
• “String Routines” on page 24-28

e Language Reference 24-37


Predefined Routines
str_chop()

• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.7 str_chop()

Purpose
Chop the tail of a string

Category
Routine

Syntax
str_chop(str: string, length: int): string

Syntax Example
var test_dir: string = str_chop(tmp_dir, 13);

Parameters

str An expression of type string.

length An integer representing the desired length.

Description
Returns str (if its length is <= length), or a copy of the first length chars of str.

Removes characters from the end of a string, returning a string of the desired length. If the original string
is already less than or equal to the desired length, this routine returns a copy of the original string.

Example
<'
extend sys {
m1() is {
var tmp_dir: string = "/rtests/test1/tmp";
var test_dir: string = str_chop(tmp_dir, 13);
print test_dir;
};
};

24-38 e Language Reference


Predefined Routines
str_empty()

'>

Result
Specman > sys.m1()
test_dir = "/rtests/test1"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.8 str_empty()

Purpose
Check if a string is empty

Category
Routine

Syntax
str_empty(str: string): bool

Syntax Example
print str_empty(s1);

Parameter

str An expression of type string.

Description
Returns TRUE if the string is uninitialized or empty.

Example
<'

e Language Reference 24-39


Predefined Routines
str_exactly()

extend sys{
m1() is {
var s1: string;
var s2: string = "";
print str_empty(s1);
print str_empty(s2);
};
};
'>

Result
Specman > sys.m1()
str_empty(s1) = TRUE
str_empty(s2) = TRUE

See Also
• “String Routines” on page 24-28

24.4.9 str_exactly()

Purpose
Get a string with exact length

Category
Routine

Syntax
str_exactly(str: string, length: int): string

Syntax Example
var long: string = str_exactly("123", 6);

Parameters

str An expression of type string.

24-40 e Language Reference


Predefined Routines
str_expand_dots()

length An integer representing the desired length.

Description
Returns a copy of the original string, whose length is the desired length, by adding blanks to the right or
by truncating the expression from the right as necessary. If non-blank characters are truncated, the *
character appears as the last character in the string returned.

Example
<'
extend sys {
m1() is {
var short: string = str_exactly("123000",3);
print short;
var long: string = str_exactly("123", 6);
print long;
};
};
'>

Result
Specman > sys.m1()
short = "12*"
long = "123 "

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.10 str_expand_dots()

Purpose
Expand strings shortened by the parser

Category
Routine

e Language Reference 24-41


Predefined Routines
str_expand_dots()

Syntax
str_expand_dots(str: string): string

Syntax Example
out("After expand: ",str_expand_dots(<1>));

Parameter

str An expression of type string.

Description
Returns a copy of the original string, expanding any dot place holders into the actual code they represent.

This routine is useful only in context of define as [computed] statements. When preprocessing an e file,
Specman converts any sequence of characters between matching brackets or quotes (such as (), [], {}, or
" ") into compressed code, with dots as place holders. If you want to retrieve the original string, not just
the compressed code, you can use this routine.

Example
To retrieve the original string passed to my_macro, the str_expand_dots() routine is called.
<'
define <my_macro'command> "my_macro (\
\"<string>\")" as computed {
out("Before expand: ", <1>);
out("After expand: ",str_expand_dots(<1>));
result = "{}"
};
'>

Result
Specman > my_macro "hello world"
Before expand: "10"
After expand: "hello world"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24-42 e Language Reference


Predefined Routines
str_insensitive()

24.4.11 str_insensitive()

Purpose
Get a case-insensitive AWK-style regular-expression

Category
Routine

Syntax
str_insensitive(regular_exp: string): string

Syntax Example
var insensitive: string = str_insensitive("/hello.*/");

Parameter

regular-exp An AWK-style regular expression.

Description
Returns an AWK-style regular expression string which is the case-insensitive version of the original
regular expression.

Example
<'
extend sys {
m1() is {
var insensitive: string = str_insensitive("/hello.*/");
print insensitive;
};
};
'>

Result
Specman > sys.m1()
insensitive = "/[Hh][Ee][Ll][Ll][Oo].*/"

e Language Reference 24-43


Predefined Routines
str_join()

See Also
• “AWK-Style String Matching” on page 2-67
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.12 str_join()

Purpose
Concatenate a list of strings

Category
Routine

Syntax
str_join(list: list of string, separator: string): string

Syntax Example
var s := str_join(slist," - ");

Parameters

list A list of type string.

separator The string that will be used to separate the list elements.

Description
Returns a single string which is the concatenation of the strings in the list of strings, separated by the
separator.

Example
<'
extend sys {
m1() is {
var slist: list of string = {"first";"second";"third"};

24-44 e Language Reference


Predefined Routines
str_len()

var s := str_join(slist," - ");


print s;
};
};
'>

Result
Specman > sys.m1()
s = "first - second - third"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.13 str_len()

Purpose
Get string length

Category
Routine

Syntax
str_len(str: string): int

Syntax Example
var length: int = str_len("hello");

Parameter

str An expression of type string.

Description
Returns the number of characters in the original string, not counting the terminating NULL character \0.

e Language Reference 24-45


Predefined Routines
str_lower()

Example
<'
extend sys {
m1() is {
var length: int = str_len("hello");
print length;
};
};
'>

Result
Specman > sys.m1()
length = 5

See Also
• “String Routines” on page 24-28

24.4.14 str_lower()

Purpose
Convert string to lowercase

Category
Routine

Syntax
str_lower(str: string): string

Syntax Example
var lower: string = str_lower("UPPER");

Parameter

str An expression of type string.

24-46 e Language Reference


Predefined Routines
str_match()

Description
Converts all upper case characters in the original string to lower case and returns the string.

Example
<'
extend sys {
m1() is {
var lower: string = str_lower("UPPER");
print lower;
};
};
'>

Result
Specman > sys.m1()
lower = "upper"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.15 str_match()

Purpose
Match strings

Category
Routine

Syntax
str_match(str: string, regular-exp: string): bool

Syntax Example
print str_match("ace", "/c(e)?$/");

e Language Reference 24-47


Predefined Routines
str_match()

Parameters

str An expression of type string.

regular-exp An AWK-style or native Specman regular expression. If not surrounded by


slashes, the expression is treated as a native style expression. See “String
Matching” on page 2-65 for more information on these types of expressions.

Description
Returns TRUE if the strings match, or FALSE if the strings do not match. The routine str_match() is
fully equivalent to the operator ~.

Example 1
After doing a match, you can use the local pseudo-variables $1, $2…$27, which correspond to the
parenthesized pieces of the match. $0 stores the entire matched piece of the string.

This example uses AWK-style regular expressions. See “AWK-Style String Matching” on page 2-67 for
more information on these types of expressions.
<'
extend sys {
m1() is {
print str_match("a", "/^(a)?(b)?$/"); -- matches "ab", "a", or "b"
print $0, $1, $2;
print str_match("hello","/^\\d*$/"); -- matches string with 0
-- or more digits
print $0, $1, $2;
print str_match("ab", "/^(a)?(b)?$/");
print $0, $1, $2;
print str_match("ace", "/c(e)?$/"); -- matches string ending
-- in "c" or "ce"
print $0, $1;
};
};
'>

Result
Specman > sys.m1()
str_match("a", "/^(a)?(b)?$/") = TRUE
$0 = "a" -- stores the entire matched portion of the string
$1 = "a" -- stores the first match
$2 = ""
str_match("hello","/^\\d*$/") = FALSE

24-48 e Language Reference


Predefined Routines
str_match()

$0 = "a" -- the values from the previous call to str_match() persist


$1 = "a"
$2 = ""
str_match("ab", "/^(a)?(b)?$/") = TRUE
$0 = "ab"
$1 = "a"
$2 = "b"
str_match("ace", "/c(e)?$/") = TRUE
$0 = "ce"
$1 = "e"

Example 2
This example uses native Specman regular expressions. See “Native Specman String Matching” on page
2-65 for more information on these types of expressions. The * character matches any sequence of
non-white characters, while the "..." string matches any sequence of characters, including white space.
<'
extend sys {
m1() is {
var s:string = "a bc";
print str_match(s, "a*");
print $0, $1, $2;
print str_match(s, "* *");
print $0, $1, $2;
print str_match(s, "a...");
print $0, $1, $2;
};
};
'>

Result
Specman > sys.m1()
str_match(s, "a*") = FALSE
$0 = ""
$1 = ""
$2 = ""
str_match(s, "* *") = TRUE
$0 = "a bc"
$1 = "a"
$2 = "bc"
str_match(s, "a...") = TRUE
$0 = "a bc"
$1 = " bc"
$2 = ""

e Language Reference 24-49


Predefined Routines
str_pad()

See Also
• “String Routines” on page 24-28
• ~ !~ on page 2-60

24.4.16 str_pad()

Purpose
Pad string with blanks

Category
Routine

Syntax
str_pad(str: string, length: int): string

Syntax Example
var s: string = str_pad("hello world",14);

Parameters

str An expression of type string.

length An integer representing the desired length, no greater than 4000.

Description
Returns a copy of the original string padded with blanks on the right, up to desired length. If the length
of the original string is greater than or equal to the desired length, then the original string is returned (not
a copy) with no padding.

Example
<'
extend sys {
m1() is {
var s: string = str_pad("hello world",14);
print s;

24-50 e Language Reference


Predefined Routines
str_replace()

};
};
'>

Result
Specman > sys.m1()
s = "hello world "

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.17 str_replace()

Purpose
Replace a substring in a string with another string

Category
Routine

Syntax
str_replace(str: string, regular-exp: string, replacement: string): string

Syntax Example
var s: string = str_replace("crc32", "/(.*32)/", "32_flip");

Parameters

str An expression of type string.

regular-exp An AWK-style or native Specman regular expression. If not surrounded by


slashes, the expression is treated as a native style expression. See “String
Matching” on page 2-65 for more information on these types of expressions.

replacement The string that you want to replace all occurrences of the regular expression.

e Language Reference 24-51


Predefined Routines
str_replace()

Description
A new copy of the original string is created, and then all the matches of the regular expression are
replaced by the replacement string. If no match is found, a copy of the source string is returned.

To incorporate the matched substrings in the replacement string, use back-slash escaped numbers \1, \2,

In native Specman regular expressions, the portion of the original string that matches the * or the …
characters is replaced by the replacement string.

In AWK-style regular expressions, you can mark the portions of the regular expressions that you want to
replace with parentheses. For example, the following regular expression marks all the characters after
“on”, up to and including “th” to be replaced.
"/on(.*th)/"

Example 1
This example uses AWK-style string matching.
<'
extend sys {
m1() is {
var new_str : string = str_replace("testing one two \
three", "/on(.*th)/" , "f");
print new_str;
};
};
'>

Result
Specman > sys.m1()
new_str = "testing free"

Example 2
Another AWK-style example, using \1, \2:
<'
extend sys {
m1() is {
var new_str : string = str_replace("A saw B",
"/(.*) saw (.*)/" , "\2 was seen by \1");
print new_str;
};

24-52 e Language Reference


Predefined Routines
str_replace()

};
'>

Result
Specman > sys.m1()
new_str = "B was seen by A"

Example 3
This example uses a Specman-style regular expression.
<'
extend sys {
m1() is {
var new_str: string=str_replace("abc z", "a* " , "xy");
print new_str;
};
};
'>

Result
Specman > sys.m1()
new_str = "xyz"

Example 4
This example uses a Specman-style regular expression with \1.
<'
extend sys {
m1() is {
var new_str: string=str_replace("abc ghi", "* " , "\1 def ");
print new_str;
};
};
'>

Result
Specman > sys.m1()
new_str = "abc def ghi"

e Language Reference 24-53


Predefined Routines
str_split()

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.18 str_split()

Purpose
Split a string to substrings

Category
Routine

Syntax
str_split(str: string, regular-exp: string): list of string

Syntax Example
var s: list of string = str_split("first-second-third", "-");

Parameters

str An expression of type string.

regular-exp An AWK-style or native Specman-style regular expression that


specifies where to split the string. See “String Matching” on page
2-65 for more information on these types of expressions.

Description
Splits the original string on each occurrence of the regular expression, and returns a list of strings. If the
regular expression occurs at the beginning or the end of the original string, an empty string is returned.

If the regular expression is an empty string, it has the effect of removing all blanks in the original string.

Example 1
<'
extend sys {

24-54 e Language Reference


Predefined Routines
str_split()

m1() is {
var s: list of string=str_split("one-two-three", "-");
print s;
};
};
'>

Result
Specman > sys.m1()
s =
0. "one"
1. "two"
2. "three"

Example 2
<'
extend sys {
m1() is {
var s: list of string = str_split(" A B C", "/ +/");
print s;
};
};
'>

Result
Specman > sys.m1()
s =
0. ""
1. "A"
2. "B"
3. "C"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

e Language Reference 24-55


Predefined Routines
str_split_all()

24.4.19 str_split_all()

Purpose
Split a string to substrings, including separators

Category
Routine

Syntax
str_split_all(str: string, regular-exp: string): list of string

Syntax Example
var s: list of string = str_split_all(" A B C", "/ +/");

Parameters

str An expression of type string.

regular-exp An AWK-style or native Specman-style regular expression that specifies where to


split the string. See “String Matching” on page 2-65 for more information on these
types of expressions.

Description
Splits the original string on each occurrence of the regular expression, and returns a list of strings. If the
regular expression occurs at the beginning or the end of the original string, an empty string is returned.

This routine is similar to str_split(), except that it includes the separators in the resulting list of strings.

Example
<'
extend sys {
m1() is {
var s: list of string = str_split_all(" A B C", "/ +/");
print s;
};
};
'>

24-56 e Language Reference


Predefined Routines
str_sub()

Result
Specman > sys.m1()
s =
0. ""
1. " "
2. "A"
3. " "
4. "B"
5. " "
6. "C"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.20 str_sub()

Purpose
Extract a substring from a string

Category
Routine

Syntax
str_sub(str: string, from: int, length: int): string

Syntax Example
var dir: string = str_sub("/rtests/test32/tmp", 8, 6);

Parameters

str An expression of type string.

from The index position from which to start extracting. The first character in the string is at
index 0.

e Language Reference 24-57


Predefined Routines
str_upper()

length An integer representing the number of characters to extract.

Description
Returns a substring of the specified length from the original string, starting from the specified index
position.

Example
<'
extend sys {
m1() is {
var dir: string = str_sub("/rtests/test32/tmp", 8, 6);
print dir;
};
};
'>

Result
Specman > sys.m1()
dir = "test32"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.21 str_upper()

Purpose
Convert a string to uppercase

Category
Routine

24-58 e Language Reference


Predefined Routines
to_string()

Syntax
str_upper(str: string): string

Syntax Example
var upper: string = str_upper("lower");

Parameter

str An expression of type string.

Description
Returns a copy of the original string, converting all lower case characters to upper case characters.

Example
<'
extend sys {
m1() is {
var upper: string = str_upper("lower");
print upper;
};
};
'>

Result
Specman > sys.m1()
upper = "LOWER"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.4.22 to_string()

Purpose
Convert any expression to a string

e Language Reference 24-59


Predefined Routines
to_string()

Category
Method

Syntax
exp.to_string(): string

Syntax Example
print pkts[0].to_string();

Parameter

exp A legal e expression.

Description
This method can be used to convert any type to a string.

If the expression is a struct expression, the to_string() method returns a unique identification string for
each struct instance. You can use this ID to refer to the struct. In Specview, this ID is hyperlinked to
display the values of that struct instance. By default, the identification string is of the form type-@ num,
where num is a unique struct number over all instances of all structs in the current run.

If the expression is a list of strings, the to_string() method is called for each element in the list. The
string returned contains all the elements with a newline between each element.

If the expression is a list of any type except string, the to_string() method returns a string containing all
the elements with a space between each element.

If the expression is a numeric type, the expression is converted using the current radix with the radix
prefix.

If the expression is a string, the to_string() method returns the string.

If the expression is an enumerated or a Boolean type, the to_string() method returns the value.

Example
<'
struct pkt {
protocol: [ethernet, atm, other];
legal : bool;
data[2]: list of byte;
};

24-60 e Language Reference


Predefined Routines
Output Routines

extend sys {
pkts[5]: list of pkt;
m1() is {
var slist: list of string = {"strA";"strB";"strC"};
print pkts[0].to_string();
print pkts[0].data.to_string();
print pkts[0].protocol.to_string();
print pkts[0].legal.to_string();
print slist.to_string();
};
};
'>

Result
Specman > sys.m1()
pkts[0].to_string() = "pkt-@0"
pkts[0].data.to_string() = "52 218"
pkts[0].protocol.to_string() = "atm"
pkts[0].legal.to_string() = "TRUE"
slist.to_string() = "strA
strB
strC"

See Also
• “String Routines” on page 24-28
• Table 3-5 on page 3-43, for information about type conversion between strings and scalars

24.5 Output Routines


The predefined output routines print formatted and unformatted information to the screen and to open
log files. The following sections describe the output routines:

• out() on page 24-62


• outf() on page 24-63
• “Format String” on page 24-65

e Language Reference 24-61


Predefined Routines
out()

24.5.1 out()

Purpose
Print expressions to output, with a new line at the end

Category
Routine

Syntax
out()

out(item: exp, …)

Syntax Example
out("pkts[1].data is ", pkts[1].data);

Parameter

item A legal e expression. String expressions must be enclosed in double quotes.


If the expression is a struct instance, the struct ID is printed. If no item is
passed to out(), an empty string is printed, followed by a new line.

Description
Calls to_string() to convert each expression to a string and prints them to the screen (and to the log file
if it is open), followed by a new line.

Example
This first example shows that if the expression is a struct, out() prints the ID of the struct. In Specview,
this ID is hyperlinked to a display of the struct fields and current values. If the expression is a list, out()
prints each element of the list from left to right, starting with the element with the lowest index. If no
expression is passed, out() prints a new line.
struct pkt {
protocol: [ethernet, atm, other];
legal : bool;
data[2]: list of byte;

24-62 e Language Reference


Predefined Routines
outf()

};

extend sys {
pkts[5]: list of pkt;
m1() is {
out();
out("ID of first packet is ", pkts[0]);
out("pkts[1].data is ", pkts[1].data);
out("pkts[1].data[0] is ", pkts[1].data[0]);
out();
};
};

Result
Specman > sys.m1()

ID of first packet is pkt-@0


pkts[1].data is 142 170
pkts[1].data[0] is 142

See Also
• outf() on page 24-63
• print on page 9-2in the Specman Command Reference

24.5.2 outf()

Purpose
Print formatted expressions to output, with no new line at the end

Category
Routine

Syntax
outf(format: string, item: exp, …)

Syntax Example
outf("%s %#08x","pkts[1].data[0] is ", pkts[1].data[0]);

e Language Reference 24-63


Predefined Routines
outf()

Parameters

format A string containing a standard C formatting mask for each item. See “Format
String” on page 24-65 for more information.

item A legal e expression. String expressions must be enclosed in double quotes. If the
expression is a struct instance, the struct ID is printed. If the expression is a list,
an error is issued.

Description
Converts each expression to a string using the corresponding format string and then prints them to the
screen (and to the log file if it is open).

To add a new line, add the \n characters to the format string.

Notes
• If the number and type of masks in the format string does not match the number and type of
expressions, an error is issued.
• Specman adds a new line by default after 80 characters. To disable this, set the line size to UNDEF
or to a very large number with the set_config() routine.
set_config(print, line_size, UNDEF);

Example 1
This example has similar results to the in the description of out() on page 24-62. Note that outf() allows
you to add the new lines where needed. Printing of lists is not supported with outf().
extend sys {
pkts[5]: list of pkt;
m1() is {
outf("%s %s\n","pkts[0] ID is ", pkts[0]);
outf("%s %#x","pkts[1].data[0] is ", pkts[1].data[0]);
};
};

Result
Specman > sys.m1()
pkts[0] ID is pkt-@0
pkts[1].data[0] is 0x8e

24-64 e Language Reference


Predefined Routines
Format String

Example 2
This example shows the control over formatting of strings that outf() allows. The fields have been
enclosed in double “:” characters so that you can easily see how wide the field is.
<'
extend sys {
m1() is {
outf(":%s:\n", "hello world");
outf(":%15s:\n", "hello world");
outf(":%-15s:\n", "hello world");
outf(":%.8s:\n", "hello world");
outf(":%08d:\n", 12);
};
};
'>

Result
Specman > sys.m1()
:hello world:
: hello world:
:hello world :
:hello wo:
:00000012:

See Also
• out() on page 24-62
• print on page 9-2 in the Specman Command Reference

24.5.3 Format String


The format string for the outf() and for the appendf() routine uses the following syntax:
"%[0|-][#][min_width][.max_chars](s|d|x|b|o|u)"

0 Pads with 0 instead of blanks. Padding is only done when right alignment is used, on
the left end of the expression.
- Aligns left. The default is to align right.
# Adds 0x before the number. Can be used only with the x (hexadecimal) format
specifier. Examples: %#x, %0#10x

e Language Reference 24-65


Predefined Routines
Configuration Routines

min_width A number that specifies the minimum number of characters. This number determines
the minimum width of the field. If there are not enough characters in the expression to
fill the field, the expression is padded to make it this many characters wide. If there are
more characters in the expression than this number (and if max_chars is set large
enough), this number is ignored and enough space is used to accommodate the entire
expression.
max_chars A number that specifies the maximum number of characters to use from the expression.
Characters in excess of this number are truncated. If this number is larger than
min_width, then the min_width number is ignored.
In the following example, min_width is 7 and max_chars is 5, so the outf() method
prints five characters from “abcdefghi” in a field seven characters wide, padding the two
unused spaces with blanks:
vrst-tool> outf("%7.5s\n", "abcdefghi")
abcde
In the following example, min_width is 8 and max_chars is 3, so the outf() method
prints three characters from “abcdefghi” in a field eight characters wide, padding the
five unused spaces with zeros, since the 0 padding option is present immediately after
the %:
vrst-tool> outf("%08.3s\n", "abcdefghi")
00000abc
s Converts the expression to a string. The routine to_string() on page 24-59 is used to
convert a non-string expression to a string.
d Prints a numeric expression in decimal format.
x Prints a numeric expression in hex format. With the optional # character, adds 0x
before the number.
b Prints a numeric expression in binary format.
o Prints a numeric expression in octal format.
u Prints integers (int and uint) in uint format.

24.6 Configuration Routines


The configuration routines set options that allow you to control printing, memory usage, runtime
characteristics, coverage, generation, and debug from within the e code.

These routines have command line equivalents that are described in detail in the Specman Command
Reference.

• set_config() on page 24-67


• get_config() on page 24-72

24-66 e Language Reference


Predefined Routines
set_config()

• write_config() on page 24-74


• read_config() on page 24-76
• set_retain_state() on page 24-78
• get_retain_state() on page 24-79

24.6.1 set_config()

Purpose
Set configuration options

Category
Routine

Syntax
set_config(category: keyword, option: keyword, value: exp [, option: keyword, value: exp…]) [[with]
{action; …}]

Syntax Example
set_config(print, radix, bin);

Parameters

category Is one of the following: cover[age], data[browser], debug[ger], gen[eration], gui,


mem[ory], misc, print, run, and wave.

e Language Reference 24-67


Predefined Routines
set_config()

option The valid options are different for each category. See the Specman Command
Reference for more information:
• configure cover on page 6-3
• configure databrowser on page 6-11
• configure debugger on page 6-14
• configure gen on page 6-17
• configure gui on page 6-23
• configure memory on page 6-26
• configure misc on page 6-33
• configure print on page 6-36
• configure run on page 6-51
• configure wave on page 6-58

value The valid values are different for each option and are described in the Specman
Command Reference.

Description
This form of the set_config() action sets the specified options of a particular category to the specified
values.

If an action block is specified, the options are set only temporarily during the execution of the action
block.

For the configuration options to be effective, they must be set before the run test phase. The
recommended place to use set_config() is in the sys.setup() method, as follows:
extend sys {
setup() is also {
set_config(category, option, value, ...);
};
};

Example 1
In the following example, the setup() method is extended to set configuration options.
<'
extend sys {
setup() is also {
set_config(print, radix, bin);
set_config(cover, sorted, TRUE);
set_config(gen, seed, random, default_max_list_size,
20);

24-68 e Language Reference


Predefined Routines
set_config()

set_config(run, tick_max, 1000, exit_on, all);


set_config(memory, gc_threshold, 100m);
set_config(misc, warn, FALSE);
};
};
'>

Result
Specman > setup
Specman > show config
configuration options for: print
-radix = BIN
.
.
.
configuration options for: cover
-sorted = TRUE
.
.
.
configuration options for: gen
-seed = 187136885
-default_max_list_size = 20
.
.
.
configuration options for: run
-tick_max = 1000
-exit_on = all
.
.
.
configuration options for: memory
-gc_threshold = 104857600
.
.
.
configuration options for: misc
-warn = FALSE
.
.
.

Example 2
<'

e Language Reference 24-69


Predefined Routines
set_config()

struct packet {
protocol: [atm, eth];
data[10]: list of byte;
};

extend sys {
!pi: list of packet;
post_generate() is also {
set_config(gen, seed, 0xff) with {gen pi;};
};
};
'>

Example 3
The following example demonstrates the difference between setting the show_sub_holes coverage
configuration option to TRUE versus the default setting of FALSE.

Two coverage items, i1 and i2 are defined, both for Boolean fields. A cross item is also defined for the
two items.
<'
extend sys {
i1: bool;
i2: bool;
event cv;
cover cv is {
item i1;
item i2;
cross i1, i2;
};
run() is also {
emit cv;
};
};
extend sys {
setup() is also {
set_config(cover, mode, on, show_mode, both);
};
};
'>

In the test, i1 gets FALSE and i2 gets TRUE.

The cross i1, i2 section of the coverage data with show_sub_holes = FALSE is shown below. In this
example, since i1 = TRUE is an empty top bucket, the coverage report does not show the non-existent
sub-buckets for i1 = TRUE, i2 = X.

24-70 e Language Reference


Predefined Routines
set_config()

** cross__i1__i2 **
Samples: 1 Tests: 1 Grade: 0.25 Weight: 1

grade goal samples tests %p/% i1/i2

0.50 - 1 1 100/100 FALSE


0.00 1 0 0 0/0 FALSE/FALSE
1.00 1 1 1 100/100 FALSE/TRUE
0.00 - 0 0 0/0 TRUE

The cross i1, i2 section of the coverage data with show_sub_holes = TRUE is shown below. In this
example, the coverage data shows the tree under the empty top bucket for i1 = TRUE, and expands the
two empty sub-buckets under it, i1/i2 = TRUE/FALSE and i1/12=TRUE/TRUE.

** cross__i1__i2 **
Samples: 1 Tests: 1 Grade: 0.25 Weight: 1

grade goal samples tests %p/%t i1/i2

0.50 - 1 1 100/100 FALSE


0.00 1 0 0 0/0 FALSE/FALSE
1.00 1 1 1 100/100 FALSE/TRUE
0.00 - 0 0 0/0 TRUE
0.00 1 0 0 0/0 TRUE/FALSE
0.00 1 0 0 0/0 TRUE/TRUE

See Also
• “Configuration Routines” on page 24-66
• set_config_max() on page 5-37
• configure cover on page 6-3 in the Specman Command Reference
• configure debugger on page 6-14 in the Specman Command Reference
• configure gen on page 6-17 in the Specman Command Reference
• configure gui on page 6-23 in the Specman Command Reference
• configure memory on page 6-26 in the Specman Command Reference
• configure misc on page 6-33 in the Specman Command Reference
• configure print on page 6-36 in the Specman Command Reference
• configure run on page 6-51 in the Specman Command Reference
• configure wave on page 6-58 in the Specman Command Reference

e Language Reference 24-71


Predefined Routines
get_config()

24.6.2 get_config()

Purpose
Get the configuration option settings

Category
Routine

Syntax
get_config(category: exp, option: exp)

Syntax Example
var s: int = get_config(gen, seed);

Parameters

category Is one of the following: cover, debugger, gen, gui, memory, misc, print, run, and
wave.

option The valid options are different for each category. See the Specman Command
Reference for more information:

configure cover on page 6-3


configure debugger on page 6-14
configure gen on page 6-17
configure gui on page 6-23
configure memory on page 6-26
configure misc on page 6-33
configure print on page 6-36
configure run on page 6-51
configure wave on page 6-58

Description
Returns the value of the configuration option. The type of the returned value depends on the specified
option.

24-72 e Language Reference


Predefined Routines
get_config()

Example
<'
struct packet {
protocol: [atm, eth];
data[10]: list of byte;
};

extend sys {
!pi: list of packet;

post_generate() is also {
set_config(gen, seed, 0xff) with {
gen pi;
var seed: int = get_config(gen, seed);
set_config(print, radix, hex) with {
print seed;
var radix: po_radix = get_config(print, radix);
print radix;
print get_config(print, radix).type().name;
};
};
};
};
'>

Results
vrst-tool> test
Doing setup ...
Generating the test using seed 0x1...
seed = 0xff
radix = HEX
get_config(print, radix).type().name = "po_radix"
Starting the test ...
Running the test ...
No actual running requested.
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.

See Also
• “Configuration Routines” on page 24-66
• configure cover on page 6-3 in the Specman Command Reference
• configure debugger on page 6-14 in the Specman Command Reference

e Language Reference 24-73


Predefined Routines
write_config()

• configure gen on page 6-17 in the Specman Command Reference


• configure gui on page 6-23 in the Specman Command Reference
• configure memory on page 6-26 in the Specman Command Reference
• configure misc on page 6-33 in the Specman Command Reference
• configure print on page 6-36 in the Specman Command Reference
• configure run on page 6-51 in the Specman Command Reference
• configure wave on page 6-58 in the Specman Command Reference

24.6.3 write_config()

Purpose
Save configuration options in a file

Category
Routine

Syntax
write_config(filename: string)

Syntax Example
write_config("test25");

Parameter

filename A string enclosed in double quotes and containing the name of a file. If a filename is
entered with no filename extension, the default extension .ecfg is used.

Description
Creates a file with the specified name and writes the current configuration options to the file.

The read_config() method can be used to read the configuration options back in from the file.

24-74 e Language Reference


Predefined Routines
write_config()

Example
<'
struct packet {
protocol: [atm, eth];
data[10]: list of byte;
};

extend sys {
pi: list of packet;
};

extend sys {
setup() is also {
set_config(print, radix, bin);
set_config(cover, sorted, TRUE);
set_config(gen, seed, random, default_max_list_size, 20);
set_config(run, tick_max, 1000, exit_on, all);
set_config(memory, gc_threshold, 100m);
set_config(misc, warn, FALSE);
write_config("test25");
};
};
'>

Result
% cat test25.ecfg
-- The top struct
struct: config_all-@0:

print: print config_options-@1:


category: print
print'radix: BIN
print'items: 0b10100
print'list_lines: 0b10100
print'list_from: 0b0
print'title: NULL
.
.
.

See Also
• “Configuration Routines” on page 24-66
• write config to on page 6-66 in the Specman Command Reference

e Language Reference 24-75


Predefined Routines
read_config()

24.6.4 read_config()

Purpose
Read configuration options from a file

Category
Routine

Syntax
read_config(filename: string)

Syntax Example
read_config("test25");

Parameter

filename A string enclosed in double quotes and containing the name of a file. If a filename is
entered with no filename extension, the default extension .ecfg is used.

Description
Read configuration options from a file with the specified name. The configuration options must
previously have been written to the file using the write_config() method.

Example
<'
struct packet {
protocol: [atm, eth];
data[10]: list of byte;
};

extend sys {
pi: list of packet;

setup() is also {
read_config("test25");
};
};

24-76 e Language Reference


Predefined Routines
read_config()

'>

Result
Specman > setup
Specman > show config
configuration options for: print
-radix = BIN
.
.
.
configuration options for: cover
-sorted = TRUE
.
.
.
configuration options for: gen
-seed = 908142002
-default_max_list_size = 20
.
.
.
configuration options for: run
-tick_max = 1000
-exit_on = all
.
.
.
configuration options for: memory
-gc_threshold = 104857600
.
.
.
configuration options for: misc
-warn = FALSE
.
.
.

See Also
• “Configuration Routines” on page 24-66
• read config from on page 6-67 in the Specman Command Reference

e Language Reference 24-77


Predefined Routines
set_retain_state()

24.6.5 set_retain_state()

Purpose
Set or reset the retain state mode

Category
Routine

Syntax
set_retain_state(bool: exp)

Syntax Example
set_retain_state(FALSE);

Parameter

bool If TRUE, Specman keeps configuration, breakpoint, trace and watch


information across all restores and reloads. If FALSE, this information is
reset at each reload or restore, using the information from the initial .esv file
instead. The default is TRUE.

Description
Sets or resets the retain state mode, which controls whether configuration settings and debugger
information is retained across restores and reloads.

This routine is exactly equivalent to the retain state command.

Notes
• When restoring from a specified .esv file, the retain state mode is ignored and the information is
taken from the specified .esv file.
• The retain state mode itself is kept across restores and reloads, unless you are restoring from a
specified .esv file. In that case, the new retain state mode is taken from the specified .esv file.
• You can override the retain state mode by using the -retain or -noretain options on the restore or
reload commands.

24-78 e Language Reference


Predefined Routines
get_retain_state()

Example
<'
extend sys {
setup() is also {
set_retain_state(FALSE);
};
};
'>

See Also
• get_retain_state() on page 24-79
• retain state on page 3-15 in the Specman Command Reference
• show retain state on page 3-16 in the Specman Command Reference
• restore on page 3-11 in the Specman Command Reference
• reload on page 3-13 in the Specman Command Reference

24.6.6 get_retain_state()

Purpose
Retrieve the value of the retain state mode

Category
Routine

Syntax
get_retain_state(): bool

Syntax Example
print get_retain_state();

Description
Retrieves the value of the retain state mode, which controls whether configuration settings and
debugger information is retained across restores and reloads.

e Language Reference 24-79


Predefined Routines
Specman Command Routine

This method is similar to the show retain state command.

Example
<'
extend sys {
setup() is also {
print get_retain_state();
set_retain_state(TRUE);
print get_retain_state();
};
};
'>

Result
vrst-tool> setup
Doing setup ...
get_retain_state() = FALSE
get_retain_state() = TRUE

See Also
• set_retain_state() on page 24-78
• retain state on page 3-15 in the Specman Command Reference
• show retain state on page 3-16 in the Specman Command Reference
• restore on page 3-11 in the Specman Command Reference
• reload on page 3-13 in the Specman Command Reference

24.7 Specman Command Routine

24.7.1 specman()

Purpose
Send Specman commands from within actions

24-80 e Language Reference


Predefined Routines
Specman Command Routine

Category
Routine

Syntax
specman()

specman(command: string, …)

Syntax Example
specman("break on tcm_start");

Parameter

command A Specman command, with or without parameters and enclosed in


double quotes. Calling specman() with commands that change state,
including restore, load, and reload, results in an error.

Description
This routine concatenates all the commands into one string and then executes the string as a Specman
command.

Example
A typical use of the specman() routine is to set defaults for a test. Calls to the specman() routine can be
placed in the sys.setup() method:
extend sys {
setup() is also {
specman("set radix hex");
specman("break on tcm_start");
};
};

Result
Specman > setup
Doing setup ...
2. break on tcm_start *.*

e Language Reference 24-81


Predefined Routines
OS Interface Routines

24.8 OS Interface Routines


The routines in this section enable use of operating system commands from within the e programming
language. These routines work on all supported operating systems.

The OS interface routines in this section are:

• spawn() on page 24-82


• spawn_check() on page 24-83
• system() on page 24-84
• output_from() on page 24-86
• output_from_check() on page 24-87
• get_symbol() on page 24-88
• date_time() on page 24-89
• getpid() on page 24-90

24.8.1 spawn()

Purpose
Send commands to the operating system

Category
Pseudo-routine

Syntax
spawn()

spawn(command: string, …)

Syntax Example
spawn("touch error.log;","grep Error specman.elog > error.log");

24-82 e Language Reference


Predefined Routines
spawn_check()

Parameter

command An operating system command, with or without parameters and enclosed in double
quotes.

Description
Takes a variable number of parameters, concatenates them together, and executes the string result as an
operating system command via system().

Example
<'
extend sys {
m1() is {
spawn("touch error.log;","grep Error specman.elog > \
error.log");
};
};
'>

See Also
• “OS Interface Routines” on page 24-82
• shell on page 22-16

24.8.2 spawn_check()

Purpose
Send a command to the operating system and report error

Category
Routine

Syntax
spawn_check(command: string)

e Language Reference 24-83


Predefined Routines
system()

Syntax Example
spawn_check("grep Error specman.elog >& error.log");

Parameter

command A single operating system command, with or without parameters and enclosed in
double quotes.

Description
Executes a single string as an operating system command via system(), then calls error() if the
execution of the command returned an error status.

Example
<'
extend sys {
m1() is {
spawn_check("grep Error specman.elog >& error.log");
};
};
'>

Result
Specman > sys.m1()
*** Error: Error while executing 'spawn_check("grep Error specman.elog
>& error.log")'

See Also
• “OS Interface Routines” on page 24-82
• shell on page 22-16

24.8.3 system()

Purpose
Send a command to the operating system

24-84 e Language Reference


Predefined Routines
system()

Category
Routine

Syntax
system(command: string): int

Syntax Example
stub = system("cat specman.v");

Parameter

command A single operating system command, with or without parameters and enclosed in
double quotes.

Description
Executes the string as an operating system command using the C system() call and returns the result.

Example
<'
extend sys {
m1() is {
var stub: int;
stub = system("cat specman.v");
print stub;
};
};
'>

Result
Specman > sys.m1()
/* specman.v - A Specman stubs file (top module is sim19_b) */
/* Generated automatically on Fri Mar 19 11:27:40 1999 */

module specman;

parameter sn_version_id = 0; /* Version */


parameter sn_version_date = 31198; /* Version date*/

...

e Language Reference 24-85


Predefined Routines
output_from()

See Also
• “OS Interface Routines” on page 24-82
• shell on page 22-16

24.8.4 output_from()

Purpose
Collect the results of a system call

Category
Routine

Syntax
output_from(command: string): list of string

Syntax Example
log_list = output_from("ls *log");

Parameter

command A single operating system command, with or without parameters and enclosed in
double quotes.

Description
Executes the string as an operating system command and returns the output as a list of string. Under
UNIX, stdout and stderr go to the string list.

Example
<'
extend sys {
m1() is {
var log_list: list of string;
log_list = output_from("ls *log");

24-86 e Language Reference


Predefined Routines
output_from_check()

print log_list;
};
};
'>

Result
Specman > sys.m1()
log_list =
0. "specman.elog"
1. "specview_specman.elog"

See Also
• “OS Interface Routines” on page 24-82
• shell on page 22-16

24.8.5 output_from_check()

Purpose
Collect the results of a system call and check for errors

Category
Routine

Syntax
output_from_check(command: string): list of string

Syntax Example
log_list = output_from_check("ls *.log");

Parameter

command A single operating system command with or without parameters and enclosed in
double quotes.

e Language Reference 24-87


Predefined Routines
get_symbol()

Description
Executes the string as an operating system command, returns the output as a list of string, and then calls
error() if the execution of the command returns an error status. Under UNIX, stdout and stderr go to
the string list.

Example
<'
extend sys {
m1() is {
var log_list: list of string;
log_list = output_from_check("ls *.log");
print log_list;
};
};
'>

Result
Specman > sys.m1()
*** Error: Error from system command "ls *.log":
No match

See Also
• “OS Interface Routines” on page 24-82
• shell on page 22-16

24.8.6 get_symbol()

Purpose
Get UNIX environment variable

Category
Routine

Syntax
get_symbol(env-variable: string): string

24-88 e Language Reference


Predefined Routines
date_time()

Syntax Example
current_dir = get_symbol("PWD");

Parameter

env-variable A UNIX environment variable enclosed in double quotes.

Description
Returns the environment variable as a string.

Example
<'
extend sys {
m1() is {
var current_dir: string;
current_dir = get_symbol("PWD");
print current_dir;
};
};
'>

Result
Specman > sys.m1()
current_dir = "/users3/sawa/docs/314/code"

See Also
• “OS Interface Routines” on page 24-82
• “Environment Variables, Initialization Files, and Scripts” on page 7-24 in the Specman Elite Integrator’s
Guide
• shell on page 22-16

24.8.7 date_time()

Purpose
Retrieve current date and time

e Language Reference 24-89


Predefined Routines
getpid()

Category
Routine

Syntax
date_time(): string

Syntax Example
print date_time();

Description
Returns the current date and time as a string.

Example
vrst-tool> print date_time()
date_time() = "Tue Jul 27 13:10:43 1999"

See Also
• “OS Interface Routines” on page 24-82
• shell on page 22-16

24.8.8 getpid()

Purpose
Retrieve process ID

Category
Routine

Syntax
getpid(): int

Syntax Example
print getpid();

24-90 e Language Reference


Predefined Routines
File Routines

Description
Returns the current process ID as an integer.

Example
vrst-tool> print getpid()
getpid() = 25517

See Also
• “OS Interface Routines” on page 24-82

24.9 File Routines


The global struct named files contains predefined routines for working with files. This chapter contains
information about using files and the predefined file routines. Like most global objects, the predefined
routines in the files struct are not meant to be extended with is also or is only.

General information about working with files is provided in the following sections.

• “File Names and Search Paths” on page 24-91


• “File Descriptors” on page 24-92
Syntax for the predefined file routines is described in the following sections.

• “Low-Level File Routines” on page 24-92


• “General File Routines” on page 24-107
• “Reading and Writing Structs” on page 24-130

See Also
• “File Iteration Actions” on page 9-17
• “String Routines” on page 24-28

24.9.1 File Names and Search Paths


Many of the file routines require a file-name parameter. The following are restrictions on file-name
parameters for most routines.

• The file-name must be the exact path to the file.

e Language Reference 24-91


Predefined Routines
File Descriptors

• You cannot use ~, or wild card patterns, or any environment variable, including $SPECMAN_PATH,
in the file-name.
• For files that have default extensions, such as .e or .ecom, leave the extension off the file-name.
The exception to the above restrictions is the files.add_file_type() routine. This routine accepts ~, wild
cards (*), or $SPECMAN_PATH as a file-name parameter (see add_file_type() on page 24-93). Before
you use any of the file routines, it is recommended that you use files.add_file_type() to make sure you
have a valid path to a file.

24.9.2 File Descriptors


For every open file, a file descriptor struct exists which contains information about the file. The routine
open() on page 24-98 returns the file descriptor as a variable of type file. The name of the file variable is
used in low-level file operations such as the files.read(), files.write() and files.flush() routines. These
routines are described in “Low-Level File Routines” on page 24-92.

24.9.3 Low-Level File Routines


This section contains descriptions of the file routines that use file descriptor structs.

To write strings to a file, the simplest routine is write_string_list() on page 24-128.

The following file routines are described in this section.

• add_file_type() on page 24-93


• close() on page 24-95
• flush() on page 24-97
• open() on page 24-98
• read() on page 24-100
• read_lob() on page 24-102
• write() on page 24-103
• write_lob() on page 24-105

See Also
• “File Routines” on page 24-91
• “General File Routines” on page 24-107

24-92 e Language Reference


Predefined Routines
add_file_type()

• “Reading and Writing Structs” on page 24-130

24.9.4 add_file_type()

Purpose
Get a file name

Category
Method

Syntax
files.add_file_type(file-name: string, file-ext: string, exists: bool): string

Syntax Example
var fv: string;
fv = files.add_file_type("fname", ".e", FALSE);

Parameters

file-name The name of the file to access. A wild card pattern can be used.

file-ext The file extension, including the dot (.) may be empty.

exists Sets checking for existence of the file.

Description
Returns a string holding the file name.

This routine assigns a string consisting of file-name and file-ext to a string variable. If file-name already
contains an extension, then file-ext is ignored. If file-ext is empty, the file-name is used with no extension.

If exists is FALSE, the routine returns the file-name string without checking for the existence of the file.
Wild cards, ~, and $SPECMAN_PATH are not evaluated.

If exists is TRUE, Specman checks to see if there is a file that matches the file-name in the current
directory. The file-name can contain ~, $SPECMAN_PATH, and * wild cards. The * wild card
represents any combination of ASCII characters. If there is one and only one file that matches the
file-name pattern, the file's name is returned. If there is no match in the current directory, then Specman

e Language Reference 24-93


Predefined Routines
add_file_type()

searches the $SPECMAN_PATH directories for the file. If no matching file can be found, or if more than
one file is found in a directory that matches a wild card, an error is issued. If there are multiple matching
files in different directories in the SPECMAN_PATH, the first one found is returned.

Examples
For the following examples, assume files named “ex_file” and “ex_file.tmp” exist in the current
directory, and a file named “ex_file.e” exists under /prog/specman/docs (which is included in the
$SPECMAN_PATH definition).

The following assigns ex_file.e to the f1 variable, without checking to see if the ex_file.e file exists.
struct f_str {
!file_list: list of string;
AppendFileToList(ex_file: string) is {
var f1: string;
f1 = files.add_file_type(ex_file, ".e", FALSE);
file_list.add(f1);
};
};
extend sys {
fi: f_str;
run() is also {
fi.AppendFileToList("ex_file");
};
};

The following statement tries to assign ex_file.e to the f2 variable, but issues an error when it checks for
the existence of ex_file.e.
AppendFileToList(ex_file: string) is {
var f2: string;
f2 = files.add_file_type(ex_file, ".e", TRUE);
file_list.add(f2);
};

The error is shown below.


*** Error: No match for file 'ex_file.e'

The following action, entered at the command line, assigns ex_file to the f3 variable.
var f3: string = files.add_file_type("ex_file", "", TRUE);

Although ex_file.e does not exist in the current directory, it does exist in the /prog/specman/docs
directory, which is in the $SPECMAN_PATH. Therefore, the following action assigns
/prog/specman/docs/ex_file.e to the f4 variable.

24-94 e Language Reference


Predefined Routines
close()

var f4: string = files.add_file_type("ex_file", ".e", TRUE);

The following action assigns ex* to the f5 variable.


var f5: string = files.add_file_type("ex*", "", FALSE);

The following action checks for files that match the ex* pattern.
var f6: string = files.add_file_type("ex*", "", TRUE);

Since more than one file in the current directory matches the pattern, the names of the matching files are
printed and an error is issued:
ex_file
ex_file.tmp
There is more than one file matching ex*

See Also
• file_exists() on page 24-113

24.9.5 close()

Purpose
Close a file

Category
Method

Syntax
files.close(file: file-descriptor)

Syntax Example
files.close(f_desc);

Parameter

file The file descriptor of the file to be closed.

e Language Reference 24-95


Predefined Routines
close()

Description
Flushes the file buffer and closes the file specified by file-descriptor. The file must previously have been
opened using open() on page 24-98. When no further activity is planned for a file, it should be closed to
prevent unintentional operations on its contents.

Example
The WrAndFlush() user-defined method in the following example opens a file named “ex_file.txt” as the
m_file variable, writes a line to the file, and then closes the file. The RFile() user-defined method then
opens the same file for reading and reads its contents into the m_string variable.

The files.flush() routine writes the “AaBaCa 0123” string to the disk immediately, so that the read
routine can read it. If there were no files.close() routine (or files.flush() routine) following the write, the
data would not be in disk file when the read was done.
struct f_s_1 {
WrAndFlush(ex_file: string) is {
var m_file: file;
m_file = files.open(ex_file, "w", "Text file");
files.write(m_file, "AaBaCa 0123");
files.close(m_file);
};
RFile(ex_file: string) is {
var m_file: file;
m_file = files.open(ex_file, "r", "Text file");
var r_chk: bool;
var m_string: string;
r_chk = files.read(m_file, m_string);
if r_chk then {print m_string}
else {out("file not read")};
};
};
extend sys {
f_si_1: f_s_1;
run() is also {
f_si_1.WrAndFlush("ex_file.txt");
f_si_1.RFile("ex_file.txt");
};
};

See Also
• open() on page 24-98
• flush() on page 24-97

24-96 e Language Reference


Predefined Routines
flush()

24.9.6 flush()

Purpose
Flush file buffers

Category
Method

Syntax
files.flush(file: file-descriptor)

Syntax Example
files.flush(a_file);

Parameter

file The file descriptor of the file to flush.

Description
Flushes all the operating system buffers associated with file to the disk.

File data is buffered in memory and only written to disk at certain times, such as when the file is closed.
This routine causes data to be written to the disk immediately, instead of later when the file is closed.

This can be useful if two processes are using the same disk file, for example, to make sure that the
current data from one process is written to the file before the other process reads from the file.

Example
The WrAndFlush() user-defined method in the following example opens a file named “ex_file.txt” as the
m_file variable, writes a line to the file, and then flushes the file’s buffer to disk. The RFile() user-defined
method then opens the same file for reading and reads its contents into the m_string variable.

The files.flush() routine writes the “AaBaCa 0123” string to the disk immediately, so that the read
routine can read it. If there were no files.flush() routine (or file.close() routine) following the write, the
data would not be in disk file when the read was done.
struct f_s_2 {

e Language Reference 24-97


Predefined Routines
open()

WrAndFlush(ex_file: string) is {
var m_file: file;
m_file = files.open(ex_file, "w", "Text file");
files.write(m_file, "AaBaCa 0123");
files.flush(m_file);
};
RFile(ex_file: string) is {
var m_file: file;
m_file = files.open(ex_file, "r", "Text file");
var r_chk: bool;
var m_string: string;
r_chk = files.read(m_file, m_string);
if r_chk then {print m_string}
else {out("file not read")};
};
};
extend sys {
f_si_2: f_s_2;
run() is also {
f_si_2.WrAndFlush("ex_file.txt");
f_si_2.RFile("ex_file.txt");
};
};

See Also
• open() on page 24-98
• flush() on page 24-97

24.9.7 open()

Purpose
Open a file for reading or writing or both

Category
Method

Syntax
files.open(file-name: string, mode: string, file-role: string): file

24-98 e Language Reference


Predefined Routines
open()

Syntax Example
var m_file: file;
m_file = files.open("a_file.txt", "r", "Text File");

Parameters

file-name The name of the file to open. Wild cards, ~, and $SPECMAN_PATH are not allowed
in the file name. To use them to select files, see add_file_type() on page 24-93.

mode The read/write mode for the file. The mode may be one of the following.

r - open the file for reading.

w - open the file for writing (overwrite the existing contents)

rw - open the file for reading and writing (add to the end of the existing contents)

a - open the file for appending (add to the end of the existing contents)

file-role A text description used in error messages about the file.

Description
Opens the file for reading, writing, both reading and writing, or append, according to mode (r, w, rw, a)
and returns the file descriptor of the file. The file-role is a description of the file, for example, “source
file”.

If the file cannot be opened, an error like the following is issued.


*** Error: Cannot open file-role 'file-name' for mode

Example 1
The following example opens a file named “/users/a_file.txt” in write mode as file variable m_file, writes
a line to the file, and then closes the file.
struct f_3_str {
RdWrFile(ex_file: string) is {
var m_file: file;
m_file = files.open(ex_file, "w", "Text file");
files.write(m_file, "HEADER");
files.close(m_file);
};
};
extend sys {
fi_3: f_3_str;

e Language Reference 24-99


Predefined Routines
read()

run() is also {
fi_3.RdWrFile("/users/a_file.txt");
};
};

Example 2
The following actions, entered at the command line, perform the same operations as Example 1, above.
var m_file: file;
m_file = files.open("/users/a_file.txt", "w", "Text file");
files.write(m_file, "HEADER");
files.close(m_file);

See Also
• add_file_type() on page 24-93
• close() on page 24-95
• write() on page 24-103

24.9.8 read()

Purpose
Read an ASCII line from a file

Category
Method

Syntax
files.read(file: file-descriptor, string-var: *string): bool

Syntax Example
r_b = files.read(f_desc, m_string);

24-100 e Language Reference


Predefined Routines
read()

Parameters

file The file descriptor of the file that contains the text to read.

string-var A variable into which the ASCII text will be read.

Description
Reads a line of text from a file into a string variable in Specman. The file must have been opened with
open() on page 24-98. The line from the file is read into the Specman variable without the final \n
newline character.

The routine returns TRUE on success. If the method cannot read a line (for example, if the end of the file
is reached), it returns FALSE.

The files.read() routine is a low level routine. For performance considerations, it is generally
recommended to use the for each line in file action, rather than this routine.

Example
The following example opens a file named “a_file.txt” as variable m_f, reads lines one by one from the
file into a variable named “m_string”, and displays each string as it reads it.
struct f_s_3 {
RFile(ex_file: string) is {
var m_file: file;
m_file = files.open(ex_file, "r", "Text file");
var r_chk: bool;
var m_string: string;
r_chk = files.read(m_file, m_string);
out("The first line is: ", m_string);
while files.read(m_file, m_string) {
out("The next line is: ", m_string);
};
files.close(m_file);
};
};
extend sys {
f_si_3: f_s_3;
run() is also {
f_si_3.RFile("ex_file.txt");
};
};

e Language Reference 24-101


Predefined Routines
read_lob()

See Also
• for each line in file on page 9-17
• open() on page 24-98
• read_lob() on page 24-102
• read_ascii_struct() on page 24-130
• read_binary_struct() on page 24-132
• Table 3-4 on page 3-41, for information about type conversion between scalar types

24.9.9 read_lob()

Purpose
Read from a binary file into a list of bits

Category
Method

Syntax
files.read_lob(file: file-descriptor, size-in-bits: int): list of bit

Syntax Example
var m_file: file = files.open("a_file.dat", "r", "Data");
var b_l: list of bit;
b_l = files.read_lob(m_file, 32);

Parameters

file The file descriptor of the file to read from.

size-in-bits The number of bits to read. Should be a multiple of 8

Description
Reads data from a binary file into a list of bits and returns the list of bits. The file must already have been
opened with open() on page 24-98. To read an entire file, use UNDEF as the size-in-bits.

24-102 e Language Reference


Predefined Routines
write()

Example 1
The following example opens a file named “a_file.dat” with the file descriptor m_f, and reads the first 16
bits from the file into a list of bits named “b_list”.
struct f_4 {
b_list: list of bit;
RdLOB(ex_file: string) is {
var m_f: file = files.open(ex_file, "r", "Data");
b_list = files.read_lob(m_f, 16);
files.close(m_f);
};
};
extend sys {
fi_4: f_4;
run() is also {
fi_4.RdLOB("a_file.dat");
};
};

Example 2
The following actions entered at the command line perform the same operations as Example 1, above.
var m_f: file = files.open("a_file.dat", "r", "data file");
var b_list: list of bit = files.read_lob(m_f, 16);
files.close(m_f);

See Also
• close() on page 24-95
• open() on page 24-98
• write_lob() on page 24-105
• Table 3-4 on page 3-41, for information about type conversion between scalar types

24.9.10 write()

Purpose
Write a string to file

e Language Reference 24-103


Predefined Routines
write()

Category
Method

Syntax
files.write(file: file-descriptor, text: string)

Syntax Example
files.write(m_file, "Test Procedure");

Parameters

file The file descriptor of the file to write into.

text The text to write to the file.

Description
Adds a string to the end of an existing, open file. A new-line \n is added automatically at the end of the
string. The file must already have been opened using open() on page 24-98. If the file is not open, an
error message is issued.

If the file is opened in write mode (w), this routine overwrites the existing contents. To avoid overwriting
the existing file, open it in append mode (a).

Note
The >> concatenation operator can be used to append information to the end of a file. For example, the
following set log command concatenates information logged for the current test onto the end of the
previously written file named “test_a.elog”.
set log >> test_a.elog

Example
The following example opens a file named “/users/a_file.txt” in write mode as file variable m_file, writes
two lines to the file, and then closes the file.
struct f_s_5 {
WrFile(ex_file: string) is {
var m_file: file;
m_file = files.open(ex_file, "w", "Text file");
files.write(m_file, "FILE 1");

24-104 e Language Reference


Predefined Routines
write_lob()

files.write(m_file, "Test 1");


files.close(m_file);
};
};
extend sys {
f_si_5: f_s_5;
run() is also {
f_si_5.WrFile("/users/a_file.txt");
};
};

See Also
• close() on page 24-95
• open() on page 24-98

24.9.11 write_lob()

Purpose
Write a list of bits to a binary file

Category
Method

Syntax
files.write_lob(file: file-descriptor, bit-list: list of bit)

Syntax Example
var m_file: file = files.open("a_f.dat", "w", "My data");
var b_l: list of bit;
files.write_lob(m_file, b_l);

Parameters

file The file descriptor of the file to write into.

bit-list A list of bits to write to the file. The size of the list must be a multiple of 8 bits.

e Language Reference 24-105


Predefined Routines
write_lob()

Description
Writes all the bits in the bit list (whose size should be a multiple of 8) to the end of the file specified by
file. The file must already have been opened with open() on page 24-98.

Lists of bits are always written in binary format.

Example
The following example opens a file named “a_file.dat” as file descriptor m_f_1 in write mode (w). The
files.write_lob() routine writes the contents of a list of bits named “b_list” into the file.

The files.read_lob() routine reads the contents of the file into a variable named “b_2” as a list of bits,
which is then printed.
struct f_5_str {
RdWrLOB(ex_file: string) is {
var b_list: list of bit = {1; 0; 1; 1; 0; 1 ;1; 1};
var m_f_1: file = files.open(ex_file, "w", "Data");
files.write_lob(m_f_1, b_list);
files.close(m_f_1);

var b_2: list of bit;


var m_f_2: file = files.open(ex_file, "r", "Data");
b_2 = files.read_lob(m_f_2, 8);
print b_2 using radix=bin, list_starts_on_right=FALSE;
};
};
extend sys {
fi_5: f_5_str;
run() is also {
fi_5.RdWrLOB("a_file.dat");
};
};

The print action in the example above displays the following.


b_2 = (8 items, bin):
0. 1 0 1 1 0 1 1 1

See Also
• close() on page 24-95
• open() on page 24-98
• read_lob() on page 24-102

24-106 e Language Reference


Predefined Routines
General File Routines

24.9.12 General File Routines


These sections contains descriptions of the following routines.

• file_age() on page 24-107


• file_append() on page 24-109
• file_copy() on page 24-110
• file_delete() on page 24-112
• file_exists() on page 24-113
• file_extension() on page 24-114
• file_is_dir() on page 24-116
• file_is_link() on page 24-117
• file_is_readable() on page 24-118
• file_is_regular() on page 24-120
• file_is_temp() on page 24-121
• file_is_text() on page 24-123
• file_rename() on page 24-124
• file_size() on page 24-125
• new_temp_file() on page 24-127
• write_string_list() on page 24-128

See Also
• “File Routines” on page 24-91
• “Low-Level File Routines” on page 24-92
• “Reading and Writing Structs” on page 24-130

24.9.13 file_age()

Purpose
Get a file’s modification date

e Language Reference 24-107


Predefined Routines
file_age()

Category
Method

Syntax
files.file_age(file-name: string): int

Syntax Example
var f_data: int;
f_data = files.file_age("f.txt");

Parameter

file-name The file whose age is to be found.

Description
Returns the modification date of the file as an integer. This routine can be used to compare the
modification dates of files. The integer returned by the routine is not recognizable as a date, but is a
unique number derived from the file’s modification date. If the modification date includes the time of
day, the time is factored into the number the routine returns. Newer files produce larger numbers than
older files.

If the file does not exist, an error like the following is issued.
*** Error: Internal error in file_age: 'file-name' does not exist

Example
In the following example, the files.file_age() routine derives a number from the modification date of a
file whose variable is my_f. The routine is called twice in the run() method in the sys extension, once for
each of two files. The age numbers are printed and compared to find the largest.
struct f_6_str {
FAge(ex_file: string): int is {
var my_f: string;
var my_age: int;
my_f = files.add_file_type(ex_file, "", TRUE);
my_age = files.file_age(my_f);
outf("file name: %s, age: %d\n", ex_file, my_age);
return my_age;
}
};

24-108 e Language Reference


Predefined Routines
file_append()

extend sys {
fi_6: f_6_str;
run() is also {
var my_age_1: int = fi_6.FAge("f_1.e");
var my_age_2: int = fi_6.FAge("f_2.e");
var oldest: int = max(my_age_1, my_age_2);
print oldest;
};
};

The example above prints the following.


file name: f_1.e, age: 927860670
file name: f_2.e, age: 927860675
oldest = 927860675

See Also
• add_file_type() on page 24-93

24.9.14 file_append()

Purpose
Append files

Category
Method

Syntax
files.file_append(from-file-name: string, to-file-name: string)

Syntax Example
files.file_append(f_1, f_2);

Parameters

from-file-name The name of the file that will be appended to the to-file.

to-file-name The name of the file to which the from-file will be appended.

e Language Reference 24-109


Predefined Routines
file_copy()

Description
Adds the contents of the file named from-file-name to the end of the file named to-file-name. If either of
the files does not exist, an error is issued.

Note
The >> concatenation operator can be used to append information to the end of a file. For example, the
following set log command concatenates information logged for the current test onto the end of the
previously written file named test_a.elog.
set log >> test_a.elog

Example
The following example appends the contents of f_2.txt to the end of f_1.txt.
struct f_7_str {
FAppend(ex_file_1: string, ex_file_2: string) is {
var my_f_1: string;
my_f_1 = files.add_file_type(ex_file_1, ".txt", TRUE);
var my_f_2: string;
my_f_2 = files.add_file_type(ex_file_2, ".txt", TRUE);
files.file_append(my_f_1, my_f_2);
}
};
extend sys {
fi_7: f_7_str;
run() is also {
fi_7.FAppend("f_2.txt", "f_1.txt");
};
};

See Also
• add_file_type() on page 24-93

24.9.15 file_copy()

Purpose
Create a copy of a file

24-110 e Language Reference


Predefined Routines
file_copy()

Category
Method

Syntax
files.file_copy(from-file-name: string, to-file-name: string)

Syntax Example
files.file_copy("file_1.txt", "tmp_file.txt");

Parameters

from-file-name The name of the file to copy.

to-file-name The name of the copy of the file.

Description
Makes a copy of the file named from-file-name, with the name to-file-name. If a files already exists with
the to-file-name, the contents of that file are replaced by the contents of the file named from-file-name. If
the file named from-file-name does not exist, an error is issued.

Example
The following example copies the contents of f_1.txt into f_1.bak.
struct f_str_8 {
FCp(ex_file_1: string, ex_file_2:string) is {
files.file_copy(ex_file_1, ex_file_2);
};
};
extend sys {
fi_8: f_str_8;
run() is also {
fi_8.FCp("f_1.txt", "f_1.bak");
};
};

See Also
• file_rename() on page 24-124

e Language Reference 24-111


Predefined Routines
file_delete()

24.9.16 file_delete()

Purpose
Delete a file

Category
Method

Syntax
files.file_delete(file-name: string)

Syntax Example
files.file_delete("run_1.log");

Parameter

file-name The file to be deleted.

Description
Deletes a specified file. If the file cannot be found, an error like the following is issued.
*** Error: No match for file 'run_1.log'

Example
The following example deletes the f_1.txt file.
struct f_str_9 {
FDel(ex_file: string) is {
var my_f_1: string;
my_f_1 = files.add_file_type(ex_file, ".txt", TRUE);
files.file_delete(my_f_1);
};
};
extend sys {
fi_9: f_str_9;
run() is also {
fi_9.FDel("f_1.txt");

24-112 e Language Reference


Predefined Routines
file_exists()

};
};

See Also
• file_exists() on page 24-113

24.9.17 file_exists()

Purpose
Check if a file exists

Category
Method

Syntax
files.file_exists(file-name: string): bool

Syntax Example
var f_e: bool;
f_e = files.file_exists("file_1.e");

Parameter

file-name The name of the file to be checked.

Description
Check if the file-name exists in the file system. Return TRUE if the file exists or issues an error if it does
not exist. Also returns TRUE if the file is a directory. The routine does not check whether the file is
readable or not.

Note
This routine only checks for the existence of a file with the exact name you specify. For a routine that can
check for multiple similarly named files, see add_file_type() on page 24-93.

e Language Reference 24-113


Predefined Routines
file_extension()

Example
The following example prints “file f_1.txt exists” if there is a file named “f_1.txt” in the current
directory. If the file does not exist, an error is issued.
struct f_str_10 {
FEx(ex_file: string) is {
var my_f_1: string;
my_f_1 = files.add_file_type(ex_file, ".txt", TRUE);
var f_exists: bool;
f_exists = files.file_exists(my_f_1);
if f_exists then {outf("file %s exists\n", my_f_1)};
};
};
extend sys {
fi_10: f_str_10;
run() is also {
fi_10.FEx("f_1.txt");
};
};

See Also
• add_file_type() on page 24-93
• file_is_dir() on page 24-116
• file_is_readable() on page 24-118
• file_is_regular() on page 24-120
• file_is_link() on page 24-117
• file_is_text() on page 24-123
• Table 3-4 on page 3-41, for information about type conversion between scalar types

24.9.18 file_extension()

Purpose
Get the extension of a file

Category
Method

24-114 e Language Reference


Predefined Routines
file_extension()

Syntax
files.file_extension(file-name: string): string

Syntax Example
var f_ext: string;
f_ext = files.file_extension("f_1.exa");

Parameter

file-name The name of the file.

Description
Returns a string containing the file extension, which is the sequence of characters after the last period (.).

Example
The following example prints “get_ext = “.bak””.
struct f_str_11 {
FExten(ex_file: string) is {
var get_ext: string;
get_ext = files.file_extension(ex_file);
print get_ext;
};
};
extend sys {
fi_11: f_str_11;
run() is also {
fi_11.FExten("f_1.bak");
};
};

See Also
• add_file_type() on page 24-93
• file_exists() on page 24-113
• Table 3-5 on page 3-43, for information about type conversion between strings and scalar types

e Language Reference 24-115


Predefined Routines
file_is_dir()

24.9.19 file_is_dir()

Purpose
Check if a file is a directory

Category
Method

Syntax
files.file_is_dir(file-name: string): bool

Syntax Example
var is_d: bool;
is_d = files.file_is_dir("a_fil");

Parameter

file-name The name of the file to be checked.

Description
Returns TRUE if the file exists and is a directory. Returns FALSE if the file does not exist or is not a
directory.

Example
The following example prints TRUE if f_1 is a directory, or FALSE if f_1 does not exist or if it is not a
directory.
struct f_str_12 {
F_is_Dir(ex_file: string) is {
var is_dir: bool;
is_dir = files.file_is_dir(ex_file);
outf("%s is_dir = %s\n", ex_file, is_dir);
};
};
extend sys {
fi_12: f_str_12;
run() is also {

24-116 e Language Reference


Predefined Routines
file_is_link()

fi_12.F_is_Dir("f_1");
};
};

See Also
• file_exists() on page 24-113
• file_is_link() on page 24-117
• file_is_readable() on page 24-118)
• file_is_regular() on page 24-120
• file_is_temp() on page 24-121
• file_is_text() on page 24-123
• Table 3-4 on page 3-41, for information about type conversion between scalar types
• Table 3-5 on page 3-43, for information about type conversion between strings and scalar types

24.9.20 file_is_link()

Purpose
Check if a file is a symbolic link

Category
Method

Syntax
files.file_is_link(file-name: string): bool

Syntax Example
var is_l: bool;
is_l = files.file_is_link("a_fil");

Parameter

file-name The name of the file to be checked.

e Language Reference 24-117


Predefined Routines
file_is_readable()

Description
Returns TRUE if the file exists and is a symbolic link. Returns FALSE if the file does not exist or is not
a symbolic link.

Example
The following example prints TRUE if f_1 is a symbolic link, or FALSE if f_1 does not exist or if it is
not a symbolic link.
struct f_str_13 {
F_is_Link(ex_file: string) is {
var is_link: bool;
is_link = files.file_is_link(ex_file);
outf("%s is_link = %s\n", ex_file, is_link);
};
};
extend sys {
fi_13: f_str_13;
run() is also {
fi_13.F_is_Link("f_1");
};
};

See Also
• file_exists() on page 24-113
• file_is_dir() on page 24-116
• file_is_readable() on page 24-118)
• file_is_regular() on page 24-120
• file_is_temp() on page 24-121
• file_is_text() on page 24-123
• Table 3-4 on page 3-41, for information about type conversion between scalar types

24.9.21 file_is_readable()

Purpose
Check if a file is readable

24-118 e Language Reference


Predefined Routines
file_is_readable()

Category
Method

Syntax
files.file_is_readable(file-name: string): bool

Syntax Example
var is_rd: bool;
is_rd = files.file_is_readable("a_fil");

Parameter

file-name The name of the file to be checked.

Description
Returns TRUE if the file exists and is readable. Returns FALSE if the file does not exist or is not
readable.

Example
The following example prints TRUE if f_1.dat is readable, or FALSE if f_1.dat does not exist or if it is
not readable.
struct f_str_14 {
F_is_Readable(ex_file: string) is {
var is_readable: bool;
is_readable = files.file_is_readable(ex_file);
outf("%s is_readable = %s\n", ex_file, is_readable);
};
};
extend sys {
fi_14: f_str_14;
run() is also {
fi_14.F_is_Readable("f_1.dat");
};
};

See Also
• file_exists() on page 24-113

e Language Reference 24-119


Predefined Routines
file_is_regular()

• file_is_dir() on page 24-116


• file_is_link() on page 24-117)
• file_is_regular() on page 24-120
• file_is_temp() on page 24-121
• file_is_text() on page 24-123
• Table 3-4 on page 3-41, for information about type conversion between scalar types

24.9.22 file_is_regular()

Purpose
Check if a file is a regular file (not a directory or link)

Category
Method

Syntax
files.file_is_regular(file-name: string): bool

Syntax Example
var is_rg: bool;
is_rg = files.file_is_regular("a_fil");

Parameter

file-name The name of the file to be checked.

Description
Returns TRUE if the file exists and is a regular file. Returns FALSE if the file does not exist or if it is a
directory or a symbolic link.

24-120 e Language Reference


Predefined Routines
file_is_temp()

Example
The following example prints TRUE if f_1 is a regular file, or FALSE if f_1 does not exist or if it is a link
or directory.
struct f_str_15 {
F_is_Regular(ex_file: string) is {
var is_regular: bool;
is_regular = files.file_is_regular(ex_file);
outf("%s is_regular = %s\n", ex_file, is_regular);
};
};
extend sys {
fi_15: f_str_15;
run() is also {
fi_15.F_is_Regular("f_1");
};
};

See Also
• file_exists() on page 24-113
• file_is_dir() on page 24-116
• file_is_link() on page 24-117
• file_is_readable() on page 24-118)
• file_is_temp() on page 24-121
• file_is_text() on page 24-123
• Table 3-4 on page 3-41, for information about type conversion between scalar types

24.9.23 file_is_temp()

Purpose
Check if a file name starts with “/tmp”

Category
Method

e Language Reference 24-121


Predefined Routines
file_is_temp()

Syntax
files.file_is_temp(file-name: string): bool

Syntax Example
var is_tmp: bool;
is_tmp = files.file_is_temp("a_fil");

Parameter

file-name The name of the file to be checked.

Description
Returns TRUE if the file name starts with “/tmp”, otherwise returns FALSE.

Example
The following example prints “/tmp/f_1.dat is_temp = TRUE”.
struct f_str_16 {
F_is_Temp(ex_file: string) is {
var is_temp: bool;
is_temp = files.file_is_temp(ex_file);
outf("%s is_temp = %s\n", ex_file, is_temp);
};
};
extend sys {
fi_16: f_str_16;
run() is also {
fi_16.F_is_Temp("/tmp/f_1.dat");
};
};

See Also
• new_temp_file() on page 24-127
• file_exists() on page 24-113
• file_is_dir() on page 24-116
• file_is_link() on page 24-117
• file_is_readable() on page 24-118)

24-122 e Language Reference


Predefined Routines
file_is_text()

• file_is_regular() on page 24-120


• file_is_text() on page 24-123
• Table 3-4 on page 3-41, for information about type conversion between scalar types

24.9.24 file_is_text()

Purpose
Check if a file is a text file

Category
Method

Syntax
files.file_is_text(file-name: string): bool

Syntax Example
var is_txt: bool;
is_txt = files.file_is_text("a_fil");

Parameter

file-name The name of the file to be checked.

Description
Returns TRUE if the file is a text file (that is, if it contains more than 20% printable characters). Returns
FALSE if the file does not exist or if it is a not a text file.

Example
The following example prints TRUE if f_1.dat is a text file, or FALSE if f_1.dat does not exist or if it is
not a text file.
struct f_str_17 {
F_is_Text(ex_file: string) is {
var is_text: bool;
is_text = files.file_is_text(ex_file);

e Language Reference 24-123


Predefined Routines
file_rename()

outf("%s is_text = %s\n", ex_file, is_text);


};
};
extend sys {
fi_17: f_str_17;
run() is also {
fi_17.F_is_Text("f_1.dat");
};
};

See Also
• file_exists() on page 24-113
• file_is_dir() on page 24-116
• file_is_link() on page 24-117
• file_is_readable() on page 24-118)
• file_is_regular() on page 24-120
• file_is_temp() on page 24-121
• Table 3-4 on page 3-41, for information about type conversion between scalar types

24.9.25 file_rename()

Purpose
Rename a file

Category
Method

Syntax
files.file_rename(from-file-name: string, to-file-name: string)

Syntax Example
files.file_rename("f_1.exa", "b_1.exa");

24-124 e Language Reference


Predefined Routines
file_size()

Parameters

from-file-name The file to rename.

to-file-name The new file name.

Description
Renames the file named from-file-name to to-file-name. If any files already exists with to-file-name, that
file is overwritten by the contents of the file named from-file-name.

If the file or directory is not writable, an error is issued.

Example
The following example changes the name of the f_1.dat file to f_old.dat. If the f_1.dat file does not exist,
the files.add_file_type() routine issues an error.
struct f_str_18 {
FRename(ex_file_1: string, ex_file_2:string) is {
var m_f: string;
m_f = files.add_file_type(ex_file_1, "", TRUE);
files.file_rename (m_f, ex_file_2);
};
};
extend sys {
fi_18: f_str_18;
run() is also {
fi_18.FRename("f_1.dat", "f_old.dat");
};
};

See Also
• add_file_type() on page 24-93
• file_copy() on page 24-110

24.9.26 file_size()

Purpose
Get the size of a file

e Language Reference 24-125


Predefined Routines
file_size()

Category
Method

Syntax
files.file_size(file-name: string): int

Syntax Example
var f_s: int;
f_s = files.file_size("a_file.txt");

Parameter

file-name The name of the file.

Description
Returns the integer number of bytes in the file. If the file does not exist, an error is issued.

Example
The following example gets and displays the number of bytes in the file named “f_1.dat”.
struct f_str_19 {
FGetSize(ex_file: string) is {
var m_f: string;
m_f = files.add_file_type(ex_file, "", TRUE);
var f_size: int;
f_size = files.file_size (m_f);
outf("%s size is %d\n", m_f, f_size);
};
};
extend sys {
fi_19: f_str_19;
run() is also {
fi_19.FGetSize("f_1.dat");
};
};

See Also
• add_file_type() on page 24-93

24-126 e Language Reference


Predefined Routines
new_temp_file()

• file_age() on page 24-107

24.9.27 new_temp_file()

Purpose
Create a unique temporary file name

Category
Method

Syntax
files.new_temp_file(): string

Syntax Example
var t_name: string;
t_name = files.new_temp_file()

Description
Computes a file name. Each file name this routine produces contains the name of the Specman process,
so names are unique across processes. Returns a string with a period at the end.

If the $SPECMAN_TEMP_DIR environment variable has been set, it is used as the prefix of the
directory path in which the file is located. If it has not been defined, the /tmp/specman directory is used
instead.

This routine only creates a file name. To create a file with this name, use the files.open() routine.

Example
The example below creates two file names with a prefixed /tmp/specman directory and prints them.
struct f_str_20 {
FMkTmp() is {
var t_name_1: string;
t_name_1 = files.new_temp_file();
print t_name_1;
var t_name_2: string;
t_name_2 = files.new_temp_file();
print t_name_2;

e Language Reference 24-127


Predefined Routines
write_string_list()

};
};
extend sys {
fi_20: f_str_20;
run() is also {
fi_20.FMkTmp();
};
};

The example above prints the following.


t_name_1 = "/tmp/specman/sn.<host>.<process-id>/snt_5924_12698."
t_name_2 = "/tmp/specman/sn.<host>.<process-id>/snt_5924_12699."

See Also
• file_is_temp() on page 24-121
• open() on page 24-98
• Table 3-5 on page 3-43, for information about type conversion between strings and scalar types

24.9.28 write_string_list()

Purpose
Write a list of strings to a file

Category
Method

Syntax
files.write_string_list(file-name: string, strings: list of string)

Syntax Example
var s_list:= {"a string"; "another string"};
files.write_string_list("a_file.txt", s_list);

Parameters

file-name The file name to write into.

24-128 e Language Reference


Predefined Routines
write_string_list()

strings A list of strings to write to the file.

Description
Writes a list of strings into a file. Every string is written on a separate line in the file, with \n appended
to the end of the string. If the file already exists, it is overwritten.

If the list of strings contains a NULL, an error is issued.

Example
The following example writes three lines of text into a file named “f_1.txt”.
struct f_str_21 {
FWrStr(ex_file: string, str_list: list of string) is {
var m_f: string;
m_f = files.add_file_type(ex_file, "", TRUE);
files.write_string_list(ex_file, str_list);
};
};
extend sys {
fi_21: f_str_21;
run() is also {
var fname:string;
fname = "f_1.txt";
var strlist: list of string;
strlist = {"first line"; "second line"; "third line"};
fi_21.FWrStr(fname, strlist);
};
};

See Also
• open() on page 24-98
• write() on page 24-103
• write_lob() on page 24-105
• write_ascii_struct() on page 24-134
• write_binary_struct() on page 24-137

e Language Reference 24-129


Predefined Routines
Reading and Writing Structs

24.9.29 Reading and Writing Structs


Structs in e can be read from files and written to files in either binary or ASCII format.

The routines that read structs from files and write structs to files are listed below and described in this
section.

• read_ascii_struct() on page 24-130


• read_binary_struct() on page 24-132
• write_ascii_struct() on page 24-134
• write_binary_struct() on page 24-137

See Also
• “File Routines” on page 24-91
• “General File Routines” on page 24-107
• “Low-Level File Routines” on page 24-92

24.9.30 read_ascii_struct()

Purpose
Read ASCII file data into a struct

Category
Method

Syntax
files.read_ascii_struct(file-name: string, struct: struct-type): struct

Syntax Example
var a_str: s_struct;
a_str = files.read_ascii_struct("a_s.out",
"s_struct").as_a(s_struct);

24-130 e Language Reference


Predefined Routines
read_ascii_struct()

Parameters

file-name The name of the file to read from. The file may have been created either with
files.write_ascii_struct() or in a similar format with an editor.

struct The struct type to read data into.

Description
Reads the ASCII contents of file-name into a struct of type struct, and returns a struct. The struct being
read must be cast to the correct data type (see as_a() on page 3-40). If the file does not exist, an error is
issued.

Example
The following example creates a variable named “str” to hold an instance of the s_st struct type, reads
ASCII contents of a file named “a_s.out” into the struct variable, and prints the contents.
struct s_st {
len: int;
hdr: string;
b_l: list of bool;
};
struct r_st {
r_file() is {
var str: s_st;
str = files.read_ascii_struct("a_s.out",
"s_st").as_a(s_st);
print str;
};
run() is also {
r_file();
};
};
extend sys {
ri: r_st;
};

See Also
• read() on page 24-100
• read_lob() on page 24-102
• file_is_readable() on page 24-118

e Language Reference 24-131


Predefined Routines
read_binary_struct()

• read_binary_struct() on page 24-132


• write_ascii_struct() on page 24-134

24.9.31 read_binary_struct()

Purpose
Read the contents of a binary file into a struct

Category
Method

Syntax
files.read_binary_struct(file-name: string, struct: struct-type,
check-version: bool): struct

Syntax Example
var b_str: s_struct;
b_str = files.read_binary_struct("b.out", "s_struct",
TRUE).as_a(s_struct);

Parameters

file-name The name of the file to read from. The file must have been created by
write_binary_struct() on page 24-137.

struct The struct type to read data into.

check-version Set to TRUE to compare the contents of the file being read with the definition
of the struct in the currently running module. Set to FALSE to allow minor
changes.

Description
Reads the binary contents of file-name into a struct of the specified type, and returns a struct. The struct
being read must be cast to the correct data type (see as_a() on page 3-40).

24-132 e Language Reference


Predefined Routines
read_binary_struct()

If check-version is FALSE, the routine can run even if the order of fields in the file struct is different
from the order of fields in the currently running e module. If check-version is TRUE, an error is issued if
the struct definition has been changed in any way since the struct was written to the file.

Example
The following example creates a variable named “str” to hold an instance of the s_st struct type, reads
binary contents of a file named “b_s.out” into the struct variable, and prints the contents. The
check-version parameter is set to TRUE to issue an error if the b_s.out file struct does not exactly match
the s_st definition. The b_s.out binary struct file was created previously by write_binary_struct() on
page 24-137.

struct s_st {
len: int;
hdr: string;
b_l: list of bool;
};
struct r_st {
r_file() is {
var str: s_st;
str = files.read_binary_struct("b_s.out", "s_st",
TRUE).as_a(s_st);
print str;
};
run() is also {
r_file();
};
};
extend sys {
ri: r_st;
};

See Also
• read() on page 24-100
• read_lob() on page 24-102
• file_is_readable() on page 24-118
• read_ascii_struct() on page 24-130
• write_ascii_struct() on page 24-134

e Language Reference 24-133


Predefined Routines
write_ascii_struct()

24.9.32 write_ascii_struct()

Purpose
Write the contents of a struct to a file in ASCII format

Category
Method

Syntax
files.write_ascii_struct(file-name: string, struct: struct, comment: string,
indent: bool, depth: int, max-list-items: int)

Syntax Example
files.write_ascii_struct("a_file.dat", a_str, "my_struct",
TRUE, 2, 10);

Parameters

file-name The name of the file to write into. If you do not specify a file name extension,
the default extension is .erd, which stands for e-readable data.

struct The name of the struct instance to write to the file.

comment A string for a comment at the beginning of the file.

indent Boolean selector for indentation to the struct’s field depth.

depth The number of levels of nested structs to write.

max-list-items For lists, how many items from each list to write.

Description
Recursively writes the contents of the struct to the file-name in ASCII format. If the struct contains other
structs, those structs are also written to the file. If the number of hierarchical levels contained in the
struct is greater than the specified depth, levels below the depth level are represented by ellipses (...) in
the ASCII file.

If the file already exists, it is overwritten.

24-134 e Language Reference


Predefined Routines
write_ascii_struct()

This routine will not write any Specman internal structs. It will write the sys struct, but not any
predefined structs within sys.

The .erd default file name extension is automatically added to the file name only if the file name you
specify has no extension and does not end with “.” (a period). That is, if you enter “myfile”, the file name
becomes “myfile.erd”. If you enter “myfile.”, the file is named “myfile.”. If you enter “myfile.out”, the
file is named “myfile.out”.

Example
In the following example, there are three levels of hierarchy under the sys struct: the w_st struct contains
a s_st struct, which contains a list of dat_s structs. The ss_i instance of the s_st struct is written to an
ASCII file with these options:

• The comment “My ASCII struct” is placed at the top of the file.
• Indentation of the struct’s fields is TRUE.
• Only the highest hierarchical level of structs is written (depth = 1).
• The first three items in lists are written.
struct dat_s {
dat_l: list of uint;
keep dat_l.size() == 5;
};
struct s_st {
ds_l: list of dat_s;
keep ds_l.size() == 6;
len: int;
hdr: string;
b_l: list of bool;
};
struct w_st {
ss_i: s_st;
wr_file() is {
files.write_ascii_struct("a_s.out", ss_i,
"My ASCII struct", TRUE, 1, 3);
};
run() is also {
wr_file();
};
};
extend sys {
wi: w_st;
};

The following is the a_s.out file created by the example above.

e Language Reference 24-135


Predefined Routines
write_ascii_struct()

-- My ASCII struct
-- The top struct
struct: s_st-@0{
ds_l:
-- struct: ...
-- struct: ...
-- struct: ...
-- ds_l[3..5] ...
};
len: -2025306869
hdr: ""
b_l:
FALSE
TRUE
FALSE
-- b_l[3..3] ...
};
};

Changing depth from 1 to 2 in the example above adds a level of hierarchy to the results, which produces
the following file.
-- My ASCII struct
-- The top struct
struct: s_st-@0{
ds_l:
-- ds_l[0]
struct: dat_s-@1{
-- root___unit: ...
dat_l:
4166871515
381462224
2293917550
-- dat_l[3..4] ...
};
};
-- ds_l[1]
struct: dat_s-@2{
-- root___unit: ...
dat_l:
3680934570
495418143
1152908095
-- dat_l[3..4] ...
};
};
-- ds_l[2]
struct: dat_s-@3{

24-136 e Language Reference


Predefined Routines
write_binary_struct()

-- root___unit: ...
dat_l:
1924257378
1889370393
3534009340
-- dat_l[3..4] ...
};
};
-- ds_l[3..5] ...
};
len: -2025306869
hdr: ""
b_l:
FALSE
TRUE
FALSE
-- b_l[3..3] ...
};
};

See Also
• write() on page 24-103
• write_lob() on page 24-105
• read_ascii_struct() on page 24-130
• write_binary_struct() on page 24-137

24.9.33 write_binary_struct()

Purpose
Write the contents of a struct to a file in binary format

Category
Method

Syntax
files.write_binary_struct(file-name: string, struct: struct)

e Language Reference 24-137


Predefined Routines
write_binary_struct()

Syntax Example
files.write_binary_struct("b_file.dat", b_str);

Parameters

file-name The name of the file to write structs into.

struct The name of the struct instance to write to the file.

Description
Recursively writes the contents of the struct to the file-name in binary format. If the struct contains other
structs, those structs are also written to the file. If the file already exists, it is overwritten.

Example
The following example creates a struct instance named “str” and writes the struct’s contents in binary
format to a file named “b_s.out”.
struct s_st {
len: int;
hdr: string;
b_l: list of bool;
};
struct w_st {
wr_file() is {
var str := a new s_st with {
.len = 1;
.hdr = "top";
.b_l = { TRUE; FALSE; TRUE };
};
files.write_binary_struct("b_s.out", str);
};
run() is also {
wr_file();
};
};
extend sys {
wi: w_st;
};

See Also
• write() on page 24-103

24-138 e Language Reference


Predefined Routines
On-the-Fly Garbage Collection Routine

• write_lob() on page 24-105


• read_binary_struct() on page 24-132
• write_ascii_struct() on page 24-134

24.10 On-the-Fly Garbage Collection Routine

24.10.1 do_otf_gc()

Purpose
Perform on-the-fly garbage collection

Category
Routine

Syntax
do_otf_gc()

Syntax Example
do_otf_gc();

Description
This routine performs on-the-fly garbage collection. It can be called at any time from either a regular
method or a TCM. It takes no arguments and returns no value.

Use this routine at any point when reducing the Specman memory heap would be beneficial. For
example, use this routine between Specman ticks, when significant memory can accumulate. (Regular
garbage collection does not occur between ticks.)

Notes
• The do_otf_gc() routine is not related to the regular garbage collection mechanism, although keeping
the memory heap low with do_otf_gc() helps limit the amount of regular garbage collection that is
performed.
• The do_otf_gc() routine does consume some CPU time, so it should be used in moderation.

e Language Reference 24-139


Predefined Routines
Calling Predefined Routines

• Use the print_otf_msg configuration option to request that on-the-fly GC messages be printed.

Example
This example calls do_otf_gc() from a TCM. However, it can also be called from a regular method.
unit port {
drive_frames : out buffer_port of frame is instance;
keep drive_frames.buffer_size() == 200;
num_frames: uint;

!next_frame: frame;

in_frames() @sys.any is {
var in_count : uint ;

while (in_count < num_frames) {


gen next_frame;
drive_frames.put(next_frame);
in_count += 1;
// invoke on-the-fly garbage collection every 10 frames
if (in_count % 10 == 0) then {
do_otf_gc();
};
};
};
};

See Also
• Chapter 8 “Managing Specman Memory” in the Usage and Concepts Guide for e Testbenches
• configure memory on page 6-26 in the Specman Command Reference
• set_config() on page 24-67 of the e Language Reference

24.11 Calling Predefined Routines

24.11.1 routine()

Purpose
Call a predefined routine

24-140 e Language Reference


Predefined Routines
Calling Predefined Routines

Category
Action

Syntax
routine-name()

routine-name(param, …)

Syntax Example
var s := str_join(slist," - ");

Parameters

routine-name The name of the routine.

param One or more parameters separated by commas, one parameter for each parameter
in the parameter list of the routine definition. Parameters are passed by their
relative position in the list, so the name of the parameter being passed does not
have to match the name of the parameter in the routine definition. The parentheses
around the parameter list are required even if the parameter list is empty.

Description
Calls a predefined routine passing it the specified parameters.

Example
This example shows how to call a predefined routine.
<'
extend sys {
m1() is {
var slist: list of string = {"first";"second";"third"};
var s := str_join(slist," - ");
print s;
};
};
'>

Result
Specman > sys.m1()

e Language Reference 24-141


Predefined Routines
Calling Predefined Routines

s = "first - second - third"

24-142 e Language Reference


25 Modeling State Machines
This chapter contains descriptions of how to create state machines and of the constructs used in them. It
contains the following sections.

• “State Machine Overview” on page 25-1


• “State Machine Constructs” on page 25-2
• “Sample State Machine” on page 25-9
• “Using State Machines” on page 25-10

See Also
• “Invoking Methods” on page 7-22
• “e Data Types” on page 3-1

25.1 State Machine Overview


The e language state machine action provides constructs for modeling state machines in Specman.

A state machine definition consists of the state machine action followed by a state holder expression
and a block that specifies the ways the state machine can get from one state to another (see state
machine on page 25-2).

State machines can be defined only within time-consuming methods (TCMs). When the execution of a
TCM reaches a state machine action, the appropriate series of state transitions occurs, and then the state
machine exits. At this point the TCM continues from the action following the state machine action.

See Also
• “State Machine Constructs” on page 25-2

e Language Reference 25-1


Modeling State Machines
State Machine Constructs

• “Sample State Machine” on page 25-9


• “Using State Machines” on page 25-10

25.2 State Machine Constructs


The e state machine constructs are used to define state machines and the transitions between their states.
This section contains descriptions of the following constructs.

• state machine on page 25-2


• state => state on page 25-5
• * => state on page 25-6
• state action on page 25-7

25.2.1 state machine

Purpose
Define a state machine

Category
Action

Syntax
state machine state-holder-exp [until final-state]
{(state-transition | state) {action; …}; …}

Syntax Example
!c_proc: [st, dn];
s_m()@sys.clk is {
state machine c_proc until dn {
*=> st {wait rise('top.rst'); wait [2]*cycle};
st => dn {out("going to dn"); wait [3]*cycle;};
};
};

25-2 e Language Reference


Modeling State Machines
state machine

Parameters

state-holder-exp Stores the current state of the state machine. This can be a variable in the current
TCM, a field under sys, or any assignable expression. It typically is an
enumerated type field of the struct in which the TCM is defined.

final-state The state at which the state machine terminates.

state-transition A state transition, which occurs when the associated action block finishes. See
state => state on page 25-5 and * => state on page 25-6.

state A state. When this state is entered, the associated action block is invoked. See
state action on page 25-7.

action; … One of the following:


• An action block which, upon completion, causes the transition to occur, if
the state-transition syntax is used.
• An action block that is to be performed when the given state is entered, if the
state syntax is used.

Description
Defines a state machine using an enumerated state-holder-exp to hold the current state of the machine.

The state machine must be defined in a time-consuming method (TCM). When the state machine action
is reached, the state machine starts, in the first state listed in the enumerated state holder expression type
definition.

During the execution of the state machine action the current state is stored in the state-holder-exp.

If the optional until final-state exit condition is used, the state machine runs until that state is reached.
The final state must be one of the enumerated values declared with the state machine name.

If the until clause is not used, the state machine runs until the TCM is terminated, or, if the state machine
is in an all of or first of action, it runs until the all of or first of action completes (see “Terminating a
State Machine” on page 25-11).

The state-transition block is a list of the allowed transitions between states of the state machine. Each
state transition contains an action block that defines conditions that cause the transition to occur.
Typically, the action block contains a single wait until action. However, it can contain any block of
actions. For example,
x => y {wait until @named_event_1; wait until @named_event_2};

The transition only occurs after both events happen, in order.

e Language Reference 25-3


Modeling State Machines
state machine

The action block can contain a regular method, as in the following.


x => y {wait until change(p_clk); me.packet.bb_operations()};

Once change(p_clk) happens, the method executes immediately, and then the transition occurs.

Example
In the following example, the struct field expression used for the state machine is the “status” field
declaration. The state machine name is “status”, and its possible states are “start” and “done”. The state
machine is defined in the “sm_meth()” TCM. It has a final state of “done”, meaning the state machine
terminates when it enters the “done” state.

Since the “start” field is listed first in the list of states, that is the initial state for the state machine. The
state changes from “start” to “done” two “sys.smclk” cycles after it enters the “start” state. Upon
entering the “done” state, the state machine exits. The out() action is executed after the state machine
exits.
struct smp_state_machine{
!status: [start, done];
sm_meth() @sys.smclk is {
state machine status until done {
start => done {wait [2]*cycle};
};
out("The status state machine is done");
};
};

A more complex state machine is shown below. The name of the state machine is “arbiter_state”, and it
is declared with states “idle”, “busy”, “grant”, and “reject”.

This state machine has no “until finish-state” exit condition, so it runs until it the “watcher()” TCM is
terminated.

The “* => idle” syntax means “from any other state to the idle state”. The condition for this transition is
that 10 cycles of “sys.pclk” have elapsed since the state machine entered the any state.
struct bus {
!arbiter_state: [idle, busy, grant, reject];
watcher() @sys.pclk is {
wait [3]*cycle;
state machine arbiter_state {
idle => busy {wait @sys.req};
busy => grant {wait [2]*cycle};
busy => reject {wait @sys.bad_pkt};
* => idle {wait [10]*cycle};
};

25-4 e Language Reference


Modeling State Machines
state => state

};
};

See Also
• “State Machine Overview” on page 25-1
• state => state on page 25-5
• * => state on page 25-6
• state action on page 25-7

25.2.2 state => state

Purpose
One-to-one state transition

Category
State transition

Syntax
current-state=>next-state {action; …}

Syntax Example
begin => run {wait [2]*cycle; out("Run state entered")};

Parameters

current-state The state from which the transition starts.

next-state The state to which the transition changes.

action; … The sequence of actions that precede the transition. It usually contains at least one
time-consuming action.

e Language Reference 25-5


Modeling State Machines
* => state

Description
Specifies how a transition occurs from one state to another. The action block starts executing when the
state machine enters the current state. When the action block completes, the transition to the next state
occurs.

Example
The example below shows a definition of a transition for the “initial” state to the “running” state. If the
'top.start' HDL signal changes while the state machine is in the “initial” state, the state changes to
“running”.
initial => running {wait until change('top.start')@sim};

See Also
• “State Machine Overview” on page 25-1
• state machine on page 25-2
• * => state on page 25-6
• state action on page 25-7

25.2.3 * => state

Purpose
Any-to-one state transition

Category
State transition

Syntax
*=>next-state {action; …}

Syntax Example
* => pause {wait @sys.restart; out("Entering pause state");};

25-6 e Language Reference


Modeling State Machines
state action

Parameters

next-state The state to which the transition changes.

action; … The sequence of actions that precede the transition. It usually contains at least one
time-consuming action.

Description
Specifies how a transition occurs from any defined state to a particular state. The action block starts
executing when the state machine enters a new state. When the action block completes, the transition to
the next state occurs.

Example
The example below shows a definition of a transition for any state to the “running” state. From any state,
if the 'top.start' HDL signal rises and later the 'top.hold' signal falls, the state changes to “running”.
* => running { wait until rise('top.start')@pclk;
wait until fall('top.hold')@pclk };

See Also
• “State Machine Overview” on page 25-1
• state machine on page 25-2
• state => state on page 25-5
• state action on page 25-7

25.2.4 state action

Purpose
Execute actions upon entering a state, with no state transition

Category
State action block

e Language Reference 25-7


Modeling State Machines
state action

Syntax
current-state {action; …}

Syntax Example
* => run {out("* to run"); wait cycle};
run {out("In run state"); wait cycle; out("Still in run");};
run => done {out("run to done"); wait cycle};

Parameters

current-state The state for which the action block is to be executed.

action; … The sequence of actions that is executed upon entering the current state. It usually
contains at least one time-consuming action.

Description
Specifies an action block that is executed when a specific state is entered. No transition occurs when the
action block completes. The state machine stays in the current state until some other transition takes
place.

Example
The last two lines in the following example contain an action block that is to be executed when the state
machine enters the “running” state. The “while TRUE …” action means that as long as the state machine
is in the “running” state, the out() action is executed every cycle.
state machine sm_1 until done {
initial => running { wait until rise('top.a') };
initial => done { wait until change('top.r1');
wait until rise('top.r2') };
running => initial { wait until rise('top.b') };
running {
out("Entered running state");
while TRUE {wait cycle; out("still running");}
};
};

See Also
• “State Machine Overview” on page 25-1
• state machine on page 25-2

25-8 e Language Reference


Modeling State Machines
Sample State Machine

• state => state on page 25-5


• * => state on page 25-6

25.3 Sample State Machine


The following example shows a single state machine. The state machine is declared in the “sm_1” field,
with possible states named “initial”, “running”, and “done”.
struct exa_1_state_machine {
!sm_1: [initial, running, done];
tcm_1()@sys.sm_clk is {
wait [10]*cycle;
state machine sm_1 until done {
initial => running { wait until rise('top.a') };
initial => done { wait until change('top.r1');
wait until rise('top.r2') };
running => done {wait until fall('top.b')};
running {while TRUE {out("Running"); wait cycle}};
};
out("tcm_1 finished");
};
};

The “sm_1” state machine is defined in the “tcm_1()” TCM. Note that the TCM contains other actions
besides the state machine. There is a 10-cycle wait before the state machine starts, and an out() that is
executed after the state machine is finished.

The “until done” clause means that the state machine will run until it reaches the “done” state.

The transition definitions are as follows:

initial => running A rise of the 'top.a' HDL signal causes a transition from “initial” to
“running”.
initial => done A change in the 'top.r1' signal followed eventually by a rise in the 'top.r2'
signal causes a transition from “initial” to “done”.
running => done A fall of the 'top.b' signal causes a transition from “running” to “done”.
running When the state machine enters the “running” state, continuously execute the
“{out(“Running”); wait cycle};” action block until the state changes.

See Also
• “State Machine Overview” on page 25-1
• “State Machine Constructs” on page 25-2

e Language Reference 25-9


Modeling State Machines
Using State Machines

• “Using State Machines” on page 25-10

25.4 Using State Machines


This section contains the following topics.

• “Initializing a State Machine” on page 25-10


• “Terminating a State Machine” on page 25-11
• “Rules for State Transitions” on page 25-12
• “Nested State Machines” on page 25-13
• “Parallel State Machines” on page 25-13

25.4.1 Initializing a State Machine


State machines start by default in the first state specified in the enumerated type definition of the
state-holder-exp (see “State Machine Overview” on page 25-1). In the following, the starting state for
state machine “sm_2” is “initial” because that is the first state listed in the “sm_2” type definition.
struct exa_2_state_machine{
!sm_2: [initial, running, done];
tcm_2()@sys.sm_clk is {
state machine sm_2 until done {
// ...
};
};
};

If the state machine is entered several times in the same TCM, it is initialized to the starting state each
time it is entered. A state machine can be re-entered if it is nested in another state machine or if it is
enclosed in a loop. Conditional initialization of the state machine can be performed within the state
machine as shown in the following.
struct exa_2_state_machine{
!sm_2: [initial, init_cond, init_no_cond, running, done];
tcm_2()@sys.sm_clk is {
state machine sm_2 until done {
initial => init_cond {sync true(cond);};
initial => init_no_cond {sync true(not cond);};
// ...
};
};
};

25-10 e Language Reference


Modeling State Machines
Terminating a State Machine

See Also
• “State Machine Overview” on page 25-1

25.4.2 Terminating a State Machine


You can terminate a state machine in any of the following ways.

• Specify a final state in an until clause.


• Enclose the state machine within a first of action.
• Terminate the TCM using the quit() method.
A state machine defined as follows will exit when it reaches the “done” state. The TCM continues
execution.
struct exa_3_state_machine{
!sm_3: [initial, running, done];
tcm_3()@sys.tclk is {
state machine sm_3 until done {
// ...
};
// ...
};
};

The following state machine is enclosed in a first of action. The other thread of the first of action
terminates after wait [MAXN] * cycle. If the state machine runs for MAXN cycles, the wait thread
finishes and the TCM terminates.
struct exa_4_state_machine {
!sm_4: [initial, running, done];
tcm_4()@sys.tclk is {
first of {
{wait [MAXN]*cycle;};
{state machine sm_4 {
// ...
};
};
// ...
};
};
};

e Language Reference 25-11


Modeling State Machines
Rules for State Transitions

The quit() method of the struct can be used in another TCM to terminate all active TCMs and their state
machines. This method cannot be used to terminate only one of several active TCMs, nor can it
terminate a state machine while allowing the TCM to continue executing. In the following example, a
TCM in sys calls the quit() method of the “exa_4_state_machine” instance, which terminates the
“tcm_4()” TCM and the state machine.
struct exa_4_state_machine{
!sm_4: [initial, running, done];
tcm_4()@sys.tclk is {
state machine sm_4 {
// ...
};
};
};

See Also
• “State Machine Overview” on page 25-1

25.4.3 Rules for State Transitions


• A transition takes place when its action block finishes.
• If there are several contending transitions (for example, several transitions with the same
current-state), their action blocks are executed in parallel. The transition whose action block finishes
first is the one that occurs.
• When the action blocks for two transitions can complete during the same cycle, it is not possible to
determine which transition will prevail. One will occur successfully and the other will not occur.
• Action blocks can take time, but transitions themselves take no time.
If the state machine specifies:
x => y {sync true('cpu.clock' == 1)};
y => z {sync true('alu.clock' == 1)};

and both ‘cpu.clock’ and ‘alu.clock’ are high within the same cycle, the two transitions both occur
within the same cycle.

See Also
• “State Machine Overview” on page 25-1

25-12 e Language Reference


Modeling State Machines
Nested State Machines

25.4.4 Nested State Machines


A state machine is just an action like all others, so it can appear anywhere an action can appear. This
makes nested and parallel state machines possible. For example, the following contains a state machine
named “run_to_finish” nested within another state machine named “sm_5”.
struct exa_5_state_machine {
!sm_5: [begin, run, finish];
run_to_finish: [s_b1, s_b2, s_b3];
tcm_5() @sys.pclk is {
state machine sm_5 until finish {
begin => run {wait [2]*cycle};
run => finish {
state machine run_to_finish until s_b3 {
s_b1 => s_b2 {wait [2]*cycle};
s_b2 => s_b1 {wait [3]*cycle};
s_b2 => s_b3 {wait @sys.s_reset};
};
};
* => begin {wait @sys.reset};
};
};
};

Whenever the “sm_5” state machine enters the “run” state, it starts the nested “run_to_finish” state
machine. When that machine finally reaches its “s_b3” state it exits, and the “sm_5” state machine
enters its “finish” state.

If “sys.reset” becomes TRUE, the “sm_5” state machine enters its “begin” state regardless of the current
state of the “run_to_finish” state machine. This is an example of preempting a state machine from the
outside.

See Also
• “State Machine Overview” on page 25-1

25.4.5 Parallel State Machines


An example of parallel state machines is shown below.
struct exa_6_state_machine {
!sm_6a: [x1, x2, x3];
!sm_6b: [y1, y2];
tcm_6() @sys.sclk is {
all of {
state machine sm_6a until x3 {

e Language Reference 25-13


Modeling State Machines
Parallel State Machines

// ...
};
state machine sm_6b until y2 {
// ...
};
};
out("sm_6a and sm_6b state machines are both done");
};
};

The two state machines in the example above are entered at the same time, and each proceeds
independently of the other. Because they are started in an all of construct, both state machines must exit
before the out() action can be executed.

In the following example, the two state machines are started in a first of rather than all of construct.
struct exa_6_2_state_machine {
!sm_6a_2: [x1, x2, x3];
!sm_6b_2: [y1, y2];
tcm_6_2() @sys.sclk is {
first of {
state machine sm_6a_2 until x3 {
// ...
};
state machine sm_6b_2 until y2 {
//...
};
};
out("either sm_6a_2 or sm_6b_2 state machine is done");
};
};

Parallel state machines can be nested within another state machine, as in the following.
a => b {
all of {
state machine x until end_x {. . .};
state machine y until end_y {. . .};
};
};

See Also
• “State Machine Overview” on page 25-1

25-14 e Language Reference


26 Encapsulation Constructs
This chapter contains syntax and descriptions of the e statements that are used to create packages and
modify access control. The constructs are:

• package package-name on page 26-1


• package type-declaration on page 26-2
• package | protected | private struct-member on page 26-4

26.1 package package-name

Purpose
Associates a module with a package.

Category
Statement

Syntax
package package-name

Syntax Example
package vr_xb;

e Language Reference 26-1


Encapsulation Constructs
package type-declaration

Parameters

package- A standard e identifier which assigns a unique name to the package. It is


name legal for a package name to be the same as a module or type name.

Description
Only one package statement can appear in a file, and it must be the first statement in the file.

A file with no package statement is equivalent to a file beginning with the statement, package main.

Example
<'
// module vr_xb_top
package vr_xb;
'>

See Also
• package type-declaration on page 26-2
• package | protected | private struct-member on page 26-4

26.2 package type-declaration

Purpose
Modifies access to a type or a struct.

Category
Statement

Syntax
[package] type-declaration

Syntax Example
package type t: int(bits: 16);

26-2 e Language Reference


Encapsulation Constructs
package type-declaration

Parameters

type-declaration An e type declaration (for a struct, unit, enumerated list, or other type).

Description
The package modifier means that code outside the package files cannot access the defined struct
member. This includes declaring a variable of the type, extending, inheriting, casting using the as_a
operator, and all other contexts in which the name of a type is used. It is equivalent to the default
(package) access level for classes in Java.

Note The package type does not determine the visibility of a package, but only its access control.

Without the package modifier, the type or struct has no access restriction.

A derived struct (using like inheritance) must be explicitly declared package if its base struct is declared
package. It can be declared package even if its base struct is not.

Definition of a when subtype (using a when or extend clause) does not allow for an access modifier. A
when subtype is public unless either its base struct or one of its determinant fields is declared package.

A when subtype cannot have a private or protected determinant field. Any reference to a when
subtype, even in a context in which the when determinant field is accessible, results in a compilation
error.

Example
<'
// module vr_xb_top
package vr_xb;;
package type width: uint(bits: 8);
'>

See Also
• package package-name on page 26-1
• package | protected | private struct-member on page 26-4

e Language Reference 26-3


Encapsulation Constructs
package | protected | private struct-member

26.3 package | protected | private struct-member

Purpose
Modifies access to a struct field, method, or event.

Category
Keyword

Syntax
package struct-member-definition

protected struct-member-definition

private struct-member-definition

Syntax examples:
private f: int;
protected m() is {};
package event e;

Parameters

struct- A struct or unit field, method, or event definition. See “Structs, Fields
member- and Subtypes” in the e Language Reference for the syntax of struct and
definition unit member definitions.

Description
A struct member declaration may include a package, protected, or private keyword to modify access
to the struct member.

If no access modifier exists in the declaration of a struct member, the struct member has no access
restriction (the default is public).

The package modifier means that code outside the package files cannot access the struct member. It is
equivalent to the default (package) access level for fields and methods in Java.

26-4 e Language Reference


Encapsulation Constructs
package | protected | private struct-member

The protected modifier means that code outside the struct family scope cannot access the struct
member. It is similar (although not equivalent) to the protected semantics in other object-oriented
languages.

The private modifier means that only code within both the package and the struct family scope can
access the struct member. This means that code within the extension of the same struct in a different
package is outside its accessibility scope. It is less restrictive than private attribute of other
object-oriented languages in the sense that methods of derived structs or units within the same package
can access a private struct member.

An extension of a struct member can restate the same access modifier as the declaration has, or omit the
modifier altogether. If a different modifier appears, the compiler issues an error.

All references to a struct member outside its accessibility scope result in an error at compile time. Using
an enumerated field’s value as a when determinant is considered such a reference, even if the field name
is not explicitly mentioned.

A field must be declared package or private if its type is package, unless it is a member of struct which
is declared package.

A method must be declared package or private if its return type or any of its parameter types are
package, unless it is a method of a struct which is declared package.

Only fields, methods and events can have access restrictions. There are other named struct members in
e, namely cover groups and named expects, to which access control does not apply - they are completely
public. However, cover groups and expects are defined in terms of fields, methods and events, and can
refer to other entities in their definitions according to the accessibility rules.

Example
<'
package P1;

struct s1 {
private f: int;
protected m() is {};
package event e;
};
'>

See Also
• package package-name on page 26-1
• package type-declaration on page 26-2

e Language Reference 26-5


Encapsulation Constructs
package | protected | private struct-member

26-6 e Language Reference


Index

Symbols (bits width) bit width specification syntax 3-36


(bits width-exp) size specification operator syntax
- subtraction operator syntax 2-52 2-84
- unary minus operator syntax 2-51 (byte width-exp) size specification operator
-- comment syntax 2-3 syntax 2-84
! Boolean NOT operator syntax 2-44 (bytes width) byte width specification syntax 3-36
! do-not-generate field indicator 4-11 * infinite integer syntax 3-4
! operator * multiplication operator syntax 2-52
used to prevent generation 4-12 * parameter passing by reference syntax 7-34,
used with pre_generate() 11-60 7-35
!= nonidentity operator syntax 2-56 + addition operator syntax 2-52
!== Verilog nonidentity operator syntax 2-58 + unary plus operator syntax 2-51
!~ string non-matching operator syntax 2-60 . (period) at start of path name 2-34
!field-name 4-11 . (period) field selection operator syntax 2-93
#define statement syntax 20-5 / division operator syntax 2-52
#ifdef statement syntax 20-1 /.../ AWK regular expression syntax 2-67
#ifndef statement syntax 20-1 // comment syntax 2-3
$ port access operator := assignment operator 8-2
event ports 6-17 < less than operator syntax 2-54
simple ports 6-7 << bit shift left operator syntax 2-42
$0 string matching pseudo-variable 2-67 <= delayed assignment action syntax 8-9
$1 - $27 string matching pseudo-variables 2-66, <= less than or equal to operator syntax 2-54
2-67 <’ begin code markers 2-2
example 2-68 = assignment action syntax 8-4
% modulo (remainder) operator syntax 2-52 = assignment operator 8-2
% physical field indicator 4-12 == Boolean equality operator 2-56
%{... , ...} bit concatenation operator syntax 2-79 versus = assignment operator 8-5
%field-name 4-12 == identity operator syntax 2-56
& bitwise AND operator syntax 2-40 === Verilog identity operator 8-5
&& Boolean AND operator syntax 2-45 === Verilog identity operator syntax 2-58

e Language Reference Index-1


Index

=> Boolean implication operator syntax 2-48 \d regular expression digit 2-67
=> Boolean imply operator syntax 2-48 \D regular expression nondigit 2-67
=> See implication operator, state transition \S regular expression non-white-space 2-67
syntax, yield temporal expression \s regular expression white space 2-67
=> yield temporal expression 13-30 \W regular expression non-word 2-67
sampling event 13-31 \w regular expression word 2-67
> greater than operator syntax 2-54 ^ bitwise XOR operator syntax 2-40
>= greater than or equal to operator syntax 2-54 _ underscore
>> bit shift right operator syntax 2-42 in numbers 2-4
>> file concatenation operator 24-110 in names 2-10
? : conditional evaluation operator syntax 2-96 {... ; ...} list concatenation operator syntax 2-77
@ sampling operator temporal expression syntax {;} temporal sequence syntax 13-21
13-37 {}
@ unary event temporal expression syntax 13-35 in temporal expressions 13-21
@n operator syntax 17-61 {} action block delimiters 2-16
@sim event 12-5 | bitwise OR operator syntax 2-40
emitting 13-5 || Boolean OR operator syntax 2-46
simulator callback 12-9 ~ bitwise negation operator syntax 2-38
@sim operator with ports 6-11 ~ string matching operator syntax 2-60
@x ~[..] true match repeat syntax 13-28
HDL logic translation 13-43 ‘ backticks
@x operator syntax 17-61 in macro names 2-12
@z ‘ backtick
HDL logic translation 13-43 in regular expressions 2-67
@z operator syntax 17-61 ‘ See also backtick
[..] first match repeat syntax 13-26 ’ (apostrophe) syntax 2-95
[..] list slice operator syntax 2-75 ’ (apostrophe) usage 2-95
[:] bit slice operator ’ (tick)
and packing 18-24 enumerated type selection syntax 3-7
and ports 6-29 subtype selection syntax 3-9
and ports, forcing 6-36 ’> end code markers 2-2
syntax 2-70
[] Numerics
in temporal expressions 13-24, 13-26, 13-28
list index syntax 3-13 0c character symbol 2-9
subscript operator 3-13 2147483647 predefined constant maximum
temporal repetition syntax 13-24 integer 2-8
[] list size operator 4-15 4-state. See four-state
[length-expression] list initial size specification
4-15 A
[name, ...] enumerated type definition syntax 3-31 abs() arithmetic routine syntax 24-16
[range, ...] range modifier operator syntax 2-83 absolute value routine 24-16
[range, ...] scalar range syntax 3-34

Index-2 e Language Reference


Index

absolute_max_list_size configuration option release 17-55


11-26 repeat until 9-9
abstract methods return 7-30
declaring 7-19 routine 24-140
restrictions on 7-20 start tcm() 7-25
access modifiers state machine 25-2
package 26-1, 26-2 state transitions 25-7
private 26-4 sync 15-1
protected 26-4 tcm() 7-23
struct members 26-4 try 10-19
actions var 8-2
= assignment 8-4 wait 15-4
all of 15-6 warning() 10-14
assert 10-21 while 9-7
break 9-20 actions, <= assignment 8-9
case bool-case-item 9-5 add(item) list pseudo-method syntax 23-3
case labeled-case-item 9-3 add(list) list pseudo-method syntax 23-5
check that 10-1 add_file_type() file routine syntax 24-93
compute 7-29 add0(item) list pseudo-method syntax 23-7
conditional 9-1 add0(list) list pseudo-method syntax 23-9
continue 9-21 advanced replacement macro, defined 19-10
defining 19-7 agent() predefined method syntax 5-25
dut_error() 10-4 agent_options
emit 12-6 coverage item option 16-50
error() 10-15 syntax
executing 13-48, 14-1 arc 16-50
executing conditionally, overview 2-18 block 16-50
executing iteratively, overview 2-18 event, 16-50
fatal() 10-17 expr 16-50
first of 15-8 hier 16-50
for 9-15 instance 16-50
for each module 16-50
file matching 9-19 state 16-50
in loop 9-11 toggle 16-50
line in file 9-17 trans 16-50
for from to 9-14 alias option, vhdl function statement 17-36
force 17-50 alias option, vhdl procedure statement 17-40
gen 11-56 all of action syntax 15-6
if then else 9-1 all() list pseudo-method syntax 23-72
iterative 9-7 all_indices() list pseudo-method syntax 23-74
method() 7-27 all_values() expression syntax 3-52
op= assignment 8-6 also method extension option 7-12, 7-14
overview 2-16 and

e Language Reference Index-3


Index

in compound constraint Boolean expression attribute


11-50 struct member
of list items 23-78 syntax 4-28
temporal expression syntax 13-16 average() list pseudo-method syntax 23-79
and_all() list pseudo-method syntax 23-78 average, of list items 23-79
any_struct
parent of all user-defined structs 22-18 B
predefined base struct type 4-2
any-state => state transition syntax 25-6 b binary number symbol 2-5
apostrophe backslash characters 2-9
usage 2-95 base 10 log routine 24-20
See also ’, tick base 2 log routine 24-19
append() string routine syntax 24-29 behavioral rules
appendf() string routine specifying 4-3
formats 24-65 temporal 13-9, 14-3
syntax 24-31 bin() string routine syntax 24-32
apply() list pseudo-method syntax 23-29 binary files
arithmetic operators 2-50 reading 24-102, 24-132
as_a type casting operator writing 24-106, 24-138
subtype casting 3-13 binary integers 2-4
as_a() type casting operator syntax 3-39 bit data type, definition of 3-2
ASCII characters 2-9 bit selects
assert action syntax 10-21 constraining 11-15
assignment bit slices
action, and copying structs or lists 22-21 and ports 6-29
of Boolean types 3-22 and ports, forcing 6-36
compound (op=) 8-6 constraining 11-15
defined 3-19 bit width, specifying 3-35
of enumerated types 3-22 bits
of lists 3-24 ANDing 2-40
of numeric types 3-21 Boolean operators 24-25
references 3-20 concatenating 2-79
rules 3-19 negating 2-38
simple (=) 8-4 ORing 2-40
of strings 3-23 shifting right, left 2-42
of structs 3-22 slicing 2-70
assignment, delayed (<=) 8-9 XORing 2-40
assume struct member bitwise_and() pseudo-method syntax 24-25
syntax 14-3 bitwise_nand() pseudo-method syntax 24-25
at_least bitwise_nor() pseudo-method syntax 24-25
coverage item option 16-10 bitwise_or() pseudo-method syntax 24-25
cross coverage item option 16-32 bitwise_xnor() pseudo-method syntax 24-25
transition coverage item option 16-43 bitwise_xor() pseudo-method syntax 24-25
bool data type, definition of 3-3
Index-4 e Language Reference
Index

Boolean in names 2-10


bitwise AND 24-26 check
bitwise OR 24-26 command, global methods called by 22-6,
bitwise XOR 24-26 22-7
data type. See bool effects
types, assigning 3-22 setting with set_check() 10-11
Boolean FALSE 2-8 predefined method syntax 22-19
Boolean operators 2-44 check that action syntax 10-1
Boolean TRUE 2-8 check_test() predefined method
brackets. See [] executed by global.stop_run() 17-65
break action syntax 9-20 syntax 22-7
buckets checking
contributing tests, listing 22-89, 22-90 subtypes 2-88
goals 22-85 See also behavioral rules
buffer ports clear() list pseudo-method syntax 23-10
defining 6-21 close() file routine syntax 24-95
byte data type, definition of 3-2 code
byte width, specifying 3-35 checking, action for 10-21
segments 2-2
C collect gen command
solving value distribution errors with 11-2
C routines, bypassing type checking for 22-47 commands
C style formatting mask 24-65 in actions 24-80
C style loop 9-15 custom, defining 19-6
callbacks in e code 24-80, 24-139
from the simulator to Specman Elite 13-5 executing from e 24-80
on bit-selects of vectors 13-5 operating system 24-82, 24-83, 24-84
using Verilog events to create 13-6 show ports 6-100
calling methods, without using value 7-29 trace ports 6-102
carriage-return characters 2-9 comparison operators 2-54
case bool-case-item action syntax 9-5 values compared 2-56
case default option syntax 9-3 compound
case labeled-case-item action syntax 9-3 constraint Boolean expressions 11-50
case sensitivity parameters, passing 7-35
in names 2-10 restrictions on 7-36
casting compute action syntax 7-29
automatic 3-22, 3-28 concatenation. See packing
explicit 3-39 conditional actions 9-1
reference parameters 3-29 conditional compilation
signed integers to unsigned integers 3-29 based on Specman Elite version 20-10
change temporal expression syntax 13-41 configuration options
characters displaying 24-72
escape sequences 2-8 file 24-74, 24-76
hidden 24-41
e Language Reference Index-5
Index

gen item in list 11-14


absolute_max_list_size 11-26 keep 11-21
default_max_list_size 11-12 keep all of 11-24
resolve_cycles 11-40 keep for each 11-27
misc keep gen before 11-39
-ports_data_pass_by_pointer 6-58 keep gen_before_subtypes() 11-43
reading 24-76 keep is_all_iterations() 11-25
retaining across restores and reloads 24-78 keep reset_gen_before_subtypes() 11-46
saving 24-74 keep reset_soft() 11-37
setting 24-67 keep soft 11-31
constants keep soft gen before 11-41
expressions treated as, in constraint Boolean keep soft select 11-33
expressions 11-5, 11-7 on lists 11-11
methods not treated as, in constraint Boolean modifying generation sequence 11-48
expressions 11-5 nested 11-27
predefined 2-8 port bindings 6-43
user-defined struct members 4-3
names 2-35 on structs 11-10
constraining numerics to even or odd 11-16 unidirectional 11-4
constraint blocks setting with value() 11-48
defining 11-24 user-defined 11-2
constraint Boolean expressions value() 11-48
compound, and soft constraints 11-31 weighted 11-33
enforceable 11-7 See also soft constraints
generatable items in 11-53 constructs, overview 2-12
syntax 11-50 consume temporal expression syntax 13-45
constraints continue action syntax 9-21
applied to one instance 11-56 contradiction errors 11-5
bit slice 11-15 caused by constraint cycle 11-6
debugging 11-19 copy predefined method syntax 22-20
and generation order 11-16 copy() predefined method syntax 23-31
limitations 11-19 copy, of expression
and signed entities 11-18 shallow 22-20
and soft constraints 11-19 count() list pseudo-method syntax 23-32
Boolean expressions 11-50 cover
cycles 11-6 struct member syntax 16-1
and keep gen before 11-40 using also ... is also struct member syntax
defined 11-1 16-53
defining 4-3, 11-1, 11-20 (see also coverage)
on generatable items, defining 11-50 coverage
generatable items, identifying 11-53 API
gen-item 11-53 end_group() method 16-73
hard value, defining 11-21 end_instance() method 16-72

Index-6 e Language Reference


Index

end_item() method 16-71 displaying overall 22-94


invoking 16-64 goals 16-10, 16-11, 16-32, 16-43
scan_bucket() method 16-70 groups, weights 16-4
start_group() method 16-66 ignored values 16-12, 16-33, 16-44
start_instance() method 16-67 illegal values 16-13, 16-34, 16-45
start_item() method 16-68 items, weights 16-14, 16-34, 16-45
basic items uint items 16-14
defining 16-8 ungradeable values 16-14
bit slices 16-23 groups
buckets automatic prev variable 16-54
defining 16-11 defining 16-1
names 16-6, 16-7 extending 16-53
code coverage prev variable 16-55
SureCov options 16-50 extending per instance 16-54
combining previous and new definitions external option 16-49
16-54 global option 16-3
contributing tests, listing 22-89 is empty syntax 16-2
cross coverage names 16-2, 16-54
extension example 16-40 no_collect option 16-3
per instance example 16-40 options 16-3
cross items radix option 16-3
at_least option 16-32 sampling events 16-2
defining 16-31 selecting 22-86
extending 16-59 struct members 4-3
ignore option 16-33 text option 16-3
illegal option 16-34 weight option 16-4
name option 16-32 when option 16-3
options 16-32 hierarchical struct fields 16-23
text option 16-32 holes 16-10, 16-11
weight option 16-34 showing all 24-70
when option 16-32 items
cross of cross example 16-41 at_least option 16-10
cross__item variable 16-34 example 16-19
current seed value 22-98 at-least-num range option 16-11
current test name 22-97 automatic prev variable 16-60
external groups cross 16-4
defining 16-49 defining 16-2, 16-8, 16-54
SureCov 16-49 every-count range option 16-11
fields generated on the fly 16-24 external option 16-49
goals ignore option 16-12
setting 22-85 example 16-20
grades illegal option 16-13
default number of buckets 16-14 example 16-21

e Language Reference Index-7


Index

name range option 16-11 transition items


names 16-9, 16-59 at_least option 16-43
no_collect option 16-10 defining 16-42
example 16-18 extending 16-59
no_trace option 16-10 ignore option 16-44
example 16-22 illegal option 16-45
options 16-9 name option 16-43
per_instance option 16-9 names 16-42
example 16-18 options 16-43
radix option 16-14 text option 16-43
example 16-21 weight option 16-45
range option 16-11 when option 16-43
ranges 16-6, 16-7 transition__item variable 16-45
ranges option 16-11 weights
example 16-19 multiplying 22-83
selecting 22-86 setting 22-83
text option 16-10 and when subtypes 4-25
example 16-18 writing .ecov file during a test 22-93
transition 16-4 covers.get_contributing_runs() predefined
types 16-9 method syntax 22-89
weight option 16-14 covers.get_unique_buckets() predefined method
example 16-22 syntax 22-90
when option 16-10 covers.include_tests() predefined method syntax
example 16-19 22-82
list elements 16-22 covers.set_at_least() predefined method syntax
per instance 16-15 22-85
errors 16-17 covers.set_cover() predefined method syntax
items 16-15 22-86
original per_type item 16-15 covers.set_weight() predefined method syntax
sample reports 16-25, 16-28 22-83
per_instance option 16-15 CRC functions for lists 23-85
predefined method expressions 16-22 crc_32() list pseudo-method syntax 23-87
ranges 16-11 crc_32_flip() list pseudo-method syntax 23-90
effects on grades 16-14 crc_8() list pseudo-method syntax 23-85
results .ecov file name 22-96 cross coverage 16-31
session.events field 2-26 item options 16-32
show cover command 16-36 item syntax 16-31
Show Coverage GUI 16-36 cross__item-a__item-b coverage cross name
test ranking syntax 16-32
listing unique buckets 22-90 cross__item-name coverage syntax 16-34
transition cycle temporal expression syntax 13-38
extension example 16-48 cyclic import
per instance example 16-47 explicit 21-2

Index-8 e Language Reference


Index

example 21-5 subtypes 3-3


implicit 21-2 scalars
example 21-4 size 3-16
cyclic importing simulator objects 3-17
parsing order 21-3 strings 3-15
cyclic redundancy checks. See CRC defaults 3-15
size 3-16
D struct pointers
size 3-16
d decimal number symbol 2-5 structs 3-8
data Boolean subtypes 3-9
comparison 10-1 size 3-16
fields. See fields subtypes 3-8
structs. See structs time 3-2
data types uint 3-2
bit 3-2 width modifiers 3-3
bit concatenations 3-17 date_time() OS routine syntax 24-89
bool 3-3 dead locks 22-76
byte 3-2 debug info
casting 3-39 retaining across restore and reload 24-78
automatic 3-28 debugging
compound 3-8 packing 18-25
enumerated, default value 3-6 dec() string routine syntax 24-34
enumerated, numeric value 3-5 decimal integers 2-4
for expressions 3-17 declarative_item option, vhdl function statement
extending 3-31 17-37
external_pointer 3-16 declarative_item option, vhdl procedure
HDL objects 3-17 statement 17-41
infinite (unbounded) integers 3-4 declared_type() pseudo-method syntax 22-45
int 3-2 deep_compare() predefined routine syntax 24-5
lists 3-13 deep_compare_physical() predefined routine
defaults 3-14 syntax 24-11
size 3-17 deep_copy() predefined routine syntax 24-2
memory requirements 3-16 default sampling event 12-9
memory size requirements 3-16 default, case action option 9-3, 9-5
nibble 3-2 -default_max_list_size 11-12
pack() expressions 3-17 define 20-5
predefined scalar types 3-2 define as
range modifiers 3-3 replacement terms, maximum number
scalar allowed 19-6
defaults 3-2 define as computed
enumerated 3-5 compiled macros 19-13
named subtypes 3-4 loaded macros 19-13
sizes 3-2
e Language Reference Index-9
Index

precedence over define as 19-5, 19-13 for from to option 9-14


replacement terms, maximum number drive option, verilog variable statement 17-17
allowed 19-13 drive_hold option, verilog variable statement
statement syntax 19-10 17-17
define as statement syntax 19-1 DUT data
‘define macros 2-12 checking 22-19
define statement collecting from 22-6, 22-7
violating import statement order] 21-7 extracting 22-24
‘defines, Verilog DUT errors
deferred 17-62 checking for 10-3
importing 17-7 defining responses 10-5
delay option, vhdl driver statement 17-31 line in module, returning 10-6
delay temporal expression syntax 13-34 method name, returning 10-6
delayed assignments struct name, returning 10-6
making 8-9 struct reference, returning 10-6
delete() list pseudo-method syntax 23-11 dut_error() action syntax 10-4
detach temporal expression 13-8 dut_error_struct predefined struct 10-5
syntax 13-31 dut_error_struct.check_effect() 10-6
disconnect_value option, vhdl driver statement dut_error_struct.pre_error() 10-7
17-31 dut_error_struct.set_check_effect() 10-7
div_round_up() arithmetic routine syntax 24-23 dut_error_struct.source_location() 10-6
division dut_error_struct.source_method_name() 10-6
rounding down 2-53 dut_error_struct.source_struct() 10-6
rounding up 24-23 dut_error_struct.source_struct_name() 10-6
do option dut_error_struct.write() 10-5, 10-7
for each file matching loop 9-19
for each in loop 9-11 E
for each line in file loop 9-18
for from to loop 9-14 .e files 2-2
for loop 9-16 e module names 2-10
while loop 9-8, 9-10, 9-11 e names
do_otf_gc() routine syntax 24-139 legal 2-10
do_pack() predefined method 18-23 e_path() predefined method syntax 5-23
syntax 18-38 .ecfg files 24-74
do_print() predefined method syntax 22-22 configuration options 24-76
do_unpack() predefined method 18-23 edges keep soft select option 11-34
syntax 18-42 ellipses, expanding 24-41
documentation ellipsis. See ellipses
conventions 1-1 else dut_error option, check that action 10-2
documentation syntax notation 1-2 omitting 10-3
dot at start of path name 2-34 else error() option, assert action 10-21
dot placeholders in strings, expanding 24-41 else if option, if then else action 9-1
down else option, if then else action 9-1, 9-2
emit action syntax 12-6
Index-10 e Language Reference
Index

empty method declaration option 7-19 event struct members


encapsulation defining 12-4
package package-name statement 26-1 syntax 12-4
package struct member modifier 26-4 event_port_edge type 6-54
package type-declaration statement 26-2 events
end_group() predefined method syntax 16-73 @
end_instance() predefined method syntax 16-72 binary syntax 13-37
end_item() predefined method syntax 16-71 unary syntax 13-35
enforceable expressions 11-7 @sim 12-5
enumerated types binary sampling expression 13-37
assigning 3-22 checking for occurrences 2-49
numeric values 3-5 consuming 13-45
casting in comparisons 3-7 for debugging 12-13
comparison operations 3-6 defined 12-1
defining 3-31 emitting 12-6
empty 3-6 end_of_test 17-65
extending 3-6 executing actions on 14-1
names for values 2-29 functional coverage data 12-2
renaming 3-6 instances 12-3
scalars, extending 3-37 invoking 12-3
environment variables is only redefinition 12-5
UNIX, getting 24-88 named 12-4
ERROR check effect 10-12 names 12-4
error detection and handling actions, overview predefined 12-10
2-22 quit 12-12
error handling redefining 12-5
programming errors 10-21 sampling 12-8
user errors 10-13 schedule of 12-3
error() action syntax 10-15 scope of 12-3
ERROR_AUTOMATIC check effect 10-12 session struct field 12-2
ERROR_BREAK_RUN check effect 10-12 session.call 12-13
ERROR_CONTINUE check effect 10-12 session.check 12-13
errors session.dut_err 12-14
exception handling 10-19 session.dut_error 12-14
setting error message 10-15 session.end_of_test 12-10, 12-12
setting warning message 10-14 session.events counter 2-26
evaluation order 2-37 session.line 12-13
eVCs session.output 12-13
version-independent 20-10 session.return 12-13
even value routine 24-18 session.sim_read 12-13
even() arithmetic routine syntax 24-18 session.sim_write 12-13
event ports session.start_of_test 12-10, 12-11
defining 6-23 session.tcm_call 12-13

e Language Reference Index-11


Index

session.tcm_end 12-13 extending


session.tcm_return 12-13 coverage groups 16-53
session.tcm_start 12-13 cross items 16-59
session.tcm_state 12-13 enumerated scalar types 3-37
session.tcm_wait 12-13 struct subtypes 4-39
struct members 4-3 restrictions 4-7
struct.quit 12-10, 12-12 structs, limitations with like 4-7
sys.any 12-9, 12-10, 12-11 transition items 16-59
sys.new_time 12-10 external coverage item option 16-49
sys.tick_end 12-10, 12-11 external_pointer
sys.tick_start 12-10, 12-11 data type 3-16
tracing 12-13 extract() predefined method syntax 22-24
unary expression 13-35 extract_test() predefined method
unattached 12-5 executed by global.stop_run() 17-65
in when subtypes 12-5 syntax 22-6
eventually temporal expression 12-12
syntax 13-23 F
exec temporal expression syntax 13-48
executing commands from e 24-80 fail temporal expression syntax 13-14
exists() list pseudo-method syntax 23-33 fall temporal expression syntax 13-41
exiting Specman Elite 10-17 fast_delete() list pseudo-method syntax 23-13
expect struct member 4-3 fatal() action syntax 10-17
syntax 14-3 field list specification syntax 23-35
exponential routine 24-21 field() pseudo-method syntax 22-46
expressions fields
all_values() 3-52 defining 4-11
constraint Boolean expressions 11-50 inhibiting generation of 11-60
converting to strings 24-59 keyed lists 4-17
data types of 3-17 lists 4-14
declared type descriptor for, getting 22-45 of unit instances 5-15
enforceable 11-7 of unit type 5-16
gen-item 11-53 of structs, iterations of 11-26
HDL pathname 17-61 order of generation 11-2
method() 7-27 path resolution 2-93
operands 2-23 physical 4-12
order of evaluation 2-37 packing 18-8, 18-38
overview 2-23 unpacking 18-8, 18-43
// specman deferred 17-62 referencing 2-27, 2-31
tcm() 7-23 restricting generated values for 11-21
temporal 13-1 selecting
type checking 2-23 . (period) operator 2-93
type descriptor for, getting 22-45 soft constraints for, defining 11-31
extend type statement syntax 3-37 struct members 4-3
type 4-12
Index-12 e Language Reference
Index

type descriptors 22-46 copying 24-110


ungenerated 4-11, 4-12 deleting 24-112
unit descriptors 24-92
instance fields 5-11 .ecfg 24-74, 24-76
type fields 5-13 existence, checking 24-113
values extensions, getting 24-114
assigning 4-13 global struct 24-91
initializing 22-28 importing 21-1
FIFO ordered resource sharing 22-54 iteration actions 9-17
file modification dates, getting 24-107
search paths 24-91 names 24-91
file_age() file routine syntax 24-107 getting 24-93
file_append() file routine syntax 24-109 pattern matching 24-93
file_copy() file routine syntax 24-110 renaming 24-124
file_delete() file routine syntax 24-112 and search paths 24-91
file_exists() file routine syntax 24-113 wild cards 24-92, 24-93
file_extension() file routine syntax 24-114 opening 24-98
file_is_dir() file routine syntax 24-116 read modes 24-99
file_is_link() file routine syntax 24-117 reading
file_is_readable() file routine syntax 24-118 ASCII 24-100
file_is_regular() file routine syntax 24-120 ASCII structs 24-130
file_is_temp() file routine syntax 24-121 binary structs 24-132
file_is_text() file routine syntax 24-123 lists of bits 24-102
file_rename() file routine syntax 24-124 renaming 24-124
file_size() file routine syntax 24-125 search paths 24-91
files size, getting 24-125
.ecov specman.v 17-2
name, displaying 22-96 temporary, creating 24-127
append mode 24-99 top module name, displaying 22-97
appending 24-109 types, checking 24-116, 24-117, 24-120,
See also concatenating 24-121, 24-123
buffers, flushing 24-96, 24-97 write modes 24-99
check writing
if directory 24-116 ASCII 24-103
if link 24-117 ASCII structs 24-134
if readable 24-118 binary 24-105
if regular 24-120 binary structs 24-137
if temporary 24-121 formatted data 22-50
if text 24-123 lists of bits 24-105
closing 24-95 lists of strings 24-128
concatenating 24-110 files predefined struct 2-25
See also files appending files.write_ascii_struct
configuration options 24-74, 24-76 .erd file name extension 24-135

e Language Reference Index-13


Index

final_reorder 18-22 G
final_reorder field 18-22
finalize command, global method 22-8 garbage collection
finalize() predefined method syntax 22-26 on-the-fly collection routine 24-139
finalize_test() predefined method gen
executed by global.stop_run() 17-65 action
syntax 22-8 syntax 11-56
first method extension option 7-12, 7-15 called from pre_generate() 11-57
first of action generatable items
syntax 15-8 defining constraints for 11-50
terminating branch of 22-78 identifying 11-53
first() list pseudo-method syntax 23-36 random values for 11-56
first_index() list pseudo-method syntax 23-37 generate command
flow control actions, overview 2-19 global methods called by 22-4, 22-5
flush() file routine syntax 24-97 generate_test() predefined method syntax 22-5
for action syntax 9-15 generated values, restricting 11-21
for each file matching action syntax 9-19 generating data 2-21
for each in action syntax 9-11 generation
for each line in file action syntax 9-17 contradiction errors during 11-5
for from to action syntax 9-14 by generate_test() 22-5
force action syntax 17-50 inhibiting field generation 11-60
forcible option, verilog variable statement 17-17 like inheritance restrictions 4-42
forcible, verilog variable statement 17-17 on-the-fly 11-1, 11-56
fork and join order 11-2
using all of action 15-7, 15-8 modifying 11-40
using first of action 15-8 modifying with value() 11-48
formal verification and soft value constraints 11-9
defining behavioral rules for 14-3 post_generate() 11-61
format string for appendf() and outf() 24-65 pre_generate() 11-59
form-feed characters 2-8 of random values 11-56
four-state starting 11-1
logic comparison operators 2-58 troubleshooting
x transitions 13-43 bit slice constraints 11-17
x value 2-58 values, manipulating 11-61
z transitions 13-43 gen-item expression syntax 11-53
z value 2-58 get_all_units() routine syntax 5-39
from_specman_scale() pseudo-method syntax get_config() configuration routine syntax 24-72
22-99 get_current_handle() predefined method syntax
full_hdl_path() predefined method syntax 5-22 22-70
full_run_name get_define() predefined method syntax 22-52
test identifier 22-82 get_enclosing_unit() predefined method syntax
5-32
get_handles_by_name() predefined method
syntax 22-72
Index-14 e Language Reference
Index

get_handles_by_type() predefined method syntax H


22-74
get_indices() list pseudo-method syntax 23-39 h hexadecimal symbol 2-5
get_parent_unit() predefined method syntax 5-27 handles for threads 22-69
get_retain_state() predefined routine syntax getting list of for struct instance 22-72
24-79 getting value of
get_symbol() OS routine syntax 24-88 by struct type 22-74
get_unit() predefined method syntax 5-29 for current TCM 22-70
getpid() OS routine syntax 24-90 hard constraints
glitch handling 12-15 defined 11-1
glitches keep 11-21
how Specman handles 12-14 keep for each 11-27
global has() list pseudo-method syntax 23-40
coverage group option 16-3 hash tables
methods, overview of 22-2 using keyed lists 4-17
global predefined struct 2-24 HDL objects
global.check_test() 22-7 accessing 17-61
global.check_test() predefined method syntax forcing values on 17-50
22-7 releasing a force action 17-55
global.extract_test() 22-6 HDL pathname expression syntax 17-61
global.extract_test() predefined method syntax hdl_path() predefined method syntax 5-19
22-6 hex() string routine syntax 24-35
global.files struct 24-91 hexadecimal integers 2-4
global.finalize_test() 22-8 high impedance HDL value translations 13-43
global.finalize_test() predefined method syntax holes (see coverage holes)
22-8
global.generate_test() 22-5 I
global.generate_test() predefined method syntax if then else action syntax 9-1
22-5 #ifdef statement
global.run_test() 22-6 violating import statement order 21-7
global.run_test() predefined method syntax 22-6 ifdef. See #ifdef
global.setup_test() 22-4 ifndef. See #ifndef
global.setup_test() predefined method syntax ignore
22-4 coverage item option 16-12, 16-13
global.start_test() 22-5 cross coverage item option 16-33
global.start_test() predefined method syntax 22-5 transition coverage item option 16-44
global.stop_run() 17-65 IGNORE check effect 10-12
global.stop_run() predefined method syntax illegal
17-65 cross coverage item option 16-34
grading transition coverage item option 16-45
goals ilog10() arithmetic routine syntax 24-20
setting 22-85 ilog2() arithmetic routine syntax 24-19
weights, setting 22-83 implication

e Language Reference Index-15


Index

operator See also like, when


in compound constraint Boolean init() predefined method syntax 22-27
expression 11-50 initial_value option, vhdl driver statement 17-31
and keep gen before 11-40 inline method 7-13
and keep soft gen before 11-42 restrictions on 7-7
implicit packing and unpacking 18-25 inline method declaration option 7-5
implicit variables inline only method extension option 7-12
in for each in loops 9-12 insert(index, item) list pseudo-method syntax
in generatable item definitions 11-53 23-15
index 2-32 insert(index, list) list pseudo-method syntax
in lists 2-86 23-16
it 2-28, 2-30 instance names
in lists 2-86 methods 2-28
me 2-28, 2-31 pseudo-methods 2-29
overview 2-30 routines 2-28
imply operator int data type, definition of 3-2
in compound constraint Boolean expression integer data type
11-50 See int
and keep gen before 11-40 integers
and keep soft gen before 11-42 casting 3-29
import maximum size 2-8
avoiding module dependency example 21-6 minimum size 2-8
import statement unbounded, and packing 18-28
cyclic import 21-2 See also numbers
cyclic referencing 21-2 interface option, vhdl function statement 17-36
multiple modules 21-2 interface option, vhdl procedure statement 17-40
placement of 2-13, 21-3 inversion operator 13-13
special case of order violation 21-7 invocation
syntax 21-1 generation 11-1
importing Verilog macros 17-7 invoking commands from e 24-80
in range list operator syntax 2-62 ipow() arithmetic routine syntax 24-21
in, constraining multiple lists 11-15 is a Boolean operator syntax 2-88
index implicit variable 2-32 is a struct subtype construct 11-51
index reference in generatable items 11-57, 11-53 is a subtype constraint syntax example 11-22
INERTIAL option, vhdl driver statement 17-31 is a subtype field reference 3-11
infinite integer, and packing 18-28 example 3-12
infinite integers 3-4 is a subtype generation constraint 3-12
infinite unsigned integers 3-4 is a subtype syntax example 3-11
inheritance 4-33–4-48 is also coverage group extension 16-53
like 4-2, 4-4 is instance unit field syntax 5-11
single 4-33 is not a Boolean operator syntax 2-88
when 4-2, 4-3, 4-21 is only event syntax 12-5
versus like 4-33 is_a_permutation()

Index-16 e Language Reference


Index

and constraining lists 11-15, 11-22 struct member syntax 11-33


is_a_permutation() list pseudo-method syntax keeping clause, in gen action 11-56
23-42 key() list pseudo-method syntax 23-92
is_empty() list pseudo-method syntax 23-44 key_exists() list pseudo-method syntax 23-97
isqrt() arithmetic routine syntax 24-22 key_index() list pseudo-method syntax 23-95
it implicit variable 2-30 keyed lists
in gen-item expression 11-53 defining 4-17
item coverage item syntax 16-8 fields 4-17
item in list constraints 11-14 not generatable 3-15, 23-98
items in list, constraining 11-12 pseudo-methods 23-91
backwards compatibility for 11-13 restrictions on 23-98
example of 11-23 syntax 4-17
iterative actions 9-7 keywords, alphabetical list of 2-10
kill() predefined method syntax 22-76
K
K (kilo) multiplier 2-4
L
keep last() list pseudo-method syntax 23-45
constraining list size 11-12 last_index() list pseudo-method syntax 23-47
constraining one list to another list 11-14 left-to-right evaluation 2-37
constraining scalar list items 11-12 library option, vhdl function statement 17-36
constraining struct list items 11-12 library option, vhdl procedure statement 17-40
item in list 11-14 like
struct member syntax 11-21 inheritance 4-4, 4-33–4-48
keep all of advantages 4-40
struct member syntax 11-24 generation restrictions 4-42
keep for each language restrictions 4-41
constraining multiple list items 11-15 limitations with extend 4-7
struct member syntax 11-27 syntax 4-3
keep gen before line in module, returning on DUT error 10-6
struct member syntax 11-39 line number in source, finding 22-47
keep gen_before_subtypes() syntax 11-43 line option 9-18
keep is_all_iterations() list functions 23-1
constraining lists of structs 11-15 list index operator syntax 2-69
list method syntax 11-25 list of <type> definition 3-13, 4-14
memory and performance considerations list of even integers
with 11-26 generating 11-16
keep reset_gen_before_subtypes() syntax 11-46 list of list definition syntax 4-14
keep reset_soft() struct member syntax 11-37 list of odd integers
keep soft generating 11-16
struct member syntax 11-31 list of unit-type field definition syntax 5-16
keep soft gen before list of unit-type is instance field definition syntax
struct member syntax 11-41 5-15
keep soft select list with key 4-17
e Language Reference Index-17
Index

list(key) of <type> definition 4-17 getting size of 23-59


list.list-method() pseudo-method calling syntax getting specific items 23-36, 23-37, 23-45,
2-86 23-47, 23-67, 23-68, 23-72, 23-74
list[size] definition 11-12 getting specific items by key 23-92, 23-95
list[size] examples 4-16 getting sublists 23-39
lists hash keys 3-14
add all items 23-84 indexes 3-13
adding items. See inserting items 23-3 initializing 11-12, 11-14, 11-15, 22-28,
and all items 23-78 23-23
assigning 3-13, 3-24 inserting
average of all items 23-79 items 23-3, 23-7, 23-15, 23-20, 23-21
of bits lists 23-5, 23-9, 23-16
reading from files 24-102 iterations, maximum allowed 11-26
writing to files 24-105 keyed 3-14, 23-91
checking restrictions 23-98
for index 23-33 of lists 3-13
for items 23-40, 23-44 logic operations for 23-77
for key 23-97 mathematical functions 23-77
permutations 23-42 mathematical operators 23-77
checking for items in 2-62 methods. See pseudo-methods
concatenating 2-77 modifying 23-3
constraining 11-11 all items 23-29
example of 11-22 multiple, constraining 11-15
constraints versus assignments 11-15 multiply all items 23-82
copying 23-31 or all items 23-81
counting items 23-32 packing and unpacking 18-9
CRC pseudo-methods 23-85 passing to methods 7-35
CRC32 function 23-87 restrictions on 7-36
flipping bits 23-90 pseudo-methods 23-2
CRC8 function 23-85 invocation syntax 2-86
defining 3-13, 4-14 removing items. See deleting items
delete multiple items 23-12 resizing 23-23
deleting reversing items 23-58
all items 23-10 selecting items from 3-13
items 23-11, 23-13, 23-18, 23-19 size
repeated items 23-69 changing 23-23
deleting a range of items 23-12 constraining 11-12
fields 4-14 constraints for permutations 23-43
getting contents of 23-35 default maximum 11-12
generation order 11-2 initializing 11-12
getting maximum values 23-48, 23-50, maximum number of iterations 11-26
23-51 sorting
getting minimum values 23-53, 23-55, 23-56 by expression value 23-61

Index-18 e Language Reference


Index

by field value 23-62 names 20-5


specifying a field 23-35 undefining 20-8
splitting 23-64 overview 2-12
of structs precedence 19-5, 19-13
constraining 11-15 replacement 19-1
iterations of fields 11-26 replacement terms, maximum number
sublist pseudo-methods 23-71 allowed 19-6, 19-13
unpacking data into 11-12 substitution 20-5
unpacking into scalar expressions 18-6 undefining 20-8
literal characters 2-9 mathematical functions
literals list pseudo-methods 23-77
multi-value logic 2-5 max keep soft select option 11-34
load order max() arithmetic routine syntax 24-15
cyclic importing 21-3 max() list pseudo-method syntax 23-48
loading multiple modules 21-2 max_index() list pseudo-method syntax 23-50
local variables MAX_INT 2-8
in implication constraints example 11-22 MAX_UINT 2-8
in keep for each constraints 11-28 max_value() list pseudo-method syntax 23-51
locker predefined struct 22-65 maximum value routine 24-15
locker struct 22-54, 22-66 me implicit variable 2-31
locks not released after rerun() 22-56 in gen-item expression 11-53
versus semaphore struct 22-56 memory
locking shared resources considerations
dead locks 22-76 and keep is_all_iterations() 11-26
logarithms NC Verilog 17-25
base 10 24-20 NC Verilog -nonmempack option 17-25
base 2 24-19 Verilog 17-24
loops 9-7 memory management
breaking execution of 9-20 on-the-fly garbage collection 24-139
continuing to next loop iteration 9-21 method @event is struct member syntax 7-8
for (C-style) 9-15 method [@event] is also|first|only|inline only
for each file matching 9-19 struct member syntax 7-12
for each in 9-11 method [@event] is undefined|empty struct
for each line in file 9-17 member syntax 7-19
for from to 9-14 method is inline struct member syntax 7-5
overview 2-18 method is struct member syntax 7-5
repeat until 9-9 method name, finding 22-49
while 9-7 method name, returning on DUT error 10-6
method() action or expression syntax 7-27
M methods
abstract 7-19
M (mega) multiplier 2-4 restrictions on 7-20
macros declaring
advanced replacement 19-10
e Language Reference Index-19
Index

empty option 7-19 passing commands from e 17-64


inline option 7-5 module in source, finding 22-47
regular 7-5 module names
undefined option 7-19 patch.e 2-10
defined 7-1 test.e 2-10
end_group() 16-73 modules
end_instance() 16-72 definition of 2-2
end_item() 16-71 hierarchy 2-24
extending importing 21-1
also option 7-12, 7-14 line number in, finding 22-47
first option 7-12, 7-15 loading 21-2
inline only option 7-12 See also files
only option 7-12 multiple lists, constraining 11-15
extension rules 7-2 example of 11-22
invoking, overview 2-20 multi-value logic
keep is_all_iterations() 11-25 literals 2-5
parameters, maximum number allowed 7-3 logic comparison operators 2-58
parameters, variable 7-3 x and z transitions 13-43
passing parameters multi-value logic (MVL) 6-9
scalar 7-34, 7-35 predefined methods 6-70
regular MVL
calling 7-27, 7-29 logic comparison operators 2-58
returning from 7-30 x and z transitions 13-43
restrictions on 7-3 MVL literals 2-5
scan_bucket() 16-70 mvl type 6-9
scan_cover() 16-64
start_group() 16-66 N
start_instance() 16-67
start_item() 16-68 name
starting 22-13, 22-39 cross coverage item option 16-32
stopping simulation with 17-65 transition coverage item option 16-43
struct members 4-3 name macros
in struct subtypes 4-26 definition 20-5
See also TCMs undefining 20-8
min keep soft select option 11-34 with #ifdef, #ifndef 20-2
min() arithmetic routine syntax 24-13 name resolution 2-33
min() list pseudo-method syntax 23-53 names
min_index() list pseudo-method syntax 23-55 resolving
MIN_INT 2-8 with path 2-33
min_value() list pseudo-method syntax 23-56 without path 2-34
minimum value routine 24-13 NC Verilog memories 17-25
mode option, vhdl driver statement 17-31 nesting constraints 11-27
ModelSim net option, verilog variable statement 17-17

Index-20 e Language Reference


Index

net or wire option, verilog variable statement O


17-17
nets o octal number symbol 2-5
releasing 17-55 objects. See structs
new ... with struct allocation operator syntax 2-90 octal integers 2-4
new struct allocation operator syntax 2-90 odd value routine 24-17
new_temp_file() file routine syntax 24-127 odd() arithmetic routine syntax 24-17
new-line character 2-8 on event struct member
nibble data type, definition of 3-2 syntax 14-1
no_collect on struct member 4-3
coverage group option 16-3 only method extension option 7-12
coverage item option 16-10 on-the-fly generation 11-1, 11-56
no_trace coverage item option 16-10 op= assignment action syntax 8-6
non-enforceable expressions 11-7 open() file routine syntax 24-98
nonterminal types operating system commands
action 19-3 collecting results of 24-86, 24-87
block 19-3 executing 24-82, 24-83, 24-84
command 19-3 retrieving process ID 24-90
expression 19-3 operator precedence
file 19-3 non-temporal operators 2-35
num 19-3 operators
statement 19-3 &&, || lazy evaluation 2-37
struct member 19-3 (bits width-exp) size specification 2-84
type 19-3 (byte width-exp) size specification 2-84
not temporal expression syntax 13-13 . (period) field selection 2-93
now Boolean event check operator syntax 2-49 = See = assignment action, op= assignment
NULL action
initial value of structs or lists 22-28 ? conditional evaluation 2-96
packing option of pack() 18-27 @n 17-61
packing option of unpack() 18-32 @x 17-61
predefined constant 2-8 @z 17-61
numbers [ .. ] list slice 2-75
base representations 2-5 [ :] bit slice 2-70
numeric data, assigning 3-21 [] list index 2-69
numeric expressions [range, ...] range modifier 2-83
context inheritance 3-25 {... , ...} bit concatenation 2-79
context-dependent 3-24 {... ; ...} list concatenation 2-77
context-independent 3-24 as_a() type cast 3-39
numeric operations is a 2-88
data conversion 3-27 is not a 2-88
precision rules 3-24 new struct allocation 2-90
sign extension 3-27 or
in compound constraint Boolean expression
11-50
e Language Reference Index-21
Index

of all list items 23-81 18-42


temporal expression syntax 13-19 packing.high 18-15, 18-27, 18-31,
or_all() list pseudo-method syntax 23-81 18-38, 18-42
order constraints, defined 11-1 packing.high_big_endian 18-16, 18-38,
OS. See operating system 18-42
others keep soft select option 11-34 packing.low 18-13, 18-27, 18-31,
out() output routine syntax 24-62 18-38, 18-42
outf() output routine syntax 24-63 packing.low_big_endian 18-14, 18-38,
output 18-42
displaying 24-62 packing.network 18-17
formatted 24-63 order, default 18-3
output_from() OS routine syntax 24-86 pack() 18-27
output_from_check() OS routine syntax 24-87 pack_options struct 18-18
outputf() output routine formats 24-65 scalar expressions 18-6
simple example of 18-2
P strings 18-7
structs 18-8
pack() pseudo-method syntax 18-27 pack_options instances 18-12
pack_options swap() 18-36
instances 18-12 and type conversion 18-1
struct 18-18 unpack() 18-31
final_reorder 18-22 packing predefined struct 2-25
reverse_fields 18-19 packing.global_default 18-18, 18-38, 18-42
reverse_list_items 18-20 packing.high 18-15, 18-27, 18-31, 18-38, 18-42
scalar_reorder 18-20 packing.high_big_endian 18-16, 18-38, 18-42
package access modifier 26-4 packing.low 18-13, 18-27, 18-31, 18-38, 18-42
package option, vhdl function statement 17-36 and implicit packing and unpacking 18-25
package option, vhdl procedure statement 17-40 packing.low_big_endian 18-14, 18-38, 18-42
package package-name statement 26-1 packing.network 18-17
package type-declaration statement 26-2 parallel execution of action blocks 15-6, 15-8
packing parameters
advanced techniques for 18-12 compound, passing 7-35
basic techniques for 18-2 restrictions on 7-36
bit slice operator 18-24 scalar, passing 7-34
customizing for struct 18-23 parity
debugging 18-25 calculating in e 24-25
defined 18-1 parsing elements
do_pack() 18-23, 18-38 () 19-4
do_unpack() 18-23, 18-42 [] 19-4
implicit 18-25 | 19-4
lists 18-9 action 19-3
options any 19-4
customizing 18-18 block 19-4
packing.global_default 18-18, 18-38,
Index-22 e Language Reference
Index

command 19-3 attributes 6-38


exp 19-4 buffer_size() 6-47
file 19-4 declared_range() 6-48
name 19-4 delayed() 6-49
num 19-4 driver() 6-50
statement 19-3 driver_delayed() 6-51
struct_member 19-4 edge() 6-53
Type 19-4 for all simulators 6-38
pass keep soft select option 11-34 for HDL simulators 6-40
passing HDL paths 6-54
by reference 7-34, 7-35 pack_options() 6-56
restrictions on 7-36 pass_by_pointer() 6-57
by value 7-34 verilog_drive() 6-58
pathnames. See paths verilog_drive_hold() 6-59
paths verilog_forcible() 6-59
it implicit variable 2-28 verilog_strobe() 6-60
paths to fields or structs 2-27 verilog_wire() 6-61
per instance coverage 16-15 vhdl_delay_model() 6-62
sample reports 16-28 vhdl_disconnect_value() 6-63
per_instance coverage item option 16-9 vhdl_initial_value() 6-52
performance considerations binding 6-43
and the inline option 7-7 binding rules 6-43
and keep is_all_iterations() 11-26 buffer
and value() 11-48 defining 6-21, 6-22
permutation of list 23-42 FIFO queue 6-66, 6-67
physical fields 4-11, 4-12 queue checking 6-68, 6-69
packing 18-8, 18-38 reading 6-65
unpacking 18-8, 18-43 writing 6-67
pointers converting bits to MVL 6-96
created by assignment 3-20 converting ints to MVL 6-94
external_pointer type 3-16 converting MVL lists to 4-value logic 6-98
pop() list pseudo-method syntax 23-18 converting MVL to 4-value logic 6-97
pop0() list pseudo-method syntax 23-19 converting MVL to bits 6-95
ports converting MVL to ints 6-92
$ access operator converting MVL to string 6-91
event ports 6-17 converting strings to 4-value logic 6-99
simple ports 6-7 converting strings to MVL 6-90
abstract types creating instances of 6-3
any_buffer_port 6-26 dangling 6-43
any_event_port 6-26 disconnected 6-43
any_simple_port 6-26 elaboration and checking 6-43
advantages of using 6-2 empty binding 6-43
associating with simulated objects 6-54 event

e Language Reference Index-23


Index

defining 6-23 defined 6-2


event ports post_generate() predefined method syntax 11-61
accessing values 6-28 power routine 24-21
examples pre_generate() predefined method
buffer ports 6-5, 6-16 calling gen action 11-57
external simple ports 6-13 syntax 11-59
simple ports 6-12 precision rules
generation of 6-64 example application 3-27
has unknown (U) 6-88 for numeric operations 3-24
has X 6-86 predefined data types
has Z 6-87 See data types
in bidirectional constraints 6-64 predefined events 12-10
initialization of 6-64 and Specman ticks 12-14
port type, defined 6-3 predefined macros
queue sizes 6-47 Specman Elite version number 20-10
reading MVL as 4-value logic 6-79 predefined methods
reading MVL data 6-72 agent() 5-25
reading MVL list as 4-value logic 6-80 bits_to_mvl() 6-96
reading MVL lists 6-75 check() 22-19
reading MVL strings 6-77 copy() 22-20
reading MVL strings as 4-value logic 6-81 covers.get_contributing_runs() 22-89
references 6-26 covers.get_unique_buckets() 22-90
rendezvous-style protocol 6-16 covers.include_tests() 22-82
simple covers.set_at_least() 22-85
defining 6-19 covers.set_cover() 22-86
simple ports covers.set_weight() 22-83
accessing bit values 6-29 do_pack() 18-38
accessing values 6-28 do_print() 22-22
forcing bit values 6-34, 6-36 do_unpack() 18-42
predefined methods 6-86 down() 22-57
predefined MVL methods 6-70 extract() 22-24
releasing forced values 6-35 finalize 22-26
temporal expressions using @sim 6-11 for units
tracing activity 6-102 e_path() 5-23
undefined binding 6-43 full_hdl_path() 5-22
writing MVL data 6-71 get_parent_unit() 5-27
writing MVL lists 6-74 hdl_path() 5-19
writing MVL strings 6-76 force_mvl_to_bit_slice() 6-84
ports, e-to-e get() 6-65
defined 6-2 get_enclosing_unit 5-32
ports, external get_max_value() 22-64
defined 6-2 get_mvl() 6-72
ports, internal get_mvl_list() 6-75

Index-24 e Language Reference


Index

get_mvl_string() 6-77 scheduler.get_current_handle() 22-70


get_mvl4() 6-79 scheduler.get_handles_by_name() 22-72
get_mvl4()_list 6-80 scheduler.get_handles_by_type() 22-74
get_mvl4()_string 6-81 scheduler.terminate_branch() 22-78
get_unit 5-29 scheduler.terminate_thread() 22-80
get_value() 22-62 set_max_value() 22-64
global.check_test() 22-7 set_unit 5-36
global.extract_test() 22-6 set_value() 22-62
global.finalize_test() 22-8 simulator.get_define() 22-52
global.generate_test() 22-5 string_to_mvl() 6-90
global.run_test() 22-6 string_to_mvl4() 6-99
global.setup_test() 22-4 for structs 22-18
global.start_test() 22-5 sys.check 22-16
global.stop_run() 17-65 sys.extract 22-15
has_unknown() 6-88 sys.finalize() 22-17
has_x() 6-86 sys.generate() 22-8
has_z() 6-87 sys.init() 22-9
init() 22-27 sys.run() 22-13
instance names 2-28 sys.setup() 22-12
int_to_mvl() 6-94 sys.wave_setup() 22-11
is_empty() 6-68 try_down() 22-61
is_full() 6-69 try_enclosing_unit 5-35
list.copy() 23-31 try_up() 22-61
locker.free() 22-65 up() 22-57
locker.lock() 22-65 visualize() 22-32
locker.release() 22-65 predefined pack_options instances 18-12
mvl_list_to_mvl4_list() 6-98 predefined routines
mvl_to_bits() 6-95 abs() 24-16
mvl_to_int() 6-92 append() 24-29
mvl_to_mvl4() 6-97 appendf() 24-31
mvl_to_string() 6-91 bin() 24-32
overview of 22-1 data_time() 24-89
post_generate() 11-61 dec() 24-34
pre_generate() 11-59 deep_compare() 24-5
print_line() 22-30 deep_compare_physical() 24-11
put() 6-67 deep_copy() 24-2
put_mvl() 6-71 div_round_up() 24-23
put_mvl_list() 6-74 do_otf_gc() 24-139
put_mvl_string() 6-76 even() 24-18
put_mvl_to_bit_slice() 6-83 files.add_file_type() 24-93
quit() 22-36 files.close() 24-95
rerun() 22-40 files.file_age() 24-107
run() 22-39 files.file_append() 24-109

e Language Reference Index-25


Index

files.file_copy() 24-110 read_config() 24-76


files.file_delete() 24-112 reductions 24-25
files.file_exists() 24-113 set_check() 10-11
files.file_extension() 24-114 set_config() 24-67
files.file_is_dir() 24-116 set_config_max() 5-37
files.file_is_link() 24-117 set_retain_state() 24-78
files.file_is_readable() 24-118 simulator_command() 17-64
files.file_is_regular() 24-120 spawn() 24-82
files.file_is_temp() 24-121 spawn_check() 24-83
files.file_is_text() 24-123 specman() 24-80
files.file_rename() 24-124 str_chop() 24-38
files.file_size() 24-125 str_empty() 24-39
files.flush() 24-97 str_exactly() 24-40
files.new_temp_file() 24-127 str_expand_dots() 24-41
files.open() 24-98 str_insensitive() 24-43
files.read() 24-100 str_join() 24-44
files.read_ascii_struct() 24-130 str_len() 24-45
files.read_binary_struct() 24-132 str_lower() 24-46
files.read_lob() 24-102 str_match() 24-47
files.write() 24-103 str_pad() 24-50
files.write_ascii_struct() 24-134 str_replace() 24-51
files.write_binary_struct() 24-137 str_split() 24-54
files.write_lob() 24-105 str_split_all() 24-56
files.write_string_list() 24-128 str_sub() 24-57
files.writef) 22-50 str_upper() 24-58
get_all_units() 5-39 system() 24-84
get_config() 24-72 to_string() 24-59
get_retain_state() 24-79 write_config() 24-74
get_symbol() 24-88 predefined structs
getpid() 24-90 dut_error_struct 10-5
hex() 24-35 global 22-2
ilog10() 24-20 locker 22-65
ilog2() 24-19 overview 2-24
ipow() 24-21 scheduler 22-69
isqrt() 24-22 simulator 22-52
max() 24-15 preprocessor directives, defining 20-1
min() 24-13 prev variable
odd() 24-17 in coverage group definitions 16-54
out() 24-62 in coverage group extensions 16-55
outf() 24-63 in coverage item definitions 16-60
output_from() 24-86 prev, in keep for each constraints 11-28
output_from_check() 24-87 prev__item-name transition coverage item 16-44
quote 24-36 print actions, overview 2-22

Index-26 e Language Reference


Index

print_line() predefined method syntax 22-30 list.first() 23-36


printing list.first_index() 23-37
struct information 22-22, 22-30 list.get_indices() 23-39
private access modifier 26-4 list.has() 23-40
private access modifier, for struct member 26-4 list.insert(index, item) 23-15
product of all list items 23-82 list.insert(index, list) 23-16
product() list pseudo-method syntax 23-82 list.is_a_permutation() 23-42
programs, hierarchical structure of 2-24 list.is_empty() 23-44
protected access modifier 26-4 list.key() 23-92
protected struct-member syntax 26-4 list.key_exists() 23-97
pseudo-methods 23-1 list.key_index() 23-95
bitwise_and() 24-25 list.last() 23-45
bitwise_nand() 24-25 list.last_index() 23-47
bitwise_nor() 24-25 list.list-method() invocation 2-86
bitwise_or() 24-25 list.max() 23-48
bitwise_xnor() 24-25 list.max_index() 23-50
bitwise_xor() 24-25 list.max_value() 23-51
declared_type() 22-45 list.min() 23-53
defined 22-44 list.min_index() 23-55
field() 22-46 list.min_value() 23-56
from_specman_scale() 22-99 list.or_all() 23-81
is_a_permutation() list.pop() 23-18
and constraining lists 11-15, 11-22 list.pop0() 23-19
keep is_all_iterations() list.product() 23-82
constraining lists of structs 11-15 list.push() 23-20
list.add(item) 23-3 list.push0() 23-21
list.add(list) 23-5 list.resize() 23-23
list.add0(item) 23-7 list.reverse() 23-58
list.add0(list) 23-9 list.size() 23-59
list.all() 23-72 list.sort() 23-61
list.all_indices() 23-74 list.split() 23-64
list.and_all() 23-78 list.sum() 23-84
list.apply() 23-29 list.top() 23-67
list.average() 23-79 list.top0() 23-68
list.clear() 23-10 list.uniq() 23-69
list.count() 23-32 list.unique() 23-69
list.crc_32() 23-87 pack() 18-27
list.crc_32_flip() 23-90 reset_soft() 11-37
list.crc_8() 23-85 sort_by_field() 23-62
list.delete() 23-11 source_location() 22-47
list.exists() 23-33 source_method() 22-49
list.fast_delete() 23-13 swap() 18-36
list.field 23-35 to_specman_scale() 22-101

e Language Reference Index-27


Index

type() 22-45 without using value 7-29


unpack() 18-31 declaring 7-5
unsafe() 22-47 abstract 7-19
using 23-2 extending 7-12
value() 11-48 passing parameters
pseudo-variables for string matching 2-66 compound 7-35
push() list pseudo-method syntax 23-20 restrictions on 7-36
push0() list pseudo-method syntax 23-21 scalar 7-34
put() method sampling event 6-67 restrictions for 7-3
returning from 7-30
Q See also methods
release action syntax 17-55
queues rendezvous semaphore 22-54
implementing with buffer ports 6-21 repeat until action syntax 9-9
queues, emulating with top0() and pop0() 23-68 replacement macro definition 19-1
quit event 12-12 rerun() predefined method
quit() predefined method syntax 22-40
executed by global.stop_run() 17-65 reserved words, alphabetical list of 2-10
syntax 22-36 resize() list pseudo-method syntax 23-23
quote characters 2-9 resolve_cycles configuration option 11-40
quote() string routine syntax 24-36 resource sharing 22-54
quotes, adding to strings 24-36 result implicit variable 2-32
using to return a method 7-32
R retain state mode
races, using delayed assignment to avoid 8-9 displaying 24-79
radix setting 24-78
coverage group option 16-3 retain_forced_value_after_release() 17-55
coverage item option 16-14 return action
random values, generating 11-56 in extended methods 7-14
range specification 2-63, 2-83 syntax 7-30
ranges reusability, by extending structs 4-2
coverage item option 16-11 reverse option, for each in loop 9-11
specifying 2-83 reverse() list pseudo-method syntax 23-58
read() file routine syntax 24-100 reverse_fields 18-19
read_ascii_struct() file routine syntax 24-130 reverse_fields pack option 18-19
read_binary_struct() file routine syntax 24-132 reverse_list_items 18-20
read_config() configuration routine syntax 24-76 reverse_list_items pack option 18-20
read_lob() file routine syntax 24-102 rise temporal expression syntax 13-41
reduction operators 24-25 routine action syntax 24-140
reference parameters routines
casting 3-29 calling 24-140
regular methods parameters 24-141
calling 7-27 See also predefined routines

Index-28 e Language Reference


Index

run command scheduler.terminate_thread() predefined method


global methods called by 22-6 syntax 22-80
run() predefined method scope
executed by global.run_test() 22-6 of events 12-3
syntax 22-39 of variables 2-35
run_test() predefined method syntax 22-6 seed
run-time errors value of, displaying 22-98
caused by constraint cycle 11-6 selecting bits 2-70
caused by non-enforceable expressions 11-7 semaphore methods 22-54
semaphore struct
S how to use 22-56
versus locker struct 22-56
sampling events 12-8, 13-37 semaphores
cycle expression 13-38 checking available resources 22-62
Sampling Events Overview 12-8 checking maximum resources 22-64
scalar locking and freeing resources 22-65
expressions, packing and unpacking 18-6 setting maximum resources 22-64
parameters, passing 7-34 setting resources 22-62
subtypes 2-83 synchronizing TCMs 22-57, 22-61
defining 3-34 semicolon temporal sequence operator 13-21
types sequences, temporal 13-8
accessing all values of 3-52 session predefined struct 2-25
specifying ranges for 3-34 session struct
scalar modifiers 3-3 events field 12-2
scalar types session.call event 12-13
accessing all values 3-52 session.check event 12-13
scalar_reorder 18-20 session.check_ok predefined field 2-25
scalars session.dut_error event 12-14
enumerated, extending 3-37 session.end_of_test event 12-10, 12-12, 17-65
sized, defining 3-35 session.events coverage item 2-26
specifying sizes 2-84 session.line event 12-13
scan_bucket() predefined method syntax 16-70 session.output event 12-13
scan_cover() predefined method syntax 16-64 session.return event 12-13
scheduler predefined struct 2-25, 22-69 session.sim_read event 12-13
scheduler.get_current_handle() predefined session.sim_write event 12-13
method syntax 22-70 session.specman_memory predefined field 2-25
scheduler.get_handles_by_name() predefined session.start_of_test event 12-10, 12-11
method syntax 22-72 session.system_time predefined field 2-25
scheduler.get_handles_by_type() predefined session.tcm_call event 12-13
method syntax 22-74 session.tcm_end event 12-13
scheduler.kill() predefined method syntax 22-76 session.tcm_return event 12-13
scheduler.terminate_branch() predefined method session.tcm_start event 12-13
syntax 22-78 session.tcm_state event 12-13

e Language Reference Index-29


Index

session.tcm_wait event 12-13 size() list pseudo-method syntax 23-59


session.user_time predefined field 2-25 sized integers
set_assign_after_force_compatible() 17-55 defining 3-35
set_check() predefined routine syntax 10-11 sized numbers 2-5
set_config() configuration routine syntax 24-67 radix specification 2-5
set_config_max() predefined routine syntax 5-37 width 2-5
set_retain_state() predefined routine syntax 24-78 soft
set_unit() predefined method syntax 5-36 not allowed in compound constraint Boolean
setup command expression 11-50
global methods called by 22-4 used with gen action 11-57
setup_test() predefined method syntax 22-4 soft constraints
shallow copy, of expression 22-20 and compound constraint Boolean
shared resources 22-54 expressions 11-31
show cover command 16-36 defined 11-1
Show Coverage GUI 16-36 distribution of values, constraining 11-33
show event coverage collection 16-6 keep reset_soft() 11-37
show gen command keep soft 11-31
solving constraint contradictions with 11-6 keep soft gen before 11-41
solving value distribution errors with 11-2 keep soft select 11-33
show_sub_holes cover configuration option order of evaluation 11-9
example 24-70 preventing from being skipped 11-40
sign, changing 2-51 sort() list pseudo-method syntax 23-61
simple ports sort_by_field() list pseudo-method syntax 23-62
defining 6-19 source files
forcing a bit slice 6-84 line number in module, finding 22-47
writing a bit slice 6-83 module in, finding 22-47
simulation delta cycles source_location() pseudo-method syntax 22-47
and Specman ticks 12-14 source_method() pseudo-method syntax 22-49
simulation time slots sparse memory example 4-20
and Specman ticks 12-14 spawn() OS routine syntax 24-82
simulation, stopping 17-65 spawn_check() OS command routine 24-83
simulator // specman deferred expression syntax 17-62
callbacks 12-9 Specman Elite
definition of 6-2 time 2-24
simulator predefined struct 2-25 specman() routine syntax 24-80
simulator struct 22-52 SPECMAN_VERSION_n_n_n predefined macro
simulator.get_define() predefined method syntax 20-10
22-52 split() list pseudo-method syntax 23-64
simulator_command() predefined routine syntax start command
17-64 global methods called by 22-4, 22-5
simulators start tcm() action syntax 7-25
glitch handling 13-44 start_group() predefined method syntax 16-66
size of lists, constraining 11-12 start_instance() predefined method syntax 16-67

Index-30 e Language Reference


Index

start_item() predefined method syntax 16-68 verilog import 17-7


start_test() predefined method syntax 22-5 verilog task 17-11
starting generation 11-1 verilog time 17-14
state => state transition syntax 25-5 verilog variable memory 17-24
state action block syntax 25-7 verilog variable reg 17-16
state machine action syntax 25-2 verilog variable wire 17-16
state machines vhdl code 17-27
defining 25-1, 25-2 vhdl function 17-35
example 25-9 vhdl procedure 17-39
initializing 25-10 vhdl time 17-48
nested 25-13 states. See state machines
parallel 25-13 step option for the for from to loop 9-14
state holder expression 25-3 stop_run() predefined method syntax 17-65
terminating 25-3, 25-11 str_chop() string routine syntax 24-38
transition block 25-3 str_empty() string routine syntax 24-39
transitions 25-12 str_exactly() string routine syntax 24-40
any-state-to-state 25-6 str_expand_dots() string routine syntax 24-41
state-to-state 25-5 str_insensitive() string routine syntax 24-43
state transition syntax str_join() string routine syntax 24-44
*=> state 25-6 str_len() string routine syntax 24-45
state => state 25-5 str_lower() string routine syntax 24-46
statements str_match() string routine syntax 24-47
#define 20-5 str_pad() string routine syntax 24-50
#ifdef 20-1 str_replace() string routine syntax 24-51
#ifndef 20-1 str_split() string routine syntax 24-54
define as 19-1 str_split_all() string routine syntax 24-56
define as computed 19-10 str_sub() string routine syntax 24-57
example of user-defined 19-14 str_upper() string routine syntax 24-58
extend type 3-37 strings
import 21-1 accessing substrings 3-15
order of 2-13 appending 24-29
special violation case 21-7 binary representation 24-32
overview 2-13 decimal representation 24-34
package package-name 26-1 formatted 24-31
package type-declaration 26-2 hexadecimal representation 24-35
struct 4-2 lists of 24-44
type enumerated scalar 3-31 assigning 3-23
type scalar subtype 3-34 case
type sized scalar 3-35 changing to lowercase 24-46
undef 20-8 changing to uppercase 24-58
unit 5-6 case sensitivity, changing 24-43
verilog code 17-2 changing length of 24-40
verilog function 17-5 checking if empty 24-39

e Language Reference Index-31


Index

concatenating 24-29 fields 4-3, 4-11


binary representation 24-32 keep 11-21
decimal representation 24-34 keep all of 11-24
formatted 24-31 keep for each 11-27
hexadecimal representation 24-35 keep gen before 11-39
lists of 24-44 keep gen_before_subtypes() 11-43
converting expressions to 24-59 keep reset_gen_before_subtypes() 11-46
escape sequences in 2-8 keep reset_soft() 11-37
expanding hidden characters 24-41 keep soft 11-31
extracting substrings 24-57 keep soft gen before 11-41
length, getting 24-45 keep soft select 11-33
matching 2-60, 2-65, 24-47 keyed lists 4-17
* wild card 2-66 lists 4-14
... sequence 2-66 method @event is 7-8
AWK-style regular expressions 2-67 method [@event] is also|first|only|inline only
blanks 2-66 7-12
longest match 2-68 method [@event] is undefined|empty 7-19
meta-characters 2-66 method is [inline] 7-5
Perl-style regular expressions 2-67 methods 4-3
shortest match 2-68 on 4-3, 14-1
operations 24-28 overview 2-15
packing and unpacking 18-7 package access modifier 26-4
padding with blanks 24-50 private access modifier 26-4
patterns 2-66 protected access modifier 26-4
quoting 24-36 temporal 14-1
replacing substrings 24-51 types 4-3
splitting 24-54, 24-56 when 4-3, 4-22
truncating 24-38 struct name, returning on DUT error 10-6
uncompressing 24-41 struct reference, returning on DUT error 10-6
writing to files 24-103, 24-128 struct statement syntax 4-2
strobe option, verilog variable statement 17-17 struct.quit event 12-10, 12-12
strobe, verilog variable statement 17-17 structs
struct IDs allocating 2-90
retrieving 24-59 assigning 3-22
struct members constraining 11-10
assume 14-3 covers 22-81
attribute 4-28 creating 2-90
constraints 4-3 fields
cover 16-1 defining 4-11
cover ... using also ... is also 16-53 generation order of 11-2
coverage groups 4-3 restricting generated values for 11-21
events 4-3, 12-4 file descriptor 24-92
expect 4-3, 14-3 generating with generate_test() 22-5

Index-32 e Language Reference


Index

hierarchy 2-24 sum, of all list items 23-84


initializing 22-27 swap() pseudo-method syntax 18-36
instances, deactivating 22-36 sync action
lists of syntax 15-1
constraining 11-15 synchronizing TCMs 15-1, 15-5
iterations of the fields 11-26 syntactic elements, overview 2-12
members. See struct members syntax hierarchy 2-13
pack_options 18-18 syntax notation for e constructs 1-2
packing and unpacking 18-8 sys predefined struct 2-24
passing to methods 7-35 sys, HDL path of 5-4
restrictions on 7-36 sys.any event 12-9, 12-10, 12-11
predefined and Specman tick 12-14
global 22-2 sys.check() predefined methods syntax 22-16
scheduler 22-69 sys.extract() predefined methods syntax 22-15
simulator 22-52 sys.finalize() predefined method syntax 22-17
predefined methods for 22-18 sys.generate() predefined method syntax 22-8
printing information about 22-22 sys.init() predefined method syntax 22-9
reading from files 24-130 sys.new_time event 12-10
referencing 2-27, 2-31 and Specman tick 12-14
running check() on 22-7 sys.run() predefined method
subtypes syntax 22-13
creating 4-22 sys.setup() predefined method syntax 22-12
extending 4-9, 4-39 sys.tick_end event 12-10, 12-11
like inheritance 4-4, 4-35 and Specman tick 12-14
multiple 4-38 sys.tick_start event 12-10, 12-11
when inheritance 4-3 and Specman tick 12-14
when subtypes sys.time field 2-24
coverage 4-25 sys.wave_setup() predefined method syntax
extending 4-25 22-11
method extension 4-26 system calls 24-82, 24-83, 24-84, 24-86, 24-87
writing to files 24-130 system variables ($0 to $27) 2-67
sublists, creating 23-71 system() OS routine syntax 24-84
subscripting lists 2-69
substructs, generation order of 11-2 T
subtypes
assigning 3-23 tab characters 2-8
creating 4-21 tcm() action or expression syntax 7-23
definition 4-23 TCMs
specifying 4-3 calling 7-23
with tick 3-9 controlling execution of 22-61, 22-62, 22-64
with when 3-11 declaring 7-8
See also struct subtypes abstract 7-19
sum() list pseudo-method syntax 23-84 defined 7-9
extending 7-12
e Language Reference Index-33
Index

extension rules 7-2 exec 13-48


interrupting 15-2, 15-5 in expect constructs 13-7
killing 22-40 fail 13-14
locking fall 13-41
dead locks 22-76 not 13-13
parallel actions 15-6, 15-8 or 13-19
parameters, maximum number of 7-10 rise 13-41
passing parameters sample forms 13-7
compound 7-35 sampling events 12-8
restrictions on 7-36 in sync actions 13-7
scalar 7-34 transition 13-41
restrictions on 7-10 true 13-40
returning from 7-30 in Verilog objects 13-5
sampling events for 12-9 in wait actions 13-7
sharing resources 22-61, 22-62, 22-64 first match expression 13-26
sharing resources, 22-57 operators 13-12
starting 7-25, 22-13, 22-39 precedence of 13-12
stopping simulation with 17-65 sequences 13-8
synchronizing 12-7, 15-1, 15-5 struct members
threads assume 14-3
defined 22-69 expect 14-3
handles, getting 22-70, 22-72, 22-74 on 14-1
terminating 22-36, 22-76, 22-78, 22-80 true match expression 13-28
temporal yield operator 13-7
behavioral rules 13-9 expressions
defining 14-3 in events 12-5
expressions temporal expressions
=> yield 13-30 errors 13-10
@ sampling operator 13-37 translation failures 13-10
@ unary event 13-35 terminate_branch() predefined method syntax
[..] first match repeat operator 13-26 22-78
[] (repetition) 13-24 terminate_thread() predefined method syntax
[] fixed repeat operator 13-24 22-80
{;} (sequence) 13-21 test
~[..] true match repeat operator 13-28 command
and 13-16 global methods called by 22-4, 22-5,
change 13-41 22-6, 22-7, 22-8
consume 13-45 predefined methods called by 22-18
context of 13-1 filename for, displaying 22-97
cycle 13-38 phases
delay 13-34 diagram of 22-3
detach 13-8, 13-31 and global methods 22-2
eventually 13-23 seed, displaying 22-98

Index-34 e Language Reference


Index

setup 22-4 time scale, setting 17-14


testing time scale, setting for VHDL 17-48
checking data for 22-19 time-consuming actions, overview 2-20
DUT data, collecting 22-6 time-consuming methods
ending 17-65 See also TCMs
finalizing test data 22-8 to_specman_scale() pseudo-method syntax
preparing for 22-5 22-101
tests to_string() string routine syntax 24-59
selecting 22-82 top module
text name, displaying 22-97
coverage group option 16-3 top() list pseudo-method syntax 23-67
coverage item option 16-10 top0() list pseudo-method syntax 23-68
cross coverage item option 16-32 trace on event 12-13
transition coverage item option 16-43 trace on gen command
text macros solving constraint contradiction errors with
substitution 11-6
Verilog 17-63 transition coverage
Verilog item options 16-43
deferred 17-62 item syntax 16-42
then option for if then else action 9-1 prev__item variable 16-44
threads transition temporal expression 13-41
defined 22-69 transition__item-name coverage syntax 16-45
handles 22-69 transitions
by struct instance 22-72 coverage 16-42
by struct type 22-74 See also state machines transitions
current TCM 22-70 TRANSPORT option, vhdl driver statement
terminating 22-76 17-31
at end of tick 22-36 tri-state
branch of 22-78 logic comparison operators 2-58
immediately 22-80 x and z transitions 13-43
tick x transitions 13-43
notation 3-8 x value 2-58
simulation delta cycle 12-14 z transitions 13-43
Specman Elite time 12-1 z value 2-58
subtype 3-9 true temporal expression syntax 13-40
time try action syntax 10-19
conversion try_enclosing_unit() predefined method syntax
using predefined methods 22-99 5-35
precision 17-14 type casting
units automatic 3-28
Verilog 17-14 between scalars and lists of scalars 3-40
VHDL 17-48 between simple lists and keyed lists 3-45
time data type, definition of 3-2 between strings and scalars or lists of scalars

e Language Reference Index-35


Index

3-42 unit statement syntax 5-6


between structs, struct subtypes, and lists of units
structs 3-44 and structs, methodology recommendations
enumerated types 3-7 5-3
type conversion associating with HDL paths 5-4
between scalars and lists of scalars 3-40 basic concepts 5-1
between simple lists and keyed lists 3-45 displaying instances of a unit 5-39
between strings and scalars or lists of scalars limitations 5-5
3-42 methodology recommendations 5-5
between structs, struct subtypes, and lists of unit-type field definition syntax 5-13
structs 3-44 unit-type is instance field definition syntax 5-11
type enumerated scalar statement syntax 3-31 UNIX environment variables, getting 24-88
type scalar subtype statement syntax 3-34 unlabeled case condition action 9-5
type sized scalar statement syntax 3-35 unpack() pseudo-method syntax 18-31
type statement unpacking
violating import statement order] 21-7 defined 18-1
type() pseudo-method syntax 22-45 implicit 18-25
lists 18-9
U scalar expressions 18-6
simple example of 18-4
uint data type, definition of 3-2 strings 18-7
unbounded integer, and packing 18-28 structs 18-8
unbounded integers 3-4 and type conversion 18-1
undef statement syntax 20-8 See also packing
UNDEF value 2-8 unsafe() pseudo-method syntax 22-47
undefined method declaration option 7-19 unsigned integer
unidirectional constraints 11-4 data type. See uint
and contradiction errors 11-5 unsigned integers
setting with value() 11-48 maximum size 2-8
uniq() list pseudo-method syntax 23-69 unsized numbers 2-4
unique() list pseudo-method syntax 23-69 until option
unit instance tree, definition of 5-1 state machine action 25-3
unit members wait action 15-4
buffer ports 6-21 untyped expression
event ports 6-23 effect of ~ operator on 2-39
simple ports 6-19 untyped expressions 3-17
verilog function 17-5 user-defined
verilog task 17-11 constraints, and generation order 11-2
verilog variable memory 17-24 methods
verilog variable reg | wire 17-16 starting 22-13, 22-39
vhdl driver 17-30 stopping simulation with 17-65
vhdl function 17-35 user-defined methods
vhdl procedure 17-39 instance names 2-28
unit members, types 5-8
Index-36 e Language Reference
Index

using also coverage group extension 16-53 memories


using index option 9-11 accessing 17-25
using keyword specifying 17-24
coverage group options 16-2 objects
coverage item options 16-9, 16-59 accessing 17-17
in temporal expressions 13-5
V registers, specifying 17-16
tasks
value constraints calling from e 17-12
defined 11-1 declaring 17-11
hard, on list items 11-27 text macros
order of evaluation 11-9 importing 17-7
unidirectional 11-4 time resolution 17-14
value() pseudo-method syntax 11-48 wires, specifying 17-16
values verilog code statement syntax 17-2
distribution of Verilog events
constraining 11-33 monitoring from Specman Elite 13-6
in generation 11-2 verilog function statement syntax 17-5
setting procedurally verilog import statement syntax 17-7
after generation 11-61 Verilog literals 2-5
before generation 11-59 Verilog simulator
var action syntax 8-2 interfaces, setting up 17-1
variable parameters for methods 7-3 verilog task statement syntax 17-11
variables Verilog time scale 17-14
declaring 8-2 verilog time statement syntax 17-14
defining 8-2 Verilog timescale 17-14
dynamic 8-2 verilog variable
initializing 8-2 drive option 17-17
names 8-2 drive_hold option 17-17
overview 2-17 forcible option 17-17
scope 2-35, 8-2 net option 17-17
types 8-2 net or wire option 17-17
vcs_pli option, verilog variable statement 17-24 strobe option 17-17
Verilog wire option 17-17
‘defines verilog variable memory statement syntax 17-24
importing 17-7 verilog variable reg statement syntax 17-16
reading 17-7 verilog variable statement
adding code vcs_pli option 17-24
to specman.v file 17-2 verilog variable wire statement 17-16
defines VHDL
getting value of 22-52 code
four-state identity operators 2-58 in stub file 17-27
functions 17-6 functions
declaring 17-5
e Language Reference Index-37
Index

calls to 17-37 warning() action syntax 10-14


declaring 17-35 weight
procedures coverage group option 16-4
calls to 17-42 coverage item option 16-14
declaring 17-39 cross coverage item option 16-34
time resolution 17-48 transition coverage item option 16-45
vhdl code statement syntax 17-27 weighted values
vhdl driver list elements 11-36
delay option 17-31 weighting generated list values 11-36
disconnect_value option 17-31 weighting generated values 11-33
INERTIAL option 17-31 weights, in keep soft select 11-33
initial_value option 17-31 when
mode option 17-31 coverage group option 16-3
TRANSPORT option 17-31 coverage item option syntax 16-10
vhdl driver unit member syntax 17-30 cross coverage item option 16-32
vhdl function determinant 4-33
alias option 17-36 constraining 4-37
declarative_item option 17-37 physical field 4-37
interface option 17-36 inheritance 4-33–4-48
library option 17-36 advantages 4-36
package option 17-36 determinant 4-33
vhdl function statement syntax 17-35 referring to conditional fields 3-11
vhdl procedure struct member
alias option 17-40 syntax 4-22
declarative_item option 17-41 transition coverage item option 16-43
interface option 17-40 when subtypes
library option 17-40 referring to fields in 3-12
package option 17-40 while action syntax 9-7
vhdl procedure statement syntax 17-39 wire option, verilog variable statement 17-17
VHDL signals wires
driving continuously via resolution function releasing 17-55
17-30 with syntax. See new
releasing a force action 17-55 write() file routine syntax 24-103
VHDL simulator write_ascii_struct() file routine syntax 24-134
interface, setting up 17-27 write_binary_struct() file routine syntax 24-137
vhdl time statement syntax 17-48 write_config() configuration routine syntax 24-74
visualization of struct information 22-32 write_lob() file routine syntax 24-105
visualize() predefined method syntax 22-32 write_string_list() file routine syntax 24-128
writef() file routine syntax 22-50
W
wait action
Y
syntax 15-4 yield operator 13-7
WARNING check effect 10-12 See also => yield temporal expression
Index-38 e Language Reference
Index

yield temporal expression sampling event 13-31


yield temporal expression syntax 13-30

e Language Reference Index-39

You might also like