Scriptable Generators

EASYHDL & SCRIPTABLE GENERATORS

Introduction

PROSPICE includes support for a programming language which can be used to write scripts for generating complex test signals. We have christened this language EasyHDL as it is much simpler to learn and use than general purpose hardware description languages such as Verilog or VHDL. However, not withstanding its relative simplicity, EasyHDL can be used to generate both analogue and digital waveforms, and it can be used to create complex test vectors in which one script specifies the behaviour of multiple generator objects on the schematic.

EasyHDL is based loosely on the BASIC programming language but adds additional features specific for its application in specifying test vectors. The remainder of this chapter will show you how to create EasyHDL scripts and how to link them to one or more generator objects on the schematic. However, this manual does not give a detailed explanation of the BASIC language except where necessary to explain the additional functionality EasyHDL provides in order to be useful as a simulator modelling and control language. The descriptions of the standard BASIC keywords are brief and is limited to an explanation of the language syntax.


CREATING, EDITING & DEBUGGING EASYHDL SCRIPTS

EasyHDL scripts can be local to a particular generator object, or they can be placed on the schematic and then associated with multiple generators in order to specify a complex set of test vectors.

To create an local EasyHDL script for single generator:

  1. Select the Generator icon to place a generator or else click right and then left to edit an existing one.
  2. Set the generator type to Easy HDL - this can be analogue or digital according to the type of generator that you want to create.
  3. Type the script into the Local Script editor field. Alternatively you can click the Edit button to edit the script in your external text editor. You can specify which editor is used by invoking the Setup External Text Editor command on the Source menu.

The output pin is automatically assigned the name ‘OUT’. If you specified an analogue generator in step 2, then OUT will be a NODE variable; if you specified a digital generator then OUT will be a PIN variable.

To create an EasyHDL script on the schematic:

  1. Select the Script icon and click left to place a script object. The Edit Script dialogue form will appear.

    See SCRIPTS in the ISIS manual for general instructions on placing and editing text scripts.
  2. The first line of the script must be:

    *SCRIPT GENERATOR script_name

     The keyword SCRIPT indicates that the text in the script block is to be included in the netlist, whilst the keyword GENERATOR indicates to PROSPICE the type of script (for the purpose of linking it). The name after GENERATOR keyword is a name supplied by you to identify the script. Any sequence of alphanumeric characters and the underscore character ('_') may be used - a space or any other character will be seen as the end of the script name.
  3. The last line in the script must be:

    *ENDSCRIPT

     This indicates the end of the script to the netlist loader in PROSPICE; ISIS will report it as missing if it is not found during netlist compilation. Anything after this line will not be included in the netlist, and is effectively ignored.
  4. Enter your EasyHDL script between the opening *SCRIPT... and closing *ENDSCRIPT. You will need to declare the generators as NODE or PIN variables.
  5. Close the edit script dialog form when you are done.

To link generator objects to a schematic based script:

  1. Select the Generator icon to place a generator or else click right and then left to edit an existing one.
  2. Set the generator type to Easy HDL - this can be analogue or digital according to the type of generator that you want to create.
  3. Used the Assigned Script selector to specify the script that will drive the generator. The generator name must match a NODE or PIN variable in the controlling script.

To debug a generator script during simulation:

  1. Place the generator in the normal way, set the generator type to be EasyHDL and write the script.
  2. Check the box on the dialogue form underneath the script to allow debugging.
  3. Pause the simulation to see the source and variables for the script.
  4. Set breakpoint(s) in the source window (double click on the source line in question) and then run the simulation.
  5. When the breakpoint is hit the simulation will pause and you can single step the script, monitoring variable changes etc. in the normal way.

Specifying a EasyHDL triangle wave script as being active for debugging

From a user interface perspective, debugging an EasyHDL script is largely identical to debugging microcontroller firmware in Proteus VSM and we recommend you reference this material in the manual if you are unsure about basic operation. Beyond that however, there are a few subtle differences that you should bear in mind:

  • EASYHDL statements execute in zero time. It follows that when you single step EASYHDL code, the electrical simulation does not advance after each step. This is significantly different from stepping microcontroller code, in which each instruction takes a finite time to execute and the simulation advances in time as you step the code.
  • Since time does not advance after each statement, the effect of any output assignments made in the script will not be seen in the circuit until either the end of the script is reached, or, in the case of a digital script, a SLEEP or WAIT statement is reached.
  • All scripts are executed once at the start of the simulation. Therefore, any breakpoints that can be reached from the start of the script will trigger before the circuit operating point has been computed. This may result in unusual voltage and logic state values being displayed on the schematic. In this situation, the operating point will be re-computed after each step until the end of the script has been reached.
  • Breakpoints and single stepping are not enabled when an analogue script is invoked on an ordinary analogue time point. Debugging is only active when the script is invoked by a timer or other callback event.

Several examples of EasyHDL scripts can be found in the Generator Scripts subdirectory of the Samples directory supplied with your Proteus installation. These range in complexity from a simple sine wave through to a complete QPSK Modulator and are well worth exploring.


PROGRAM STRUCTURE

EasyHDL consists of declarations, assignments and commands. Declarations are used to declare the names of variables, and possibly to initialise them. Assignments are used to assign the result of an expression to a variable. Commands are used to control the flow of the program script.

Each declaration or command has one or more keywords associated with it, though not all the keywords need necessarily be specified; that is some parts of the command are optional. For example the FOR...TO...STEP...NEXT command has four keywords, of which only the keywords FOR, TO and NEXT are essential (the STEP keyword and the expression that follows it being optional).

Some commands have both a block syntax and an inline syntax. A block syntax allows several commands to be nested between the start of the command and its end keyword. An inline syntax only allows other commands to be specified on the same line as the command itself; there is no need to specify the end keyword of the command as the end of the line is assumed to be the end of command. The following example shows the IF...ELSE...ENDIF command in both its block and inline formats:

IF i=0 THEN

j=1 // IF... BLOCK

k=2

ELSE

j=3 // ELSE... BLOCK

k=4

ENDIF

IF i=0 THEN j=1:k=2 ELSE j=3:k=4 // No need for an ENDIF


EXPLANATION OF SYNTAX LAYOUT

The following nomenclature and syntax symbols have been used throughout the subsequent command reference sections. It is strongly suggested that the reader fully acquaints himself with this nomenclature before attempting to understand the reference material.

