Language Overview

Scope and model

A TScript file is a sequence of commands and expressions.

  • A line can execute a global command, an object command method, an assignment, or an expression.

  • Newline is a statement separator (internally treated like ;).

  • ; can also be used explicitly to separate statements.

  • Lines can be continued with a trailing \.

  • Blocks use { …​ }.

File Extensions

By convention TScript is written in files using the extension .temu. TEMU also recognise .ts, and .tscript but the ts-extension may clash with TypeScript.

Comments

TScript supports comments using either of the single line shell style (#) or C style (//). The shell-style comments has been supported since TEMU 2 while the C-style comments were added in TEMU 3.

C-style comments are the preferred style since TEMU 3.

Example of Comments
echo Hello // trailing comment
echo World # trailing comment

Lexical elements

Identifiers

Identifiers start with a letter (or @) and can contain letters, digits, -, and _.

Literals

  • Integers: decimal, binary (0b…​), octal (0o…​), hexadecimal (0x…​)

  • Reals: decimal floating-point (supports exponent notation)

  • Strings: single-quoted or double-quoted

Numeric literals may contain _ for readability.

a = 123
b = 0xDEAD_BEEF
c = 0b1010_0011
d = 3.1415
e = 1.2e-3
s = "hello"
t = 'world'

Commands and Command Methods

Commands are stand alone global commands. This was the only type of command in TEMU 2. TEMU 3 introduces command method, a command that is associated to a specific class and invoked on objects.

The difference is that when interacting with objects using a traditional command, the object must be passed explicitly and the command must verify the type or compliance of the object to what the command expects, for a command method, this is not the case since they can only be invoked on objects that are already compliant to whatever rules are imposed on the object.

Meta Classes and Class Objects

In TEMU 3, TScript has been extended with meta classes and class objects. This primarily means that an object can be created using the class objects new method.

The new method does by default only take one argument (the object name) but classes can (in C or C++) customise the new method by querying for it by name from the class objects meta class and adding named required or optional arguments to the method reference.

Each registered class has a class object with the name of the class, in addition each class object is associated with a meta class, with the name @{CLASS_NAME}. In addition a root meta class responsible for constructing class and meta class pairs exists, this root class is named @MetaClass.

You should normally not be interacting with the meta classes directly, but they exist there to maintain property and methods registries for the class objects.

Variables and Assignments

Assignment uses =:

answer = 42
path = ./my/file

Variable reads use $name or ${name}:

echo $answer
load file=${TEST_ROOT}/image.elf obj=cpu0

Inside defcmd, parameters become scoped variables and are typically read via $paramName.

Expressions

Tscript supports expressions. The operators supported depends on the type of the left and right hand sides.

Operator Kind Types

+

Binary

integer, float

-

Binary, Unary

integer, float

/

Binary

integer, float, paths

*

Binary

integer, float

./

Unary

paths

<<

Binary

integers

>>

Binary

integers

|

Binary

integers

&

Binary

integers

~

Unary

integers

!

Unary

integers

The condition in if/elif must evaluate to an integer (0 = false, non-zero = true).

Control Flow

if / elif / else

if 1 < 2 {
  echo "true"
} elif 2 < 1 {
  echo "never"
} else {
  echo "fallback"
}

Error Handling

The TScript language supports emitting command errors. In-non-interactive mode, a command error aborts the executing script.

There are two ways of interacting with command errors in the TScript language itself.

These are the try and raise keywords.

try

The try keywords executes a command and converts any errors to integers. In non-interactive mode this can be used to prevent a failing command from stopping the interpreter.

More importantly though is that it can be used in if-else constructs to conditionally run code when a command succeeds or fails.

try <command> executes a command and returns an integer status:

  • 1 on success

  • 0 on failure (error is suppressed)

if try load file=missing.elf obj=cpu0 {
  echo "loaded"
} else {
  echo "failed"
}

raise

Raises a command error with a string message:

raise "Danger Will Robinson"

A raised error stops the command execution in non-interactive mode. By it self it is less useful, but serves a purpose in the custom commands defined with defcmd.

In these cases the command in question fails, and the failure can be handled by the script using if else.

// Simulate bootloader
defcmd boot(file: path) {
  if !try load obj=mem0 file=$file {
    raise "Could not load file"
  }
  cpu0.setPC pc=0x40000000
}

if try boot file="foo.elf" {
  echo "Boot succeeded"
} else {
  echo "Boot failed"
}

Commands and Command Methods

Commands are entities that can fail. A command halts execution of a script if running non interactivelly. Functions however are expressions and cannot fail.

Commands can be converted to expression values which will prevent non-interactive scripts from terminating by using the try keyword which converts the result of the command to a 1 for success and 0 for failure.

Global commands

Global commands are system-provided commands:

run time=5.0 perf=1
echo "hello"

Command methods on objects

Command methods are invoked on object references:

cpu0.setPC pc=0x40000
cpu0.setReg reg="%sp" value=0x0FFFFE80

This is equivalent to invoking a class command registered on the object type.

Named and positional arguments

Both styles are accepted:

cmd key=value
cmd positionalArg
cmd key=value positionalArg

Named arguments are type-checked against the command signature.

Command Definitions

It is possible to define commands both using the TEMU API and by defining commands in a TScript file.

defcmd mycmdname(a: string, b: path) {
  echo $a
  echo $b
}

mycmdname a=hello b=file.txt

A command can be failed using the raise statement.

A common use of a command would be to implement boot software emulation. The following example shows how a LEON3 processor can be booted:

defcmd boot(app: path) {
  if try load obj=mem0 file=${app} start-addr-var=startpc {
    if defined(startpc) {
      cpu0.setPC pc=$startpc
    }
    // Scaler reload register should be freq in MHz - 1
    grTimer0.scalerReload = cpu0.freq / 1e6 - 1

    // Prepare stack and frame pointer registers
    cpu0.setReg reg="%fp" value=0x40000000 + ram0.size - 4
    cpu0.setReg reg="%sp" value=0x40000000 + ram0.size - 4 - 92
  } else {
    raise "Failed to load file"
  }
}

Command Argument Types

The argument list is in the form of name type pairs, the argument name comes first, followed by a colon and then the typename. A number of types are supported at the moment:

  • int: integer type

  • real: double precision floating point

  • string: string type

  • path: string type (path indicates to auto completion to complete paths)

  • object: temu object type

  • class: temu class object

  • iface: interface reference

  • prop: property reference

The arguments are available as scoped variables in the command body.

Object properties and indexing

Property access uses .. Indexed properties use [index].

cpu0.steps = 1234
cpu0.steps

cpu0.extraRegs[0] = 42
cpu0.extraRegs[1] = 50
cpu0.extraRegs[0]

Property writes are type-checked by the property type.

Interface references

Interface references use object:IfaceName and indexed form object:IfaceName[index]. These are commonly passed to typed command arguments.

connect a=mem0.postTransaction b=tracer0:PostAccessIface
connect a=mdiobus0.phyDevices b=phy0:MDIOIface

Built-in functions

Built-in functions can be used in expressions.

Function Signature Description

defined

defined(name: string) → int

Returns 1 if a variable exists in any scope, else 0.

defined-in-scope

defined-in-scope(name: string) → int

Returns 1 if a variable exists in current scope, else 0.

file-exists

file-exists(path: string) → int

Returns 1 if path exists, else 0.

is-instance-of

is-instance-of(obj: object, cls: class) → int

Returns 1 if object is exactly of class cls, else 0.

bin

bin(v: int) → string

Binary string formatting ('0b…​.') with nibble separators.

cbin

cbin(v: int) → string

Compact binary formatting ('0b…​.') without separators.

oct

oct(v: int) → string

Octal string formatting ('0o…​').

coct

coct(v: int) → string

Compact octal formatting.

dec

dec(v: int) → string

Decimal string formatting ('…​').

cdec

cdec(v: int) → string

Compact decimal formatting.

hex

hex(v: int) → string

Hex string formatting ('0x…​').

chex

chex(v: int) → string

Compact hex formatting.

major-version

major-version() → int

Returns TEMU major version.

minor-version

minor-version() → int

Returns TEMU minor version.

patch-version

patch-version() → int

Returns TEMU patch version.

Examples

Error Handling in Scripts

defcmd failingcmd() {
  raise "Danger Will Robinson"
}

if try failingcmd {
  echo "Unexpected success"
} else {
  echo "Expected failure"
}

Command Method and Typed Arguments

cpu0.setPC pc=0x40000
cpu0.setReg reg="%fp" value=0x10000000
run time=5.0 perf=1

Current Limitations

  • Parser tokens exist for loop/function constructs (while, for, ret, fn), but these are currently not executable through the interpreter path used by TScript. These are reserved words however.