Overview

The core of the OCRA project is the microsequencer, a softcore processor implemented in the FPGA to ensure real-time execution. This processor supports a very small instruction set that allows the convenient construction of real-time event tables and basic looping over the tables. An event-table describes the time at which an event is to happen inside the program. The most common such event is the production of a pulse waveform, such as a RF pulse or a gradient pulse, and the gating of the signal receiver. As result, the totality of these event tables is also called a pulse sequence, as it describes the precise timing and sequence of the pulses being played out by OCRA as part of a NMR/MRI experiment.

At the lowest level, the microsequencer can be programmed in a compact assembly-like language describing these tables. This language is designed to be machine generated, assuming there would always be either a UI-based or higher-level language generating the micro-sequencer instructions, but for very simple experiements, even basic imaging, these can be easily human written. The biggest down-side of human written microsequencer code is that the timing isn’t easily parameterizable, as the microsequencer has no math capabilities, and the python assembler as of now cannot evaluate literal math expressions (anyone interested in implementing that, please contact me).

The microsequencer reads its instructions from a memory block (more details in the PS interface description below), and its execution state can be controlled from the ARM over a set of control registeres described in the PS interface section below. The events the sequencer controls are expressed by a 64-bit register, “pulse register”, where each bit is connected to a particular hardware event. A description of the available events for the OCRA can be found below. The pulse sequence is responsible for maintaining the state of that pulse register. The command PR copies the contents of a 64-bit register in the microsequencer to the pulse register, therefore updating the state of it immediately. This means, the pulse sequence code must maintain the state of all events at all times. Commands that allow updating individual bits by OR operation on the state, or XOR operation on state have not yet been implemented, but might make useful additions in the future.

Microsequencer Instructions

All instructions for the microsequencer are 64-bit wide, with a 6-bit opcode identifying the instruction in the most significant bit. The microsequencer features 16 general purpose 64-bit wide registers, denoted R0...R15 that can be used as parameters to some of the instructions. When an instruction takes a register index as argument, its usually denoted as Rx in the manual.

Some instructions have a delay argument, which is a literal constant denoting the time to the next event in clock cycles. For OCRA, one clock cycle is exactly 8 nanoseconds (FPGA clock set to 125MHz). The delay argument is 40-bit wide. If longer delays are needed, the instruction can be repeated creating another delay.

When instructions have a addr argument, this refers to word address in the pulse sequence memory, and a microsequncer word is 64-bit wide. The microsequencer cannot address bytes, and it doesn’t need to.

There is several formats these instructions come in:

Format A:
format_a

Format B:
format_b

Format C: Need a figure, but it is identical to format B, with no register argument

Table of all instructions:

Instruction Opcode Format Description
NOP 0b000000 Do nothing
HALT 0b011001 Halt the sequence
DEC Rx 0b000001 A Decrement register value of Rx by 1
INC Rx 0b000010 A Increment register value of Rx by 1
LD64 Rx, addr 0b000100 A Load 64-bit integer from address addr to Rx
JNZ Rx, addr 0b010000 A jump to addr if Rx != 0
J addr 0b010111 A Unconditional jump to addr
PR Rx, delay 0b011101 B Pulse register Rx followed by a 40-bit delay in clock cycles
TXOFFSET offset 0b001000 B Set offset of Tx (RF) pulse to offset
GRADOFFSET offset 0b001001 B Set offset of gradient pulse to offset
LITR delay 0b000011 B Indicate end of TR, followed by 40-bit delay
RASTCSYNC clkmask 0b000101 C Reset raster clocks indicated in clkmask

NOP

This instruction literally does nothing

HALT

This instruction ends the pulse sequence.

LD64

PR

J and JNZ

DEC and INC

RASTCSYNC

This instruction resets the raster clock of the clock indicated in the mask to start with the current clock cycle. All raster clocks in the OCRA are derived directly from the master clock of the FPGA by a divider, and are therefore ALWAYS synchronous. In order to start a raster clock cycle with a TR for example, the phase of the raster clock needs to reset with the beginning of the TR. This is accomplished by using this instruction at the beginning of the TR.