For each command in the command reference section, its syntax is given shown in a simplified BNF format which is explained below:

  1. 1. Within the syntax definitions and examples, all command keywords are shown in courier. Within the syntax definitions, all command keywords are also in bold in order to help differentiate between mandatory keywords and textual descriptions of arguments. For example:

    IF expression THEN ...
  2. Ellipses ('...') indicate one or more other commands, separated by colons.
  3. Opening and closing double square brackets ('[[' and ]]') indicate that the text within the brackets is optional. Where square-bracketed text is nested, then the inner-bracketed text is only allowed provided the outer-bracketed text is entered; that is, if you choose to omit the outer-bracketed text then you must omit all the text between its opening and closing double square brackets, and this includes all inner-bracketed text. For example:

    COMMAND [[A[[,B]] ]]

     means that if you may optionally follow COMMAND with 'A'. If you do so, then you may optionally follow the 'A' with a comma and then 'B'. If you don't follow the command with 'A', then you cannot follow it with anything.
  4. The pipe symbol ('|') is used to indicate that one of several, mutually exclusive options may be entered. The example:

    COMMAND A | B | C

     indicates that the COMMAND keyword may be followed by any one of 'A', 'B', or 'C'.
  5. The letters etc are used to indicate repetition of the previous parameter(s). The characters in front of the etc indicate from where in the previous text you can repeat the parameter(s). In the example:

    INT variable=expression[[,variable=expression]][[,etc]]

     the ,etc indicates that previous parameter [[,variable=expression]] can be repeated indefinitely.
  6. Words or phrases in lower case Times Roman italics refer to some arbitrary expression or variable, often referred to in the text that follows the syntax definition. In the example:

    IF test_expression THEN ...

the phrase test_expression indicates an arbitrary numeric expression.


USING EASYHDL TO SPECIFY ANALOGUE SIGNALS

Declaring the Output(s)

The output pin(s) for an analogue scriptable generator should be declared as NODE variables. For example:

NODE V(OUT) // Single voltage output

NODE V(POS,NEG) // Differential voltage output

NODE I(OUT) // Single ended current output

NODE I(POS,NEG) // Current output

A local generator script contains an implicit declaration of NODE V(OUT) for a voltage generator or NODE I(OUT) for a current generator.

Program Flow

When an EasyHDL script is used to specify analogue signals, the entire script is executed from top to bottom at each analogue timepoint and also whenever a callback event occurs. Commands such as SLEEP are not allowed, and the assumption is that the program will make assignments to all the declared NODE variables.

Callback events may be scheduled using either the CALLBACK or TIMER commands. These commands cause an analogue simulation timepoint to occur at the specified time and the script to be invoked with a corresponding event id.

Typically, you will use mathematical formulae to specify the output at a particular time and then use callback events to change some of the parameters in the formula at specific times. If this sounds a little confusing the example below should help clarify the concept:

REM TRIANGLE WAVE GENERATOR

REM Define the Waveform Parameters

FLOAT FREQ=100, AMP=2, SLOPE=1

FLOAT PERIOD=1/FREQ,OFFSET=0

REM Repeating event for positive slope

ON TIMER AT PERIOD EVERY PERIOD

 OFFSET=EVTTIME

 SLOPE=1

ENDON

REM Repeating event for negative slope

ON TIMER AT PERIOD/2 EVERY PERIOD

 OFFSET=EVTTIME

 SLOPE=-1

ENDON

REM Set the output as a function of both time

REM and the current waveform slope.

OUT=AMP*SLOPE*(4*(REALTIME-OFFSET)/PERIOD-1)

When the script is invoked at an arbitrary timepoint, only the last line is executed. This specifies the output in terms of a voltage that will rise or fall linearly with time according to the value of SLOPE. This value is set alternately to 1 and –1 by the two ON TIMER blocks that trigger alternately every full and half cycle such that a triangle wave is produced.

It should also be apparent from this that variables hold their values between invocations. However, you must be careful not to make assumptions about how many times your script will be invoked over a given period of simulation time. For example:

REM !!!BAD CODE!!!

FLOAT VOUT=0

VOUT = VOUT + 1.0

OUT=VOUT

This will produce unpredictable results because the rate of rise of VOUT will depend entirely on the timesteps chosen by the SPICE kernel.

Specifying Output Transitions

You can specify the of an analogue generator in one of two ways:

  • As an instantaneous value.
    OUT=vout
  • As a timed transition.
    OUT=vout AFTER time_interval

In the case of a timed transition, the output will ramp linearly from its current value to the destination value over the specified time interval. You can also specify an absolute destination time for the transition with

OUT=vout AT time

The example, below, shows how output transitions can be used to generate a piecewise linear waveform from stored data.

REM PIECEWISE LINEAR GENERATOR

REM Define time/value pairs for the output

DATA 2m,5

DATA 3m,5

DATA 5m,0

DATA 0,0  // End of data

FLOAT PERIOD=10m

FLOAT v,t,td

TIME OFFSET=0

REM Reset the data pointer to

REM start a new cycle

ON TIMER AT PERIOD EVERY PERIOD

   RESTORE

   OFFSET=EVTTIME

ENDON

ON EVENT

READ t,v

IF t > 0

t = t + OFFSET

OUT=v AT t // The output is set to voltage v at time t

CALLBACK AT t

ENDIF

ENDON


USING EASYHDL TO SPECIFY DIGITAL SIGNALS

Declaring the Output(s)

The output pin(s) for a digital scriptable generator should be declared as PIN variables. For example:

PIN Q // Single bit output

PIN D[0..7] // 8 bit data bus

A local generator script contains an implicit declaration of PIN OUT.

Where the generator has a name that is not a valid EasyHDL variable name you can use an ALIAS command:

ALIAS OUT=Test Signal

PIN OUT

Program Flow

When an EasyHDL script is used to specify digital signals, the entire script is executed from the top and executes until one of the following conditions is met:

· An END statement is executed.

· The last statement in the script is executed.

· A SLEEP or WAIT command causes suspension of the script.

Once and END statement or the end of the script has been reached, it will not be re-invoked until a CALLBACK or TIMER event is scheduled. These commands will cause the script to be resumed (if suspended) or else re-executed from the top with a corresponding event id. Note that there is only ever one thread of execution; if an event occurs whilst the script is suspended or sleeping then execution always resumes at the following statement.

