SET statement

The SET statement is the primary mechanism for controlling pins on the hardware under test. SET statements can be used to:

  • Read and write bus values on a device, via JTAG or external hardware.
  • Read and write pins on the XJLink2 directly.

Note that controlling busses on a device is only possible within a device file, not from a circuit code file.

Using SET to access busses

Each SET statement equates to either one or two JTAG scan chain cycles:

  • If all the pins which need to be read are already set as inputs, there will only be a single scan cycle.
  • If there are pins which require reading but are currently set as outputs, they must first be set as inputs (which requires one cycle of the JTAG scan chain) before they can be read.

Syntax

SET [ bus := I |
      bus := expression |
      variable := bus |
      variable :=* bus ]
    { , ... } ;

Parameters

bus

The name of the bus with an optional bit range to read from or write to. Just supplying the name of the bus will access all pins of the bus. If an optional bit range is supplied then the read or write is confined to just those bits, with the caveat below (see How SET handles writing to partial busses).

I

The value I tells XJTAG to prepare the bus to be an input. It will stop driving the bus, and if there is logic on the bus will prepare the bus to be read in a subsequent SET statement.

expression

An integer value to write to the bus' pins.

variable

An integer variable in which to store the value read from the bus.

The SET statement is constructed from a comma-separated list of assignments. Each side of the assignment must be of equal width (a bus may include a bit range, e.g. ADDR[2..0]). For example:

SET ADDR[15..0] := address[15..0], nCE := 0, nWE := 1, DATA := I;

This example will in a single cycle set the address bus to the value in the address variable, set the nCE pin low and set nWE high. The final assignment stops driving the DATA bus. This means that if we want to read the data bus in the next operation, no extra scan cycle is needed to set the DATA bus as an input:

SET data := DATA;

Reading a bus that is outputting

The :=* operator can be used inside a SET statement to read the value of a bus without disabling its output.

SET isDisabled :=* nCE;

Here we read the value of nCE, even though the pin is currently an output. This reads the value regardless of the current direction of the bus, which is particularly useful for finding out if a pin is shorted, since we can read the actual value of the pin.

N.B. Some bidirectional pins cannot be read whilst they are outputting, so if the only JTAG pin on a net is such a bidirectional pin, you will get an error message when trying to read the net using the :=* operator. The standard BC_7 JTAG cell-type, however, is capable of reading whilst outputting, and this is the most commonly used cell-type for bidirectional pins.

How SET handles writing to partial busses

When a bus is written to in a SET statement (e.g. ADDR or DATA above), all the pins in the bus are written to, even if only a subset are specifically referenced. For example, the following code will set bit 2 high, but will also drive all the pins of the address bus to their last assigned value:

// Set the ADDR bus bit 2 high.
SET ADDR[2] := 1;

This means that if you set a single bus bit as above it might be possible to see a warning message or error message such as:

Warning: Cannot write to bus member ADDR[0] for device Main.IC5

An example of this might be where the design has a 16-bit memory device with A0 tied low. The device file has the pin defined as part of the bus, and so the warning is displayed when the bus is driven, even if ADDR[0] is not explicitly set.

Sometimes, JTAG pins share a common control cell and so it may not be possible to disable a single pin of a bus:

SET DATA[0] := I, DATA[15..1] := 0x7ff;

If the JTAG pins that are driving the ADDR bus share a common control cell, then an error will be thrown at run-time.

Checking for bus access at run-time

Since device files are intended to be independent from the board the device is used on, it is useful to find out if read or write access is available to a particular bus or pins of a bus before trying to access the bus, which might otherwise generate a run-time error or warning.

The READABLE keyword can be used to check if read access is available to the bus or pins of a bus.

The WRITEABLE keyword can be used to check if write access is available to the bus or pins of a bus.

Grouping of SET statements

Sometimes, it is important that several JTAG scan chain cycles occur in quick succession. This might be important if there are timing constraints on the signals being manipulated. To group several JTAG scan cycles together, use a HOLDOFF block - for example:

HOLDOFF
  SET nOE := 1, ADDR := 0x5555, DATA:=0xAA, nWE := 1, nCE := 1;
  SET nCE := 0, nWE := 0;

  SET nCE := 1, nWE := 1, ADDR := 0x2AAA, DATA:=0x55;
  SET nCE := 0, nWE := 0;
END;

The JTAG scan chains cycles will be stored (i.e. 'held off') until the end of the HOLDOFF block has been reached and then sent to the hardware altogether.

Controlling writes

If a SET statement contains just writes, then it may not get sent immediately and program execution will continue in parallel. This is done to improve the throughput of data to the XJLink and is typically not noticeable. However, there are some cases where its effect can be observed:

  • Strict delays are needed between writes
  • The write results in a user-observable effect, e.g. an LED is lit

In these kinds of cases, the FLUSH keyword can be used to force any outstanding writes to be sent immediately. See Accelerating JTAG chains for more information.

Example

This example code flashes an LED at 1Hz until the user presses 'y' or 'n'.

INT key;
INT state := 0;

PRINT("Press 'y' or 'n'\n");
DO
  SET LED := state;
  FLUSH;
  key := GETKEY();
WHILE key != 'y' &&? key != 'n'
  SLEEP(500);
  state := !state;
END;

Using SET to access XJLink PIO pins

PIO pins and nTRST pins (nTRST, nTRST2, nTRST3 and nTRST4) can be directly controlled at any point during testing. For setting XJLink pins, including the TAP pins (TCK, TMS, TDI, etc) inside a JTAG block, see SET statement for raw JTAG access.

Using SET in this way was added in XJTAG v2.3 and is not recognised in versions prior to that.

PIO and nTRST pins are capable of reading whilst outputting and the :=* operator can be used with these pins in the same way as JTAG accesses.

PIO pin accesses can be combined with JTAG accesses in the same SET statement. Since writing to a PIO pin does not require a JTAG scan, this can speed up writing to a memory device.

Syntax

SET [ PIO.name := I |
      PIO.name := expression |
      variable := PIO.name |
      variable :=* PIO.name ]
    { , ... } ;

Parameters

name

The name is the name of the PIO or nTRST pin.

expression

An integer value to write to the pin.

variable

An integer variable in which to store the value read from the pin.

Errors

A compile error occurs if name is not a valid PIO or nTRST pin defined in the pin mapping.

Example

// An optimised write cycle.
// Requires a pin on the XJLink2 connector connected directly to the write enable pin on the memory device.
// This pin is defined as PIO in the Pin Mapping, and named nWE.
//
WriteCycle(INT address, INT data)()
  SET PIO.nWE := 0, ADDRESS := address, DATA := data;
  SET PIO.nWE := 1;
END;