GRADOFFSET and TXOFFSET

LITR

Tutorial

Microsequencer PS interface

Old section, please ignore everything below

Sequence Programming

Pulse sequences are written in an Assembly-like language. Fundamentally, the language specifies events (e.g. turning on an amplifier gating signal) by writing to and reading from registers. At the lowest level, the FPGA determines the event type by an 8-bit number written to a register, where event is specified by one bit. The pulse bits are described in the table below:

Bit Description
0 Tx Pulse
1 Rx Pulse
2 Grad Pulse
4 Tx Gate
5 Rx Gate

The unspecified bits are unused. These bit patterns can be grouped into four groups specific to execution:

  1. Wait
  2. Fire RF pulse
  3. Fire Gradient pulse
  4. Fire RF and gradient pulses

Each of these functions can be carried out with the receiver on and the receiver off, thus yielding 8 total possible groups. The bit RX_PULSE has inverted logic, so when it is on, the receiver is off. This is summarized in the table below. Here, OR refers to the bitwise OR operation.

Command Hex code Description
RX_PULSE 0x2 All off/wait
0x0 0x0 Only receiver on
TX_GATE OR TX_PULSE OR RX_PULSE 0x13 RF pulse
TX_GATE OR TX_PULSE 0x11 RF pulse with receiver on
GRAD_PULSE OR RX_PULSE 0x6 Gradient pulse
GRAD_PULSE 0x4 Gradient pulse with receiver on
TX_GATE OR TX_PULSE OR GRAD_PULSE OR RX_PULSE 0x17 RF and gradient pulse
TX_GATE OR TX_PULSE OR GRAD_PULSE 0x15 RF and gradient pulse with receiver on

The assembly-like language specifies low-level operations on registers. The language is specified by 64-bit words. However, because the bus between the ARM CPU and RAM is 32 bits, these words must be specified in two 32-bit integers. The bit order is little-Endian, meaning that the first 32-bit integer is the operand, and the second 32-bit integer contains the opcode. Like Assembly, there are commands to JMP to an address in memory, LD64 a 64-bit integer into memory, and PR pulse a register for a certain amount of time. Each command is specified by a 6-bit opcode. The full list of commands is shown below.

Instruction Opcode Format Description
NOP 0b000000 Do nothing
HALT 0b011001 Halt the sequence
DEC Rx 0b000001 A Decrement register value by 1
INC Rx 0b000010 A Increment register value by 1
LD64 Rx, Addr 0b000100 A Load 64-bit integer from address Addr to Rx
JNZ Rx, Addr 0b010000 A Jump to Addr if Rx! = 0
J Addr 0b010111 A Jump to Addr
PR Rx, Delay 0b011101 B Pulse register Rx after 40-bit Delay
TXOFFSET Offset 0b001000 B Set offset of Tx (RF) pulse to Offset
GRADOFFSET Offset 0b001001 B Set offset of gradient pulse to Offset

There are two formats for instructions: Format A and Format B. In both formats, the highest 6 bits are used for the opcode. In Format A, bits 36:32 specify the register to operate on, while the lower 32 bits specify an address in memory. In Format B, bits 44:40 specify the register, and the lower 40 bits specify a constant. Formats A and B are illustrated below.

Format A:
format_a

Format B:
format_b

We provide a number of example sequences. In the basic folder, there is a sequence for spin echo (se_default.txt) and FID (fid_default.txt). The spin echo sequence has a TE of 10ms.

In the img folder, there are a number of sequences for different image acquisitions. Use the txt file that is not prepended with hex - for instance, in the 0 se folder, use se.txt, not se_hex.txt. The hex txt file is an automatically generated file with the commands in hexadecimal, used for debugging. We provide the following sequences:

You can upload sequences to either the Signals GUI or the 2D Imaging GUI.