Typically, a digital generator script will be consist of output assignments interspersed with SLEEP or WAIT statements so as to create the desired timing. For example, the following code will ‘bit bang’ a serial data stream from a variable.

// Bit Bang a single character

// 1 Start bit, 1 Stop bit and no

// parity are assumed.

// Start bit

OUT = 0

SLEEP FOR BITTIME

// Data bits

FOR j=0 TO 7

OUT = d & (1 << j)

SLEEP FOR BITTIME

NEXT j

// Stop bit

OUT = 1

SLEEP FOR BITTIME

If you do not include appropriate SLEEP or WAIT statements your script will execute almost instantaneously and you will not see the desired output waveform.

Specifying Output Transitions

You can specify the of a digital generator in several ways:

  • As an instantaneous value (transition with zero delay)
    OUT=dout
  • As a future value
    OUT=vout AT time

Multiple future assignments may be scheduled at once. For example, a single pulse could be described with

OUT=1 AT time

OUT=0 AT time+width

  • As a timed transition.

    OUT=dout AFTER delay
    OUT=dout AFTER tdlh,tdhl

In the case of a timed transition with two parameters, tdlh is used when the output is rising (low->high transition) and tdlh is used when it is falling (high->low transition).


VARIABLES

Variable Declarations

Variables can be declared as singular or as arrays. Arrays of variables provide a means of producing look up tables and, more importantly, support for buses.

Declarations of variables have the form:

TYPE name[[[lower..upper]]] [[=expression]] [[,etc]]

TYPE name[[[width]]] [[=expression]] [[,etc]]

A declaration takes the form of the name of the variable type you wish to declare variables of, followed by a comma separated list of variable names. If the variable represents an array, then the name must be followed by either the lower and upper inclusive bounds of the array separated by two periods or the width of the array, enclosed in square brackets. The width or lower and upper bounds of the array must be integer constants - expressions are not allowed. If you specify an array by its width, then a lower bound of zero and an upper bound of width-1 is assumed. Variable initialisation is achieved by following the variable name or closing square bracket of an array declaration by an equals sign and then the initialisation expression.

For example,

PIN data[2..5]=13, output

INT i

INT j=0,k[2]

TIME t1,t2=10n

declares two variables of type PIN (data and output), three variables of type INT (i, j, and k) and two variables of type TIME (t1 and t2). The data and k variables have both been declared as an arrays; data has four elements: data[2], data[3], data[4] and data[5], whilst k has two elements: k[0] and k[1]. Of the variables declared, data, j, and t2 have been initialised with the values 10, 1 and 1E-8 respectively.

Variables declared with an initialisation expression are only assigned the result of the expression once, as part of the DSIM boot stage. After the boot stage, variables maintain their values from the previous invocations of the BASIC script and are not assigned the results of their initialisation expressions prior to each invocation.

See BOOL and PIN Types for more information on declaring arrays of PIN variables.

See Assigning to Variables on for an explanation of assigning expressions to variables.

Numeric Types

There are three numeric types in EasyHDL:

Type | Description
INT | Signed or unsigned integers in the range 0 to 2,147,483,648.
FLOAT | Signed or unsigned floating point values in the range 2.225074 x 10-308 to 1.767693 x 10308.
TIME | Signed or unsigned integers capable of holding an event time which has a resolution of 1ps. The current time in an analogue simulation may be obtained from the system variable REALTIME which returns a floating point quantity.

Note that you can only assign values (not expressions) to variables of type TIME. For example, you cannot have T= fred * 1000 where T is of type TIME.

String Types

EasyHDL supports a simple string type

STRING Simple ASCII character string.

Various operations can be performed on a string variable:

STRING S1 = "Hello", S2 = "World", S3

INT C

S3 = S1+" "+S2 // S3 <= "Hello World"

S3 = S1[1,4] // S3 <= "Hell"

C=ASC(S1) // C <= 48h ('H')

C=ASC(S1[2]) // C <= 65h ('e')

S3 = CHR(C+1) // S3 <= "f"

BOOL and PIN Types

The EasyHDL PIN is provided for accessing the pins on the digital generator(s) that the script is linked to. Variables declared of this type are 'linked' to the same-named generator(s) to which the script is assigned.

See Declaring the Outputs for more information how to declare PIN variables.

The order of variable declaration is not important, and as for other EasyHDL types, initialisation of the variables declared is allowed.

When a variable of type PIN is read or tested, it returns both the current and previous activity of the pin, where the pin's activity is dependant on the state of the net to which the pin is connected, the electrical type of the pin, the translation-table for the logic family, and any properties assigned to the pin by the owner device or generator. Variables of type PIN should only be tested by equivalence to one of the following system constants:

Type | Description
TRUE,ACTIVE | The pin is currently active; its previous activity is ignored.
FALSE,INACTIVE | The pin is currently inactive, its previous activity is ignored.
FF | The pin was inactive and remains inactive.
FT,POSEDGE | The pin was inactive and has become active.
TF,NEGEDGE | The pin was active and has become inactive.
TT | The pin was active and remains active.

It is possible to directly drive the net to which an output pin connects, regardless of the electrical type of the pin or any properties assigned to it, by assigning the PIN variable one of the following system constants:

Type | Description
FLT | Drive the net with the floating state.
SLO | Drive the net with a strong low.
SHI | Drive the net with a strong high.
WLO | Drive the net with a weak low.
WHI | Drive the net with a weak high.

As the storage of a pin's activity state is complex, the special type BOOL is provided for holding the state of a PIN variable. The BOOL type is identical to the PIN type except that variables declared to be of type BOOL are not linked to an external pin.

NODE Type

The EasyHDL type NODE is provided for accessing the pins on the analogue generator(s) that the script is linked to. Variables declared of this type are 'linked' to the same-named generator(s) to which the script is assigned.

See Declaring the Output(s) for more information how to declare NODE variables.

The order of variable declaration is not important, and as for other EasyHDL types, initialisation of the variables declared is allowed.

When a variable of type NODE is read or tested, it returns the voltage or current value that it is driving. In the case of a timed transition, this will be the interpolated value at the current simulation time.

Assigning To Variables

Assignments to single variables has the general syntax:

[[LET]] variable = expr'n[[,variable=expr'n]][[,etc]]

For example:

INT VAR1, VAR2, VAR2

...

VAR1=10, VAR2=20, VAR3=30

