Home > Articles > Software Development & Management

Basic e Concepts

  • Print
  • + Share This
This chapter is from the book

This chapter is from the book

In this chapter we discuss the basic constructs and conventions in e. These conventions and constructs are used throughout the later chapters. These conventions provide the necessary framework for understanding e. This chapter may seem dry, but understanding these concepts is a necessary foundation for the successive chapters.

Chapter Objectives

  • Understand conventions for code segments, comments, white space, numbers, constants, and macros.

  • Describe how to import other e files.

  • Define the data types such as scalar type and subtypes, enumerated scalar type, list type, and string type.

  • Understand syntax hierarchy of statements, struct members, actions, and expressions.

  • Explain the use of simulator variables in e.

3.1 Conventions

e contains a stream of tokens. Tokens can be comments, delimiters, numbers, constants, identifiers, and keywords. e is a case-sensitive language. All keywords are in lowercase.

3.1.1 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 (leftmost), with no other text on that same line (no code and no comments). The example below shows three lines of code that 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.

3.1.2 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...
This is a comment

<'
    import cpu_test_env;
'>

This particular test requires the code that bypasses bug#72 as well as the constraints
graphics/ccc.gif that focus on the immediate instructions. This is a comment
   
   <'
   import bypass_bug72;
   import cpu_test0012;
   '>
   

3.1.3 Numbers

There are two types of numbers, sized and unsized.

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

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

Table 3-1. Representing Unsized Numbers in Expressions

Notation

Legal Characters

Examples

Decimal integer

Any combination of 0-9 possibly preceded by a hyphen - for negative numbers. An underscore (_) can be added anywhere in the number for readability.

12, 55_32, -764

Binary integer

Any combination of 0-1 preceded by 0b. An underscore (_) can be added anywhere in the number for readability.

0b100111, 0b1100_0101

Hexadecimal integer

Any combination of 0-9 and a-f preceded by 0x. An underscore (_) can be added anywhere in the number for readability.

0xff, 0x99_aa_bb_cc

Octal integer

Any combination of 0-7 preceded by 0o. An underscore (_) can be added anywhere in the number for readability.

0o66_123

K (kilo: multiply by 1024)

A decimal integer followed by a K or k. For example, 32K = 32768.

32K, 32k, 128k

M (mega: multiply by 1024*1024)

A decimal integer followed by an M or m. For example, 2m = 2097152.

1m, 4m, 4M

3.1.3.2 Sized Numbers

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

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 it can be specified in one of four radixes, as shown in Table 3-2.

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

3.1.4 Predefined Constants

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

Table 3-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 largest negative 32-bit int (-231)

MAX_UINT

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

3.1.4.1 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 3-4 are allowed.

Table 3-4. Escape Sequences in Strings

Escape Sequence

Meaning

\n

New-line

\t

Tab

\f

Form-feed

\”

Quote

\\

Backslash

\r

Carriage-return

This example shows escape sequences used in strings. Although other constructs are introduced here only for the sake of completeness, please focus only on the string syntax.

<'
extend sys {

    m() is {
        var header: string = //Define a string variable
          "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);
    };
};
'>

The result of running the example above is shown below.

Specman> sys.m()
   Name    Size in Bytes
   ----    -------------
   packet  20
   

3.1.5 Identifiers and Keywords

The following sections describe the legal syntax for identifiers and keywords.

3.1.5.1 Legal e Identifiers

User-defined identifiers 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. Identifiers beginning with an underscore have a special meaning in e and are not recommended for general use. Identifiers beginning with a number are not allowed.

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.

3.1.5.2 e Keywords

The keywords listed in Table 3-5 below are the reserved words of the e language. Some of the terms are keywords only when used together with other terms, such as “key” in “list(key:key)”, “before” in “keep gen x before y”, or “computed” in “define def as computed.

Table 3-5. List of Keywords

all of

all_values

and

as a

as_a

assert

assume

async

attribute

before

bit

bits

bool

break

byte

bytes

c export

case

change

check that

compute

computed

consume

continue

cover

cross

cvl call

cvl callback

cvl method

cycle

default

define

delay

detach

do

down to

dut_error

each

edges

else

emit

event

exec

expect

extend

fail

fall

file

first of

for

force

from

gen

global

hdl pathname

if

#ifdef

#ifndef

in

index

int

is

is a

is also

is c routine

is empty

is first

is inline

is instance

is not a

is not empty

is only

is undefined

item

keep

keeping

key

like

line

list of

matching

me

nand

new

nor

not

not in

now

on

only

or

others

pass

prev_

print

range

ranges

release

repeat

return

reverse

rise

routine

select

session

soft

start

state machine

step

struct

string

sync

sys

that

then

time

to

transition

true

try

type

uint

unit

until

using

var

verilog code

verilog function

verilog import

verilog simulator

verilog task

verilog time

verilog timescale

verilog trace

verilog variable

vhdl code

vhdl driver

vhdl function

vhdl procedure

vhdl driver

vhdl simulator

vhdl time

when

while

with

within

       

3.1.6 Macros

The simplest way to define e macros is with the define statement. An e macro can be defined with or without an initial ` character.

<'
define WORD_WIDTH 16; //Definition of the WORD_WIDTH macro
struct t {
    f: uint (bits: WORD_WIDTH); //Usage of WORD_WIDTH macro
};
'>

You can also import a file with Verilog 'define macros using the keywords verilog import.

macros.v (Verilog defines file)
   `define BASIC_DELAY   2
   `define TRANS_DELAY   `BASIC_DELAY+3
   `define WORD_WIDTH 8
   
   -----------------------------------------------------
   dut_driver.e (e file)
   <'
   verilog import macros.v; //Imports all definitions from
   //macros.v file
   //Macros imported from Verilog must be used
   //with a preceding '.
   struct dut_driver {
   ld: list of int(bits: `WORD_WIDTH); //use verilog macro
   keep ld.size() in [1..'TRANS_DELAY];//use verilog macro
   };
   '>
   

3.1.7 Importing e Files

e files are called modules. An e file can import another e file using the import keyword. The import statement loads additional e modules before continuing to load the current file. If no extension is given for the imported file name, a “.e” extension is assumed. The modules are loaded in the order they are imported. The import statements must be before any other statements in the file.

//File Name: 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;
};
'>
//End File: pci_transaction_definition.e
------------------------------------------------------------
//File Name: pci_transaction_extension.e
<'
//Import the file defined above. Note that the .e
//extension is assumed in an import statement
import pci_transaction_definition; //.e extension is the default

extend pci_transaction {
    data: list of uint;
};
'>
//End File: pci_transaction_extension.e

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. The current directory

  2. Directories specified by the SPECMAN_PATH1 environment variable

  3. The directory in which the importing module resides

  • + Share This
  • 🔖 Save To Your Account