In general, the result of any expression is always cast to the type of the variable it is being assigned to prior to assignment. The exception to this is assigning a net state to a variable of type PIN that links to an external generator or output device pin, where the state is applied directly to the net the pin or generator connects to.

Arrays can also be assigned. If the expression yields an array result and the number of elements in the expression array is at least the same as the number of elements in the array variable being assigned, then the assignment operation assigns each element from the expression to the variable array in turn starting at the lower bound of each array. If there are insufficient elements in the expression result for the array variable being assigned, a run-time error results.

For example:

INT A[10..19]

A[10..12]=A[15..19] // A[10]=A[11], A[11]=A[16], A[12]=A[17]

A[10..15]=A[16..17] // Error, insufficient elements in // A[16..17].

If the expression result is a single value, and the array variable being assigned is not of type PIN, then this value is first cast to the type of the array variable and is then assigned to each element in turn. For variable arrays of type PIN, the value is first cast to a INT and then each element of the PIN array is set active or inactive according to whether the bit in the INT result is set or reset respectively. The lowest element in the array is always set according to the value of bit zero of expression result, the next element according to bit one, and so on. Assignment is not made according to the value of the bit corresponding to element number. For example:

INT A[3]

PIN D[2..3]

A=4 // A[0]=4, A[1]=4, A[2]=4

D=10 // D[2]=Bit 0 of 10, D[3]=Bit 1 of 10.

An assignment to a variable of type PIN (either a single variable or an array) can use an extended syntax to provide timing information, as follows:

pin_var = expression AFTER time_expression

pin_var = expression AFTER tlh_expression,thl_expression

pin_var = expression AT|@ time_expression

The first syntax uses the keyword AFTER and a single time_expression to force the pin's output to change only after the specified time. The second syntax again uses the keyword AFTER, but has two time expressions, tlh_expression and thl_expression to force the pin's output to change either after tlh_expression if the pin's output change involves a low-to-high transition, or after thl_expression if the pin's output change involves a high-to-low transition. Note that the terms low-to-high and high-to-low are general - an output switching from a floating state to a weak-low is deemed to be performing a high-to-low transition. The final syntax uses the AT or @ symbol to specify an absolute time at which the pin's output is to change.

It should be noted that an assignment to a pin does not occur until the time specified, and not until after the script ends or is suspended, even if the assignment time is the same as the script invocation time. Thus assigning to a pin and subsequently testing pin within the same script invocation will not yield the assigned value.

For example:

PIN p

p=TRUE // Assume pin was inactive, we assign it active.

IF p=TRUE THEN // Pin is still inactive, therefore test fails.

...

See BOOL and PIN Types on for more information on assigning to PIN variables.


EXPRESSIONS

Expressions in EasyHDL consist of terms separated by operators. A term consists of an optional unary operator followed by either a literal value, a variable or constant, a function, or the result of a sub-expression that is enclosed in parentheses.

Operators

The following operators are all valid in EasyHDL:

Operator | Description
() | Parentheses
- | Unary minus
NOT or ! | Unary logical NOT
NOT~ | Unary bitwise
AND or && | Logical AND
OR or || | Logical OR
& | Bitwise AND
| | Bitwise OR
^ | Bitwise XOR
<= | Less than or equal
< | Less than
= or == | Equal
<> or != | Not Equal
> | Greater than
>= | Greater than or equal
>> | Left Shift
<< | Right Shift
+ | Addition
- | Subtraction
* | Multiplication
 | Division
% | Modulus

Operator precedence is defined, in decreasing order, as

Unary operators (!, NOT, -).

Parentheses.

Modulus, Division, Multiplication.

Addition, Subtraction.

Left and Right Shift.

Bitwise AND, OR and XOR.

Less than, Less than or equal, Greater than, Greater than or equal.

Equals, Not equals

Logical AND and OR.

Values

Values can be either variables, system variables, system constants, the result of functions, the results of sub-expressions (evaluated by enclosing the expression in brackets), or literal numbers. Literal numbers can be specified in decimal, hexadecimal (by preceding the number with a unary dollar character) or binary (by preceding the value with a unary percent character). All values can be modified by preceding them with a unary operator.

Values | Description
23 | Decimal value, 23 decimal
%1010 | Binary value 1010 (10 decimal)
$010A | Hexadecimal value 010A (266 decimal)
(10*5) | Sub-expression, 10*5 (50 decimal)
TRUE | System constant, TRUE
!TRUE | Unary operator and constant, NOT TRUE
max_count | Variable, max_count
EVTTIME | System variable, EVTTIME
~%1010 | Unary Bitwise NOT (5 decimal)
!$A | Unary Logical NOT (0 decimal)
"Hello" | String constant

Evaluation Precedence Examples

Here are some example expressions:

Expression | Answer
2 * -3 + 4 | Evaluates as -2
2 * -(3 + 4) | Evaluates as -14
5 << 3 | Evaluates as 40
10 >> 2 | Evaluates as 2
3 << 3+4 | Evaluates as 28
20-3*4 | Evaluates as 8
2<1+3 | Evaluates as 1 (i.e. TRUE, 2<4)
1+2>=8 | Evaluates as 0 (i.e. FALSE, 3>=8)
40%16 | Evaluates as 8
!(1<3) | Evaluates as 0 (i.e. FALSE, !TRUE)
!5<2 | Evaluates as 1 (i.e. TRUE, 0<2)

Functions

EasyHDL supports several useful mathematical functions. All functions consist of the function name followed by a single argument (which may be an expression) enclosed in parentheses. The result of the a function is returned as its value. For example, the following expression uses assigns the square-root of the expression a*b*c to the variable z:

z = sqrt (a*b*c)

EasyHDL supports the following functions:

Function | Description
DEG | Returns its argument in degrees which must be in radians.
RAD | Returns its argument in radians which must be in degrees.
SIN | Returns the sine of its argument which must be in radians.
COS | Returns the cosine of its argument which must be in radians.
TAN | Returns the tangent of its argument which must be in radians.
ASIN | Returns the arc-sine of its argument in radians.
ACOS | Returns the arc-cosine of its argument in radians.
ATAN | Returns the arc-tangent of its argument in radians
SQRT | Returns the square-root of its argument.
ROUND | Returns the its argument as rounded to the nearest integer.
FRAC | Returns the decimal part of its floating-pointing argument.
ASC | Returns the ASCII code of the first character in a string
CHR | Returns a single character corresponding to the ASCII code of the argument.
LEN | Returns the length of a string
SUBSTR | Returns a substring of a string argument starting at the second argument and of length of the optional third argument.


SYSTEM CONSTANTS AND VARIABLES

A system constant is a constant value defined with DSIM for the purpose of providing portability of scripts; system constants are fixed for a particular release of the simulator engine and never change value from one invocation of the script to another. A system variable is a read-only variable that returns some value particular to the current simulation run and the current invocation of the script; system variables may thus change from one invocation to another. The DSIM system constants defined as follows:

Numeric Constants

The following numeric constants are defined:

PI (p) - 3.141582654…

Event Identification Constants

The constants EI_ANY, EI_BOOT, EI_SETTLE, EI_INPUT and EI_CALLBACK are provided for testing the system variable EVTID in order to determine whether the current invocation of the script is a result of system (or undefined user) event, and for use in the SLEEP and WAIT commands.

When a script is invoked, the event identification that caused the invocation is placed in the system constant EVTID. The EI_INPUT value indicates that the invocation is the result of a change in the state of a net to which one of the pins of the device the script is modelling. The EI_CALLBACK value indicates that the invocation is the result of a user-defined call-back event that was initialised without a user supplied event identification code.

See The SLEEP Command for information on the SLEEP command.

See The WAIT Command for information on the WAIT command.

Net State Constants

The constants SHI, SLO, FLT, WLO, WHI are provided for assignment to variables of type PIN in order to directly drive the net to which the corresponding device pin or generator is connected.

See BOOL and PIN Types for information on using these constants.

PIN And BOOL Pin Activity Constants

The pin activity states FALSE, INACTIVE, FF, FT,TRUE, ACTIVE, TF, FT, POSEDGE, and NEGEDGE are provided for testing against variables of type PIN in order to obtain information on the current and previous pin activity.

See BOOL and PIN Types for information on using these constants.

TDSCALE System Variable

The TDSCALE variable returns the current value of the simulator engine's TDSCALE Simulator Control Property which provides a scaling value for timing properties. If the TDSCALE property was initialised to produce random time-scaling values, then the TDSCALE variable returns a new random value time-scaling value each time it is read.

RANDOM System Variable

The RANDOM variable returns the next random number from the DSIM script's random number generator. The random number returned is in the range 1 to 32767 (215-1).

Whilst the sequence of numbers generated by the generator appears to be random, the sequence itself is determinate and is set by the generators seed value. You can seed the generator at any point in the script by using the SEED command. DSIM guarantees that, for a given seed value, the sequence of numbers generated by subsequent reading of the RANDOM variable is determinate.

See The SEED Command on for information on using the SEED command to seed the script's random number generator.

REALTIME and EVTTIME System Variables

The REALTIME variable returns the current value of time in the analogue simuation as a value of type FLOAT This contrasts with EVTTIME which returns the time of the current event in the digital simulation as a value of type TIME. Event times are quantized with a resolution of 1ps.


COMMAND REFERENCE

The following sections list all the commands supported by EasyHDL. For each command there is listed its syntax, purpose and one or more examples of its use.

The ABORT Command

Syntax

ABORT idcode_expr

Purpose

The ABORT command provides a means of aborting the current simulation. The execution of this command causes the simulator engine to cause a EasyHDL process run-time error. The error message inserted into the simulation log includes the identification code given in the idcode_expr expression that followed the ABORT keyword.

You should note that ABORT command not only aborts the current EasyHDL invocation but the entire simulation session.

Example

IF input=TRUE THEN PRINT "Input Is TRUE!" : ABORT 0

The ALIAS Command

Syntax

ALIAS new_name=existing_name [[,new_name=existing_name]] [[,etc]]

Purpose

The ALIAS command provides a means of aliasing one variable name with another. Aliasing is particularly useful where the name of the pin on a device uses characters not allowed in a EasyHDL variable name. and therefore it is not possible to directly declare a variable of type PIN or NODE for the generator pin. The new_name is the name you now wish to refer to the variable or external pin or property by, and must obey EasyHDL variable naming rules. The existing_name is the existing variable, property or pin name - all characters up to a space or comma are regarded as valid - if you need to alias something which has spaces or commas in its name, then you should enclose existing_name in double quotes. Following the alias declaration, new_name can be regarded as synonym for existing_name and can be used wherever you might have needed to use existing_name.

For example, the 7493 TTL counter has reset pin names that contain brackets - R0(1) and R0(2). As you cannot have variable names with brackets within EasyHDL you need to alias the 7493 pin name with your own names - e.g. RS0 and RS1, and then declare variables of type PIN with these names - see the following example.

See BOOL and PIN Types for further information on using the ALIAS command to declare variables of type PIN.

Example

ALIAS RS1=R0(1),RS2=R0(2)

...

PIN RS1,RS2 // RS1 is the synonymous with R0(1), etc.

...

IF RS1 AND RS2 THEN ...

The BREAK Command

Syntax

BREAK

Purpose

The BREAK command causes termination of the current FOR...TO...NEXT, WHILE...WEND, REPEAT...UNTIL loop or the termination of the current case of a MAP ON or SWITCH command, as follows:

· The execution of the command within a WHILE...WEND loop causes execution to continue with the first command after the WEND keyword.

· The execution of the command within a REPEAT...UNTIL loop causes execution to continue with the first command after the UNTIL keyword.

· The execution of the command within a FOR...TO...NEXT loop causes execution to continue with the first command after the NEXT keyword.

· The execution of the command within a MAP ON...ENDMAP command causes execution to continue with the first command after the ENDMAP keyword.

· The execution of the command within a SWITCH...ENDSW command causes execution to continue with the first command after the ENDSW keyword.

Example

WHILE pin_enable=TRUE

...

IF EVTTIME > 1 THEN BREAK

...

WEND

The CALLBACK Command

Syntax

CALLBACK [[eventid]] AFTER time_expression

CALLBACK [[eventid]] AT time_expression [[EVERY repeat_expression]]

Purpose

The CALLBACK command allows a call-back event to be posted; the EasyHDL script is invoked when the event time is reached.

This command also allows an event identification value to be specified; this will be placed in the system variable EVTID when the event is processed and the script invoked. As all system event identification codes are zero or negative, only positive non-zero identification codes should be used in CALLBACK commands. If no identification value is specified, then the EVTID variable will contain the system constant value EI_CALLBACK when the script is invoked.

The event identification expression, if any, is followed by either the keyword AFTER or the keyword AT and then an expression for the time at which the call-back is to take place. The AFTER keyword indicates that the time expression is a delay value to be added to the current event time; the AT keyword indicates that the time expression is the absolute time at which that call-back event is to occur.

A repeating callback may be scheduled using the AT... EVERY construct.

See Event Identification Constants on for an explanation of the EVTID system variable and the event identification codes.

Example:

IF EVTID = EI_BOOT THEN

REM BOOT Sequence; post call back for 1u.

CALLBACK 2 AT 1u

ELIF EVTID = 2 THEN

REM Process out call-back.

...

ENDIF

The CONTINUE Command

Syntax

CONTINUE

Purpose

The CONTINUE command causes the loop expression of the current WHILE...WEND, REPEAT...UNTIL loop to be re-evaluated or for the loop variable of the current FOR...TO...NEXT loop to be incremented and re-tested against the command's limit expression, as follows:

  • The execution of the command within a WHILE...WEND loop causes execution to continue with the WHILE command.
  • The execution of the command within a REPEAT...UNTIL loop causes execution to continue with the UNTIL command.
  • The execution of the command within a FOR...TO...NEXT loop causes execution to continue as though the NEXT keyword had been reached.

Example:

REPEAT

...

IF EVTTIME <= 100n THEN CONTINUE

...

UNTIL pin_enable=F

The DATA Command

Syntax

DATA constant [[,constant]] [[,etc]]

DATA REPEAT

Purpose

The DATA command specifies one or more constant values that can be read in sequence by the READ command. Typically, the data stored will determine the evolution of the test signal(s) controlled by the script over time. For example, you could define time/voltage pairs in order to define a piecewise linear waveform, or you could store data and address values to be output onto a bus.

The constant values can be any of any valid EASYHDL data type including strings.

The keyword REPEAT causes the data table to be considered as circular, that is that after the last data item has been read, the next READ command will begin again at the start of the table again.

Example:

DATA "Hello World ", 250m

DATA "- EASYHDL Test Program\r", 500m

DATA REPEAT

The END Command

Syntax

END

Purpose

The END command causes termination of the current invocation of the BASIC script and return of control to the simulator engine. There is no need to end a BASIC script with an END command; this is implicit.

Example

IF EVTTIME < 100n THEN END

The FOR...TO...STEP...NEXT Command

Syntax

FOR variable=init_expr'n TO limit_expr'n [[STEP step_expr'n]]

...

NEXT variable

Purpose

The FOR...TO...STEP...NEXT command allows a the set of commands between the FOR and NEXT keywords to be executed a given number of times. The variable after the FOR keyword is referred to as the loop variable and must be a previously declared variable of either INT or FLOAT type and must also be specified after the NEXT keyword.

The loop variable is initialised to the value of init_expression, and the commands inside the FOR...NEXT block are then executed. When the NEXT keyword is encountered, the value of the loop variable is incremented by either the value of step_expression if one is specified, or by one. If the new value of the loop variable is less than or equal to the value of the limit_expression, then execution continues with the first command after the FOR keyword, otherwise execution continues with the first command after the NEXT keyword.

The commands within a FOR...NEXT block are always executed at least once, regardless of the values of the init_expression and limit_expression. The loop variable is valid within the FOR...NEXT block and may be manipulated just like any other variable. Note however that it is possible to manipulate the loop variable such that FOR...NEXT loop never terminates. For example:

FOR i=0 TO 10 STEP 2

i=0

NEXT i

the loop variable (i) is always set to zero; even with its increment by the step value when the NEXT keyword is encountered, the loop variable will never reach the value of 10.

Example

INT v

FOR v=0 TO 10 STEP 2

PRINT v;"*";v;"=";v*v

NEXT v

Note that you cannot use variables of type float as loop counters - they should be of type INT.

The GOTO Command

Syntax

GOTO label_name

Purpose

The GOTO allows program execution order to be switched to the next command after the label specified in label_name. A label of the same name as label_name must be declared somewhere within the BASIC script; forward and backward jumps are both allowed.

A label must be declared at the start of a line and must consist of no more than thirty alphanumeric and underscore ('_') characters. The label must be followed by a colon and, to avoid ambiguity, the label should not be the same as any EasyHDL keyword. Further commands may follow the label's terminating colon, if desired.

Example

LBL_START: // Declare the label.

PRINT "START OF SCRIPT"

...

IF !done THEN GOTO LBL_START // Jump to PRINT... command.

The IF...ELIF...ELSE...ENDIF Command

Syntax

IF expression [[THEN]]

...

...

[[ELIF expression [[THEN]]

...

...]]

[[ELIF expression [[THEN]]

...

...]]

etc

[[ELSE

...

...]]

ENDIF

IF expression [[THEN]] ... [[ELIF expression [[THEN]] ... ]][[ELSE ... ]][[ENDIF]]

Purpose

The IF...ELIF...ELSE...ENDIF command allows conditional execution of the commands in each of the blocks. There can only be one IF keyword and optionally one ELSE keyword. There may be any number of ELIF keywords between the IF keyword before the ELSE or ENDIF keywords.

The expression following the IF and ELIF keywords are evaluated in succession; if any of the these evaluates non-zero, then the commands following the IF or ELIF keyword and before the next ELIF, ELSE or ENDIF keyword are executed. If none of the IF or ELIF expressions evaluates non-zero, then statements following the ELSE keyword (if any) are executed. Execution then continues with the command after ENDIF keyword.

Example

IF i=0 THEN

PRINT "Value is zero"

zero = TRUE

ELSE

PRINT "Value is non-zero"

zero = FALSE

ENDIF

IF i THEN j=0 : WHILE (i>0) j=j*2:i=i-1 : WEND : i=0 ELSE j=-1

The MAP ON...ENDMAP Command

Syntax

MAP ON property_name

CASE string1 : ...

...

[[BREAK]]

[[CASE string2 : ...

...

[[BREAK]] ]]

[[DEFAULT : ...

...

[[BREAK]] ]]

ENDMAP

Purpose

The MAP ON...ENDMAP command allows a set commands in one or more of its cases to be executed, the case being selected according to the result of the comparing value of the property named after the MAP ON keyword with each case's label.

Within the MAP ON...ENDMAP block are one or more cases. Each case consists of the either the DEFAULT followed by a colon, or the keyword CASE followed by a case label and a colon. The first fifteen characters after CASE keyword and up to either a space, a tab character or the colon are deemed part of the case label. Following the colon are the commands associated with the case.

The textual value of property named after the MAP ON keyword is compared against each case label in the order the cases are declared. Case is not sensitive. If a match is found, then execution continues with the first command after the case label; if no match is found, and a DEFAULT case is specified, then execution continues with the first command after the DEFAULT keyword. Execution then continues with all commands up to the ENDMAP keyword; if execution only up to the next case is required, then the last command in the case should be a BREAK command. If no match is found with any case and there is DEFAULT case, or if a BREAK command is encountered in any case, execution continues with the first command after the ENDMAP keyword.

The MAP ON...ENDMAP is intended for use in initialising a model script according to the state of some device property, most likely its value. To this end, it is only within a MAP ON...ENDMAP block that properties may be assigned, and consequently, the command and the relevant case or cases within it are only executed during the boot invocation of the script - for all other invocations, the command is automatically ignored and there is no need to place it within an IF

...ENDIF block.

Example

// Assign timing properties depending on what family

// of device we are modelling.

MAP ON VALUE

CASE 74259 : TDRQ=16n : TDLHDQ=14n

TDHLDQ=11n : TDLHAQ=15n

BREAK

CASE 74LS259 : TDRQ=12n : TDLHDQ=19n

TDHLDQ=13n : TDLHAQ=17n

BREAK

ENDMAP

The ON BOOT … ENDON Command

Syntax

ON BOOT

...

...

ENDON

Purpose

The ON BOOT command allows a set commands in to be executed just once, at the start of the simulation. It is exactly equivalent to writing:

IF EVTID = EI_BOOT THEN

...

...

ENDIF

Example

ON BOOT

REM BOOT Sequence; post call back for 1u.

CALLBACK AT 1u

ENDON

The ON EVENT … ENDON Command

Syntax

ON EVENT [[event_id]]

...

...

ENDON

Purpose

The ON EVENT command allows a set commands to be executed whenever a particular event occurs. It is exactly equivalent to

IF EVTID = event_id THEN

...

...

ENDIF

If event_id is not specified then it is assumed to be EI_ANY.

Any code inside an ON EVENT block is will not be executed during an ordinart analogue timepoint.

Example

ON TIMER AT PERIOD EVERY PERIOD

RESTORE

OFFSET=EVTTIME

ENDON

ON EVENT

READ t,v

IF t > 0

t = t + OFFSET

OUT=v AT t

CALLBACK AT t

ENDIF

ENDON

The ON EVENT clause is executed at startup (EI_BOOT), every TIMER period, and also at each callback (EI_CALLBACK).

The ON TIMER… ENDON Command

Syntax

ON TIMER event_id AFTER delay_expr

...

...

ENDON

ON TIMER event_id AT time_expr [[EVERY period_expr]]

...

...

ENDON

Purpose

The ON TIMER command sets up a timer and then allows a set commands to be executed whenever it is triggered. It is exactly equivalent to

TIMER event_id AT time_expr EVERY period_expr

IF EVTID = event_id

...

...

ENDIF

If event_id is not specified then a unique id is allocated automatically.

As with the TIMER command, an ON TIMER command cannot be retriggered once an event has been scheduled.

Example

ON TIMER AT PERIOD EVERY PERIOD

OFFSET=EVTTIME

SLOPE=1

ENDON

The PRINT Command

Syntax

PRINT expression | "text" [[,|; expression | "text"]][[etc]][[,|;]]

Purpose

The PRINT command provides a means to insert text and the values of variables/expressions into the simulation log.

The PRINT keyword is followed by a list of arguments separated by commas or semicolons; each argument can be either an expression or literal text enclosed in double-quotes. Each argument is inserted in the simulation log in order from left to right; arguments separated by a comma will be inserted in to the log separated by a single space, arguments separated by a semicolon will be inserted in to the log directly after the previous argument. If the PRINT command's argument list ends with an argument, then a new line (a carriage-return and linefeed) is inserted in to the log after the last argument; if the list ends in a comma or semicolon separator then no new line is inserted and any output from subsequent PRINT commands will follow the last argument output, on the same line.

Example

PRINT var1;"+";var2;"=";var1+var2;".";

The READ Command

Syntax

READ var1 [[,var2]] [[,etc]]

Purpose

The READ command retrives the next item(s) from constant values declared in any DATA statements within the program and stores it(them) in the specified variable(s).

Example

REM Define data to be output

DATA "Hello World", 250m

REM Read the data

READ s,td

The REM Command

Syntax

REM text

Purpose

The REM (remark) command allows comments and information to be included within a EasyHDL script. All text after the REM keyword is ignored by the EasyHDL Compiler.

Note that, as all text after the REM keyword is ignored, the REM command should before the end of a colon-separated sequence of commands.

Note also that you can also indicate a comment with a double forward-stroke ('//'); this has advantage that, not being a keyword, it does not require a colon in front of it. As for a REM everything after the second stroke is ignored by the EasyHDL compiler.

Example

REM This is a comment, and will be ignored.

REM So is this.

PRINT "A=",a // Display the value of A

The REPEAT...UNTIL Command

Syntax

REPEAT

...

...

UNTIL expression

Purpose

The REPEAT...UNTIL command allows the commands between the REPEAT and UNTIL keywords to be repeatedly executed until the loop expression following the UNTIL keyword evaluates as non-zero.

The commands between the REPEAT and UNTIL keyword are executed. When the UNTIL keyword is reached, the loop expression following it is evaluated; if the result is non-zero, execution continues with the first command after the UNTIL keyword, otherwise execution continues with the first command after the REPEAT keyword.

Note that, as the loop expression is tested at the end of the loop, the commands between the REPEAT and UNTIL keywords are always executed at least once.

Example:

REPEAT

WAIT

count=count+1

UNTIL enable_pin=TRUE

The RESTORE Command

Syntax

RESTORE

Purpose

The RESTORE command resets the data pointer used by the READ command such that it points to the first DATA statement in the program. This allows the data to be read again.

Example:

// Define data to be output

DATA "Hello World", 250m

// Read the data

READ s,td

// Read the data again

RESTORE

READ s,td

The SEED Command

Syntax

SEED (value)

Purpose

The SEED command is used to seed the script's random number generator. For a given seed value, DSIM guarantees that, whilst the sequence of values returned by subsequent reads of the RANDOM system variable appear random, the sequence itself is finite and determinate.

For example, given a seed value of 1, the first ten random values produced by the RANDOM system variable will always be: 909, 3365, 5030, 24170, 3305, 10539, 20191, 14244, 15844, 21839, 9277. Similarly, for a seed value for 500, the first ten values would always be: 14616, 21006, 7672, 12031, 9888, 2966, 3985, 24555, 30757, 30317, 27030.

See RANDOM System Variable for an explanation of the RANDOM System Variable.

Example

SEED (500)

FOR i=1 TO 10

PRINT "Random Value",i,"=",RANDOM

NEXT I

The SLEEP Command

Syntax

SLEEP [[eventid]] FOR time_expression

SLEEP [[eventid]] UNTIL time_expression

Purpose

The SLEEP command causes the current invocation of a digital script to be suspended either for a fixed delay or until a set time. When the end time is reached execution continues with the first command after the SLEEP command.

The SLEEP command allows an event identification value to be specified. The value of this expression determines whether the script's suspension can be interrupted by other events, such as a previously declared call-back event becoming due, or a change occurring in one or more of the nets to which input pins are connected. The event identification expression, if specified, should be either a unique positive non-zero integer or one of the system constants: EI_ANY, EI_INPUT, or EI_CALLBACK. Using either a unique integer or the EI_CALLBACK constant guarantees that the suspension will not be interrupted; EI_ANY or EI_INPUT allows the suspension to be interrupted by either any event or by changes on input pin nets. When the suspension is complete, the EVTID variable will contain the value for the event identification specified. The default identification value, if no expression is given, is EI_CALLBACK.

The event identification expression, if any, is followed by either the keyword FOR or the keyword UNTIL and then an expression for the time at which the suspension is to end. The FOR keyword indicates that the time expression is a delay value to be added to the current event time; the UNTIL keyword indicates that the time expression is the absolute time at which that suspension is to end.

The SLEEP command cannot be used in an analogue generator script.

See Event Identification Constants for an explanation of the EVTID system variable and the event identification codes.

Example

PIN output

...

// Generate 100 periods of mark=20n, space=10n clock

FOR i=0 TO 100

output = TRUE // Output active

SLEEP 1 FOR 20n // Wait 20ns (mark time)

output = FALSE // Output inactive

SLEEP 1 FOR 10n // Wait 10ns (space time)

NEXT i

...

The SWITCH...ENDSW Command

Syntax

SWITCH switch_expression

CASE value1 : ...

...

[[BREAK]]

[[CASE value2 : ...

...

[[BREAK]] ]]

[[DEFAULT : ...

...

[[BREAK]] ]]

ENDSW

Purpose

The SWITCH...ENDSW command allows a set commands in one or more of its cases to be executed, the case being selected according to the result of the evaluating switch expression.

Within the SWITCH...ENDSW block are one or more cases. Each case consists of the either the keyword CASE followed by a fixed FLOAT value and a colon or the keyword DEFAULT followed by a colon. Following the colon are the commands associated with the case.

The switch expression which follows the SWITCH keyword is evaluated as a floating point (FLOAT) value and is compared against each case value in the order they are declared. If a match is found, then execution continues with the first command after the CASE value; if no match is found, and a DEFAULT case is specified, then execution continues with the first command after the DEFAULT keyword. Execution then continues with all commands up to the ENDSW keyword; if execution only up to the next case is required, then the last command in the case should be a BREAK command. If no match is found with any case and there is DEFAULT case, or if a BREAK command is encountered in any case, execution continues with the first command after the ENDSW keyword.

Example

SWITCH bus[0..2]

CASE 0 : REM Fall through to next case...

CASE 1 : REM Fall through to next case...

CASE 2 : PRINT "Bus is 0,1,or 2" : BREAK

DEFAULT : PRINT "Unknown bus value!" : BREAK

ENDSW

The TIMER Command

Syntax

TIMER [[event_id]] AFTER delay_expr

TIMER [[event_id]] AT time_expr [[EVERY period_expr]]

Purpose

The TIMER command allows for the scheduling of events in a fashion similar to the CALLBACK command. However, it is different in that a timer can only be re-triggered when any previously scheduled event has occurred. In other words, once a TIMER statement has been executed and has posted an event, subsequent executions of it will do nothing until the time of that event has been reached.

Example

PIN OUT = 0

TIMER 1 AT PERIOD EVERY PERIOD

OUT = !OUT

The WAIT Command

Syntax

WAIT [[eventid]]

Purpose

The WAIT command causes the current invocation of the script to be suspended pending a new event. When and if this event occurs, execution continues with the first command after the WAIT command.

The command can optionally be followed by an expression for the event identification value to be waited for; if such a value is specified, then the script will only resume when an event of the expression value becomes due. If no event identification value is specified, then a default value equal to the system constant EI_ANY is used, and the script will resume on any event becoming due.

See Event Identification Constants for an explanation of event identification codes.

Example

REM Post call-back, and then wait for it and only it - input

REM pin transitions are ignored.

CALLBACK 2 AFTER 100n

WAIT 2

...

REM Post call-back; wait for it or an input pin transition

CALLBACK 3 AFTER 200n

WHILE EVTID != 3 AND EVTID != EI_INPUT WAIT

The WHILE...WEND Command

Syntax

WHILE expression

...

...

WEND

WHILE expression ... [[WEND]]

Purpose

The WHILE...WEND command allows the commands between the WHILE and WEND keywords to be repeatedly executed whilst the loop expression following the WHILE keyword evaluates non-zero.

The loop expression following the WHILE keyword is evaluated and if the result is zero, execution continues with the first command after the WEND keyword. Otherwise, the commands between the WHILE and WEND keywords are executed; when the WEND keyword is encountered, execution returns to the WHILE command and the re-evaluation of the loop expression.

Note that, as the loop expression is evaluated at the start of the loop, the commands between the WHILE and WEND keywords may not be executed at all if the expression evaluates as zero the first time it is tested.

Example

WHILE i<j

PRINT "i is less than j"

i=i+2:j=j+1

WEND

WHILE enable_pin=F WAIT